From a73256dbbfccae4c3a74895b2c7166041def6e21 Mon Sep 17 00:00:00 2001 From: Claus Stadler Date: Thu, 10 Jan 2019 02:33:13 +0100 Subject: [PATCH 1/9] Revised the core API to resolve some long standing design issues --- docker-service-api-core/pom.xml | 5 + .../docker/api/DockerServiceBuilder.java | 89 +++++--- .../api/DockerServiceBuilderFactory.java | 6 + .../docker/api/DockerServiceFactory.java | 40 +++- .../service/docker/api/DockerServiceSpec.java | 24 +++ .../docker/api/DockerServiceSpecLike.java | 14 ++ .../docker/api/DockerServiceSystem.java | 19 ++ .../service/docker/api/ResourceAware.java | 13 ++ .../docker/api/SimpleServiceFactory.java | 15 +- .../core/AbstractSimpleServiceFactory.java | 26 +-- .../core/DockerServiceBuilderFactory.java | 3 +- .../impl/core/DockerServiceBuilderImpl.java | 42 ++++ .../DockerServiceBuilderJsonDelegate.java | 16 ++ .../DockerServiceBuilderSimpleDelegation.java | 15 ++ .../impl/core/DockerServiceFactoryChain.java | 8 +- .../impl/core/DockerServiceSpecImpl.java | 98 +++++++++ .../core/DockerServiceSpecLikeForwarding.java | 48 +++++ .../DockerServiceBuilderDockerClient.java | 203 ++++++++---------- .../DockerServiceFactoryDockerClient.java | 80 ++++++- .../DockerServiceSpecDockerClient.java | 114 ++++++++++ .../MainDockerServiceExampleVirtuoso.java | 2 +- docker-service-api-spring-boot/pom.xml | 1 + ...erviceFactorySpringApplicationBuilder.java | 22 +- pom.xml | 7 + 24 files changed, 722 insertions(+), 188 deletions(-) create mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceBuilderFactory.java create mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSpec.java create mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSpecLike.java create mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSystem.java create mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/ResourceAware.java create mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderImpl.java create mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceSpecImpl.java create mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceSpecLikeForwarding.java create mode 100644 docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSpecDockerClient.java diff --git a/docker-service-api-core/pom.xml b/docker-service-api-core/pom.xml index 7e0158a..90e9aad 100644 --- a/docker-service-api-core/pom.xml +++ b/docker-service-api-core/pom.xml @@ -13,6 +13,11 @@ + + org.apache.jena + jena-arq + + com.google.guava guava diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceBuilder.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceBuilder.java index ef61367..9655f91 100644 --- a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceBuilder.java +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceBuilder.java @@ -1,8 +1,13 @@ package org.hobbit.core.service.docker.api; -import java.util.Map; - /** + * Typically, + * a docker serviceBuilder internally bundles a DockerServiceFactory with a mutable configuration object. + * + * + * Note, {@link DockerServiceBuilderFactory} provides the mechanism to create new, + * possibly preconfigured, configurations. + * * Base implementation for creating docker services. * * Calling the .get() method will create a service object whose state is based on the factories current state but independent from it. @@ -10,41 +15,61 @@ * The factory does not do book keeping of created services. * * + * Note: Although DockerService builder extends DockerServiceSpec, it should never be used as such. + * The reason for this inheritance is simply to make method forwarding easier: We can just reuse + * DockerServiceSpecForwarding. + * * @author raven Sep 20, 2017 * */ public interface DockerServiceBuilder - extends ServiceBuilder + extends ServiceBuilder, DockerServiceSpecLike> { - String getImageName(); - DockerServiceBuilder setImageName(String imageName); - - - /** - * Get the local environment of the factory. - * - * - * Local means, that it should NOT return e.g. the system environment - * or anything else that is outside of control of this factory. - * - * - * We use the term local enviroment in order for subclasses to support spring's Environment object, - * which is at the core of dependency injenction, and it has a proper API - * for nesting of property sources - * - * Under this consideration, the local environment should be the treated as the first property source - * of an overall spring environment. - * - * - * @return - */ - Map getLocalEnvironment(); +// String getContainerName(); +// DockerServiceBuilder setContainerName(String containerName); +// +// String getImageName(); +// DockerServiceBuilder setImageName(String imageName); +// +// Map getLocalEnvironment(); +// DockerServiceBuilder setLocalEnvironment(Map localEnvironment); - /** - * - * @param environment - * @return - */ - DockerServiceBuilder setLocalEnvironment(Map environment); + // Yield the object that backs the service builder. + // May be null. + // DockerServiceSpec getSpec(); +// +// String getContainerName(); +// DockerServiceBuilder setContainerName(String containerName); +// +// String getImageName(); +// DockerServiceBuilder setImageName(String imageName); +// +// +// /** +// * Get the local environment of the factory. +// * +// * +// * Local means, that it should NOT return e.g. the system environment +// * or anything else that is outside of control of this factory. +// * +// * +// * We use the term local enviroment in order for subclasses to support spring's Environment object, +// * which is at the core of dependency injenction, and it has a proper API +// * for nesting of property sources +// * +// * Under this consideration, the local environment should be the treated as the first property source +// * of an overall spring environment. +// * +// * +// * @return +// */ +// Map getLocalEnvironment(); +// +// /** +// * +// * @param environment +// * @return +// */ +// DockerServiceBuilder setLocalEnvironment(Map environment); } diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceBuilderFactory.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceBuilderFactory.java new file mode 100644 index 0000000..1e54ab2 --- /dev/null +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceBuilderFactory.java @@ -0,0 +1,6 @@ +package org.hobbit.core.service.docker.api; + +public interface DockerServiceBuilderFactory +{ + DockerServiceBuilder newServiceBuilder(); +} diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceFactory.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceFactory.java index 6ac2e78..ed691ec 100644 --- a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceFactory.java +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceFactory.java @@ -2,6 +2,8 @@ import java.util.Map; +import org.hobbit.core.service.docker.impl.core.DockerServiceSpecImpl; + /** * In contrast to the builder, the service factory only provides a single create method. * @@ -11,5 +13,41 @@ public interface DockerServiceFactory extends AutoCloseable { - T create(String imageName, Map env); + /** + * Create a service object based on a specification + * + * @param serviceSpec + * @return + */ + T create(DockerServiceSpec serviceSpec); + + /** + * Method to obtain a new, possibly partially configured, service specification object. + * + * @return + */ +// default DockerServiceSpec newSpec() { +// return new DockerServiceSpecImpl(); +// } + + // TODO Due to dependence on the serviceSpec object, which might already be implementation dependnent, + // this implementation might better fit into an abstract class + default T create(String containerName, String imageName, Map env) { + //DockerServiceSpec r = ModelFactory.createDefaultModel().createResource().as(DockerServiceSpec.class); + +// DockerServiceSpec r = newSpec(); + DockerServiceSpec r = new DockerServiceSpecImpl(); + + r.setContainerName(containerName); + r.setImageName(imageName); + r.setLocalEnvironment(env); + + T result = create(r); + return result; + } + + default T create(String imageName, Map env) { + T result = create(null, imageName, env); + return result; + } } diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSpec.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSpec.java new file mode 100644 index 0000000..8412f56 --- /dev/null +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSpec.java @@ -0,0 +1,24 @@ +package org.hobbit.core.service.docker.api; + +/** + * Simple mutable specification of a docker(-like) service. + * + * Note, that this is deliberately an interface so that implementations + * can choose to use different backing specification objects, + * such as JSON or RDF resources. + * + * @author Claus Stadler, Jan 9, 2019 + * + */ +public interface DockerServiceSpec + extends DockerServiceSpecLike +{ +// String getContainerName(); +// DockerServiceSpec setContainerName(String containerName); +// +// String getImageName(); +// DockerServiceSpec setImageName(String imageName); +// +// Map getLocalEnvironment(); +// DockerServiceSpec setLocalEnvironment(Map localEnvironment); +} diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSpecLike.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSpecLike.java new file mode 100644 index 0000000..6170d00 --- /dev/null +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSpecLike.java @@ -0,0 +1,14 @@ +package org.hobbit.core.service.docker.api; + +import java.util.Map; + +public interface DockerServiceSpecLike> { + String getContainerName(); + F setContainerName(String containerName); + + String getImageName(); + F setImageName(String imageName); + + Map getLocalEnvironment(); + F setLocalEnvironment(Map localEnvironment); +} diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSystem.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSystem.java new file mode 100644 index 0000000..f269250 --- /dev/null +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSystem.java @@ -0,0 +1,19 @@ +package org.hobbit.core.service.docker.api; + + +/** + * A DockerServiceSystem combines both the factory and the builder APIs: + * - The builder API creates preconfigured configuration objects that can be modified using the + * DockerServiceSpec API (possibly using casts) + * - The factory API, which only takes a single service specification, and fills the rest up with + * default values based on the factory state. + * + * @author Claus Stadler, Jan 9, 2019 + * + * @param + */ +public interface DockerServiceSystem + extends DockerServiceFactory, DockerServiceBuilderFactory +{ + +} diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/ResourceAware.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/ResourceAware.java new file mode 100644 index 0000000..761f78d --- /dev/null +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/ResourceAware.java @@ -0,0 +1,13 @@ +package org.hobbit.core.service.docker.api; + +/** + * Interface for Java classes to expose whether they can make use of Jena's + * Resource infrastructure + * + * @author Claus Stadler, Jan 9, 2019 + * + */ +public interface ResourceAware { + boolean isResource(); + +} diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/SimpleServiceFactory.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/SimpleServiceFactory.java index ea8ac64..5bb0ba8 100644 --- a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/SimpleServiceFactory.java +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/SimpleServiceFactory.java @@ -1,17 +1,14 @@ package org.hobbit.core.service.docker.api; -import java.util.Map; - -import com.google.common.util.concurrent.Service; - /** * A simple service factory is configured via an environment * * @author raven * */ -public interface SimpleServiceFactory - extends ServiceBuilder -{ - Map getEnvironment(); -} +//Probably can be removed +//public interface SimpleServiceFactory +// extends ServiceBuilder +//{ +// Map getEnvironment(); +//} diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/AbstractSimpleServiceFactory.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/AbstractSimpleServiceFactory.java index 7fda6e4..a514c2d 100644 --- a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/AbstractSimpleServiceFactory.java +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/AbstractSimpleServiceFactory.java @@ -1,18 +1,12 @@ package org.hobbit.core.service.docker.impl.core; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.hobbit.core.service.docker.api.SimpleServiceFactory; - -import com.google.common.util.concurrent.Service; - -public abstract class AbstractSimpleServiceFactory - implements SimpleServiceFactory -{ - protected Map environment = new LinkedHashMap<>(); - - public Map getEnvironment() { - return environment; - } -} +// Probably can be removed +//public abstract class AbstractSimpleServiceFactory +// implements SimpleServiceFactory +//{ +// protected Map environment = new LinkedHashMap<>(); +// +// public Map getEnvironment() { +// return environment; +// } +//} diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderFactory.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderFactory.java index 43208a5..1965aee 100644 --- a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderFactory.java +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderFactory.java @@ -4,6 +4,7 @@ import org.hobbit.core.service.docker.api.DockerService; import org.hobbit.core.service.docker.api.DockerServiceBuilder; +import org.hobbit.core.service.docker.api.DockerServiceFactory; /** * A convenience interface which can be used e.g. in dependency injection. @@ -16,8 +17,6 @@ public interface DockerServiceBuilderFactory> extends Supplier { - - /** * Creates a DockerServiceBuilderFactory from a Supplier. * A down cast is performed (instead of wrapping) if this supplier is already a DockerServiceBuilderFactory diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderImpl.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderImpl.java new file mode 100644 index 0000000..13ee766 --- /dev/null +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderImpl.java @@ -0,0 +1,42 @@ +package org.hobbit.core.service.docker.impl.core; + +import java.util.Map; + +import org.hobbit.core.service.docker.api.DockerService; +import org.hobbit.core.service.docker.api.DockerServiceBuilder; +import org.hobbit.core.service.docker.api.DockerServiceFactory; +import org.hobbit.core.service.docker.api.DockerServiceSpec; +import org.hobbit.core.service.docker.api.DockerServiceSpecLike; + +/** + * + * + * @author Claus Stadler, Jan 9, 2019 + * + * @param + */ +public class DockerServiceBuilderImpl + extends DockerServiceSpecLikeForwarding> + implements DockerServiceBuilder +{ + protected DockerServiceFactory dockerServiceFactory; + protected DockerServiceSpec serviceSpec; + + + public DockerServiceBuilderImpl(DockerServiceFactory dockerServiceFactory, DockerServiceSpec serviceSpec) { + super(); + this.dockerServiceFactory = dockerServiceFactory; + this.serviceSpec = serviceSpec; + } + + @Override + public DockerServiceSpecLike getDelegate() { + return serviceSpec; + } + + @Override + public T get() { + T result = dockerServiceFactory.create(serviceSpec); + return result; + } +} diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderJsonDelegate.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderJsonDelegate.java index 99a8fb7..fe0124c 100644 --- a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderJsonDelegate.java +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderJsonDelegate.java @@ -26,6 +26,7 @@ public class DockerServiceBuilderJsonDelegate implements DockerServiceBuilder//, Cloneable { + public static final String KEY_CONTAINER_NAME = "containerName"; public static final String KEY_IMAGE_NAME = "imageName"; public static final String KEY_ENV = "env"; public static final String KEY_BASE_ENV = "baseEnv"; @@ -46,6 +47,20 @@ public DockerServiceBuilderJsonDelegate(Function delegate, JsonOb this.config = config; } + @Override + public String getContainerName() { + String result = config.get(KEY_CONTAINER_NAME).getAsString(); + return result; + } + + @Override + public DockerServiceBuilder setContainerName(String containerName) { + config.remove(KEY_CONTAINER_NAME); + config.addProperty(KEY_CONTAINER_NAME, containerName); + + return this; + } + @Override public String getImageName() { String result = config.get(KEY_IMAGE_NAME).getAsString(); @@ -110,6 +125,7 @@ public T get() { public static Type mapStringStringType = new TypeToken>() {}.getType(); + // TODO The argument should be Function serviceFactory public static DockerServiceBuilderJsonDelegate create(BiFunction, T> serviceFactory) { Function wrapperFn = jsonObj -> { String imageName = jsonObj.get(KEY_IMAGE_NAME).getAsString(); diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderSimpleDelegation.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderSimpleDelegation.java index d545d3d..effa447 100644 --- a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderSimpleDelegation.java +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceBuilderSimpleDelegation.java @@ -26,6 +26,10 @@ public class DockerServiceBuilderSimpleDelegation implements DockerServiceBuilder//, Cloneable { + // FIXME The design we actually want is to use an Resource to hold the state, + // and then just delegate the resource to a function + // The consumer can then create any view of the resource it wants + protected String containerName; protected String imageName; protected Map localEnvironment; @@ -62,6 +66,17 @@ public DockerServiceBuilderSimpleDelegation( // return result; // } + @Override + public String getContainerName() { + return containerName; + } + + @Override + public DockerServiceBuilder setContainerName(String containerName) { + this.containerName = containerName; + return this; + } + @Override public String getImageName() { return imageName; diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceFactoryChain.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceFactoryChain.java index 8ba9312..7326f62 100644 --- a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceFactoryChain.java +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceFactoryChain.java @@ -3,10 +3,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; import org.hobbit.core.service.docker.api.DockerService; import org.hobbit.core.service.docker.api.DockerServiceFactory; +import org.hobbit.core.service.docker.api.DockerServiceSpec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,12 +26,14 @@ public DockerServiceFactoryChain(DockerServiceFactory ... _factories) { @Override - public DockerService create(String imageName, Map env) { + public DockerService create(DockerServiceSpec serviceSpec) { + + String imageName = serviceSpec.getImageName(); DockerService result = null; for(DockerServiceFactory factory : factories) { try { - result = factory.create(imageName, env); + result = factory.create(serviceSpec); break; } catch(UnsupportedOperationException e) { logger.info("Service factory did not support " + imageName + ", trying next one"); diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceSpecImpl.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceSpecImpl.java new file mode 100644 index 0000000..36cfcc6 --- /dev/null +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceSpecImpl.java @@ -0,0 +1,98 @@ +package org.hobbit.core.service.docker.impl.core; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.hobbit.core.service.docker.api.DockerServiceSpec; + +/** + * Most simple implementation of a service specification as a Pojo. + * + * + * + * @author Claus Stadler, Jan 9, 2019 + * + */ +public class DockerServiceSpecImpl + implements DockerServiceSpec +{ + protected String containerName = null; + protected String imageName = null; + protected Map localEnvironment = new LinkedHashMap<>(); + + @Override + public String getContainerName() { + return containerName; + } + + @Override + public DockerServiceSpec setContainerName(String containerName) { + this.containerName = containerName; + return this; + } + + @Override + public String getImageName() { + return imageName; + } + + @Override + public DockerServiceSpec setImageName(String imageName) { + this.imageName = imageName; + return this; + } + + @Override + public Map getLocalEnvironment() { + return localEnvironment; + } + + @Override + public DockerServiceSpec setLocalEnvironment(Map localEnvironment) { + this.localEnvironment = localEnvironment; + return this; + } + + @Override + public String toString() { + return "DockerServiceSpecImpl [containerName=" + containerName + ", imageName=" + imageName + + ", localEnvironment=" + localEnvironment + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((containerName == null) ? 0 : containerName.hashCode()); + result = prime * result + ((imageName == null) ? 0 : imageName.hashCode()); + result = prime * result + ((localEnvironment == null) ? 0 : localEnvironment.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + DockerServiceSpecImpl other = (DockerServiceSpecImpl) obj; + if (containerName == null) { + if (other.containerName != null) + return false; + } else if (!containerName.equals(other.containerName)) + return false; + if (imageName == null) { + if (other.imageName != null) + return false; + } else if (!imageName.equals(other.imageName)) + return false; + if (localEnvironment == null) { + if (other.localEnvironment != null) + return false; + } else if (!localEnvironment.equals(other.localEnvironment)) + return false; + return true; + } +} diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceSpecLikeForwarding.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceSpecLikeForwarding.java new file mode 100644 index 0000000..c20ced2 --- /dev/null +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceSpecLikeForwarding.java @@ -0,0 +1,48 @@ +package org.hobbit.core.service.docker.impl.core; + +import java.util.Map; + +import org.hobbit.core.service.docker.api.DockerServiceSpecLike; + +public abstract class DockerServiceSpecLikeForwarding> + implements DockerServiceSpecLike +{ + public abstract DockerServiceSpecLike getDelegate(); + + @Override + public String getContainerName() { + return getDelegate().getContainerName(); + } + + @SuppressWarnings("unchecked") + @Override + public F setContainerName(String containerName) { + getDelegate().setContainerName(containerName); + return (F)this; + } + + @Override + public String getImageName() { + return getDelegate().getImageName(); + } + + @SuppressWarnings("unchecked") + @Override + public F setImageName(String imageName) { + getDelegate().setImageName(imageName); + return (F)this; + } + + @Override + public Map getLocalEnvironment() { + return getDelegate().getLocalEnvironment(); + } + + @SuppressWarnings("unchecked") + @Override + public F setLocalEnvironment(Map localEnvironment) { + getDelegate().setLocalEnvironment(localEnvironment); + return (F)this; + } + +} diff --git a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceBuilderDockerClient.java b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceBuilderDockerClient.java index a5c6f1d..a2106f9 100644 --- a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceBuilderDockerClient.java +++ b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceBuilderDockerClient.java @@ -1,123 +1,110 @@ package org.hobbit.core.service.docker.impl.docker_client; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -import org.hobbit.core.service.docker.api.DockerServiceBuilder; -import org.hobbit.core.service.docker.util.EnvironmentUtils; - -import com.spotify.docker.client.DockerClient; -import com.spotify.docker.client.messages.ContainerConfig; - /** * Implementation of DockerServiceFactory for docker containers backed by spotify's docker client * * @author raven Sep 20, 2017 * */ -@Deprecated -public class DockerServiceBuilderDockerClient - implements DockerServiceBuilder -{ - protected DockerClient dockerClient; - protected ContainerConfig.Builder containerConfigBuilder; - protected boolean hostMode; - protected Set networks; - - protected Map localEnv = new LinkedHashMap<>(); - -// public DockerServiceBuilderDockerClient() { +//@Deprecated +//public class DockerServiceBuilderDockerClient +// implements DockerServiceBuilder +//{ +// protected DockerClient dockerClient; +// protected ContainerConfig.Builder containerConfigBuilder; +// protected boolean hostMode; +// protected Set networks; +// +// protected Map localEnv = new LinkedHashMap<>(); +// +//// public DockerServiceBuilderDockerClient() { +//// super(); +//// } +// +//// public DockerServiceFactoryDockerClient(DockerClient dockerClient) { +//// this(null, null); //new ContainerCon +//// } +// +// public DockerServiceBuilderDockerClient(DockerClient dockerClient, ContainerConfig.Builder containerConfigBuilder, boolean hostMode, Set networks) { // super(); +// this.dockerClient = dockerClient; +// this.containerConfigBuilder = containerConfigBuilder; +// this.hostMode = hostMode; +// this.networks = networks; // } - -// public DockerServiceFactoryDockerClient(DockerClient dockerClient) { -// this(null, null); //new ContainerCon +// +// public DockerClient getDockerClient() { +// return dockerClient; // } - - public DockerServiceBuilderDockerClient(DockerClient dockerClient, ContainerConfig.Builder containerConfigBuilder, boolean hostMode, Set networks) { - super(); - this.dockerClient = dockerClient; - this.containerConfigBuilder = containerConfigBuilder; - this.hostMode = hostMode; - this.networks = networks; - } - - public DockerClient getDockerClient() { - return dockerClient; - } - - public DockerServiceBuilderDockerClient setDockerClient(DockerClient dockerClient) { - this.dockerClient = dockerClient; - return this; - } - - public ContainerConfig.Builder getContainerConfigBuilder() { - return containerConfigBuilder; - } - - public DockerServiceBuilderDockerClient setContainerConfigBuilder(ContainerConfig.Builder containerConfigBuilder) { - this.containerConfigBuilder = containerConfigBuilder; - return this; - } - - - public String getImageName() { - return containerConfigBuilder.build().image(); - } - - public DockerServiceBuilderDockerClient setImageName(String imageName) { - containerConfigBuilder.image(imageName); - return this; - } - - - @Override - public Map getLocalEnvironment() { - return localEnv; -// List env = containerConfigBuilder.build().env(); -// if(env == null) { -// env = Collections.emptyList(); -// } // -// Map result = EnvironmentUtils.listToMap("=", env); +// public DockerServiceBuilderDockerClient setDockerClient(DockerClient dockerClient) { +// this.dockerClient = dockerClient; +// return this; +// } // -// return result; - } - - @Override - public DockerServiceBuilder setLocalEnvironment(Map environment) { - this.localEnv = environment; - return this; -// List env = EnvironmentUtils.mapToList("=", environment); +// public ContainerConfig.Builder getContainerConfigBuilder() { +// return containerConfigBuilder; +// } // -// containerConfigBuilder.env(env); +// public DockerServiceBuilderDockerClient setContainerConfigBuilder(ContainerConfig.Builder containerConfigBuilder) { +// this.containerConfigBuilder = containerConfigBuilder; // return this; - } - - - @Override - public DockerServiceDockerClient get() { - Objects.requireNonNull(dockerClient); - Objects.requireNonNull(containerConfigBuilder); - - // Merge the local environment into that of the containerConfig - List rawEnv = containerConfigBuilder.build().env(); - if(rawEnv == null) { - rawEnv = Collections.emptyList(); - } - - Map env = EnvironmentUtils.listToMap(rawEnv); - env.putAll(localEnv); - - List envList = EnvironmentUtils.mapToList(env); - containerConfigBuilder.env(envList); - ContainerConfig containerConfig = containerConfigBuilder.build(); - - DockerServiceDockerClient result = new DockerServiceDockerClient(dockerClient, containerConfig, null, hostMode, networks); - return result; - } -} +// } +// +// +// public String getImageName() { +// return containerConfigBuilder.build().image(); +// } +// +// public DockerServiceBuilderDockerClient setImageName(String imageName) { +// containerConfigBuilder.image(imageName); +// return this; +// } +// +// +// @Override +// public Map getLocalEnvironment() { +// return localEnv; +//// List env = containerConfigBuilder.build().env(); +//// if(env == null) { +//// env = Collections.emptyList(); +//// } +//// +//// Map result = EnvironmentUtils.listToMap("=", env); +//// +//// return result; +// } +// +// @Override +// public DockerServiceBuilder setLocalEnvironment(Map environment) { +// this.localEnv = environment; +// return this; +//// List env = EnvironmentUtils.mapToList("=", environment); +//// +//// containerConfigBuilder.env(env); +//// return this; +// } +// +// +// @Override +// public DockerServiceDockerClient get() { +// Objects.requireNonNull(dockerClient); +// Objects.requireNonNull(containerConfigBuilder); +// +// // Merge the local environment into that of the containerConfig +// List rawEnv = containerConfigBuilder.build().env(); +// if(rawEnv == null) { +// rawEnv = Collections.emptyList(); +// } +// +// Map env = EnvironmentUtils.listToMap(rawEnv); +// env.putAll(localEnv); +// +// List envList = EnvironmentUtils.mapToList(env); +// containerConfigBuilder.env(envList); +// ContainerConfig containerConfig = containerConfigBuilder.build(); +// +// DockerServiceDockerClient result = new DockerServiceDockerClient(dockerClient, containerConfig, null, hostMode, networks); +// return result; +// } +//} diff --git a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceFactoryDockerClient.java b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceFactoryDockerClient.java index 5cbddd9..5594264 100644 --- a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceFactoryDockerClient.java +++ b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceFactoryDockerClient.java @@ -1,6 +1,7 @@ package org.hobbit.core.service.docker.impl.docker_client; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -11,7 +12,11 @@ import java.util.function.Supplier; import org.hobbit.core.service.docker.api.DockerService; +import org.hobbit.core.service.docker.api.DockerServiceBuilder; import org.hobbit.core.service.docker.api.DockerServiceFactory; +import org.hobbit.core.service.docker.api.DockerServiceSpec; +import org.hobbit.core.service.docker.api.DockerServiceSystem; +import org.hobbit.core.service.docker.impl.core.DockerServiceBuilderImpl; import org.hobbit.core.service.docker.util.EnvironmentUtils; import com.spotify.docker.client.DefaultDockerClient; @@ -23,7 +28,8 @@ import com.spotify.docker.client.messages.PortBinding; public class DockerServiceFactoryDockerClient - implements DockerServiceFactory + //implements DockerServiceFactory + implements DockerServiceSystem { protected DockerClient dockerClient; protected Supplier containerConfigBuilderSupplier; @@ -92,14 +98,36 @@ public static String deriveHostname(String imageName) { } @Override - public DockerService create(String imageName, Map localEnv) { - Builder builder = containerConfigBuilderSupplier.get(); - Map env = new LinkedHashMap<>(); - env.putAll(EnvironmentUtils.listToMap(builder.build().env())); - env.putAll(localEnv); + public DockerService create(DockerServiceSpec serviceSpec) { - String containerName = null; - if(!hostMode) { + String containerName = serviceSpec.getContainerName(); + String imageName = serviceSpec.getImageName(); + Map localEnv = serviceSpec.getLocalEnvironment(); + + Builder builder = null; + if(serviceSpec instanceof DockerServiceSpecDockerClient) { + DockerServiceSpecDockerClient tmp = (DockerServiceSpecDockerClient)serviceSpec; + + //DockerServiceSpecContainerConfig.finalizeContainerConfig(tmp); + + builder = tmp.getContainerConfigBuilder(); + } + + if(builder == null) { + builder = containerConfigBuilderSupplier.get(); + } + + + List rawEnv = builder.build().env(); + if(rawEnv == null) { + rawEnv = Collections.emptyList(); + } + + Map env = EnvironmentUtils.listToMap(rawEnv); + env.putAll(localEnv); + + //String containerName = null; + if(containerName == null && !hostMode) { String hostname = deriveHostname(imageName); builder.hostname(hostname); containerName = hostname; @@ -120,7 +148,6 @@ public static DockerServiceFactory create( boolean hostMode, Map env, Set networks) throws DockerCertificateException { DockerClient dockerClient = DefaultDockerClient.fromEnv().build(); - // Bind container port 443 to an automatically allocated available host String[] ports = { }; //{ "80", "22" }; Map> portBindings = new HashMap<>(); @@ -152,9 +179,40 @@ public static DockerServiceFactory create( return result; } - @Override public void close() throws Exception { dockerClient.close(); - } + } + + + @Override + public DockerServiceBuilder newServiceBuilder() { + Builder containerConfigBuilder = containerConfigBuilderSupplier.get(); + + DockerServiceSpec serviceSpec = DockerServiceSpecDockerClient.wrap(containerConfigBuilder); + +// // // Merge the local environment into that of the containerConfig +// List rawEnv = containerConfigBuilder.build().env(); +// if(rawEnv == null) { +// rawEnv = Collections.emptyList(); +// } +// +// Map env = EnvironmentUtils.listToMap(rawEnv); +// env.putAll(localEnv); +// +// List envList = EnvironmentUtils.mapToList(env); +// containerConfigBuilder.env(envList); +// ContainerConfig containerConfig = containerConfigBuilder.build(); +// +// DockerServiceDockerClient result = new DockerServiceDockerClient(dockerClient, containerConfig, null, hostMode, networks); +// return result; +// + + return new DockerServiceBuilderImpl<>(this, serviceSpec); + } + +// @Override +// public DockerServiceSpec newSpec() { +// return new DockerServiceSpecImpl(); +// } } diff --git a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSpecDockerClient.java b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSpecDockerClient.java new file mode 100644 index 0000000..09f2603 --- /dev/null +++ b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSpecDockerClient.java @@ -0,0 +1,114 @@ +package org.hobbit.core.service.docker.impl.docker_client; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.hobbit.core.service.docker.api.DockerServiceSpec; +import org.hobbit.core.service.docker.util.EnvironmentUtils; + +import com.spotify.docker.client.messages.ContainerConfig; + +/** + * DockerServceSpec implementation that is backed by + * DockerClient's containerConfig object + * + * @author Claus Stadler, Jan 9, 2019 + * + */ +public class DockerServiceSpecDockerClient + implements DockerServiceSpec +{ + protected ContainerConfig.Builder containerConfigBuilder; + protected boolean hostMode; + protected Set networks; + protected String containerName; + + protected Map localEnv = new LinkedHashMap<>(); + + + public static DockerServiceSpecDockerClient wrap(ContainerConfig.Builder containerConfigBuilder) { + DockerServiceSpecDockerClient result = new DockerServiceSpecDockerClient(); + result.setContainerConfigBuilder(containerConfigBuilder); + + return result; + } + + public ContainerConfig.Builder getContainerConfigBuilder() { + return containerConfigBuilder; + } + + public DockerServiceSpecDockerClient setContainerConfigBuilder(ContainerConfig.Builder containerConfigBuilder) { + this.containerConfigBuilder = containerConfigBuilder; + return this; + } + + @Override + public String getContainerName() { + return containerName; + } + + @Override + public DockerServiceSpec setContainerName(String containerName) { + this.containerName = containerName; + return this; + } + + + public String getImageName() { + return containerConfigBuilder.build().image(); + } + + public DockerServiceSpecDockerClient setImageName(String imageName) { + containerConfigBuilder.image(imageName); + return this; + } + + @Override + public Map getLocalEnvironment() { + return localEnv; + } + + @Override + public DockerServiceSpecDockerClient setLocalEnvironment(Map environment) { + this.localEnv = environment; + return this; + } + + public Set getNetworks() { + return networks; + } + + public boolean isHostMode() { + return hostMode; + } + + /** + * Specifically, merges the local environment into that of the containerConfig + * + * @return + */ + public static void finalizeContainerConfig(DockerServiceSpecDockerClient config) { + //Objects.requireNonNull(containerConfigBuilder); + ContainerConfig.Builder containerConfigBuilder = config.getContainerConfigBuilder(); + Map localEnv = config.getLocalEnvironment(); + + // Merge the local environment into that of the containerConfig + List rawEnv = containerConfigBuilder.build().env(); + if (rawEnv == null) { + rawEnv = Collections.emptyList(); + } + + Map env = EnvironmentUtils.listToMap(rawEnv); + env.putAll(localEnv); + + List envList = EnvironmentUtils.mapToList(env); + containerConfigBuilder.env(envList); + //ContainerConfig containerConfig = containerConfigBuilder.build(); + + //return containerConfig; + } + +} diff --git a/docker-service-api-examples/src/main/java/org/hobbit/core/service/docker/example/MainDockerServiceExampleVirtuoso.java b/docker-service-api-examples/src/main/java/org/hobbit/core/service/docker/example/MainDockerServiceExampleVirtuoso.java index 9d41ec4..35431ce 100644 --- a/docker-service-api-examples/src/main/java/org/hobbit/core/service/docker/example/MainDockerServiceExampleVirtuoso.java +++ b/docker-service-api-examples/src/main/java/org/hobbit/core/service/docker/example/MainDockerServiceExampleVirtuoso.java @@ -26,7 +26,7 @@ public static void main(String[] args) throws DockerCertificateException, Except try (DockerServiceFactory dsf = DockerServiceFactoryDockerClient.create(true, Collections.emptyMap(), Collections.emptySet())) { - DockerService ds = dsf.create("tenforce/virtuoso", ImmutableMap.builder() + DockerService ds = dsf.create(null, "tenforce/virtuoso", ImmutableMap.builder() .put("SPARQL_UPDATE", "true") .put("DEFAULT_GRAPH", "http://www.example.org/") .build()); diff --git a/docker-service-api-spring-boot/pom.xml b/docker-service-api-spring-boot/pom.xml index dad63b6..5b95cff 100644 --- a/docker-service-api-spring-boot/pom.xml +++ b/docker-service-api-spring-boot/pom.xml @@ -13,6 +13,7 @@ + org.hobbit docker-service-api-core diff --git a/docker-service-api-spring-boot/src/main/java/org/hobbit/core/service/docker/impl/spring_boot/DockerServiceFactorySpringApplicationBuilder.java b/docker-service-api-spring-boot/src/main/java/org/hobbit/core/service/docker/impl/spring_boot/DockerServiceFactorySpringApplicationBuilder.java index 3c86e83..6d1de69 100644 --- a/docker-service-api-spring-boot/src/main/java/org/hobbit/core/service/docker/impl/spring_boot/DockerServiceFactorySpringApplicationBuilder.java +++ b/docker-service-api-spring-boot/src/main/java/org/hobbit/core/service/docker/impl/spring_boot/DockerServiceFactorySpringApplicationBuilder.java @@ -11,7 +11,9 @@ import org.hobbit.core.service.docker.api.DockerService; import org.hobbit.core.service.docker.api.DockerServiceFactory; +import org.hobbit.core.service.docker.api.DockerServiceSpec; import org.hobbit.core.service.docker.impl.core.DockerServicePseudoDelegate; +import org.hobbit.core.service.docker.impl.core.DockerServiceSpecImpl; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; @@ -63,8 +65,17 @@ public static SpringApplicationBuilder getParent(SpringApplicationBuilder appBui } @Override - public DockerService create(String imageName, Map env) { + public void close() throws Exception { + } + + @Override + public DockerService create(DockerServiceSpec serviceSpec) { + + //String containerName = serviceSpec.getContainerName(); + String imageName = serviceSpec.getImageName(); + Map localEnv = serviceSpec.getLocalEnvironment(); + Supplier imageConfigSupplier = imageNameToConfigSupplier.get(imageName); if(imageConfigSupplier == null) { throw new UnsupportedOperationException("No image '" + imageName + "' registered with this docker service factory"); @@ -75,7 +86,7 @@ public DockerService create(String imageName, Map env) { SpringApplicationBuilder appBuilder = imageConfigSupplier.get(); SpringApplicationBuilder rootBuilder = getRoot(appBuilder, DockerServiceFactorySpringApplicationBuilder::getParent); - Map env2 = env.entrySet().stream().collect(Collectors.toMap(Entry::getKey, x -> (Object)x.getValue())); + Map env2 = localEnv.entrySet().stream().collect(Collectors.toMap(Entry::getKey, x -> (Object)x.getValue())); ConfigurableEnvironment cenv = new StandardEnvironment(); cenv.getPropertySources().addFirst(new MapPropertySource("myPropertySource", env2)); @@ -92,9 +103,10 @@ public DockerService create(String imageName, Map env) { return result; } - @Override - public void close() throws Exception { - } +// @Override +// public DockerServiceSpec newSpec() { +// return new DockerServiceSpecImpl(); +// } } diff --git a/pom.xml b/pom.xml index 371fcb7..b12f4ee 100644 --- a/pom.xml +++ b/pom.xml @@ -53,6 +53,11 @@ ${project.version} + + org.apache.jena + jena-arq + 3.9.0 + @@ -346,6 +351,7 @@ University Leipzig, AKSW Maven2 Repository http://maven.aksw.org/repository/snapshots + From 762ca0fbc8ecec8daa30ad3dc88b45f3e7f47ecf Mon Sep 17 00:00:00 2001 From: Claus Stadler Date: Sun, 13 Jan 2019 01:09:53 +0100 Subject: [PATCH 2/9] Some fixes in the api --- .../service/docker/api/DockerService.java | 2 + .../docker/api/DockerServiceSystem.java | 7 ++-- ...elegate.java => DockerServiceWrapper.java} | 6 +-- ...a => DockerServiceSystemDockerClient.java} | 41 ++++++++++++++++--- .../MainDockerServiceExampleVirtuoso.java | 9 ++-- ...erviceFactorySpringApplicationBuilder.java | 4 +- 6 files changed, 51 insertions(+), 18 deletions(-) rename docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/{DockerServicePseudoDelegate.java => DockerServiceWrapper.java} (89%) rename docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/{DockerServiceFactoryDockerClient.java => DockerServiceSystemDockerClient.java} (84%) diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerService.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerService.java index 2c19b75..feb0ec2 100644 --- a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerService.java +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerService.java @@ -17,6 +17,8 @@ public interface DockerService /** * The container id of a once started service * + * TODO This is usually NOT the docker Id, but an IP address, a host name, or some other form of handle + * * @return */ String getContainerId(); diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSystem.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSystem.java index f269250..8996d1a 100644 --- a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSystem.java +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/api/DockerServiceSystem.java @@ -4,9 +4,10 @@ /** * A DockerServiceSystem combines both the factory and the builder APIs: * - The builder API creates preconfigured configuration objects that can be modified using the - * DockerServiceSpec API (possibly using casts) + * DockerServiceSpec API. Internal config objects may be accessible by casting the + * DockerServiceSpec config object. * - The factory API, which only takes a single service specification, and fills the rest up with - * default values based on the factory state. + * default values based on the factory state. This approach does not give access to internal config objects. * * @author Claus Stadler, Jan 9, 2019 * @@ -15,5 +16,5 @@ public interface DockerServiceSystem extends DockerServiceFactory, DockerServiceBuilderFactory { - + T findServiceByName(String id); } diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServicePseudoDelegate.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceWrapper.java similarity index 89% rename from docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServicePseudoDelegate.java rename to docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceWrapper.java index 9c6fb23..a57a9eb 100644 --- a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServicePseudoDelegate.java +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/impl/core/DockerServiceWrapper.java @@ -17,17 +17,17 @@ * * @param */ -public class DockerServicePseudoDelegate +public class DockerServiceWrapper extends ServiceDelegate implements DockerService { - private static final Logger logger = LoggerFactory.getLogger(DockerServicePseudoDelegate.class); + private static final Logger logger = LoggerFactory.getLogger(DockerServiceWrapper.class); protected String imageName; protected Supplier getContainerId; - public DockerServicePseudoDelegate(S service, String imageName, Supplier getContainerId) { + public DockerServiceWrapper(S service, String imageName, Supplier getContainerId) { super(service); this.imageName = imageName; this.getContainerId = getContainerId; diff --git a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceFactoryDockerClient.java b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSystemDockerClient.java similarity index 84% rename from docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceFactoryDockerClient.java rename to docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSystemDockerClient.java index 5594264..d86f64d 100644 --- a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceFactoryDockerClient.java +++ b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSystemDockerClient.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -13,7 +12,6 @@ import org.hobbit.core.service.docker.api.DockerService; import org.hobbit.core.service.docker.api.DockerServiceBuilder; -import org.hobbit.core.service.docker.api.DockerServiceFactory; import org.hobbit.core.service.docker.api.DockerServiceSpec; import org.hobbit.core.service.docker.api.DockerServiceSystem; import org.hobbit.core.service.docker.impl.core.DockerServiceBuilderImpl; @@ -21,13 +19,17 @@ import com.spotify.docker.client.DefaultDockerClient; import com.spotify.docker.client.DockerClient; +import com.spotify.docker.client.DockerClient.ListContainersParam; import com.spotify.docker.client.exceptions.DockerCertificateException; +import com.spotify.docker.client.exceptions.DockerException; +import com.spotify.docker.client.messages.Container; import com.spotify.docker.client.messages.ContainerConfig; import com.spotify.docker.client.messages.ContainerConfig.Builder; +import com.spotify.docker.client.messages.ContainerInfo; import com.spotify.docker.client.messages.HostConfig; import com.spotify.docker.client.messages.PortBinding; -public class DockerServiceFactoryDockerClient +public class DockerServiceSystemDockerClient //implements DockerServiceFactory implements DockerServiceSystem { @@ -37,7 +39,7 @@ public class DockerServiceFactoryDockerClient protected Set networks; - public DockerServiceFactoryDockerClient( + public DockerServiceSystemDockerClient( DockerClient dockerClient, Supplier containerConfigBuilderSupplier, boolean hostMode, @@ -144,7 +146,7 @@ public DockerService create(DockerServiceSpec serviceSpec) { } - public static DockerServiceFactory create( + public static DockerServiceSystem create( boolean hostMode, Map env, Set networks) throws DockerCertificateException { DockerClient dockerClient = DefaultDockerClient.fromEnv().build(); @@ -175,7 +177,7 @@ public static DockerServiceFactory create( ; //Set networks = Collections.singleton("hobbit"); - DockerServiceFactoryDockerClient result = new DockerServiceFactoryDockerClient(dockerClient, containerConfigBuilderSupplier, hostMode, networks); + DockerServiceSystemDockerClient result = new DockerServiceSystemDockerClient(dockerClient, containerConfigBuilderSupplier, hostMode, networks); return result; } @@ -211,6 +213,33 @@ public DockerServiceBuilder newServiceBuilder() { return new DockerServiceBuilderImpl<>(this, serviceSpec); } + + @Override + public DockerService findServiceByName(String name) { + List containers; + try { + containers = dockerClient.listContainers(ListContainersParam.allContainers()); + } catch (DockerException | InterruptedException e) { + throw new RuntimeException(e); + } + + for (Container container : containers) { + List names = container.names(); + if(names.contains(name)) { + System.out.println("Got container with name: " + name); + } +// String containerId = container.names(); +// if(containerId.equals(id)) { +// if (imageName.equals(container.image())) { +// ContainerInfo containerInfo = dockerClient.inspectContainer(container.id()); +// if (containerInfo.state().running()) { +// } +// } + } + // TODO Auto-generated method stub + return null; + } + // @Override // public DockerServiceSpec newSpec() { // return new DockerServiceSpecImpl(); diff --git a/docker-service-api-examples/src/main/java/org/hobbit/core/service/docker/example/MainDockerServiceExampleVirtuoso.java b/docker-service-api-examples/src/main/java/org/hobbit/core/service/docker/example/MainDockerServiceExampleVirtuoso.java index 35431ce..546221c 100644 --- a/docker-service-api-examples/src/main/java/org/hobbit/core/service/docker/example/MainDockerServiceExampleVirtuoso.java +++ b/docker-service-api-examples/src/main/java/org/hobbit/core/service/docker/example/MainDockerServiceExampleVirtuoso.java @@ -15,8 +15,8 @@ import org.apache.jena.riot.WebContent; import org.apache.jena.sparql.engine.http.QueryEngineHTTP; import org.hobbit.core.service.docker.api.DockerService; -import org.hobbit.core.service.docker.api.DockerServiceFactory; -import org.hobbit.core.service.docker.impl.docker_client.DockerServiceFactoryDockerClient; +import org.hobbit.core.service.docker.api.DockerServiceSystem; +import org.hobbit.core.service.docker.impl.docker_client.DockerServiceSystemDockerClient; import com.google.common.collect.ImmutableMap; import com.spotify.docker.client.exceptions.DockerCertificateException; @@ -24,9 +24,9 @@ public class MainDockerServiceExampleVirtuoso { public static void main(String[] args) throws DockerCertificateException, Exception { - try (DockerServiceFactory dsf = DockerServiceFactoryDockerClient.create(true, Collections.emptyMap(), Collections.emptySet())) { + try (DockerServiceSystem dss = DockerServiceSystemDockerClient.create(true, Collections.emptyMap(), Collections.emptySet())) { - DockerService ds = dsf.create(null, "tenforce/virtuoso", ImmutableMap.builder() + DockerService ds = dss.create("docker-service-example", "tenforce/virtuoso", ImmutableMap.builder() .put("SPARQL_UPDATE", "true") .put("DEFAULT_GRAPH", "http://www.example.org/") .build()); @@ -41,6 +41,7 @@ public static void main(String[] args) throws DockerCertificateException, Except String sparqlApiBase = "http://" + ds.getContainerId() + ":8890/"; String sparqlEndpoint = sparqlApiBase + "sparql"; + dss.findServiceByName("docker-service-example"); try(RDFConnection rawConn = RDFConnectionFactory.connect(sparqlEndpoint)) { diff --git a/docker-service-api-spring-boot/src/main/java/org/hobbit/core/service/docker/impl/spring_boot/DockerServiceFactorySpringApplicationBuilder.java b/docker-service-api-spring-boot/src/main/java/org/hobbit/core/service/docker/impl/spring_boot/DockerServiceFactorySpringApplicationBuilder.java index 6d1de69..dbb1def 100644 --- a/docker-service-api-spring-boot/src/main/java/org/hobbit/core/service/docker/impl/spring_boot/DockerServiceFactorySpringApplicationBuilder.java +++ b/docker-service-api-spring-boot/src/main/java/org/hobbit/core/service/docker/impl/spring_boot/DockerServiceFactorySpringApplicationBuilder.java @@ -12,7 +12,7 @@ import org.hobbit.core.service.docker.api.DockerService; import org.hobbit.core.service.docker.api.DockerServiceFactory; import org.hobbit.core.service.docker.api.DockerServiceSpec; -import org.hobbit.core.service.docker.impl.core.DockerServicePseudoDelegate; +import org.hobbit.core.service.docker.impl.core.DockerServiceWrapper; import org.hobbit.core.service.docker.impl.core.DockerServiceSpecImpl; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.core.env.ConfigurableEnvironment; @@ -99,7 +99,7 @@ public DockerService create(DockerServiceSpec serviceSpec) { Service service = new ServiceSpringApplicationBuilder(imageName, appBuilder); - DockerService result = new DockerServicePseudoDelegate<>(service, imageName, idStrSupplier); + DockerService result = new DockerServiceWrapper<>(service, imageName, idStrSupplier); return result; } From c5bbf75d065c135eb7a833512cc1fb713bb408ef Mon Sep 17 00:00:00 2001 From: Claus Stadler Date: Fri, 5 Apr 2019 01:33:01 +0200 Subject: [PATCH 3/9] Added support for container labels --- .../impl/docker_client/DockerServiceDockerClient.java | 4 ++-- .../docker_client/DockerServiceSystemDockerClient.java | 10 ++++++++-- pom.xml | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceDockerClient.java b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceDockerClient.java index 89c3c17..4a607e5 100644 --- a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceDockerClient.java +++ b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceDockerClient.java @@ -42,7 +42,7 @@ public class DockerServiceDockerClient // Status fields for running services // Container id (requires the service to be running) protected String containerId; - protected Integer exitCode; + protected Long exitCode; protected String containerName; @@ -233,7 +233,7 @@ protected Scheduler scheduler() { @Override public Integer getExitCode() { //logger.warn("STUB! Exist code always returns 0"); - return exitCode; + return exitCode != null ? exitCode.intValue() : null; } } diff --git a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSystemDockerClient.java b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSystemDockerClient.java index d86f64d..65234a6 100644 --- a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSystemDockerClient.java +++ b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSystemDockerClient.java @@ -25,7 +25,6 @@ import com.spotify.docker.client.messages.Container; import com.spotify.docker.client.messages.ContainerConfig; import com.spotify.docker.client.messages.ContainerConfig.Builder; -import com.spotify.docker.client.messages.ContainerInfo; import com.spotify.docker.client.messages.HostConfig; import com.spotify.docker.client.messages.PortBinding; @@ -56,6 +55,13 @@ public DockerServiceSystemDockerClient( this.networks = networks; } + /** + * + * @return the backing docker client instance + */ + public DockerClient getDockerClient() { + return dockerClient; + } // public static boolean containsVersionTag(String imageName) { // int pos = 0; @@ -146,7 +152,7 @@ public DockerService create(DockerServiceSpec serviceSpec) { } - public static DockerServiceSystem create( + public static DockerServiceSystemDockerClient create( boolean hostMode, Map env, Set networks) throws DockerCertificateException { DockerClient dockerClient = DefaultDockerClient.fromEnv().build(); diff --git a/pom.xml b/pom.xml index b12f4ee..9a36c9c 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ com.spotify docker-client - 8.9.0 + 8.15.1 ch.qos.logback From 8c667c45325ff64999fe9495df325d8b17d74e26 Mon Sep 17 00:00:00 2001 From: Claus Stadler Date: Mon, 8 Apr 2019 16:29:02 +0200 Subject: [PATCH 4/9] Minor updates to the service api to give access to backing objects --- .../impl/docker_client/DockerServiceDockerClient.java | 11 +++++++++-- .../DockerServiceSystemDockerClient.java | 8 ++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceDockerClient.java b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceDockerClient.java index 4a607e5..5860c03 100644 --- a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceDockerClient.java +++ b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceDockerClient.java @@ -48,6 +48,9 @@ public class DockerServiceDockerClient protected boolean hostMode; + + protected String creationId; + public DockerServiceDockerClient(DockerClient dockerClient, ContainerConfig containerConfig, String name, boolean hostMode, Set networks) { super(); this.dockerClient = dockerClient; @@ -64,8 +67,8 @@ protected void startUp() throws Exception { logger.info("Attempting to start docker container: " + getImageName() + " env: " + containerConfig.env() + " hostMode: " + hostMode + " networks: " + networks); ContainerCreation creation = dockerClient.createContainer(containerConfig, name); - containerId = creation.id(); - + creationId = creation.id(); + containerId = creationId; ContainerInfo containerInfo = dockerClient.inspectContainer(containerId); @@ -203,6 +206,10 @@ public String getImageName() { return result; } + public String getCreationId() { + return creationId; + } + @Override public String getContainerId() { //return containerId; diff --git a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSystemDockerClient.java b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSystemDockerClient.java index 65234a6..99e1500 100644 --- a/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSystemDockerClient.java +++ b/docker-service-api-docker-client/src/main/java/org/hobbit/core/service/docker/impl/docker_client/DockerServiceSystemDockerClient.java @@ -30,7 +30,7 @@ public class DockerServiceSystemDockerClient //implements DockerServiceFactory - implements DockerServiceSystem + implements DockerServiceSystem { protected DockerClient dockerClient; protected Supplier containerConfigBuilderSupplier; @@ -106,7 +106,7 @@ public static String deriveHostname(String imageName) { } @Override - public DockerService create(DockerServiceSpec serviceSpec) { + public DockerServiceDockerClient create(DockerServiceSpec serviceSpec) { String containerName = serviceSpec.getContainerName(); String imageName = serviceSpec.getImageName(); @@ -194,7 +194,7 @@ public void close() throws Exception { @Override - public DockerServiceBuilder newServiceBuilder() { + public DockerServiceBuilder newServiceBuilder() { Builder containerConfigBuilder = containerConfigBuilderSupplier.get(); DockerServiceSpec serviceSpec = DockerServiceSpecDockerClient.wrap(containerConfigBuilder); @@ -221,7 +221,7 @@ public DockerServiceBuilder newServiceBuilder() { @Override - public DockerService findServiceByName(String name) { + public DockerServiceDockerClient findServiceByName(String name) { List containers; try { containers = dockerClient.listContainers(ListContainersParam.allContainers()); From cd3e2e8dafb68e7484f403f1fc30d3f750e6a887 Mon Sep 17 00:00:00 2001 From: Claus Stadler Date: Tue, 20 Aug 2019 17:54:40 +0200 Subject: [PATCH 5/9] bumped versions --- pom.xml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 9a36c9c..3a8db23 100644 --- a/pom.xml +++ b/pom.xml @@ -11,11 +11,13 @@ - 3.8.0 - ${jena.version}-1-SNAPSHOT - 4.3.11.RELEASE + 3.12.0 + ${jena.version}-2-SNAPSHOT + 1.7.25 + 2.1.6.RELEASE + UTF-8 1.8 1.8 @@ -56,7 +58,7 @@ org.apache.jena jena-arq - 3.9.0 + ${jena.version} @@ -75,22 +77,22 @@ org.springframework.boot spring-boot - 1.5.7.RELEASE + ${spring-boot.version} org.springframework.boot spring-boot-autoconfigure - 1.5.7.RELEASE + ${spring-boot.version} org.springframework.boot spring-boot-loader - 1.5.7.RELEASE + ${spring-boot.version} - + com.google.guava From 5bcf199e0ff15659cdf6ce18447e5fba3fd11176 Mon Sep 17 00:00:00 2001 From: Claus Stadler Date: Thu, 22 Aug 2019 14:22:02 +0200 Subject: [PATCH 6/9] bumped version --- docker-service-api-spring-boot/pom.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docker-service-api-spring-boot/pom.xml b/docker-service-api-spring-boot/pom.xml index 5b95cff..a3d0ca4 100644 --- a/docker-service-api-spring-boot/pom.xml +++ b/docker-service-api-spring-boot/pom.xml @@ -24,6 +24,15 @@ spring-boot + + org.springframework.boot + spring-boot-loader + + + org.springframework.boot + spring-boot-autoconfigure + + From e3c214c7f889a80b553a426d4539b1a04f50f42a Mon Sep 17 00:00:00 2001 From: Claus Stadler Date: Thu, 26 Sep 2019 14:58:23 +0200 Subject: [PATCH 7/9] bumped guava version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3a8db23..df89a5d 100644 --- a/pom.xml +++ b/pom.xml @@ -127,7 +127,7 @@ com.google.guava guava - 23.0 + 27.0.1-jre From 7c33675efede6afb4d28022af226a39e6221cd48 Mon Sep 17 00:00:00 2001 From: Claus Stadler Date: Wed, 3 Jun 2020 14:44:19 +0200 Subject: [PATCH 8/9] bumped project version --- docker-service-api-core/pom.xml | 2 +- .../util/AbstractDockerServiceDelegate.java | 28 +++++ .../docker/util/AbstractServiceDelegate.java | 70 ++++++++++++ .../service/docker/util/ComponentUtils.java | 108 ++++++++++++++++++ .../docker/util/HealthcheckRunner.java | 89 +++++++++++++++ .../service/docker/util/HealthcheckUtils.java | 41 +++++++ docker-service-api-docker-client/pom.xml | 2 +- docker-service-api-examples/pom.xml | 2 +- docker-service-api-spring-boot/pom.xml | 2 +- pom.xml | 6 +- 10 files changed, 343 insertions(+), 7 deletions(-) create mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/AbstractDockerServiceDelegate.java create mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/AbstractServiceDelegate.java create mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/ComponentUtils.java create mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckRunner.java create mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckUtils.java diff --git a/docker-service-api-core/pom.xml b/docker-service-api-core/pom.xml index 90e9aad..c856cf3 100644 --- a/docker-service-api-core/pom.xml +++ b/docker-service-api-core/pom.xml @@ -9,7 +9,7 @@ org.hobbit docker-service-api-parent - 1.0.0-SNAPSHOT + 1.0.1-SNAPSHOT diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/AbstractDockerServiceDelegate.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/AbstractDockerServiceDelegate.java new file mode 100644 index 0000000..ab5dd2c --- /dev/null +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/AbstractDockerServiceDelegate.java @@ -0,0 +1,28 @@ +package org.hobbit.core.service.docker.util; + +import org.hobbit.core.service.docker.api.DockerService; + +public class AbstractDockerServiceDelegate + extends AbstractServiceDelegate + implements DockerService // TODO There could be default methods for delegation +{ + public AbstractDockerServiceDelegate(S delegate) { + super(delegate); + } + + @Override + public String getImageName() { + return delegate.getImageName(); + } + + @Override + public String getContainerId() { + return delegate.getContainerId(); + } + + @Override + public Integer getExitCode() { + return delegate.getExitCode(); + } + +} \ No newline at end of file diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/AbstractServiceDelegate.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/AbstractServiceDelegate.java new file mode 100644 index 0000000..74d4968 --- /dev/null +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/AbstractServiceDelegate.java @@ -0,0 +1,70 @@ +package org.hobbit.core.service.docker.util; + +import com.google.common.util.concurrent.AbstractService; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.common.util.concurrent.Service; + +/** + * Service wrapper that allows post start and post stop action to be appended + * to an existing service. + * The service wrapper is only considered started/stopped when the post + * action is completed. + * + * @author raven + * + * @param + */ +public class AbstractServiceDelegate + extends AbstractService +{ + protected S delegate; + + public AbstractServiceDelegate(S delegate) { + super(); + this.delegate = delegate; + } + + @Override + protected void doStart() { + delegate.addListener(new Listener() { + @Override + public void running() { + try { + afterStart(); + } catch(Exception e) { + delegate.stopAsync(); + notifyFailed(e); + } + + notifyStarted(); + } + @Override + public void failed(State priorState, Throwable t) { + notifyFailed(t); + } + + @Override + public void terminated(State priorState) { + try { + afterStop(); + } finally { + notifyStopped(); + } + } + }, MoreExecutors.directExecutor()); + + delegate.startAsync(); + } + + @Override + protected void doStop() { + delegate.stopAsync(); + } + + public void afterStart() { + } + + public void afterStop() { + } +} + diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/ComponentUtils.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/ComponentUtils.java new file mode 100644 index 0000000..540cd38 --- /dev/null +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/ComponentUtils.java @@ -0,0 +1,108 @@ +package org.hobbit.core.service.docker.util; + +import java.net.URL; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.hobbit.core.service.docker.api.DockerService; +import org.hobbit.core.service.docker.api.DockerServiceFactory; +import org.hobbit.core.service.docker.api.DockerServiceSpec; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ComponentUtils { + private static final Logger logger = LoggerFactory.getLogger(ComponentUtils.class); + + public static final String COMPONENT_NAME_KEY = "componentName"; + public static final String DEFAULT_REQUESTED_CONTAINER_TYPE_KEY = "defaultRequstedContainerType"; + + + +// public static DockerServiceFactory createVirtualComponentDockerServiceFactory() { +// +// Map> virtualDockerComponentRegistry = getVirtualDockerComponentRegistry(); +// DockerServiceFactory result = new DockerServiceFactorySpringApplicationBuilder(virtualDockerComponentRegistry); +// +// return result; +// } + + + public static DockerService wrapSparqlServiceWithHealthCheck(S dockerService, Function healthCheckUrlFromServiceDelegate) { + + DockerService result = new AbstractDockerServiceDelegate(dockerService) { + // FIXME We want to enhance the startup method within the thread allocated by the guava service + @Override + public void afterStart() { + // The delegate has started, so we have a container id + //String host = delegate.getContainerId(); + String urlStr = healthCheckUrlFromServiceDelegate.apply(delegate); + + //String destination = "http://" + host + (port == null ? "" : ":" + port) + "/sparql"; + + URL url = HealthcheckUtils.createUrl(urlStr); + + new HealthcheckRunner( + 60, 1, TimeUnit.SECONDS, () -> { + HealthcheckUtils.checkUrl(url); + + // This part seems to leak connections with jena 3.7.0 as long as the endpoint is not ready +// try (RDFConnection conn = RDFConnectionFactory.connect(destination)) { +// //conn.querySelect("SELECT * { a ?t }", qs -> {}); +// ResultSetFormatter.consume(conn.query("SELECT * { a ?t }").execSelect()); +// } + }).run(); + } + }; + + return result; + } + + public static DockerService wrapSparqlServiceWithHealthCheck(DockerService dockerService, Integer port) { + return wrapSparqlServiceWithHealthCheck(dockerService, delegate -> "http://" + delegate.getContainerId() + (port == null ? "" : ":" + port) + "/sparql"); + } + + + public static DockerServiceFactory applyServiceWrappers(DockerServiceFactory delegate) { + + // Service wrappers which modifies startup/shutdown of other services; mostly healthchecks + // on startup + Map> serviceWrappers = new LinkedHashMap<>(); + serviceWrappers.put(Pattern.compile("virtuoso"), dockerService -> wrapSparqlServiceWithHealthCheck(dockerService, 8890)); + DockerServiceFactory result = new DockerServiceFactory() { + + @Override + public DockerService create(DockerServiceSpec serviceSpec) { + + String imageName = serviceSpec.getImageName(); + + DockerService r = delegate.create(serviceSpec); + + Map> cands = + serviceWrappers.entrySet().stream() + .filter(x -> x.getKey().matcher(imageName).find()) + .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); + + + for(Entry> cand : cands.entrySet()) { + logger.info("Applying service decorator: " + cand.getKey() + " to docker image " + imageName); + r = cand.getValue().apply(r); + } + + return r; + } + + @Override + public void close() throws Exception { + delegate.close(); + } + }; + + return result; + } + +} \ No newline at end of file diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckRunner.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckRunner.java new file mode 100644 index 0000000..fc3f1b5 --- /dev/null +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckRunner.java @@ -0,0 +1,89 @@ +package org.hobbit.core.service.docker.util; + +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.concurrent.TimeUnit; + +import org.apache.jena.shared.NotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HealthcheckRunner + implements Runnable +{ + private static final Logger logger = LoggerFactory.getLogger(HealthcheckRunner.class); + + protected long healthcheckRetryCount; + protected long healthcheckInterval; + protected TimeUnit healthcheckIntervalUnit; + protected Runnable healthcheckAction; + + public HealthcheckRunner(long healthcheckRetryCount, long healthcheckInterval, TimeUnit healthcheckIntervalUnit, + Runnable healthcheck) { + super(); + this.healthcheckRetryCount = healthcheckRetryCount; + this.healthcheckInterval = healthcheckInterval; + this.healthcheckIntervalUnit = healthcheckIntervalUnit; + this.healthcheckAction = healthcheck; + } + + @Override + public void run() { + + // Wait for the health check to succeed the first time + boolean success = false; + Exception lastException = null; + + int i = 0; + for(; i < healthcheckRetryCount; ++i) { + try { + healthcheckAction.run(); + logger.debug("Health check status: success"); + success = true; + break; + } catch(Exception e) { + logger.debug("Health check status: not ok - " + (healthcheckRetryCount - i) + " retries remaining"); + lastException = e; + } + + try { + healthcheckIntervalUnit.sleep(healthcheckInterval); + } catch (InterruptedException e) { + break; + } + } + + if(!success) { + throw new RuntimeException("Startup considered failed after " + i + " failed health checks", lastException); + } + } + + public static URL createUrl(String str) { + URL url; + try { + url = new URL(str); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + return url; + } + + public static void checkUrl(URL url) { + try { + HttpURLConnection connection = (HttpURLConnection)url.openConnection(); + try { + connection.setRequestMethod("GET"); + connection.connect(); + int code = connection.getResponseCode(); + if(code != 200) { + throw new NotFoundException(url.toString()); + } + } finally { + connection.disconnect(); + } + } catch(Exception e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckUtils.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckUtils.java new file mode 100644 index 0000000..cf5b5d1 --- /dev/null +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckUtils.java @@ -0,0 +1,41 @@ +package org.hobbit.core.service.docker.util; + +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; + +import org.apache.jena.shared.NotFoundException; + +public class HealthcheckUtils { + + public static URL createUrl(String str) { + URL url; + try { + url = new URL(str); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + return url; + } + + + public static void checkUrl(URL url) { + try { + HttpURLConnection connection = (HttpURLConnection)url.openConnection(); + try { + connection.setRequestMethod("GET"); + connection.connect(); + int code = connection.getResponseCode(); + if(code != 200) { + //logger.info("Health check status: fail"); + throw new NotFoundException(url.toString()); + } + } finally { + connection.disconnect(); + } + //logger.info("Health check status: success"); + } catch(Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/docker-service-api-docker-client/pom.xml b/docker-service-api-docker-client/pom.xml index 1740fae..f50d38e 100644 --- a/docker-service-api-docker-client/pom.xml +++ b/docker-service-api-docker-client/pom.xml @@ -9,7 +9,7 @@ org.hobbit docker-service-api-parent - 1.0.0-SNAPSHOT + 1.0.1-SNAPSHOT diff --git a/docker-service-api-examples/pom.xml b/docker-service-api-examples/pom.xml index 4539bc3..b89d96f 100644 --- a/docker-service-api-examples/pom.xml +++ b/docker-service-api-examples/pom.xml @@ -9,7 +9,7 @@ org.hobbit docker-service-api-parent - 1.0.0-SNAPSHOT + 1.0.1-SNAPSHOT diff --git a/docker-service-api-spring-boot/pom.xml b/docker-service-api-spring-boot/pom.xml index a3d0ca4..14c6dd6 100644 --- a/docker-service-api-spring-boot/pom.xml +++ b/docker-service-api-spring-boot/pom.xml @@ -9,7 +9,7 @@ org.hobbit docker-service-api-parent - 1.0.0-SNAPSHOT + 1.0.1-SNAPSHOT diff --git a/pom.xml b/pom.xml index df89a5d..7448402 100644 --- a/pom.xml +++ b/pom.xml @@ -6,13 +6,13 @@ org.hobbit docker-service-api-parent - 1.0.0-SNAPSHOT + 1.0.1-SNAPSHOT pom - 3.12.0 - ${jena.version}-2-SNAPSHOT + 3.15.0 + ${jena.version}-1-SNAPSHOT 1.7.25 From a680985c24d5570b3810dc8e7a4539d9f28031d3 Mon Sep 17 00:00:00 2001 From: Claus Stadler Date: Wed, 14 Jun 2023 17:51:40 +0200 Subject: [PATCH 9/9] Bumped legacy project dependencies --- docker-service-api-core/pom.xml | 7 +- .../service/docker/util/ComponentUtils.java | 30 ++++--- .../docker/util/HealthcheckRunner.java | 89 ------------------- .../service/docker/util/HealthcheckUtils.java | 41 --------- docker-service-api-docker-client/pom.xml | 2 +- docker-service-api-examples/pom.xml | 2 +- docker-service-api-spring-boot/pom.xml | 2 +- pom.xml | 7 +- 8 files changed, 34 insertions(+), 146 deletions(-) delete mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckRunner.java delete mode 100644 docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckUtils.java diff --git a/docker-service-api-core/pom.xml b/docker-service-api-core/pom.xml index c856cf3..8c7c213 100644 --- a/docker-service-api-core/pom.xml +++ b/docker-service-api-core/pom.xml @@ -9,10 +9,15 @@ org.hobbit docker-service-api-parent - 1.0.1-SNAPSHOT + 1.1.0-SNAPSHOT + + org.aksw.commons + aksw-commons-utils + + org.apache.jena jena-arq diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/ComponentUtils.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/ComponentUtils.java index 540cd38..960b1ba 100644 --- a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/ComponentUtils.java +++ b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/ComponentUtils.java @@ -9,6 +9,8 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import org.aksw.commons.util.healthcheck.HealthcheckRunner; +import org.aksw.commons.util.healthcheck.HealthcheckUtils; import org.hobbit.core.service.docker.api.DockerService; import org.hobbit.core.service.docker.api.DockerServiceFactory; import org.hobbit.core.service.docker.api.DockerServiceSpec; @@ -45,17 +47,23 @@ public void afterStart() { //String destination = "http://" + host + (port == null ? "" : ":" + port) + "/sparql"; URL url = HealthcheckUtils.createUrl(urlStr); - - new HealthcheckRunner( - 60, 1, TimeUnit.SECONDS, () -> { - HealthcheckUtils.checkUrl(url); - - // This part seems to leak connections with jena 3.7.0 as long as the endpoint is not ready -// try (RDFConnection conn = RDFConnectionFactory.connect(destination)) { -// //conn.querySelect("SELECT * { a ?t }", qs -> {}); -// ResultSetFormatter.consume(conn.query("SELECT * { a ?t }").execSelect()); -// } - }).run(); + HealthcheckRunner.builder() + .setRetryCount(60) + .setInterval(1, TimeUnit.SECONDS) + .setAction(() -> HealthcheckUtils.checkUrl(url)) + .build() + .run(); + +// new HealthcheckRunner( +// 60, 1, TimeUnit.SECONDS, () -> { +// HealthcheckUtils.checkUrl(url); +// +// // This part seems to leak connections with jena 3.7.0 as long as the endpoint is not ready +//// try (RDFConnection conn = RDFConnectionFactory.connect(destination)) { +//// //conn.querySelect("SELECT * { a ?t }", qs -> {}); +//// ResultSetFormatter.consume(conn.query("SELECT * { a ?t }").execSelect()); +//// } +// }).run(); } }; diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckRunner.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckRunner.java deleted file mode 100644 index fc3f1b5..0000000 --- a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckRunner.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.hobbit.core.service.docker.util; - -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.concurrent.TimeUnit; - -import org.apache.jena.shared.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class HealthcheckRunner - implements Runnable -{ - private static final Logger logger = LoggerFactory.getLogger(HealthcheckRunner.class); - - protected long healthcheckRetryCount; - protected long healthcheckInterval; - protected TimeUnit healthcheckIntervalUnit; - protected Runnable healthcheckAction; - - public HealthcheckRunner(long healthcheckRetryCount, long healthcheckInterval, TimeUnit healthcheckIntervalUnit, - Runnable healthcheck) { - super(); - this.healthcheckRetryCount = healthcheckRetryCount; - this.healthcheckInterval = healthcheckInterval; - this.healthcheckIntervalUnit = healthcheckIntervalUnit; - this.healthcheckAction = healthcheck; - } - - @Override - public void run() { - - // Wait for the health check to succeed the first time - boolean success = false; - Exception lastException = null; - - int i = 0; - for(; i < healthcheckRetryCount; ++i) { - try { - healthcheckAction.run(); - logger.debug("Health check status: success"); - success = true; - break; - } catch(Exception e) { - logger.debug("Health check status: not ok - " + (healthcheckRetryCount - i) + " retries remaining"); - lastException = e; - } - - try { - healthcheckIntervalUnit.sleep(healthcheckInterval); - } catch (InterruptedException e) { - break; - } - } - - if(!success) { - throw new RuntimeException("Startup considered failed after " + i + " failed health checks", lastException); - } - } - - public static URL createUrl(String str) { - URL url; - try { - url = new URL(str); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - return url; - } - - public static void checkUrl(URL url) { - try { - HttpURLConnection connection = (HttpURLConnection)url.openConnection(); - try { - connection.setRequestMethod("GET"); - connection.connect(); - int code = connection.getResponseCode(); - if(code != 200) { - throw new NotFoundException(url.toString()); - } - } finally { - connection.disconnect(); - } - } catch(Exception e) { - throw new RuntimeException(e); - } - } -} \ No newline at end of file diff --git a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckUtils.java b/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckUtils.java deleted file mode 100644 index cf5b5d1..0000000 --- a/docker-service-api-core/src/main/java/org/hobbit/core/service/docker/util/HealthcheckUtils.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.hobbit.core.service.docker.util; - -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; - -import org.apache.jena.shared.NotFoundException; - -public class HealthcheckUtils { - - public static URL createUrl(String str) { - URL url; - try { - url = new URL(str); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - return url; - } - - - public static void checkUrl(URL url) { - try { - HttpURLConnection connection = (HttpURLConnection)url.openConnection(); - try { - connection.setRequestMethod("GET"); - connection.connect(); - int code = connection.getResponseCode(); - if(code != 200) { - //logger.info("Health check status: fail"); - throw new NotFoundException(url.toString()); - } - } finally { - connection.disconnect(); - } - //logger.info("Health check status: success"); - } catch(Exception e) { - throw new RuntimeException(e); - } - } -} diff --git a/docker-service-api-docker-client/pom.xml b/docker-service-api-docker-client/pom.xml index f50d38e..9a4f50a 100644 --- a/docker-service-api-docker-client/pom.xml +++ b/docker-service-api-docker-client/pom.xml @@ -9,7 +9,7 @@ org.hobbit docker-service-api-parent - 1.0.1-SNAPSHOT + 1.1.0-SNAPSHOT diff --git a/docker-service-api-examples/pom.xml b/docker-service-api-examples/pom.xml index b89d96f..15603cc 100644 --- a/docker-service-api-examples/pom.xml +++ b/docker-service-api-examples/pom.xml @@ -9,7 +9,7 @@ org.hobbit docker-service-api-parent - 1.0.1-SNAPSHOT + 1.1.0-SNAPSHOT diff --git a/docker-service-api-spring-boot/pom.xml b/docker-service-api-spring-boot/pom.xml index 14c6dd6..ff06259 100644 --- a/docker-service-api-spring-boot/pom.xml +++ b/docker-service-api-spring-boot/pom.xml @@ -9,7 +9,7 @@ org.hobbit docker-service-api-parent - 1.0.1-SNAPSHOT + 1.1.0-SNAPSHOT diff --git a/pom.xml b/pom.xml index 7448402..5039d06 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.hobbit docker-service-api-parent - 1.0.1-SNAPSHOT + 1.1.0-SNAPSHOT pom @@ -36,6 +36,11 @@ + + org.aksw.commons + aksw-commons-utils + 0.9.7-SNAPSHOT + org.hobbit