blob: 889af0bd758707900b1254d94a10322e33485458 [file] [log] [blame]
package org.csanchez.jenkins.plugins.kubernetes;
import com.cloudbees.plugins.credentials.CredentialsMatchers;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.common.StandardCredentials;
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import com.cloudbees.plugins.credentials.common.UsernamePasswordCredentials;
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import hudson.AbortException;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.AbstractProject;
import hudson.model.Item;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.security.ACL;
import hudson.tasks.BuildWrapperDescriptor;
import hudson.util.ListBoxModel;
import hudson.util.Secret;
import jenkins.model.Jenkins;
import jenkins.tasks.SimpleBuildWrapper;
import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Collections;
/**
* @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
*/
public class KubectlBuildWrapper extends SimpleBuildWrapper {
private final String serverUrl;
private final String credentialsId;
@DataBoundConstructor
public KubectlBuildWrapper(@Nonnull String serverUrl, @Nonnull String credentialsId) {
this.serverUrl = serverUrl;
this.credentialsId = credentialsId;
}
public String getServerUrl() {
return serverUrl;
}
public String getCredentialsId() {
return credentialsId;
}
@Override
public void setUp(Context context, Run<?, ?> build, FilePath workspace, Launcher launcher, TaskListener listener, EnvVars initialEnvironment) throws IOException, InterruptedException {
FilePath configFile = workspace.createTempFile(".kube", "config");
int status = launcher.launch()
.cmdAsSingleString("kubectl config --kubeconfig=" + configFile.getRemote() + " set-cluster k8s --server=" + serverUrl + " --insecure-skip-tls-verify=true")
.join();
if (status != 0) throw new IOException("Failed to run kubectl config "+status);
final StandardCredentials c = getCredentials();
String login;
if (c == null) {
throw new AbortException("No credentials defined to setup Kubernetes CLI");
} else if (c instanceof TokenProducer) {
login = "--token=" + ((TokenProducer) c).getToken(serverUrl, null, true);
} else if (c instanceof UsernamePasswordCredentials) {
UsernamePasswordCredentials upc = (UsernamePasswordCredentials) c;
login = "--username=" + upc.getUsername() + " --password=" + Secret.toString(upc.getPassword());
} else {
throw new AbortException("Unsupported Credentials type " + c.getClass().getName());
}
status = launcher.launch()
.cmdAsSingleString("kubectl config --kubeconfig=" + configFile.getRemote() + " set-credentials cluster-admin " + login)
.masks(false, false, false, false, false, false, true)
.join();
if (status != 0) throw new IOException("Failed to run kubectl config "+status);
status = launcher.launch()
.cmdAsSingleString("kubectl config --kubeconfig=" + configFile.getRemote() + " set-context k8s --cluster=k8s --user=cluster-admin")
.join();
if (status != 0) throw new IOException("Failed to run kubectl config "+status);
status = launcher.launch()
.cmdAsSingleString("kubectl config --kubeconfig=" + configFile.getRemote() + " use-context k8s")
.join();
if (status != 0) throw new IOException("Failed to run kubectl config "+status);
context.setDisposer(new CleanupDisposer(configFile.getRemote()));
context.env("KUBECONFIG", configFile.getRemote());
}
/**
* Get the {@link StandardCredentials}.
*
* @return the credentials matching the {@link #credentialsId} or {@code null} is {@code #credentialsId} is blank
* @throws AbortException if no {@link StandardCredentials} matching {@link #credentialsId} is found
*/
@CheckForNull
private StandardCredentials getCredentials() throws AbortException {
if (StringUtils.isBlank(credentialsId)) {
return null;
}
StandardCredentials result = CredentialsMatchers.firstOrNull(
CredentialsProvider.lookupCredentials(StandardCredentials.class,
Jenkins.getInstance(), ACL.SYSTEM, Collections.<DomainRequirement>emptyList()),
CredentialsMatchers.withId(credentialsId)
);
if (result == null) {
throw new AbortException("No credentials found for id \"" + credentialsId + "\"");
}
return result;
}
@Extension
public static class DescriptorImpl extends BuildWrapperDescriptor {
@Override
public boolean isApplicable(AbstractProject<?, ?> item) {
return true;
}
@Override
public String getDisplayName() {
return "Setup Kubernetes CLI (kubectl)";
}
public ListBoxModel doFillCredentialsIdItems(@AncestorInPath Item item, @QueryParameter String serverUrl) {
return new StandardListBoxModel()
.withEmptySelection()
.withMatching(
CredentialsMatchers.anyOf(
CredentialsMatchers.instanceOf(StandardUsernamePasswordCredentials.class),
CredentialsMatchers.instanceOf(TokenProducer.class)
),
CredentialsProvider.lookupCredentials(
StandardCredentials.class,
item,
null,
URIRequirementBuilder.fromUri(serverUrl).build()
)
);
}
}
private static class CleanupDisposer extends Disposer {
private String configFile;
public CleanupDisposer(String configFile) {
this.configFile = configFile;
}
@Override
public void tearDown(Run<?, ?> build, FilePath workspace, Launcher launcher, TaskListener listener) throws IOException, InterruptedException {
workspace.child(configFile).delete();
}
}
}