summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Shrewsbury <shrewsbury.dave@gmail.com>2018-11-28 15:23:44 -0500
committerDavid Shrewsbury <shrewsbury.dave@gmail.com>2018-11-29 09:35:59 -0500
commit16325d5c4c5edd32a1467eaef6b3212cd51f3956 (patch)
tree356b2af7baed57c2f12cf8fd396c83259fead8dd
parentf13c736f52467a138238ace4c57fc68243abe12b (diff)
Add arbitrary node attributes config option
This config option, available under each provider pool section, can contain static key-value pairs that will be stored in ZooKeeper on each Node znode. This will allow us to pass along abitrary data from nodepool to any user of nodepool (specifically, zuul). Initially, this will be used to pass along zone information to zuul executors. Change-Id: I126d37a8c0a4f44dca59c11f76a583b9181ab653
Notes
Notes (review): Code-Review+2: Monty Taylor <mordred@inaugust.com> Code-Review+2: Tobias Henkel <tobias.henkel@bmw.de> Code-Review+2: James E. Blair <corvus@inaugust.com> Code-Review+2: Paul Belanger <pabelanger@redhat.com> Workflow+1: Paul Belanger <pabelanger@redhat.com> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Thu, 29 Nov 2018 20:14:31 +0000 Reviewed-on: https://review.openstack.org/620691 Project: openstack-infra/nodepool Branch: refs/heads/master
-rw-r--r--doc/source/configuration.rst9
-rw-r--r--nodepool/driver/__init__.py14
-rw-r--r--nodepool/driver/openstack/config.py2
-rw-r--r--nodepool/tests/fixtures/config_validate/good.yaml3
-rw-r--r--nodepool/tests/fixtures/node.yaml3
-rw-r--r--nodepool/tests/unit/test_launcher.py2
-rw-r--r--nodepool/tests/unit/test_zk.py4
-rwxr-xr-xnodepool/zk.py6
-rw-r--r--releasenotes/notes/node-metadata-e1e822b49464f51a.yaml7
9 files changed, 46 insertions, 4 deletions
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index aed6ae1..27abacf 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -700,6 +700,9 @@ Selecting the OpenStack driver adds the following options to the
700 - zuul-security-group 700 - zuul-security-group
701 auto-floating-ip: False 701 auto-floating-ip: False
702 host-key-checking: True 702 host-key-checking: True
703 node-attributes:
704 key1: value1
705 key2: value2
703 labels: 706 labels:
704 - name: trusty 707 - name: trusty
705 min-ram: 8192 708 min-ram: 8192
@@ -720,6 +723,12 @@ Selecting the OpenStack driver adds the following options to the
720 723
721 Pool name 724 Pool name
722 725
726 .. attr:: node-attributes
727 :type: dict
728
729 A dictionary of key-value pairs that will be stored with the node data
730 in ZooKeeper. The keys and values can be any arbitrary string.
731
723 .. attr:: max-cores 732 .. attr:: max-cores
724 :type: int 733 :type: int
725 734
diff --git a/nodepool/driver/__init__.py b/nodepool/driver/__init__.py
index 660833b..216bfe8 100644
--- a/nodepool/driver/__init__.py
+++ b/nodepool/driver/__init__.py
@@ -501,6 +501,10 @@ class NodeRequestHandler(NodeRequestHandlerNotifications,
501 node.launcher = self.launcher_id 501 node.launcher = self.launcher_id
502 node.allocated_to = self.request.id 502 node.allocated_to = self.request.id
503 503
504 # This sets static data defined in the config file in the
505 # ZooKeeper Node object.
506 node.attributes = self.pool.node_attributes
507
504 self.setNodeMetadata(node) 508 self.setNodeMetadata(node)
505 509
506 # Note: It should be safe (i.e., no race) to lock the node 510 # Note: It should be safe (i.e., no race) to lock the node
@@ -756,8 +760,10 @@ class NodeRequestHandler(NodeRequestHandlerNotifications,
756 760
757 def setNodeMetadata(self, node): 761 def setNodeMetadata(self, node):
758 ''' 762 '''
759 Handler may implement this to store metadata before building the node. 763 Handler may implement this to store driver-specific metadata in the
760 The OpenStack handler uses this to set az, cloud and region. 764 Node object before building the node. This data is normally dynamically
765 calculated during runtime. The OpenStack handler uses this to set az,
766 cloud and region.
761 ''' 767 '''
762 pass 768 pass
763 769
@@ -822,11 +828,13 @@ class ConfigPool(ConfigValue):
822 def __init__(self): 828 def __init__(self):
823 self.labels = {} 829 self.labels = {}
824 self.max_servers = math.inf 830 self.max_servers = math.inf
831 self.node_attributes = None
825 832
826 def __eq__(self, other): 833 def __eq__(self, other):
827 if isinstance(other, ConfigPool): 834 if isinstance(other, ConfigPool):
828 return (self.labels == other.labels and 835 return (self.labels == other.labels and
829 self.max_servers == other.max_servers) 836 self.max_servers == other.max_servers and
837 self.node_attributes == other.node_attributes)
830 return False 838 return False
831 839
832 840
diff --git a/nodepool/driver/openstack/config.py b/nodepool/driver/openstack/config.py
index 32c1454..ea680c1 100644
--- a/nodepool/driver/openstack/config.py
+++ b/nodepool/driver/openstack/config.py
@@ -275,6 +275,7 @@ class OpenStackProviderConfig(ProviderConfig):
275 pp.security_groups = pool.get('security-groups', []) 275 pp.security_groups = pool.get('security-groups', [])
276 pp.auto_floating_ip = bool(pool.get('auto-floating-ip', True)) 276 pp.auto_floating_ip = bool(pool.get('auto-floating-ip', True))
277 pp.host_key_checking = bool(pool.get('host-key-checking', True)) 277 pp.host_key_checking = bool(pool.get('host-key-checking', True))
278 pp.node_attributes = pool.get('node-attributes')
278 279
279 for label in pool.get('labels', []): 280 for label in pool.get('labels', []):
280 pl = ProviderLabel() 281 pl = ProviderLabel()
@@ -367,6 +368,7 @@ class OpenStackProviderConfig(ProviderConfig):
367 'max-servers': int, 368 'max-servers': int,
368 'max-ram': int, 369 'max-ram': int,
369 'labels': [pool_label], 370 'labels': [pool_label],
371 'node-attributes': dict,
370 'availability-zones': [str], 372 'availability-zones': [str],
371 'security-groups': [str] 373 'security-groups': [str]
372 } 374 }
diff --git a/nodepool/tests/fixtures/config_validate/good.yaml b/nodepool/tests/fixtures/config_validate/good.yaml
index 372641c..db7d1ec 100644
--- a/nodepool/tests/fixtures/config_validate/good.yaml
+++ b/nodepool/tests/fixtures/config_validate/good.yaml
@@ -38,6 +38,9 @@ providers:
38 max-servers: 184 38 max-servers: 184
39 auto-floating-ip: True 39 auto-floating-ip: True
40 host-key-checking: True 40 host-key-checking: True
41 node-attributes:
42 key1: value1
43 key2: value2
41 labels: 44 labels:
42 - name: trusty 45 - name: trusty
43 diskimage: trusty 46 diskimage: trusty
diff --git a/nodepool/tests/fixtures/node.yaml b/nodepool/tests/fixtures/node.yaml
index 4568267..1e65f16 100644
--- a/nodepool/tests/fixtures/node.yaml
+++ b/nodepool/tests/fixtures/node.yaml
@@ -26,6 +26,9 @@ providers:
26 pools: 26 pools:
27 - name: main 27 - name: main
28 max-servers: 96 28 max-servers: 96
29 node-attributes:
30 key1: value1
31 key2: value2
29 availability-zones: 32 availability-zones:
30 - az1 33 - az1
31 networks: 34 networks:
diff --git a/nodepool/tests/unit/test_launcher.py b/nodepool/tests/unit/test_launcher.py
index b59732a..07934e2 100644
--- a/nodepool/tests/unit/test_launcher.py
+++ b/nodepool/tests/unit/test_launcher.py
@@ -488,6 +488,8 @@ class TestLauncher(tests.DBTestCase):
488 self.assertEqual(nodes[0].type, ['fake-label']) 488 self.assertEqual(nodes[0].type, ['fake-label'])
489 self.assertEqual(nodes[0].username, 'zuul') 489 self.assertEqual(nodes[0].username, 'zuul')
490 self.assertNotEqual(nodes[0].host_keys, []) 490 self.assertNotEqual(nodes[0].host_keys, [])
491 self.assertEqual(nodes[0].attributes,
492 {'key1': 'value1', 'key2': 'value2'})
491 493
492 def test_node_host_key_checking_false(self): 494 def test_node_host_key_checking_false(self):
493 """Test that an image and node are created""" 495 """Test that an image and node are created"""
diff --git a/nodepool/tests/unit/test_zk.py b/nodepool/tests/unit/test_zk.py
index 8f1dca5..401196a 100644
--- a/nodepool/tests/unit/test_zk.py
+++ b/nodepool/tests/unit/test_zk.py
@@ -862,6 +862,7 @@ class TestZKModel(tests.BaseTestCase):
862 o.comment = 'comment' 862 o.comment = 'comment'
863 o.hold_job = 'hold job' 863 o.hold_job = 'hold job'
864 o.host_keys = ['key1', 'key2'] 864 o.host_keys = ['key1', 'key2']
865 o.attributes = {'executor-zone': 'vpn'}
865 866
866 d = o.toDict() 867 d = o.toDict()
867 self.assertNotIn('id', d) 868 self.assertNotIn('id', d)
@@ -883,6 +884,7 @@ class TestZKModel(tests.BaseTestCase):
883 self.assertEqual(d['comment'], o.comment) 884 self.assertEqual(d['comment'], o.comment)
884 self.assertEqual(d['hold_job'], o.hold_job) 885 self.assertEqual(d['hold_job'], o.hold_job)
885 self.assertEqual(d['host_keys'], o.host_keys) 886 self.assertEqual(d['host_keys'], o.host_keys)
887 self.assertEqual(d['attributes'], o.attributes)
886 888
887 def test_Node_fromDict(self): 889 def test_Node_fromDict(self):
888 now = int(time.time()) 890 now = int(time.time())
@@ -907,6 +909,7 @@ class TestZKModel(tests.BaseTestCase):
907 'hold_job': 'hold job', 909 'hold_job': 'hold job',
908 'host_keys': ['key1', 'key2'], 910 'host_keys': ['key1', 'key2'],
909 'connection_port': 22022, 911 'connection_port': 22022,
912 'attributes': {'executor-zone': 'vpn'},
910 } 913 }
911 914
912 o = zk.Node.fromDict(d, node_id) 915 o = zk.Node.fromDict(d, node_id)
@@ -930,6 +933,7 @@ class TestZKModel(tests.BaseTestCase):
930 self.assertEqual(o.hold_job, d['hold_job']) 933 self.assertEqual(o.hold_job, d['hold_job'])
931 self.assertEqual(o.host_keys, d['host_keys']) 934 self.assertEqual(o.host_keys, d['host_keys'])
932 self.assertEqual(o.connection_port, d['connection_port']) 935 self.assertEqual(o.connection_port, d['connection_port'])
936 self.assertEqual(o.attributes, d['attributes'])
933 937
934 def test_custom_connection_port(self): 938 def test_custom_connection_port(self):
935 n = zk.Node('0001') 939 n = zk.Node('0001')
diff --git a/nodepool/zk.py b/nodepool/zk.py
index 5e84dcb..5f1010e 100755
--- a/nodepool/zk.py
+++ b/nodepool/zk.py
@@ -517,6 +517,7 @@ class Node(BaseModel):
517 self.host_keys = [] 517 self.host_keys = []
518 self.hold_expiration = None 518 self.hold_expiration = None
519 self.resources = None 519 self.resources = None
520 self.attributes = None
520 521
521 def __repr__(self): 522 def __repr__(self):
522 d = self.toDict() 523 d = self.toDict()
@@ -552,7 +553,8 @@ class Node(BaseModel):
552 self.connection_port == other.connection_port and 553 self.connection_port == other.connection_port and
553 self.host_keys == other.host_keys and 554 self.host_keys == other.host_keys and
554 self.hold_expiration == other.hold_expiration and 555 self.hold_expiration == other.hold_expiration and
555 self.resources == other.resources) 556 self.resources == other.resources and
557 self.attributes == other.attributes)
556 else: 558 else:
557 return False 559 return False
558 560
@@ -599,6 +601,7 @@ class Node(BaseModel):
599 d['connection_port'] = self.connection_port 601 d['connection_port'] = self.connection_port
600 d['hold_expiration'] = self.hold_expiration 602 d['hold_expiration'] = self.hold_expiration
601 d['resources'] = self.resources 603 d['resources'] = self.resources
604 d['attributes'] = self.attributes
602 return d 605 return d
603 606
604 @staticmethod 607 @staticmethod
@@ -660,6 +663,7 @@ class Node(BaseModel):
660 else: 663 else:
661 self.hold_expiration = hold_expiration 664 self.hold_expiration = hold_expiration
662 self.resources = d.get('resources') 665 self.resources = d.get('resources')
666 self.attributes = d.get('attributes')
663 667
664 668
665class ZooKeeper(object): 669class ZooKeeper(object):
diff --git a/releasenotes/notes/node-metadata-e1e822b49464f51a.yaml b/releasenotes/notes/node-metadata-e1e822b49464f51a.yaml
new file mode 100644
index 0000000..3d467f9
--- /dev/null
+++ b/releasenotes/notes/node-metadata-e1e822b49464f51a.yaml
@@ -0,0 +1,7 @@
1---
2features:
3 - |
4 A new configuration option is available under the 'pools' attribute
5 of an OpenStack provider. This config value, 'node-attributes', can contain
6 a dictionary of arbitrary key-value pairs and will be stored with the
7 node data within ZooKeeper.