Browse Source

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
tags/3.4.0
David Shrewsbury 5 months ago
parent
commit
16325d5c4c

+ 9
- 0
doc/source/configuration.rst View File

@@ -700,6 +700,9 @@ Selecting the OpenStack driver adds the following options to the
700 700
               - zuul-security-group
701 701
             auto-floating-ip: False
702 702
             host-key-checking: True
703
+            node-attributes:
704
+              key1: value1
705
+              key2: value2
703 706
             labels:
704 707
               - name: trusty
705 708
                 min-ram: 8192
@@ -720,6 +723,12 @@ Selecting the OpenStack driver adds the following options to the
720 723
 
721 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 732
      .. attr:: max-cores
724 733
         :type: int
725 734
 

+ 11
- 3
nodepool/driver/__init__.py View File

@@ -501,6 +501,10 @@ class NodeRequestHandler(NodeRequestHandlerNotifications,
501 501
                 node.launcher = self.launcher_id
502 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 508
                 self.setNodeMetadata(node)
505 509
 
506 510
                 # Note: It should be safe (i.e., no race) to lock the node
@@ -756,8 +760,10 @@ class NodeRequestHandler(NodeRequestHandlerNotifications,
756 760
 
757 761
     def setNodeMetadata(self, node):
758 762
         '''
759
-        Handler may implement this to store metadata before building the node.
760
-        The OpenStack handler uses this to set az, cloud and region.
763
+        Handler may implement this to store driver-specific metadata in the
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 768
         pass
763 769
 
@@ -822,11 +828,13 @@ class ConfigPool(ConfigValue):
822 828
     def __init__(self):
823 829
         self.labels = {}
824 830
         self.max_servers = math.inf
831
+        self.node_attributes = None
825 832
 
826 833
     def __eq__(self, other):
827 834
         if isinstance(other, ConfigPool):
828 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 838
         return False
831 839
 
832 840
 

+ 2
- 0
nodepool/driver/openstack/config.py View File

@@ -275,6 +275,7 @@ class OpenStackProviderConfig(ProviderConfig):
275 275
             pp.security_groups = pool.get('security-groups', [])
276 276
             pp.auto_floating_ip = bool(pool.get('auto-floating-ip', True))
277 277
             pp.host_key_checking = bool(pool.get('host-key-checking', True))
278
+            pp.node_attributes = pool.get('node-attributes')
278 279
 
279 280
             for label in pool.get('labels', []):
280 281
                 pl = ProviderLabel()
@@ -367,6 +368,7 @@ class OpenStackProviderConfig(ProviderConfig):
367 368
             'max-servers': int,
368 369
             'max-ram': int,
369 370
             'labels': [pool_label],
371
+            'node-attributes': dict,
370 372
             'availability-zones': [str],
371 373
             'security-groups': [str]
372 374
         }

+ 3
- 0
nodepool/tests/fixtures/config_validate/good.yaml View File

@@ -38,6 +38,9 @@ providers:
38 38
         max-servers: 184
39 39
         auto-floating-ip: True
40 40
         host-key-checking: True
41
+        node-attributes:
42
+          key1: value1
43
+          key2: value2
41 44
         labels:
42 45
           - name: trusty
43 46
             diskimage: trusty

+ 3
- 0
nodepool/tests/fixtures/node.yaml View File

@@ -26,6 +26,9 @@ providers:
26 26
     pools:
27 27
       - name: main
28 28
         max-servers: 96
29
+        node-attributes:
30
+          key1: value1
31
+          key2: value2
29 32
         availability-zones:
30 33
           - az1
31 34
         networks:

+ 2
- 0
nodepool/tests/unit/test_launcher.py View File

@@ -488,6 +488,8 @@ class TestLauncher(tests.DBTestCase):
488 488
         self.assertEqual(nodes[0].type, ['fake-label'])
489 489
         self.assertEqual(nodes[0].username, 'zuul')
490 490
         self.assertNotEqual(nodes[0].host_keys, [])
491
+        self.assertEqual(nodes[0].attributes,
492
+                         {'key1': 'value1', 'key2': 'value2'})
491 493
 
492 494
     def test_node_host_key_checking_false(self):
493 495
         """Test that an image and node are created"""

+ 4
- 0
nodepool/tests/unit/test_zk.py View File

@@ -862,6 +862,7 @@ class TestZKModel(tests.BaseTestCase):
862 862
         o.comment = 'comment'
863 863
         o.hold_job = 'hold job'
864 864
         o.host_keys = ['key1', 'key2']
865
+        o.attributes = {'executor-zone': 'vpn'}
865 866
 
866 867
         d = o.toDict()
867 868
         self.assertNotIn('id', d)
@@ -883,6 +884,7 @@ class TestZKModel(tests.BaseTestCase):
883 884
         self.assertEqual(d['comment'], o.comment)
884 885
         self.assertEqual(d['hold_job'], o.hold_job)
885 886
         self.assertEqual(d['host_keys'], o.host_keys)
887
+        self.assertEqual(d['attributes'], o.attributes)
886 888
 
887 889
     def test_Node_fromDict(self):
888 890
         now = int(time.time())
@@ -907,6 +909,7 @@ class TestZKModel(tests.BaseTestCase):
907 909
             'hold_job': 'hold job',
908 910
             'host_keys': ['key1', 'key2'],
909 911
             'connection_port': 22022,
912
+            'attributes': {'executor-zone': 'vpn'},
910 913
         }
911 914
 
912 915
         o = zk.Node.fromDict(d, node_id)
@@ -930,6 +933,7 @@ class TestZKModel(tests.BaseTestCase):
930 933
         self.assertEqual(o.hold_job, d['hold_job'])
931 934
         self.assertEqual(o.host_keys, d['host_keys'])
932 935
         self.assertEqual(o.connection_port, d['connection_port'])
936
+        self.assertEqual(o.attributes, d['attributes'])
933 937
 
934 938
     def test_custom_connection_port(self):
935 939
         n = zk.Node('0001')

+ 5
- 1
nodepool/zk.py View File

@@ -517,6 +517,7 @@ class Node(BaseModel):
517 517
         self.host_keys = []
518 518
         self.hold_expiration = None
519 519
         self.resources = None
520
+        self.attributes = None
520 521
 
521 522
     def __repr__(self):
522 523
         d = self.toDict()
@@ -552,7 +553,8 @@ class Node(BaseModel):
552 553
                     self.connection_port == other.connection_port and
553 554
                     self.host_keys == other.host_keys and
554 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 558
         else:
557 559
             return False
558 560
 
@@ -599,6 +601,7 @@ class Node(BaseModel):
599 601
         d['connection_port'] = self.connection_port
600 602
         d['hold_expiration'] = self.hold_expiration
601 603
         d['resources'] = self.resources
604
+        d['attributes'] = self.attributes
602 605
         return d
603 606
 
604 607
     @staticmethod
@@ -660,6 +663,7 @@ class Node(BaseModel):
660 663
         else:
661 664
             self.hold_expiration = hold_expiration
662 665
         self.resources = d.get('resources')
666
+        self.attributes = d.get('attributes')
663 667
 
664 668
 
665 669
 class ZooKeeper(object):

+ 7
- 0
releasenotes/notes/node-metadata-e1e822b49464f51a.yaml View File

@@ -0,0 +1,7 @@
1
+---
2
+features:
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.

Loading…
Cancel
Save