Skip to content

Commit

Permalink
feat(provider/kubernetes): support for kubectl server-side-apply stra…
Browse files Browse the repository at this point in the history
…tegy

kubernetes server-side apply (SSA) was released back in 1.14 and became GA In 1.22. This new strategy will use the new merging algorithm, as well as tracking field ownership at the kubernetes api-server

Signed-off-by: Amir Alavi <amiralavi7@gmail.com>
  • Loading branch information
a7i committed Aug 4, 2023
1 parent 3cbd478 commit 1279682
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ ImmutableMap<String, String> toAnnotations() {
public enum DeployStrategy {
APPLY(null),
RECREATE(STRATEGY_ANNOTATION_PREFIX + "/recreate"),
REPLACE(STRATEGY_ANNOTATION_PREFIX + "/replace");
REPLACE(STRATEGY_ANNOTATION_PREFIX + "/replace"),
SERVER_SIDE_APPLY(STRATEGY_ANNOTATION_PREFIX + "/server-side-apply");

@Nullable private final String annotation;

Expand All @@ -122,6 +123,9 @@ static DeployStrategy fromAnnotations(Map<String, String> annotations) {
if (Boolean.parseBoolean(annotations.get(REPLACE.annotation))) {
return REPLACE;
}
if (Boolean.parseBoolean(annotations.get(SERVER_SIDE_APPLY.annotation))) {
return SERVER_SIDE_APPLY;
}
return APPLY;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ default OperationResult deploy(
case REPLACE:
deployedManifest = credentials.createOrReplace(manifest, task, opName);
break;
case SERVER_SIDE_APPLY:
deployedManifest = credentials.deploy(manifest, task, opName, "--server-side");
break;
case APPLY:
deployedManifest = credentials.deploy(manifest, task, opName);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -587,12 +587,17 @@ public ImmutableList<KubernetesManifest> list(
}

public KubernetesManifest deploy(
KubernetesCredentials credentials, KubernetesManifest manifest, Task task, String opName) {
KubernetesCredentials credentials,
KubernetesManifest manifest,
Task task,
String opName,
String... cmdArgs) {
log.info("Deploying manifest {}", manifest.getFullResourceName());
List<String> command = kubectlAuthPrefix(credentials);

// Read from stdin
command.add("apply");
command.addAll(List.of(cmdArgs));
command.add("-o");
command.add("json");
command.add("-f");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -561,12 +561,13 @@ public Collection<KubernetesPodMetric> topPod(KubernetesCoordinates coords) {
() -> jobExecutor.topPod(this, coords.getNamespace(), coords.getName()));
}

public KubernetesManifest deploy(KubernetesManifest manifest, Task task, String opName) {
public KubernetesManifest deploy(
KubernetesManifest manifest, Task task, String opName, String... cmdArgs) {
return runAndRecordMetrics(
"deploy",
manifest.getKind(),
manifest.getNamespace(),
() -> jobExecutor.deploy(this, manifest, task, opName));
() -> jobExecutor.deploy(this, manifest, task, opName, cmdArgs));
}

private KubernetesManifest replace(KubernetesManifest manifest, Task task, String opName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ void replaceStrategy() {
assertThat(strategy).isEqualTo(DeployStrategy.REPLACE);
}

@Test
void serverSideApplyStrategy() {
KubernetesManifestStrategy.DeployStrategy strategy =
KubernetesManifestStrategy.DeployStrategy.fromAnnotations(
ImmutableMap.of("strategy.spinnaker.io/server-side-apply", "true"));
assertThat(strategy).isEqualTo(DeployStrategy.SERVER_SIDE_APPLY);
}

@Test
void nonBooleanValue() {
KubernetesManifestStrategy.DeployStrategy strategy =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ void applyReturnValue() {
assertThat(result.getManifests()).containsExactlyInAnyOrder(manifest);
}

@Test
void applyServerSideMutations() {
KubernetesCredentials credentials = mock(KubernetesCredentials.class);
KubernetesManifest manifest = ManifestFetcher.getManifest("candeploy/deployment.yml");
when(credentials.deploy(manifest, task, OP_NAME, "--server-side")).thenReturn(manifest);
handler.deploy(credentials, manifest, DeployStrategy.SERVER_SIDE_APPLY, task, OP_NAME);
verify(credentials).deploy(manifest, task, OP_NAME, "--server-side");
verifyNoMoreInteractions(credentials);
}

@Test
void replaceMutations() {
KubernetesCredentials credentials = mock(KubernetesCredentials.class);
Expand Down

0 comments on commit 1279682

Please sign in to comment.