diff options
24 files changed, 222 insertions, 103 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java index 095b27a0904..291a2824e46 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomAdminV4Builder.java @@ -6,6 +6,7 @@ import com.yahoo.config.model.api.ConfigServerSpec; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.SystemName; +import com.yahoo.container.handler.LogHandler; import com.yahoo.log.LogLevel; import com.yahoo.searchdefinition.derived.RankProfileList; import com.yahoo.vespa.model.HostResource; @@ -110,10 +111,9 @@ public class DomAdminV4Builder extends DomAdminBuilderBase { admin.addAndInitializeService(hostResource, container); } - // TODO: Wire in handler for getting logs private void addLogHandler(ContainerCluster cluster) { - Handler<?> logHandler = Handler.fromClassName("TODO"); - //logHandler.addServerBindings("http://*/logs/", "https://*/logs/"); + Handler<?> logHandler = Handler.fromClassName("com.yahoo.container.handler.LogHandler"); + logHandler.addServerBindings("http://*/logs/", "https://*/logs/"); cluster.addComponent(logHandler); } diff --git a/config-proxy/pom.xml b/config-proxy/pom.xml index a266f68efe2..0985eeca6cf 100644 --- a/config-proxy/pom.xml +++ b/config-proxy/pom.xml @@ -63,6 +63,11 @@ <artifactId>filedistribution</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpkix-jdk15on</artifactId> + <scope>compile</scope> + </dependency> </dependencies> <build> <plugins> diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java index bcb51f335a3..6a55fb77933 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java @@ -53,7 +53,6 @@ import com.yahoo.vespa.config.server.session.SilentDeployLogger; import com.yahoo.vespa.config.server.tenant.Rotations; import com.yahoo.vespa.config.server.tenant.Tenant; import com.yahoo.vespa.config.server.tenant.TenantRepository; -import com.yahoo.vespa.model.VespaModel; import java.io.File; import java.io.IOException; @@ -485,7 +484,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye // ---------------- Logs ---------------------------------------------------------------- public HttpResponse getLogs(ApplicationId applicationId) { - String logServerHostName = getLogServerHostname(applicationId); + String logServerHostName = getLogServerURI(applicationId); LogRetriever logRetriever = new LogRetriever(); return logRetriever.getLogs(logServerHostName); } @@ -703,27 +702,28 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye } } - private String getLogServerHostname(ApplicationId applicationId) { + private String getLogServerURI(ApplicationId applicationId) { Application application = getApplication(applicationId); - VespaModel model = (VespaModel) application.getModel(); - String logServerHostname = model.getAdmin().getLogserver().getHostName(); Collection<HostInfo> hostInfos = application.getModel().getHosts(); HostInfo logServerHostInfo = hostInfos.stream() - .filter(host -> host.getHostname().equals(logServerHostname)) - .findFirst().orElseThrow(() -> new IllegalArgumentException("Could not find HostInfo")); + .filter(host -> host.getServices().stream() + .filter(serviceInfo -> + serviceInfo.getServiceType().equalsIgnoreCase("logserver")) + .count() > 0) + .findFirst().orElseThrow(() -> new IllegalArgumentException("Could not find HostInfo for LogServer")); - ServiceInfo serviceInfo = logServerHostInfo.getServices().stream() + ServiceInfo containerServiceInfo = logServerHostInfo.getServices().stream() .filter(service -> service.getServiceType().equals("container")) .findFirst().orElseThrow(() -> new IllegalArgumentException("No container running on logserver host")); - int port = serviceInfo.getPorts().stream() + int port = containerServiceInfo.getPorts().stream() .filter(portInfo -> portInfo.getTags().stream() .filter(tag -> tag.equalsIgnoreCase("http")).count() > 0) .findFirst().orElseThrow(() -> new IllegalArgumentException("Could not find HTTP port")) .getPort(); - return logServerHostname + ":" + port + "/logs"; + return "http://" + logServerHostInfo.getHostname() + ":" + port + "/logs"; } /** Returns version to use when deploying application in given environment */ diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/BuildService.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/BuildService.java index 56c2ee8da6b..d0edbdcb8a6 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/BuildService.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/BuildService.java @@ -37,8 +37,6 @@ public interface BuildService { } - // TODO jvenstad: Argh, refactor this, considering the new JobId, etc.. - // TODO jvenstad: Probably: make jobName JobType instead. class BuildJob { private final ApplicationId applicationId; diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java index a3a4e99c38d..af5b9198343 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java @@ -43,6 +43,7 @@ import com.yahoo.vespa.hosted.controller.application.JobList; import com.yahoo.vespa.hosted.controller.application.JobStatus; import com.yahoo.vespa.hosted.controller.application.JobStatus.JobRun; import com.yahoo.vespa.hosted.controller.application.SystemApplication; +import com.yahoo.vespa.hosted.controller.concurrent.Once; import com.yahoo.vespa.hosted.controller.deployment.DeploymentTrigger; import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; import com.yahoo.vespa.hosted.controller.rotation.Rotation; @@ -117,13 +118,17 @@ public class ApplicationController { this.rotationRepository = new RotationRepository(rotationsConfig, this, curator); this.deploymentTrigger = new DeploymentTrigger(controller, buildService, clock); - Instant start = clock.instant(); - int count = 0; - for (Application application : curator.readApplications()) { - lockIfPresent(application.id(), this::store); - count++; - } - log.log(Level.INFO, String.format("Wrote %d applications in %s", count, Duration.between(start, clock.instant()))); + // Update serialization format of all applications + Once.after(Duration.ofMinutes(1), () -> { + Instant start = clock.instant(); + int count = 0; + for (Application application : curator.readApplications()) { + lockIfPresent(application.id(), this::store); + count++; + } + log.log(Level.INFO, String.format("Wrote %d applications in %s", count, + Duration.between(start, clock.instant()))); + }); } /** Returns the application with the given id, or null if it is not present */ diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java index 21db5c0b68f..1ae3e6a6577 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/TenantController.java @@ -10,6 +10,7 @@ import com.yahoo.vespa.curator.Lock; import com.yahoo.vespa.hosted.controller.api.identifiers.UserId; import com.yahoo.vespa.hosted.controller.api.integration.athenz.AthenzClientFactory; import com.yahoo.vespa.hosted.controller.api.integration.athenz.ZmsClient; +import com.yahoo.vespa.hosted.controller.concurrent.Once; import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; import com.yahoo.vespa.hosted.controller.tenant.AthenzTenant; import com.yahoo.vespa.hosted.controller.tenant.Tenant; @@ -47,22 +48,30 @@ public class TenantController { this.curator = Objects.requireNonNull(curator, "curator must be non-null"); this.athenzClientFactory = Objects.requireNonNull(athenzClientFactory, "athenzClientFactory must be non-null"); - // Write all tenants to ensure persisted data uses latest serialization format - Instant start = controller.clock().instant(); - int count = 0; - for (Tenant tenant : curator.readTenants()) { - try (Lock lock = lock(tenant.name())) { - if (tenant instanceof AthenzTenant) { - curator.writeTenant((AthenzTenant) tenant); - } else if (tenant instanceof UserTenant) { - curator.writeTenant((UserTenant) tenant); - } else { - throw new IllegalArgumentException("Unknown tenant type: " + tenant.getClass().getSimpleName()); + // Update serialization format of all tenants + Once.after(Duration.ofMinutes(1), () -> { + Instant start = controller.clock().instant(); + int count = 0; + for (TenantName name : curator.readTenantNames()) { + try (Lock lock = lock(name)) { + // Get while holding lock so that we know we're operating on a current version + Optional<Tenant> optionalTenant = tenant(name); + if (!optionalTenant.isPresent()) continue; // Deleted while updating, skip + + Tenant tenant = optionalTenant.get(); + if (tenant instanceof AthenzTenant) { + curator.writeTenant((AthenzTenant) tenant); + } else if (tenant instanceof UserTenant) { + curator.writeTenant((UserTenant) tenant); + } else { + throw new IllegalArgumentException("Unknown tenant type: " + tenant.getClass().getSimpleName()); + } } + count++; } - count++; - } - log.log(Level.INFO, String.format("Wrote %d tenants in %s", count, Duration.between(start, controller.clock().instant()))); + log.log(Level.INFO, String.format("Wrote %d tenants in %s", count, + Duration.between(start, controller.clock().instant()))); + }); } /** Returns a list of all known tenants sorted by name */ diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/concurrent/Once.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/concurrent/Once.java new file mode 100644 index 00000000000..81ddd8d2d70 --- /dev/null +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/concurrent/Once.java @@ -0,0 +1,46 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.concurrent; + +import java.time.Duration; +import java.util.Objects; +import java.util.Timer; +import java.util.TimerTask; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Execute a runnable exactly once in a background thread. + * + * @author mpolden + */ +public class Once extends TimerTask { + + private static final Logger log = Logger.getLogger(Once.class.getName()); + + private final Runnable runnable; + private final Timer timer = new Timer(true); + + // private to avoid exposing run method + private Once(Runnable runnable, Duration delay) { + this.runnable = Objects.requireNonNull(runnable, "runnable must be non-null"); + Objects.requireNonNull(delay, "delay must be non-null"); + timer.schedule(this, delay.toMillis()); + } + + /** Execute runnable after given delay */ + public static void after(Duration delay, Runnable runnable) { + new Once(runnable, delay); + } + + @Override + public void run() { + try { + runnable.run(); + } catch (Throwable t) { + log.log(Level.WARNING, "Task '" + runnable + "' failed", t); + } finally { + timer.cancel(); + } + } + +} diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobProfile.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobProfile.java index 0cad9e98d5d..f7794747db9 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobProfile.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobProfile.java @@ -15,7 +15,6 @@ import static com.yahoo.vespa.hosted.controller.deployment.Step.*; */ public enum JobProfile { - // TODO jvenstad: runTests is not a run-always step, as it really means: check if tests are done, and store whatever is ready. systemTest(EnumSet.of(deployReal, installReal, deployTester, diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgrader.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgrader.java index bf9fbeb26d3..a83c9cdf06f 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgrader.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgrader.java @@ -46,8 +46,10 @@ public class OsUpgrader extends InfrastructureUpgrader { @Override protected void upgrade(Version target, SystemApplication application, ZoneId zone) { + if (wantedVersion(zone, application, target).equals(target)) { + return; + } log.info(String.format("Upgrading OS of %s to version %s in %s", application.id(), target, zone)); - // Node repository ensures the upgrade call is idempotent application.nodeTypesWithUpgradableOs().forEach(nodeType -> controller().configServer().nodeRepository() .upgradeOs(zone, nodeType, target)); } @@ -75,6 +77,10 @@ public class OsUpgrader extends InfrastructureUpgrader { return minVersion(zone, application, Node::currentOsVersion).orElse(defaultVersion); } + private Version wantedVersion(ZoneId zone, SystemApplication application, Version defaultVersion) { + return minVersion(zone, application, Node::wantedOsVersion).orElse(defaultVersion); + } + /** Returns whether node in application should be upgraded by this */ public static boolean eligibleForUpgrade(Node node, SystemApplication application) { return upgradableNodeStates.contains(node.state()) && diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java index e117592d608..0d8ea8d2537 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java @@ -302,12 +302,17 @@ public class CuratorDb { } public List<Tenant> readTenants() { + return readTenantNames().stream() + .map(this::readTenant) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); + } + + public List<TenantName> readTenantNames() { return curator.getChildren(tenantRoot).stream() .map(TenantName::from) - .map(this::readTenant) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(collectingAndThen(Collectors.toList(), Collections::unmodifiableList)); + .collect(Collectors.toList()); } public void removeTenant(TenantName name) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/LogSerializer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/LogSerializer.java index 457ef761c0f..17b4a42fb91 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/LogSerializer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/LogSerializer.java @@ -27,7 +27,6 @@ import java.util.stream.Collectors; class LogSerializer { private static final String idField = "id"; - private static final String levelField = "level"; private static final String typeField = "type"; private static final String timestampField = "at"; private static final String messageField = "message"; @@ -54,7 +53,6 @@ class LogSerializer { private void toSlime(LogEntry entry, Cursor entryObject) { entryObject.setLong(idField, entry.id()); entryObject.setLong(timestampField, entry.at()); - entryObject.setString(levelField, valueOf(entry.type())); // TODO jvenstad: Remove after one deployment. entryObject.setString(typeField, valueOf(entry.type())); entryObject.setString(messageField, entry.message()); } @@ -87,9 +85,7 @@ class LogSerializer { private LogEntry fromSlime(Inspector entryObject) { return new LogEntry(entryObject.field(idField).asLong(), entryObject.field(timestampField).asLong(), - entryObject.field(typeField).valid() // TODO jvenstad: Remove after one deployment. - ? typeOf(entryObject.field(typeField).asString()) - : typeOf(entryObject.field(levelField).asString()), + typeOf(entryObject.field(typeField).asString()), entryObject.field(messageField).asString()); } @@ -105,7 +101,7 @@ class LogSerializer { } static Type typeOf(String type) { - switch (type.toLowerCase()) { // TODO jvenstad: Remove lowercasing after this has been deployed. + switch (type) { case "debug": return Type.debug; case "info": return Type.info; case "warning": return Type.warning; diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/concurrent/OnceTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/concurrent/OnceTest.java new file mode 100644 index 00000000000..e11fdcba7c6 --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/concurrent/OnceTest.java @@ -0,0 +1,25 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.concurrent; + +import org.junit.Test; + +import java.time.Duration; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertTrue; + +/** + * @author mpolden + */ +public class OnceTest { + + @Test(timeout = 60_000) + public void test_run() throws Exception { + CountDownLatch latch = new CountDownLatch(1); + Once.after(Duration.ZERO, latch::countDown); + + assertTrue(latch.await(30, TimeUnit.SECONDS)); + } + +} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/logs.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/logs.json index a6a092109a1..ce9bd2139c7 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/logs.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/persistence/testdata/logs.json @@ -3,13 +3,13 @@ [ { "id": 0, - "level": "info", + "type": "info", "at": 0, "message": "First" }, { "id": 2, - "level": "debug", + "type": "debug", "at": 1000, "message": "Third" } @@ -18,13 +18,13 @@ [ { "id": 1, - "level": "info", + "type": "info", "at": 0, "message": "Second" }, { "id": 3, - "level": "warning", + "type": "warning", "at": 2000, "message": "Fourth" } diff --git a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/ContainerStatsImpl.java b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/ContainerStatsImpl.java index f0419a36d46..a56c1e41a51 100644 --- a/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/ContainerStatsImpl.java +++ b/docker-api/src/main/java/com/yahoo/vespa/hosted/dockerapi/ContainerStatsImpl.java @@ -1,12 +1,14 @@ // 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.dockerapi; +import java.util.Collections; import java.util.Map; +import java.util.Optional; /** * Wrapper class for {@link com.github.dockerjava.api.model.Statistics} to prevent leaking from docker-java library. * - * @author valerijf + * @author freva */ public class ContainerStatsImpl implements Docker.ContainerStats { private final Map<String, Object> networks; @@ -16,7 +18,8 @@ public class ContainerStatsImpl implements Docker.ContainerStats { public ContainerStatsImpl(Map<String, Object> networks, Map<String, Object> cpuStats, Map<String, Object> memoryStats, Map<String, Object> blkioStats) { - this.networks = networks; + // Network stats are null when container uses host network + this.networks = Optional.ofNullable(networks).orElse(Collections.emptyMap()); this.cpuStats = cpuStats; this.memoryStats = memoryStats; this.blkioStats = blkioStats; diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/component/Environment.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/component/Environment.java index f0c0a9c31d3..dc0ac0df05d 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/component/Environment.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/component/Environment.java @@ -15,16 +15,14 @@ import com.yahoo.vespa.hosted.node.admin.task.util.network.IPAddressesImpl; import java.net.URI; import java.nio.file.Path; import java.nio.file.Paths; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.Collections; -import java.util.Date; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.TimeZone; /** * Various utilities for getting values from node-admin's environment. Immutable. @@ -33,7 +31,8 @@ import java.util.TimeZone; * @author hmusum */ public class Environment { - private static final DateFormat filenameFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); + private static final DateTimeFormatter filenameFormatter = DateTimeFormatter + .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS").withZone(ZoneOffset.UTC); public static final String APPLICATION_STORAGE_CLEANUP_PATH_PREFIX = "cleanup_"; private static final String ENVIRONMENT = "ENVIRONMENT"; @@ -52,13 +51,13 @@ public class Environment { private final String environment; private final String region; private final String system; + private final String cloud; private final String parentHostHostname; private final IPAddresses ipAddresses; private final PathResolver pathResolver; private final List<String> logstashNodes; private final Optional<String> coredumpFeedEndpoint; private final NodeType nodeType; - private final String cloud; private final ContainerEnvironmentResolver containerEnvironmentResolver; private final String certificateDnsSuffix; private final URI ztsUri; @@ -66,10 +65,7 @@ public class Environment { private final boolean nodeAgentCertEnabled; private final boolean isRunningOnHost; private final Path trustStorePath; - - static { - filenameFormatter.setTimeZone(TimeZone.getTimeZone("UTC")); - } + private final DockerNetworking dockerNetworking; public Environment(ConfigServerConfig configServerConfig) { this(configServerConfig, @@ -77,19 +73,20 @@ public class Environment { getEnvironmentVariable(ENVIRONMENT), getEnvironmentVariable(REGION), getEnvironmentVariable(SYSTEM), + getEnvironmentVariable(CLOUD), Defaults.getDefaults().vespaHostname(), new IPAddressesImpl(), new PathResolver(), getLogstashNodesFromEnvironment(), Optional.of(getEnvironmentVariable(COREDUMP_FEED_ENDPOINT)), NodeType.host, - getEnvironmentVariable(CLOUD), new DefaultContainerEnvironmentResolver(), getEnvironmentVariable(CERTIFICATE_DNS_SUFFIX), URI.create(getEnvironmentVariable(ZTS_URI)), (AthenzService)AthenzIdentities.from(getEnvironmentVariable(NODE_ATHENZ_IDENTITY)), Boolean.valueOf(getEnvironmentVariable(ENABLE_NODE_AGENT_CERT)), - false); + false, + DockerNetworking.MACVLAN); } private Environment(ConfigServerConfig configServerConfig, @@ -97,36 +94,33 @@ public class Environment { String environment, String region, String system, + String cloud, String parentHostHostname, IPAddresses ipAddresses, PathResolver pathResolver, List<String> logstashNodes, Optional<String> coreDumpFeedEndpoint, NodeType nodeType, - String cloud, ContainerEnvironmentResolver containerEnvironmentResolver, String certificateDnsSuffix, URI ztsUri, AthenzService nodeAthenzIdentity, boolean nodeAgentCertEnabled, - boolean isRunningOnHost) { + boolean isRunningOnHost, + DockerNetworking dockerNetworking) { Objects.requireNonNull(configServerConfig, "configServerConfig cannot be null"); - Objects.requireNonNull(environment, "environment cannot be null"); - Objects.requireNonNull(region, "region cannot be null"); - Objects.requireNonNull(system, "system cannot be null"); - Objects.requireNonNull(cloud, "cloud cannot be null"); this.configServerInfo = new ConfigServerInfo(configServerConfig); - this.environment = environment; - this.region = region; - this.system = system; + this.environment = Objects.requireNonNull(environment, "environment cannot be null");; + this.region = Objects.requireNonNull(region, "region cannot be null");; + this.system = Objects.requireNonNull(system, "system cannot be null");; + this.cloud = Objects.requireNonNull(cloud, "cloud cannot be null"); this.parentHostHostname = parentHostHostname; this.ipAddresses = ipAddresses; this.pathResolver = pathResolver; this.logstashNodes = logstashNodes; this.coredumpFeedEndpoint = coreDumpFeedEndpoint; this.nodeType = nodeType; - this.cloud = cloud; this.containerEnvironmentResolver = containerEnvironmentResolver; this.certificateDnsSuffix = certificateDnsSuffix; this.ztsUri = ztsUri; @@ -134,6 +128,7 @@ public class Environment { this.nodeAgentCertEnabled = nodeAgentCertEnabled; this.isRunningOnHost = isRunningOnHost; this.trustStorePath = trustStorePath; + this.dockerNetworking = Objects.requireNonNull(dockerNetworking, "dockerNetworking cannot be null"); } public List<String> getConfigServerHostNames() { return configServerInfo.getConfigServerHostNames(); } @@ -148,6 +143,8 @@ public class Environment { return system; } + public String getCloud() { return cloud; } + public String getParentHostHostname() { return parentHostHostname; } @@ -197,7 +194,7 @@ public class Environment { public Path pathInNodeAdminToNodeCleanup(ContainerName containerName) { return pathResolver.getApplicationStoragePathForNodeAdmin() .resolve(APPLICATION_STORAGE_CLEANUP_PATH_PREFIX + containerName.asString() + - "_" + filenameFormatter.format(Date.from(Instant.now()))); + "_" + filenameFormatter.format(Instant.now())); } /** @@ -243,8 +240,6 @@ public class Environment { public NodeType getNodeType() { return nodeType; } - public String getCloud() { return cloud; } - public ContainerEnvironmentResolver getContainerEnvironmentResolver() { return containerEnvironmentResolver; } @@ -282,7 +277,7 @@ public class Environment { } public DockerNetworking getDockerNetworking() { - return DockerNetworking.from(cloud, nodeType, isRunningOnHost); + return dockerNetworking; } public static class Builder { @@ -290,13 +285,13 @@ public class Environment { private String environment; private String region; private String system; + private String cloud; private String parentHostHostname; private IPAddresses ipAddresses; private PathResolver pathResolver; private List<String> logstashNodes = Collections.emptyList(); private Optional<String> coredumpFeedEndpoint = Optional.empty(); private NodeType nodeType = NodeType.tenant; - private String cloud; private ContainerEnvironmentResolver containerEnvironmentResolver; private String certificateDnsSuffix; private URI ztsUri; @@ -304,6 +299,7 @@ public class Environment { private boolean nodeAgentCertEnabled; private boolean isRunningOnHost; private Path trustStorePath; + private DockerNetworking dockerNetworking; public Builder configServerConfig(ConfigServerConfig configServerConfig) { this.configServerConfig = configServerConfig; @@ -325,6 +321,11 @@ public class Environment { return this; } + public Builder cloud(String cloud) { + this.cloud = cloud; + return this; + } + public Builder parentHostHostname(String parentHostHostname) { this.parentHostHostname = parentHostHostname; return this; @@ -360,11 +361,6 @@ public class Environment { return this; } - public Builder cloud(String cloud) { - this.cloud = cloud; - return this; - } - public Builder certificateDnsSuffix(String certificateDnsSuffix) { this.certificateDnsSuffix = certificateDnsSuffix; return this; @@ -395,25 +391,31 @@ public class Environment { return this; } + public Builder dockerNetworking(DockerNetworking dockerNetworking) { + this.dockerNetworking = dockerNetworking; + return this; + } + public Environment build() { return new Environment(configServerConfig, trustStorePath, environment, region, system, + cloud, parentHostHostname, Optional.ofNullable(ipAddresses).orElseGet(IPAddressesImpl::new), Optional.ofNullable(pathResolver).orElseGet(PathResolver::new), logstashNodes, coredumpFeedEndpoint, nodeType, - cloud, Optional.ofNullable(containerEnvironmentResolver).orElseGet(DefaultContainerEnvironmentResolver::new), certificateDnsSuffix, ztsUri, nodeAthenzIdentity, nodeAgentCertEnabled, - isRunningOnHost); + isRunningOnHost, + Optional.ofNullable(dockerNetworking).orElseGet(() -> DockerNetworking.from(cloud, nodeType, isRunningOnHost))); } } } diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerNetworking.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerNetworking.java index 60146a4fbb7..7678ad8169a 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerNetworking.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerNetworking.java @@ -10,13 +10,22 @@ import com.yahoo.config.provision.NodeType; */ public enum DockerNetworking { /** Each container has an associated macvlan bridge. */ - MACVLAN, + MACVLAN("vespa-macvlan"), /** Network Prefix-Translated networking. */ - NPT, + NPT("vespa-bridge"), /** A host running a single container in the host network namespace. */ - HOST_NETWORK; + HOST_NETWORK("host"); + + private final String dockerNetworkMode; + DockerNetworking(String dockerNetworkMode) { + this.dockerNetworkMode = dockerNetworkMode; + } + + public String getDockerNetworkMode() { + return dockerNetworkMode; + } public static DockerNetworking from(String cloud, NodeType nodeType, boolean hostAdmin) { if (cloud.equals("AWS")) { diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImpl.java index 47729ebb416..a197eafe923 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImpl.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImpl.java @@ -10,7 +10,6 @@ import com.yahoo.vespa.hosted.dockerapi.ContainerName; import com.yahoo.vespa.hosted.dockerapi.ContainerResources; import com.yahoo.vespa.hosted.dockerapi.Docker; import com.yahoo.vespa.hosted.dockerapi.DockerImage; -import com.yahoo.vespa.hosted.dockerapi.DockerImpl; import com.yahoo.vespa.hosted.dockerapi.DockerNetworkCreator; import com.yahoo.vespa.hosted.dockerapi.ProcessResult; import com.yahoo.vespa.hosted.node.admin.component.Environment; @@ -45,8 +44,7 @@ public class DockerOperationsImpl implements DockerOperations { private static final String IPV6_NPT_PREFIX = "fd00::"; private static final String IPV4_NPT_PREFIX = "172.17.0.0"; - private static final String DOCKER_CUSTOM_BRIDGE_NETWORK_NAME = "vespa-bridge"; - + private final Docker docker; private final Environment environment; private final ProcessExecuter processExecuter; @@ -107,11 +105,13 @@ public class DockerOperationsImpl implements DockerOperations { } } - if (environment.getDockerNetworking() == DockerNetworking.MACVLAN) { + DockerNetworking networking = environment.getDockerNetworking(); + command.withNetworkMode(networking.getDockerNetworkMode()); + + if (networking == DockerNetworking.MACVLAN) { // TODO: Remove this if when migration to host-admin is complete command.withIpAddress(ipV6Address); - command.withNetworkMode(DockerImpl.DOCKER_CUSTOM_MACVLAN_NETWORK_NAME); command.withSharedVolume("/etc/hosts", "/etc/hosts"); - } else { + } else if (networking == DockerNetworking.NPT) { InetAddress ipV6Prefix = InetAddresses.forString(IPV6_NPT_PREFIX); InetAddress ipV6Local = IPAddresses.prefixTranslate(ipV6Address, ipV6Prefix, 8); command.withIpAddress(ipV6Local); @@ -125,8 +125,6 @@ public class DockerOperationsImpl implements DockerOperations { ipV4Local.ifPresent(command::withIpAddress); addEtcHosts(containerData, node.getHostname(), ipV4Local, ipV6Local); - - command.withNetworkMode(DOCKER_CUSTOM_BRIDGE_NETWORK_NAME); } for (Path pathInNode : directoriesToMount.keySet()) { diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImplTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImplTest.java index e2db75eb6fb..fa94a7ff819 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImplTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/docker/DockerOperationsImplTest.java @@ -39,6 +39,7 @@ public class DockerOperationsImplTest { .environment("prod") .system("main") .cloud("mycloud") + .dockerNetworking(DockerNetworking.HOST_NETWORK) .build(); private final Docker docker = mock(Docker.class); private final ProcessExecuter processExecuter = mock(ProcessExecuter.class); diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerTester.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerTester.java index d0e4377ffc5..15bb2825738 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerTester.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integrationTests/DockerTester.java @@ -10,6 +10,7 @@ import com.yahoo.vespa.hosted.dockerapi.Docker; import com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiverWrapper; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; import com.yahoo.vespa.hosted.node.admin.config.ConfigServerConfig; +import com.yahoo.vespa.hosted.node.admin.docker.DockerNetworking; 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.acl.AclMaintainer; @@ -69,8 +70,9 @@ public class DockerTester implements AutoCloseable { .region("us-east-1") .environment("prod") .system("main") - .pathResolver(new PathResolver(PATH_TO_VESPA_HOME, Paths.get("/tmp"), Paths.get("/tmp"))) .cloud("mycloud") + .pathResolver(new PathResolver(PATH_TO_VESPA_HOME, Paths.get("/tmp"), Paths.get("/tmp"))) + .dockerNetworking(DockerNetworking.HOST_NETWORK) .build(); NodeSpec hostSpec = new NodeSpec.Builder() diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/logging/FilebeatConfigProviderTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/logging/FilebeatConfigProviderTest.java index 77c0a30ae18..f418552553e 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/logging/FilebeatConfigProviderTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/logging/FilebeatConfigProviderTest.java @@ -6,6 +6,7 @@ import com.yahoo.config.provision.NodeType; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; import com.yahoo.vespa.hosted.node.admin.component.Environment; import com.yahoo.vespa.hosted.node.admin.config.ConfigServerConfig; +import com.yahoo.vespa.hosted.node.admin.docker.DockerNetworking; import com.yahoo.vespa.hosted.provision.Node; import org.junit.Test; @@ -104,6 +105,7 @@ public class FilebeatConfigProviderTest { .system(system) .logstashNodes(logstashNodes) .cloud("mycloud") + .dockerNetworking(DockerNetworking.HOST_NETWORK) .build(); } diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/StorageMaintainerTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/StorageMaintainerTest.java index 627517b824e..d9cce7f80a0 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/StorageMaintainerTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/StorageMaintainerTest.java @@ -10,6 +10,7 @@ import com.yahoo.vespa.hosted.dockerapi.ContainerName; import com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiverWrapper; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; import com.yahoo.vespa.hosted.node.admin.config.ConfigServerConfig; +import com.yahoo.vespa.hosted.node.admin.docker.DockerNetworking; import com.yahoo.vespa.hosted.node.admin.docker.DockerOperations; import com.yahoo.vespa.hosted.node.admin.component.Environment; import com.yahoo.vespa.hosted.node.admin.component.PathResolver; @@ -41,8 +42,9 @@ public class StorageMaintainerTest { .region("us-east-1") .environment("prod") .system("main") - .pathResolver(new PathResolver()) .cloud("mycloud") + .pathResolver(new PathResolver()) + .dockerNetworking(DockerNetworking.HOST_NETWORK) .coredumpFeedEndpoint("http://domain.tld/docid") .build(); private final DockerOperations docker = mock(DockerOperations.class); diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImplTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImplTest.java index f5d4dcf4e5e..ebed20326a3 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImplTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImplTest.java @@ -16,6 +16,7 @@ import com.yahoo.vespa.hosted.dockerapi.metrics.MetricReceiverWrapper; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; import com.yahoo.vespa.hosted.node.admin.config.ConfigServerConfig; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeAttributes; +import com.yahoo.vespa.hosted.node.admin.docker.DockerNetworking; import com.yahoo.vespa.hosted.node.admin.docker.DockerOperations; import com.yahoo.vespa.hosted.node.admin.maintenance.StorageMaintainer; import com.yahoo.vespa.hosted.node.admin.maintenance.acl.AclMaintainer; @@ -88,9 +89,10 @@ public class NodeAgentImplTest { .environment("dev") .region("us-east-1") .system("main") + .cloud("mycloud") .parentHostHostname("parent.host.name.yahoo.com") .pathResolver(pathResolver) - .cloud("mycloud") + .dockerNetworking(DockerNetworking.HOST_NETWORK) .build(); private final NodeSpec.Builder nodeBuilder = new NodeSpec.Builder() diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/util/EnvironmentTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/util/EnvironmentTest.java index a3a455605ad..893607f1806 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/util/EnvironmentTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/util/EnvironmentTest.java @@ -6,6 +6,7 @@ import com.yahoo.vespa.hosted.dockerapi.ContainerName; import com.yahoo.vespa.hosted.node.admin.component.Environment; import com.yahoo.vespa.hosted.node.admin.component.PathResolver; import com.yahoo.vespa.hosted.node.admin.config.ConfigServerConfig; +import com.yahoo.vespa.hosted.node.admin.docker.DockerNetworking; import org.junit.Test; import java.nio.file.Path; @@ -22,8 +23,9 @@ public class EnvironmentTest { .region("us-east-1") .environment("prod") .system("main") - .pathResolver(new PathResolver()) .cloud("mycloud") + .pathResolver(new PathResolver()) + .dockerNetworking(DockerNetworking.HOST_NETWORK) .build(); @Test diff --git a/vespalib/src/tests/alloc/alloc_test.cpp b/vespalib/src/tests/alloc/alloc_test.cpp index 0e52d06a2d5..dd4adfc2fa1 100644 --- a/vespalib/src/tests/alloc/alloc_test.cpp +++ b/vespalib/src/tests/alloc/alloc_test.cpp @@ -179,6 +179,7 @@ TEST("auto alloced mmap alloc can not be extended if no room") { } TEST("mmap alloc can be extended if room") { + Alloc dummy = Alloc::allocMMap(100); Alloc reserved = Alloc::allocMMap(100); Alloc buf = Alloc::allocMMap(100); @@ -187,6 +188,7 @@ TEST("mmap alloc can be extended if room") { } TEST("mmap alloc can not be extended if no room") { + Alloc dummy = Alloc::allocMMap(100); Alloc reserved = Alloc::allocMMap(100); Alloc buf = Alloc::allocMMap(100); |