diff options
Diffstat (limited to 'node-repository/src')
4 files changed, 123 insertions, 0 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java index 7b191538ad8..7b0606b809b 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java @@ -38,6 +38,7 @@ public class NodeRepositoryMaintenance extends AbstractComponent { private final NodeFailer nodeFailer; private final PeriodicApplicationMaintainer periodicApplicationMaintainer; private final OperatorChangeApplicationMaintainer operatorChangeApplicationMaintainer; + private final ZooKeeperAccessMaintainer zooKeeperAccessMaintainer; private final ReservationExpirer reservationExpirer; private final InactiveExpirer inactiveExpirer; private final RetiredExpirer retiredExpirer; @@ -69,6 +70,7 @@ public class NodeRepositoryMaintenance extends AbstractComponent { nodeFailer = new NodeFailer(deployer, hostLivenessTracker, serviceMonitor, nodeRepository, durationFromEnv("fail_grace").orElse(defaults.failGrace), clock, orchestrator, throttlePolicyFromEnv("throttle_policy").orElse(defaults.throttlePolicy), metric, jobControl, configserverConfig); periodicApplicationMaintainer = new PeriodicApplicationMaintainer(deployer, nodeRepository, durationFromEnv("periodic_redeploy_interval").orElse(defaults.periodicRedeployInterval), jobControl); operatorChangeApplicationMaintainer = new OperatorChangeApplicationMaintainer(deployer, nodeRepository, clock, durationFromEnv("operator_change_redeploy_interval").orElse(defaults.operatorChangeRedeployInterval), jobControl); + zooKeeperAccessMaintainer = new ZooKeeperAccessMaintainer(nodeRepository, curator, durationFromEnv("zookeeper_access_maintenance_interval").orElse(defaults.zooKeeperAccessMaintenanceInterval), jobControl); reservationExpirer = new ReservationExpirer(nodeRepository, clock, durationFromEnv("reservation_expiry").orElse(defaults.reservationExpiry), jobControl); retiredExpirer = new RetiredExpirer(nodeRepository, orchestrator, deployer, clock, durationFromEnv("retired_interval").orElse(defaults.retiredInterval), durationFromEnv("retired_expiry").orElse(defaults.retiredExpiry), jobControl); inactiveExpirer = new InactiveExpirer(nodeRepository, clock, durationFromEnv("inactive_expiry").orElse(defaults.inactiveExpiry), jobControl); @@ -89,6 +91,7 @@ public class NodeRepositoryMaintenance extends AbstractComponent { nodeFailer.deconstruct(); periodicApplicationMaintainer.deconstruct(); operatorChangeApplicationMaintainer.deconstruct(); + zooKeeperAccessMaintainer.deconstruct(); reservationExpirer.deconstruct(); inactiveExpirer.deconstruct(); retiredExpirer.deconstruct(); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ZooKeeperAccessMaintainer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ZooKeeperAccessMaintainer.java new file mode 100644 index 00000000000..b392d670a77 --- /dev/null +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/ZooKeeperAccessMaintainer.java @@ -0,0 +1,49 @@ +// 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.provision.maintenance; + +import com.yahoo.vespa.curator.Curator; +import com.yahoo.vespa.hosted.provision.Node; +import com.yahoo.vespa.hosted.provision.NodeRepository; +import com.yahoo.vespa.zookeeper.ZooKeeperServer; + +import java.time.Duration; +import java.util.HashSet; +import java.util.Set; + +/** + * Maintains the list of hosts that should be allowed to access ZooKeeper in this runtime. + * These are the zookeeper servers and all nodes in node repository. This is maintained in the background + * because nodes could be added or removed on another server. + * + * We could limit access to the <i>active</i> subset of nodes, but that + * does not seem to have any particular operational or security benefits and might make it more problematic + * for this job to be behind actual changes to the active set of nodes. + * + * @author bratseth + */ +public class ZooKeeperAccessMaintainer extends Maintainer { + + private final Curator curator; + + public ZooKeeperAccessMaintainer(NodeRepository nodeRepository, Curator curator, Duration maintenanceInterval, + JobControl jobControl) { + super(nodeRepository, maintenanceInterval, jobControl); + this.curator = curator; + } + + @Override + protected void maintain() { + Set<String> hosts = new HashSet<>(); + + for (Node node : nodeRepository().getNodes()) + hosts.add(node.hostname()); + + if ( ! hosts.isEmpty()) { // no nodes -> not a hosted instance: Pass an empty list to deactivate restriction + for (String hostPort : curator.zooKeeperEnsembleConnectionSpec().split(",")) + hosts.add(hostPort.split(":")[0]); + } + + ZooKeeperServer.setAllowedClientHostnames(hosts); + } + +} diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ZooKeeperAccessMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ZooKeeperAccessMaintainerTest.java new file mode 100644 index 00000000000..93cf19f5450 --- /dev/null +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ZooKeeperAccessMaintainerTest.java @@ -0,0 +1,68 @@ +// 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.provision.maintenance; + +import com.yahoo.config.provision.NodeType; +import com.yahoo.vespa.hosted.provision.NodeRepositoryTester; +import com.yahoo.vespa.hosted.provision.node.Agent; +import com.yahoo.vespa.zookeeper.ZooKeeperServer; +import org.junit.Test; + +import java.time.Duration; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author bratseth + */ +public class ZooKeeperAccessMaintainerTest { + + @Test + public void test() { + NodeRepositoryTester tester = new NodeRepositoryTester(); + tester.curator().setZooKeeperEnsembleConnectionSpec("server1:1234,server2:5678"); + ZooKeeperAccessMaintainer maintainer = new ZooKeeperAccessMaintainer(tester.nodeRepository(), + tester.curator(), Duration.ofHours(1), new JobControl(tester.nodeRepository().database())); + assertTrue(ZooKeeperServer.getAllowedClientHostnames().isEmpty()); + maintainer.maintain(); + assertTrue("We don't restrict to only config servers", ZooKeeperServer.getAllowedClientHostnames().isEmpty()); + + tester.addNode("id1", "host1", "default", NodeType.tenant); + tester.addNode("id2", "host2", "default", NodeType.tenant); + tester.addNode("id3", "host3", "default", NodeType.tenant); + maintainer.maintain(); + + assertEquals(3, tester.getNodes(NodeType.tenant).size()); + assertEquals(0, tester.getNodes(NodeType.proxy).size()); + assertEquals(asSet("host1,host2,host3,server1,server2"), ZooKeeperServer.getAllowedClientHostnames()); + + tester.addNode("proxy1", "host4", "default", NodeType.proxy); + tester.addNode("proxy2", "host5", "default", NodeType.proxy); + maintainer.maintain(); + + assertEquals(3, tester.getNodes(NodeType.tenant).size()); + assertEquals(2, tester.getNodes(NodeType.proxy).size()); + assertEquals(asSet("host1,host2,host3,host4,host5,server1,server2"), ZooKeeperServer.getAllowedClientHostnames()); + + tester.nodeRepository().park("host2", Agent.system, "Parking to unit test"); + tester.nodeRepository().removeRecursively("host2"); + maintainer.maintain(); + + assertEquals(2, tester.getNodes(NodeType.tenant).size()); + assertEquals(2, tester.getNodes(NodeType.proxy).size()); + assertEquals(asSet("host1,host3,host4,host5,server1,server2"), ZooKeeperServer.getAllowedClientHostnames()); + + tester.addNode("docker-host-1", "host6", "default", NodeType.host); + tester.addNode("docker-host-2", "host7", "default", NodeType.host); + maintainer.maintain(); + assertEquals(asSet("host1,host3,host4,host5,host6,host7,server1,server2"), ZooKeeperServer.getAllowedClientHostnames()); + } + + private Set<String> asSet(String s) { + return new HashSet<>(Arrays.asList(s.split(","))); + } + +} diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/maintenance.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/maintenance.json index 28e28f9678e..979d846704e 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/maintenance.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/maintenance.json @@ -34,6 +34,9 @@ "name":"MetricsReporter" }, { + "name":"ZooKeeperAccessMaintainer" + }, + { "name":"NodeFailer" } ], |