From bef662b9743999cce4e71afa3f331b2b9bdfa5be Mon Sep 17 00:00:00 2001 From: Martin Polden Date: Mon, 28 Jun 2021 11:52:26 +0200 Subject: Remove docker-api --- node-admin/pom.xml | 6 - node-admin/src/main/application/services.xml | 3 +- .../hosted/node/admin/container/Container.java | 80 +++++++ .../hosted/node/admin/container/ContainerId.java | 36 ++++ .../hosted/node/admin/container/ContainerName.java | 54 +++++ .../node/admin/container/ContainerOperations.java | 7 - .../node/admin/container/ContainerResources.java | 130 ++++++++++++ .../node/admin/container/ContainerStats.java | 231 +++++++++++++++++++++ .../hosted/node/admin/container/ProcessResult.java | 48 +++++ .../node/admin/container/RegistryCredentials.java | 57 +++++ .../container/RegistryCredentialsProvider.java | 2 - .../node/admin/container/metrics/Counter.java | 28 +++ .../admin/container/metrics/DimensionMetrics.java | 76 +++++++ .../node/admin/container/metrics/Dimensions.java | 55 +++++ .../hosted/node/admin/container/metrics/Gauge.java | 24 +++ .../node/admin/container/metrics/MetricValue.java | 9 + .../node/admin/container/metrics/Metrics.java | 128 ++++++++++++ .../node/admin/container/metrics/package-info.java | 5 + .../node/admin/maintenance/StorageMaintainer.java | 4 +- .../admin/maintenance/coredump/CoreCollector.java | 2 +- .../maintenance/coredump/CoredumpHandler.java | 4 +- .../identity/AthenzCredentialsMaintainer.java | 2 +- .../hosted/node/admin/nodeadmin/NodeAdminImpl.java | 8 +- .../node/admin/nodeagent/NodeAgentContext.java | 2 +- .../node/admin/nodeagent/NodeAgentContextImpl.java | 2 +- .../hosted/node/admin/nodeagent/NodeAgentImpl.java | 26 +-- .../node/admin/container/ContainerNameTest.java | 45 ++++ .../admin/container/ContainerResourcesTest.java | 49 +++++ .../node/admin/container/ProcessResultTest.java | 24 +++ .../node/admin/container/metrics/MetricsTest.java | 99 +++++++++ .../node/admin/integration/ContainerFailTest.java | 2 +- .../admin/integration/ContainerOperationsMock.java | 14 +- .../node/admin/integration/ContainerTester.java | 6 +- .../node/admin/integration/MultiContainerTest.java | 2 +- .../hosted/node/admin/integration/RebootTest.java | 2 +- .../hosted/node/admin/integration/RestartTest.java | 2 +- .../maintenance/coredump/CoreCollectorTest.java | 2 +- .../maintenance/coredump/CoredumpHandlerTest.java | 4 +- .../node/admin/nodeadmin/NodeAdminImplTest.java | 2 +- .../node/admin/nodeagent/NodeAgentImplTest.java | 17 +- 40 files changed, 1223 insertions(+), 76 deletions(-) create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/Container.java create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerId.java create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerName.java create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerResources.java create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerStats.java create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ProcessResult.java create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/RegistryCredentials.java create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Counter.java create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/DimensionMetrics.java create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Dimensions.java create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Gauge.java create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/MetricValue.java create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Metrics.java create mode 100644 node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/package-info.java create mode 100644 node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/ContainerNameTest.java create mode 100644 node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/ContainerResourcesTest.java create mode 100644 node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/ProcessResultTest.java create mode 100644 node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/metrics/MetricsTest.java (limited to 'node-admin') diff --git a/node-admin/pom.xml b/node-admin/pom.xml index 52873501744..473d106775e 100644 --- a/node-admin/pom.xml +++ b/node-admin/pom.xml @@ -19,12 +19,6 @@ - - com.yahoo.vespa - docker-api - ${project.version} - provided - com.yahoo.vespa config-provisioning diff --git a/node-admin/src/main/application/services.xml b/node-admin/src/main/application/services.xml index d978b358032..e8747ca2977 100644 --- a/node-admin/src/main/application/services.xml +++ b/node-admin/src/main/application/services.xml @@ -5,8 +5,7 @@ - - + diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/Container.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/Container.java new file mode 100644 index 00000000000..7aeb43e44f4 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/Container.java @@ -0,0 +1,80 @@ +// 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.container; + +import com.yahoo.config.provision.DockerImage; + +import java.util.Objects; + +/** + * @author stiankri + */ +public class Container { + private final ContainerId id; + public final String hostname; + public final DockerImage image; + public final ContainerResources resources; + public final ContainerName name; + public final State state; + public final int pid; + + public Container( + final ContainerId id, + final String hostname, + final DockerImage image, + final ContainerResources resources, + final ContainerName containerName, + final State state, + final int pid) { + this.id = id; + this.hostname = hostname; + this.image = image; + this.resources = resources; + this.name = containerName; + this.state = state; + this.pid = pid; + } + + public ContainerId id() { + return id; + } + + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof Container)) { + return false; + } + final Container other = (Container) obj; + return Objects.equals(id, other.id) + && Objects.equals(hostname, other.hostname) + && Objects.equals(image, other.image) + && Objects.equals(resources, other.resources) + && Objects.equals(name, other.name) + && Objects.equals(pid, other.pid); + } + + @Override + public int hashCode() { + return Objects.hash(hostname, image, resources, name, pid); + } + + @Override + public String toString() { + return "Container {" + + " id=" + id + + " hostname=" + hostname + + " image=" + image + + " resources=" + resources + + " name=" + name + + " state=" + state + + " pid=" + pid + + "}"; + } + + public enum State { + CREATED, RESTARTING, RUNNING, REMOVING, PAUSED, EXITED, DEAD, UNKNOWN, CONFIGURED, STOPPED; + + public boolean isRunning() { + return this == RUNNING; + } + } +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerId.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerId.java new file mode 100644 index 00000000000..0e6a4835abf --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerId.java @@ -0,0 +1,36 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// +package com.yahoo.vespa.hosted.node.admin.container; + +import java.util.Objects; + +/** + * The ID of a container. + * + * @author hakon + */ +public class ContainerId { + private final String id; + + public ContainerId(String id) { + this.id = Objects.requireNonNull(id, "id cannot be null"); + } + + @Override + public String toString() { + return id; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ContainerId that = (ContainerId) o; + return id.equals(that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerName.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerName.java new file mode 100644 index 00000000000..49dacc44335 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerName.java @@ -0,0 +1,54 @@ +// 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.container; + +import java.util.Objects; +import java.util.regex.Pattern; + +/** + * Type-safe value wrapper for docker container names. + * + * @author bakksjo + */ +public class ContainerName { + private static final Pattern LEGAL_CONTAINER_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9-]+$"); + private final String name; + + public ContainerName(final String name) { + this.name = Objects.requireNonNull(name); + if (! LEGAL_CONTAINER_NAME_PATTERN.matcher(name).matches()) { + throw new IllegalArgumentException("Illegal container name: " + name + ". Must match " + + LEGAL_CONTAINER_NAME_PATTERN.toString()); + } + } + + public String asString() { + return name; + } + + public static ContainerName fromHostname(final String hostName) { + return new ContainerName(hostName.split("\\.", 2)[0]); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(final Object o) { + if (!(o instanceof ContainerName)) { + return false; + } + + final ContainerName other = (ContainerName) o; + + return Objects.equals(name, other.name); + } + + @Override + public String toString() { + return getClass().getSimpleName() + " {" + + " name=" + name + + " }"; + } +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerOperations.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerOperations.java index 8bd6382fa5f..e48927279a4 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerOperations.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerOperations.java @@ -2,13 +2,6 @@ package com.yahoo.vespa.hosted.node.admin.container; import com.yahoo.config.provision.DockerImage; -import com.yahoo.vespa.hosted.dockerapi.Container; -import com.yahoo.vespa.hosted.dockerapi.ContainerId; -import com.yahoo.vespa.hosted.dockerapi.ContainerName; -import com.yahoo.vespa.hosted.dockerapi.ContainerResources; -import com.yahoo.vespa.hosted.dockerapi.ContainerStats; -import com.yahoo.vespa.hosted.dockerapi.ProcessResult; -import com.yahoo.vespa.hosted.dockerapi.RegistryCredentials; import com.yahoo.vespa.hosted.node.admin.component.TaskContext; import com.yahoo.vespa.hosted.node.admin.nodeagent.ContainerData; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext; diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerResources.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerResources.java new file mode 100644 index 00000000000..f01527f58d1 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerResources.java @@ -0,0 +1,130 @@ +// 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.node.admin.container; + +import java.util.Objects; + +/** + * @author valerijf + */ +public class ContainerResources { + + public static final ContainerResources UNLIMITED = ContainerResources.from(0, 0, 0); + public static final int CPU_PERIOD_US = 100_000; // 100 ms + + /** + * Hard limit on container's CPU usage: Implemented using Completely Fair Scheduler (CFS) by allocating a given + * time within a given period, Container's processes are not bound to any specific CPU, which may create significant + * performance degradation as processes are scheduled on another CPU after exhausting the quota. + */ + private final double cpus; + + /** + * Soft limit on container's CPU usage: When plenty of CPU cycles are available, all containers use as much + * CPU as they need. It prioritizes container CPU resources for the available CPU cycles. + * It does not guarantee or reserve any specific CPU access. + */ + private final int cpuShares; + + /** The maximum amount, in bytes, of memory the container can use. */ + private final long memoryBytes; + + public ContainerResources(double cpus, int cpuShares, long memoryBytes) { + this.cpus = cpus; + this.cpuShares = cpuShares; + this.memoryBytes = memoryBytes; + + if (cpus < 0) + throw new IllegalArgumentException("CPUs must be a positive number or 0 for unlimited, was " + cpus); + if (cpuShares != 0 && (cpuShares < 2 || cpuShares > 262_144)) + throw new IllegalArgumentException("CPU shares must be a positive integer in [2, 262144] or 0 for unlimited, was " + cpuShares); + if (memoryBytes < 0) + throw new IllegalArgumentException("memoryBytes must be a positive integer or 0 for unlimited, was " + memoryBytes); + } + + /** + * Create container resources from required fields. + * + * @param maxVcpu the amount of vcpu that allocation policies should allocate exclusively to this container. + * This is a hard upper limit. To allow an unlimited amount use 0. + * @param minVcpu the minimal amount of vcpu dedicated to this container. + * To avoid dedicating any cpu at all, use 0. + * @param memoryGb the amount of memory that allocation policies should allocate to this container. + * This is a hard upper limit. To allow the container to allocate an unlimited amount use 0. + * @return the container resources encapsulating the parameters + */ + public static ContainerResources from(double maxVcpu, double minVcpu, double memoryGb) { + return new ContainerResources(maxVcpu, + (int) Math.round(32 * minVcpu), + (long) ((1L << 30) * memoryGb)); + } + + public double cpus() { + return cpus; + } + + /** Returns the CFS CPU quota per {@link #cpuPeriod()}, or -1 if disabled. */ + public int cpuQuota() { + return cpus > 0 ? (int) (cpus * CPU_PERIOD_US) : -1; + } + + /** Duration (in µs) of a single period used as the basis for process scheduling */ + public int cpuPeriod() { + return CPU_PERIOD_US; + } + + public int cpuShares() { + return cpuShares; + } + + public long memoryBytes() { + return memoryBytes; + } + + /** Returns true iff the memory component(s) of between this and other are equal */ + public boolean equalsMemory(ContainerResources other) { + return memoryBytes == other.memoryBytes; + } + + /** Returns true iff the CPU component(s) of between this and other are equal */ + public boolean equalsCpu(ContainerResources other) { + return Math.abs(other.cpus - cpus) < 0.0001 && cpuShares == other.cpuShares; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ContainerResources that = (ContainerResources) o; + return equalsMemory(that) && equalsCpu(that); + } + + @Override + public int hashCode() { + return Objects.hash(cpus, cpuShares, memoryBytes); + } + + + /** Returns only the memory component(s) of {@link #toString()} */ + public String toStringMemory() { + return (memoryBytes > 0 ? memoryBytes + "B" : "unlimited") + " memory"; + } + + /** Returns only the CPU component(s) of {@link #toString()} */ + public String toStringCpu() { + return (cpus > 0 ? String.format("%.2f", cpus) : "unlimited") +" CPUs, " + + (cpuShares > 0 ? cpuShares : "unlimited") + " CPU Shares"; + } + + @Override + public String toString() { + return toStringCpu() + ", " + toStringMemory(); + } + + public ContainerResources withMemoryBytes(long memoryBytes) { + return new ContainerResources(cpus, cpuShares, memoryBytes); + } + + public ContainerResources withUnlimitedCpus() { + return new ContainerResources(0, 0, memoryBytes); + } +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerStats.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerStats.java new file mode 100644 index 00000000000..78adcebe31e --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ContainerStats.java @@ -0,0 +1,231 @@ +// 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.container; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; + +/** + * CPU, memory and network statistics collected from a container. + * + * @author freva + */ +public class ContainerStats { + + private final Map networkStatsByInterface; + private final MemoryStats memoryStats; + private final CpuStats cpuStats; + + public ContainerStats(Map networkStatsByInterface, MemoryStats memoryStats, CpuStats cpuStats) { + this.networkStatsByInterface = new LinkedHashMap<>(Objects.requireNonNull(networkStatsByInterface)); + this.memoryStats = Objects.requireNonNull(memoryStats); + this.cpuStats = Objects.requireNonNull(cpuStats); + } + + public Map getNetworks() { + return Collections.unmodifiableMap(networkStatsByInterface); + } + + public MemoryStats getMemoryStats() { + return memoryStats; + } + + public CpuStats getCpuStats() { + return cpuStats; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ContainerStats that = (ContainerStats) o; + return networkStatsByInterface.equals(that.networkStatsByInterface) && memoryStats.equals(that.memoryStats) && cpuStats.equals(that.cpuStats); + } + + @Override + public int hashCode() { + return Objects.hash(networkStatsByInterface, memoryStats, cpuStats); + } + + /** Statistics for network usage */ + public static class NetworkStats { + + private final long rxBytes; + private final long rxDropped; + private final long rxErrors; + private final long txBytes; + private final long txDropped; + private final long txErrors; + + public NetworkStats(long rxBytes, long rxDropped, long rxErrors, long txBytes, long txDropped, long txErrors) { + this.rxBytes = rxBytes; + this.rxDropped = rxDropped; + this.rxErrors = rxErrors; + this.txBytes = txBytes; + this.txDropped = txDropped; + this.txErrors = txErrors; + } + + /** Returns received bytes */ + public long getRxBytes() { return this.rxBytes; } + + /** Returns received bytes, which was dropped */ + public long getRxDropped() { return this.rxDropped; } + + /** Returns received errors */ + public long getRxErrors() { return this.rxErrors; } + + /** Returns transmitted bytes */ + public long getTxBytes() { return this.txBytes; } + + /** Returns transmitted bytes, which was dropped */ + public long getTxDropped() { return this.txDropped; } + + /** Returns transmission errors */ + public long getTxErrors() { return this.txErrors; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + NetworkStats that = (NetworkStats) o; + return rxBytes == that.rxBytes && rxDropped == that.rxDropped && rxErrors == that.rxErrors && txBytes == that.txBytes && txDropped == that.txDropped && txErrors == that.txErrors; + } + + @Override + public int hashCode() { + return Objects.hash(rxBytes, rxDropped, rxErrors, txBytes, txDropped, txErrors); + } + + @Override + public String toString() { + return "NetworkStats{" + + "rxBytes=" + rxBytes + + ", rxDropped=" + rxDropped + + ", rxErrors=" + rxErrors + + ", txBytes=" + txBytes + + ", txDropped=" + txDropped + + ", txErrors=" + txErrors + + '}'; + } + + } + + /** Statistics for memory usage */ + public static class MemoryStats { + + private final long cache; + private final long usage; + private final long limit; + + public MemoryStats(long cache, long usage, long limit) { + this.cache = cache; + this.usage = usage; + this.limit = limit; + } + + /** Returns memory used by cache in bytes */ + public long getCache() { return this.cache; } + + /** Returns memory usage in bytes */ + public long getUsage() { return this.usage; } + + /** Returns memory limit in bytes */ + public long getLimit() { return this.limit; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MemoryStats that = (MemoryStats) o; + return cache == that.cache && usage == that.usage && limit == that.limit; + } + + @Override + public int hashCode() { + return Objects.hash(cache, usage, limit); + } + + @Override + public String toString() { + return "MemoryStats{" + + "cache=" + cache + + ", usage=" + usage + + ", limit=" + limit + + '}'; + } + + } + + /** Statistics for CPU usage */ + public static class CpuStats { + + private final int onlineCpus; + private final long systemCpuUsage; + private final long totalUsage; + private final long usageInKernelMode; + private final long throttledTime; + private final long throttlingActivePeriods; + private final long throttledPeriods; + + public CpuStats(int onlineCpus, long systemCpuUsage, long totalUsage, long usageInKernelMode, + long throttledTime, long throttlingActivePeriods, long throttledPeriods) { + this.onlineCpus = onlineCpus; + this.systemCpuUsage = systemCpuUsage; + this.totalUsage = totalUsage; + this.usageInKernelMode = usageInKernelMode; + this.throttledTime = throttledTime; + this.throttlingActivePeriods = throttlingActivePeriods; + this.throttledPeriods = throttledPeriods; + } + + public int getOnlineCpus() { return this.onlineCpus; } + + /** Total CPU time (in ns) spent executing all the processes on this host */ + public long getSystemCpuUsage() { return this.systemCpuUsage; } + + /** Total CPU time (in ns) spent running all the processes in this container */ + public long getTotalUsage() { return totalUsage; } + + /** Total CPU time (in ns) spent in kernel mode while executing processes in this container */ + public long getUsageInKernelMode() { return usageInKernelMode; } + + /** Total CPU time (in ns) processes in this container were throttled for */ + public long getThrottledTime() { return throttledTime; } + + /** Number of periods with throttling enabled for this container */ + public long getThrottlingActivePeriods() { return throttlingActivePeriods; } + + /** Number of periods this container hit the throttling limit */ + public long getThrottledPeriods() { return throttledPeriods; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CpuStats cpuStats = (CpuStats) o; + return onlineCpus == cpuStats.onlineCpus && systemCpuUsage == cpuStats.systemCpuUsage && totalUsage == cpuStats.totalUsage && usageInKernelMode == cpuStats.usageInKernelMode && throttledTime == cpuStats.throttledTime && throttlingActivePeriods == cpuStats.throttlingActivePeriods && throttledPeriods == cpuStats.throttledPeriods; + } + + @Override + public int hashCode() { + return Objects.hash(onlineCpus, systemCpuUsage, totalUsage, usageInKernelMode, throttledTime, throttlingActivePeriods, throttledPeriods); + } + + @Override + public String toString() { + return "CpuStats{" + + "onlineCpus=" + onlineCpus + + ", systemCpuUsage=" + systemCpuUsage + + ", totalUsage=" + totalUsage + + ", usageInKernelMode=" + usageInKernelMode + + ", throttledTime=" + throttledTime + + ", throttlingActivePeriods=" + throttlingActivePeriods + + ", throttledPeriods=" + throttledPeriods + + '}'; + } + + } + +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ProcessResult.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ProcessResult.java new file mode 100644 index 00000000000..066a65eb409 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/ProcessResult.java @@ -0,0 +1,48 @@ +// 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.container; + +import java.util.Objects; + +// TODO: Replace usages of this with CommandResult +public class ProcessResult { + private final int exitStatus; + private final String output; + private final String errors; + + public ProcessResult(int exitStatus, String output, String errors) { + this.exitStatus = exitStatus; + this.output = output; + this.errors = errors; + } + + public boolean isSuccess() { return exitStatus == 0; } + public int getExitStatus() { return exitStatus; } + + public String getOutput() { return output; } + + public String getErrors() { return errors; } + + @Override + public boolean equals(Object o) { + if (!(o instanceof ProcessResult)) return false; + ProcessResult other = (ProcessResult) o; + return Objects.equals(exitStatus, other.exitStatus) + && Objects.equals(output, other.output) + && Objects.equals(errors, other.errors); + } + + @Override + public int hashCode() { + return Objects.hash(exitStatus, output, errors); + } + + @Override + public String toString() { + return "ProcessResult {" + + " exitStatus=" + exitStatus + + " output=" + output + + " errors=" + errors + + " }"; + } + +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/RegistryCredentials.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/RegistryCredentials.java new file mode 100644 index 00000000000..6437497fa68 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/RegistryCredentials.java @@ -0,0 +1,57 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.node.admin.container; + +import java.util.Objects; + +/** + * Credentials for a container registry server. + * + * @author mpolden + */ +public class RegistryCredentials { + + public static final RegistryCredentials none = new RegistryCredentials("", "", ""); + + private final String username; + private final String password; + private final String registryAddress; + + public RegistryCredentials(String username, String password, String registryAddress) { + this.username = Objects.requireNonNull(username); + this.password = Objects.requireNonNull(password); + this.registryAddress = Objects.requireNonNull(registryAddress); + } + + public String username() { + return username; + } + + public String password() { + return password; + } + + public String registryAddress() { + return registryAddress; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RegistryCredentials that = (RegistryCredentials) o; + return username.equals(that.username) && + password.equals(that.password) && + registryAddress.equals(that.registryAddress); + } + + @Override + public int hashCode() { + return Objects.hash(username, password, registryAddress); + } + + @Override + public String toString() { + return "registry credentials for " + registryAddress + " [username=" + username + ",password=" + password + "]"; + } + +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/RegistryCredentialsProvider.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/RegistryCredentialsProvider.java index 44e00425a11..1cd342d68a5 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/RegistryCredentialsProvider.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/RegistryCredentialsProvider.java @@ -1,8 +1,6 @@ // Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.node.admin.container; -import com.yahoo.vespa.hosted.dockerapi.RegistryCredentials; - /** * Interface for retrieving credentials for a container registry. * diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Counter.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Counter.java new file mode 100644 index 00000000000..9cb26d71275 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Counter.java @@ -0,0 +1,28 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.node.admin.container.metrics; + +/** + * @author freva + */ +public class Counter implements MetricValue { + private final Object lock = new Object(); + + private long value = 0; + + public void increment() { + add(1L); + } + + public void add(long n) { + synchronized (lock) { + value += n; + } + } + + @Override + public Number getValue() { + synchronized (lock) { + return value; + } + } +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/DimensionMetrics.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/DimensionMetrics.java new file mode 100644 index 00000000000..929fcde9492 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/DimensionMetrics.java @@ -0,0 +1,76 @@ +// 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.container.metrics; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * @author freva + */ +public class DimensionMetrics { + + private final String application; + private final Dimensions dimensions; + private final Map metrics; + + DimensionMetrics(String application, Dimensions dimensions, Map metrics) { + this.application = Objects.requireNonNull(application); + this.dimensions = Objects.requireNonNull(dimensions); + this.metrics = metrics.entrySet().stream() + .filter(DimensionMetrics::metricIsFinite) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + public String getApplication() { + return application; + } + + public Dimensions getDimensions() { + return dimensions; + } + + public Map getMetrics() { + return metrics; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DimensionMetrics that = (DimensionMetrics) o; + return application.equals(that.application) && + dimensions.equals(that.dimensions) && + metrics.equals(that.metrics); + } + + @Override + public int hashCode() { + return Objects.hash(application, dimensions, metrics); + } + + private static boolean metricIsFinite(Map.Entry metric) { + return ! (metric.getValue() instanceof Double) || Double.isFinite((double) metric.getValue()); + } + + public static class Builder { + private final String application; + private final Dimensions dimensions; + private final Map metrics = new HashMap<>(); + + public Builder(String application, Dimensions dimensions) { + this.application = application; + this.dimensions = dimensions; + } + + public Builder withMetric(String metricName, Number metricValue) { + metrics.put(metricName, metricValue); + return this; + } + + public DimensionMetrics build() { + return new DimensionMetrics(application, dimensions, metrics); + } + } +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Dimensions.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Dimensions.java new file mode 100644 index 00000000000..2999a3c8839 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Dimensions.java @@ -0,0 +1,55 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.node.admin.container.metrics; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author freva + */ +public class Dimensions { + + public static final Dimensions NONE = new Dimensions(Map.of()); + + private final Map dimensionsMap; + + public Dimensions(Map dimensionsMap) { + this.dimensionsMap = Map.copyOf(dimensionsMap); + } + + public Map asMap() { + return dimensionsMap; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Dimensions that = (Dimensions) o; + return dimensionsMap.equals(that.dimensionsMap); + } + + @Override + public int hashCode() { + return dimensionsMap.hashCode(); + } + + @Override + public String toString() { + return dimensionsMap.toString(); + } + + public static class Builder { + private final Map dimensionsMap = new HashMap<>(); + + public Dimensions.Builder add(String dimensionName, String dimensionValue) { + dimensionsMap.put(dimensionName, dimensionValue); + return this; + } + + public Dimensions build() { + return new Dimensions(dimensionsMap); + } + } +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Gauge.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Gauge.java new file mode 100644 index 00000000000..d3a7072b08b --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Gauge.java @@ -0,0 +1,24 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.node.admin.container.metrics; + +/** + * @author freva + */ +public class Gauge implements MetricValue { + private final Object lock = new Object(); + + private double value; + + public void sample(double x) { + synchronized (lock) { + this.value = x; + } + } + + @Override + public Number getValue() { + synchronized (lock) { + return value; + } + } +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/MetricValue.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/MetricValue.java new file mode 100644 index 00000000000..07a6ffd9d22 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/MetricValue.java @@ -0,0 +1,9 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.node.admin.container.metrics; + +/** + * @author freva + */ +public interface MetricValue { + Number getValue(); +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Metrics.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Metrics.java new file mode 100644 index 00000000000..ec3b2d347e5 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/Metrics.java @@ -0,0 +1,128 @@ +// 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.container.metrics; + +import com.google.inject.Inject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * Stores the latest metric for the given application, name, dimension triplet in memory + * + * @author freva + */ +public class Metrics { + // Application names used + public static final String APPLICATION_HOST = "vespa.host"; + public static final String APPLICATION_NODE = "vespa.node"; + + private final Object monitor = new Object(); + private final Map> metrics = new HashMap<>(); + + @Inject + public Metrics() { } + + /** + * Creates a counter metric under vespa.host application, with no dimensions and default dimension type + * See {@link #declareCounter(String, String, Dimensions, DimensionType)} + */ + public Counter declareCounter(String name) { + return declareCounter(name, Dimensions.NONE); + } + + /** + * Creates a counter metric under vespa.host application, with the given dimensions and default dimension type + * See {@link #declareCounter(String, String, Dimensions, DimensionType)} + */ + public Counter declareCounter(String name, Dimensions dimensions) { + return declareCounter(APPLICATION_HOST, name, dimensions, DimensionType.DEFAULT); + } + + /** Creates a counter metric. This method is idempotent. */ + public Counter declareCounter(String application, String name, Dimensions dimensions, DimensionType type) { + synchronized (monitor) { + return (Counter) getOrCreateApplicationMetrics(application, type) + .computeIfAbsent(dimensions, d -> new HashMap<>()) + .computeIfAbsent(name, n -> new Counter()); + } + } + + /** + * Creates a gauge metric under vespa.host application, with no dimensions and default dimension type + * See {@link #declareGauge(String, String, Dimensions, DimensionType)} + */ + public Gauge declareGauge(String name) { + return declareGauge(name, Dimensions.NONE); + } + + /** + * Creates a gauge metric under vespa.host application, with the given dimensions and default dimension type + * See {@link #declareGauge(String, String, Dimensions, DimensionType)} + */ + public Gauge declareGauge(String name, Dimensions dimensions) { + return declareGauge(APPLICATION_HOST, name, dimensions, DimensionType.DEFAULT); + } + + /** Creates a gauge metric. This method is idempotent */ + public Gauge declareGauge(String application, String name, Dimensions dimensions, DimensionType type) { + synchronized (monitor) { + return (Gauge) getOrCreateApplicationMetrics(application, type) + .computeIfAbsent(dimensions, d -> new HashMap<>()) + .computeIfAbsent(name, n -> new Gauge()); + } + } + + public List getDefaultMetrics() { + return getMetricsByType(DimensionType.DEFAULT); + } + + public List getMetricsByType(DimensionType type) { + synchronized (monitor) { + List dimensionMetrics = new ArrayList<>(); + metrics.getOrDefault(type, Map.of()) + .forEach((application, applicationMetrics) -> applicationMetrics.metricsByDimensions().entrySet().stream() + .map(entry -> new DimensionMetrics(application, entry.getKey(), + entry.getValue().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, value -> value.getValue().getValue())))) + .forEach(dimensionMetrics::add)); + return dimensionMetrics; + } + } + + public void deleteMetricByDimension(String name, Dimensions dimensionsToRemove, DimensionType type) { + synchronized (monitor) { + Optional.ofNullable(metrics.get(type)) + .map(m -> m.get(name)) + .map(ApplicationMetrics::metricsByDimensions) + .ifPresent(m -> m.remove(dimensionsToRemove)); + } + } + + Map> getOrCreateApplicationMetrics(String application, DimensionType type) { + return metrics.computeIfAbsent(type, m -> new HashMap<>()) + .computeIfAbsent(application, app -> new ApplicationMetrics()) + .metricsByDimensions(); + } + + // "Application" is the monitoring application, not Vespa application + private static class ApplicationMetrics { + private final Map> metricsByDimensions = new LinkedHashMap<>(); + + Map> metricsByDimensions() { + return metricsByDimensions; + } + } + + // Used to distinguish whether metrics have been populated with all tag vaules + public enum DimensionType { + /** Default metrics get added default dimensions set in check config */ + DEFAULT, + + /** Pretagged metrics will only get the dimensions explicitly set when creating the counter/gauge */ + PRETAGGED + } +} diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/package-info.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/package-info.java new file mode 100644 index 00000000000..3f514f96f84 --- /dev/null +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/container/metrics/package-info.java @@ -0,0 +1,5 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +@ExportPackage +package com.yahoo.vespa.hosted.node.admin.container.metrics; + +import com.yahoo.osgi.annotation.ExportPackage; diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/StorageMaintainer.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/StorageMaintainer.java index 9ced178cff9..15705557447 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/StorageMaintainer.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/StorageMaintainer.java @@ -5,8 +5,8 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.yahoo.config.provision.DockerImage; import com.yahoo.config.provision.NodeType; -import com.yahoo.vespa.hosted.dockerapi.Container; -import com.yahoo.vespa.hosted.dockerapi.ContainerName; +import com.yahoo.vespa.hosted.node.admin.container.Container; +import com.yahoo.vespa.hosted.node.admin.container.ContainerName; import com.yahoo.vespa.hosted.node.admin.component.TaskContext; import com.yahoo.vespa.hosted.node.admin.maintenance.coredump.CoredumpHandler; import com.yahoo.vespa.hosted.node.admin.maintenance.disk.CoredumpCleanupRule; diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoreCollector.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoreCollector.java index ab3cb3147fa..16b7e462ad3 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoreCollector.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoreCollector.java @@ -1,7 +1,7 @@ // 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.node.admin.maintenance.coredump; -import com.yahoo.vespa.hosted.dockerapi.ProcessResult; +import com.yahoo.vespa.hosted.node.admin.container.ProcessResult; import com.yahoo.vespa.hosted.node.admin.container.ContainerOperations; import com.yahoo.vespa.hosted.node.admin.nodeadmin.ConvergenceException; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext; diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandler.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandler.java index 7f79efdeab9..0fd912b528c 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandler.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandler.java @@ -2,8 +2,8 @@ package com.yahoo.vespa.hosted.node.admin.maintenance.coredump; import com.fasterxml.jackson.databind.ObjectMapper; -import com.yahoo.vespa.hosted.dockerapi.metrics.Dimensions; -import com.yahoo.vespa.hosted.dockerapi.metrics.Metrics; +import com.yahoo.vespa.hosted.node.admin.container.metrics.Dimensions; +import com.yahoo.vespa.hosted.node.admin.container.metrics.Metrics; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; import com.yahoo.vespa.hosted.node.admin.nodeadmin.ConvergenceException; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext; diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java index eb04765c621..a0d074c29d9 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java @@ -20,7 +20,7 @@ import com.yahoo.vespa.athenz.identityprovider.client.CsrGenerator; import com.yahoo.vespa.athenz.identityprovider.client.DefaultIdentityDocumentClient; import com.yahoo.vespa.athenz.tls.AthenzIdentityVerifier; import com.yahoo.vespa.athenz.utils.SiaUtils; -import com.yahoo.vespa.hosted.dockerapi.ContainerName; +import com.yahoo.vespa.hosted.node.admin.container.ContainerName; import com.yahoo.vespa.hosted.node.admin.component.ConfigServerInfo; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentTask; diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminImpl.java index 5d7ab48753f..8c8f3d88a71 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminImpl.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminImpl.java @@ -1,10 +1,10 @@ // 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.nodeadmin; -import com.yahoo.vespa.hosted.dockerapi.metrics.Counter; -import com.yahoo.vespa.hosted.dockerapi.metrics.Dimensions; -import com.yahoo.vespa.hosted.dockerapi.metrics.Gauge; -import com.yahoo.vespa.hosted.dockerapi.metrics.Metrics; +import com.yahoo.vespa.hosted.node.admin.container.metrics.Counter; +import com.yahoo.vespa.hosted.node.admin.container.metrics.Dimensions; +import com.yahoo.vespa.hosted.node.admin.container.metrics.Gauge; +import com.yahoo.vespa.hosted.node.admin.container.metrics.Metrics; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgent; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContextManager; diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContext.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContext.java index 1eac9103583..479f2342773 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContext.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContext.java @@ -6,7 +6,7 @@ import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.NodeType; import com.yahoo.config.provision.zone.ZoneApi; import com.yahoo.vespa.athenz.api.AthenzIdentity; -import com.yahoo.vespa.hosted.dockerapi.ContainerName; +import com.yahoo.vespa.hosted.node.admin.container.ContainerName; import com.yahoo.vespa.hosted.node.admin.component.TaskContext; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.Acl; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java index 5e2ce5e565e..c0406f91c30 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentContextImpl.java @@ -12,7 +12,7 @@ import com.yahoo.vespa.flags.FetchVector; import com.yahoo.vespa.flags.FlagSource; import com.yahoo.vespa.flags.InMemoryFlagSource; import com.yahoo.vespa.flags.PermanentFlags; -import com.yahoo.vespa.hosted.dockerapi.ContainerName; +import com.yahoo.vespa.hosted.node.admin.container.ContainerName; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.Acl; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; import com.yahoo.vespa.hosted.node.admin.container.ContainerNetworkMode; diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java index 267e72ea0aa..a41bfac57c0 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeagent/NodeAgentImpl.java @@ -10,11 +10,6 @@ import com.yahoo.vespa.flags.DoubleFlag; import com.yahoo.vespa.flags.FetchVector; import com.yahoo.vespa.flags.FlagSource; import com.yahoo.vespa.flags.PermanentFlags; -import com.yahoo.vespa.hosted.dockerapi.Container; -import com.yahoo.vespa.hosted.dockerapi.ContainerResources; -import com.yahoo.vespa.hosted.dockerapi.RegistryCredentials; -import com.yahoo.vespa.hosted.dockerapi.exception.ContainerNotFoundException; -import com.yahoo.vespa.hosted.dockerapi.exception.DockerException; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeAttributes; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeMembership; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeRepository; @@ -22,7 +17,10 @@ import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeState; import com.yahoo.vespa.hosted.node.admin.configserver.orchestrator.Orchestrator; import com.yahoo.vespa.hosted.node.admin.configserver.orchestrator.OrchestratorException; +import com.yahoo.vespa.hosted.node.admin.container.Container; import com.yahoo.vespa.hosted.node.admin.container.ContainerOperations; +import com.yahoo.vespa.hosted.node.admin.container.ContainerResources; +import com.yahoo.vespa.hosted.node.admin.container.RegistryCredentials; import com.yahoo.vespa.hosted.node.admin.container.RegistryCredentialsProvider; import com.yahoo.vespa.hosted.node.admin.maintenance.StorageMaintainer; import com.yahoo.vespa.hosted.node.admin.maintenance.acl.AclMaintainer; @@ -284,13 +282,9 @@ public class NodeAgentImpl implements NodeAgent { private void stopServices(NodeAgentContext context) { context.log(logger, "Stopping services"); if (containerState == ABSENT) return; - try { - hasStartedServices = hasResumedNode = false; - firstSuccessfulHealthCheckInstant = Optional.empty(); - containerOperations.stopServices(context); - } catch (ContainerNotFoundException e) { - containerState = ABSENT; - } + hasStartedServices = hasResumedNode = false; + firstSuccessfulHealthCheckInstant = Optional.empty(); + containerOperations.stopServices(context); } @Override @@ -307,8 +301,6 @@ public class NodeAgentImpl implements NodeAgent { if (!output.isBlank()) { context.log(logger, "Suspend services output: " + output); } - } catch (ContainerNotFoundException e) { - containerState = ABSENT; } catch (RuntimeException e) { // It's bad to continue as-if nothing happened, but on the other hand if we do not proceed to // remove container, we will not be able to upgrade to fix any problems in the suspend logic! @@ -424,12 +416,6 @@ public class NodeAgentImpl implements NodeAgent { context.log(logger, Level.INFO, "Converged"); } catch (ConvergenceException e) { context.log(logger, e.getMessage()); - } catch (ContainerNotFoundException e) { - containerState = ABSENT; - context.log(logger, Level.WARNING, "Container unexpectedly gone, resetting containerState to " + containerState); - } catch (DockerException e) { - numberOfUnhandledException++; - context.log(logger, Level.SEVERE, "Caught a DockerException", e); } catch (Throwable e) { numberOfUnhandledException++; context.log(logger, Level.SEVERE, "Unhandled exception, ignoring", e); diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/ContainerNameTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/ContainerNameTest.java new file mode 100644 index 00000000000..f98c78c740a --- /dev/null +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/ContainerNameTest.java @@ -0,0 +1,45 @@ +// 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.container; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @author freva + */ +public class ContainerNameTest { + @Test + public void testAlphanumericalContainerName() { + String name = "container123"; + ContainerName containerName = new ContainerName(name); + assertEquals(containerName.asString(), name); + } + + @Test + public void testAlphanumericalWithDashContainerName() { + String name = "container-123"; + ContainerName containerName = new ContainerName(name); + assertEquals(containerName.asString(), name); + } + + @Test + public void testContainerNameFromHostname() { + assertEquals(new ContainerName("container-123"), ContainerName.fromHostname("container-123.sub.domain.tld")); + } + + @Test(expected=IllegalArgumentException.class) + public void testAlphanumericalWithSlashContainerName() { + new ContainerName("container/123"); + } + + @Test(expected=IllegalArgumentException.class) + public void testEmptyContainerName() { + new ContainerName(""); + } + + @Test(expected=NullPointerException.class) + public void testNullContainerName() { + new ContainerName(null); + } +} diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/ContainerResourcesTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/ContainerResourcesTest.java new file mode 100644 index 00000000000..d2ff57e5c09 --- /dev/null +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/ContainerResourcesTest.java @@ -0,0 +1,49 @@ +// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.node.admin.container; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * @author freva + */ +public class ContainerResourcesTest { + + @Test + public void verify_unlimited() { + assertEquals(-1, ContainerResources.UNLIMITED.cpuQuota()); + assertEquals(100_000, ContainerResources.UNLIMITED.cpuPeriod()); + assertEquals(0, ContainerResources.UNLIMITED.cpuShares()); + } + + @Test + public void validate_shares() { + new ContainerResources(0, 0, 0); + new ContainerResources(0, 2, 0); + new ContainerResources(0, 2048, 0); + new ContainerResources(0, 262_144, 0); + + assertThrows(IllegalArgumentException.class, () -> new ContainerResources(0, -1, 0)); // Negative shares not allowed + assertThrows(IllegalArgumentException.class, () -> new ContainerResources(0, 1, 0)); // 1 share not allowed + assertThrows(IllegalArgumentException.class, () -> new ContainerResources(0, 262_145, 0)); + } + + @Test + public void cpu_shares_scaling() { + ContainerResources resources = ContainerResources.from(5.3, 2.5, 0); + assertEquals(530_000, resources.cpuQuota()); + assertEquals(100_000, resources.cpuPeriod()); + assertEquals(80, resources.cpuShares()); + } + + private static void assertThrows(Class clazz, Runnable runnable) { + try { + runnable.run(); + fail("Expected " + clazz); + } catch (Throwable e) { + if (!clazz.isInstance(e)) throw e; + } + } +} diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/ProcessResultTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/ProcessResultTest.java new file mode 100644 index 00000000000..f7b832bd566 --- /dev/null +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/ProcessResultTest.java @@ -0,0 +1,24 @@ +// 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.container; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class ProcessResultTest { + @Test + public void testBasicProperties() { + ProcessResult processResult = new ProcessResult(0, "foo", "bar"); + assertEquals(0, processResult.getExitStatus()); + assertEquals("foo", processResult.getOutput()); + assertTrue(processResult.isSuccess()); + } + + @Test + public void testSuccessFails() { + ProcessResult processResult = new ProcessResult(1, "foo", "bar"); + assertFalse(processResult.isSuccess()); + } +} diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/metrics/MetricsTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/metrics/MetricsTest.java new file mode 100644 index 00000000000..6c48fe65142 --- /dev/null +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/container/metrics/MetricsTest.java @@ -0,0 +1,99 @@ +// 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.container.metrics; + +import org.junit.Test; + +import java.util.Map; +import java.util.stream.Collectors; + +import static com.yahoo.vespa.hosted.node.admin.container.metrics.Metrics.APPLICATION_HOST; +import static com.yahoo.vespa.hosted.node.admin.container.metrics.Metrics.DimensionType.DEFAULT; +import static org.junit.Assert.assertEquals; + +/** + * @author freva + */ +public class MetricsTest { + private static final Dimensions hostDimension = new Dimensions.Builder().add("host", "abc.yahoo.com").build(); + private final Metrics metrics = new Metrics(); + + @Test + public void testDefaultValue() { + metrics.declareCounter("some.name", hostDimension); + + assertEquals(getMetricsForDimension(hostDimension).get("some.name"), 0L); + } + + @Test + public void testSimpleIncrementMetric() { + Counter counter = metrics.declareCounter("a_counter.value", hostDimension); + + counter.add(5); + counter.add(8); + + Map latestMetrics = getMetricsForDimension(hostDimension); + assertEquals("Expected only 1 metric value to be set", 1, latestMetrics.size()); + assertEquals(latestMetrics.get("a_counter.value"), 13L); // 5 + 8 + } + + @Test + public void testSimpleGauge() { + Gauge gauge = metrics.declareGauge("test.gauge", hostDimension); + + gauge.sample(42); + gauge.sample(-342.23); + + Map latestMetrics = getMetricsForDimension(hostDimension); + assertEquals("Expected only 1 metric value to be set", 1, latestMetrics.size()); + assertEquals(latestMetrics.get("test.gauge"), -342.23); + } + + @Test + public void testRedeclaringSameGauge() { + Gauge gauge = metrics.declareGauge("test.gauge", hostDimension); + gauge.sample(42); + + // Same as hostDimension, but new instance. + Dimensions newDimension = new Dimensions.Builder().add("host", "abc.yahoo.com").build(); + Gauge newGauge = metrics.declareGauge("test.gauge", newDimension); + newGauge.sample(56); + + assertEquals(getMetricsForDimension(hostDimension).get("test.gauge"), 56.); + } + + @Test + public void testSameMetricNameButDifferentDimensions() { + Gauge gauge = metrics.declareGauge("test.gauge", hostDimension); + gauge.sample(42); + + // Not the same as hostDimension. + Dimensions newDimension = new Dimensions.Builder().add("host", "abcd.yahoo.com").build(); + Gauge newGauge = metrics.declareGauge("test.gauge", newDimension); + newGauge.sample(56); + + assertEquals(getMetricsForDimension(hostDimension).get("test.gauge"), 42.); + assertEquals(getMetricsForDimension(newDimension).get("test.gauge"), 56.); + } + + @Test + public void testDeletingMetric() { + metrics.declareGauge("test.gauge", hostDimension); + + Dimensions differentDimension = new Dimensions.Builder().add("host", "abcd.yahoo.com").build(); + metrics.declareGauge("test.gauge", differentDimension); + + assertEquals(2, metrics.getMetricsByType(DEFAULT).size()); + metrics.deleteMetricByDimension(APPLICATION_HOST, differentDimension, DEFAULT); + assertEquals(1, metrics.getMetricsByType(DEFAULT).size()); + assertEquals(getMetricsForDimension(hostDimension).size(), 1); + assertEquals(getMetricsForDimension(differentDimension).size(), 0); + } + + private Map getMetricsForDimension(Dimensions dimensions) { + return metrics.getOrCreateApplicationMetrics(APPLICATION_HOST, DEFAULT) + .getOrDefault(dimensions, Map.of()) + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getValue())); + } +} diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerFailTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerFailTest.java index d187c8e5476..04d86a69057 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerFailTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerFailTest.java @@ -2,7 +2,7 @@ package com.yahoo.vespa.hosted.node.admin.integration; import com.yahoo.config.provision.DockerImage; -import com.yahoo.vespa.hosted.dockerapi.ContainerName; +import com.yahoo.vespa.hosted.node.admin.container.ContainerName; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContextImpl; diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerOperationsMock.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerOperationsMock.java index 9600444c8f0..a19e031e41f 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerOperationsMock.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerOperationsMock.java @@ -2,13 +2,13 @@ package com.yahoo.vespa.hosted.node.admin.integration; import com.yahoo.config.provision.DockerImage; -import com.yahoo.vespa.hosted.dockerapi.Container; -import com.yahoo.vespa.hosted.dockerapi.ContainerId; -import com.yahoo.vespa.hosted.dockerapi.ContainerName; -import com.yahoo.vespa.hosted.dockerapi.ContainerResources; -import com.yahoo.vespa.hosted.dockerapi.ContainerStats; -import com.yahoo.vespa.hosted.dockerapi.ProcessResult; -import com.yahoo.vespa.hosted.dockerapi.RegistryCredentials; +import com.yahoo.vespa.hosted.node.admin.container.Container; +import com.yahoo.vespa.hosted.node.admin.container.ContainerId; +import com.yahoo.vespa.hosted.node.admin.container.ContainerName; +import com.yahoo.vespa.hosted.node.admin.container.ContainerResources; +import com.yahoo.vespa.hosted.node.admin.container.ContainerStats; +import com.yahoo.vespa.hosted.node.admin.container.ProcessResult; +import com.yahoo.vespa.hosted.node.admin.container.RegistryCredentials; import com.yahoo.vespa.hosted.node.admin.component.TaskContext; import com.yahoo.vespa.hosted.node.admin.container.ContainerOperations; import com.yahoo.vespa.hosted.node.admin.nodeagent.ContainerData; diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerTester.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerTester.java index c5092e833b2..9153afd8e54 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerTester.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/ContainerTester.java @@ -4,9 +4,9 @@ package com.yahoo.vespa.hosted.node.admin.integration; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.NodeType; import com.yahoo.vespa.flags.InMemoryFlagSource; -import com.yahoo.vespa.hosted.dockerapi.ContainerName; -import com.yahoo.vespa.hosted.dockerapi.RegistryCredentials; -import com.yahoo.vespa.hosted.dockerapi.metrics.Metrics; +import com.yahoo.vespa.hosted.node.admin.container.ContainerName; +import com.yahoo.vespa.hosted.node.admin.container.RegistryCredentials; +import com.yahoo.vespa.hosted.node.admin.container.metrics.Metrics; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; import com.yahoo.vespa.hosted.node.admin.configserver.orchestrator.Orchestrator; import com.yahoo.vespa.hosted.node.admin.maintenance.StorageMaintainer; diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/MultiContainerTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/MultiContainerTest.java index 78e9dc78a0f..86db3ae092e 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/MultiContainerTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/MultiContainerTest.java @@ -2,7 +2,7 @@ package com.yahoo.vespa.hosted.node.admin.integration; import com.yahoo.config.provision.DockerImage; -import com.yahoo.vespa.hosted.dockerapi.ContainerName; +import com.yahoo.vespa.hosted.node.admin.container.ContainerName; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeState; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext; diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/RebootTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/RebootTest.java index c77c3034142..dad02f46d88 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/RebootTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/RebootTest.java @@ -2,7 +2,7 @@ package com.yahoo.vespa.hosted.node.admin.integration; import com.yahoo.config.provision.DockerImage; -import com.yahoo.vespa.hosted.dockerapi.ContainerName; +import com.yahoo.vespa.hosted.node.admin.container.ContainerName; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; import com.yahoo.vespa.hosted.node.admin.nodeadmin.NodeAdminStateUpdater; import org.junit.Test; diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/RestartTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/RestartTest.java index 319623e69de..160948d7996 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/RestartTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/integration/RestartTest.java @@ -2,7 +2,7 @@ package com.yahoo.vespa.hosted.node.admin.integration; import com.yahoo.config.provision.DockerImage; -import com.yahoo.vespa.hosted.dockerapi.ContainerName; +import com.yahoo.vespa.hosted.node.admin.container.ContainerName; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeAttributes; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; import org.junit.Test; diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoreCollectorTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoreCollectorTest.java index afa2262b2df..3c22305d006 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoreCollectorTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoreCollectorTest.java @@ -1,7 +1,7 @@ // 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.node.admin.maintenance.coredump; -import com.yahoo.vespa.hosted.dockerapi.ProcessResult; +import com.yahoo.vespa.hosted.node.admin.container.ProcessResult; import com.yahoo.vespa.hosted.node.admin.container.ContainerOperations; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContextImpl; diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandlerTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandlerTest.java index 6dd7241fd63..d5ac850c770 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandlerTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/maintenance/coredump/CoredumpHandlerTest.java @@ -2,8 +2,8 @@ package com.yahoo.vespa.hosted.node.admin.maintenance.coredump; import com.yahoo.test.ManualClock; -import com.yahoo.vespa.hosted.dockerapi.metrics.DimensionMetrics; -import com.yahoo.vespa.hosted.dockerapi.metrics.Metrics; +import com.yahoo.vespa.hosted.node.admin.container.metrics.DimensionMetrics; +import com.yahoo.vespa.hosted.node.admin.container.metrics.Metrics; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContextImpl; import com.yahoo.vespa.hosted.node.admin.task.util.file.UnixPath; diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminImplTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminImplTest.java index b33f52ff629..68519cfc53d 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminImplTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/NodeAdminImplTest.java @@ -2,7 +2,7 @@ package com.yahoo.vespa.hosted.node.admin.nodeadmin; import com.yahoo.test.ManualClock; -import com.yahoo.vespa.hosted.dockerapi.metrics.Metrics; +import com.yahoo.vespa.hosted.node.admin.container.metrics.Metrics; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContext; import com.yahoo.vespa.hosted.node.admin.nodeagent.NodeAgentContextImpl; import org.junit.Test; 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 ff9ca86365d..454374fe3bd 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 @@ -9,12 +9,6 @@ import com.yahoo.config.provision.NodeType; import com.yahoo.test.ManualClock; import com.yahoo.vespa.flags.InMemoryFlagSource; import com.yahoo.vespa.flags.PermanentFlags; -import com.yahoo.vespa.hosted.dockerapi.Container; -import com.yahoo.vespa.hosted.dockerapi.ContainerId; -import com.yahoo.vespa.hosted.dockerapi.ContainerName; -import com.yahoo.vespa.hosted.dockerapi.ContainerResources; -import com.yahoo.vespa.hosted.dockerapi.RegistryCredentials; -import com.yahoo.vespa.hosted.dockerapi.exception.DockerException; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeAttributes; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeRepository; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeSpec; @@ -22,7 +16,12 @@ import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.NodeState; import com.yahoo.vespa.hosted.node.admin.configserver.noderepository.OrchestratorStatus; import com.yahoo.vespa.hosted.node.admin.configserver.orchestrator.Orchestrator; import com.yahoo.vespa.hosted.node.admin.configserver.orchestrator.OrchestratorException; +import com.yahoo.vespa.hosted.node.admin.container.Container; +import com.yahoo.vespa.hosted.node.admin.container.ContainerId; +import com.yahoo.vespa.hosted.node.admin.container.ContainerName; import com.yahoo.vespa.hosted.node.admin.container.ContainerOperations; +import com.yahoo.vespa.hosted.node.admin.container.ContainerResources; +import com.yahoo.vespa.hosted.node.admin.container.RegistryCredentials; 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.maintenance.identity.CredentialsMaintainer; @@ -556,12 +555,12 @@ public class NodeAgentImplTest { NodeAgentImpl nodeAgent = spy(makeNodeAgent(null, false)); when(containerOperations.pullImageAsyncIfNeeded(any(), eq(dockerImage), any())).thenReturn(false); - doThrow(new DockerException("Failed to set up network")).doNothing().when(containerOperations).startContainer(eq(context)); + doThrow(new RuntimeException("Failed to set up network")).doNothing().when(containerOperations).startContainer(eq(context)); try { nodeAgent.doConverge(context); - fail("Expected to get DockerException"); - } catch (DockerException ignored) { } + fail("Expected to get RuntimeException"); + } catch (RuntimeException ignored) { } verify(containerOperations, never()).removeContainer(eq(context), any()); verify(containerOperations, times(1)).createContainer(eq(context), any(), any()); -- cgit v1.2.3