You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@libcloud.apache.org by qu...@apache.org on 2017/09/25 04:03:21 UTC

libcloud git commit: Adding support for GCE node labels.

Repository: libcloud
Updated Branches:
  refs/heads/trunk 29d1480ba -> a83130139


Adding support for GCE node labels.

Closes #1115

Signed-off-by: Quentin Pradet <qu...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/a8313013
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/a8313013
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/a8313013

Branch: refs/heads/trunk
Commit: a831301394443399bdee613176d0e84d0154d14b
Parents: 29d1480
Author: maxlip <ma...@gmail.com>
Authored: Wed Sep 20 14:09:18 2017 -0700
Committer: Quentin Pradet <qu...@apache.org>
Committed: Mon Sep 25 07:52:49 2017 +0400

----------------------------------------------------------------------
 CHANGES.rst                                     |  2 +
 libcloud/compute/drivers/gce.py                 | 60 +++++++++++++++++---
 ..._us_central1_a_node_name_setLabels_post.json | 15 +++++
 ...l1_a_instances_node_name_setLabels_post.json | 15 +++++
 libcloud/test/compute/test_gce.py               | 36 ++++++++++++
 5 files changed, 119 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/a8313013/CHANGES.rst
----------------------------------------------------------------------
diff --git a/CHANGES.rst b/CHANGES.rst
index bc42ce5..1644367 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -16,6 +16,8 @@ Compute
 - Update ProfitBricks driver and add support for the new API v4. (GITHUB-1103)
   [Nurfet Becirevic]
 
+- [GCE] Support GCE node labels. (GITHUB-1115) [@maxlip]
+
 Changes in Apache Libcloud 2.2.1
 --------------------------------
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/a8313013/libcloud/compute/drivers/gce.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/gce.py b/libcloud/compute/drivers/gce.py
index c9c3c17..7b052a2 100644
--- a/libcloud/compute/drivers/gce.py
+++ b/libcloud/compute/drivers/gce.py
@@ -1919,6 +1919,29 @@ class GCENodeDriver(NodeDriver):
         self.connection.async_request(request, method='POST', data=body)
         return True
 
+    def ex_set_node_labels(self, node, labels):
+        """
+        Set labels for the specified node.
+
+        :keyword  node: The existing target Node (instance) for the request.
+        :type     node: ``Node``
+
+        :keyword  labels: Set (or clear with None) labels for this node.
+        :type     labels: ``dict`` or ``None``
+
+        :return: True if successful
+        :rtype:  ``bool``
+        """
+        if not isinstance(node, Node):
+            raise ValueError("Must specify a valid libcloud node object.")
+        node_name = node.name
+        zone_name = node.extra['zone'].name
+        current_fp = node.extra['labelFingerprint']
+        body = {'labels': labels, 'labelFingerprint': current_fp}
+        request = '/zones/%s/instances/%s/setLabels' % (zone_name, node_name)
+        self.connection.async_request(request, method='POST', data=body)
+        return True
+
     def ex_get_serial_output(self, node):
         """
         Fetch the console/serial port output from the node.
@@ -3699,7 +3722,7 @@ class GCENodeDriver(NodeDriver):
             ex_service_accounts=None, description=None, ex_can_ip_forward=None,
             ex_disks_gce_struct=None, ex_nic_gce_struct=None,
             ex_on_host_maintenance=None, ex_automatic_restart=None,
-            ex_preemptible=None, ex_image_family=None):
+            ex_preemptible=None, ex_image_family=None, ex_labels=None):
         """
         Create a new node and return a node object for the node.
 
@@ -3820,6 +3843,9 @@ class GCENodeDriver(NodeDriver):
                                    to use this keyword.
         :type     ex_image_family: ``str`` or ``None``
 
+        :keyword  ex_labels: Labels dictionary for instance.
+        :type     ex_labels: ``dict`` or ``None``
+
         :return:  A Node object for the new node.
         :rtype:   :class:`Node`
         """
@@ -3879,7 +3905,7 @@ class GCENodeDriver(NodeDriver):
             ex_boot_disk, external_ip, ex_disk_type, ex_disk_auto_delete,
             ex_service_accounts, description, ex_can_ip_forward,
             ex_disks_gce_struct, ex_nic_gce_struct, ex_on_host_maintenance,
-            ex_automatic_restart, ex_preemptible, ex_subnetwork)
+            ex_automatic_restart, ex_preemptible, ex_subnetwork, ex_labels)
         self.connection.async_request(request, method='POST', data=node_data)
         return self.ex_get_node(name, location.name)
 
@@ -4033,7 +4059,7 @@ class GCENodeDriver(NodeDriver):
             service_accounts=None, on_host_maintenance=None,
             automatic_restart=None, preemptible=None, tags=None, metadata=None,
             description=None, disks_gce_struct=None, nic_gce_struct=None,
-            use_selflinks=True):
+            use_selflinks=True, labels=None):
         """
         Create the GCE instance properties needed for instance templates.
 
@@ -4143,6 +4169,9 @@ class GCENodeDriver(NodeDriver):
                                   details.
         :type     nic_gce_struct: ``list`` or ``None``
 
+        :type     labels: Labels dict for instance
+        :type     labels: ``dict`` or ``None``
+
         :return:  A dictionary formatted for use with the GCE API.
         :rtype:   ``dict``
         """
@@ -4218,6 +4247,8 @@ class GCENodeDriver(NodeDriver):
         if metadata:
             instance_properties['metadata'] = self._format_metadata(
                 fingerprint='na', metadata=metadata)
+        if labels:
+            instance_properties['labels'] = labels
         if can_ip_forward:
             instance_properties['canIpForward'] = True
 
@@ -4566,7 +4597,7 @@ class GCENodeDriver(NodeDriver):
             description=None, ex_can_ip_forward=None, ex_disks_gce_struct=None,
             ex_nic_gce_struct=None, ex_on_host_maintenance=None,
             ex_automatic_restart=None, ex_image_family=None,
-            ex_preemptible=None):
+            ex_preemptible=None, ex_labels=None):
         """
         Create multiple nodes and return a list of Node objects.
 
@@ -4702,6 +4733,9 @@ class GCENodeDriver(NodeDriver):
                                    to use this keyword.
         :type     ex_image_family: ``str`` or ``None``
 
+        :param    ex_labels: Label dict for node.
+        :type     ex_labels: ``dict``
+
         :return:  A list of Node objects for the new nodes.
         :rtype:   ``list`` of :class:`Node`
 
@@ -4752,7 +4786,8 @@ class GCENodeDriver(NodeDriver):
                       'ex_nic_gce_struct': ex_nic_gce_struct,
                       'ex_on_host_maintenance': ex_on_host_maintenance,
                       'ex_automatic_restart': ex_automatic_restart,
-                      'ex_preemptible': ex_preemptible}
+                      'ex_preemptible': ex_preemptible,
+                      'ex_labels': ex_labels}
         # List for holding the status information for disk/node creation.
         status_list = []
 
@@ -7644,7 +7679,7 @@ class GCENodeDriver(NodeDriver):
             ex_service_accounts=None, description=None, ex_can_ip_forward=None,
             ex_disks_gce_struct=None, ex_nic_gce_struct=None,
             ex_on_host_maintenance=None, ex_automatic_restart=None,
-            ex_preemptible=None, ex_subnetwork=None):
+            ex_preemptible=None, ex_subnetwork=None, ex_labels=None):
         """
         Returns a request and body to create a new node.
 
@@ -7759,6 +7794,9 @@ class GCENodeDriver(NodeDriver):
         :param  ex_subnetwork: The network to associate with the node.
         :type   ex_subnetwork: :class:`GCESubnetwork`
 
+        :param  ex_labels: Label dict for node.
+        :type   ex_labels: ``dict`` or ``None``
+
         :return:  A tuple containing a request string and a node_data dict.
         :rtype:   ``tuple`` of ``str`` and ``dict``
         """
@@ -7786,8 +7824,8 @@ class GCENodeDriver(NodeDriver):
             service_accounts=ex_service_accounts,
             on_host_maintenance=ex_on_host_maintenance,
             automatic_restart=ex_automatic_restart, preemptible=ex_preemptible,
-            tags=tags, metadata=metadata, description=description,
-            disks_gce_struct=ex_disks_gce_struct,
+            tags=tags, metadata=metadata, labels=ex_labels,
+            description=description, disks_gce_struct=ex_disks_gce_struct,
             nic_gce_struct=ex_nic_gce_struct, use_selflinks=use_selflinks)
         node_data['name'] = name
 
@@ -7891,7 +7929,9 @@ class GCENodeDriver(NodeDriver):
             ex_on_host_maintenance=node_attrs['ex_on_host_maintenance'],
             ex_automatic_restart=node_attrs['ex_automatic_restart'],
             ex_subnetwork=node_attrs['subnetwork'],
-            ex_preemptible=node_attrs['ex_preemptible'])
+            ex_preemptible=node_attrs['ex_preemptible'],
+            ex_labels=node_attrs['ex_labels']
+        )
 
         try:
             node_res = self.connection.request(request, method='POST',
@@ -8362,6 +8402,8 @@ class GCENodeDriver(NodeDriver):
         extra['serviceAccounts'] = node.get('serviceAccounts', [])
         extra['scheduling'] = node.get('scheduling', {})
         extra['boot_disk'] = None
+        extra['labels'] = node.get('labels')
+        extra['labelFingerprint'] = node.get('labelFingerprint')
 
         for disk in extra['disks']:
             if disk.get('boot') and disk.get('type') == 'PERSISTENT':

http://git-wip-us.apache.org/repos/asf/libcloud/blob/a8313013/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_node_name_setLabels_post.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_node_name_setLabels_post.json b/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_node_name_setLabels_post.json
new file mode 100644
index 0000000..f72e383
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/operations_operation_zones_us_central1_a_node_name_setLabels_post.json
@@ -0,0 +1,15 @@
+{
+  "endTime": "2013-06-26T10:05:07.630-07:00",
+  "id": "3681664092089171723",
+  "insertTime": "2013-06-26T10:05:03.271-07:00",
+  "kind": "compute#operation",
+  "name": "operation-setLabels_post",
+  "operationType": "insert",
+  "progress": 100,
+  "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/operations/operation-setLabels_post",
+  "startTime": "2013-06-26T10:05:03.315-07:00",
+  "status": "DONE",
+  "targetId": "16211908079305042870",
+  "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instances/node-name/setLabels",
+  "user": "foo@developer.gserviceaccount.com"
+}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/a8313013/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instances_node_name_setLabels_post.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instances_node_name_setLabels_post.json b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instances_node_name_setLabels_post.json
new file mode 100644
index 0000000..e698a3c
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/zones_us_central1_a_instances_node_name_setLabels_post.json
@@ -0,0 +1,15 @@
+{
+  "endTime": "2013-06-26T10:05:07.630-07:00",
+  "id": "3681664092089171723",
+  "insertTime": "2013-06-26T10:05:03.271-07:00",
+  "kind": "compute#operation",
+  "name": "operation-setLabelspost",
+  "operationType": "insert",
+  "progress": 0,
+  "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/operations/operation-setLabels_post",
+  "startTime": "2013-06-26T10:05:03.315-07:00",
+  "status": "PENDING",
+  "targetId": "16211908079305042870",
+  "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/zones/us-central1-a/instances/node-name/setLabels",
+  "user": "foo@developer.gserviceaccount.com"
+}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/a8313013/libcloud/test/compute/test_gce.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_gce.py b/libcloud/test/compute/test_gce.py
index 8332f08..31a1bce 100644
--- a/libcloud/test/compute/test_gce.py
+++ b/libcloud/test/compute/test_gce.py
@@ -1216,6 +1216,21 @@ class GCENodeDriverTest(GoogleTestCase, TestCaseMixin):
         self.assertEqual(data['metadata']['items'][0]['key'], 'k0')
         self.assertEqual(data['metadata']['items'][0]['value'], 'v0')
 
+    def test_create_node_with_labels(self):
+        node_name = 'node-name'
+        image = self.driver.ex_get_image('debian-7')
+        size = self.driver.ex_get_size('n1-standard-1')
+        zone = self.driver.ex_get_zone('us-central1-a')
+
+        # labels is a dict
+        labels = {'label1': 'v1', 'label2': 'v2'}
+        request, data = self.driver._create_node_req(node_name, size, image,
+                                                     zone, ex_labels=labels)
+        self.assertTrue(data['labels'] is not None)
+        self.assertEqual(len(data['labels']), 2)
+        self.assertEqual(data['labels']['label1'], 'v1')
+        self.assertEqual(data['labels']['label2'], 'v2')
+
     def test_create_node_existing(self):
         node_name = 'libcloud-demo-europe-np-node'
         image = self.driver.ex_get_image('debian-7')
@@ -1862,6 +1877,15 @@ class GCENodeDriverTest(GoogleTestCase, TestCaseMixin):
                                                'value': 'v2'}]}
         self.driver.ex_set_node_metadata(node, gcedict)
 
+    def test_ex_set_node_labels(self):
+        node = self.driver.ex_get_node('node-name', 'us-central1-a')
+        # Test basic values
+        simplelabel = {'key': 'value'}
+        self.driver.ex_set_node_labels(node, simplelabel)
+        # Test multiple values
+        multilabels = {'item1': 'val1', 'item2': 'val2'}
+        self.driver.ex_set_node_labels(node, multilabels)
+
     def test_ex_get_region(self):
         region_name = 'us-central1'
         region = self.driver.ex_get_region(region_name)
@@ -2079,6 +2103,12 @@ class GCEMockHttp(MockHttp):
             'zones_us_central1_a_instances_node_name_setMetadata_post.json')
         return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
 
+    def _zones_us_central1_a_instances_node_name_setLabels(self, method, url,
+                                                           body, headers):
+        body = self.fixtures.load(
+            'zones_us_central1_a_instances_node_name_setLabels_post.json')
+        return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
     def _setCommonInstanceMetadata(self, method, url, body, headers):
         if method == 'POST':
             body = self.fixtures.load('setCommonInstanceMetadata_post.json')
@@ -2554,6 +2584,12 @@ class GCEMockHttp(MockHttp):
             'operations_operation_zones_us_central1_a_node_name_setMetadata_post.json')
         return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
 
+    def _zones_us_central1_a_operations_operation_setLabels_post(
+            self, method, url, body, headers):
+        body = self.fixtures.load(
+            'operations_operation_zones_us_central1_a_node_name_setLabels_post.json')
+        return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
     def _zones_us_central1_a_operations_operation_zones_us_central1_a_targetInstances_post(
             self, method, url, body, headers):
         body = self.fixtures.load(