package com.nirima.jenkins.plugins.docker.client;
import com.cloudbees.plugins.credentials.Credentials;
import com.cloudbees.plugins.credentials.common.CertificateCredentials;
import com.cloudbees.plugins.credentials.common.StandardUsernamePasswordCredentials;
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientConfig;
import com.github.dockerjava.core.KeystoreSSLConfig;
import com.github.dockerjava.core.LocalDirectorySSLConfig;
import com.nirima.jenkins.plugins.docker.DockerCloud;
import com.nirima.jenkins.plugins.docker.utils.DockerDirectoryCredentials;
import hudson.security.ACL;
import jenkins.model.Jenkins;
import javax.annotation.Nullable;
import java.net.URI;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;
import static com.cloudbees.plugins.credentials.CredentialsMatchers.firstOrNull;
import static com.cloudbees.plugins.credentials.CredentialsMatchers.withId;
import static com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials;
import static com.github.dockerjava.core.DefaultDockerClientConfig.createDefaultConfigBuilder;
import static org.apache.commons.lang.StringUtils.isNotBlank;
/**
* @author lanwen (Merkushev Kirill)
*/
public class ClientConfigBuilderForPlugin {
private static final Logger LOGGER = Logger.getLogger(ClientConfigBuilderForPlugin.class.getName());
private DefaultDockerClientConfig.Builder config = createDefaultConfigBuilder();
private ClientConfigBuilderForPlugin() {
}
public static ClientConfigBuilderForPlugin dockerClientConfig() {
return new ClientConfigBuilderForPlugin();
}
/**
* Provides ready to use docker client with information from docker cloud
*
* @param cloud docker cloud with info about url, version, creds and timeout
*
* @return docker-java client
*/
public ClientConfigBuilderForPlugin forCloud(DockerCloud cloud) {
LOGGER.log(Level.FINE, "Building connection to docker host \"{0}\" at: {1}",
new Object[]{cloud.getDisplayName(), cloud.getServerUrl()});
forServer(cloud.getServerUrl(), cloud.version);
return withCredentials(cloud.credentialsId);
}
/**
* Method to setup url and docker-api version. Convenient for test-connection purposes and quick requests
*
* @param uri docker server uri
* @param version docker-api version
*
* @return this builder
*/
public ClientConfigBuilderForPlugin forServer(String uri, @Nullable String version) {
config.withDockerHost(URI.create(uri).toString())
.withApiVersion(version);
return this;
}
/**
* Sets username and password or ssl config by credentials id
*
* @param credentialsId credentials to find in jenkins
*
* @return docker-java client
*/
public ClientConfigBuilderForPlugin withCredentials(String credentialsId) {
if (isNotBlank(credentialsId)) {
Credentials credentials = lookupSystemCredentials(credentialsId);
if (credentials instanceof CertificateCredentials) {
CertificateCredentials certificateCredentials = (CertificateCredentials) credentials;
config.withCustomSslConfig(new KeystoreSSLConfig(
certificateCredentials.getKeyStore(),
certificateCredentials.getPassword().getPlainText()
));
}
else if( credentials instanceof DockerDirectoryCredentials) {
DockerDirectoryCredentials ddc = (DockerDirectoryCredentials)credentials;
config.withCustomSslConfig( new LocalDirectorySSLConfig(ddc.getPath()));
} else if (credentials instanceof StandardUsernamePasswordCredentials) {
StandardUsernamePasswordCredentials usernamePasswordCredentials =
((StandardUsernamePasswordCredentials) credentials);
// TODO: Don't think this makes sense. API change in docker-java
// has exposed that this probably wasn't the intent!
config.withRegistryUsername(usernamePasswordCredentials.getUsername());
config.withRegistryPassword(usernamePasswordCredentials.getPassword().getPlainText());
}
}
return this;
}
/**
* Build the config
*/
public DockerClientConfig build() {
return config.build();
}
/**
* Shortcut to build an actual client.
*
* Consider if you actually want to do this or alternatively
* build the config then build the client, as if your activity is on a remote
* node, the client will fail to serialize.
*/
public DockerClient buildClient() {
return ClientBuilderForPlugin.builder().withDockerClientConfig(build()).build();
}
/**
* For test purposes mostly
*
* @return docker config builder
*/
/* package */ DefaultDockerClientConfig.Builder config() {
return config;
}
/**
* Util method to find credential by id in jenkins
*
* @param credentialsId credentials to find in jenkins
*
* @return {@link CertificateCredentials} or {@link StandardUsernamePasswordCredentials} expected
*/
private static Credentials lookupSystemCredentials(String credentialsId) {
return firstOrNull(
lookupCredentials(
Credentials.class,
Jenkins.getInstance(),
ACL.SYSTEM,
Collections.<DomainRequirement>emptyList()
),
withId(credentialsId)
);
}
}