summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHÃ¥kon Hallingstad <hakon@oath.com>2017-12-20 15:19:05 +0100
committerGitHub <noreply@github.com>2017-12-20 15:19:05 +0100
commit84401aab45cabddb3530b9d20ecd7cc7a92f21be (patch)
treeedad8ec4614ec03f4c92603d5b6e01d80619f104
parenta8662ee3e07e3608eea25d8312080ca4e12e865a (diff)
Revert "Revert "Prepare for making node admin components optional""
-rw-r--r--docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java5
-rw-r--r--docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java79
-rw-r--r--docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerTestUtils.java6
-rw-r--r--node-admin/src/main/application/services.xml2
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/bootstrap/NodeAdminComponent.java29
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/bootstrap/NodeAdminConfig.java26
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/bootstrap/NodeAdminMain.java113
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/restapi/RestApiHandler.java5
-rw-r--r--node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java3
9 files changed, 236 insertions, 32 deletions
diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java
index 2bf3f0f8d84..bc94c39d135 100644
--- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java
+++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/Docker.java
@@ -12,6 +12,11 @@ import java.util.Optional;
* and to avoid OSGi exporting those classes.
*/
public interface Docker {
+ /**
+ * Must be called before any other method. May be called more than once.
+ */
+ void start();
+
interface CreateContainerCommand {
CreateContainerCommand withLabel(String name, String value);
CreateContainerCommand withEnvironment(String name, String value);
diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java
index 9de2cae604f..054f466657f 100644
--- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java
+++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerImpl.java
@@ -59,7 +59,10 @@ public class DockerImpl implements Docker {
static final String LABEL_NAME_MANAGEDBY = "com.yahoo.vespa.managedby";
private final int SECONDS_TO_WAIT_BEFORE_KILLING;
+ private final boolean fallbackTo123OnErrors;
private static final String FRAMEWORK_CONTAINER_PREFIX = "/";
+ private final DockerConfig config;
+ private final boolean inProduction;
private Optional<DockerImageGarbageCollector> dockerImageGC = Optional.empty();
private CounterWrapper numberOfDockerDaemonFails;
@@ -68,39 +71,61 @@ public class DockerImpl implements Docker {
private final Set<DockerImage> scheduledPulls = new HashSet<>();
// Exposed for testing.
- final DockerClient dockerClient;
+ DockerClient dockerClient;
+
+ @Inject
+ public DockerImpl(final DockerConfig config, MetricReceiverWrapper metricReceiver) {
+ this(config,
+ true, /* fallback to 1.23 on errors */
+ metricReceiver,
+ !config.isRunningLocally());
+ }
+
+ private DockerImpl(final DockerConfig config,
+ boolean fallbackTo123OnErrors,
+ MetricReceiverWrapper metricReceiverWrapper,
+ boolean inProduction) {
+ this.config = config;
+ this.fallbackTo123OnErrors = fallbackTo123OnErrors;
+ this.inProduction = inProduction;
+ if (config == null) {
+ this.SECONDS_TO_WAIT_BEFORE_KILLING = 10;
+ } else {
+ SECONDS_TO_WAIT_BEFORE_KILLING = config.secondsToWaitBeforeKillingContainer();
+ }
+ if (metricReceiverWrapper != null) {
+ setMetrics(metricReceiverWrapper);
+ }
+ }
// For testing
DockerImpl(final DockerClient dockerClient) {
+ this(null, false, null, false);
this.dockerClient = dockerClient;
- this.SECONDS_TO_WAIT_BEFORE_KILLING = 10;
}
- DockerImpl(
- final DockerConfig config,
- boolean fallbackTo123OnErrors,
- MetricReceiverWrapper metricReceiverWrapper) {
- SECONDS_TO_WAIT_BEFORE_KILLING = config.secondsToWaitBeforeKillingContainer();
-
- dockerClient = initDockerConnection(config, fallbackTo123OnErrors);
- setMetrics(metricReceiverWrapper);
+ // For testing
+ DockerImpl(final DockerConfig config,
+ boolean fallbackTo123OnErrors,
+ MetricReceiverWrapper metricReceiverWrapper) {
+ this(config, fallbackTo123OnErrors, metricReceiverWrapper, false);
}
- @Inject
- public DockerImpl(final DockerConfig config, MetricReceiverWrapper metricReceiver) {
- this(
- config,
- true, /* fallback to 1.23 on errors */
- metricReceiver);
-
- if (!config.isRunningLocally()) {
- Duration minAgeToDelete = Duration.ofMinutes(config.imageGCMinTimeToLiveMinutes());
- dockerImageGC = Optional.of(new DockerImageGarbageCollector(minAgeToDelete));
-
- try {
- setupDockerNetworkIfNeeded();
- } catch (Exception e) {
- throw new DockerException("Could not setup docker network", e);
+ @Override
+ public void start() {
+ if (config != null) {
+ if (dockerClient == null) {
+ dockerClient = initDockerConnection();
+ }
+ if (inProduction) {
+ Duration minAgeToDelete = Duration.ofMinutes(config.imageGCMinTimeToLiveMinutes());
+ dockerImageGC = Optional.of(new DockerImageGarbageCollector(minAgeToDelete));
+
+ try {
+ setupDockerNetworkIfNeeded();
+ } catch (Exception e) {
+ throw new DockerException("Could not setup docker network", e);
+ }
}
}
}
@@ -489,7 +514,7 @@ public class DockerImpl implements Docker {
}
}
- private DockerClient initDockerConnection(final DockerConfig config, boolean fallbackTo123orErrors) {
+ private DockerClient initDockerConnection() {
JerseyDockerCmdExecFactory dockerFactory = new JerseyDockerCmdExecFactory()
.withMaxPerRouteConnections(config.maxPerRouteConnections())
.withMaxTotalConnections(config.maxTotalConnections())
@@ -508,7 +533,7 @@ public class DockerImpl implements Docker {
logger.info("Found version 1.24 or newer of remote API, using 1.23.");
}
} catch (Exception e) {
- if (!fallbackTo123orErrors) {
+ if (!fallbackTo123OnErrors) {
throw e;
}
logger.log(LogLevel.ERROR, "Failed when trying to figure out remote API version of docker, using 1.23", e);
diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerTestUtils.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerTestUtils.java
index 079d6876043..549af0d85cb 100644
--- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerTestUtils.java
+++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/DockerTestUtils.java
@@ -46,11 +46,13 @@ public class DockerTestUtils {
public static DockerImpl getDocker() {
if (docker == null) {
- docker = new DockerImpl(
+ DockerImpl tmpDocker = new DockerImpl(
dockerConfig,
false, /* fallback to 1.23 on errors */
new MetricReceiverWrapper(MetricReceiver.nullImplementation));
- createDockerTestNetworkIfNeeded(docker);
+ tmpDocker.start();
+ createDockerTestNetworkIfNeeded(tmpDocker);
+ docker = tmpDocker;
}
return docker;
diff --git a/node-admin/src/main/application/services.xml b/node-admin/src/main/application/services.xml
index 030c42ac8c5..b39a9bce30a 100644
--- a/node-admin/src/main/application/services.xml
+++ b/node-admin/src/main/application/services.xml
@@ -6,7 +6,7 @@
<handler id="com.yahoo.vespa.hosted.node.admin.restapi.RestApiHandler" bundle="node-admin">
<binding>http://*/rest/*</binding>
</handler>
- <component id="node-admin" class="com.yahoo.vespa.hosted.node.admin.provider.NodeAdminProvider" bundle="node-admin"/>
+ <component id="node-admin" class="com.yahoo.vespa.hosted.node.admin.bootstrap.NodeAdminComponent" bundle="node-admin"/>
<component id="docker-api" class="com.yahoo.vespa.hosted.dockerapi.DockerImpl" bundle="docker-api"/>
<component id="metrics-wrapper" class="com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiverWrapper" bundle="docker-api"/>
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/bootstrap/NodeAdminComponent.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/bootstrap/NodeAdminComponent.java
new file mode 100644
index 00000000000..fbcee36b724
--- /dev/null
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/bootstrap/NodeAdminComponent.java
@@ -0,0 +1,29 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.node.admin.bootstrap;
+
+import com.google.inject.Inject;
+import com.yahoo.concurrent.classlock.ClassLocking;
+import com.yahoo.container.di.componentgraph.Provider;
+import com.yahoo.vespa.hosted.dockerapi.Docker;
+import com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiverWrapper;
+
+public class NodeAdminComponent implements Provider<NodeAdminMain> {
+ private final NodeAdminMain nodeAdminMain;
+
+ @Inject
+ NodeAdminComponent(Docker docker,
+ MetricReceiverWrapper metricReceiver,
+ ClassLocking classLocking) {
+ this.nodeAdminMain = new NodeAdminMain(docker, metricReceiver, classLocking);
+ }
+
+ @Override
+ public NodeAdminMain get() {
+ return nodeAdminMain;
+ }
+
+ @Override
+ public void deconstruct() {
+ nodeAdminMain.close();
+ }
+}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/bootstrap/NodeAdminConfig.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/bootstrap/NodeAdminConfig.java
new file mode 100644
index 00000000000..f8d5962fc3f
--- /dev/null
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/bootstrap/NodeAdminConfig.java
@@ -0,0 +1,26 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.node.admin.bootstrap;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonInclude(value = JsonInclude.Include.NON_NULL)
+public class NodeAdminConfig {
+ private static final ObjectMapper mapper = new ObjectMapper();
+
+ enum Mode {
+ TENANT,
+ CONFIG_SERVER_HOST
+ }
+
+ @JsonProperty("mode")
+ public Mode mode = Mode.TENANT;
+
+ public static NodeAdminConfig get() {
+ // TODO: Get config from file
+ return new NodeAdminConfig();
+ }
+}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/bootstrap/NodeAdminMain.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/bootstrap/NodeAdminMain.java
new file mode 100644
index 00000000000..87c3f5452ed
--- /dev/null
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/bootstrap/NodeAdminMain.java
@@ -0,0 +1,113 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.node.admin.bootstrap;
+
+import com.yahoo.concurrent.classlock.ClassLocking;
+import com.yahoo.net.HostName;
+import com.yahoo.system.ProcessExecuter;
+import com.yahoo.vespa.hosted.dockerapi.Docker;
+import com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiverWrapper;
+import com.yahoo.vespa.hosted.node.admin.docker.DockerOperations;
+import com.yahoo.vespa.hosted.node.admin.docker.DockerOperationsImpl;
+import com.yahoo.vespa.hosted.node.admin.maintenance.StorageMaintainer;
+import com.yahoo.vespa.hosted.node.admin.maintenance.acl.AclMaintainer;
+import com.yahoo.vespa.hosted.node.admin.nodeadmin.NodeAdmin;
+import com.yahoo.vespa.hosted.node.admin.nodeadmin.NodeAdminImpl;
+import com.yahoo.vespa.hosted.node.admin.nodeadmin.NodeAdminStateUpdater;
+import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgent;
+import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentImpl;
+import com.yahoo.vespa.hosted.node.admin.noderepository.NodeRepository;
+import com.yahoo.vespa.hosted.node.admin.noderepository.NodeRepositoryImpl;
+import com.yahoo.vespa.hosted.node.admin.orchestrator.Orchestrator;
+import com.yahoo.vespa.hosted.node.admin.orchestrator.OrchestratorImpl;
+import com.yahoo.vespa.hosted.node.admin.util.ConfigServerHttpRequestExecutor;
+import com.yahoo.vespa.hosted.node.admin.util.Environment;
+
+import java.time.Clock;
+import java.time.Duration;
+import java.util.function.Function;
+
+/**
+ * NodeAdminMain is the main component of the node admin JDisc application:
+ * - It will read config and check its environment to figure out its responsibilities
+ * - It will "start" (only) the necessary components.
+ * - Other components MUST NOT try to start (typically in constructor) since the features
+ * they provide is NOT WANTED and possibly destructive, and/or the environment may be
+ * incompatible. For instance, trying to contact the Docker daemon too early will
+ * be fatal: the node admin may not have installed and started the docker daemon.
+ */
+public class NodeAdminMain implements AutoCloseable {
+ private static final Duration NODE_AGENT_SCAN_INTERVAL = Duration.ofSeconds(30);
+ private static final Duration NODE_ADMIN_CONVERGE_STATE_INTERVAL = Duration.ofSeconds(30);
+
+ private final Docker docker;
+ private final MetricReceiverWrapper metricReceiver;
+ private final ClassLocking classLocking;
+
+ private NodeAdminStateUpdater nodeAdminStateUpdater;
+
+ NodeAdminMain(Docker docker, MetricReceiverWrapper metricReceiver, ClassLocking classLocking) {
+ this.docker = docker;
+ this.metricReceiver = metricReceiver;
+ this.classLocking = classLocking;
+ start();
+ }
+
+ @Override
+ public void close() {
+ nodeAdminStateUpdater.stop();
+ }
+
+ public NodeAdminStateUpdater getNodeAdminStateUpdater() {
+ return nodeAdminStateUpdater;
+ }
+
+ public void start() {
+ NodeAdminConfig config = NodeAdminConfig.get();
+
+ switch (config.mode) {
+ case TENANT:
+ setupTenantHostNodeAdmin();
+ break;
+ case CONFIG_SERVER_HOST:
+ setupConfigServerHostNodeAdmin();
+ break;
+ default:
+ throw new IllegalStateException(
+ "Unknown bootstrap mode: " + config.mode.name());
+ }
+ }
+
+ private void setupTenantHostNodeAdmin() {
+ Clock clock = Clock.systemUTC();
+ String dockerHostHostName = HostName.getLocalhost();
+ ProcessExecuter processExecuter = new ProcessExecuter();
+ Environment environment = new Environment();
+
+ ConfigServerHttpRequestExecutor requestExecutor = ConfigServerHttpRequestExecutor.create(environment.getConfigServerUris());
+ NodeRepository nodeRepository = new NodeRepositoryImpl(requestExecutor);
+ Orchestrator orchestrator = new OrchestratorImpl(requestExecutor);
+ DockerOperations dockerOperations = new DockerOperationsImpl(docker, environment, processExecuter);
+
+ StorageMaintainer storageMaintainer = new StorageMaintainer(docker, processExecuter, metricReceiver, environment, clock);
+ AclMaintainer aclMaintainer = new AclMaintainer(dockerOperations, nodeRepository, dockerHostHostName);
+
+ Function<String, NodeAgent> nodeAgentFactory =
+ (hostName) -> new NodeAgentImpl(hostName, nodeRepository, orchestrator, dockerOperations,
+ storageMaintainer, aclMaintainer, environment, clock, NODE_AGENT_SCAN_INTERVAL);
+ NodeAdmin nodeAdmin = new NodeAdminImpl(dockerOperations, nodeAgentFactory, storageMaintainer, aclMaintainer,
+ metricReceiver, clock);
+
+ nodeAdminStateUpdater = new NodeAdminStateUpdater(nodeRepository, orchestrator, storageMaintainer, nodeAdmin,
+ dockerHostHostName, clock, NODE_ADMIN_CONVERGE_STATE_INTERVAL, classLocking);
+
+ nodeAdminStateUpdater.start();
+ }
+
+ private void setupConfigServerHostNodeAdmin() {
+ // TODO:
+ // - install and start docker daemon
+ // - Read config that specifies which containers to start how
+ // - use thin static backends for node repo, orchestrator, and others
+ // - Start core node admin.
+ }
+}
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/restapi/RestApiHandler.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/restapi/RestApiHandler.java
index 42b36d95374..b7377ff172c 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/restapi/RestApiHandler.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/restapi/RestApiHandler.java
@@ -9,6 +9,7 @@ import com.yahoo.container.jdisc.LoggingRequestHandler;
import com.yahoo.container.logging.AccessLog;
import com.yahoo.vespa.hosted.dockerapi.metrics.DimensionMetrics;
import com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiverWrapper;
+import com.yahoo.vespa.hosted.node.admin.bootstrap.NodeAdminMain;
import com.yahoo.vespa.hosted.node.admin.nodeadmin.NodeAdminStateUpdater;
import javax.inject.Inject;
@@ -38,10 +39,10 @@ public class RestApiHandler extends LoggingRequestHandler{
@Inject
public RestApiHandler(Executor executor, AccessLog accessLog,
- NodeAdminStateUpdater nodeAdminStateUpdater,
+ NodeAdminMain nodeAdminMain,
MetricReceiverWrapper metricReceiverWrapper) {
super(executor, accessLog);
- this.refresher = nodeAdminStateUpdater;
+ this.refresher = nodeAdminMain.getNodeAdminStateUpdater();
this.metricReceiverWrapper = metricReceiverWrapper;
}
diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java
index a1cc1850d23..7a5d713936d 100644
--- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java
+++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerMock.java
@@ -33,6 +33,9 @@ public class DockerMock implements Docker {
}
@Override
+ public void start() { }
+
+ @Override
public CreateContainerCommand createContainerCommand(
DockerImage dockerImage,
ContainerResources containerResources,