Adding basic docker command capability to docker activity plugin.
Project: http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/commit/d4be6805 Tree: http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/tree/d4be6805 Diff: http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/diff/d4be6805 Branch: refs/heads/docker Commit: d4be680580f7509c57cc07bb6c3a4dcf3c1155b4 Parents: 689b6d2 Author: Nadeesh Dilanga <[email protected]> Authored: Fri Jun 24 01:51:04 2016 -0400 Committer: Nadeesh Dilanga <[email protected]> Committed: Fri Jun 24 01:51:04 2016 -0400 ---------------------------------------------------------------------- .../activities/docker/DockerActivity.java | 92 +++++++-- .../docker/DockerContainerConfiguration.java | 31 +++ .../DockerContainerConfigurationImpl.java | 198 +++++++++++++++--- .../activities/docker/DockerHttpResponse.java | 51 ----- .../activities/docker/DockerRemoteConfig.java | 104 ++++++++++ .../taverna/activities/docker/RESTUtil.java | 202 ------------------- .../taverna/activities/docker/RemoteClient.java | 167 +++++++++++++++ .../docker/test/TestConfigurationManager.java | 35 ++++ .../docker/test/TestCreateContainer.java | 44 ---- .../docker/test/TestDockerCommands.java | 101 ++++++++++ 10 files changed, 683 insertions(+), 342 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d4be6805/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerActivity.java ---------------------------------------------------------------------- diff --git a/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerActivity.java b/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerActivity.java index 4cae049..aff0115 100644 --- a/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerActivity.java +++ b/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerActivity.java @@ -19,6 +19,12 @@ package org.apache.taverna.activities.docker; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectImageResponse; +import org.apache.log4j.Logger; import org.apache.taverna.invocation.InvocationContext; import org.apache.taverna.reference.ErrorDocument; import org.apache.taverna.reference.ReferenceService; @@ -35,49 +41,95 @@ import java.util.Map; */ public class DockerActivity extends AbstractAsynchronousActivity<JsonNode> { - private JsonNode activityConfig; - private DockerContainerConfigurationImpl containerConfiguration; + private JsonNode json; - public DockerActivity(DockerContainerConfigurationImpl containerConfiguration) { + private DockerContainerConfiguration containerConfiguration; + + private static final String ACTION = "action"; + + private static final String INSPECT = "inspect"; + + private static final String CREATE_CONTAINER = "create-container"; + + private static final String START_CONTAINER = "start-container"; + + private static final String STOP_CONTAINER = "stop-container"; + + private static final String LIST_CONTAINERS = "list-containers"; + + private static final String OUT_CONTAINER_ID = "container-id"; + + private static final String OUT_IMAGE_ID = "container-id"; + + private static final String OUT_IMAGE_AUTHOR = "image-author"; + + private static final String OUT_IMAGE_CONTAINER = "image-container"; + + private static final String IN_IMAGE_NAME = "image-name"; + + private static Logger LOG = Logger.getLogger(DockerActivity.class); + + + public DockerActivity(DockerContainerConfiguration containerConfiguration) { this.containerConfiguration = containerConfiguration; } @Override - public void configure(JsonNode activityConfig) throws ActivityConfigurationException { - this.activityConfig = activityConfig; + public void configure(JsonNode json) throws ActivityConfigurationException { + this.json = json; } @Override public JsonNode getConfiguration() { - return activityConfig; + return json; } @Override - public void executeAsynch(Map<String, T2Reference> map, final AsynchronousActivityCallback callback) { + public void executeAsynch(final Map<String, T2Reference> map, final AsynchronousActivityCallback callback) { callback.requestRun(new Runnable() { @Override public void run() { + Map<String, T2Reference> outputs = new HashMap<String, T2Reference>(); T2Reference responseBodyRef = null; - InvocationContext context = callback.getContext(); ReferenceService referenceService = context.getReferenceService(); + String action = map.get(ACTION).getLocalPart(); - DockerHttpResponse response = RESTUtil.createContainer(containerConfiguration); - if(response != null && response.getStatusCode() == DockerHttpResponse.HTTP_201_CODE){ - responseBodyRef = referenceService.register(response.getBody(), 0, true, context); - } else { - ErrorDocument errorDocument = referenceService.getErrorDocumentService().registerError(response.getBody(),0,context); - responseBodyRef = referenceService.register(errorDocument, 0, true, context); - } + JsonNodeFactory factory = new ObjectMapper().getNodeFactory(); + ObjectNode outJson = factory.objectNode(); - outputs.put("response_body", responseBodyRef); - T2Reference statusRef = referenceService.register(response.getStatusCode(), 0, true, context); - outputs.put("response_code", statusRef); - //TODO add any more useful parameters to the output + RemoteClient remoteClient = new RemoteClient(containerConfiguration); + try { + if (CREATE_CONTAINER.equalsIgnoreCase(action)) { - callback.receiveResult(outputs, new int[0]); + CreateContainerResponse response = remoteClient.createContainer(); + outJson.put(OUT_CONTAINER_ID, response.getId()); + + } else if (INSPECT.equalsIgnoreCase(action)) { + + String imageName = map.get(IN_IMAGE_NAME).getLocalPart(); + InspectImageResponse response = remoteClient.inspect(imageName); + outJson.put(OUT_IMAGE_ID, response.getId()); + outJson.put(OUT_IMAGE_AUTHOR, response.getAuthor()); + outJson.put(OUT_IMAGE_CONTAINER, response.getContainer()); + } else if (START_CONTAINER.equalsIgnoreCase(action)) { + // TODO + } else if (STOP_CONTAINER.equalsIgnoreCase(action)) { + // TODO + } else if (LIST_CONTAINERS.equalsIgnoreCase(action)) { + // TODO + } + //TODO add any more supporting actions + responseBodyRef = referenceService.register(outJson.toString(), 0, true, context); + } catch (Exception e){ + String log = "Error occurred while executing remote docker commands " + e.getMessage(); + LOG.error(log ,e); + responseBodyRef = referenceService.register("{\"error\",\"" + log + "\"}", 0, true, context); + } + outputs.put("response_body", responseBodyRef); + callback.receiveResult(outputs, new int[0]); } }); } http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d4be6805/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerContainerConfiguration.java ---------------------------------------------------------------------- diff --git a/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerContainerConfiguration.java b/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerContainerConfiguration.java new file mode 100644 index 0000000..526fdc0 --- /dev/null +++ b/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerContainerConfiguration.java @@ -0,0 +1,31 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 org.apache.taverna.activities.docker; + +public interface DockerContainerConfiguration { + + public String getName(); + + public String getImage(); + + public String getCmd(); + + //TODO add all remaining getters + +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d4be6805/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerContainerConfigurationImpl.java ---------------------------------------------------------------------- diff --git a/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerContainerConfigurationImpl.java b/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerContainerConfigurationImpl.java index 8a4a379..0f3380c 100644 --- a/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerContainerConfigurationImpl.java +++ b/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerContainerConfigurationImpl.java @@ -20,6 +20,8 @@ package org.apache.taverna.activities.docker; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.dockerjava.api.model.*; +import com.github.dockerjava.core.command.CreateContainerCmdImpl; import org.apache.taverna.configuration.AbstractConfigurable; import org.apache.taverna.configuration.Configurable; import org.apache.taverna.configuration.ConfigurationManager; @@ -30,68 +32,214 @@ import java.util.List; import java.util.Map; import java.util.Set; -public class DockerContainerConfigurationImpl extends AbstractConfigurable { +public class DockerContainerConfigurationImpl extends AbstractConfigurable implements DockerContainerConfiguration{ /** - * Key for Remote host + * String Values */ - public static final String CONTAINER_REMOTE_HOST = "key-cnt-host"; + public static final String NAME = "name"; + + public static final String HOST_NAME = "hostName"; + + public static final String DOMAIN_NAME = "domainName"; + + public static final String USER = "user"; + + public static final String IMAGE = "image"; + + public static final String WORKING_DIR = "workingDir"; + + public static final String MAC_ADDRESS = "macAddress"; + + public static final String STOP_SIGNAL = "stopSignal"; + + public static final String IPV4_ADDRESS = "ipv4Address"; + + public static final String IPV6_ADDRESS = "ipv6Address"; /** - * Key for transport protocol + * Boolean values */ - public static final String PROTOCOL = "key-cnt-protocol"; + + public static final String ATTACH_STDIN = "attachStdin"; + + public static final String ATTACH_STDOUT = "attachStdout"; + + public static final String ATTACH_STDERR = "attachStderr"; + + public static final String TTY = "tty"; + + public static final String STDIN_OPEN = "stdinOpen"; + + public static final String STDIN_ONCE = "stdInOnce"; + + public static final String NETWORK_DISABLED = "networkDisabled"; /** - * Key for Remote port + * String Arrays */ - public static final String CONTAINER_REMOTE_PORT = "key-cnt-port"; + public static final String PORT_SPECS = "portSpecs"; + + public static final String ENV = "env"; + + public static final String CMD = "cmd"; + + public static final String ENTRY_POINT = "entrypoint"; /** - * Key for create container payload. Here we accept entire JSON payload as the value of this key in hash map. + * Type Volumes[] */ - public static final String CONTAINER_CREATE_PAYLOAD = "key-cnt-create-payload"; + public static final String VOLUMES = "volumes"; /** - * Docker remote REST resource path for creating a container + * Type Bindings[] */ - public static final String CREATE_CONTAINER_RESOURCE_PATH = "/containers/create"; + public static final String BINDINGS = "bindings"; /** - * Identifier for Http over SSL protocol + * List<String> aliases */ - public static final String HTTP_OVER_SSL = "https"; + public static final String ALIASES = "aliases"; /** - * Transport protocol + * Type ExposedPorts[] */ - private String protocol = "http"; + public static final String EXPOSED_PORTS = "exposedPorts"; + /** + * Type Map<String,String> + */ + public static final String LABELS = "labels"; + + /** + * Type HostConfig + */ + public static final String HOST_CONFIG = "hostConfig"; + + /** + * Type CreateContainerCmdImpl.NetworkingConfig + */ + public static final String NETWORKING_CONFIG = "networkingConfig"; public DockerContainerConfigurationImpl(ConfigurationManager configurationManager){ super(configurationManager); + } + + public DockerContainerConfigurationImpl(){ + super(null); + } + + public String getName() { + return this.getInternalPropertyMap().get(NAME); + } + + public String getHostName() { + return HOST_NAME; + } + + public String getDomainName() { + return DOMAIN_NAME; + } + + public String getUser() { + return USER; + } + + public String getImage() { + return this.getInternalPropertyMap().get(IMAGE); + } + + public String getWorkingDir() { + return WORKING_DIR; + } + + public String getMacAddress() { + return MAC_ADDRESS; + } + + public String getStopSignal() { + return STOP_SIGNAL; + } + + public String getIpv4Address() { + return IPV4_ADDRESS; + } + + public String getIpv6Address() { + return IPV6_ADDRESS; + } + + public String getAttachStdin() { + return ATTACH_STDIN; + } + + public String getAttachStdout() { + return ATTACH_STDOUT; + } + + public String getAttachStderr() { + return ATTACH_STDERR; + } + + public String getTty() { + return TTY; + } + + public String getStdinOpen() { + return STDIN_OPEN; + } + + public String getStdinOnce() { + return STDIN_ONCE; + } + + public String getNetworkDisabled() { + return NETWORK_DISABLED; + } + + public String getPortSpecs() { + return PORT_SPECS; + } + + public String getEnv() { + return ENV; + } + + public String getCmd() { + return this.getInternalPropertyMap().get(CMD); + } + + public String getEntryPoint() { + return ENTRY_POINT; + } + + public String getVolumes() { + return VOLUMES; + } + public String getBindings() { + return BINDINGS; } - public String getContainerHost() { - return getInternalPropertyMap().get(CONTAINER_REMOTE_HOST); + public String getAliases() { + return ALIASES; } - public String getProtocol() { - return getInternalPropertyMap().get(PROTOCOL); + public String getExposedPorts() { + return EXPOSED_PORTS; } - public int getRemoteAPIPort() { - return Integer.parseInt(getInternalPropertyMap().get(CONTAINER_REMOTE_PORT)); + public String getLabels() { + return LABELS; } - public JsonNode getCreateContainerPayload() throws IOException { - return new ObjectMapper().readTree(getInternalPropertyMap().get(CONTAINER_CREATE_PAYLOAD)); + public String getHostConfig() { + return HOST_CONFIG; } - public String getCreateContainerURL() { - return getProtocol() + "://" + getContainerHost() + ":" + getRemoteAPIPort() + CREATE_CONTAINER_RESOURCE_PATH; + public String getNetworkingConfig() { + return NETWORKING_CONFIG; } @Override http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d4be6805/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerHttpResponse.java ---------------------------------------------------------------------- diff --git a/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerHttpResponse.java b/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerHttpResponse.java deleted file mode 100644 index 5ac5b8e..0000000 --- a/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerHttpResponse.java +++ /dev/null @@ -1,51 +0,0 @@ -/* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you 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 org.apache.taverna.activities.docker; - -import org.apache.http.Header; - -public class DockerHttpResponse { - - public static final int HTTP_201_CODE = 201; - - private Header[] headers; - - private int statusCode; - - private String body; - - public DockerHttpResponse(Header[] headers, int statusCode, String body) { - this.headers = headers; - this.statusCode = statusCode; - this.body = body; - } - - public Header[] getHeaders() { - return headers; - } - - public int getStatusCode() { - return statusCode; - } - - public String getBody() { - return body; - } -} http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d4be6805/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerRemoteConfig.java ---------------------------------------------------------------------- diff --git a/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerRemoteConfig.java b/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerRemoteConfig.java new file mode 100644 index 0000000..3999253 --- /dev/null +++ b/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/DockerRemoteConfig.java @@ -0,0 +1,104 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 org.apache.taverna.activities.docker; + +public class DockerRemoteConfig { + + private String dockerHost; + private String registryUsername; + private String registryPassword; + private String registryEmail; + private String registryUrl; + private String dockerConfig; + private String dockerCertPath; + private boolean dockerTlsVerify; + private String apiVersion = "1.21"; + + public String getDockerHost() { + return dockerHost; + } + + public void setDockerHost(String dockerHost) { + this.dockerHost = dockerHost; + } + + public String getRegistryUsername() { + return registryUsername; + } + + public void setRegistryUsername(String registryUsername) { + this.registryUsername = registryUsername; + } + + public String getRegistryPassword() { + return registryPassword; + } + + public void setRegistryPassword(String registryPassword) { + this.registryPassword = registryPassword; + } + + public String getRegistryEmail() { + return registryEmail; + } + + public void setRegistryEmail(String registryEmail) { + this.registryEmail = registryEmail; + } + + public String getRegistryUrl() { + return registryUrl; + } + + public void setRegistryUrl(String registryUrl) { + this.registryUrl = registryUrl; + } + + public String getDockerConfig() { + return dockerConfig; + } + + public void setDockerConfig(String dockerConfig) { + this.dockerConfig = dockerConfig; + } + + public String getDockerCertPath() { + return dockerCertPath; + } + + public void setDockerCertPath(String dockerCertPath) { + this.dockerCertPath = dockerCertPath; + } + + public boolean isDockerTlsVerify() { + return dockerTlsVerify; + } + + public void setDockerTlsVerify(boolean dockerTlsVerify) { + this.dockerTlsVerify = dockerTlsVerify; + } + + public String getApiVersion() { + return apiVersion; + } + + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d4be6805/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/RESTUtil.java ---------------------------------------------------------------------- diff --git a/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/RESTUtil.java b/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/RESTUtil.java deleted file mode 100644 index 0c24859..0000000 --- a/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/RESTUtil.java +++ /dev/null @@ -1,202 +0,0 @@ -/* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you 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 org.apache.taverna.activities.docker; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.SingleClientConnManager; -import org.apache.http.message.BasicHeader; -import org.apache.log4j.Logger; - -import javax.net.ssl.SSLContext; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.MalformedURLException; -import java.net.URL; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -public class RESTUtil { - - /** - * Http header name for content type - */ - private static final String CONTENT_TYPE = "Content-Type"; - - /** - * Http content type value for JSON messages. - */ - private static final String JSON_CONTENT_TYPE = "application/json"; - - /** - * - */ - private static final String DEFAULT_ERROR_MSG= "{\"type\";\"Internal server error\"}"; - - - /** - * Logger - */ - private static Logger LOG = Logger.getLogger(RESTUtil.class); - - - public static DockerHttpResponse createContainer(DockerContainerConfigurationImpl dockerContainerConfigurationImpl) { - String errMsg; - try { - ClientConnectionManager connectionManager = null; - URL url = new URL(dockerContainerConfigurationImpl.getCreateContainerURL()); - if(DockerContainerConfigurationImpl.HTTP_OVER_SSL.equalsIgnoreCase(dockerContainerConfigurationImpl.getProtocol())) { - org.apache.http.conn.ssl.SSLSocketFactory factory = new org.apache.http.conn.ssl.SSLSocketFactory(SSLContext.getDefault()); - Scheme https = new Scheme(dockerContainerConfigurationImpl.getProtocol(), factory, url.getPort()); - SchemeRegistry schemeRegistry = new SchemeRegistry(); - schemeRegistry.register(https); - connectionManager = new SingleClientConnManager(null, schemeRegistry); - } - - Map<String,String> headers = new HashMap<String,String>(); - headers.put(CONTENT_TYPE, JSON_CONTENT_TYPE); - DockerHttpResponse response = doPost(connectionManager, dockerContainerConfigurationImpl.getCreateContainerURL(), headers, dockerContainerConfigurationImpl.getCreateContainerPayload()); - if(response.getStatusCode() == DockerHttpResponse.HTTP_201_CODE){ - JsonNode node = getJson(response.getBody()); - LOG.info(String.format("Successfully created Docker container id: %s ", getDockerId(node))); - return response; - } - - } catch (MalformedURLException e1) { - errMsg = String.format("Malformed URL encountered. This can be due to invalid URL parts. " + - "Docker Host=%s, Port=%d and Resource Path=%s", - dockerContainerConfigurationImpl.getContainerHost(), - dockerContainerConfigurationImpl.getRemoteAPIPort(), - DockerContainerConfigurationImpl.CREATE_CONTAINER_RESOURCE_PATH); - LOG.error(errMsg, e1); - } catch (NoSuchAlgorithmException e2) { - errMsg = "Failed to create SSLContext for invoking the REST service over https." + e2.getMessage(); - LOG.error(dockerContainerConfigurationImpl); - } catch (IOException e3) { - errMsg = "Error occurred while reading the docker http response " + e3.getMessage(); - LOG.error(errMsg, e3); - } - return null; - } - - private static DockerHttpResponse doPost(ClientConnectionManager connectionManager, String url, Map<String, String> headers, JsonNode payload) { - HttpClient httpClient = null; - HttpResponse response = null; - DockerHttpResponse dockerResponse = null; - HttpPost httpPost = null; - try { - httpPost = new HttpPost(url); - HttpEntity entity = new StringEntity(payload.toString()); - httpPost.setEntity(entity); - for (Map.Entry<String, String> entry : headers.entrySet()) { - httpPost.setHeader(new BasicHeader(entry.getKey(), entry.getValue())); - } - httpClient = connectionManager != null ? new DefaultHttpClient(connectionManager, null):HttpClients.createDefault();; - - response = httpClient.execute(httpPost); - if (response != null) { - dockerResponse = new DockerHttpResponse(response.getAllHeaders(), response.getStatusLine().getStatusCode(),readBody(response.getEntity()).toString()); - } - } catch (IOException e) { - e.printStackTrace(); - LOG.error("Failed to complete Http POST invocation", e); - dockerResponse = new DockerHttpResponse(new Header[]{new BasicHeader( - CONTENT_TYPE, JSON_CONTENT_TYPE)}, - 500, - "{\"error\":\"internal server error\", \"message\":\""+ e.getMessage() +"\"}"); - } finally { - - if(httpPost != null){ - httpPost.releaseConnection(); - } - if (httpClient != null) { - if(httpClient instanceof DefaultHttpClient) { - ((DefaultHttpClient) httpClient).close(); - } else if(httpClient instanceof CloseableHttpClient){ - try { - ((CloseableHttpClient) httpClient).close(); - } catch (IOException ignore) {} - } - } - if (response != null) { - try { - if(response instanceof CloseableHttpResponse) { - ((CloseableHttpResponse)response).close(); - } - } catch (IOException ignore) {} - } - } - return dockerResponse; - } - - private static StringBuilder readBody(HttpEntity entity) throws IOException { - String charset = null; - String contentType = entity.getContentType().getValue().toLowerCase(); - String[] contentTypeParts = contentType.split(";"); - for (String contentTypePart : contentTypeParts) { - contentTypePart = contentTypePart.trim(); - if (contentTypePart.startsWith("charset=")) { - charset = contentTypePart.substring("charset=".length()); - } - } - BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), charset != null ? charset : "UTF-8")); - String str; - StringBuilder responseBuilder = new StringBuilder(); - while ((str = reader.readLine()) != null) { - responseBuilder.append(str + "\n"); - } - return responseBuilder; - } - - private static JsonNode getJson(String s) throws IOException { - ObjectMapper mapper = new ObjectMapper(); - return mapper.readTree(s); - } - - private static String getDockerId(JsonNode node){ - String dockerId = null; - Iterator<JsonNode> itr = node.elements(); - while(itr.hasNext()){ - JsonNode child = itr.next(); - if("id".equalsIgnoreCase(child.textValue())){ - dockerId = child.textValue(); - break; - } - } - return dockerId; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d4be6805/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/RemoteClient.java ---------------------------------------------------------------------- diff --git a/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/RemoteClient.java b/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/RemoteClient.java new file mode 100644 index 0000000..3c7c030 --- /dev/null +++ b/taverna-docker-activity/src/main/java/org/apache/taverna/activities/docker/RemoteClient.java @@ -0,0 +1,167 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 org.apache.taverna.activities.docker; + + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.command.CreateContainerCmd; +import com.github.dockerjava.api.command.CreateContainerResponse; +import com.github.dockerjava.api.command.InspectImageResponse; +import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.api.model.Info; +import com.github.dockerjava.api.model.SearchItem; +import com.github.dockerjava.core.DockerClientBuilder; +import com.github.dockerjava.core.DockerClientConfig; +import org.apache.log4j.Logger; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; + +public class RemoteClient { + + /** + * Docker client + */ + private DockerClient dockerClient; + + private DockerContainerConfiguration containerConfig; + + private DockerRemoteConfig remoteConfig; + + private static Logger LOG = Logger.getLogger(RemoteClient.class); + + + public RemoteClient(DockerContainerConfiguration containerConfig) { + this.containerConfig = containerConfig; + } + + public DockerRemoteConfig getRemoteConfig() { + return remoteConfig; + } + + public void init(DockerRemoteConfig remoteConfig) { + this.remoteConfig = remoteConfig; + DockerClientConfig config = config(); + dockerClient = DockerClientBuilder.getInstance(config).build(); + } + + /** + * Login to the Docker + * @return Status of the login response + */ + public String login(){ + return dockerClient.authCmd().exec().getStatus(); + } + + /** + * + * @param name Image Name/Id + * @return Complete docker response + */ + public InspectImageResponse inspect(String name){ + return dockerClient.inspectImageCmd(name).exec(); + } + + /** + * This creates a container based on the inout params. Docker command "docker ps -a" will show you all created containers. + * @return complete docker response + */ + public CreateContainerResponse createContainer(){ + CreateContainerResponse response = buildCreateContainerCmd().exec(); + return response; + } + + /** + * @return List all containers + */ + public List<Container> listContainers(){ + return dockerClient.listContainersCmd().withShowAll(true).exec(); + } + + /** + * @return Docker Info response from docker + */ + public Info info(){ + return dockerClient.infoCmd().exec(); + } + + /** + * @param containerId To be start + */ + public void startContainer(String containerId){ + dockerClient.startContainerCmd(containerId).exec(); + } + + /** + * @param containerId to be stopped + */ + public void stopContainer(String containerId){ + dockerClient.stopContainerCmd(containerId).exec(); + } + + /** + * @param term Search term for images (ex: image name) + * @return List of Images + */ + public List<SearchItem> searchImages(String term){ + return dockerClient.searchImagesCmd(term).exec(); + } + + private CreateContainerCmd buildCreateContainerCmd(){ + CreateContainerCmd createCmd = dockerClient.createContainerCmd(containerConfig.getImage()); + createCmd.withCmd(containerConfig.getCmd()); + createCmd.withName(containerConfig.getName()); + return createCmd; + } + + private DockerClientConfig config() { + DockerClientConfig.DockerClientConfigBuilder builder = DockerClientConfig.createDefaultConfigBuilder(); + builder.withDockerHost(remoteConfig.getDockerHost()); + builder.withDockerTlsVerify(remoteConfig.isDockerTlsVerify()); + builder.withApiVersion(remoteConfig.getApiVersion()); + + if(remoteConfig.getDockerCertPath() != null){ + builder.withDockerCertPath(remoteConfig.getDockerCertPath()); + } + + if(remoteConfig.getDockerConfig() != null){ + builder.withDockerConfig(remoteConfig.getDockerConfig()); + } + + if(remoteConfig.getRegistryUrl() != null){ + builder.withRegistryUrl(remoteConfig.getRegistryUrl()); + } + + if(remoteConfig.getRegistryUsername() != null){ + builder.withRegistryUsername(remoteConfig.getRegistryUsername()); + } + + if(remoteConfig.getRegistryPassword() != null){ + builder.withRegistryPassword(remoteConfig.getRegistryPassword()); + } + + if(remoteConfig.getRegistryEmail() != null){ + builder.withRegistryEmail(remoteConfig.getRegistryEmail()); + } + + return builder.build(); + } + + } http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d4be6805/taverna-docker-activity/src/test/java/org/apache/taverna/activities/docker/test/TestConfigurationManager.java ---------------------------------------------------------------------- diff --git a/taverna-docker-activity/src/test/java/org/apache/taverna/activities/docker/test/TestConfigurationManager.java b/taverna-docker-activity/src/test/java/org/apache/taverna/activities/docker/test/TestConfigurationManager.java new file mode 100644 index 0000000..48a41f0 --- /dev/null +++ b/taverna-docker-activity/src/test/java/org/apache/taverna/activities/docker/test/TestConfigurationManager.java @@ -0,0 +1,35 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 org.apache.taverna.activities.docker.test; + +import org.apache.taverna.configuration.Configurable; +import org.apache.taverna.configuration.ConfigurationManager; + +public class TestConfigurationManager implements ConfigurationManager { + + @Override + public void store(Configurable configurable) throws Exception { + + } + + @Override + public void populate(Configurable configurable) throws Exception { + + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d4be6805/taverna-docker-activity/src/test/java/org/apache/taverna/activities/docker/test/TestCreateContainer.java ---------------------------------------------------------------------- diff --git a/taverna-docker-activity/src/test/java/org/apache/taverna/activities/docker/test/TestCreateContainer.java b/taverna-docker-activity/src/test/java/org/apache/taverna/activities/docker/test/TestCreateContainer.java deleted file mode 100644 index a82c746..0000000 --- a/taverna-docker-activity/src/test/java/org/apache/taverna/activities/docker/test/TestCreateContainer.java +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you 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 org.apache.taverna.activities.docker.test; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.taverna.activities.docker.DockerContainerConfigurationImpl; -import org.apache.taverna.activities.docker.DockerHttpResponse; -import org.apache.taverna.activities.docker.RESTUtil; -import org.junit.Test; - -import java.io.IOException; - -public class TestCreateContainer{ - - -// @Test -// public void testCreateContainer(){ -// try { -// String payload = "{\"Image\":\"6fae60ef3446\", \"ExposedPorts\":{\"8080/tcp\":{}}}"; -// DockerContainerConfigurationImpl config = new DockerContainerConfigurationImpl("192.168.99.100",2376,"https",new ObjectMapper().readTree(payload)); -// DockerHttpResponse res = RESTUtil.createContainer(config); -// System.out.println(">>>" + res.toString()); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// } -} http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/d4be6805/taverna-docker-activity/src/test/java/org/apache/taverna/activities/docker/test/TestDockerCommands.java ---------------------------------------------------------------------- diff --git a/taverna-docker-activity/src/test/java/org/apache/taverna/activities/docker/test/TestDockerCommands.java b/taverna-docker-activity/src/test/java/org/apache/taverna/activities/docker/test/TestDockerCommands.java new file mode 100644 index 0000000..5f44e2b --- /dev/null +++ b/taverna-docker-activity/src/test/java/org/apache/taverna/activities/docker/test/TestDockerCommands.java @@ -0,0 +1,101 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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 org.apache.taverna.activities.docker.test; + +import com.github.dockerjava.api.command.InspectImageResponse; +import com.github.dockerjava.api.model.Container; +import org.apache.taverna.activities.docker.DockerContainerConfigurationImpl; +import org.apache.taverna.activities.docker.DockerRemoteConfig; +import org.apache.taverna.activities.docker.RemoteClient; +import org.junit.Assert; +import org.junit.Test; + +import java.util.List; + +public class TestDockerCommands { + + private RemoteClient remoteClient; + + private static final String IMAGE_NAME = "training/webapp"; + + private static final String CONTAINER_NAME = "test-container"; + + private static final String DOCKER_LOGIN_SUCCESS = "Login Succeeded"; + + public static void main(String[] args) { + TestDockerCommands commands = new TestDockerCommands(); + commands.testLogin(); +// commands.testInspectImage(); + commands.testListContainers(); +// commands.testCreateContainer(); + } + + public TestDockerCommands(){ + DockerContainerConfigurationImpl containerConfiguration = new DockerContainerConfigurationImpl(new TestConfigurationManager()); + containerConfiguration.getInternalPropertyMap().put(DockerContainerConfigurationImpl.NAME,CONTAINER_NAME); + containerConfiguration.getInternalPropertyMap().put(DockerContainerConfigurationImpl.IMAGE,IMAGE_NAME); + containerConfiguration.getInternalPropertyMap().put(DockerContainerConfigurationImpl.CMD,"env"); + + DockerRemoteConfig remoteConfig = new DockerRemoteConfig(); + remoteConfig.setDockerHost("tcp://192.168.99.100:2376"); + remoteConfig.setApiVersion("1.21"); + remoteConfig.setDockerTlsVerify(true); + remoteConfig.setDockerCertPath("/Users/Nadeesh/Documents/docker/"); + remoteConfig.setDockerConfig("/home/user/.docker"); + remoteConfig.setRegistryUrl("https://registry-1.docker.io/v2/library/busybox/manifests/latest"); + remoteClient = new RemoteClient(containerConfiguration); + remoteClient.init(remoteConfig); + } + + @Test + public void testLogin(){ + String status = remoteClient.login(); + Assert.assertEquals(DOCKER_LOGIN_SUCCESS, status); + } + + /** + * Corresponding docker command > docker images --no-trunc | head + */ + @Test + public void testInspectImage(){ + InspectImageResponse response = remoteClient.inspect(IMAGE_NAME); + System.out.println(response.getId()); + Assert.assertNotNull(response.getId()); + } + + + @Test + public void testListContainers(){ + List<Container> list = remoteClient.listContainers(); + for(Container container: list){ + System.out.println(container.toString()); + } + } + + /** + * Corresponding docker command > docker images --no-trunc | head + */ + @Test + public void testInspectImage1(){ + InspectImageResponse response = remoteClient.inspect(IMAGE_NAME); + System.out.println(response.getId()); + Assert.assertNotNull(response.getId()); + } +}
