Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(provider/kubernetes): depend on kubectl where possible #2041

Merged
merged 3 commits into from
Oct 31, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,12 @@

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

import io.kubernetes.client.models.V1DeleteOptions;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.Map;

@EqualsAndHashCode(callSuper = true)
@Data
public class KubernetesDeleteManifestDescription extends KubernetesManifestOperationDescription {
Map deleteOptions;
V1DeleteOptions options;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,16 @@

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

import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesKind;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.op.job.KubectlJobExecutor;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.security.KubernetesV2Credentials;
import com.netflix.spinnaker.clouddriver.model.ServerGroup.Capacity;
import io.kubernetes.client.models.V1DeleteOptions;

public interface CanDelete<T> {
Class<T> getDeleteOptionsClass();
void delete(KubernetesV2Credentials credentials, String namespace, String name, T deleteOptions);
public interface CanDelete {
KubernetesKind kind();
KubectlJobExecutor getJobExecutor();

default void delete(KubernetesV2Credentials credentials, String namespace, String name, V1DeleteOptions deleteOptions) {
getJobExecutor().delete(credentials, kind(), namespace, name, deleteOptions);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.netflix.spinnaker.clouddriver.kubernetes.v2.op.job.KubectlJobExecutor;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.security.KubernetesV2Credentials;
import com.netflix.spinnaker.clouddriver.model.Manifest.Status;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
Expand All @@ -39,6 +40,7 @@ public abstract class KubernetesDeployer {
@Autowired
private KubernetesCacheUtils cacheUtils;

@Getter
@Autowired
protected KubectlJobExecutor jobExecutor;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import org.springframework.stereotype.Component;

@Component
public class KubernetesDeploymentDeployer extends KubernetesDeployer implements CanResize, CanDelete<V1DeleteOptions> {
public class KubernetesDeploymentDeployer extends KubernetesDeployer implements CanResize, CanDelete {
@Override
public KubernetesKind kind() {
return KubernetesKind.DEPLOYMENT;
Expand Down Expand Up @@ -114,16 +114,6 @@ private Status status(V1beta2Deployment deployment) {

@Override
public void resize(KubernetesV2Credentials credentials, String namespace, String name, Capacity capacity) {
credentials.resizeDeployment(namespace, name, capacity.getDesired());
}

@Override
public Class<V1DeleteOptions> getDeleteOptionsClass() {
return V1DeleteOptions.class;
}

@Override
public void delete(KubernetesV2Credentials credentials, String namespace, String name, V1DeleteOptions deleteOptions) {
credentials.deleteDeployment(namespace, name, deleteOptions);
jobExecutor.scale(credentials, kind(), namespace, name, capacity.getDesired());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,11 @@
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.KubernetesSpinnakerKindMap.SpinnakerKind;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesKind;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesManifest;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.security.KubernetesV2Credentials;
import com.netflix.spinnaker.clouddriver.model.Manifest;
import com.netflix.spinnaker.clouddriver.model.Manifest.Status;
import io.kubernetes.client.models.V1DeleteOptions;
import org.springframework.stereotype.Component;

@Component
public class KubernetesIngressDeployer extends KubernetesDeployer implements CanDelete<V1DeleteOptions> {
public class KubernetesIngressDeployer extends KubernetesDeployer implements CanDelete {
@Override
public KubernetesKind kind() {
return KubernetesKind.INGRESS;
Expand All @@ -47,14 +44,4 @@ public SpinnakerKind spinnakerKind() {
public Status status(KubernetesManifest manifest) {
return Status.stable();
}

@Override
public Class<V1DeleteOptions> getDeleteOptionsClass() {
return V1DeleteOptions.class;
}

@Override
public void delete(KubernetesV2Credentials credentials, String namespace, String name, V1DeleteOptions deleteOptions) {
credentials.deleteIngress(namespace, name, deleteOptions);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import com.netflix.spinnaker.clouddriver.kubernetes.v2.security.KubernetesV2Credentials;
import com.netflix.spinnaker.clouddriver.model.Manifest.Status;
import com.netflix.spinnaker.clouddriver.model.ServerGroup.Capacity;
import io.kubernetes.client.models.V1DeleteOptions;
import io.kubernetes.client.models.V1beta1ReplicaSet;
import io.kubernetes.client.models.V1beta1ReplicaSetStatus;
import io.kubernetes.client.models.V1beta2ReplicaSet;
Expand All @@ -34,17 +33,12 @@
import java.util.Map;

@Component
public class KubernetesReplicaSetDeployer extends KubernetesDeployer implements CanResize, CanDelete<V1DeleteOptions> {
public class KubernetesReplicaSetDeployer extends KubernetesDeployer implements CanResize, CanDelete {
@Override
public KubernetesKind kind() {
return KubernetesKind.REPLICA_SET;
}

@Override
public Class<V1DeleteOptions> getDeleteOptionsClass() {
return V1DeleteOptions.class;
}

@Override
public boolean versioned() {
return true;
Expand Down Expand Up @@ -121,12 +115,7 @@ private Status status(V1beta2ReplicaSet replicaSet) {

@Override
public void resize(KubernetesV2Credentials credentials, String namespace, String name, Capacity capacity) {
credentials.resizeReplicaSet(namespace, name, capacity.getDesired());
}

@Override
public void delete(KubernetesV2Credentials credentials, String namespace, String name, V1DeleteOptions deleteOptions) {
credentials.deleteReplicaSet(namespace, name, deleteOptions);
jobExecutor.scale(credentials, KubernetesKind.REPLICA_SET, namespace, name, capacity.getDesired());
}

public static Map<String, String> getPodTemplateLabels(KubernetesManifest manifest) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import java.util.Map;

@Component
public class KubernetesServiceDeployer extends KubernetesDeployer implements CanDelete<Void> {
public class KubernetesServiceDeployer extends KubernetesDeployer implements CanDelete {
@Override
public KubernetesKind kind() {
return KubernetesKind.SERVICE;
Expand All @@ -50,16 +50,6 @@ public Status status(KubernetesManifest manifest) {
return Status.stable();
}

@Override
public Class<Void> getDeleteOptionsClass() {
return Void.class;
}

@Override
public void delete(KubernetesV2Credentials credentials, String namespace, String name, Void deleteOptions) {
credentials.deleteService(namespace, name);
}

public static Map<String, String> getSelector(KubernetesManifest manifest) {
switch (manifest.getApiVersion()) {
case V1:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesManifest;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesManifestList;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.security.KubernetesV2Credentials;
import io.kubernetes.client.models.V1DeleteOptions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -42,10 +43,10 @@ public class KubectlJobExecutor {
@Value("${kubernetes.kubectl.poll.minSleepMillis:100}")
Long minSleepMillis;

@Value("${kubernetes.kubectl.poll.maxSleepMillis:1000}")
@Value("${kubernetes.kubectl.poll.maxSleepMillis:2000}")
Long maxSleepMillis;

@Value("${kubernetes.kubectl.poll.timeout:10000}")
@Value("${kubernetes.kubectl.poll.timeoutMillis:100000}")
Long timeoutMillis;

@Value("${kubernetes.kubectl.poll.maxInterruptRetries:10}")
Expand All @@ -63,6 +64,57 @@ public class KubectlJobExecutor {
this.jobExecutor = jobExecutor;
}

public void delete(KubernetesV2Credentials credentials, KubernetesKind kind, String namespace, String name, V1DeleteOptions deleteOptions) {
List<String> command = kubectlNamespacedAuthPrefix(credentials, namespace);

command.add("delete");
command.add(kind.toString());
command.add(name);

// spinnaker generally accepts deletes of resources that don't exist
command.add("--ignore-not-found=true");

if (deleteOptions.isOrphanDependents() != null) {
command.add("--cascade=" + !deleteOptions.isOrphanDependents());
}

if (deleteOptions.getGracePeriodSeconds() != null) {
command.add("--grace-period=" + deleteOptions.getGracePeriodSeconds());
}

if (StringUtils.isNotEmpty(deleteOptions.getPropagationPolicy())) {
throw new IllegalArgumentException("Propagation policy is not yet supported as a delete option");
}

String jobId = jobExecutor.startJob(new JobRequest(command),
System.getenv(),
new ByteArrayInputStream(new byte[0]));

JobStatus status = backoffWait(jobId, credentials.isDebug());

if (status.getResult() != JobStatus.Result.SUCCESS) {
throw new KubectlException("Failed to delete " + kind + "/" + name + " from " + namespace + ": " + status.getStdErr());
}
}

public void scale(KubernetesV2Credentials credentials, KubernetesKind kind, String namespace, String name, int replicas) {
List<String> command = kubectlNamespacedAuthPrefix(credentials, namespace);

command.add("scale");
command.add(kind.toString() + "/" + name);
command.add("--replicas=" + replicas);

String jobId = jobExecutor.startJob(new JobRequest(command),
System.getenv(),
new ByteArrayInputStream(new byte[0]));

JobStatus status = backoffWait(jobId, credentials.isDebug());

if (status.getResult() != JobStatus.Result.SUCCESS) {
throw new KubectlException("Failed to scale " + kind + "/" + name + " from " + namespace + ": " + status.getStdErr());
}
}

public KubernetesManifest get(KubernetesV2Credentials credentials, KubernetesKind kind, String namespace, String name) {
List<String> command = kubectlNamespacedGet(credentials, kind, namespace);
command.add(name);
Expand All @@ -74,6 +126,10 @@ public KubernetesManifest get(KubernetesV2Credentials credentials, KubernetesKin
JobStatus status = backoffWait(jobId, credentials.isDebug());

if (status.getResult() != JobStatus.Result.SUCCESS) {
if (status.getStdErr().contains("(NotFound)")) {
return null;
}

throw new KubectlException("Failed to read " + kind + " from " + namespace + ": " + status.getStdErr());
}

Expand Down Expand Up @@ -180,14 +236,12 @@ private List<String> kubectlAuthPrefix(KubernetesV2Credentials credentials) {

String kubeconfigFile = credentials.getKubeconfigFile();
if (StringUtils.isNotEmpty(kubeconfigFile)) {
command.add("--kubeconfig");
command.add(kubeconfigFile);
command.add("--kubeconfig=" + kubeconfigFile);
}

String context = credentials.getContext();
if (StringUtils.isNotEmpty(context)) {
command.add("--context");
command.add(context);
command.add("--context=" + context);
}

return command;
Expand All @@ -199,8 +253,7 @@ private List<String> kubectlNamespacedAuthPrefix(KubernetesV2Credentials credent
namespace = credentials.getDefaultNamespace();
}

command.add("--namespace");
command.add(namespace);
command.add("--namespace=" + namespace);

return command;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,10 @@ public Void operate(List priorOutputs) {
CanDelete canDelete = (CanDelete) deployer;

getTask().updateStatus(OP_NAME, "Calling delete operation...");
Map deleteOptions = description.getDeleteOptions();
Object convertedDeleteOptions = deleteOptions == null ? null : mapper.convertValue(deleteOptions, (canDelete).getDeleteOptionsClass());
canDelete.delete(credentials,
coordinates.getNamespace(),
coordinates.getName(),
convertedDeleteOptions);
description.getOptions());

return null;
}
Expand Down
Loading