Alexandru Mahmoud 8 anni fa
parent
commit
6328de9194

+ 61 - 47
cloudbridge/cloud/providers/azure/azure_client.py

@@ -16,43 +16,50 @@ from . import helpers as azure_helpers
 
 
 log = logging.getLogger(__name__)
 log = logging.getLogger(__name__)
 
 
-IMAGE_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/' \
-                    '{resourceGroupName}/providers/Microsoft.Compute/' \
-                    'images/{imageName}'
-NETWORK_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/' \
-                     '{resourceGroupName}/providers/Microsoft.Network' \
-                     '/virtualNetworks/{virtualNetworkName}'
-NETWORK_INTERFACE_RESOURCE_ID = '/subscriptions/{subscriptionId}/' \
-                                'resourceGroups/{resourceGroupName}' \
-                                '/providers/Microsoft.Network/' \
-                                'networkInterfaces/{networkInterfaceName}'
-PUBLIC_IP_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups' \
-                        '/{resourceGroupName}/providers/Microsoft.Network' \
-                        '/publicIPAddresses/{publicIpAddressName}'
-SNAPSHOT_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/' \
-                       '{resourceGroupName}/providers/Microsoft.Compute/' \
-                       'snapshots/{snapshotName}'
-SUBNET_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/' \
-                     '{resourceGroupName}/providers/Microsoft.Network' \
-                     '/virtualNetworks/{virtualNetworkName}/subnets' \
-                     '/{subnetName}'
-VM_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/' \
-                       '{resourceGroupName}/providers/Microsoft.Compute/' \
-                       'virtualMachines/{vmName}'
-VM_FIREWALL_RESOURCE_ID = '/subscriptions/{subscriptionId}/' \
-                             'resourceGroups/{resourceGroupName}/' \
-                             'providers/Microsoft.Network/' \
-                             'networkSecurityGroups/' \
-                             '{networkSecurityGroupName}'
-VM_FIREWALL_RULE_RESOURCE_ID = '/subscriptions/{subscriptionId}/' \
-                             'resourceGroups/{resourceGroupName}/' \
-                             'providers/Microsoft.Network/' \
-                             'networkSecurityGroups/' \
-                             '{networkSecurityGroupName}/' \
-                             'securityRules/{securityRuleName}'
-VOLUME_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/' \
+IMAGE_RESOURCE_ID = ['/subscriptions/{subscriptionId}/resourceGroups/' \
                      '{resourceGroupName}/providers/Microsoft.Compute/' \
                      '{resourceGroupName}/providers/Microsoft.Compute/' \
-                     'disks/{diskName}'
+                     'images/{imageName}',
+                     '{imageName}',
+                     '{publisher}/{offer}/{sku}/{version}']
+NETWORK_RESOURCE_ID = ['/subscriptions/{subscriptionId}/resourceGroups/' \
+                       '{resourceGroupName}/providers/Microsoft.Network' \
+                       '/virtualNetworks/{virtualNetworkName}',
+                       '{virtualNetworkName}']
+NETWORK_INTERFACE_RESOURCE_ID = ['/subscriptions/{subscriptionId}/' \
+                                 'resourceGroups/{resourceGroupName}' \
+                                 '/providers/Microsoft.Network/' \
+                                 'networkInterfaces/{networkInterfaceName}',
+                                 '{networkInterfaceName}']
+PUBLIC_IP_RESOURCE_ID = ['/subscriptions/{subscriptionId}/resourceGroups' \
+                         '/{resourceGroupName}/providers/Microsoft.Network' \
+                         '/publicIPAddresses/{publicIpAddressName}',
+                         '{publicIpAddressName}']
+SNAPSHOT_RESOURCE_ID = ['/subscriptions/{subscriptionId}/resourceGroups/' \
+                        '{resourceGroupName}/providers/Microsoft.Compute/' \
+                        'snapshots/{snapshotName}', '{snapshotName}']
+SUBNET_RESOURCE_ID = ['/subscriptions/{subscriptionId}/resourceGroups/' \
+                      '{resourceGroupName}/providers/Microsoft.Network' \
+                      '/virtualNetworks/{virtualNetworkName}/subnets' \
+                      '/{subnetName}', '{subnetName}']
+VM_RESOURCE_ID = ['/subscriptions/{subscriptionId}/resourceGroups/' \
+                  '{resourceGroupName}/providers/Microsoft.Compute/' \
+                  'virtualMachines/{vmName}', '{vmName}']
+VM_FIREWALL_RESOURCE_ID = ['/subscriptions/{subscriptionId}/' \
+                           'resourceGroups/{resourceGroupName}/' \
+                           'providers/Microsoft.Network/' \
+                           'networkSecurityGroups/' \
+                           '{networkSecurityGroupName}',
+                           '{networkSecurityGroupName}']
+VM_FIREWALL_RULE_RESOURCE_ID = ['/subscriptions/{subscriptionId}/' \
+                                'resourceGroups/{resourceGroupName}/' \
+                                'providers/Microsoft.Network/' \
+                                'networkSecurityGroups/' \
+                                '{networkSecurityGroupName}/' \
+                                'securityRules/{securityRuleName}',
+                                '{securityRuleName}']
+VOLUME_RESOURCE_ID = ['/subscriptions/{subscriptionId}/resourceGroups/' \
+                      '{resourceGroupName}/providers/Microsoft.Compute/' \
+                      'disks/{diskName}', '{diskName}']
 
 
 IMAGE_NAME = 'imageName'
 IMAGE_NAME = 'imageName'
 NETWORK_NAME = 'virtualNetworkName'
 NETWORK_NAME = 'virtualNetworkName'
@@ -367,8 +374,9 @@ class AzureClient(object):
     def delete_image(self, image_id):
     def delete_image(self, image_id):
         url_params = azure_helpers.parse_url(IMAGE_RESOURCE_ID,
         url_params = azure_helpers.parse_url(IMAGE_RESOURCE_ID,
                                              image_id)
                                              image_id)
-        name = url_params.get(IMAGE_NAME)
-        self.compute_client.images.delete(self.resource_group, name).wait()
+        if len(url_params) < 3:
+            name = url_params.get(IMAGE_NAME)
+            self.compute_client.images.delete(self.resource_group, name).wait()
 
 
     def list_images(self):
     def list_images(self):
         return self.compute_client.images. \
         return self.compute_client.images. \
@@ -377,19 +385,25 @@ class AzureClient(object):
     def get_image(self, image_id):
     def get_image(self, image_id):
         url_params = azure_helpers.parse_url(IMAGE_RESOURCE_ID,
         url_params = azure_helpers.parse_url(IMAGE_RESOURCE_ID,
                                              image_id)
                                              image_id)
-        name = url_params.get(IMAGE_NAME)
-        return self.compute_client.images.get(self.resource_group, name)
+        if len(url_params) > 3:
+            return url_params
+        else:
+            name = url_params.get(IMAGE_NAME)
+            return self.compute_client.images.get(self.resource_group, name)
 
 
     def update_image_tags(self, image_id, tags):
     def update_image_tags(self, image_id, tags):
         url_params = azure_helpers.parse_url(IMAGE_RESOURCE_ID,
         url_params = azure_helpers.parse_url(IMAGE_RESOURCE_ID,
                                              image_id)
                                              image_id)
-        name = url_params.get(IMAGE_NAME)
-        return self.compute_client.images. \
-            create_or_update(self.resource_group, name,
-                             {
-                                 'tags': tags,
-                                 'location': self.region_name
-                             }).result()
+        if len(url_params) > 3:
+            return 1
+        else:
+            name = url_params.get(IMAGE_NAME)
+            return self.compute_client.images. \
+                create_or_update(self.resource_group, name,
+                                 {
+                                     'tags': tags,
+                                     'location': self.region_name
+                                 }).result()
 
 
     def list_vm_types(self):
     def list_vm_types(self):
         return self.compute_client.virtual_machine_sizes. \
         return self.compute_client.virtual_machine_sizes. \

+ 8 - 4
cloudbridge/cloud/providers/azure/helpers.py

@@ -20,7 +20,7 @@ def filter_by_tag(list_items, filters):
         return list_items
         return list_items
 
 
 
 
-def parse_url(template_url, original_url):
+def parse_url(template_urls, original_url):
     """
     """
     In Azure all the resource IDs are returned as URIs.
     In Azure all the resource IDs are returned as URIs.
     ex: '/subscriptions/{subscriptionId}/resourceGroups/' \
     ex: '/subscriptions/{subscriptionId}/resourceGroups/' \
@@ -29,13 +29,17 @@ def parse_url(template_url, original_url):
     This function splits the resource ID based on the template url passed
     This function splits the resource ID based on the template url passed
     and returning the dictionary.
     and returning the dictionary.
     """
     """
-    template_url_parts = template_url.split('/')
+    if not original_url:
+        raise InvalidValueException(template_urls, original_url)
     original_url_parts = original_url.split('/')
     original_url_parts = original_url.split('/')
+    for each_template in template_urls:
+        template_url_parts = each_template.split('/')
+        if len(template_url_parts) == len(original_url_parts):
+            break
     if len(template_url_parts) != len(original_url_parts):
     if len(template_url_parts) != len(original_url_parts):
-        raise InvalidValueException(template_url, original_url)
+        raise InvalidValueException(template_urls, original_url)
     resource_param = {}
     resource_param = {}
     for key, value in zip(template_url_parts, original_url_parts):
     for key, value in zip(template_url_parts, original_url_parts):
         if key.startswith('{') and key.endswith('}'):
         if key.startswith('{') and key.endswith('}'):
             resource_param.update({key[1:-1]: value})
             resource_param.update({key[1:-1]: value})
-
     return resource_param
     return resource_param

+ 49 - 24
cloudbridge/cloud/providers/azure/resources.py

@@ -673,10 +673,15 @@ class AzureMachineImage(BaseMachineImage):
 
 
     def __init__(self, provider, image):
     def __init__(self, provider, image):
         super(AzureMachineImage, self).__init__(provider)
         super(AzureMachineImage, self).__init__(provider)
+        # Image can be either a dict for public image reference
+        # or the Azure iamge object
         self._image = image
         self._image = image
-        self._state = self._image.provisioning_state
+        if not isinstance(self._image, dict):
+            self._state = self._image.provisioning_state
+        else:
+            self._state = 'AVAILABLE'
 
 
-        if not self._image.tags:
+        if not isinstance(image, dict) and not self._image.tags:
             self._image.tags = {}
             self._image.tags = {}
 
 
     @property
     @property
@@ -687,11 +692,17 @@ class AzureMachineImage(BaseMachineImage):
         :rtype: ``str``
         :rtype: ``str``
         :return: ID for this instance as returned by the cloud middleware.
         :return: ID for this instance as returned by the cloud middleware.
         """
         """
-        return self._image.id
+        if not isinstance(self._image, dict):
+            return self._image.id
+        else:
+            return self._image['offer']
 
 
     @property
     @property
     def resource_id(self):
     def resource_id(self):
-        return self._image.id
+        if not isinstance(self._image, dict):
+            return self._image.id
+        else:
+            return self._image['offer']
 
 
     @property
     @property
     def name(self):
     def name(self):
@@ -701,17 +712,21 @@ class AzureMachineImage(BaseMachineImage):
         :rtype: ``str``
         :rtype: ``str``
         :return: Name for this image as returned by the cloud middleware.
         :return: Name for this image as returned by the cloud middleware.
         """
         """
-        return self._image.tags.get('Name', self._image.name)
+        if not isinstance(self._image, dict):
+            return self._image.tags.get('Name', self._image.name)
+        else:
+            return self._image['offer']
 
 
     @name.setter
     @name.setter
     def name(self, value):
     def name(self, value):
         """
         """
         Set the image name.
         Set the image name.
         """
         """
-        self.assert_valid_resource_name(value)
-        self._image.tags.update(Name=value)
-        self._provider.azure_client. \
-            update_image_tags(self.id, self._image.tags)
+        if not isinstance(self._image, dict):
+            self.assert_valid_resource_name(value)
+            self._image.tags.update(Name=value)
+            self._provider.azure_client. \
+                update_image_tags(self.id, self._image.tags)
 
 
     @property
     @property
     def description(self):
     def description(self):
@@ -721,16 +736,20 @@ class AzureMachineImage(BaseMachineImage):
         :rtype: ``str``
         :rtype: ``str``
         :return: Description for this image as returned by the cloud middleware
         :return: Description for this image as returned by the cloud middleware
         """
         """
-        return self._image.tags.get('Description', None)
+        if not isinstance(self._image, dict):
+            return self._image.tags.get('Description', None)
+        else:
+            return 'Public Image'
 
 
     @description.setter
     @description.setter
     def description(self, value):
     def description(self, value):
         """
         """
         Set the image name.
         Set the image name.
         """
         """
-        self._image.tags.update(Description=value)
-        self._provider.azure_client. \
-            update_image_tags(self.id, self._image.tags)
+        if not isinstance(self._image, dict):
+            self._image.tags.update(Description=value)
+            self._provider.azure_client. \
+                update_image_tags(self.id, self._image.tags)
 
 
     @property
     @property
     def min_disk(self):
     def min_disk(self):
@@ -743,31 +762,37 @@ class AzureMachineImage(BaseMachineImage):
         :rtype: ``int``
         :rtype: ``int``
         :return: The minimum disk size needed by this image
         :return: The minimum disk size needed by this image
         """
         """
-        return self._image.storage_profile.os_disk.disk_size_gb or 0
+        if not isinstance(self._image, dict):
+            return self._image.storage_profile.os_disk.disk_size_gb or 0
 
 
     def delete(self):
     def delete(self):
         """
         """
         Delete this image
         Delete this image
         """
         """
-        self._provider.azure_client.delete_image(self.id)
+        if not isinstance(self._image, dict):
+            self._provider.azure_client.delete_image(self.id)
 
 
     @property
     @property
     def state(self):
     def state(self):
-        return AzureMachineImage.IMAGE_STATE_MAP.get(
-            self._state, MachineImageState.UNKNOWN)
+        if not isinstance(self._image, dict):
+            return AzureMachineImage.IMAGE_STATE_MAP.get(
+                self._state, MachineImageState.UNKNOWN)
+        else:
+            return MachineImageState.RUNNING
 
 
     def refresh(self):
     def refresh(self):
         """
         """
         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.
         """
         """
-        try:
-            self._image = self._provider.azure_client.get_image(self.id)
-            self._state = self._image.provisioning_state
-        except CloudError as cloudError:
-            log.exception(cloudError.message)
-            # image no longer exists
-            self._state = "unknown"
+        if not isinstance(self._image, dict):
+            try:
+                self._image = self._provider.azure_client.get_image(self.id)
+                self._state = self._image.provisioning_state
+            except CloudError as cloudError:
+                log.exception(cloudError.message)
+                # image no longer exists
+                self._state = "unknown"
 
 
 
 
 class AzureGatewayContainer(BaseGatewayContainer):
 class AzureGatewayContainer(BaseGatewayContainer):