summaryrefslogtreecommitdiffstats
path: root/node-repository/src/main/java
diff options
context:
space:
mode:
authorgjoranv <gjoranv@gmail.com>2022-11-17 11:35:41 +0100
committerGitHub <noreply@github.com>2022-11-17 11:35:41 +0100
commit684b47c7f1f32d92d4d909fe0596c312219afd89 (patch)
treec7d34e6327de10eaa97beef13809a2f38ed38c8e /node-repository/src/main/java
parente6309e8836b834016b565797840c21595b322c35 (diff)
parent1a5a45828f609e59b6aa247e8f61d3f271f6fc8d (diff)
Merge pull request #24902 from vespa-engine/enclaves-api
Enclaves api
Diffstat (limited to 'node-repository/src/main/java')
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/filter/CloudAccountFilter.java29
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java8
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java12
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java71
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java45
5 files changed, 117 insertions, 48 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/filter/CloudAccountFilter.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/filter/CloudAccountFilter.java
new file mode 100644
index 00000000000..c7a4f50ab7c
--- /dev/null
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/filter/CloudAccountFilter.java
@@ -0,0 +1,29 @@
+package com.yahoo.vespa.hosted.provision.node.filter;
+
+import com.yahoo.config.provision.CloudAccount;
+import com.yahoo.vespa.hosted.provision.Node;
+
+import java.util.Collection;
+import java.util.Objects;
+import java.util.function.Predicate;
+
+/**
+ * Filters nodes based on their cloud account.
+ *
+ * @author gjoranv
+ */
+public class CloudAccountFilter {
+
+ private CloudAccountFilter() { }
+
+ /** Creates a node filter which removes the nodes from the given cloud accounts */
+ public static Predicate<Node> from(Collection<CloudAccount> unwantedAccounts, boolean enabled) {
+ Objects.requireNonNull(unwantedAccounts, "unwantedAccounts cannot be null");
+ return node -> {
+ if (unwantedAccounts.isEmpty()) return true;
+ if (! enabled) return true;
+ return ! unwantedAccounts.contains(node.cloudAccount());
+ };
+ }
+
+}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java
index e8410c6ec12..942f029bc6a 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesResponse.java
@@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.provision.restapi;
import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.DockerImage;
import com.yahoo.config.provision.NodeResources;
@@ -27,8 +28,10 @@ import com.yahoo.vespa.orchestrator.status.HostInfo;
import com.yahoo.vespa.orchestrator.status.HostStatus;
import java.net.URI;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
+import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -58,12 +61,15 @@ class NodesResponse extends SlimeJsonResponse {
Orchestrator orchestrator, NodeRepository nodeRepository) {
this.parentUrl = toParentUrl(request);
this.nodeParentUrl = toNodeParentUrl(request);
- this.filter = NodesV2ApiHandler.toNodeFilter(request);
this.recursive = request.getBooleanProperty("recursive");
this.orchestrator = orchestrator.getHostResolver();
this.nodeRepository = nodeRepository;
this.wantedDockerTagFlag = PermanentFlags.WANTED_DOCKER_TAG.bindTo(nodeRepository.flagSource());
+ // Cannot use Set.of() because the nodeRepository account can also be the empty account (at least in tests).
+ var nonEnclaveAccounts = new HashSet<>(Arrays.asList(CloudAccount.empty, nodeRepository.zone().cloud().account()));
+ this.filter = NodesV2ApiHandler.toNodeFilter(request, nonEnclaveAccounts);
+
Cursor root = slime.setObject();
switch (responseType) {
case nodeList -> nodesToSlime(filter.states(), root);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java
index f6637b60695..a3acb9b95d8 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java
@@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.provision.restapi;
import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ApplicationLockException;
+import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.Flavor;
import com.yahoo.config.provision.HostFilter;
import com.yahoo.config.provision.NodeFlavors;
@@ -36,6 +37,7 @@ import com.yahoo.vespa.hosted.provision.node.Address;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.IP;
import com.yahoo.vespa.hosted.provision.node.filter.ApplicationFilter;
+import com.yahoo.vespa.hosted.provision.node.filter.CloudAccountFilter;
import com.yahoo.vespa.hosted.provision.node.filter.NodeFilter;
import com.yahoo.vespa.hosted.provision.node.filter.NodeHostFilter;
import com.yahoo.vespa.hosted.provision.node.filter.NodeOsVersionFilter;
@@ -51,6 +53,7 @@ import java.io.UncheckedIOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
@@ -73,6 +76,7 @@ public class NodesV2ApiHandler extends ThreadedHttpRequestHandler {
private final NodeRepository nodeRepository;
private final MetricsDb metricsDb;
private final NodeFlavors nodeFlavors;
+ private final CloudAccount cloudAccount;
@Inject
public NodesV2ApiHandler(ThreadedHttpRequestHandler.Context parentCtx, Orchestrator orchestrator,
@@ -82,6 +86,7 @@ public class NodesV2ApiHandler extends ThreadedHttpRequestHandler {
this.nodeRepository = nodeRepository;
this.metricsDb = metricsDb;
this.nodeFlavors = flavors;
+ this.cloudAccount = nodeRepository.zone().cloud().account();
}
@Override
@@ -329,6 +334,10 @@ public class NodesV2ApiHandler extends ThreadedHttpRequestHandler {
}
public static NodeFilter toNodeFilter(HttpRequest request) {
+ return toNodeFilter(request, Set.of());
+ }
+
+ public static NodeFilter toNodeFilter(HttpRequest request, Collection<CloudAccount> nonEnclaveAccounts) {
return NodeFilter.in(request.getProperty("state"),
request.getBooleanProperty("includeDeprovisioned"))
.matching(NodeHostFilter.from(HostFilter.from(request.getProperty("hostname"),
@@ -338,7 +347,8 @@ public class NodesV2ApiHandler extends ThreadedHttpRequestHandler {
.and(ApplicationFilter.from(request.getProperty("application")))
.and(NodeTypeFilter.from(request.getProperty("type")))
.and(ParentHostFilter.from(request.getProperty("parentHost")))
- .and(NodeOsVersionFilter.from(request.getProperty("osVersion"))));
+ .and(NodeOsVersionFilter.from(request.getProperty("osVersion")))
+ .and(CloudAccountFilter.from(nonEnclaveAccounts, request.getBooleanProperty("enclave"))));
}
private static boolean isPatchOverride(HttpRequest request) {
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java
index 024f071abb1..f0f85b6523f 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java
@@ -1,6 +1,8 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.testutils;
+import com.yahoo.config.provision.CloudAccount;
+
/**
* For running NodeRepository API with some mocked data.
* This is used by both NodeAdmin and NodeRepository tests.
@@ -9,38 +11,43 @@ package com.yahoo.vespa.hosted.provision.testutils;
*/
public class ContainerConfig {
- public static String servicesXmlV2(int port) {
- return "<container version='1.0'>\n" +
- " <config name=\"container.handler.threadpool\">\n" +
- " <maxthreads>20</maxthreads>\n" +
- " </config>\n" +
- " <accesslog type='disabled'/>\n" +
- " <component id='com.yahoo.test.ManualClock'/>\n" +
- " <component id='com.yahoo.vespa.curator.mock.MockCurator'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.OrchestratorMock'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.MockDeployer'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.MockInfraDeployer'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.MockProvisioner'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.ServiceMonitorStub'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.MockDuperModel'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.MockNodeFlavors'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.autoscale.QuestMetricsDb'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.MockMetricsFetcher'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.MockNodeRepository'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.MockProvisionServiceProvider'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.maintenance.NodeRepositoryMaintenance'/>\n" +
- " <component id='com.yahoo.vespa.flags.InMemoryFlagSource'/>\n" +
- " <component id='com.yahoo.config.provision.Zone'/>\n" +
- " <handler id='com.yahoo.vespa.hosted.provision.restapi.NodesV2ApiHandler'>\n" +
- " <binding>http://*/nodes/v2*</binding>\n" +
- " </handler>\n" +
- " <handler id='com.yahoo.vespa.hosted.provision.restapi.LoadBalancersV1ApiHandler'>\n" +
- " <binding>http://*/loadbalancers/v1*</binding>\n" +
- " </handler>\n" +
- " <http>\n" +
- " <server id='myServer' port='" + port + "'/>\n" +
- " </http>\n" +
- "</container>";
+ public static String servicesXmlV2(int port, CloudAccount cloudAccount) {
+ return """
+ <container version='1.0'>
+ <config name="container.handler.threadpool">
+ <maxthreads>20</maxthreads>
+ </config>
+ <config name="config.provisioning.cloud">
+ <account>%s</account>
+ </config>
+ <accesslog type='disabled'/>
+ <component id='com.yahoo.test.ManualClock'/>
+ <component id='com.yahoo.vespa.curator.mock.MockCurator'/>
+ <component id='com.yahoo.vespa.hosted.provision.testutils.OrchestratorMock'/>
+ <component id='com.yahoo.vespa.hosted.provision.testutils.MockDeployer'/>
+ <component id='com.yahoo.vespa.hosted.provision.testutils.MockInfraDeployer'/>
+ <component id='com.yahoo.vespa.hosted.provision.testutils.MockProvisioner'/>
+ <component id='com.yahoo.vespa.hosted.provision.testutils.ServiceMonitorStub'/>
+ <component id='com.yahoo.vespa.hosted.provision.testutils.MockDuperModel'/>
+ <component id='com.yahoo.vespa.hosted.provision.testutils.MockNodeFlavors'/>
+ <component id='com.yahoo.vespa.hosted.provision.autoscale.QuestMetricsDb'/>
+ <component id='com.yahoo.vespa.hosted.provision.testutils.MockMetricsFetcher'/>
+ <component id='com.yahoo.vespa.hosted.provision.testutils.MockNodeRepository'/>
+ <component id='com.yahoo.vespa.hosted.provision.testutils.MockProvisionServiceProvider'/>
+ <component id='com.yahoo.vespa.hosted.provision.maintenance.NodeRepositoryMaintenance'/>
+ <component id='com.yahoo.vespa.flags.InMemoryFlagSource'/>
+ <component id='com.yahoo.config.provision.Zone'/>
+ <handler id='com.yahoo.vespa.hosted.provision.restapi.NodesV2ApiHandler'>
+ <binding>http://*/nodes/v2*</binding>
+ </handler>
+ <handler id='com.yahoo.vespa.hosted.provision.restapi.LoadBalancersV1ApiHandler'>
+ <binding>http://*/loadbalancers/v1*</binding>
+ </handler>
+ <http>
+ <server id='myServer' port='%s'/>
+ </http>
+ </container>
+ """.formatted(cloudAccount.value(), port);
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
index dccfa830a8d..a19e48cfa6b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
@@ -7,6 +7,7 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ApplicationName;
import com.yahoo.config.provision.ApplicationTransaction;
import com.yahoo.config.provision.Capacity;
+import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.DockerImage;
@@ -34,6 +35,7 @@ import com.yahoo.vespa.hosted.provision.node.Status;
import com.yahoo.vespa.hosted.provision.provisioning.EmptyProvisionServiceProvider;
import com.yahoo.vespa.hosted.provision.provisioning.NodeRepositoryProvisioner;
+import javax.inject.Inject;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
@@ -56,20 +58,23 @@ import static com.yahoo.config.provision.NodeResources.StorageType.remote;
* Instantiated by DI.
*/
public class MockNodeRepository extends NodeRepository {
+ public static final CloudAccount tenantAccount = CloudAccount.from("777888999000");
private final NodeFlavors flavors;
+ private final CloudAccount defaultCloudAccount;
/**
* Constructor
*
* @param flavors flavors to have in node repo
*/
- public MockNodeRepository(MockCurator curator, NodeFlavors flavors) {
+ @Inject
+ public MockNodeRepository(MockCurator curator, NodeFlavors flavors, Zone zone) {
super(flavors,
new EmptyProvisionServiceProvider(),
curator,
Clock.fixed(Instant.ofEpochMilli(123), ZoneId.of("Z")),
- Zone.defaultZone(),
+ zone,
new MockNameResolver().mockAnyLookup(),
DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa"),
Optional.empty(),
@@ -79,6 +84,7 @@ public class MockNodeRepository extends NodeRepository {
true,
0, 1000);
this.flavors = flavors;
+ defaultCloudAccount = zone.cloud().account();
curator.setZooKeeperEnsembleConnectionSpec("cfg1:1234,cfg2:1234,cfg3:1234");
populate();
@@ -89,14 +95,19 @@ public class MockNodeRepository extends NodeRepository {
List<Node> nodes = new ArrayList<>();
// Regular nodes
- nodes.add(Node.create("node1", ipConfig(1), "host1.yahoo.com", resources(2, 8, 50, 1, fast, local), NodeType.tenant).build());
- nodes.add(Node.create("node2", ipConfig(2), "host2.yahoo.com", resources(2, 8, 50, 1, fast, local), NodeType.tenant).build());
- nodes.add(Node.create("node3", ipConfig(3), "host3.yahoo.com", resources(0.5, 48, 500, 1, fast, local), NodeType.tenant).build());
+ nodes.add(Node.create("node1", ipConfig(1), "host1.yahoo.com", resources(2, 8, 50, 1, fast, local), NodeType.tenant)
+ .cloudAccount(defaultCloudAccount).build());
+ nodes.add(Node.create("node2", ipConfig(2), "host2.yahoo.com", resources(2, 8, 50, 1, fast, local), NodeType.tenant)
+ .cloudAccount(defaultCloudAccount).build());
+ // Emulate node in tenant account
+ nodes.add(Node.create("node3", ipConfig(3), "host3.yahoo.com", resources(0.5, 48, 500, 1, fast, local), NodeType.tenant)
+ .cloudAccount(tenantAccount).build());
Node node4 = Node.create("node4", ipConfig(4), "host4.yahoo.com", resources(1, 4, 100, 1, fast, local), NodeType.tenant)
.parentHostname("dockerhost1.yahoo.com")
.status(Status.initial()
.withVespaVersion(new Version("6.41.0"))
.withContainerImage(DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa:6.41.0")))
+ .cloudAccount(defaultCloudAccount)
.build();
nodes.add(node4);
@@ -105,12 +116,15 @@ public class MockNodeRepository extends NodeRepository {
.status(Status.initial()
.withVespaVersion(new Version("1.2.3"))
.withContainerImage(DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa:1.2.3")))
+ .cloudAccount(defaultCloudAccount)
.build();
nodes.add(node5);
- nodes.add(Node.create("node6", ipConfig(6), "host6.yahoo.com", resources(2, 8, 50, 1, fast, local), NodeType.tenant).build());
- Node node7 = Node.create("node7", ipConfig(7), "host7.yahoo.com", resources(2, 8, 50, 1, fast, local), NodeType.tenant).build();
+ nodes.add(Node.create("node6", ipConfig(6), "host6.yahoo.com", resources(2, 8, 50, 1, fast, local), NodeType.tenant)
+ .cloudAccount(defaultCloudAccount).build());
+ Node node7 = Node.create("node7", ipConfig(7), "host7.yahoo.com", resources(2, 8, 50, 1, fast, local), NodeType.tenant)
+ .cloudAccount(defaultCloudAccount).build();
nodes.add(node7);
// 8, 9, 11 and 12 are added by web service calls
@@ -119,26 +133,29 @@ public class MockNodeRepository extends NodeRepository {
.status(Status.initial()
.withVespaVersion(Version.fromString("5.104.142"))
.withContainerImage(DockerImage.fromString("docker-registry.domain.tld:8080/dist/vespa:5.104.142")))
+ .cloudAccount(defaultCloudAccount)
.build();
nodes.add(node10);
Node node55 = Node.create("node55", ipConfig(55), "host55.yahoo.com", resources(2, 8, 50, 1, fast, local), NodeType.tenant)
- .status(Status.initial().withWantToRetire(true, true, false)).build();
+ .status(Status.initial().withWantToRetire(true, true, false))
+ .cloudAccount(defaultCloudAccount).build();
nodes.add(node55);
/* Setup docker hosts (two of these will be reserved for spares */
nodes.add(Node.create("dockerhost1", ipConfig(100, 1, 3), "dockerhost1.yahoo.com",
- flavors.getFlavorOrThrow("large"), NodeType.host).build());
+ flavors.getFlavorOrThrow("large"), NodeType.host).cloudAccount(defaultCloudAccount).build());
+ // Emulate host in tenant account
nodes.add(Node.create("dockerhost2", ipConfig(101, 1, 3), "dockerhost2.yahoo.com",
- flavors.getFlavorOrThrow("large"), NodeType.host).build());
+ flavors.getFlavorOrThrow("large"), NodeType.host).cloudAccount(tenantAccount).build());
nodes.add(Node.create("dockerhost3", ipConfig(102, 1, 3), "dockerhost3.yahoo.com",
- flavors.getFlavorOrThrow("large"), NodeType.host).build());
+ flavors.getFlavorOrThrow("large"), NodeType.host).cloudAccount(defaultCloudAccount).build());
nodes.add(Node.create("dockerhost4", ipConfig(103, 1, 3), "dockerhost4.yahoo.com",
- flavors.getFlavorOrThrow("large"), NodeType.host).build());
+ flavors.getFlavorOrThrow("large"), NodeType.host).cloudAccount(defaultCloudAccount).build());
nodes.add(Node.create("dockerhost5", ipConfig(104, 1, 3), "dockerhost5.yahoo.com",
- flavors.getFlavorOrThrow("large"), NodeType.host).build());
+ flavors.getFlavorOrThrow("large"), NodeType.host).cloudAccount(defaultCloudAccount).build());
nodes.add(Node.create("dockerhost6", ipConfig(105, 1, 3), "dockerhost6.yahoo.com",
- flavors.getFlavorOrThrow("arm64"), NodeType.host).build());
+ flavors.getFlavorOrThrow("arm64"), NodeType.host).cloudAccount(defaultCloudAccount).build());
// Config servers
nodes.add(Node.create("cfg1", ipConfig(201), "cfg1.yahoo.com", flavors.getFlavorOrThrow("default"), NodeType.config).build());