From 86a3c5125596e2201d47bb3d6fad93bd237f2534 Mon Sep 17 00:00:00 2001 From: ChristopherDancy Date: Mon, 23 Feb 2015 12:52:04 -0500 Subject: [PATCH] Initial PR for jclouds Shipyard provider. This PR is concerned only with the Containers, Engines, and Images API's. --- .gitignore | 2 +- pom.xml | 2 + shipyard/README.md | 26 +++ shipyard/pom.xml | 146 +++++++++++++++++ .../org/jclouds/shipyard/ShipyardApi.java | 36 +++++ .../jclouds/shipyard/ShipyardApiMetadata.java | 81 ++++++++++ .../config/ShipyardHttpApiModule.java | 45 ++++++ .../domain/containers/ContainerImageInfo.java | 71 ++++++++ .../domain/containers/ContainerInfo.java | 58 +++++++ .../domain/containers/DeployContainer.java | 82 ++++++++++ .../shipyard/domain/engines/AddEngine.java | 45 ++++++ .../shipyard/domain/engines/EngineInfo.java | 37 +++++ .../domain/engines/EngineSettingsInfo.java | 54 +++++++ .../shipyard/domain/images/ImageInfo.java | 58 +++++++ .../domain/images/ImagePortsInfo.java | 41 +++++ .../shipyard/features/ContainersApi.java | 69 ++++++++ .../jclouds/shipyard/features/EnginesApi.java | 59 +++++++ .../jclouds/shipyard/features/ImagesApi.java | 38 +++++ .../filters/ServiceKeyAuthentication.java | 55 +++++++ .../handlers/ShipyardErrorHandler.java | 96 +++++++++++ .../shipyard/ShipyardApiMetadataTest.java | 49 ++++++ .../features/ContainersApiLiveTest.java | 153 ++++++++++++++++++ .../features/ContainersApiMockTest.java | 145 +++++++++++++++++ .../shipyard/features/EnginesApiLiveTest.java | 90 +++++++++++ .../shipyard/features/EnginesApiMockTest.java | 134 +++++++++++++++ .../shipyard/features/ImagesApiLiveTest.java | 42 +++++ .../shipyard/features/ImagesApiMockTest.java | 69 ++++++++ .../internal/BaseShipyardApiLiveTest.java | 47 ++++++ .../internal/BaseShipyardMockTest.java | 112 +++++++++++++ .../internal/BaseShipyardParseTest.java | 31 ++++ .../shipyard/parse/ContainersParseTest.java | 67 ++++++++ .../shipyard/parse/EnginesParseTest.java | 51 ++++++ .../shipyard/parse/ImagesParseTest.java | 51 ++++++ .../resources/container-deploy-response.json | 49 ++++++ .../src/test/resources/container-deploy.json | 18 +++ shipyard/src/test/resources/container.json | 47 ++++++ shipyard/src/test/resources/containers.json | 49 ++++++ shipyard/src/test/resources/engine-add.json | 15 ++ shipyard/src/test/resources/engine.json | 12 ++ shipyard/src/test/resources/engines.json | 14 ++ shipyard/src/test/resources/image.json | 10 ++ shipyard/src/test/resources/images.json | 12 ++ 42 files changed, 2367 insertions(+), 1 deletion(-) create mode 100644 shipyard/README.md create mode 100644 shipyard/pom.xml create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/ShipyardApi.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/ShipyardApiMetadata.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/config/ShipyardHttpApiModule.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/domain/containers/ContainerImageInfo.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/domain/containers/ContainerInfo.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/domain/containers/DeployContainer.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/domain/engines/AddEngine.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/domain/engines/EngineInfo.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/domain/engines/EngineSettingsInfo.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/domain/images/ImageInfo.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/domain/images/ImagePortsInfo.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/features/ContainersApi.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/features/EnginesApi.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/features/ImagesApi.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/filters/ServiceKeyAuthentication.java create mode 100644 shipyard/src/main/java/org/jclouds/shipyard/handlers/ShipyardErrorHandler.java create mode 100644 shipyard/src/test/java/org/jclouds/shipyard/ShipyardApiMetadataTest.java create mode 100644 shipyard/src/test/java/org/jclouds/shipyard/features/ContainersApiLiveTest.java create mode 100644 shipyard/src/test/java/org/jclouds/shipyard/features/ContainersApiMockTest.java create mode 100644 shipyard/src/test/java/org/jclouds/shipyard/features/EnginesApiLiveTest.java create mode 100644 shipyard/src/test/java/org/jclouds/shipyard/features/EnginesApiMockTest.java create mode 100644 shipyard/src/test/java/org/jclouds/shipyard/features/ImagesApiLiveTest.java create mode 100644 shipyard/src/test/java/org/jclouds/shipyard/features/ImagesApiMockTest.java create mode 100644 shipyard/src/test/java/org/jclouds/shipyard/internal/BaseShipyardApiLiveTest.java create mode 100644 shipyard/src/test/java/org/jclouds/shipyard/internal/BaseShipyardMockTest.java create mode 100644 shipyard/src/test/java/org/jclouds/shipyard/internal/BaseShipyardParseTest.java create mode 100644 shipyard/src/test/java/org/jclouds/shipyard/parse/ContainersParseTest.java create mode 100644 shipyard/src/test/java/org/jclouds/shipyard/parse/EnginesParseTest.java create mode 100644 shipyard/src/test/java/org/jclouds/shipyard/parse/ImagesParseTest.java create mode 100644 shipyard/src/test/resources/container-deploy-response.json create mode 100644 shipyard/src/test/resources/container-deploy.json create mode 100644 shipyard/src/test/resources/container.json create mode 100644 shipyard/src/test/resources/containers.json create mode 100644 shipyard/src/test/resources/engine-add.json create mode 100644 shipyard/src/test/resources/engine.json create mode 100644 shipyard/src/test/resources/engines.json create mode 100644 shipyard/src/test/resources/image.json create mode 100644 shipyard/src/test/resources/images.json diff --git a/.gitignore b/.gitignore index 9fc2438b9..50f382152 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,4 @@ atlassian-ide-plugin.xml .DS_Store .java-version *nb-configuration.xml -*nbactions.xml \ No newline at end of file +*nbactions.xml diff --git a/pom.xml b/pom.xml index 424b75527..b5265bf7e 100644 --- a/pom.xml +++ b/pom.xml @@ -79,6 +79,7 @@ joyentcloud abiquo profitbricks + shipyard @@ -188,3 +189,4 @@ + diff --git a/shipyard/README.md b/shipyard/README.md new file mode 100644 index 000000000..c39414774 --- /dev/null +++ b/shipyard/README.md @@ -0,0 +1,26 @@ +#Shipyard provider for jclouds +- jclouds-shipyard allows one to connect and administer multiple docker daemons from a single endpoint. + +-------------- + +#Setup + +- Notes on how to standup a Shipyard instance can be found here: + + https://github.com/shipyard/shipyard + +- More detailed information (docs, API, etc..) can be found on their site: + + http://shipyard-project.com/ + +-------------- + +#Notes +- jclouds-shipyard is still at alpha stage please report any issues you find at [jclouds issues](https://issues.apache.org/jira/browse/JCLOUDS) + +-------------- + +#Testing +- To run integration tests we need a valid Shipyard instance/endpoint, identity-key, and docker daemon to use. Testing, for now, assumes the docker daemon does not have ssl enabled. To run integration tests you could do something like: + + $> mvn clean install -Plive -Dtest.shipyard.endpoint=http://10.0.0.8:8080 -Dtest.shipyard.identity=zEswusMbqMR8D7QA0yJbIc1CxGYqfLAG5bZO -Dtest.shipyard.docker.endpoint=http://10.0.0.8:2375 diff --git a/shipyard/pom.xml b/shipyard/pom.xml new file mode 100644 index 000000000..30dfbf847 --- /dev/null +++ b/shipyard/pom.xml @@ -0,0 +1,146 @@ + + + + 4.0.0 + + org.apache.jclouds.labs + jclouds-labs + 2.0.0-SNAPSHOT + + + + shipyard + jclouds shipyard API + ComputeService binding to the Shipyard API + bundle + + + http://localhost:8080 + http://localhost:2375 + FIXME + 2.0.8 + org.jclouds.shipyard*;version="${project.version}" + + org.jclouds.compute.internal;version="${project.version}", + org.jclouds.rest.internal;version="${project.version}", + org.jclouds*;version="${project.version}", + * + + + + + + org.apache.jclouds + jclouds-core + ${project.version} + + + org.apache.jclouds + jclouds-compute + ${project.version} + + + com.google.auto.value + auto-value + provided + + + com.google.auto.service + auto-service + provided + + + org.apache.jclouds.driver + jclouds-okhttp + ${project.version} + + + ch.qos.logback + logback-classic + test + + + org.apache.jclouds.driver + jclouds-slf4j + ${project.version} + test + + + org.apache.jclouds + jclouds-core + ${project.version} + test-jar + test + + + org.apache.jclouds + jclouds-compute + ${project.version} + test-jar + test + + + com.squareup.okhttp + mockwebserver + test + + + + org.bouncycastle + bcprov-jdk15on + + + + + + + + live + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration + integration-test + + test + + + 1 + + ${test.shipyard.endpoint} + ${test.shipyard.docker.endpoint} + ${test.shipyard.identity} + ${test.shipyard.api-version} + + + + + + + + + + + diff --git a/shipyard/src/main/java/org/jclouds/shipyard/ShipyardApi.java b/shipyard/src/main/java/org/jclouds/shipyard/ShipyardApi.java new file mode 100644 index 000000000..c92a4b5e2 --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/ShipyardApi.java @@ -0,0 +1,36 @@ +/* + * 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.jclouds.shipyard; + +import org.jclouds.rest.annotations.Delegate; +import org.jclouds.shipyard.features.ContainersApi; +import org.jclouds.shipyard.features.EnginesApi; +import org.jclouds.shipyard.features.ImagesApi; + +import java.io.Closeable; + +public interface ShipyardApi extends Closeable { + + @Delegate + ContainersApi containersApi(); + + @Delegate + ImagesApi imagesApi(); + + @Delegate + EnginesApi enginesApi(); +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/ShipyardApiMetadata.java b/shipyard/src/main/java/org/jclouds/shipyard/ShipyardApiMetadata.java new file mode 100644 index 000000000..ea4adb37e --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/ShipyardApiMetadata.java @@ -0,0 +1,81 @@ +/* + * 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.jclouds.shipyard; + +import com.google.auto.service.AutoService; +import com.google.common.collect.ImmutableSet; +import com.google.inject.Module; + +import org.jclouds.apis.ApiMetadata; +import org.jclouds.rest.internal.BaseHttpApiMetadata; +import org.jclouds.shipyard.config.ShipyardHttpApiModule; + +import java.net.URI; +import java.util.Properties; + +@AutoService(ApiMetadata.class) +public class ShipyardApiMetadata extends BaseHttpApiMetadata { + + @Override + public Builder toBuilder() { + return new Builder().fromApiMetadata(this); + } + + public ShipyardApiMetadata() { + this(new Builder()); + } + + protected ShipyardApiMetadata(Builder builder) { + super(builder); + } + + public static Properties defaultProperties() { + return BaseHttpApiMetadata.defaultProperties(); + } + + public static class Builder extends BaseHttpApiMetadata.Builder { + + protected Builder() { + super(ShipyardApi.class); + id("shipyard") + .name("Shipyard Remote Docker Management API") + .identityName("") + .credentialName("not used") + .documentation(URI.create("http://shipyard-project.com/docs/api/")) + .version("2.0.4") + .defaultEndpoint("https://127.0.0.1:8080") + .defaultProperties(ShipyardApiMetadata.defaultProperties()) + .defaultModules(ImmutableSet.>of( + ShipyardHttpApiModule.class)); + } + + @Override + public ShipyardApiMetadata build() { + return new ShipyardApiMetadata(this); + } + + @Override + protected Builder self() { + return this; + } + + @Override + public Builder fromApiMetadata(ApiMetadata in) { + return this; + } + } +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/config/ShipyardHttpApiModule.java b/shipyard/src/main/java/org/jclouds/shipyard/config/ShipyardHttpApiModule.java new file mode 100644 index 000000000..adcfc38df --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/config/ShipyardHttpApiModule.java @@ -0,0 +1,45 @@ +/* + * 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.jclouds.shipyard.config; + +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.annotation.ClientError; +import org.jclouds.http.annotation.Redirection; +import org.jclouds.http.annotation.ServerError; +import org.jclouds.http.config.ConfiguresHttpCommandExecutorService; +import org.jclouds.http.okhttp.config.OkHttpCommandExecutorServiceModule; +import org.jclouds.rest.ConfiguresHttpApi; +import org.jclouds.rest.config.HttpApiModule; +import org.jclouds.shipyard.ShipyardApi; +import org.jclouds.shipyard.handlers.ShipyardErrorHandler; + +@ConfiguresHttpApi +@ConfiguresHttpCommandExecutorService +public class ShipyardHttpApiModule extends HttpApiModule { + + @Override + protected void bindErrorHandlers() { + bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ShipyardErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ShipyardErrorHandler.class); + bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ShipyardErrorHandler.class); + } + + protected void configure() { + super.configure(); + install(new OkHttpCommandExecutorServiceModule()); + } +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/domain/containers/ContainerImageInfo.java b/shipyard/src/main/java/org/jclouds/shipyard/domain/containers/ContainerImageInfo.java new file mode 100644 index 000000000..315e7870d --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/domain/containers/ContainerImageInfo.java @@ -0,0 +1,71 @@ +/* + * 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.jclouds.shipyard.domain.containers; + +import java.util.List; +import java.util.Map; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; +import org.jclouds.shipyard.domain.images.ImagePortsInfo; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +@AutoValue +public abstract class ContainerImageInfo { + + @Nullable public abstract String name(); + + public abstract Map environment(); + + public abstract List entryPoint(); + + @Nullable public abstract String hostName(); + + public abstract List bindPorts(); + + public abstract List volumes(); + + public abstract Map restartPolicy(); + + public abstract boolean publish(); + + @Nullable public abstract String networkMode(); + + ContainerImageInfo() { + } + + @SerializedNames({ "name", "environment", "entrypoint", "hostname", "bind_ports", "volumes", "restart_policy", "publish", "network_mode" }) + public static ContainerImageInfo create(String name, Map environment, List entryPoint, + String hostName, List bindPorts, + List volumes, Map restartPolicy, + boolean publish, String networkMode) { + + if (environment == null) environment = Maps.newHashMap(); + if (entryPoint == null) entryPoint = Lists.newArrayList(); + if (bindPorts == null) bindPorts = Lists.newArrayList(); + if (volumes == null) volumes = Lists.newArrayList(); + if (restartPolicy == null) restartPolicy = Maps.newHashMap(); + + return new AutoValue_ContainerImageInfo(name, environment, entryPoint, + hostName, bindPorts, + volumes, restartPolicy, + publish, networkMode); + } +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/domain/containers/ContainerInfo.java b/shipyard/src/main/java/org/jclouds/shipyard/domain/containers/ContainerInfo.java new file mode 100644 index 000000000..8e6404d53 --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/domain/containers/ContainerInfo.java @@ -0,0 +1,58 @@ +/* + * 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.jclouds.shipyard.domain.containers; + +import java.util.List; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; +import org.jclouds.shipyard.domain.engines.EngineSettingsInfo; +import org.jclouds.shipyard.domain.images.ImagePortsInfo; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.Lists; + +@AutoValue +public abstract class ContainerInfo { + + public abstract String id(); + + @Nullable public abstract String name(); + + public abstract ContainerImageInfo image(); + + public abstract EngineSettingsInfo engine(); + + public abstract String state(); + + public abstract List ports(); + + ContainerInfo() { + } + + @SerializedNames({ "id", "name", "image", "engine", "state", "ports" }) + public static ContainerInfo create(String id, String name, + ContainerImageInfo image, + EngineSettingsInfo engine, + String state, List ports) { + + if (state == null) state = "unknown"; + if (ports == null) ports = Lists.newArrayList(); + + return new AutoValue_ContainerInfo(id, name, image, engine, state, ports); + } +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/domain/containers/DeployContainer.java b/shipyard/src/main/java/org/jclouds/shipyard/domain/containers/DeployContainer.java new file mode 100644 index 000000000..e1352ae14 --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/domain/containers/DeployContainer.java @@ -0,0 +1,82 @@ +/* + * 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.jclouds.shipyard.domain.containers; + +import java.util.List; +import java.util.Map; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; +import org.jclouds.shipyard.domain.images.ImagePortsInfo; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +@AutoValue +public abstract class DeployContainer { + + public abstract String name(); + + public abstract String containerName(); + + public abstract double cpus(); + + public abstract int memory(); + + public abstract String type(); + + @Nullable public abstract String hostName(); + + @Nullable public abstract String domain(); + + public abstract List labels(); + + public abstract List args(); + + public abstract Map environment(); + + public abstract Map restartPolicy(); + + public abstract List bindPorts(); + + public abstract Map links(); + + DeployContainer() { + } + + @SerializedNames({ "name", "container_name", "cpus", "memory", "type", "hostname", "domain", "labels", "args", "environment", "restart_policy", "bind_ports", "links" }) + public static DeployContainer create(String name, String containerName, double cpus, + int memory, String type, String hostName, + String domain, List labels, List args, + Map environment, Map restartPolicy, + List bindPorts, Map links) { + + if (labels == null) labels = Lists.newArrayList(); + if (args == null) args = Lists.newArrayList(); + if (environment == null) environment = Maps.newHashMap(); + if (restartPolicy == null) restartPolicy = Maps.newHashMap(); + if (bindPorts == null) bindPorts = Lists.newArrayList(); + if (links == null) links = Maps.newHashMap(); + + return new AutoValue_DeployContainer(name, containerName, cpus, + memory, "service", hostName, + domain, labels, args, + environment, restartPolicy, bindPorts, + links); + } +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/domain/engines/AddEngine.java b/shipyard/src/main/java/org/jclouds/shipyard/domain/engines/AddEngine.java new file mode 100644 index 000000000..683568d93 --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/domain/engines/AddEngine.java @@ -0,0 +1,45 @@ +/* + * 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.jclouds.shipyard.domain.engines; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class AddEngine { + + public abstract String local(); + + @Nullable abstract String sslCert(); + + @Nullable abstract String sslKey(); + + @Nullable abstract String caCert(); + + public abstract EngineSettingsInfo engine(); + + AddEngine() { + } + + @SerializedNames({ "local", "ssl_cert", "ssl_key", "ca_cert", "engine" }) + public static AddEngine create(String local, String sslCert, + String sslKey, String caCert, EngineSettingsInfo engine) { + return new AutoValue_AddEngine(local, sslCert, sslKey, caCert, engine); + } +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/domain/engines/EngineInfo.java b/shipyard/src/main/java/org/jclouds/shipyard/domain/engines/EngineInfo.java new file mode 100644 index 000000000..f7bbf8972 --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/domain/engines/EngineInfo.java @@ -0,0 +1,37 @@ +/* + * 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.jclouds.shipyard.domain.engines; + +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class EngineInfo { + + public abstract String id(); + + public abstract EngineSettingsInfo engine(); + + EngineInfo() { + } + + @SerializedNames({ "id", "engine" }) + public static EngineInfo create(String id, EngineSettingsInfo engine) { + return new AutoValue_EngineInfo(id, engine); + } +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/domain/engines/EngineSettingsInfo.java b/shipyard/src/main/java/org/jclouds/shipyard/domain/engines/EngineSettingsInfo.java new file mode 100644 index 000000000..1a5f923c1 --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/domain/engines/EngineSettingsInfo.java @@ -0,0 +1,54 @@ +/* + * 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.jclouds.shipyard.domain.engines; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import java.util.List; + +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class EngineSettingsInfo { + + public abstract String id(); + + public abstract String addr(); + + public abstract double cpus(); + + public abstract double memory(); + + public abstract List labels(); + + EngineSettingsInfo() { + } + + @SerializedNames({ "id", "addr", "cpus", "memory", "labels" }) + public static EngineSettingsInfo create(String id, String addr, + double cpus, double memory, + List labels) { + + checkNotNull(labels, "labels must be non-null"); + checkState(labels.size() > 0, "labels must have at least 1 entry"); + + return new AutoValue_EngineSettingsInfo(id, addr, cpus, memory, labels); + } +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/domain/images/ImageInfo.java b/shipyard/src/main/java/org/jclouds/shipyard/domain/images/ImageInfo.java new file mode 100644 index 000000000..c18bf30b0 --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/domain/images/ImageInfo.java @@ -0,0 +1,58 @@ +/* + * 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.jclouds.shipyard.domain.images; + +import java.util.List; + +import org.jclouds.domain.Location; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.Lists; + +@AutoValue +public abstract class ImageInfo { + + public abstract int created(); + + @Nullable public abstract String id(); + + public abstract String parentId(); + + public abstract List repoTags(); + + public abstract int size(); + + public abstract int virtualSize(); + + @Nullable abstract Location location(); + + ImageInfo() { + } + + @SerializedNames({ "Created", "Id", "ParentId", "RepoTags", "Size", "VirtualSize" , "Location"}) + public static ImageInfo create(int created, String id, + String parentId, List repoTags, + int size, int virtualSize, + Location location) { + + if (repoTags == null) repoTags = Lists.newArrayList(); + + return new AutoValue_ImageInfo(created, id, parentId, repoTags, size, virtualSize, location); + } +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/domain/images/ImagePortsInfo.java b/shipyard/src/main/java/org/jclouds/shipyard/domain/images/ImagePortsInfo.java new file mode 100644 index 000000000..1728e2eae --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/domain/images/ImagePortsInfo.java @@ -0,0 +1,41 @@ +/* + * 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.jclouds.shipyard.domain.images; + +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class ImagePortsInfo { + + public abstract String proto(); + + public abstract String hostIp(); + + public abstract int port(); + + public abstract int containerPort(); + + ImagePortsInfo() { + } + + @SerializedNames({ "proto", "host_ip", "port", "container_port" }) + public static ImagePortsInfo create(String proto, String hostIp, int port, int containerPort) { + return new AutoValue_ImagePortsInfo(proto, hostIp, port, containerPort); + } +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/features/ContainersApi.java b/shipyard/src/main/java/org/jclouds/shipyard/features/ContainersApi.java new file mode 100644 index 000000000..0ca98fc91 --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/features/ContainersApi.java @@ -0,0 +1,69 @@ +/* + * 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.jclouds.shipyard.features; + +import java.util.List; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.rest.annotations.BinderParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.binders.BindToJsonPayload; +import org.jclouds.shipyard.domain.containers.ContainerInfo; +import org.jclouds.shipyard.domain.containers.DeployContainer; +import org.jclouds.shipyard.filters.ServiceKeyAuthentication; + +@Consumes(MediaType.APPLICATION_JSON) +@RequestFilters({ ServiceKeyAuthentication.class }) +@Path("/api/containers") +public interface ContainersApi { + + @Named("containers:list") + @GET + List listContainers(); + + @Named("containers:info") + @GET + @Path("/{id}") + ContainerInfo getContainer(@PathParam("id") String id); + + @Named("containers:delete") + @DELETE + @Path("/{id}") + void deleteContainer(@PathParam("id") String id); + + @Named("containers:stop") + @GET + @Path("/{id}/stop") + void stopContainer(@PathParam("id") String id); + + @Named("containers:restart") + @GET + @Path("/{id}/restart") + void restartContainer(@PathParam("id") String id); + + @Named("containers:deploy") + @POST + List deployContainer(@BinderParam(BindToJsonPayload.class) DeployContainer deployContainer); +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/features/EnginesApi.java b/shipyard/src/main/java/org/jclouds/shipyard/features/EnginesApi.java new file mode 100644 index 000000000..bcb027c8b --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/features/EnginesApi.java @@ -0,0 +1,59 @@ +/* + * 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.jclouds.shipyard.features; + +import java.util.List; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.MediaType; + +import org.jclouds.rest.annotations.BinderParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.binders.BindToJsonPayload; +import org.jclouds.shipyard.domain.engines.AddEngine; +import org.jclouds.shipyard.domain.engines.EngineInfo; +import org.jclouds.shipyard.filters.ServiceKeyAuthentication; + +@Consumes(MediaType.APPLICATION_JSON) +@RequestFilters({ ServiceKeyAuthentication.class }) +@Path("/api/engines") +public interface EnginesApi { + + @Named("engines:list-info") + @GET + List listEngines(); + + @Named("engines:info") + @GET + @Path("/{id}") + EngineInfo getEngine(@PathParam("id") String engineID); + + @Named("engines:add") + @POST + void addEngine(@BinderParam(BindToJsonPayload.class) AddEngine addEngine); + + @Named("engines:remove") + @DELETE + @Path("/{id}") + void removeEngine(@PathParam("id") String engineID); +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/features/ImagesApi.java b/shipyard/src/main/java/org/jclouds/shipyard/features/ImagesApi.java new file mode 100644 index 000000000..80dad17d8 --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/features/ImagesApi.java @@ -0,0 +1,38 @@ +/* + * 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.jclouds.shipyard.features; + +import java.net.URI; +import java.util.List; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; + +import org.jclouds.rest.annotations.EndpointParam; +import org.jclouds.shipyard.domain.images.ImageInfo; + +@Consumes(MediaType.APPLICATION_JSON) +@Path("/images/json") +public interface ImagesApi { + + @Named("images:list") + @GET + List listImages(@EndpointParam URI rootURL); +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/filters/ServiceKeyAuthentication.java b/shipyard/src/main/java/org/jclouds/shipyard/filters/ServiceKeyAuthentication.java new file mode 100644 index 000000000..9750bb1be --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/filters/ServiceKeyAuthentication.java @@ -0,0 +1,55 @@ +/* + * 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.jclouds.shipyard.filters; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.domain.Credentials; +import org.jclouds.http.HttpException; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpRequestFilter; +import org.jclouds.location.Provider; +import org.jclouds.rest.AuthorizationException; + +import com.google.common.base.Supplier; + +/** + * Shipyard remote API authentication is made via the HTTP header 'X-Service-Key' which in turns + * has it's value as an encoded string (Shipyard-cli generates this for you). + * + */ +@Singleton +public class ServiceKeyAuthentication implements HttpRequestFilter { + private final Supplier creds; + + @Inject + ServiceKeyAuthentication(@Provider Supplier creds) { + this.creds = creds; + } + + @Override + public HttpRequest filter(HttpRequest request) throws HttpException { + Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null"); + if (currentCreds.identity == null) { + throw new AuthorizationException("Credentials identity can not be null"); + } + return request.toBuilder().addHeader("X-Service-Key", currentCreds.identity).build(); + } +} diff --git a/shipyard/src/main/java/org/jclouds/shipyard/handlers/ShipyardErrorHandler.java b/shipyard/src/main/java/org/jclouds/shipyard/handlers/ShipyardErrorHandler.java new file mode 100644 index 000000000..0e43814b2 --- /dev/null +++ b/shipyard/src/main/java/org/jclouds/shipyard/handlers/ShipyardErrorHandler.java @@ -0,0 +1,96 @@ +/* + * 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.jclouds.shipyard.handlers; + +import static org.jclouds.util.Closeables2.closeQuietly; + +import java.io.IOException; + +import javax.annotation.Resource; + +import org.jclouds.http.HttpCommand; +import org.jclouds.http.HttpErrorHandler; +import org.jclouds.http.HttpResponse; +import org.jclouds.http.HttpResponseException; +import org.jclouds.logging.Logger; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.util.Strings2; + +import com.google.common.base.Throwables; + +/** + * Handle errors and propagate exception + * + */ +public class ShipyardErrorHandler implements HttpErrorHandler { + @Resource + protected Logger logger = Logger.NULL; + + public void handleError(HttpCommand command, HttpResponse response) { + + Exception exception = null; + try { + + String message = parseMessage(response); + message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(), response.getStatusLine()); + switch (response.getStatusCode()) { + case 401: + exception = new AuthorizationException(message, exception); + break; + case 404: + if (command.getCurrentRequest().getMethod().equals("GET")) { + if (command.getCurrentRequest().getEndpoint().getPath().endsWith("/images/json")) { + exception = new HttpResponseException("Unable to reach docker daemon", command, response); + } + } + break; + case 409: + if (command.getCurrentRequest().getMethod().equals("POST")) { + if (command.getCurrentRequest().getEndpoint().getPath().endsWith("/containers")) { + exception = new HttpResponseException("Container already exists", command, response); + } + } + break; + case 500: + if (command.getCurrentRequest().getMethod().equals("POST")) { + if (command.getCurrentRequest().getEndpoint().getPath().endsWith("/engines")) { + exception = new HttpResponseException("Connection refused registering docker daemon", command, response); + } + } + break; + default: + exception = new HttpResponseException(message, command, response); + break; + } + } catch (Exception e) { + exception = new HttpResponseException(command, response, e); + } finally { + closeQuietly(response.getPayload()); + command.setException(exception); + } + } + + private String parseMessage(HttpResponse response) { + if (response.getPayload() == null) + return null; + try { + return Strings2.toStringAndClose(response.getPayload().openStream()); + } catch (IOException e) { + throw Throwables.propagate(e); + } + } +} diff --git a/shipyard/src/test/java/org/jclouds/shipyard/ShipyardApiMetadataTest.java b/shipyard/src/test/java/org/jclouds/shipyard/ShipyardApiMetadataTest.java new file mode 100644 index 000000000..b6db47354 --- /dev/null +++ b/shipyard/src/test/java/org/jclouds/shipyard/ShipyardApiMetadataTest.java @@ -0,0 +1,49 @@ +/* + * 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.jclouds.shipyard; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.util.HashSet; +import org.jclouds.View; +import org.jclouds.apis.ApiMetadata; +import org.jclouds.apis.Apis; +import org.jclouds.apis.internal.BaseApiMetadataTest; +import org.testng.annotations.Test; + +import com.google.common.reflect.TypeToken; + +/** + * Unit tests for the {@link ShipyardApiMetadata} class. + */ +@Test(groups = "unit", testName = "ShipyardApiMetadataTest") +public class ShipyardApiMetadataTest extends BaseApiMetadataTest { + + public ShipyardApiMetadataTest() { + super(new ShipyardApiMetadata(), new HashSet>()); + } + + public void testShipyardApiRegistered() { + ApiMetadata api = Apis.withId("shipyard"); + + assertNotNull(api); + assertTrue(api instanceof ShipyardApiMetadata); + assertEquals(api.getId(), "shipyard"); + } +} diff --git a/shipyard/src/test/java/org/jclouds/shipyard/features/ContainersApiLiveTest.java b/shipyard/src/test/java/org/jclouds/shipyard/features/ContainersApiLiveTest.java new file mode 100644 index 000000000..8ec10d146 --- /dev/null +++ b/shipyard/src/test/java/org/jclouds/shipyard/features/ContainersApiLiveTest.java @@ -0,0 +1,153 @@ +/* + * 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.jclouds.shipyard.features; + +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.util.List; + +import org.jclouds.http.HttpResponseException; +import org.jclouds.shipyard.domain.containers.ContainerInfo; +import org.jclouds.shipyard.domain.containers.DeployContainer; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; + + +@Test(groups = "live", testName = "ContainersApiLiveTest", singleThreaded = true) +public class ContainersApiLiveTest extends EnginesApiLiveTest { + + private String containerName = "shipyard-jclouds-container-test"; + private String containerID = null; + + @BeforeClass + protected void init() throws Exception { + super.init(); + super.testGetAllEngines(); + } + + @AfterClass (alwaysRun = true) + protected void tearDown() { + super.tearDown(); + } + + public void testDeployContainer() throws Exception { + + DeployContainer deployContainer = DeployContainer.create("ubuntu:14.04.1", + containerName, + 1, + 512, + null, + null, + null, + Lists.newArrayList(EnginesApiLiveTest.engineName), + Lists.newArrayList("/bin/bash"), + ImmutableMap.of("shipyard-jclouds", "test"), + null, + null, + null); + + List container = api().deployContainer(deployContainer); + assertNotNull(container, "Expected valid container but returned NULL"); + assertTrue(container.size() == 1, "Expected exactly 1 container removed and found " + container.size()); + assertTrue(container.get(0).name().endsWith(containerName), + "Expected name does not match actual name: requested=" + containerName + ", actual=" + container.get(0).name()); + assertTrue(container.get(0).engine().labels().contains(EnginesApiLiveTest.engineName), + "Expected label was not found in container: expected=" + EnginesApiLiveTest.engineName + ", found=" + container.get(0).engine().labels()); + containerID = container.get(0).id(); + } + + @Test (dependsOnMethods = "testDeployContainer") + public void testDeployAlreadyExistentContainer() throws Exception { + + DeployContainer deployContainer = DeployContainer.create("ubuntu:14.04.1", + containerName, + 1, + 512, + null, + null, + null, + Lists.newArrayList(EnginesApiLiveTest.engineName), + Lists.newArrayList("/bin/bash"), + ImmutableMap.of("shipyard-jclouds", "test"), + null, + null, + null); + + List container = api().deployContainer(deployContainer); + assertNull(container); + } + + public void testDeployNonExistentContainer() throws Exception { + + DeployContainer deployContainer = DeployContainer.create("jclouds-shipyard-test:99.99.99", + containerName, + 1, + 512, + null, + null, + null, + Lists.newArrayList(EnginesApiLiveTest.engineName), + Lists.newArrayList("/bin/bash"), + ImmutableMap.of("shipyard-jclouds", "test"), + null, + null, + null); + + List container = api().deployContainer(deployContainer); + assertNull(container); + } + + @Test (dependsOnMethods = "testDeployAlreadyExistentContainer") + public void testStopContainer() throws Exception { + api().stopContainer(containerID); + } + + @Test (expectedExceptions = HttpResponseException.class) + public void testStopNonExistentContainer() throws Exception { + api().stopContainer("aaabbbccc111222333"); + } + + @Test (dependsOnMethods = "testStopContainer") + public void testRestartContainer() throws Exception { + api().restartContainer(containerID); + } + + @Test (expectedExceptions = HttpResponseException.class) + public void testRestartNonExistentContainer() throws Exception { + api().restartContainer("aaabbbccc111222333"); + } + + @Test (dependsOnMethods = "testRestartContainer") + public void testDeleteContainer() throws Exception { + api().deleteContainer(containerID); + } + + @Test (expectedExceptions = HttpResponseException.class) + public void testDeleteNonExistentContainer() throws Exception { + api().deleteContainer("aaabbbccc111222333"); + } + + private ContainersApi api() { + return api.containersApi(); + } +} diff --git a/shipyard/src/test/java/org/jclouds/shipyard/features/ContainersApiMockTest.java b/shipyard/src/test/java/org/jclouds/shipyard/features/ContainersApiMockTest.java new file mode 100644 index 000000000..ca30e284a --- /dev/null +++ b/shipyard/src/test/java/org/jclouds/shipyard/features/ContainersApiMockTest.java @@ -0,0 +1,145 @@ +/* + * 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.jclouds.shipyard.features; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.util.List; + +import org.jclouds.shipyard.ShipyardApi; +import org.jclouds.shipyard.domain.containers.ContainerInfo; +import org.jclouds.shipyard.domain.containers.DeployContainer; +import org.jclouds.shipyard.internal.BaseShipyardMockTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; + +/** + * Mock tests for the {@link org.jclouds.shipyard.features.ContainersApi} class. + */ +@Test(groups = "unit", testName = "ContainersApiMockTest") +public class ContainersApiMockTest extends BaseShipyardMockTest { + + + public void testListContainers() throws Exception { + MockWebServer server = mockShipyardWebServer(); + server.enqueue(new MockResponse().setBody(payloadFromResource("/containers.json"))); + ShipyardApi shipyardApi = api(server.getUrl("/")); + ContainersApi api = shipyardApi.containersApi(); + try { + assertEquals(api.listContainers().size(), 1); + assertSent(server, "GET", "/api/containers"); + } finally { + shipyardApi.close(); + server.shutdown(); + } + } + + public void testGetContainer() throws Exception { + MockWebServer server = mockShipyardWebServer(); + server.enqueue(new MockResponse().setBody(payloadFromResource("/container.json"))); + ShipyardApi shipyardApi = api(server.getUrl("/")); + ContainersApi api = shipyardApi.containersApi(); + String containerId = "e2f6784b75ed8768e83b7ec46ca8ef784941f6ce4c53231023804277965da1d2"; + try { + assertEquals(api.getContainer(containerId).id(), containerId); + assertSent(server, "GET", "/api/containers/" + containerId); + } finally { + shipyardApi.close(); + server.shutdown(); + } + } + + public void testDeployContainer() throws Exception { + MockWebServer server = mockShipyardWebServer(); + server.enqueue(new MockResponse().setResponseCode(201).setBody(payloadFromResource("/container-deploy-response.json"))); + ShipyardApi shipyardApi = api(server.getUrl("/")); + ContainersApi api = shipyardApi.containersApi(); + + DeployContainer deployContainer = DeployContainer.create("nkatsaros/atlassian-stash:3.5", + "atlassian-stash", + 8, + 8096, + null, + null, + null, + Lists.newArrayList("localhost"), + null, + ImmutableMap.of("STASH_HOME", "/var/atlassian/stash", "STASH_VERSION", "3.5.0"), + null, + null, + null); + try { + List container = api.deployContainer(deployContainer); + assertNotNull(container); + assertEquals(container.get(0).id(), "e2f6784b75ed8768e83b7ec46ca8ef784941f6ce4c53231023804277965da1d2"); + assertSent(server, "POST", "/api/containers", new String(payloadFromResource("/container-deploy.json"))); + } finally { + shipyardApi.close(); + server.shutdown(); + } + } + + public void testDeleteContainer() throws Exception { + MockWebServer server = mockShipyardWebServer(); + server.enqueue(new MockResponse().setResponseCode(204)); + ShipyardApi shipyardApi = api(server.getUrl("/")); + ContainersApi api = shipyardApi.containersApi(); + String containerId = "e2f6784b75ed8768e83b7ec46ca8ef784941f6ce4c53231023804277965da1d2"; + try { + api.deleteContainer(containerId); + assertSent(server, "DELETE", "/api/containers/" + containerId); + } finally { + shipyardApi.close(); + server.shutdown(); + } + } + + public void testStopContainer() throws Exception { + MockWebServer server = mockShipyardWebServer(); + server.enqueue(new MockResponse().setResponseCode(204)); + ShipyardApi shipyardApi = api(server.getUrl("/")); + ContainersApi api = shipyardApi.containersApi(); + String containerId = "e2f6784b75ed8768e83b7ec46ca8ef784941f6ce4c53231023804277965da1d2"; + try { + api.stopContainer(containerId); + assertSent(server, "GET", "/api/containers/" + containerId + "/stop"); + } finally { + shipyardApi.close(); + server.shutdown(); + } + } + + public void testStartOrRestartContainer() throws Exception { + MockWebServer server = mockShipyardWebServer(); + server.enqueue(new MockResponse().setResponseCode(204)); + ShipyardApi shipyardApi = api(server.getUrl("/")); + ContainersApi api = shipyardApi.containersApi(); + String containerId = "e2f6784b75ed8768e83b7ec46ca8ef784941f6ce4c53231023804277965da1d2"; + try { + api.restartContainer(containerId); + assertSent(server, "GET", "/api/containers/" + containerId + "/restart"); + } finally { + shipyardApi.close(); + server.shutdown(); + } + } +} diff --git a/shipyard/src/test/java/org/jclouds/shipyard/features/EnginesApiLiveTest.java b/shipyard/src/test/java/org/jclouds/shipyard/features/EnginesApiLiveTest.java new file mode 100644 index 000000000..8a4546823 --- /dev/null +++ b/shipyard/src/test/java/org/jclouds/shipyard/features/EnginesApiLiveTest.java @@ -0,0 +1,90 @@ +/* + * 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.jclouds.shipyard.features; + +import java.util.List; + +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertNotNull; + +import org.jclouds.http.HttpResponseException; +import org.jclouds.shipyard.domain.engines.AddEngine; +import org.jclouds.shipyard.domain.engines.EngineInfo; +import org.jclouds.shipyard.domain.engines.EngineSettingsInfo; +import org.jclouds.shipyard.internal.BaseShipyardApiLiveTest; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.google.common.collect.Lists; + +@Test(groups = "live", testName = "EnginesApiLiveTest", singleThreaded = true) +public class EnginesApiLiveTest extends BaseShipyardApiLiveTest { + + protected static final String engineName = "jclouds-shipard-live-test"; + protected String engineID = null; + + @BeforeClass + protected void init() throws Exception { + String dockerEndpoint = System.getProperty("test.shipyard.docker.endpoint"); + EngineSettingsInfo info = EngineSettingsInfo.create(engineName, dockerEndpoint, 1, 1024, Lists.newArrayList(engineName)); + AddEngine additionalEngine = AddEngine.create("local", "", "", "", info); + api().addEngine(additionalEngine); + } + + @AfterClass (alwaysRun = true) + protected void tearDown() { + assertNotNull(engineID, "Expected engineID to be set but was not"); + api().removeEngine(engineID); + } + + public void testGetAllEngines() throws Exception { + List engines = api().listEngines(); + assertTrue(engines.size() >= 1, "Shipyard did not contain at least 1 Engine which was expected"); + boolean engineFound = false; + for (EngineInfo engine : api().listEngines()) { + if (engine.engine().id().equals(engineName)) { + engineID = engine.id(); + engineFound = true; + } + } + assertTrue(engineFound, "Expected but could not find Engine amongst " + engines.size() + " found"); + } + + @Test (dependsOnMethods = "testGetAllEngines") + public void testGetEngine() throws Exception { + assertNotNull(engineID, "Expected engineID to be set but was not"); + EngineInfo engine = api().getEngine(engineID); + assertTrue(engine.engine().id().equals(engineName), "Expected Engine name " + engineName + " but found " + engine.engine().id()); + } + + @Test (expectedExceptions = HttpResponseException.class) + public void testAddNonExistentEngine() throws Exception { + EngineSettingsInfo info = EngineSettingsInfo.create("local", "http://www.test-jclouds-shipyard:9999", 1, 1024, Lists.newArrayList("default")); + AddEngine additionalEngine = AddEngine.create("local", "", "", "", info); + api().addEngine(additionalEngine); + } + + @Test (expectedExceptions = HttpResponseException.class) + public void testRemoveNonExistentEngine() throws Exception { + api().removeEngine("1234567890-shipyard-jclouds"); + } + + private EnginesApi api() { + return api.enginesApi(); + } +} diff --git a/shipyard/src/test/java/org/jclouds/shipyard/features/EnginesApiMockTest.java b/shipyard/src/test/java/org/jclouds/shipyard/features/EnginesApiMockTest.java new file mode 100644 index 000000000..b5a4ad142 --- /dev/null +++ b/shipyard/src/test/java/org/jclouds/shipyard/features/EnginesApiMockTest.java @@ -0,0 +1,134 @@ +/* + * 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.jclouds.shipyard.features; + +import com.google.common.collect.Lists; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; + +import org.jclouds.http.HttpResponseException; +import org.jclouds.shipyard.ShipyardApi; +import org.jclouds.shipyard.domain.engines.AddEngine; +import org.jclouds.shipyard.domain.engines.EngineSettingsInfo; +import org.jclouds.shipyard.internal.BaseShipyardMockTest; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; + +/** + * Mock tests for the {@link org.jclouds.shipyard.features.EnginesApi} class. + */ +@Test(groups = "unit", testName = "EnginesApiMockTest") +public class EnginesApiMockTest extends BaseShipyardMockTest { + + public void testGetEngine() throws Exception { + MockWebServer server = mockShipyardWebServer(); + server.enqueue(new MockResponse().setBody(payloadFromResource("/engine.json"))); + ShipyardApi shipyardApi = api(server.getUrl("/")); + EnginesApi api = shipyardApi.enginesApi(); + try { + String specificEngineID = "e2059d20-e9df-44f3-8a9b-1bf2321b4eae"; + assertEquals(api.getEngine(specificEngineID).id(), specificEngineID); + assertSent(server, "GET", "/api/engines/" + specificEngineID); + } finally { + shipyardApi.close(); + server.shutdown(); + } + } + + public void testGetAllEngines() throws Exception { + MockWebServer server = mockShipyardWebServer(); + server.enqueue(new MockResponse().setBody(payloadFromResource("/engines.json"))); + ShipyardApi shipyardApi = api(server.getUrl("/")); + EnginesApi api = shipyardApi.enginesApi(); + try { + assertEquals(api.listEngines().size(), 1); + assertSent(server, "GET", "/api/engines"); + } finally { + shipyardApi.close(); + server.shutdown(); + } + } + + public void testAddEngine() throws Exception { + MockWebServer server = mockShipyardWebServer(); + server.enqueue(new MockResponse().setResponseCode(200)); + ShipyardApi shipyardApi = api(server.getUrl("/")); + EnginesApi api = shipyardApi.enginesApi(); + try { + AddEngine addEngine = AddEngine.create("local", + "", + "", + "", + EngineSettingsInfo.create("1234", + "http://localhost:2375", + 1, + 1024, + Lists.newArrayList("shipyard-test"))); + + api.addEngine(addEngine); + assertSent(server, "POST", "/api/engines", new String(payloadFromResource("/engine-add.json"))); + } finally { + shipyardApi.close(); + server.shutdown(); + } + } + + @Test (expectedExceptions = HttpResponseException.class) + public void testAddNonExistentEngine() throws Exception { + MockWebServer server = mockShipyardWebServer(); + server.enqueue(new MockResponse().setResponseCode(500)); + ShipyardApi shipyardApi = api(server.getUrl("/")); + EnginesApi api = shipyardApi.enginesApi(); + try { + AddEngine addEngine = AddEngine.create("local", + "", + "", + "", + EngineSettingsInfo.create("9999", + "http://shipyard.failure.com:9999", + 1, + 1024, + Lists.newArrayList("shipyard-faiure"))); + + api.addEngine(addEngine); + assertSent(server, "POST", "/api/engines", new String(payloadFromResource("/engine-add.json"))); + } finally { + shipyardApi.close(); + server.shutdown(); + } + } + + public void testRemoveEngine() throws Exception { + MockWebServer server = mockShipyardWebServer(); + server.enqueue(new MockResponse().setResponseCode(200)); + ShipyardApi shipyardApi = api(server.getUrl("/")); + EnginesApi api = shipyardApi.enginesApi(); + try { + String specificEngineID = "e2059d20-e9df-44f3-8a9b-1bf2321b4eae"; + api.removeEngine(specificEngineID); + assertSent(server, "DELETE", "/api/engines/" + specificEngineID); + } finally { + shipyardApi.close(); + server.shutdown(); + } + } + + public void testRemoveNonExistentEngine() throws Exception { + //TODO + } +} diff --git a/shipyard/src/test/java/org/jclouds/shipyard/features/ImagesApiLiveTest.java b/shipyard/src/test/java/org/jclouds/shipyard/features/ImagesApiLiveTest.java new file mode 100644 index 000000000..47af8e13d --- /dev/null +++ b/shipyard/src/test/java/org/jclouds/shipyard/features/ImagesApiLiveTest.java @@ -0,0 +1,42 @@ +/* + * 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.jclouds.shipyard.features; + +import static org.testng.Assert.assertNotNull; + +import java.net.URI; +import java.util.List; + +import org.jclouds.shipyard.domain.images.ImageInfo; +import org.jclouds.shipyard.internal.BaseShipyardApiLiveTest; +import org.testng.annotations.Test; + +@Test(groups = "live", testName = "ImagesApiLiveTest", singleThreaded = true) +public class ImagesApiLiveTest extends BaseShipyardApiLiveTest { + + public void testGetAllImages() throws Exception { + // we only have to test that this does not fail. It's entirely possible we get 0 images back. + // This is a placeholder test-hack until Shipyard gets a proper images API expected in v2.10 + String dockerEndpoint = System.getProperty("test.shipyard.docker.endpoint"); + List images = api().listImages(URI.create(dockerEndpoint)); + assertNotNull(images); + } + + private ImagesApi api() { + return api.imagesApi(); + } +} diff --git a/shipyard/src/test/java/org/jclouds/shipyard/features/ImagesApiMockTest.java b/shipyard/src/test/java/org/jclouds/shipyard/features/ImagesApiMockTest.java new file mode 100644 index 000000000..cbc5f1e43 --- /dev/null +++ b/shipyard/src/test/java/org/jclouds/shipyard/features/ImagesApiMockTest.java @@ -0,0 +1,69 @@ +/* + * 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.jclouds.shipyard.features; + +import static org.testng.Assert.assertEquals; + +import java.net.URI; + +import org.jclouds.http.HttpResponseException; +import org.jclouds.shipyard.ShipyardApi; +import org.jclouds.shipyard.internal.BaseShipyardMockTest; +import org.testng.annotations.Test; + +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; + +/** + * Mock tests for the {@link org.jclouds.shipyard.features.ImagesApi} class. + */ +@Test(groups = "unit", testName = "ImagesApiMockTest") +public class ImagesApiMockTest extends BaseShipyardMockTest { + + public void testGetAllImages() throws Exception { + MockWebServer server = mockShipyardWebServer(); + server.enqueue(new MockResponse(). + setResponseCode(200). + setBody(payloadFromResource("/images.json"))); + ShipyardApi shipyardApi = api(server.getUrl("/")); + ImagesApi api = shipyardApi.imagesApi(); + try { + assertEquals(api.listImages(URI.create("")).size(), 1); + assertSentIgnoreServiceKey(server, "GET", "/images/json"); + } finally { + shipyardApi.close(); + server.shutdown(); + } + } + + @Test (expectedExceptions = HttpResponseException.class) + public void testGetNonExistentDockerDaemon() throws Exception { + MockWebServer server = mockShipyardWebServer(); + server.enqueue(new MockResponse(). + setResponseCode(404). + setBody(payloadFromResource("/images.json"))); + ShipyardApi shipyardApi = api(server.getUrl("/")); + ImagesApi api = shipyardApi.imagesApi(); + try { + assertEquals(api.listImages(URI.create("http://test-jclouds-ship:9999")).size(), 0); + assertSentIgnoreServiceKey(server, "GET", "/images/json"); + } finally { + shipyardApi.close(); + server.shutdown(); + } + } +} diff --git a/shipyard/src/test/java/org/jclouds/shipyard/internal/BaseShipyardApiLiveTest.java b/shipyard/src/test/java/org/jclouds/shipyard/internal/BaseShipyardApiLiveTest.java new file mode 100644 index 000000000..fa295249a --- /dev/null +++ b/shipyard/src/test/java/org/jclouds/shipyard/internal/BaseShipyardApiLiveTest.java @@ -0,0 +1,47 @@ +/* + * 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.jclouds.shipyard.internal; + +import java.util.Properties; + +import org.jclouds.Constants; +import org.jclouds.apis.BaseApiLiveTest; +import org.jclouds.shipyard.ShipyardApi; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Module; + +@Test(groups = "live") +public class BaseShipyardApiLiveTest extends BaseApiLiveTest { + + public BaseShipyardApiLiveTest() { + provider = "shipyard"; + } + + @Override + protected Iterable setupModules() { + return ImmutableSet.of(getLoggingModule()); + } + + @Override + protected Properties setupProperties() { + Properties overrides = super.setupProperties(); + overrides.setProperty(Constants.PROPERTY_MAX_RETRIES, "0"); + return overrides; + } +} diff --git a/shipyard/src/test/java/org/jclouds/shipyard/internal/BaseShipyardMockTest.java b/shipyard/src/test/java/org/jclouds/shipyard/internal/BaseShipyardMockTest.java new file mode 100644 index 000000000..e2e9405d7 --- /dev/null +++ b/shipyard/src/test/java/org/jclouds/shipyard/internal/BaseShipyardMockTest.java @@ -0,0 +1,112 @@ +/* + * 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.jclouds.shipyard.internal; + +import static com.google.common.base.Charsets.UTF_8; +import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor; +import static org.assertj.core.api.Assertions.assertThat; +import static org.jclouds.util.Strings2.toStringAndClose; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.net.URL; +import java.util.Properties; +import java.util.Set; + +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; + +import org.jclouds.Constants; +import org.jclouds.ContextBuilder; +import org.jclouds.concurrent.config.ExecutorServiceModule; +import org.jclouds.shipyard.ShipyardApi; + +import com.google.common.base.Charsets; +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableSet; +import com.google.gson.JsonParser; +import com.google.inject.Module; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import com.squareup.okhttp.mockwebserver.RecordedRequest; + +/** + * Base class for all Shipyard mock tests. + */ +public class BaseShipyardMockTest { + private final Set modules = ImmutableSet. of(new ExecutorServiceModule(sameThreadExecutor())); + + protected String provider; + private final JsonParser parser = new JsonParser(); + + public BaseShipyardMockTest() { + provider = "shipyard"; + } + + public ShipyardApi api(URL url) { + return ContextBuilder.newBuilder(provider) + .credentials("shipyard-service-key", "") + .endpoint(url.toString()) + .modules(modules) + .overrides(setupProperties()) + .buildApi(ShipyardApi.class); + } + + protected Properties setupProperties() { + Properties properties = new Properties(); + properties.setProperty(Constants.PROPERTY_MAX_RETRIES, "0"); + return properties; + } + + public static MockWebServer mockShipyardWebServer() throws IOException { + MockWebServer server = new MockWebServer(); + server.play(); + return server; + } + + public byte[] payloadFromResource(String resource) { + try { + return toStringAndClose(getClass().getResourceAsStream(resource)).getBytes(Charsets.UTF_8); + } catch (IOException e) { + throw Throwables.propagate(e); + } + } + + protected RecordedRequest assertSent(MockWebServer server, String method, String path) throws InterruptedException { + RecordedRequest request = server.takeRequest(); + assertThat(request.getMethod()).isEqualTo(method); + assertThat(request.getPath()).isEqualTo(path); + assertThat(request.getHeader("X-Service-Key").equals("shipyard-service-key")); + assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON); + return request; + } + + protected RecordedRequest assertSentIgnoreServiceKey(MockWebServer server, String method, String path) throws InterruptedException { + RecordedRequest request = server.takeRequest(); + assertThat(request.getMethod()).isEqualTo(method); + assertThat(request.getPath()).isEqualTo(path); + assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo(MediaType.APPLICATION_JSON); + return request; + } + + protected RecordedRequest assertSent(MockWebServer server, String method, String path, String json) throws InterruptedException { + RecordedRequest request = assertSent(server, method, path); + assertEquals(request.getHeader("Content-Type"), APPLICATION_JSON); + assertEquals(parser.parse(new String(request.getBody(), UTF_8)), parser.parse(json)); + return request; + } +} diff --git a/shipyard/src/test/java/org/jclouds/shipyard/internal/BaseShipyardParseTest.java b/shipyard/src/test/java/org/jclouds/shipyard/internal/BaseShipyardParseTest.java new file mode 100644 index 000000000..8bc95327d --- /dev/null +++ b/shipyard/src/test/java/org/jclouds/shipyard/internal/BaseShipyardParseTest.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.jclouds.shipyard.internal; + +import org.jclouds.json.BaseItemParserTest; +import org.jclouds.json.config.GsonModule; + +import com.google.inject.Guice; +import com.google.inject.Injector; + +public abstract class BaseShipyardParseTest extends BaseItemParserTest { + + @Override + protected Injector injector() { + return Guice.createInjector(new GsonModule()); + } +} diff --git a/shipyard/src/test/java/org/jclouds/shipyard/parse/ContainersParseTest.java b/shipyard/src/test/java/org/jclouds/shipyard/parse/ContainersParseTest.java new file mode 100644 index 000000000..0db240770 --- /dev/null +++ b/shipyard/src/test/java/org/jclouds/shipyard/parse/ContainersParseTest.java @@ -0,0 +1,67 @@ +/* + * 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.jclouds.shipyard.parse; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.shipyard.domain.containers.ContainerImageInfo; +import org.jclouds.shipyard.domain.containers.ContainerInfo; +import org.jclouds.shipyard.domain.engines.EngineSettingsInfo; +import org.jclouds.shipyard.domain.images.ImagePortsInfo; +import org.jclouds.shipyard.internal.BaseShipyardParseTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +@Test(groups = "unit") +public class ContainersParseTest extends BaseShipyardParseTest> { + + @Override + public String resource() { + return "/containers.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public List expected() { + + return ImmutableList.of( + ContainerInfo.create("e2f6784b75ed8768e83b7ec46ca8ef784941f6ce4c53231023804277965da1d2", + "/atlassian-stash", + ContainerImageInfo.create("nkatsaros/atlassian-stash:3.5", + ImmutableMap.of("STASH_HOME", "/var/atlassian/stash", "STASH_VERSION", "3.5.0"), + ImmutableList.of("/docker-entrypoint.sh"), + "e2f6784b75ed", + ImmutableList.of(ImagePortsInfo.create("tcp", "0.0.0.0", 8089, 8080)), + ImmutableList.of("/var/atlassian/stash"), + ImmutableMap.of(), + true, + "bridge"), + EngineSettingsInfo.create("sdrelnx150", + "http://sdrelnx150:2375", + 8, + 8096, + ImmutableList.of("sdrelnx150")), + "stopped", + ImmutableList.of(ImagePortsInfo.create("tcp", "0.0.0.0", 8089, 8080))) + ); + } +} diff --git a/shipyard/src/test/java/org/jclouds/shipyard/parse/EnginesParseTest.java b/shipyard/src/test/java/org/jclouds/shipyard/parse/EnginesParseTest.java new file mode 100644 index 000000000..9e208fcdf --- /dev/null +++ b/shipyard/src/test/java/org/jclouds/shipyard/parse/EnginesParseTest.java @@ -0,0 +1,51 @@ +/* + * 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.jclouds.shipyard.parse; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.shipyard.domain.engines.EngineInfo; +import org.jclouds.shipyard.domain.engines.EngineSettingsInfo; +import org.jclouds.shipyard.internal.BaseShipyardParseTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; + +@Test(groups = "unit") +public class EnginesParseTest extends BaseShipyardParseTest> { + + @Override + public String resource() { + return "/engines.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public List expected() { + return ImmutableList.of( + EngineInfo.create("e2059d20-e9df-44f3-8a9b-1bf2321b4eae", + EngineSettingsInfo.create("sdrelnx150", + "http://sdrelnx150:2375", + 8, + 8096, + ImmutableList.of("sdrelnx150"))) + ); + } +} diff --git a/shipyard/src/test/java/org/jclouds/shipyard/parse/ImagesParseTest.java b/shipyard/src/test/java/org/jclouds/shipyard/parse/ImagesParseTest.java new file mode 100644 index 000000000..359cf0b96 --- /dev/null +++ b/shipyard/src/test/java/org/jclouds/shipyard/parse/ImagesParseTest.java @@ -0,0 +1,51 @@ +/* + * 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.jclouds.shipyard.parse; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.shipyard.domain.images.ImageInfo; +import org.jclouds.shipyard.internal.BaseShipyardParseTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; + +@Test(groups = "unit") +public class ImagesParseTest extends BaseShipyardParseTest> { + + @Override + public String resource() { + return "/images.json"; + } + + @Override + @Consumes(MediaType.APPLICATION_JSON) + public List expected() { + return ImmutableList.of( + ImageInfo.create(1416370366, + "3f0d936caee4777872d6ad8dfae0077b6857d86f0232a240a95e748fb1c981f1", + "5cd3a141e0cc8523bf5d76b9187124bb9d43b874da2656abf1f417e4d4858643", + ImmutableList.of("nkatsaros/atlassian-stash:3.4"), + 6233, + 480107370, + null) + ); + } +} diff --git a/shipyard/src/test/resources/container-deploy-response.json b/shipyard/src/test/resources/container-deploy-response.json new file mode 100644 index 000000000..acce5690f --- /dev/null +++ b/shipyard/src/test/resources/container-deploy-response.json @@ -0,0 +1,49 @@ +[ +{ + "id": "e2f6784b75ed8768e83b7ec46ca8ef784941f6ce4c53231023804277965da1d2", + "name": "/atlassian-stash", + "image": { + "name": "nkatsaros/atlassian-stash:3.5", + "entrypoint": [ + "/docker-entrypoint.sh" + ], + "environment": { + "STASH_HOME": "/var/atlassian/stash", + "STASH_VERSION": "3.5.0" + }, + "hostname": "e2f6784b75ed", + "bind_ports": [ + { + "proto": "tcp", + "host_ip": "0.0.0.0", + "port": 8089, + "container_port": 8080 + } + ], + "volumes": [ + "/var/atlassian/stash" + ], + "restart_policy": {}, + "publish": true, + "network_mode": "bridge" + }, + "engine": { + "id": "localhost", + "addr": "http://localhost:2375", + "cpus": 8, + "memory": 8096, + "labels": [ + "localhost" + ] + }, + "state": "stopped", + "ports": [ + { + "proto": "tcp", + "host_ip": "0.0.0.0", + "port": 8089, + "container_port": 8080 + } + ] +} +] \ No newline at end of file diff --git a/shipyard/src/test/resources/container-deploy.json b/shipyard/src/test/resources/container-deploy.json new file mode 100644 index 000000000..74d391b6d --- /dev/null +++ b/shipyard/src/test/resources/container-deploy.json @@ -0,0 +1,18 @@ +{ + "name": "nkatsaros/atlassian-stash:3.5", + "container_name": "atlassian-stash", + "cpus": 8, + "memory": 8096, + "type" : "service", + "labels": [ + "localhost" + ], + "args": [], + "environment": { + "STASH_HOME": "/var/atlassian/stash", + "STASH_VERSION": "3.5.0" + }, + "restart_policy": {}, + "bind_ports": [], + "links": {} +} \ No newline at end of file diff --git a/shipyard/src/test/resources/container.json b/shipyard/src/test/resources/container.json new file mode 100644 index 000000000..1d60c11af --- /dev/null +++ b/shipyard/src/test/resources/container.json @@ -0,0 +1,47 @@ +{ + "id": "e2f6784b75ed8768e83b7ec46ca8ef784941f6ce4c53231023804277965da1d2", + "name": "/atlassian-stash", + "image": { + "name": "nkatsaros/atlassian-stash:3.5", + "entrypoint": [ + "/docker-entrypoint.sh" + ], + "environment": { + "STASH_HOME": "/var/atlassian/stash", + "STASH_VERSION": "3.5.0" + }, + "hostname": "e2f6784b75ed", + "bind_ports": [ + { + "proto": "tcp", + "host_ip": "0.0.0.0", + "port": 8089, + "container_port": 8080 + } + ], + "volumes": [ + "/var/atlassian/stash" + ], + "restart_policy": {}, + "publish": true, + "network_mode": "bridge" + }, + "engine": { + "id": "localhost", + "addr": "http://localhost:2375", + "cpus": 8, + "memory": 8096, + "labels": [ + "localhost" + ] + }, + "state": "stopped", + "ports": [ + { + "proto": "tcp", + "host_ip": "0.0.0.0", + "port": 8089, + "container_port": 8080 + } + ] +} \ No newline at end of file diff --git a/shipyard/src/test/resources/containers.json b/shipyard/src/test/resources/containers.json new file mode 100644 index 000000000..2b838b2e1 --- /dev/null +++ b/shipyard/src/test/resources/containers.json @@ -0,0 +1,49 @@ +[ + { + "id": "e2f6784b75ed8768e83b7ec46ca8ef784941f6ce4c53231023804277965da1d2", + "name": "/atlassian-stash", + "image": { + "name": "nkatsaros/atlassian-stash:3.5", + "entrypoint": [ + "/docker-entrypoint.sh" + ], + "environment": { + "STASH_HOME": "/var/atlassian/stash", + "STASH_VERSION": "3.5.0" + }, + "hostname": "e2f6784b75ed", + "bind_ports": [ + { + "proto": "tcp", + "host_ip": "0.0.0.0", + "port": 8089, + "container_port": 8080 + } + ], + "volumes": [ + "/var/atlassian/stash" + ], + "restart_policy": {}, + "publish": true, + "network_mode": "bridge" + }, + "engine": { + "id": "sdrelnx150", + "addr": "http://sdrelnx150:2375", + "cpus": 8, + "memory": 8096, + "labels": [ + "sdrelnx150" + ] + }, + "state": "stopped", + "ports": [ + { + "proto": "tcp", + "host_ip": "0.0.0.0", + "port": 8089, + "container_port": 8080 + } + ] + } +] \ No newline at end of file diff --git a/shipyard/src/test/resources/engine-add.json b/shipyard/src/test/resources/engine-add.json new file mode 100644 index 000000000..11b08008e --- /dev/null +++ b/shipyard/src/test/resources/engine-add.json @@ -0,0 +1,15 @@ +{ + "local": "local", + "ssl_cert": "", + "ssl_key": "", + "ca_cert": "", + "engine": { + "id": "1234", + "addr": "http://localhost:2375", + "cpus": 1.0, + "memory": 1024.0, + "labels": [ + "shipyard-test" + ] + } +} diff --git a/shipyard/src/test/resources/engine.json b/shipyard/src/test/resources/engine.json new file mode 100644 index 000000000..11f009971 --- /dev/null +++ b/shipyard/src/test/resources/engine.json @@ -0,0 +1,12 @@ +{ + "id": "e2059d20-e9df-44f3-8a9b-1bf2321b4eae", + "engine": { + "id": "sdrelnx150", + "addr": "http://sdrelnx150:2375", + "cpus": 8, + "memory": 8096, + "labels": [ + "sdrelnx150" + ] + } +} \ No newline at end of file diff --git a/shipyard/src/test/resources/engines.json b/shipyard/src/test/resources/engines.json new file mode 100644 index 000000000..6cc205a35 --- /dev/null +++ b/shipyard/src/test/resources/engines.json @@ -0,0 +1,14 @@ +[ + { + "id": "e2059d20-e9df-44f3-8a9b-1bf2321b4eae", + "engine": { + "id": "sdrelnx150", + "addr": "http://sdrelnx150:2375", + "cpus": 8, + "memory": 8096, + "labels": [ + "sdrelnx150" + ] + } + } +] \ No newline at end of file diff --git a/shipyard/src/test/resources/image.json b/shipyard/src/test/resources/image.json new file mode 100644 index 000000000..0c2747034 --- /dev/null +++ b/shipyard/src/test/resources/image.json @@ -0,0 +1,10 @@ +{ + "Created": 1416370366, + "Id": "3f0d936caee4777872d6ad8dfae0077b6857d86f0232a240a95e748fb1c981f1", + "ParentId": "5cd3a141e0cc8523bf5d76b9187124bb9d43b874da2656abf1f417e4d4858643", + "RepoTags": [ + "nkatsaros/atlassian-stash:3.4" + ], + "Size": 6233, + "VirtualSize": 480107370 +} diff --git a/shipyard/src/test/resources/images.json b/shipyard/src/test/resources/images.json new file mode 100644 index 000000000..8affec48e --- /dev/null +++ b/shipyard/src/test/resources/images.json @@ -0,0 +1,12 @@ +[ + { + "Created": 1416370366, + "Id": "3f0d936caee4777872d6ad8dfae0077b6857d86f0232a240a95e748fb1c981f1", + "ParentId": "5cd3a141e0cc8523bf5d76b9187124bb9d43b874da2656abf1f417e4d4858643", + "RepoTags": [ + "nkatsaros/atlassian-stash:3.4" + ], + "Size": 6233, + "VirtualSize": 480107370 + } +] \ No newline at end of file