Skip to content

Commit

Permalink
Make PropagationPolicy configurable when deletingExisting is configured
Browse files Browse the repository at this point in the history
  • Loading branch information
bbeaudreault committed Dec 17, 2020
1 parent cbc5d52 commit 49d2eae
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* Fix #2656: Binding operations can be instantiated

#### Improvements
* Fix: Allow specifying PropagationPolicy when using deleteExisting
* Fix: CustomResourceDefinitionContext.fromCrd support for v1 CustomResourceDefinition
* Fix #2642: Update kubernetes-examples to use apps/v1 Deployment rather than extensions/v1beta1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@
/**
* Created by iocanel on 9/15/16.
*/
public interface CascadingDeletable extends Deletable, Cascading<Deletable> {
public interface CascadingDeletable<T> extends Deletable, Cascading<Deletable>, Recreateable<Applicable<T>> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
public interface ListVisitFromServerGetDeleteRecreateWaitApplicable<T> extends Visitable<ListVisitFromServerGetDeleteRecreateWaitApplicable<T>>,
FromServerGettable<List<T>>,
RecreateApplicable<List<T>, T>,
CascadingDeletable,
CascadingDeletable<List<T>>,
Waitable<List<T>, T>,
GracePeriodConfigurable<CascadingDeletable>,
PropagationPolicyConfigurable<CascadingDeletable> {
GracePeriodConfigurable<CascadingDeletable<List<T>>>,
PropagationPolicyConfigurable<CascadingDeletable<List<T>>> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@

public interface VisitFromServerGetWatchDeleteRecreateWaitApplicable<T> extends Visitable<VisitFromServerGetWatchDeleteRecreateWaitApplicable<T>>,
FromServerGettable<T>, RecreateApplicable<T, T>,
CascadingDeletable,
CascadingDeletable<T>,
Watchable<Watcher<T>>,
Waitable<T, T>,
GracePeriodConfigurable<CascadingDeletable>,
PropagationPolicyConfigurable<CascadingDeletable> {
GracePeriodConfigurable<CascadingDeletable<T>>,
PropagationPolicyConfigurable<CascadingDeletable<T>> {
}
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,12 @@ public VisitFromServerGetWatchDeleteRecreateWaitApplicable<HasMetadata> accept(V
}

@Override
public CascadingDeletable withGracePeriod(long gracePeriodSeconds) {
public CascadingDeletable<HasMetadata> withGracePeriod(long gracePeriodSeconds) {
return new NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl(client, config, fallbackNamespace, explicitNamespace, fromServer, true, visitors, item, gracePeriodSeconds, propagationPolicy, cascading, watchRetryInitialBackoffMillis, watchRetryBackoffMultiplier);
}

@Override
public CascadingDeletable withPropagationPolicy(DeletionPropagation propagationPolicy) {
public CascadingDeletable<HasMetadata> withPropagationPolicy(DeletionPropagation propagationPolicy) {
return new NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableImpl(client, config, fallbackNamespace, explicitNamespace, fromServer, true, visitors, item, gracePeriodSeconds, propagationPolicy, cascading, watchRetryInitialBackoffMillis, watchRetryBackoffMultiplier);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,12 +382,12 @@ public ListVisitFromServerGetDeleteRecreateWaitApplicable<HasMetadata> accept(Vi
return new NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl(client, config, fallbackNamespace, explicitNamespace, fromServer, true, newVisitors, item, null, null, gracePeriodSeconds, propagationPolicy, cascading, watchRetryInitialBackoffMillis, watchRetryBackoffMultiplier);
}

@Override public CascadingDeletable withGracePeriod(long gracePeriodSeconds)
@Override public CascadingDeletable<List<HasMetadata>> withGracePeriod(long gracePeriodSeconds)
{
return new NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl(client, config, fallbackNamespace, explicitNamespace, fromServer, true, visitors, item, null, null, gracePeriodSeconds, propagationPolicy, cascading, watchRetryInitialBackoffMillis, watchRetryBackoffMultiplier);
}

@Override public CascadingDeletable withPropagationPolicy(DeletionPropagation propagationPolicy)
@Override public CascadingDeletable<List<HasMetadata>> withPropagationPolicy(DeletionPropagation propagationPolicy)
{
return new NamespaceVisitFromServerGetWatchDeleteRecreateWaitApplicableListImpl(client, config, fallbackNamespace, explicitNamespace, fromServer, true, visitors, item, null, null, gracePeriodSeconds, propagationPolicy, cascading, watchRetryInitialBackoffMillis, watchRetryBackoffMultiplier);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import io.fabric8.kubernetes.api.model.ServiceBuilder;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
import io.fabric8.kubernetes.api.model.apps.ReplicaSetList;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.arquillian.cube.kubernetes.api.Session;
import org.arquillian.cube.kubernetes.impl.requirement.RequiresKubernetes;
Expand All @@ -49,6 +50,7 @@
import static junit.framework.TestCase.assertNotNull;
import static org.awaitility.Awaitility.await;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;

@RunWith(ArquillianConditionalRunner.class)
Expand Down Expand Up @@ -159,6 +161,60 @@ public void delete() {
assertTrue(client.resource(pod1).inNamespace(session.getNamespace()).delete());
}

@Test
public void testDeleteExistingWithOrphanDeletion() {
// Create Deployment
client.resource(deployment).inNamespace(session.getNamespace()).createOrReplace();
await().atMost(30, TimeUnit.SECONDS).until(resourceIsReady(deployment));

// get creationTimestamp of underlying replicaset. we expect this NOT to match later, meaning the orphan WAS deleted.
ReplicaSetList replicaSetList = client.apps().replicaSets().inNamespace(session.getNamespace()).withLabel("run", "deploy1").list();
assertEquals(1, replicaSetList.getItems().size());
String replicaSetCreationTimestamp = replicaSetList.getItems().get(0).getMetadata().getCreationTimestamp();

// Recreate deployment with deleteExisting
client.resource(deployment).inNamespace(session.getNamespace()).withPropagationPolicy(DeletionPropagation.BACKGROUND).deletingExisting().createOrReplace();
await().atMost(30, TimeUnit.SECONDS).until(resourceIsReady(deployment));

// check that creationTimestamp DOES NOT MATCH original, meaning the orphan WAS deleted
replicaSetList = client.apps().replicaSets().inNamespace(session.getNamespace()).withLabel("run", "deploy1").list();
assertEquals(1, replicaSetList.getItems().size());
assertNotEquals(replicaSetCreationTimestamp, replicaSetList.getItems().get(0).getMetadata().getCreationTimestamp());

// cleanup
assertEquals(true, client.resource(deployment).inNamespace(session.getNamespace()).delete());
// Check whether child resources are also deleted
await().atMost(30, TimeUnit.SECONDS)
.until(() -> client.apps().replicaSets().inNamespace(session.getNamespace()).withLabel("run", "deploy1").list().getItems().size() == 0);
}

@Test
public void testDeleteExistingWithoutOrphanDeletion() {
// Create Deployment
client.resource(deployment).inNamespace(session.getNamespace()).createOrReplace();
await().atMost(30, TimeUnit.SECONDS).until(resourceIsReady(deployment));

// get creationTimestamp of underlying replicaset. we expect this to match later, meaning the orphan was not deleted.
ReplicaSetList replicaSetList = client.apps().replicaSets().inNamespace(session.getNamespace()).withLabel("run", "deploy1").list();
assertEquals(1, replicaSetList.getItems().size());
String replicaSetCreationTimestamp = replicaSetList.getItems().get(0).getMetadata().getCreationTimestamp();

// Recreate deployment with deleteExisting
client.resource(deployment).inNamespace(session.getNamespace()).withPropagationPolicy(DeletionPropagation.ORPHAN).deletingExisting().createOrReplace();
await().atMost(30, TimeUnit.SECONDS).until(resourceIsReady(deployment));

// check that creationTimestamp matches original, meaning the orphan was not deleted
replicaSetList = client.apps().replicaSets().inNamespace(session.getNamespace()).withLabel("run", "deploy1").list();
assertEquals(1, replicaSetList.getItems().size());
assertEquals(replicaSetCreationTimestamp, replicaSetList.getItems().get(0).getMetadata().getCreationTimestamp());

// cleanup
assertEquals(true, client.resource(deployment).inNamespace(session.getNamespace()).delete());
// Check whether child resources are also deleted
await().atMost(30, TimeUnit.SECONDS)
.until(() -> client.apps().replicaSets().inNamespace(session.getNamespace()).withLabel("run", "deploy1").list().getItems().size() == 0);
}

@Test
public void testDeletionWithOrphanDeletion() {
// Create Deployment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package io.fabric8.kubernetes.client.mock;

import io.fabric8.kubernetes.api.model.DeleteOptions;
import io.fabric8.kubernetes.api.model.DeletionPropagation;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.PodBuilder;
Expand All @@ -33,6 +35,7 @@
import io.fabric8.kubernetes.client.dsl.PodResource;
import io.fabric8.kubernetes.client.internal.readiness.Readiness;
import io.fabric8.kubernetes.client.server.mock.KubernetesServer;
import io.fabric8.kubernetes.client.utils.Serialization;
import okhttp3.mockwebserver.RecordedRequest;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.Assert;
Expand Down Expand Up @@ -118,6 +121,30 @@ void testCreateOrReplaceWithDeleteExisting() throws Exception {
assertEquals("POST", request.getMethod());
}

@Test
void itPassesPropagationPolicyWithDeleteExisting() throws InterruptedException {
Pod pod1 = new PodBuilder().withNewMetadata().withName("pod1").withNamespace("test").and().build();

server.expect().delete().withPath("/api/v1/namespaces/ns1/pods/pod1").andReturn(HttpURLConnection.HTTP_OK, pod1).once();
server.expect().post().withPath("/api/v1/namespaces/ns1/pods").andReturn(HttpURLConnection.HTTP_CREATED, pod1).once();

KubernetesClient client = server.getClient();
HasMetadata response = client.resource(pod1).inNamespace("ns1").withPropagationPolicy(DeletionPropagation.FOREGROUND).deletingExisting().createOrReplace();
assertEquals(pod1, response);

assertEquals(2, server.getMockServer().getRequestCount());

RecordedRequest deleteRequest = server.getMockServer().takeRequest();
assertEquals("/api/v1/namespaces/ns1/pods/pod1", deleteRequest.getPath());
assertEquals("DELETE", deleteRequest.getMethod());
DeleteOptions deleteOptions = Serialization.unmarshal(deleteRequest.getBody().readUtf8(), DeleteOptions.class);
assertEquals("Foreground", deleteOptions.getPropagationPolicy());

RecordedRequest postRequest = server.getLastRequest();
assertEquals("/api/v1/namespaces/ns1/pods", postRequest.getPath());
assertEquals("POST", postRequest.getMethod());
}

@Test
void testCreateOrReplaceWithDeleteExistingWithCreateFailed() {
// Given
Expand Down

0 comments on commit 49d2eae

Please sign in to comment.