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): v2 pod logs #2099

Merged
merged 1 commit into from
Nov 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -19,27 +19,44 @@

import com.netflix.spinnaker.cats.cache.CacheData;
import com.netflix.spinnaker.clouddriver.kubernetes.KubernetesCloudProvider;
import com.netflix.spinnaker.clouddriver.kubernetes.security.KubernetesNamedAccountCredentials;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.caching.Keys;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.caching.agent.KubernetesCacheDataConverter;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.caching.view.model.KubernetesV2Instance;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.KubernetesSpinnakerKindMap;
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.op.job.KubectlJobExecutor;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.security.KubernetesV2Credentials;
import com.netflix.spinnaker.clouddriver.model.InstanceProvider;
import com.netflix.spinnaker.clouddriver.security.AccountCredentialsRepository;
import com.netflix.spinnaker.clouddriver.security.ProviderVersion;
import io.kubernetes.client.models.V1Container;
import io.kubernetes.client.models.V1Pod;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Optional;

@Component
@Slf4j
public class KubernetesV2InstanceProvider implements InstanceProvider<KubernetesV2Instance> {
private final KubernetesCacheUtils cacheUtils;
private final KubernetesSpinnakerKindMap kindMap;
private final AccountCredentialsRepository accountCredentialsRepository;
private final KubectlJobExecutor jobExecutor;

@Autowired
KubernetesV2InstanceProvider(KubernetesCacheUtils cacheUtils, KubernetesSpinnakerKindMap kindMap) {
KubernetesV2InstanceProvider(KubernetesCacheUtils cacheUtils,
KubernetesSpinnakerKindMap kindMap,
AccountCredentialsRepository accountCredentialsRepository,
KubectlJobExecutor jobExecutor) {
this.cacheUtils = cacheUtils;
this.kindMap = kindMap;
this.accountCredentialsRepository = accountCredentialsRepository;
this.jobExecutor = jobExecutor;
}

@Override
Expand Down Expand Up @@ -71,8 +88,46 @@ public KubernetesV2Instance getInstance(String account, String location, String
}

@Override
public String getConsoleOutput(String account, String location, String name) {
// todo(lwander)
return null;
public String getConsoleOutput(String account, String location, String fullName) {
KubernetesNamedAccountCredentials<KubernetesV2Credentials> credentials;
try {
credentials = (KubernetesNamedAccountCredentials) accountCredentialsRepository.getOne(account);
} catch (Exception e) {
log.warn("Failure getting account {}", account);
return null;
}

if (credentials == null || credentials.getProviderVersion() != ProviderVersion.v2) {
return null;
}

Pair<KubernetesKind, String> parsedName;
try {
parsedName = KubernetesManifest.fromFullResourceName(fullName);
} catch (Exception e) {
return null;
}

String name = parsedName.getRight();

V1Pod pod = KubernetesCacheDataConverter.getResource(
jobExecutor.get(credentials.getCredentials(), KubernetesKind.POD, location, name), V1Pod.class
);

StringBuilder result = new StringBuilder();

// Make live calls rather than abuse the cache for storing all logs
for (V1Container container : pod.getSpec().getContainers()) {
result.append("====== " + container.getName() + " ======\n\n");
try {
result.append(jobExecutor.logs(credentials.getCredentials(), location, name, container.getName()));
} catch (KubectlJobExecutor.KubectlException e) {
// Typically happens if the container/pod isn't running yet
result.append(e.getMessage());
}
result.append("\n\n");
}

return result.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,25 @@ public class KubectlJobExecutor {
this.jobExecutor = jobExecutor;
}

public String logs(KubernetesV2Credentials credentials, String namespace, String podName, String containerName) {
List<String> command = kubectlNamespacedAuthPrefix(credentials, namespace);
command.add("logs");
command.add(podName);
command.add("-c=" + containerName);

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 get logs from " + podName + "/" + containerName + " in " + namespace + ": " + status.getStdErr());
}

return status.getStdOut();
}

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

Expand Down