01000101 9 лет назад
Родитель
Сommit
22ad0d785b

+ 38 - 7
cloudbridge/cloud/providers/aws/resources.py

@@ -340,10 +340,10 @@ class AWSInstance(BaseInstance):
         """
         Get the security groups IDs associated with this instance.
         """
-        return set([
+        return list(set([
             group.get('GroupId') for group in
             self._ec2_instance.security_groups
-        ])
+        ]))
 
     @property
     def key_pair_name(self):
@@ -419,9 +419,12 @@ class AWSInstance(BaseInstance):
             # Silently fail for now
             return
 
-    def wait_until_exists(self, timeout=None, interval=None):
+    def wait_till_ready(self, timeout=None, interval=None):
         self._ec2_instance.wait_until_running()
 
+    def wait_till_exists(self, timeout=None, interval=None):
+        self._ec2_instance.wait_until_exists()
+
 
 class AWSVolume(BaseVolume):
 
@@ -562,6 +565,14 @@ class AWSVolume(BaseVolume):
             self._volume.status = 'unknown'
             return False
 
+    def wait_till_ready(self, timeout=None, interval=None):
+        self._provider.ec2_conn.meta.client.get_waiter('volume_available').wait(
+            VolumeIds=[self.id])
+        self.refresh()
+
+    def wait_till_deleted(self, timeout=None, interval=None):
+        self._provider.ec2_conn.meta.client.get_waiter('volume_deleted').wait(
+            VolumeIds=[self.id])
 
 class AWSSnapshot(BaseSnapshot):
 
@@ -664,6 +675,10 @@ class AWSSnapshot(BaseSnapshot):
         cb_vol.name = "Created from {0} ({1})".format(self.id, self.name)
         return cb_vol
 
+    def wait_till_ready(self, timeout=None, interval=None):
+        self._provider.ec2_conn.meta.client.get_waiter('snapshot_completed').wait(
+            SnapshotIds=[self.id])
+        self.refresh()
 
 class AWSKeyPair(BaseKeyPair):
 
@@ -1066,10 +1081,14 @@ class AWSNetwork(BaseNetwork):
             self._vpc.reload()
             return True
         except (EC2ResponseError, ValueError):
-            # The snapshot no longer exists and cannot be refreshed.
-            # set the status to unknown
+            # The network no longer exists and cannot be refreshed.
             return False
 
+    def wait_till_ready(self, timeout=None, interval=None):
+        self._provider.ec2_conn.meta.client.get_waiter('vpc_available').wait(
+            VpcIds=[self.id])
+        self.refresh()
+
 
 class AWSSubnet(BaseSubnet):
 
@@ -1117,6 +1136,19 @@ class AWSSubnet(BaseSubnet):
     def delete(self):
         return self._subnet.delete()
 
+    def refresh(self):
+        try:
+            self._subnet.reload()
+            return True
+        except (EC2ResponseError, ValueError):
+            # The resource no longer exists and cannot be refreshed.
+            return False
+
+    def wait_till_ready(self, timeout=None, interval=None):
+        self._provider.ec2_conn.meta.client.get_waiter('subnet_available').wait(
+            SubnetIds=[self.id])
+        self.refresh()
+
 
 class AWSFloatingIP(BaseFloatingIP):
 
@@ -1206,8 +1238,7 @@ class AWSRouter(BaseRouter):
             self._router.reload()
             return True
         except (EC2ResponseError, ValueError):
-            # The snapshot no longer exists and cannot be refreshed.
-            # set the status to unknown
+            # The resource no longer exists and cannot be refreshed.
             return False
 
     @property

+ 25 - 16
cloudbridge/cloud/providers/aws/services.py

@@ -251,9 +251,12 @@ class AWSSecurityGroupService(BaseSecurityGroupService):
 
     def create(self, name, description, network_id=None):
         """Creates a security group pair"""
-        res = self.iface.create('create_security_group',
-                                GroupName=name,
-                                Description=description)
+        res = self.iface.create('create_security_group', **{
+            k: v for k, v in {
+                'GroupName': name,
+                'Description': description,
+                'VpcId': network_id,
+            }.items() if v is not None})
         if not self.iface.wait_for_create(res.id, 'group-id'):
             return None
         return res
@@ -319,8 +322,8 @@ class AWSVolumeService(BaseVolumeService):
         if snapshot_id:
             params['SnapshotId'] = snapshot_id
         res = self.iface.create('create_volume', **params)
-        if not self.iface.wait_for_create(res.id, 'volume-id'):
-            return None
+        # Wait until ready to tag instance
+        res.wait_till_ready()
         res.name = name
         if res.description:
             res.description = description
@@ -332,7 +335,8 @@ class AWSVolumeService(BaseVolumeService):
         if res:
             res = res[0]
             self.iface.delete(res.id, 'volume-id')
-            return self.iface.wait_for_delete(res.id, 'volume-id')
+            # Wait until the volume is deleted
+            res.wait_till_deleted()
         return None
 
 class AWSSnapshotService(BaseSnapshotService):
@@ -359,8 +363,8 @@ class AWSSnapshotService(BaseSnapshotService):
         volume_id = volume.id if isinstance(volume, AWSVolume) else volume
         res = self.iface.create('create_snapshot',
                                 VolumeId=volume_id)
-        if not self.iface.wait_for_create(res.id, 'snapshot-id'):
-            return None
+        # Wait until ready to tag instance
+        res.wait_till_ready()
         res.name = name
         if res.description:
             res.description = description
@@ -537,7 +541,9 @@ class AWSInstanceService(BaseInstanceService):
         })
         if ress and len(ress) == 1:
             # Wait until the resource exists
-            ress[0].wait_until_exists()
+            ress[0].wait_till_exists()
+            # Tag the instance w/ the name
+            ress[0].name = name
             return ress[0]
         raise ValueError(
             'Expected a single object response, got a list: %s' % ress)
@@ -590,19 +596,19 @@ class AWSInstanceService(BaseInstanceService):
             if dev.is_volume:
                 # Generate the device path
                 bdm['DeviceName'] = \
-                    'dev/sd' + 'a1' if dev.is_root else next(next_letter)
-                bdm['Ebs'] = {
+                    '/dev/sd' + 'a1' if dev.is_root else next(next_letter)
+                bdm['Ebs'] = {k: v for k, v in {
                     'SnapshotId':
                         dev.source.id
                         if isinstance(dev.source, Snapshot) or
                         isinstance(dev.source, Volume) else None,
                     'VolumeSize': dev.size,
-                    'DeleteOnTerminate': dev.delete_on_terminate
-                }
+                    'DeleteOnTermination': dev.delete_on_terminate
+                }.items() if v is not None}
             else:  # device is ephemeral
                 bdm['VirtualName'] = 'ephemeral%s' % ephemeral_counter
             # Append the config
-            bdml.append(bdm)
+            bdml.append({k: v for k, v in bdm.items() if v is not None})
         return bdml
 
     def create_launch_config(self):
@@ -701,8 +707,8 @@ class AWSNetworkService(BaseNetworkService):
         default_cidr = '10.0.0.0/16'
         res = self.iface.create('create_vpc',
                                 CidrBlock=default_cidr)
-        if not self.iface.wait_for_create(res.id, 'vpc-id'):
-            return None
+        # Wait until ready to tag instance
+        res.wait_till_ready()
         if name:
             res.name = name
         return res
@@ -758,6 +764,9 @@ class AWSSubnetService(BaseSubnetService):
                 'CidrBlock': cidr_block,
                 'AvailabilityZone': zone,
             }.items() if v is not None})
+        # The resource must be "available" before tagging
+        # Wait until ready to tag instance
+        # res.wait_till_ready()
         if name:
             res.name = name
         return res

+ 1 - 1
test/test_compute_service.py

@@ -274,7 +274,7 @@ class CloudComputeServiceTestCase(ProviderTestBase):
             # TODO: This should be greater than the ami size or tests
             # will fail on actual infrastructure. Needs an image.size
             # method
-            size=2,
+            size=8,
             delete_on_terminate=True)
 
         # Add all available ephemeral devices

+ 0 - 2
test/test_image_service.py

@@ -35,8 +35,6 @@ class CloudImageServiceTestCase(ProviderTestBase):
                     [MachineImageState.UNKNOWN, MachineImageState.ERROR])
 
             with helpers.cleanup_action(lambda: cleanup_img(test_image)):
-                test_image.wait_till_ready()
-
                 self.assertTrue(
                     test_instance.id in repr(test_instance),
                     "repr(obj) should contain the object id so that the object"