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

Add tools to deal with resource URLs

Now we can parse resource URLs and get resources by URL.
Ehsan Chiniforooshan 9 лет назад
Родитель
Сommit
819a71d46f

+ 9 - 11
cloudbridge/cloud/providers/gce/provider.py

@@ -82,9 +82,9 @@ class GCECloudProvider(BaseCloudProvider):
             self._gce_compute = self._connect_gce_compute()
         return self._gce_compute
 
-    @staticmethod
-    def parse_url(url):
-        return {}
+    @property
+    def gcp_storage(self):
+        raise NotImplementedError("To be implemented")
 
     def _connect_gce_compute(self):
         if self.credentials_dict:
@@ -98,12 +98,13 @@ class GCECloudProvider(BaseCloudProvider):
         args = {'project': self.project_name, 'operation': operation['name']}
         if not region and not zone:
             operations = self.gce_compute.globalOperations()
-        elif region:
-            args['region'] = region
-            operations = self.gce_compute.regionOperations()
-        else:
-            args['zone'] = zone
+        elif zone:
             operations = self.gce_compute.zoneOperations()
+            args['zone'] = zone
+        else:
+            operations = self.gce_compute.regionOperations()
+            args['region'] = region
+
         while True:
             result = operations.get(**args).execute()
             if result['status'] == 'DONE':
@@ -112,6 +113,3 @@ class GCECloudProvider(BaseCloudProvider):
                 return result
 
             time.sleep(0.5)
-
-    def get_url(self, url):
-        return {'kind': 'error'}

+ 101 - 20
cloudbridge/cloud/providers/gce/resources.py

@@ -26,6 +26,95 @@ import json
 import re
 import uuid
 
+
+class GCPResourceType(object):
+
+    def __init__(self, platform, resource_type):
+        self.platform = platform
+        self.resource_type = resource_type
+
+    @property
+    def kind(self):
+        return '%s#%s' % (self.platform, self.resource_type)
+
+    @property
+    def url_field_name(self):
+        return '%ss' % self.resource_type
+
+
+# GCP resource types we are interested in
+FORWARDING_RULE_TYPE = GCPResourceType('compute', 'forwardingRule')
+INSTANCE_TYPE = GCPResourceType('compute', 'instance')
+NETWORK_TYPE = GCPResourceType('compute', 'network')
+REGION_TYPE = GCPResourceType('compute', 'region')
+TARGET_INSTANCE_TYPE = GCPResourceType('compute', 'targetInstance')
+
+ALL_RESOURCE_TYPES = [FORWARDING_RULE_TYPE,
+                      INSTANCE_TYPE,
+                      NETWORK_TYPE,
+                      REGION_TYPE,
+                      TARGET_INSTANCE_TYPE]
+
+
+class GCPResourceUrl(GCPResourceType):
+
+    def __init__(self, platform, resource_type, project=None, region=None,
+                 zone=None, name=None, connection=None):
+        super(GCPResourceUrl, self).__init__(platform, resource_type)
+        self.project = project
+        self.region = region
+        self.zone = zone
+        self.name = name
+        self.connection = connection
+
+    @staticmethod
+    def parse_url(url, provider=None):
+        parts = url.split('/')
+        out = None
+        for resource_type in ALL_RESOURCE_TYPES:
+            if parts[-2] == resource_type.url_field_name:
+                out = GCPResourceUrl(resource_type.platform,
+                                     resource_type.resource_type)
+        if not out:
+            return out
+        out.name = parts[-1]
+
+        # If a cloud provider is given, set the connection.
+        if provider:
+            if out.platform == 'compute':
+                out.connection = provider.gce_compute
+            elif out.platform == 'storage':
+                out.connection = provider.gcp_storage
+
+        # Set region, zone, and project fields.
+        i = 0
+        while i < len(parts) - 2:
+            if parts[i] == 'regions':
+                out.region = parts[i + 1]
+                i += 2
+            elif parts[i] == 'zones':
+                out.zone = parts[i + 1]
+                i += 2
+            elif parts[i] == 'projects':
+                out.project = parts[i + 1]
+                i += 2
+            else:
+                i += 1
+        return out
+
+    @property
+    def discovery_object(self):
+        if not self.connection:
+            raise Exception('Connection is not set, yet')
+        return getattr(self.connection, self.url_field_name)()
+
+    def get(self):
+        args = {'project': self.project, self.resource_type: self.name}
+        if self.region: args['region'] = self.region
+        if self.zone: args['zone'] = self.zone
+        return self.discovery_object.get(**args).execute()
+
+
 class GCEKeyPair(BaseKeyPair):
 
     def __init__(self, provider, kp_id, kp_name, kp_material=None):
@@ -207,12 +296,7 @@ class GCEFirewallsDelegate(object):
         """
         if 'network' not in firewall:
             return GCEFirewallsDelegate.DEFAULT_NETWORK
-        match = re.search(
-                GCEFirewallsDelegate._NETWORK_URL_PREFIX + '([^/]*)$',
-                firewall['network'])
-        if match and len(match.groups()) == 1:
-            return match.group(1)
-        return None
+        return GCPResourceUrl.parse_url(firewall['network']).name
 
     @property
     def provider(self):
@@ -752,11 +836,7 @@ class GCEFloatingIP(BaseFloatingIP):
         # We use regional IPs to simulate floating IPs not global IPs because
         # global IPs can be forwarded only to load balancing resources, not to
         # a specific instance. Find out the region to which the IP belongs.
-        parsed_url = GCECloudProvider.parse_url(self._ip['region'])
-        if 'regions' in parsed_url:
-            self._region = parsed_url['regions']
-        else:
-            self._region = provider.region_name
+        self._region = GCPResourceUrl.parse_url(self._ip['region']).name
 
         # Check if the address is used by a resource.
         self._rule = None
@@ -764,14 +844,15 @@ class GCEFloatingIP(BaseFloatingIP):
         if 'users' in floating_ip and len(floating_ip['users']) > 0:
             if len(floating_ip['users']) > 1:
                 cb.log.warning('IP is in user by more than one resource')
-            resource = provider.get_url(floating_ip['users'][0])
-            if resource['kind'] == 'compute#instance':
-                self._target_instance = resource
-            elif resource['kind'] == 'compute#forwardingRule':
+            url = GCPResourceUrl.parse_url(floating_ip['users'][0], provider)
+            resource = url.get()
+            if resource['kind'] == FORWARDING_RULE_TYPE.kind:
                 self._rule = resource
-                target = provider.get_url(resource['target'])
-                if target['kind'] == 'compute#targetInstance':
-                    self._target_instance = provider.get_url(target['instance'])
+                url = GCPResourceUrl.parse_url(resource['target'], provider)
+                target = url.get()
+                if target['kind'] == TARGET_INSTANCE_TYPE.kind:
+                    url = GCPResourceUrl.parse_url(target['instance'], provider)
+                    self._target_instance = url.get()
                 else:
                     cb.log.warning('IP is forwarded to a %s' % target['kind'])
             else:
@@ -799,12 +880,12 @@ class GCEFloatingIP(BaseFloatingIP):
        # First, delete the forwarding rule, if there is any.
        if self._rule:
            response = (self._provider.gce_compute
-                                     .forwarding_rules()
+                                     .forwardingRules()
                                      .delete(project=project_name,
                                              region=self._region,
                                              forwardingRule=self._rule['name'])
                                      .execute())
-           self._provider.wait_forion(response, region=self._region)
+           self._provider.wait_for_operation(response, region=self._region)
 
        # Release the address.
        response = (self._provider.gce_compute

+ 1 - 0
cloudbridge/cloud/providers/gce/services.py

@@ -29,6 +29,7 @@ from .resources import GCERegion
 from .resources import GCESecurityGroup
 from .resources import GCESecurityGroupRule
 
+
 class GCESecurityService(BaseSecurityService):
 
     def __init__(self, provider):