Update static nodes in Zookeeper on config change
Config changes of existing nodes were not updated in Zookeeper, leading to inconsistent states. Changing a label or connection related attributes is now reflected without the workaround of first removing and re-adding the node. Change-Id: Ia6278512c2e81a720a957fe269d1ae0522860b8f
This commit is contained in:
parent
ef6be899b6
commit
d4485fbad0
@ -122,6 +122,52 @@ class StaticNodeProvider(Provider):
|
|||||||
self.zk.storeNode(node)
|
self.zk.storeNode(node)
|
||||||
self.log.debug("Registered static node %s", node.hostname)
|
self.log.debug("Registered static node %s", node.hostname)
|
||||||
|
|
||||||
|
def updateNodeFromConfig(self, static_node):
|
||||||
|
'''
|
||||||
|
Update a static node in ZooKeeper according to config.
|
||||||
|
|
||||||
|
The node is only updated if one of the relevant config items
|
||||||
|
changed. Name changes of nodes are handled via the
|
||||||
|
register/deregister flow.
|
||||||
|
|
||||||
|
:param dict static_node: The node definition from the config file.
|
||||||
|
'''
|
||||||
|
host_keys = self.checkHost(static_node)
|
||||||
|
nodes = self.getRegisteredReadyNodes(static_node["name"])
|
||||||
|
new_attrs = (
|
||||||
|
static_node["labels"],
|
||||||
|
static_node["username"],
|
||||||
|
static_node["connection-port"],
|
||||||
|
static_node["connection-type"],
|
||||||
|
host_keys,
|
||||||
|
)
|
||||||
|
|
||||||
|
for node in nodes:
|
||||||
|
original_attrs = (node.type, node.username, node.connection_port,
|
||||||
|
node.connection_type, node.host_keys)
|
||||||
|
|
||||||
|
if original_attrs == new_attrs:
|
||||||
|
continue
|
||||||
|
|
||||||
|
node.type = static_node["labels"]
|
||||||
|
node.username = static_node["username"]
|
||||||
|
node.connection_port = static_node["connection-port"]
|
||||||
|
node.connection_type = static_node["connection-type"]
|
||||||
|
nodeutils.set_node_ip(node)
|
||||||
|
node.host_keys = host_keys
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.zk.lockNode(node, blocking=False)
|
||||||
|
except exceptions.ZKLockException:
|
||||||
|
self.log.warning("Unable to lock node %s for update", node.id)
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.zk.storeNode(node)
|
||||||
|
self.log.debug("Updated static node %s", node.hostname)
|
||||||
|
finally:
|
||||||
|
self.zk.unlockNode(node)
|
||||||
|
|
||||||
def deregisterNode(self, count, node_name):
|
def deregisterNode(self, count, node_name):
|
||||||
'''
|
'''
|
||||||
Attempt to delete READY nodes.
|
Attempt to delete READY nodes.
|
||||||
@ -192,6 +238,12 @@ class StaticNodeProvider(Provider):
|
|||||||
self.log.exception("Couldn't deregister static node:")
|
self.log.exception("Couldn't deregister static node:")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.updateNodeFromConfig(node)
|
||||||
|
except Exception:
|
||||||
|
self.log.exception("Couldn't update static node:")
|
||||||
|
continue
|
||||||
|
|
||||||
self.static_nodes[node["name"]] = node
|
self.static_nodes[node["name"]] = node
|
||||||
|
|
||||||
# De-register nodes to synchronize with our configuration.
|
# De-register nodes to synchronize with our configuration.
|
||||||
|
23
nodepool/tests/fixtures/static-update.yaml
vendored
Normal file
23
nodepool/tests/fixtures/static-update.yaml
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
zookeeper-servers:
|
||||||
|
- host: {zookeeper_host}
|
||||||
|
port: {zookeeper_port}
|
||||||
|
chroot: {zookeeper_chroot}
|
||||||
|
|
||||||
|
labels:
|
||||||
|
- name: fake-label
|
||||||
|
- name: fake-label2
|
||||||
|
|
||||||
|
providers:
|
||||||
|
- name: static-provider
|
||||||
|
driver: static
|
||||||
|
pools:
|
||||||
|
- name: main
|
||||||
|
nodes:
|
||||||
|
- name: fake-host-1
|
||||||
|
labels:
|
||||||
|
- fake-label
|
||||||
|
- fake-label2
|
||||||
|
timeout: 13
|
||||||
|
connection-type: winrm
|
||||||
|
connection-port: 5986
|
||||||
|
username: admin
|
@ -155,6 +155,29 @@ class TestDriverStatic(tests.DBTestCase):
|
|||||||
nodes = self.waitForNodes('fake-label')
|
nodes = self.waitForNodes('fake-label')
|
||||||
self.assertEqual(len(nodes), 1)
|
self.assertEqual(len(nodes), 1)
|
||||||
|
|
||||||
|
def test_static_node_update(self):
|
||||||
|
'''
|
||||||
|
Test that updates a static node on config change.
|
||||||
|
'''
|
||||||
|
configfile = self.setup_config('static-basic.yaml')
|
||||||
|
pool = self.useNodepool(configfile, watermark_sleep=1)
|
||||||
|
pool.start()
|
||||||
|
|
||||||
|
self.log.debug("Waiting for initial node")
|
||||||
|
nodes = self.waitForNodes('fake-label')
|
||||||
|
self.assertEqual(len(nodes), 1)
|
||||||
|
|
||||||
|
self.log.debug("Waiting for new label")
|
||||||
|
self.replace_config(configfile, 'static-update.yaml')
|
||||||
|
nodes = self.waitForNodes('fake-label2')
|
||||||
|
self.assertEqual(len(nodes), 1)
|
||||||
|
self.assertIn('fake-label', nodes[0].type)
|
||||||
|
self.assertIn('fake-label2', nodes[0].type)
|
||||||
|
self.assertEqual(nodes[0].username, 'admin')
|
||||||
|
self.assertEqual(nodes[0].connection_port, 5986)
|
||||||
|
self.assertEqual(nodes[0].connection_type, 'winrm')
|
||||||
|
self.assertEqual(nodes[0].host_keys, None)
|
||||||
|
|
||||||
def test_static_multilabel(self):
|
def test_static_multilabel(self):
|
||||||
configfile = self.setup_config('static-multilabel.yaml')
|
configfile = self.setup_config('static-multilabel.yaml')
|
||||||
pool = self.useNodepool(configfile, watermark_sleep=1)
|
pool = self.useNodepool(configfile, watermark_sleep=1)
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
The static driver now updates labels and connection related attributes
|
||||||
|
in Zookeeper at startup and on config change. Changing the name of a node
|
||||||
|
will be handled via the registration/deregistration flow as before.
|
Loading…
Reference in New Issue
Block a user