Просмотр исходного кода

Moving KeyPairService helper functions to helpers.py & moving core delete function to service

almahmoud 7 лет назад
Родитель
Сommit
3627cae9a3

+ 106 - 0
cloudbridge/cloud/providers/gce/helpers.py

@@ -1,8 +1,20 @@
+from collections import namedtuple
+import hashlib
+
 # based on http://stackoverflow.com/a/39126754
 # based on http://stackoverflow.com/a/39126754
 from cryptography.hazmat.backends import default_backend
 from cryptography.hazmat.backends import default_backend
 from cryptography.hazmat.primitives import serialization as crypt_serialization
 from cryptography.hazmat.primitives import serialization as crypt_serialization
 from cryptography.hazmat.primitives.asymmetric import rsa
 from cryptography.hazmat.primitives.asymmetric import rsa
 
 
+from retrying import retry
+
+
+GCEKeyInfo = namedtuple('GCEKeyInfo', 'format public_key email')
+
+
+def gce_projects(provider):
+    return provider.gce_compute.projects()
+
 
 
 def generate_key_pair():
 def generate_key_pair():
     key_pair = rsa.generate_private_key(
     key_pair = rsa.generate_private_key(
@@ -28,3 +40,97 @@ def iter_all(resource, **kwargs):
         if 'nextPageToken' not in response:
         if 'nextPageToken' not in response:
             return
             return
         token = response['nextPageToken']
         token = response['nextPageToken']
+
+
+def _iter_gce_key_pairs(provider):
+    """
+    Iterates through the project's metadata, yielding a GCEKeyInfo object
+    for each entry in commonInstanceMetaData/items
+    """
+    metadata = _get_common_metadata(provider)
+    for kpinfo in _iter_gce_ssh_keys(metadata):
+        yield kpinfo
+
+
+def _get_common_metadata(provider):
+    """
+    Get a project's commonInstanceMetadata entry
+    """
+    metadata = gce_projects(provider).get(
+        project=provider.project_name).execute()
+    return metadata["commonInstanceMetadata"]
+
+
+def _get_or_add_sshkey_entry(metadata):
+    """
+    Get the ssh-keys entry from commonInstanceMetadata/items.
+    If an entry does not exist, adds a new empty entry
+    """
+    sshkey_entry = None
+    entries = [item for item in metadata.get('items', [])
+               if item['key'] == 'ssh-keys']
+    if entries:
+        sshkey_entry = entries[0]
+    else:  # add a new entry
+        sshkey_entry = {'key': 'ssh-keys', 'value': ''}
+        if 'items' not in metadata:
+            metadata['items'] = [sshkey_entry]
+        else:
+            metadata['items'].append(sshkey_entry)
+    return sshkey_entry
+
+
+def _iter_gce_ssh_keys(metadata):
+    """
+    Iterates through the ssh keys given a commonInstanceMetadata dict,
+    yielding a GCEKeyInfo object for each entry in
+    commonInstanceMetaData/items
+    """
+    sshkeys = _get_or_add_sshkey_entry(metadata)["value"]
+    for key in sshkeys.split("\n"):
+        # elems should be "ssh-rsa <public_key> <email>"
+        elems = key.split(" ")
+        if elems and elems[0]:  # ignore blank lines
+            yield GCEKeyInfo(
+                    elems[0], elems[1].encode('ascii'), elems[2])
+
+
+def gce_metadata_save_op(provider, callback):
+    """
+    Carries out a metadata save operation. In GCE, a fingerprint based
+    locking mechanism is used to prevent lost updates. A new fingerprint
+    is returned each time metadata is retrieved. Therefore, this method
+    retrieves the metadata, invokes the provided callback with that
+    metadata, and saves the metadata using the original fingerprint
+    immediately afterwards, ensuring that update conflicts can be detected.
+    """
+    def _save_common_metadata(provider):
+        metadata = _get_common_metadata(provider)
+        # add a new entry if one doesn't exist
+        sshkey_entry = _get_or_add_sshkey_entry(metadata)
+        gce_kp_list = callback(_iter_gce_ssh_keys(metadata))
+
+        entry = ""
+        for gce_kp in gce_kp_list:
+            entry = entry + u"{0} {1} {2}\n".format(gce_kp.format,
+                                                    gce_kp.public_key,
+                                                    gce_kp.email)
+        sshkey_entry["value"] = entry.rstrip()
+        # common_metadata will have the current fingerprint at this point
+        operation = gce_projects(provider).setCommonInstanceMetadata(
+            project=provider.project_name, body=metadata).execute()
+        provider.wait_for_operation(operation)
+
+    # Retry a few times if the fingerprints conflict
+    retry_decorator = retry(stop_max_attempt_number=5)
+    retry_decorator(_save_common_metadata)(provider)
+
+
+def gce_kp_to_id(gce_kp):
+    """
+    Accept a GCEKeyInfo object and return a unique
+    ID for it
+    """
+    md5 = hashlib.md5()
+    md5.update(gce_kp.public_key)
+    return md5.hexdigest()

+ 1 - 12
cloudbridge/cloud/providers/gce/resources.py

@@ -74,18 +74,7 @@ class GCEKeyPair(BaseKeyPair):
         return self._kp_name
         return self._kp_name
 
 
     def delete(self):
     def delete(self):
-        svc = self._provider.security.key_pairs
-
-        def _delete_key(gce_kp_generator):
-            kp_list = []
-            for gce_kp in gce_kp_generator:
-                if svc.gce_kp_to_id(gce_kp) == self.id:
-                    continue
-                else:
-                    kp_list.append(gce_kp)
-            return kp_list
-
-        svc.gce_metadata_save_op(_delete_key)
+        self._provider.security.key_pairs.delete(self.id)
 
 
     @property
     @property
     def material(self):
     def material(self):

+ 18 - 105
cloudbridge/cloud/providers/gce/services.py

@@ -1,12 +1,9 @@
-import hashlib
 import logging
 import logging
 import time
 import time
 import uuid
 import uuid
-from collections import namedtuple
 
 
 import googleapiclient
 import googleapiclient
 
 
-from retrying import retry
 
 
 import cloudbridge as cb
 import cloudbridge as cb
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.base.resources import ClientPagedResultList
@@ -71,17 +68,8 @@ class GCESecurityService(BaseSecurityService):
 
 
 class GCEKeyPairService(BaseKeyPairService):
 class GCEKeyPairService(BaseKeyPairService):
 
 
-    GCEKeyInfo = namedtuple('GCEKeyInfo', 'format public_key email')
-
     def __init__(self, provider):
     def __init__(self, provider):
         super(GCEKeyPairService, self).__init__(provider)
         super(GCEKeyPairService, self).__init__(provider)
-        self._gce_projects = None
-
-    @property
-    def gce_projects(self):
-        if not self._gce_projects:
-            self._gce_projects = self.provider.gce_compute.projects()
-        return self._gce_projects
 
 
     def get(self, key_pair_id):
     def get(self, key_pair_id):
         """
         """
@@ -93,98 +81,10 @@ class GCEKeyPairService(BaseKeyPairService):
         else:
         else:
             return None
             return None
 
 
-    def _iter_gce_key_pairs(self):
-        """
-        Iterates through the project's metadata, yielding a GCEKeyInfo object
-        for each entry in commonInstanceMetaData/items
-        """
-        metadata = self._get_common_metadata()
-        for kpinfo in self._iter_gce_ssh_keys(metadata):
-            yield kpinfo
-
-    def _get_common_metadata(self):
-        """
-        Get a project's commonInstanceMetadata entry
-        """
-        metadata = self.gce_projects.get(
-            project=self.provider.project_name).execute()
-        return metadata["commonInstanceMetadata"]
-
-    def _get_or_add_sshkey_entry(self, metadata):
-        """
-        Get the ssh-keys entry from commonInstanceMetadata/items.
-        If an entry does not exist, adds a new empty entry
-        """
-        sshkey_entry = None
-        entries = [item for item in metadata.get('items', [])
-                   if item['key'] == 'ssh-keys']
-        if entries:
-            sshkey_entry = entries[0]
-        else:  # add a new entry
-            sshkey_entry = {'key': 'ssh-keys', 'value': ''}
-            if 'items' not in metadata:
-                metadata['items'] = [sshkey_entry]
-            else:
-                metadata['items'].append(sshkey_entry)
-        return sshkey_entry
-
-    def _iter_gce_ssh_keys(self, metadata):
-        """
-        Iterates through the ssh keys given a commonInstanceMetadata dict,
-        yielding a GCEKeyInfo object for each entry in
-        commonInstanceMetaData/items
-        """
-        sshkeys = self._get_or_add_sshkey_entry(metadata)["value"]
-        for key in sshkeys.split("\n"):
-            # elems should be "ssh-rsa <public_key> <email>"
-            elems = key.split(" ")
-            if elems and elems[0]:  # ignore blank lines
-                yield GCEKeyPairService.GCEKeyInfo(
-                        elems[0], elems[1].encode('ascii'), elems[2])
-
-    def gce_metadata_save_op(self, callback):
-        """
-        Carries out a metadata save operation. In GCE, a fingerprint based
-        locking mechanism is used to prevent lost updates. A new fingerprint
-        is returned each time metadata is retrieved. Therefore, this method
-        retrieves the metadata, invokes the provided callback with that
-        metadata, and saves the metadata using the original fingerprint
-        immediately afterwards, ensuring that update conflicts can be detected.
-        """
-        def _save_common_metadata():
-            metadata = self._get_common_metadata()
-            # add a new entry if one doesn'te xist
-            sshkey_entry = self._get_or_add_sshkey_entry(metadata)
-            gce_kp_list = callback(self._iter_gce_ssh_keys(metadata))
-
-            entry = ""
-            for gce_kp in gce_kp_list:
-                entry = entry + u"{0} {1} {2}\n".format(gce_kp.format,
-                                                        gce_kp.public_key,
-                                                        gce_kp.email)
-            sshkey_entry["value"] = entry.rstrip()
-            # common_metadata will have the current fingerprint at this point
-            operation = self.gce_projects.setCommonInstanceMetadata(
-                project=self.provider.project_name, body=metadata).execute()
-            self.provider.wait_for_operation(operation)
-
-        # Retry a few times if the fingerprints conflict
-        retry_decorator = retry(stop_max_attempt_number=5)
-        retry_decorator(_save_common_metadata)()
-
-    def gce_kp_to_id(self, gce_kp):
-        """
-        Accept a GCEKeyInfo object and return a unique
-        ID for it
-        """
-        md5 = hashlib.md5()
-        md5.update(gce_kp.public_key)
-        return md5.hexdigest()
-
     def list(self, limit=None, marker=None):
     def list(self, limit=None, marker=None):
         key_pairs = []
         key_pairs = []
-        for gce_kp in self._iter_gce_key_pairs():
-            kp_id = self.gce_kp_to_id(gce_kp)
+        for gce_kp in helpers._iter_gce_key_pairs(self.provider):
+            kp_id = helpers.gce_kp_to_id(gce_kp)
             key_pairs.append(GCEKeyPair(self.provider, kp_id, gce_kp.email))
             key_pairs.append(GCEKeyPair(self.provider, kp_id, gce_kp.email))
         return ClientPagedResultList(self.provider, key_pairs,
         return ClientPagedResultList(self.provider, key_pairs,
                                      limit=limit, marker=marker)
                                      limit=limit, marker=marker)
@@ -221,7 +121,7 @@ class GCEKeyPairService(BaseKeyPairService):
         parts = public_key_material.split(b' ')
         parts = public_key_material.split(b' ')
         if len(parts) == 2:
         if len(parts) == 2:
             public_key_material = parts[1]
             public_key_material = parts[1]
-        kp_info = GCEKeyPairService.GCEKeyInfo(
+        kp_info = helpers.GCEKeyInfo(
             '%s:ssh-rsa' % name, public_key_material, name)
             '%s:ssh-rsa' % name, public_key_material, name)
 
 
         def _add_kp(gce_kp_generator):
         def _add_kp(gce_kp_generator):
@@ -232,10 +132,23 @@ class GCEKeyPairService(BaseKeyPairService):
                 kp_list.append(gce_kp)
                 kp_list.append(gce_kp)
             return kp_list
             return kp_list
 
 
-        self.gce_metadata_save_op(_add_kp)
-        return GCEKeyPair(self.provider, self.gce_kp_to_id(kp_info), name,
+        helpers.gce_metadata_save_op(self.provider, _add_kp)
+        return GCEKeyPair(self.provider, helpers.gce_kp_to_id(kp_info), name,
                           private_key)
                           private_key)
 
 
+    def delete(self, key_pair_id):
+
+        def _delete_key(gce_kp_generator):
+            kp_list = []
+            for gce_kp in gce_kp_generator:
+                if helpers.gce_kp_to_id(gce_kp) == key_pair_id:
+                    continue
+                else:
+                    kp_list.append(gce_kp)
+            return kp_list
+
+        helpers.gce_metadata_save_op(self.provider, _delete_key)
+
 
 
 class GCEVMFirewallService(BaseVMFirewallService):
 class GCEVMFirewallService(BaseVMFirewallService):