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

Merge branch 'gce' of https://github.com/CloudVE/cloudbridge into gce

almahmoud 7 лет назад
Родитель
Сommit
fba15678bb
3 измененных файлов с 147 добавлено и 86 удалено
  1. 120 52
      cloudbridge/cloud/providers/gce/resources.py
  2. 26 33
      cloudbridge/cloud/providers/gce/services.py
  3. 1 1
      setup.py

+ 120 - 52
cloudbridge/cloud/providers/gce/resources.py

@@ -469,6 +469,18 @@ class GCEVMFirewall(BaseVMFirewall):
         """
         """
         return self._vm_firewall
         return self._vm_firewall
 
 
+    @property
+    def label(self):
+        tag_name = "_".join(["firewall", self.name, "label"])
+        return helpers.get_metadata_item_value(self._provider, tag_name)
+        # TODO: Add removing metadata to delete function
+
+    @label.setter
+    def label(self, value):
+        self.assert_valid_resource_label(value)
+        tag_name = "_".join(["firewall", self.name, "label"])
+        helpers.modify_or_add_metadata_item(self._provider, tag_name, value)
+
     @property
     @property
     def description(self):
     def description(self):
         """
         """
@@ -797,10 +809,13 @@ class GCEMachineImage(BaseMachineImage):
         Refreshes the state of this instance by re-querying the cloud provider
         Refreshes the state of this instance by re-querying the cloud provider
         for its latest state.
         for its latest state.
         """
         """
-        name = self.name
-        self._gce_image = self._provider.get_resource('images', self.id)
-        if not self._gce_image:
-            self._gce_image = {'name': name, 'status': 'UNKNOWN'}
+        image = self._provider.compute.images.get(self.id)
+        if image:
+            # pylint:disable=protected-access
+            self._gce_image = image._gce_image
+        else:
+            # image no longer exists
+            self._gce_image['status'] = MachineImageState.UNKNOWN
 
 
 
 
 class GCEInstance(BaseInstance):
 class GCEInstance(BaseInstance):
@@ -1048,10 +1063,53 @@ class GCEInstance(BaseInstance):
         key in metadata.
         key in metadata.
         """
         """
         try:
         try:
-            return next(iter(self._provider.security.key_pairs))
+            kp = next(iter(self._provider.security.key_pairs))
+            return kp.id if kp else None
         except StopIteration:
         except StopIteration:
             return None
             return None
 
 
+    @key_pair_id.setter
+    # pylint:disable=arguments-differ
+    def key_pair_id(self, value):
+        self.assert_valid_resource_label(value)
+        key_pair = None
+        if not isinstance(value, GCEKeyPair):
+            key_pair = self._provider.security.key_pairs.get(value)
+        if key_pair:
+            key_pair_name = key_pair.name
+        kp = None
+        for kpi in self._provider.security.key_pairs._iter_gce_key_pairs(
+                self._provider):
+            if kpi.email == key_pair_name:
+                kp = kpi
+                break
+        if kp:
+            kp_items = [{
+                "key": "ssh-keys",
+                # FIXME: ssh username & key format are fixed here while they
+                # should correspond to the operating system, or be customizable
+                "value": "ubuntu:ssh-rsa {0} {1}".format(kp.public_key,
+                                                         kp.email)
+            }]
+            config = {
+                "items": kp_items,
+                "fingerprint": self._gce_instance['metadata']['fingerprint']
+            }
+            try:
+                (self._provider
+                    .gce_compute
+                    .instances()
+                    .setMetadata(project=self._provider.project_name,
+                                 zone=self._provider.default_zone,
+                                 instance=self.name,
+                                 body=config)
+                    .execute())
+            except Exception as e:
+                cb.log.warning('Exception while setting instance key pair: %s',
+                               e)
+                raise e
+            self.refresh()
+
     @property
     @property
     def inet_gateway(self):
     def inet_gateway(self):
         if self._inet_gateway:
         if self._inet_gateway:
@@ -1293,10 +1351,13 @@ class GCEInstance(BaseInstance):
         Refreshes the state of this instance by re-querying the cloud provider
         Refreshes the state of this instance by re-querying the cloud provider
         for its latest state.
         for its latest state.
         """
         """
-        name = self.name
-        self._gce_instance = self._provider.get_resource('instances', self.id)
-        if not self._gce_instance:
-            self._gce_instance = {'name': name, 'status': 'UNKNOWN'}
+        inst = self._provider.compute.instances.get(self.id)
+        if inst:
+            # pylint:disable=protected-access
+            self._gce_instance = inst._gce_instance
+        else:
+            # instance no longer exists
+            self._gce_instance['status'] = InstanceState.UNKNOWN
 
 
     def add_vm_firewall(self, sg):
     def add_vm_firewall(self, sg):
         tag = sg.name if isinstance(sg, GCEVMFirewall) else sg
         tag = sg.name if isinstance(sg, GCEVMFirewall) else sg
@@ -1354,6 +1415,7 @@ class GCENetwork(BaseNetwork):
 
 
     @label.setter
     @label.setter
     def label(self, value):
     def label(self, value):
+        self.assert_valid_resource_label(value)
         tag_name = "_".join(["network", self.name, "label"])
         tag_name = "_".join(["network", self.name, "label"])
         helpers.modify_or_add_metadata_item(self._provider, tag_name, value)
         helpers.modify_or_add_metadata_item(self._provider, tag_name, value)
 
 
@@ -1440,9 +1502,13 @@ class GCENetwork(BaseNetwork):
             label, self, cidr_block, zone)
             label, self, cidr_block, zone)
 
 
     def refresh(self):
     def refresh(self):
-        self._network = self._provider.get_resource('networks', self.id)
-        if not self._network:
-            self._network = {'status': 'UNKNOWN'}
+        net = self._provider.networking.networks.get(self.id)
+        if net:
+            # pylint:disable=protected-access
+            self._network = net._network
+        else:
+            # network no longer exists
+            self._network['status'] = NetworkState.UNKNOWN
 
 
     @property
     @property
     def gateways(self):
     def gateways(self):
@@ -1456,7 +1522,8 @@ class GCEFloatingIPContainer(BaseFloatingIPContainer):
 
 
     def get(self, floating_ip_id):
     def get(self, floating_ip_id):
         fip = self._provider.get_resource('addresses', floating_ip_id)
         fip = self._provider.get_resource('addresses', floating_ip_id)
-        return GCEFloatingIP(self._provider, fip) if fip else None
+        return (GCEFloatingIP(self._provider, self.gateway, fip)
+                if fip else None)
 
 
     def list(self, limit=None, marker=None):
     def list(self, limit=None, marker=None):
         max_result = limit if limit is not None and limit < 500 else 500
         max_result = limit if limit is not None and limit < 500 else 500
@@ -1469,7 +1536,7 @@ class GCEFloatingIPContainer(BaseFloatingIPContainer):
                                   maxResults=max_result,
                                   maxResults=max_result,
                                   pageToken=marker)
                                   pageToken=marker)
                             .execute())
                             .execute())
-            ips = [GCEFloatingIP(self._provider, ip)
+            ips = [GCEFloatingIP(self._provider, self.gateway, ip)
                    for ip in response.get('items', [])]
                    for ip in response.get('items', [])]
             if len(ips) > max_result:
             if len(ips) > max_result:
                 cb.log.warning('Expected at most %d results; got %d',
                 cb.log.warning('Expected at most %d results; got %d',
@@ -1504,8 +1571,9 @@ class GCEFloatingIPContainer(BaseFloatingIPContainer):
 class GCEFloatingIP(BaseFloatingIP):
 class GCEFloatingIP(BaseFloatingIP):
     _DEAD_INSTANCE = 'dead instance'
     _DEAD_INSTANCE = 'dead instance'
 
 
-    def __init__(self, provider, floating_ip):
+    def __init__(self, provider, gateway, floating_ip):
         super(GCEFloatingIP, self).__init__(provider)
         super(GCEFloatingIP, self).__init__(provider)
+        self._gateway = gateway
         self._ip = floating_ip
         self._ip = floating_ip
         self._process_ip_users()
         self._process_ip_users()
 
 
@@ -1561,11 +1629,10 @@ class GCEFloatingIP(BaseFloatingIP):
         self._provider.wait_for_operation(response, region=self.region_name)
         self._provider.wait_for_operation(response, region=self.region_name)
 
 
     def refresh(self):
     def refresh(self):
-        self._ip = self._provider.get_resource('addresses', self.id)
-        if not self._ip:
-            self._ip = {'status': 'UNKNOWN'}
-        else:
-            self._process_ip_users()
+        fip = self.gateway.floating_ips.get(self.id)
+        # pylint:disable=protected-access
+        self._ip = fip._ip
+        self._process_ip_users()
 
 
     def _process_ip_users(self):
     def _process_ip_users(self):
         self._rule = None
         self._rule = None
@@ -1642,9 +1709,13 @@ class GCERouter(BaseRouter):
         return parsed_url.parameters['region']
         return parsed_url.parameters['region']
 
 
     def refresh(self):
     def refresh(self):
-        self._router = self._provider.get_resource('routers', self.id)
-        if not self._router:
-            self._router = {'status': 'UNKNOWN'}
+        router = self._provider.networking.routers.get(self.id)
+        if router:
+            # pylint:disable=protected-access
+            self._router = router._router
+        else:
+            # router no longer exists
+            self._router['status'] = RouterState.UNKNOWN
 
 
     @property
     @property
     def state(self):
     def state(self):
@@ -1774,30 +1845,14 @@ class GCESubnet(BaseSubnet):
 
 
     @property
     @property
     def label(self):
     def label(self):
-        return self._subnet.get('description')
+        tag_name = "_".join(["subnet", self.name, "label"])
+        return helpers.get_metadata_item_value(self._provider, tag_name)
 
 
     @label.setter
     @label.setter
     def label(self, value):
     def label(self, value):
         self.assert_valid_resource_label(value)
         self.assert_valid_resource_label(value)
-        request_body = {
-            'description': value.replace(' ', '_').lower(),
-            'fingerprint': self._subnet.get('fingerprint')
-        }
-        try:
-            (self._provider
-                 .gce_compute
-                 .subnetworks()
-                 .patch(project=self._provider.project_name,
-                        region=self.region_name,
-                        subnetwork=self.name,
-                        body=request_body)
-                 .execute())
-        except Exception as e:
-            cb.log.warning('Exception while setting subnet label: %s. '
-                           'Check for invalid characters in label. '
-                           'Should conform to RFC1035.', e)
-            raise e
-        self.refresh()
+        tag_name = "_".join(["subnet", self.name, "label"])
+        helpers.modify_or_add_metadata_item(self._provider, tag_name, value)
 
 
     @property
     @property
     def cidr_block(self):
     def cidr_block(self):
@@ -1834,9 +1889,13 @@ class GCESubnet(BaseSubnet):
         return SubnetState.AVAILABLE
         return SubnetState.AVAILABLE
 
 
     def refresh(self):
     def refresh(self):
-        self._subnet = self._provider.get_resource('subnetworks', self.id)
-        if not self._subnet:
-            self._subnet = {'status': 'UNKNOWN'}
+        subnet = self._provider.networking.subnets.get(self.id)
+        if subnet:
+            # pylint:disable=protected-access
+            self._subnet = subnet._subnet
+        else:
+            # subnet no longer exists
+            self._subnet['status'] = SubnetState.UNKNOWN
 
 
 
 
 class GCEVolume(BaseVolume):
 class GCEVolume(BaseVolume):
@@ -2048,9 +2107,13 @@ class GCEVolume(BaseVolume):
         Refreshes the state of this volume by re-querying the cloud provider
         Refreshes the state of this volume by re-querying the cloud provider
         for its latest state.
         for its latest state.
         """
         """
-        self._volume = self._provider.get_resource('disks', self.id)
-        if not self._volume:
-            self._volume = {'status': 'UNKNOWN'}
+        vol = self._provider.storage.volumes.get(self.id)
+        if vol:
+            # pylint:disable=protected-access
+            self._volume = vol._volume
+        else:
+            # volume no longer exists
+            self._volume['status'] = VolumeState.UNKNOWN
 
 
 
 
 class GCESnapshot(BaseSnapshot):
 class GCESnapshot(BaseSnapshot):
@@ -2153,9 +2216,13 @@ class GCESnapshot(BaseSnapshot):
         Refreshes the state of this snapshot by re-querying the cloud provider
         Refreshes the state of this snapshot by re-querying the cloud provider
         for its latest state.
         for its latest state.
         """
         """
-        self._snapshot = self._provider.get_resource('snapshots', self.id)
-        if not self._snapshot:
-            self._snapshot = {'status': 'UNKNOWN'}
+        snap = self._provider.storage.snapshots.get(self.id)
+        if snap:
+            # pylint:disable=protected-access
+            self._snapshot = snap._snapshot
+        else:
+            # snapshot no longer exists
+            self._snapshot['status'] = SnapshotState.UNKNOWN
 
 
     def delete(self):
     def delete(self):
         """
         """
@@ -2284,6 +2351,7 @@ class GCSObject(BaseBucketObject):
                                               url_encoded_signature))
                                               url_encoded_signature))
 
 
     def refresh(self):
     def refresh(self):
+        # pylint:disable=protected-access
         self._obj = self.bucket.objects.get(self.id)._obj
         self._obj = self.bucket.objects.get(self.id)._obj
 
 
 
 

+ 26 - 33
cloudbridge/cloud/providers/gce/services.py

@@ -252,6 +252,7 @@ class GCEVMFirewallService(BaseVMFirewallService):
         fw.rules.create_with_priority(
         fw.rules.create_with_priority(
                 direction=TrafficDirection.OUTBOUND, protocol='tcp',
                 direction=TrafficDirection.OUTBOUND, protocol='tcp',
                 priority=65534, cidr='0.0.0.0/0')
                 priority=65534, cidr='0.0.0.0/0')
+        fw.label = label
         return fw
         return fw
 
 
     def find(self, name, limit=None, marker=None):
     def find(self, name, limit=None, marker=None):
@@ -532,8 +533,7 @@ class GCEInstanceService(BaseInstanceService):
             'name': GCEInstance._generate_name_from_label(label, 'cb-inst'),
             'name': GCEInstance._generate_name_from_label(label, 'cb-inst'),
             'machineType': vm_type.resource_url,
             'machineType': vm_type.resource_url,
             'disks': disks,
             'disks': disks,
-            'networkInterfaces': [network_interface],
-            'labels': {'cblabel': label.replace(' ', '_').lower()}
+            'networkInterfaces': [network_interface]
         }
         }
 
 
         if vm_firewalls and isinstance(vm_firewalls, list):
         if vm_firewalls and isinstance(vm_firewalls, list):
@@ -560,7 +560,11 @@ class GCEInstanceService(BaseInstanceService):
             return None
             return None
         instance_id = operation.get('targetLink')
         instance_id = operation.get('targetLink')
         self.provider.wait_for_operation(operation, zone=zone_name)
         self.provider.wait_for_operation(operation, zone=zone_name)
-        return self.get(instance_id)
+        cb_inst = self.get(instance_id)
+        cb_inst.label = label
+        if key_pair:
+            cb_inst.key_pair_id = key_pair
+        return cb_inst
 
 
     def get(self, instance_id):
     def get(self, instance_id):
         """
         """
@@ -714,6 +718,7 @@ class GCENetworkService(BaseNetworkService):
         False: For creating a custom mode VPC network. Subnetworks should be
         False: For creating a custom mode VPC network. Subnetworks should be
                created manually.
                created manually.
         """
         """
+        GCENetwork.assert_valid_resource_label(label)
         if create_subnetworks is not None and cidr_block is not None:
         if create_subnetworks is not None and cidr_block is not None:
             cb.log.warning('cidr_block is ignored in non-legacy networks. '
             cb.log.warning('cidr_block is ignored in non-legacy networks. '
                            'Auto mode networks use the default CIDR of '
                            'Auto mode networks use the default CIDR of '
@@ -737,13 +742,7 @@ class GCENetworkService(BaseNetworkService):
             if 'error' in response:
             if 'error' in response:
                 return None
                 return None
             self.provider.wait_for_operation(response)
             self.provider.wait_for_operation(response)
-            gce_net = (self.provider
-                       .gce_compute
-                       .networks()
-                       .get(project=self.provider.project_name,
-                            network=name)
-                       .execute())
-            return gce_net
+            return self.get(name)
         except googleapiclient.errors.HttpError as http_error:
         except googleapiclient.errors.HttpError as http_error:
             cb.log.warning('googleapiclient.errors.HttpError: %s', http_error)
             cb.log.warning('googleapiclient.errors.HttpError: %s', http_error)
             return None
             return None
@@ -753,9 +752,7 @@ class GCENetworkService(BaseNetworkService):
         Creates an auto mode VPC network with default subnets. It is possible
         Creates an auto mode VPC network with default subnets. It is possible
         to add additional subnets later.
         to add additional subnets later.
         """
         """
-        GCENetwork.assert_valid_resource_label(label)
-        gce_net = self._create(label, cidr_block, False)
-        cb_net = GCENetwork(self.provider, gce_net)
+        cb_net = self._create(label, cidr_block, False)
         cb_net.label = label
         cb_net.label = label
         return cb_net
         return cb_net
 
 
@@ -800,14 +797,11 @@ class GCERouterService(BaseRouterService):
     def get(self, router_id):
     def get(self, router_id):
         return self._get_in_region(router_id)
         return self._get_in_region(router_id)
 
 
-    def find(self, name, limit=None, marker=None):
-        routers = []
-        for region in self.provider.compute.regions.list():
-            router = self._get_in_region(name, region.name)
-            if router:
-                routers.append(router)
-        return ClientPagedResultList(self.provider, routers, limit=limit,
-                                     marker=marker)
+    def find(self, **kwargs):
+        obj_list = self
+        filters = ['name', 'label']
+        matches = cb_helpers.generic_find(filters, kwargs, obj_list)
+        return ClientPagedResultList(self._provider, list(matches))
 
 
     def list(self, limit=None, marker=None):
     def list(self, limit=None, marker=None):
         region = self.provider.region_name
         region = self.provider.region_name
@@ -947,8 +941,7 @@ class GCESubnetService(BaseSubnetService):
         body = {'ipCidrRange': cidr_block,
         body = {'ipCidrRange': cidr_block,
                 'name': name,
                 'name': name,
                 'network': network.resource_url,
                 'network': network.resource_url,
-                'region': region_name,
-                'labels': {'cblabel': label.replace(' ', '_').lower()}
+                'region': region_name
                 }
                 }
         try:
         try:
             response = (self.provider
             response = (self.provider
@@ -963,7 +956,9 @@ class GCESubnetService(BaseSubnetService):
                                response['error'])
                                response['error'])
                 return None
                 return None
             self.provider.wait_for_operation(response, region=region_name)
             self.provider.wait_for_operation(response, region=region_name)
-            return self.get(name)
+            cb_subnet = self.get(name)
+            cb_subnet.label = label
+            return cb_subnet
         except googleapiclient.errors.HttpError as http_error:
         except googleapiclient.errors.HttpError as http_error:
             cb.log.warning('googleapiclient.errors.HttpError: %s', http_error)
             cb.log.warning('googleapiclient.errors.HttpError: %s', http_error)
             return None
             return None
@@ -1126,7 +1121,6 @@ class GCEVolumeService(BaseVolumeService):
             'type': 'zones/{0}/diskTypes/{1}'.format(zone_name, 'pd-standard'),
             'type': 'zones/{0}/diskTypes/{1}'.format(zone_name, 'pd-standard'),
             'sourceSnapshot': snapshot_id,
             'sourceSnapshot': snapshot_id,
             'description': description,
             'description': description,
-            'labels': {'cblabel': label.replace(' ', '_').lower()}
         }
         }
         operation = (self.provider
         operation = (self.provider
                          .gce_compute
                          .gce_compute
@@ -1136,7 +1130,9 @@ class GCEVolumeService(BaseVolumeService):
                              zone=zone_name,
                              zone=zone_name,
                              body=disk_body)
                              body=disk_body)
                          .execute())
                          .execute())
-        return self.get(operation.get('targetLink'))
+        cb_vol = self.get(operation.get('targetLink'))
+        cb_vol.label = label
+        return cb_vol
 
 
 
 
 class GCESnapshotService(BaseSnapshotService):
 class GCESnapshotService(BaseSnapshotService):
@@ -1204,8 +1200,7 @@ class GCESnapshotService(BaseSnapshotService):
         volume_name = volume.name if isinstance(volume, GCEVolume) else volume
         volume_name = volume.name if isinstance(volume, GCEVolume) else volume
         snapshot_body = {
         snapshot_body = {
             "name": name,
             "name": name,
-            "description": description,
-            "labels": {"cblabel": label}
+            "description": description
         }
         }
         operation = (self.provider
         operation = (self.provider
                          .gce_compute
                          .gce_compute
@@ -1219,11 +1214,9 @@ class GCESnapshotService(BaseSnapshotService):
             return None
             return None
         self.provider.wait_for_operation(operation,
         self.provider.wait_for_operation(operation,
                                          zone=self.provider.default_zone)
                                          zone=self.provider.default_zone)
-        snapshots = self.provider.storage.snapshots.find(label=label)
-        if snapshots:
-            return snapshots[0]
-        else:
-            return None
+        cb_snap = self.get(name)
+        cb_snap.label = label
+        return cb_snap
 
 
 
 
 class GCSBucketService(BaseBucketService):
 class GCSBucketService(BaseBucketService):

+ 1 - 1
setup.py

@@ -41,7 +41,7 @@ REQS_AZURE = ['msrest>=0.5.4,<0.6',
               'azure-storage-blob==1.3.1',
               'azure-storage-blob==1.3.1',
               'azure-cosmosdb-table==1.0.4',
               'azure-cosmosdb-table==1.0.4',
               'pysftp==0.2.9']
               'pysftp==0.2.9']
-REQS_GCP = ['google-api-python-client', 'oauth2client', 'retrying']
+REQS_GCP = ['google-api-python-client', 'oauth2client']
 REQS_OPENSTACK = [
 REQS_OPENSTACK = [
     'openstacksdk>=0.12.0,<=0.17',
     'openstacksdk>=0.12.0,<=0.17',
     'python-novaclient>=7.0.0,<=11.0',
     'python-novaclient>=7.0.0,<=11.0',