Skip to content

Commit af6fb97

Browse files
committed
feat(provider/kubernetes): support for kubectl server-side-apply strategy
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>
1 parent 3cbd478 commit af6fb97

File tree

6 files changed

+35
-5
lines changed

6 files changed

+35
-5
lines changed

clouddriver-kubernetes/src/main/java/com/netflix/spinnaker/clouddriver/kubernetes/description/manifest/KubernetesManifestStrategy.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ ImmutableMap<String, String> toAnnotations() {
107107
public enum DeployStrategy {
108108
APPLY(null),
109109
RECREATE(STRATEGY_ANNOTATION_PREFIX + "/recreate"),
110-
REPLACE(STRATEGY_ANNOTATION_PREFIX + "/replace");
110+
REPLACE(STRATEGY_ANNOTATION_PREFIX + "/replace"),
111+
SERVER_SIDE_APPLY(STRATEGY_ANNOTATION_PREFIX + "/server-side-apply");
111112

112113
@Nullable private final String annotation;
113114

@@ -122,6 +123,9 @@ static DeployStrategy fromAnnotations(Map<String, String> annotations) {
122123
if (Boolean.parseBoolean(annotations.get(REPLACE.annotation))) {
123124
return REPLACE;
124125
}
126+
if (Boolean.parseBoolean(annotations.get(SERVER_SIDE_APPLY.annotation))) {
127+
return SERVER_SIDE_APPLY;
128+
}
125129
return APPLY;
126130
}
127131

clouddriver-kubernetes/src/main/java/com/netflix/spinnaker/clouddriver/kubernetes/op/handler/CanDeploy.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ default OperationResult deploy(
5959
case REPLACE:
6060
deployedManifest = credentials.createOrReplace(manifest, task, opName);
6161
break;
62+
case SERVER_SIDE_APPLY:
63+
deployedManifest = credentials.deploy(manifest, task, opName, "--server-side");
64+
break;
6265
case APPLY:
6366
deployedManifest = credentials.deploy(manifest, task, opName);
6467
break;

clouddriver-kubernetes/src/main/java/com/netflix/spinnaker/clouddriver/kubernetes/op/job/KubectlJobExecutor.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -587,10 +587,14 @@ public ImmutableList<KubernetesManifest> list(
587587
}
588588

589589
public KubernetesManifest deploy(
590-
KubernetesCredentials credentials, KubernetesManifest manifest, Task task, String opName) {
590+
KubernetesCredentials credentials,
591+
KubernetesManifest manifest,
592+
Task task,
593+
String opName,
594+
String... cmdArgs) {
591595
log.info("Deploying manifest {}", manifest.getFullResourceName());
592596
List<String> command = kubectlAuthPrefix(credentials);
593-
597+
command.addAll(List.of(cmdArgs));
594598
// Read from stdin
595599
command.add("apply");
596600
command.add("-o");

clouddriver-kubernetes/src/main/java/com/netflix/spinnaker/clouddriver/kubernetes/security/KubernetesCredentials.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -561,12 +561,13 @@ public Collection<KubernetesPodMetric> topPod(KubernetesCoordinates coords) {
561561
() -> jobExecutor.topPod(this, coords.getNamespace(), coords.getName()));
562562
}
563563

564-
public KubernetesManifest deploy(KubernetesManifest manifest, Task task, String opName) {
564+
public KubernetesManifest deploy(
565+
KubernetesManifest manifest, Task task, String opName, String... cmdArgs) {
565566
return runAndRecordMetrics(
566567
"deploy",
567568
manifest.getKind(),
568569
manifest.getNamespace(),
569-
() -> jobExecutor.deploy(this, manifest, task, opName));
570+
() -> jobExecutor.deploy(this, manifest, task, opName, cmdArgs));
570571
}
571572

572573
private KubernetesManifest replace(KubernetesManifest manifest, Task task, String opName) {

clouddriver-kubernetes/src/test/java/com/netflix/spinnaker/clouddriver/kubernetes/description/manifest/KubernetesManifestStrategyTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ void replaceStrategy() {
6464
assertThat(strategy).isEqualTo(DeployStrategy.REPLACE);
6565
}
6666

67+
@Test
68+
void serverSideApplyStrategy() {
69+
KubernetesManifestStrategy.DeployStrategy strategy =
70+
KubernetesManifestStrategy.DeployStrategy.fromAnnotations(
71+
ImmutableMap.of("strategy.spinnaker.io/server-side-apply", "true"));
72+
assertThat(strategy).isEqualTo(DeployStrategy.SERVER_SIDE_APPLY);
73+
}
74+
6775
@Test
6876
void nonBooleanValue() {
6977
KubernetesManifestStrategy.DeployStrategy strategy =

clouddriver-kubernetes/src/test/java/com/netflix/spinnaker/clouddriver/kubernetes/op/handler/CanDeployTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@ void applyReturnValue() {
6161
assertThat(result.getManifests()).containsExactlyInAnyOrder(manifest);
6262
}
6363

64+
@Test
65+
void applyServerSideMutations() {
66+
KubernetesCredentials credentials = mock(KubernetesCredentials.class);
67+
KubernetesManifest manifest = ManifestFetcher.getManifest("candeploy/deployment.yml");
68+
when(credentials.deploy(manifest, task, OP_NAME, "--server-side")).thenReturn(manifest);
69+
handler.deploy(credentials, manifest, DeployStrategy.SERVER_SIDE_APPLY, task, OP_NAME);
70+
verify(credentials).deploy(manifest, task, OP_NAME, "--server-side");
71+
verifyNoMoreInteractions(credentials);
72+
}
73+
6474
@Test
6575
void replaceMutations() {
6676
KubernetesCredentials credentials = mock(KubernetesCredentials.class);

0 commit comments

Comments
 (0)