libcloud-notifications mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From to...@apache.org
Subject [1/2] git commit: Support deletion and deprecation of GCE's images.
Date Fri, 14 Mar 2014 10:03:34 GMT
Repository: libcloud
Updated Branches:
  refs/heads/trunk f7a9ba0ca -> f86f3277f


Support deletion and deprecation of GCE's images.

Add a new class GCENodeImage to represent GCE's images, and support the
`delete` and `deprecated` functions.

Added a new extra field to the image object to specify the deprecation
status.

Closes #260

Signed-off-by: Tomaz Muraus <tomaz@apache.org>


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

Branch: refs/heads/trunk
Commit: fb4099eadfd0f3991160be1733a0935e37463741
Parents: f7a9ba0
Author: Franck Cuny <franck.cuny@gmail.com>
Authored: Tue Mar 11 08:26:58 2014 -0700
Committer: Tomaz Muraus <tomaz@apache.org>
Committed: Fri Mar 14 10:50:55 2014 +0100

----------------------------------------------------------------------
 libcloud/compute/drivers/gce.py                 | 126 ++++++++++++++++---
 ...es_debian_6_squeeze_v20130926_deprecate.json |  14 +++
 ...images_debian_7_wheezy_v20130617_delete.json |  15 +++
 ..._operation_global_images_debian7_delete.json |  15 +++
 libcloud/test/compute/test_gce.py               |  26 ++++
 5 files changed, 179 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/fb4099ea/libcloud/compute/drivers/gce.py
----------------------------------------------------------------------
diff --git a/libcloud/compute/drivers/gce.py b/libcloud/compute/drivers/gce.py
index 6b12de6..7aa48f2 100644
--- a/libcloud/compute/drivers/gce.py
+++ b/libcloud/compute/drivers/gce.py
@@ -229,6 +229,37 @@ class GCEForwardingRule(UuidMixin):
             self.id, self.name, self.address)
 
 
+class GCENodeImage(NodeImage):
+    """A GCE Node Image class."""
+    def __init__(self, id, name, driver, extra=None):
+        super(GCENodeImage, self).__init__(id, name, driver, extra=extra)
+
+    def delete(self):
+        """
+        Delete this image
+
+        :return: True if successful
+        :rtype:  ``bool``
+        """
+        return self.driver.ex_delete_image(image=self)
+
+    def deprecate(self, replacement, state):
+        """
+        Deprecate this image
+
+        :param  replacement: Image to use as a replacement
+        :type   replacement: ``str`` or :class: `GCENodeImage`
+
+        :param  state: Deprecation state of this image. Possible values include
+                       \'DELETED\', \'DEPRECATED\' or \'OBSOLETE\'.
+        :type   state: ``str``
+
+        :return: True if successful
+        :rtype:  ``bool``
+        """
+        return self.driver.ex_deprecate_image(self, replacement, state)
+
+
 class GCENetwork(UuidMixin):
     """A GCE Network object class."""
     def __init__(self, id, name, cidr, driver, extra=None):
@@ -661,10 +692,9 @@ class GCENodeDriver(NodeDriver):
         :keyword  ex_project: Optional alternate project name.
         :type     ex_project: ``str`` or ``None``
 
-        :return:  List of NodeImage objects
-        :rtype:   ``list`` of :class:`NodeImage`
+        :return:  List of GCENodeImage objects
+        :rtype:   ``list`` of :class:`GCENodeImage`
         """
-        list_images = []
         request = '/global/images'
         if ex_project is None:
             response = self.connection.request(request, method='GET').object
@@ -1109,7 +1139,7 @@ class GCENodeDriver(NodeDriver):
 
         :param  image: The image to use to create the node (or, if attaching
                        a persistent disk, the image used to create the disk)
-        :type   image: ``str`` or :class:`NodeImage`
+        :type   image: ``str`` or :class:`GCENodeImage`
 
         :keyword  location: The location (zone) to create the node in.
         :type     location: ``str`` or :class:`NodeLocation` or
@@ -1189,7 +1219,7 @@ class GCENodeDriver(NodeDriver):
         :type   size: ``str`` or :class:`GCENodeSize`
 
         :param  image: The image to use to create the nodes.
-        :type   image: ``str`` or :class:`NodeImage`
+        :type   image: ``str`` or :class:`GCENodeImage`
 
         :param  number: The number of nodes to create.
         :type   number: ``int``
@@ -1372,7 +1402,7 @@ class GCENodeDriver(NodeDriver):
         :type     snapshot: :class:`GCESnapshot` or ``str`` or ``None``
 
         :keyword  image: Image to create disk from.
-        :type     image: :class:`NodeImage` or ``str`` or ``None``
+        :type     image: :class:`GCENodeImage` or ``str`` or ``None``
 
         :keyword  use_existing: If True and a disk with the given name already
                                 exists, return an object for that disk instead
@@ -1740,7 +1770,7 @@ class GCENodeDriver(NodeDriver):
         :type   size: ``str`` or :class:`GCENodeSize`
 
         :param  image: The image to use to create the node.
-        :type   image: ``str`` or :class:`NodeImage`
+        :type   image: ``str`` or :class:`GCENodeImage`
 
         :param  script: File path to start-up script
         :type   script: ``str``
@@ -1854,6 +1884,66 @@ class GCENodeDriver(NodeDriver):
         self.connection.async_request(request, method='DELETE')
         return True
 
+    def ex_delete_image(self, image):
+        """
+        Delete a specific image resource.
+
+        :param  image: Image object to delete
+        :type   image: ``str`` or :class:`GCENodeImage`
+
+        :return: True if successfull
+        :rtype:  ``bool``
+        """
+        if not hasattr(image, 'name'):
+            image = self.ex_get_image(image)
+
+        request = '/global/images/%s' % (image.name)
+        self.connection.async_request(request, method='DELETE')
+        return True
+
+    def ex_deprecate_image(self, image, replacement, state=None):
+        """
+        Deprecate a specific image resource.
+
+        :param  image: Image object to deprecate
+        :type   image: ``str`` or :class: `GCENodeImage`
+
+        :param  replacement: Image object to use as a replacement
+        :type   replacement: ``str`` or :class: `GCENodeImage`
+
+        :param  state: State of the image
+        :type   state: ``str``
+
+        :return: True if successfull
+        :rtype:  ``bool``
+        """
+        if not hasattr(image, 'name'):
+            image = self.ex_get_image(image)
+
+        if not hasattr(replacement, 'name'):
+            replacement = self.ex_get_image(replacement)
+
+        if state is None:
+            state = 'DEPRECATED'
+
+        possible_states = ['DELETED', 'DEPRECATED', 'OBSOLETE']
+
+        if state not in possible_states:
+            raise ValueError('state must be one of %s'
+                             % ','.join(possible_states))
+
+        image_data = {
+            'state': state,
+            'replacement': replacement.extra['selfLink'],
+        }
+
+        request = '/global/images/%s/deprecate' % (image.name)
+
+        self.connection.request(
+            request, method='POST', data=image_data).object
+
+        return True
+
     def ex_destroy_healthcheck(self, healthcheck):
         """
         Destroy a healthcheck.
@@ -2154,15 +2244,15 @@ class GCENodeDriver(NodeDriver):
 
     def ex_get_image(self, partial_name):
         """
-        Return an NodeImage object based on the name or link provided.
+        Return an GCENodeImage object based on the name or link provided.
 
         :param  partial_name: The name, partial name, or full path of a GCE
                               image.
         :type   partial_name: ``str``
 
-        :return:  NodeImage object based on provided information or None if an
-                  image with that name is not found.
-        :rtype:   :class:`NodeImage` or ``None``
+        :return:  GCENodeImage object based on provided information or None if
+                  an image with that name is not found.
+        :rtype:   :class:`GCENodeImage` or ``None``
         """
         if partial_name.startswith('https://'):
             response = self.connection.request(partial_name, method='GET')
@@ -2469,7 +2559,7 @@ class GCENodeDriver(NodeDriver):
 
         :return:  The latest image object that matches the partial name or None
                   if no matching image is found.
-        :rtype:   :class:`NodeImage` or ``None``
+        :rtype:   :class:`GCENodeImage` or ``None``
         """
         project_images = self.list_images(project)
         partial_match = []
@@ -2538,7 +2628,7 @@ class GCENodeDriver(NodeDriver):
 
         :param  image: The image to use to create the node (or, if using a
                        persistent disk, the image the disk was created from).
-        :type   image: :class:`NodeImage`
+        :type   image: :class:`GCENodeImage`
 
         :param  location: The location (zone) to create the node in.
         :type   location: :class:`NodeLocation` or :class:`GCEZone`
@@ -2755,7 +2845,7 @@ class GCENodeDriver(NodeDriver):
         :type     snapshot: :class:`GCESnapshot` or ``str`` or ``None``
 
         :keyword  image: Image to create disk from.
-        :type     image: :class:`NodeImage` or ``str`` or ``None``
+        :type     image: :class:`GCENodeImage` or ``str`` or ``None``
 
         :return:  Tuple containing the request string, the data dictionary and
                   the URL parameters
@@ -2918,15 +3008,17 @@ class GCENodeDriver(NodeDriver):
         :type   image: ``dict``
 
         :return: Image object
-        :rtype: :class:`NodeImage`
+        :rtype: :class:`GCENodeImage`
         """
         extra = {}
         extra['preferredKernel'] = image.get('preferredKernel', None)
         extra['description'] = image.get('description', None)
         extra['creationTimestamp'] = image.get('creationTimestamp')
         extra['selfLink'] = image.get('selfLink')
-        return NodeImage(id=image['id'], name=image['name'], driver=self,
-                         extra=extra)
+        extra['deprecated'] = image.get('deprecated', None)
+
+        return GCENodeImage(id=image['id'], name=image['name'], driver=self,
+                            extra=extra)
 
     def _to_node_location(self, location):
         """

http://git-wip-us.apache.org/repos/asf/libcloud/blob/fb4099ea/libcloud/test/compute/fixtures/gce/global_images_debian_6_squeeze_v20130926_deprecate.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/global_images_debian_6_squeeze_v20130926_deprecate.json
b/libcloud/test/compute/fixtures/gce/global_images_debian_6_squeeze_v20130926_deprecate.json
new file mode 100644
index 0000000..fdc6654
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/global_images_debian_6_squeeze_v20130926_deprecate.json
@@ -0,0 +1,14 @@
+{
+    "status": "PENDING",
+    "kind": "compute#operation",
+    "name": "operation-1394594316110-4f4604ad0e708-2e4622ab",
+    "startTime": "2014-03-11T20:18:36.194-07:00",
+    "insertTime": "2014-03-11T20:18:36.110-07:00",
+    "targetId": "10034929421075729520",
+    "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/images/debian_6_squeeze_v20130926",
+    "operationType": "setDeprecation",
+    "progress": 0,
+    "id": "11223768474922166090",
+    "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/operations/operation-1394594316110-4f4604ad0e708-2e4622ab",
+    "user": "user@developer.gserviceaccount.com"
+}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/fb4099ea/libcloud/test/compute/fixtures/gce/global_images_debian_7_wheezy_v20130617_delete.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/global_images_debian_7_wheezy_v20130617_delete.json
b/libcloud/test/compute/fixtures/gce/global_images_debian_7_wheezy_v20130617_delete.json
new file mode 100644
index 0000000..7b70942
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/global_images_debian_7_wheezy_v20130617_delete.json
@@ -0,0 +1,15 @@
+{
+ "kind": "compute#operation",
+ "id": "10762099380229198553",
+ "name": "operation-global_images_debian7_delete",
+ "operationType": "delete",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/images/debian-7-wheezy-v20130617",
+ "targetId": "14881612020726561163",
+ "status": "PENDING",
+ "user": "user@developer.gserviceaccount.com",
+ "progress": 0,
+ "insertTime": "2014-03-11T14:37:48.075-07:00",
+ "startTime": "2014-03-11T14:37:48.158-07:00",
+ "endTime": "2014-03-11T14:37:48.634-07:00",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/operations/operation-global_images_debian7_delete"
+}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/fb4099ea/libcloud/test/compute/fixtures/gce/operations_operation_global_images_debian7_delete.json
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/fixtures/gce/operations_operation_global_images_debian7_delete.json
b/libcloud/test/compute/fixtures/gce/operations_operation_global_images_debian7_delete.json
new file mode 100644
index 0000000..0c085a9
--- /dev/null
+++ b/libcloud/test/compute/fixtures/gce/operations_operation_global_images_debian7_delete.json
@@ -0,0 +1,15 @@
+{
+ "kind": "compute#operation",
+ "id": "10762099380229198553",
+ "name": "operation-global_images_debian7_delete",
+ "operationType": "delete",
+ "targetLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/images/debian-7-wheezy-v20130617",
+ "targetId": "14881612020726561163",
+ "status": "DONE",
+ "user": "user@developer.gserviceaccount.com",
+ "progress": 100,
+ "insertTime": "2014-03-11T14:37:48.075-07:00",
+ "startTime": "2014-03-11T14:37:48.158-07:00",
+ "endTime": "2014-03-11T14:37:48.634-07:00",
+ "selfLink": "https://www.googleapis.com/compute/v1/projects/project_name/global/operations/operation-global_images_debian7_delete"
+}

http://git-wip-us.apache.org/repos/asf/libcloud/blob/fb4099ea/libcloud/test/compute/test_gce.py
----------------------------------------------------------------------
diff --git a/libcloud/test/compute/test_gce.py b/libcloud/test/compute/test_gce.py
index 31f35bf..5a4af54 100644
--- a/libcloud/test/compute/test_gce.py
+++ b/libcloud/test/compute/test_gce.py
@@ -416,6 +416,16 @@ class GCENodeDriverTest(LibcloudTestCase, TestCaseMixin):
         destroyed = hc.destroy()
         self.assertTrue(destroyed)
 
+    def test_ex_delete_image(self):
+        image = self.driver.ex_get_image('debian-7')
+        deleted = self.driver.ex_delete_image(image)
+        self.assertTrue(deleted)
+
+    def test_ex_deprecate_image(self):
+        image = self.driver.ex_get_image('debian-6')
+        deprecated = image.deprecate('debian-7', 'DEPRECATED')
+        self.assertTrue(deprecated)
+
     def test_ex_destroy_firewall(self):
         firewall = self.driver.ex_get_firewall('lcfirewall')
         destroyed = firewall.destroy()
@@ -672,6 +682,16 @@ class GCEMockHttp(MockHttpTestCase):
         body = self.fixtures.load('global_images.json')
         return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
 
+    def _global_images_debian_7_wheezy_v20130617(
+            self, method, url, body, headers):
+        body = self.fixtures.load('global_images_debian_7_wheezy_v20130617_delete.json')
+        return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
+    def _global_images_debian_6_squeeze_v20130926_deprecate(
+            self, method, url, body, headers):
+        body = self.fixtures.load('global_images_debian_6_squeeze_v20130926_deprecate.json')
+        return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
     def _global_networks(self, method, url, body, headers):
         if method == 'POST':
             body = self.fixtures.load('global_networks_post.json')
@@ -719,6 +739,12 @@ class GCEMockHttp(MockHttpTestCase):
             'operations_operation_global_httpHealthChecks_lchealthcheck_delete.json')
         return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
 
+    def _global_operations_operation_global_images_debian7_delete(
+            self, method, url, body, headers):
+        body = self.fixtures.load(
+            'operations_operation_global_images_debian7_delete.json')
+        return (httplib.OK, body, self.json_hdr, httplib.responses[httplib.OK])
+
     def _global_operations_operation_global_httpHealthChecks_lchealthcheck_put(
             self, method, url, body, headers):
         body = self.fixtures.load(


Mime
View raw message