Skip to content

Commit

Permalink
Change rolling restart/pause/resume to use rfc6902 JSON patch
Browse files Browse the repository at this point in the history
  • Loading branch information
dkaukov committed Dec 16, 2024
1 parent a5d57e5 commit 7276a81
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@
import java.security.NoSuchAlgorithmException;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
Expand Down Expand Up @@ -169,8 +169,8 @@ public T rollUpdate(T oldObj, T newObj) {
}
}

private static <T> T applyPatch(Resource<T> resource, Map<String, Object> map, KubernetesSerialization serialization) {
return resource.patch(PatchContext.of(PatchType.STRATEGIC_MERGE), serialization.asJson(map));
private static <T> T applyPatch(Resource<T> resource, List<Object> list, KubernetesSerialization serialization) {
return resource.patch(PatchContext.of(PatchType.JSON), serialization.asJson(list));
}

public static <T extends HasMetadata> T resume(RollableScalableResourceOperation<T, ?, ?> resource) {
Expand All @@ -185,35 +185,29 @@ public static <T extends HasMetadata> T restart(RollableScalableResourceOperatio
return applyPatch(resource, RollingUpdater.requestPayLoadForRolloutRestart(), resource.getKubernetesSerialization());
}

public static Map<String, Object> requestPayLoadForRolloutPause() {
Map<String, Object> jsonPatchPayload = new HashMap<>();
Map<String, Object> spec = new HashMap<>();
spec.put("paused", true);
jsonPatchPayload.put("spec", spec);
return jsonPatchPayload;
public static List<Object> requestPayLoadForRolloutPause() {
HashMap<String, Object> patch = new HashMap<>();
patch.put("op", "add");
patch.put("path", "/spec/paused");
patch.put("value", true);
return Collections.singletonList(patch);
}

public static Map<String, Object> requestPayLoadForRolloutResume() {
Map<String, Object> jsonPatchPayload = new HashMap<>();
Map<String, Object> spec = new HashMap<>();
spec.put("paused", null);
jsonPatchPayload.put("spec", spec);
return jsonPatchPayload;
public static List<Object> requestPayLoadForRolloutResume() {
HashMap<String, Object> patch = new HashMap<>();
patch.put("op", "remove");
patch.put("path", "/spec/paused");
return Collections.singletonList(patch);
}

public static Map<String, Object> requestPayLoadForRolloutRestart() {
Map<String, Object> jsonPatchPayload = new HashMap<>();
Map<String, String> annotations = new HashMap<>();
annotations.put("kubectl.kubernetes.io/restartedAt",
new Date().toInstant().atOffset(ZoneOffset.UTC).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
Map<String, Object> templateMetadata = new HashMap<>();
templateMetadata.put("annotations", annotations);
Map<String, Object> template = new HashMap<>();
template.put("metadata", templateMetadata);
Map<String, Object> deploymentSpec = new HashMap<>();
deploymentSpec.put("template", template);
jsonPatchPayload.put("spec", deploymentSpec);
return jsonPatchPayload;
public static List<Object> requestPayLoadForRolloutRestart() {
HashMap<String, Object> patch = new HashMap<>();
HashMap<String, Object> value = new HashMap<>();
patch.put("op", "replace");
patch.put("path", "/spec/template/metadata/annotations");
value.put("kubectl.kubernetes.io/restartedAt", new Date().toInstant().atOffset(ZoneOffset.UTC).format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
patch.put("value", value);
return Collections.singletonList(patch);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

@EnableKubernetesMockClient(crud = true)
Expand Down Expand Up @@ -125,4 +126,94 @@ void testReplace() {
assertFalse(replacedDeployment.getMetadata().getLabels().isEmpty());
assertEquals("one", replacedDeployment.getMetadata().getLabels().get("testKey"));
}

@Test
@DisplayName("Should pause resource")
void testPause() {
// Given
Deployment deployment1 = new DeploymentBuilder().withNewMetadata()
.withName("d1")
.withNamespace("ns1")
.addToLabels("testKey", "testValue")
.endMetadata()
.withNewSpec()
.endSpec()
.build();
client.apps().deployments().inNamespace("ns1").create(deployment1);

// When
client.apps()
.deployments()
.inNamespace("ns1")
.withName("d1")
.rolling()
.pause();
Deployment updatedDeployment = client.apps().deployments().inNamespace("ns1").withName("d1").get();

// Then
assertNotNull(updatedDeployment);
assertEquals(true, updatedDeployment.getSpec().getPaused());
}

@Test
@DisplayName("Should resume rollout")
void testRolloutResume() throws InterruptedException {
// Given
Deployment deployment1 = new DeploymentBuilder().withNewMetadata()
.withName("d1")
.withNamespace("ns1")
.addToLabels("testKey", "testValue")
.endMetadata()
.withNewSpec()
.withPaused(true)
.endSpec()
.build();
client.apps().deployments().inNamespace("ns1").create(deployment1);

// When
client.apps()
.deployments()
.inNamespace("ns1")
.withName("d1")
.rolling()
.resume();
Deployment updatedDeployment = client.apps().deployments().inNamespace("ns1").withName("d1").get();

// Then
assertNotNull(updatedDeployment);
assertNull(updatedDeployment.getSpec().getPaused());
}

@Test
@DisplayName("Should restart rollout")
void testRolloutRestart() throws InterruptedException {
// Given
Deployment deployment1 = new DeploymentBuilder().withNewMetadata()
.withName("d1")
.withNamespace("ns1")
.addToLabels("testKey", "testValue")
.endMetadata()
.withNewSpec()
.withNewTemplate()
.withNewMetadata()
.addToAnnotations("", "")
.endMetadata()
.endTemplate()
.endSpec()
.build();
client.apps().deployments().inNamespace("ns1").create(deployment1);

// When
client.apps()
.deployments()
.inNamespace("ns1")
.withName("d1")
.rolling()
.restart();
Deployment updatedDeployment = client.apps().deployments().inNamespace("ns1").withName("d1").get();

// Then
assertNotNull(updatedDeployment);
assertNotNull(updatedDeployment.getSpec().getTemplate().getMetadata().getAnnotations().get("kubectl.kubernetes.io/restartedAt"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ void testRolloutPause() throws InterruptedException {
// Then
RecordedRequest recordedRequest = server.getLastRequest();
assertEquals("PATCH", recordedRequest.getMethod());
assertEquals("{\"spec\":{\"paused\":true}}", recordedRequest.getBody().readUtf8());
assertEquals("[{\"op\":\"add\",\"path\":\"/spec/paused\",\"value\":true}]", recordedRequest.getBody().readUtf8());
}

@Test
Expand Down Expand Up @@ -652,7 +652,7 @@ void testRolloutResume() throws InterruptedException {
RecordedRequest recordedRequest = server.getLastRequest();
assertNotNull(deployment);
assertEquals("PATCH", recordedRequest.getMethod());
assertEquals("{\"spec\":{\"paused\":null}}", recordedRequest.getBody().readUtf8());
assertEquals("[{\"op\":\"remove\",\"path\":\"/spec/paused\"}]", recordedRequest.getBody().readUtf8());
}

@Test
Expand Down

0 comments on commit 7276a81

Please sign in to comment.