Skip to content

Commit

Permalink
feat(kubernetes): support rolling restart operation for deployments
Browse files Browse the repository at this point in the history
  • Loading branch information
maggieneterval committed Oct 17, 2019
1 parent 079ee0a commit e076eba
Show file tree
Hide file tree
Showing 11 changed files with 276 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public final class AtomicOperations {
public static final String PAUSE_ROLLOUT_MANIFEST = "pauseRolloutManifest";
public static final String RESUME_ROLLOUT_MANIFEST = "resumeRolloutManifest";
public static final String UNDO_ROLLOUT_MANIFEST = "undoRolloutManifest";
public static final String ROLLING_RESTART_MANIFEST = "rollingRestartManifest";
public static final String DISABLE_MANIFEST = "disableManifest";
public static final String ENABLE_MANIFEST = "enableManifest";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2019 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.clouddriver.kubernetes.v2.converter.manifest;

import static com.netflix.spinnaker.clouddriver.orchestration.AtomicOperations.ROLLING_RESTART_MANIFEST;

import com.netflix.spinnaker.clouddriver.kubernetes.KubernetesOperation;
import com.netflix.spinnaker.clouddriver.kubernetes.deploy.converters.KubernetesAtomicOperationConverterHelper;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesRollingRestartManifestDescription;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.op.manifest.KubernetesRollingRestartManifestOperation;
import com.netflix.spinnaker.clouddriver.orchestration.AtomicOperation;
import com.netflix.spinnaker.clouddriver.security.AbstractAtomicOperationsCredentialsSupport;
import com.netflix.spinnaker.clouddriver.security.ProviderVersion;
import java.util.Map;
import org.springframework.stereotype.Component;

@KubernetesOperation(ROLLING_RESTART_MANIFEST)
@Component
public class KubernetesRollingRestartManifestConverter
extends AbstractAtomicOperationsCredentialsSupport {
@Override
public AtomicOperation convertOperation(Map input) {
return new KubernetesRollingRestartManifestOperation(convertDescription(input));
}

@Override
public KubernetesRollingRestartManifestDescription convertDescription(Map input) {
return KubernetesAtomicOperationConverterHelper.convertDescription(
input, this, KubernetesRollingRestartManifestDescription.class);
}

@Override
public boolean acceptsVersion(ProviderVersion version) {
return version == ProviderVersion.v2;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2019 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest;

import lombok.Data;
import lombok.EqualsAndHashCode;

@EqualsAndHashCode(callSuper = true)
@Data
public class KubernetesRollingRestartManifestDescription
extends KubernetesManifestOperationDescription {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2019 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.clouddriver.kubernetes.v2.op.handler;

import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesKind;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.security.KubernetesV2Credentials;

public interface CanRollingRestart {
KubernetesKind kind();

default void rollingRestart(KubernetesV2Credentials credentials, String namespace, String name) {
credentials.rollingRestart(kind(), namespace, name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@

@Component
public class KubernetesDaemonSetHandler extends KubernetesHandler
implements CanResize, CanPauseRollout, CanResumeRollout, CanUndoRollout, ServerGroupHandler {
implements CanResize,
CanPauseRollout,
CanResumeRollout,
CanUndoRollout,
CanRollingRestart,
ServerGroupHandler {

@Nonnull
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class KubernetesDeploymentHandler extends KubernetesHandler
CanPauseRollout,
CanResumeRollout,
CanUndoRollout,
CanRollingRestart,
ServerGroupManagerHandler {

private static final ImmutableSet<KubernetesApiVersion> SUPPORTED_API_VERSIONS =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public class KubernetesStatefulSetHandler extends KubernetesHandler
CanPauseRollout,
CanResumeRollout,
CanUndoRollout,
CanRollingRestart,
ServerGroupHandler {
@Nonnull
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,31 @@ public Void resumeRollout(
return null;
}

public Void rollingRestart(
KubernetesV2Credentials credentials, KubernetesKind kind, String namespace, String name) {
List<String> command = kubectlNamespacedAuthPrefix(credentials, namespace);

command.add("rollout");
command.add("restart");
command.add(kind.toString() + "/" + name);

JobResult<String> status = jobExecutor.runJob(new JobRequest(command));

if (status.getResult() != JobResult.Result.SUCCESS) {
throw new KubectlException(
"Failed to complete rolling restart of "
+ kind
+ "/"
+ name
+ " from "
+ namespace
+ ": "
+ status.getError());
}

return null;
}

public KubernetesManifest get(
KubernetesV2Credentials credentials, KubernetesKind kind, String namespace, String name) {
List<String> command =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2019 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.clouddriver.kubernetes.v2.op.manifest;

import com.netflix.spinnaker.clouddriver.data.task.Task;
import com.netflix.spinnaker.clouddriver.data.task.TaskRepository;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.KubernetesCoordinates;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.KubernetesResourceProperties;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesRollingRestartManifestDescription;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.op.handler.CanRollingRestart;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.op.handler.KubernetesHandler;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.security.KubernetesV2Credentials;
import com.netflix.spinnaker.clouddriver.orchestration.AtomicOperation;
import java.util.List;

public class KubernetesRollingRestartManifestOperation implements AtomicOperation<Void> {
private final KubernetesRollingRestartManifestDescription description;
private final KubernetesV2Credentials credentials;
private static final String OP_NAME = "ROLLING_RESTART_KUBERNETES_MANIFEST";

public KubernetesRollingRestartManifestOperation(
KubernetesRollingRestartManifestDescription description) {
this.description = description;
this.credentials = (KubernetesV2Credentials) description.getCredentials().getCredentials();
}

private static Task getTask() {
return TaskRepository.threadLocalTask.get();
}

@Override
public Void operate(List priorOutputs) {
getTask().updateStatus(OP_NAME, "Starting rolling restart operation...");
KubernetesCoordinates coordinates = description.getPointCoordinates();

getTask().updateStatus(OP_NAME, "Looking up resource properties...");
KubernetesResourceProperties properties =
credentials.getResourcePropertyRegistry().get(coordinates.getKind());
KubernetesHandler deployer = properties.getHandler();

if (!(deployer instanceof CanRollingRestart)) {
throw new IllegalArgumentException(
"Resource with " + coordinates + " does not support rolling restart");
}

CanRollingRestart canRollingRestart = (CanRollingRestart) deployer;

getTask().updateStatus(OP_NAME, "Calling rolling restart operation...");
canRollingRestart.rollingRestart(
credentials, coordinates.getNamespace(), coordinates.getName());

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,14 @@ public void resumeRollout(KubernetesKind kind, String namespace, String name) {
() -> jobExecutor.resumeRollout(this, kind, namespace, name));
}

public void rollingRestart(KubernetesKind kind, String namespace, String name) {
runAndRecordMetrics(
"rollingRestart",
kind,
namespace,
() -> jobExecutor.rollingRestart(this, kind, namespace, name));
}

public void patch(
KubernetesKind kind,
String namespace,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2019 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.clouddriver.kubernetes.v2.validator.manifest;

import static com.netflix.spinnaker.clouddriver.orchestration.AtomicOperations.ROLLING_RESTART_MANIFEST;

import com.netflix.spinnaker.clouddriver.deploy.DescriptionValidator;
import com.netflix.spinnaker.clouddriver.kubernetes.KubernetesOperation;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesRollingRestartManifestDescription;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.validator.KubernetesValidationUtil;
import com.netflix.spinnaker.clouddriver.security.AccountCredentialsProvider;
import com.netflix.spinnaker.clouddriver.security.ProviderVersion;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;

@KubernetesOperation(ROLLING_RESTART_MANIFEST)
@Component
public class KubernetesRollingRestartManifestValidator
extends DescriptionValidator<KubernetesRollingRestartManifestDescription> {
private final AccountCredentialsProvider provider;

@Autowired
public KubernetesRollingRestartManifestValidator(AccountCredentialsProvider provider) {
this.provider = provider;
}

@Override
public void validate(
List priorDescriptions,
KubernetesRollingRestartManifestDescription description,
Errors errors) {
KubernetesValidationUtil util =
new KubernetesValidationUtil("rollingRestartKubernetesManifest", errors);
if (!util.validateV2Credentials(
provider,
description.getAccount(),
description.getPointCoordinates().getKind(),
description.getPointCoordinates().getNamespace())) {
return;
}
}

@Override
public boolean acceptsVersion(ProviderVersion version) {
return version == ProviderVersion.v2;
}
}

0 comments on commit e076eba

Please sign in to comment.