Sfoglia il codice sorgente

Merge branch 'master' into azure_dev_v4

jatin 8 anni fa
parent
commit
e05f72fea2

+ 2 - 2
cloudbridge/cloud/base/services.py

@@ -223,7 +223,7 @@ class BaseFloatingIPService(
 
 
 class BaseRouterService(
-    BasePageableObjectMixin, RouterService, BaseCloudService):
+     BasePageableObjectMixin, RouterService, BaseCloudService):
     def __init__(self, provider):
         super(BaseRouterService, self).__init__(provider)
 
@@ -240,6 +240,6 @@ class BaseRouterService(
 
 
 class BaseGatewayService(
-    GatewayService, BaseCloudService):
+     GatewayService, BaseCloudService):
     def __init__(self, provider):
         super(BaseGatewayService, self).__init__(provider)

+ 2 - 2
cloudbridge/cloud/providers/aws/services.py

@@ -567,7 +567,7 @@ class AWSRegionService(BaseRegionService):
         regions = [
             AWSRegion(self.provider, region) for region in
             self.provider.ec2_conn.meta.client.describe_regions()
-                .get('Regions', [])]
+            .get('Regions', [])]
         return ClientPagedResultList(self.provider, regions,
                                      limit=limit, marker=marker)
 
@@ -699,7 +699,7 @@ class AWSSubnetService(BaseSubnetService):
             # pylint:disable=protected-access
             for tag in sn._subnet.tags or {}:
                 if (tag.get('Key') == 'Name' and
-                            tag.get('Value') == AWSSubnet.CB_DEFAULT_SUBNET_NAME):
+                        tag.get('Value') == AWSSubnet.CB_DEFAULT_SUBNET_NAME):
                     return sn
         # No provider-default Subnet exists, try to create it (net + subnets)
         default_net = self.provider.networking.networks.create(

+ 14 - 11
cloudbridge/cloud/providers/azure/azure_client.py

@@ -1,3 +1,4 @@
+import datetime
 import logging
 
 from io import BytesIO
@@ -205,9 +206,11 @@ class AzureClient(object):
         self.blob_service.delete_blob(container_name, blob_name)
 
     def get_blob_url(self, container_name, blob_name, expiry_time):
+        expiry_date = datetime.datetime.now() + datetime.timedelta(
+            seconds=expiry_time)
         sas = self.blob_service.generate_blob_shared_access_signature(
             container_name, blob_name, permission=BlobPermissions.READ,
-            expiry=expiry_time)
+            expiry=expiry_date)
         return self.blob_service.make_blob_url(container_name, blob_name,
                                                sas_token=sas)
 
@@ -509,10 +512,10 @@ class AzureClient(object):
 
             result_create = self.network_management_client. \
                 subnets.create_or_update(
-                self.resource_group,
-                network_name,
-                subnet_name,
-                subnet_info)
+                 self.resource_group,
+                 network_name,
+                 subnet_name,
+                 subnet_info)
             subnet_info = result_create.result()
 
         return subnet_info
@@ -531,10 +534,10 @@ class AzureClient(object):
 
             result_create = self.network_management_client. \
                 subnets.create_or_update(
-                self.resource_group,
-                network_name,
-                subnet_name,
-                subnet_info)
+                 self.resource_group,
+                 network_name,
+                 subnet_name,
+                 subnet_info)
             subnet_info = result_create.result()
 
         return subnet_info
@@ -550,8 +553,8 @@ class AzureClient(object):
     def create_route_table(self, route_table_name, params):
         return self.network_management_client. \
             route_tables.create_or_update(
-            self.resource_group,
-            route_table_name, params).result()
+             self.resource_group,
+             route_table_name, params).result()
 
     def update_route_table_tags(self, route_table_name, tags):
         self.network_management_client.route_tables. \

+ 4 - 4
cloudbridge/cloud/providers/azure/resources.py

@@ -463,7 +463,7 @@ class AzureVolume(BaseVolume):
     def _update_state(self):
         if not self._volume.provisioning_state == 'Succeeded':
             self._state = self._volume.provisioning_state
-        elif self._volume.owner_id:
+        elif self._volume.managed_by:
             self._state = 'Attached'
         else:
             self._state = 'Unattached'
@@ -544,9 +544,9 @@ class AzureVolume(BaseVolume):
         to the BaseAttachmentInfo
         :return:
         """
-        if self._volume.owner_id:
+        if self._volume.managed_by:
             url_params = azure_helpers.parse_url(INSTANCE_RESOURCE_ID,
-                                                 self._volume.owner_id)
+                                                 self._volume.managed_by)
             return BaseAttachmentInfo(self,
                                       url_params.get(VM_NAME),
                                       None)
@@ -708,7 +708,7 @@ class AzureSnapshot(BaseSnapshot):
     def volume_id(self):
         url_params = azure_helpers. \
             parse_url(VOLUME_RESOURCE_ID,
-                      self._snapshot.creation_data.source_uri)
+                      self._snapshot.creation_data.source_resource_id)
         return url_params.get(VOLUME_NAME)
 
     @property

+ 163 - 71
cloudbridge/cloud/providers/azure/services.py

@@ -6,10 +6,11 @@ from azure.common import AzureException
 
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.base.services import BaseBlockStoreService, \
-    BaseComputeService, BaseImageService, BaseInstanceService, \
-    BaseInstanceTypesService, BaseKeyPairService, \
-    BaseNetworkService, BaseObjectStoreService, \
-    BaseRegionService, BaseSecurityGroupService, BaseSecurityService, \
+    BaseComputeService, BaseGatewayService, BaseImageService, \
+    BaseInstanceService, BaseInstanceTypesService, \
+    BaseKeyPairService, BaseNetworkService, BaseNetworkingService, \
+    BaseObjectStoreService, BaseRegionService, BaseRouterService, \
+    BaseSecurityGroupService, BaseSecurityService, \
     BaseSnapshotService, BaseSubnetService, BaseVolumeService
 from cloudbridge.cloud.interfaces import InvalidConfigurationException
 
@@ -22,7 +23,8 @@ from cloudbridge.cloud.providers.azure import helpers as azure_helpers
 from msrestazure.azure_exceptions import CloudError
 
 from .resources import AzureBucket, AzureFloatingIP, \
-    AzureInstance, AzureInstanceType, AzureKeyPair, \
+    AzureInstance, AzureInstanceType, \
+    AzureInternetGateway, AzureKeyPair, \
     AzureLaunchConfig, AzureMachineImage, \
     AzureNetwork, AzureRegion, AzureRouter, AzureSecurityGroup, \
     AzureSnapshot, AzureSubnet, AzureVolume
@@ -106,6 +108,7 @@ class AzureSecurityGroupService(BaseSecurityGroupService):
         :rtype: ``object`` of :class:`.SecurityGroup`
         :return:  A SecurityGroup instance or ``None`` if one was not created.
         """
+        AzureSecurityGroup.assert_valid_resource_name(name)
         parameters = {"location": self.provider.region_name,
                       'tags': {'Name': name}}
 
@@ -159,7 +162,7 @@ class AzureKeyPairService(BaseKeyPairService):
 
     def get(self, key_pair_id):
         try:
-            key_pair = self.provider.azure_client. \
+            key_pair = self.provider.azure_client.\
                 get_public_key(key_pair_id)
 
             if key_pair:
@@ -172,7 +175,7 @@ class AzureKeyPairService(BaseKeyPairService):
     def list(self, limit=None, marker=None):
         key_pairs = [AzureKeyPair(self.provider, key_pair) for key_pair in
                      self.provider.azure_client.
-                         list_public_keys(AzureKeyPairService.PARTITION_KEY)]
+                     list_public_keys(AzureKeyPairService.PARTITION_KEY)]
         return ClientPagedResultList(self.provider, key_pairs, limit, marker)
 
     def find(self, name, limit=None, marker=None):
@@ -182,6 +185,7 @@ class AzureKeyPairService(BaseKeyPairService):
                                      limit, marker)
 
     def create(self, name):
+        AzureKeyPair.assert_valid_resource_name(name)
 
         key_pair = self.get(name)
 
@@ -192,11 +196,11 @@ class AzureKeyPairService(BaseKeyPairService):
         private_key_str, public_key_str = azure_helpers.gen_key_pair()
 
         entity = {
-            'PartitionKey': AzureKeyPairService.PARTITION_KEY,
-            'RowKey': str(uuid.uuid4()),
-            'Name': name,
-            'Key': public_key_str
-        }
+                  'PartitionKey': AzureKeyPairService.PARTITION_KEY,
+                  'RowKey': str(uuid.uuid4()),
+                  'Name': name,
+                  'Key': public_key_str
+                 }
 
         self.provider.azure_client.create_public_key(entity)
 
@@ -247,6 +251,7 @@ class AzureObjectStoreService(BaseObjectStoreService):
         """
         Create a new bucket.
         """
+        AzureBucket.assert_valid_resource_name(name)
         bucket = self.provider.azure_client.create_container(name.lower())
         return AzureBucket(self.provider, bucket)
 
@@ -308,6 +313,7 @@ class AzureVolumeService(BaseVolumeService):
         """
         Creates a new volume.
         """
+        AzureVolume.assert_valid_resource_name(name)
         zone_id = zone.id if isinstance(zone, PlacementZone) else zone
         snapshot = (self.provider.block_store.snapshots.get(snapshot)
                     if snapshot and isinstance(snapshot, str) else snapshot)
@@ -386,6 +392,7 @@ class AzureSnapshotService(BaseSnapshotService):
         """
         Creates a new snapshot of a given volume.
         """
+        AzureSnapshot.assert_valid_resource_name(name)
         volume = (self.provider.block_store.volumes.get(volume)
                   if isinstance(volume, str) else volume)
 
@@ -446,7 +453,10 @@ class AzureInstanceService(BaseInstanceService):
                key_pair=None, security_groups=None, user_data=None,
                launch_config=None, **kwargs):
 
-        instance_name = "{0}-{1}".format(name, uuid.uuid4().hex[:6])
+        instance_name = name.replace("_", "-") if name \
+            else "{0} - {1}".format("cb", uuid.uuid4())
+
+        AzureInstance.assert_valid_resource_name(instance_name)
 
         # Key_pair is mandatory in azure and it should not be None.
         if key_pair:
@@ -463,9 +473,9 @@ class AzureInstanceService(BaseInstanceService):
             isinstance(instance_type, InstanceType) else instance_type
 
         if not subnet:
-            subnet = self.provider.network.subnets.get_or_create_default()
+            subnet = self.provider.networking.subnets.get_or_create_default()
         else:
-            subnet = (self.provider.network.subnets.get(subnet)
+            subnet = (self.provider.networking.subnets.get(subnet)
                       if isinstance(subnet, str) else subnet)
 
         zone_id = zone.id if isinstance(zone, PlacementZone) else zone
@@ -483,15 +493,15 @@ class AzureInstanceService(BaseInstanceService):
             root_disk_size = None
 
         nic_params = {
-            'location': self._provider.region_name,
-            'ip_configurations': [{
-                'name': instance_name + '_ip_config',
-                'private_ip_allocation_method': 'Dynamic',
-                'subnet': {
-                    'id': subnet_id
-                }
-            }]
-        }
+                'location': self._provider.region_name,
+                'ip_configurations': [{
+                    'name': instance_name + '_ip_config',
+                    'private_ip_allocation_method': 'Dynamic',
+                    'subnet': {
+                        'id': subnet_id
+                    }
+                }]
+            }
 
         if security_group_id:
             nic_params['network_security_group'] = {
@@ -503,8 +513,8 @@ class AzureInstanceService(BaseInstanceService):
         )
         # #! indicates shell script
         ud = '#cloud-config\n' + user_data \
-            if user_data and not user_data.startswith('#!') \
-               and not user_data.startswith('#cloud-config') else user_data
+            if user_data and not user_data.startswith('#!')\
+            and not user_data.startswith('#cloud-config') else user_data
 
         params = {
             'location': zone_id or self._provider.region_name,
@@ -512,16 +522,16 @@ class AzureInstanceService(BaseInstanceService):
                 'admin_username': self.provider.vm_default_user_name,
                 'computer_name': instance_name,
                 'linux_configuration': {
-                    "disable_password_authentication": True,
-                    "ssh": {
-                        "public_keys": [{
-                            "path":
-                                "/home/{}/.ssh/authorized_keys".format(
-                                    self.provider.vm_default_user_name),
-                            "key_data": key_pair._key_pair.Key
-                        }]
-                    }
-                }
+                             "disable_password_authentication": True,
+                             "ssh": {
+                                 "public_keys": [{
+                                      "path":
+                                      "/home/{}/.ssh/authorized_keys".format(
+                                          self.provider.vm_default_user_name),
+                                      "key_data": key_pair._key_pair.Key
+                                     }]
+                                   }
+                           }
             },
             'hardware_profile': {
                 'vm_size': instance_size
@@ -593,12 +603,12 @@ class AzureInstanceService(BaseInstanceService):
                 security_group_id = security_groups[0].resource_id
             else:
                 security_groups_ids = security_groups
-                seuciry_group = self.provider.security. \
+                seuciry_group = self.provider.security.\
                     security_groups.get(security_groups[0])
                 security_group_id = seuciry_group.resource_id
 
             if len(security_groups) > 1:
-                new_sg = self.provider.security.security_groups. \
+                new_sg = self.provider.security.security_groups.\
                     create('{0}-sg'.format(name), 'Merge security groups {0}'.
                            format(','.join(security_groups_ids)))
 
@@ -637,7 +647,7 @@ class AzureInstanceService(BaseInstanceService):
             # This method uses the azure tags functionality to store
             # the  delete_on_terminate option when the virtual machine
             # is deleted, we parse the tags and delete accordingly
-            self.provider.azure_client. \
+            self.provider.azure_client.\
                 update_disk_tags(volume.id, volume.tags)
 
         for device in launch_config.block_devices:
@@ -763,6 +773,7 @@ class AzureImageService(BaseImageService):
 
 
 class AzureInstanceTypesService(BaseInstanceTypesService):
+
     def __init__(self, provider):
         super(AzureInstanceTypesService, self).__init__(provider)
 
@@ -781,10 +792,34 @@ class AzureInstanceTypesService(BaseInstanceTypesService):
                                      limit=limit, marker=marker)
 
 
+class AzureNetworkingService(BaseNetworkingService):
+    def __init__(self, provider):
+        super(AzureNetworkingService, self).__init__(provider)
+        self._network_service = AzureNetworkService(self.provider)
+        self._subnet_service = AzureSubnetService(self.provider)
+        self._router_service = AzureRouterService(self.provider)
+        self._gateway_service = AzureGatewayService(self.provider)
+
+    @property
+    def networks(self):
+        return self._network_service
+
+    @property
+    def subnets(self):
+        return self._subnet_service
+
+    @property
+    def routers(self):
+        return self._router_service
+
+    @property
+    def gateways(self):
+        return self._gateway_service
+
+
 class AzureNetworkService(BaseNetworkService):
     def __init__(self, provider):
         super(AzureNetworkService, self).__init__(provider)
-        self._subnet_svc = AzureSubnetService(self.provider)
 
     def get(self, network_id):
         try:
@@ -805,25 +840,33 @@ class AzureNetworkService(BaseNetworkService):
         return ClientPagedResultList(self.provider, networks,
                                      limit=limit, marker=marker)
 
-    def create(self, name=None):
+    def find(self, name, limit=None, marker=None):
+        filters = {'Name': name}
+        networks = [AzureNetwork(self.provider, network)
+                    for network in azure_helpers.filter(
+                self.provider.azure_client.list_networks(), filters)]
+        return ClientPagedResultList(self.provider, networks,
+                                     limit=limit, marker=marker)
+
+    def create(self, name, cidr_block):
         # Azure requires CIDR block to be specified when creating a network
         # so set a default one and use the largest allowed netmask.
         network_name = AzureNetwork.CB_DEFAULT_NETWORK_NAME
         if name:
             network_name = "{0}-{1}".format(name, uuid.uuid4().hex[:6])
 
+        AzureNetwork.assert_valid_resource_name(network_name)
+
         params = {
             'location': self.provider.azure_client.region_name,
             'address_space': {
-                'address_prefixes': ['10.0.0.0/16']
+                'address_prefixes': [cidr_block]
             },
             'tags': {'Name': name or AzureNetwork.CB_DEFAULT_NETWORK_NAME}
         }
-
         self.provider.azure_client.create_network(network_name, params)
         network = self.provider.azure_client.get_network(network_name)
         cb_network = AzureNetwork(self.provider, network)
-
         return cb_network
 
     def create_floating_ip(self):
@@ -834,32 +877,20 @@ class AzureNetworkService(BaseNetworkService):
             'public_ip_allocation_method': 'Static'
         }
 
-        floating_ip = self.provider.azure_client. \
+        floating_ip = self.provider.azure_client.\
             create_floating_ip(public_ip_address_name, public_ip_parameters)
         return AzureFloatingIP(self.provider, floating_ip)
 
     @property
-    def subnets(self):
-        return self._subnet_svc
-
-    def floating_ips(self, network_id=None):
+    def floating_ips(self):
         """
                List all floating ips.
         """
         floating_ips = [AzureFloatingIP(self.provider, floating_ip)
                         for floating_ip in self.provider.azure_client.
-                            list_floating_ips()]
-
+                        list_floating_ips()]
         return ClientPagedResultList(self.provider, floating_ips)
 
-    def routers(self):
-        return ClientPagedResultList(self.provider, [])
-
-    def create_router(self, name=None):
-        ar = AzureRouter(self.provider, None)
-        ar.name = name
-        return ar
-
     def delete(self, network_id):
         """
                 Delete an existing network.
@@ -897,6 +928,7 @@ class AzureRegionService(BaseRegionService):
 
 
 class AzureSubnetService(BaseSubnetService):
+
     def __init__(self, provider):
         super(AzureSubnetService, self).__init__(provider)
 
@@ -912,7 +944,9 @@ class AzureSubnetService(BaseSubnetService):
         """
         try:
             subnet_id_parts = subnet_id.split('|$|')
-            azure_subnet = self.provider.azure_client. \
+            if (len(subnet_id_parts) != 2):
+                return None
+            azure_subnet = self.provider.azure_client.\
                 get_subnet(subnet_id_parts[0], subnet_id_parts[1])
             return AzureSubnet(self.provider,
                                azure_subnet) if azure_subnet else None
@@ -949,6 +983,7 @@ class AzureSubnetService(BaseSubnetService):
         """
         Create subnet
         """
+        AzureSubnet.assert_valid_resource_name(name)
         network_id = network.id \
             if isinstance(network, Network) else network
 
@@ -957,14 +992,14 @@ class AzureSubnetService(BaseSubnetService):
         else:
             subnet_name = name
 
-        subnet_info = self.provider.azure_client \
+        subnet_info = self.provider.azure_client\
             .create_subnet(
-            network_id,
-            subnet_name,
-            {
-                'address_prefix': cidr_block
-            }
-        )
+                            network_id,
+                            subnet_name,
+                            {
+                                'address_prefix': cidr_block
+                            }
+                          )
 
         return AzureSubnet(self.provider, subnet_info)
 
@@ -987,18 +1022,20 @@ class AzureSubnetService(BaseSubnetService):
             return AzureSubnet(self.provider, subnet)
 
         # No provider-default Subnet exists, try to create it (net + subnets)
+        default_net_name = AzureNetwork.CB_DEFAULT_NETWORK_NAME
         try:
             network = self.provider.azure_client \
-                .get_network(AzureNetwork.CB_DEFAULT_NETWORK_NAME)
+                .get_network(default_net_name)
         except CloudError:
             # Azure raises the cloud error if the resource not available
             pass
 
         if not network:
-            self.provider.network.create()
+            network = self.provider.networking.networks.create(
+                name=default_net_name, cidr_block='10.0.0.0/16')
 
         subnet = self.provider.azure_client.create_subnet(
-            AzureNetwork.CB_DEFAULT_NETWORK_NAME,
+            network.id,
             AzureSubnet.CB_DEFAULT_SUBNET_NAME,
             {'address_prefix': default_cdir}
         )
@@ -1013,10 +1050,65 @@ class AzureSubnetService(BaseSubnetService):
 
             subnet_id = subnet.id if isinstance(subnet, Subnet) else subnet
             subnet_id_parts = subnet_id.split('|$|')
-            self.provider.azure_client. \
+            self.provider.azure_client.\
                 delete_subnet(subnet_id_parts[0], subnet_id_parts[1])
             return True
         except CloudError as cloudError:
             # Azure raises the cloud error if the resource not available
             log.exception(cloudError.message)
             return False
+
+
+class AzureRouterService(BaseRouterService):
+    def __init__(self, provider):
+        super(AzureRouterService, self).__init__(provider)
+
+    def get(self, router_id):
+        try:
+            route = self.provider.azure_client.get_route_table(router_id)
+            return AzureRouter(self.provider, route)
+
+        except CloudError as cloudError:
+            # Azure raises the cloud error if the resource not available
+            log.exception(cloudError.message)
+            return None
+
+    def find(self, name, limit=None, marker=None):
+        filters = {'Name': name}
+        routes = [AzureRouter(self.provider, route)
+                  for route in azure_helpers.filter(
+                self.provider.azure_client.list_route_tables(), filters)]
+
+        return ClientPagedResultList(self.provider, routes,
+                                     limit=limit, marker=marker)
+
+    def list(self, limit=None, marker=None):
+        routes = [AzureRouter(self.provider, route)
+                  for route in
+                  self.provider.azure_client.list_route_tables()]
+        return ClientPagedResultList(self.provider,
+                                     routes,
+                                     limit=limit, marker=marker)
+
+    def create(self, name, network):
+        AzureRouter.assert_valid_resource_name(name)
+        parameters = {"location": self.provider.region_name,
+                      'tags': {'Name': name}}
+        route = self.provider.azure_client. \
+            create_route_table(name, parameters)
+        return AzureRouter(self.provider, route)
+
+
+class AzureGatewayService(BaseGatewayService):
+    def __init__(self, provider):
+        super(AzureGatewayService, self).__init__(provider)
+
+    def get_or_create_inet_gateway(self, name):
+        AzureInternetGateway.assert_valid_resource_name(name)
+
+        gateway = AzureInternetGateway(self.provider, None)
+        gateway.name = name
+        return gateway
+
+    def delete(self, gateway):
+        pass

+ 9 - 6
setup.py

@@ -24,12 +24,15 @@ REQS_BASE = [
     'retrying>=1.3.3'
 ]
 REQS_AWS = ['boto3']
-REQS_AZURE = ['azure-common==1.1.5',
-              'azure-mgmt-resource==1.0.0rc1',
-              'azure-mgmt-compute==1.0.0rc1',
-              'azure-mgmt-network==1.0.0rc1',
-              'azure-mgmt-storage==1.0.0rc1',
-              'azure-storage==0.34.0']
+REQS_AZURE = ['msrest>=0.4.7',
+              'msrestazure>=0.4.7',
+              'azure-common>=1.1.5',
+              'azure-mgmt-resource>=1.0.0rc1',
+              'azure-mgmt-compute>=1.0.0rc1',
+              'azure-mgmt-network>=1.0.0rc1',
+              'azure-mgmt-storage>=1.0.0rc1',
+              'azure-storage>=0.34.0',
+              'pysftp>=0.2.9']
 REQS_OPENSTACK = [
     'openstacksdk',
     'python-novaclient>=7.0.0',

+ 20 - 2
test/helpers/__init__.py

@@ -88,6 +88,14 @@ TEST_DATA_CONFIG = {
                                 '842b949c-ea76-48df-998d-8a41f2626243'),
         "vm_type": os.environ.get('CB_VM_TYPE_OS', 'm1.tiny'),
         "placement": os.environ.get('CB_PLACEMENT_OS', 'zone-r1'),
+    },
+    "AzureCloudProvider": {
+        "placement":
+            os.environ.get('CB_PLACEMENT_AZURE', 'eastus'),
+        "image":
+            os.environ.get('CB_IMAGE_AZURE', 'CbTest-Img'),
+        "instance_type":
+            os.environ.get('CB_INSTANCE_TYPE_AZURE', 'Standard_DS1_v2'),
     }
 }
 
@@ -124,17 +132,27 @@ def delete_test_network(network):
 def create_test_instance(
         provider, instance_name, subnet, launch_config=None,
         key_pair=None, vm_firewalls=None, user_data=None):
-    return provider.compute.instances.create(
+
+    kp = None
+    if not key_pair:
+        kp = provider.security.key_pairs.create(name=instance_name)
+
+    instance = provider.compute.instances.create(
         instance_name,
         get_provider_test_data(provider, 'image'),
         get_provider_test_data(provider, 'vm_type'),
         subnet=subnet,
         zone=get_provider_test_data(provider, 'placement'),
-        key_pair=key_pair,
+        key_pair=key_pair or kp,
         vm_firewalls=vm_firewalls,
         launch_config=launch_config,
         user_data=user_data)
 
+    if kp:
+        kp.delete()
+
+    return instance
+
 
 def get_test_instance(provider, name, key_pair=None, vm_firewalls=None,
                       subnet=None, user_data=None):

+ 2 - 1
test/test_image_service.py

@@ -35,7 +35,8 @@ class CloudImageServiceTestCase(ProviderTestBase):
             # check image size
             img.refresh()
             self.assertGreater(img.min_disk, 0, "Minimum disk"
-                                                " size required by image is invalid")
+                                                " size required by "
+                                                "image is invalid")
 
         with helpers.cleanup_action(lambda: helpers.cleanup_test_resources(
                 test_instance, net)):

+ 2 - 0
test/test_interface.py

@@ -57,6 +57,8 @@ class CloudInterfaceTestCase(ProviderTestBase):
         elif self.provider.PROVIDER_ID == 'openstack':
             cloned_config['os_username'] = "cb_dummy"
             cloned_config['os_password'] = "cb_dummy"
+        elif self.provider.PROVIDER_ID == 'azure':
+            cloned_config['azure_subscription_id'] = "cb_dummy"
 
         with self.assertRaises(ProviderConnectionException):
             cloned_provider = CloudProviderFactory().create_provider(