2
0
jatin 9 жил өмнө
parent
commit
dae72699a4

+ 23 - 0
azure_integration_test/test_integration_azure_image_service.py

@@ -0,0 +1,23 @@
+import azure_integration_test.helpers as helpers
+
+from azure_integration_test.helpers import ProviderTestBase
+
+
+class AzureIntegrationImageServiceTestCase(ProviderTestBase):
+    @helpers.skipIfNoService(['security.security_groups'])
+    def test_azure_image_service(self):
+        image_id = "/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96" \
+                   "/resourceGroups/cloudbridge-azure/providers" \
+                   "/Microsoft.Compute/images/sampleImage"
+
+        images_list = self.provider.compute.images.list()
+        print("List image - " + str(images_list))
+        self.assertEqual(len(images_list), 2)
+
+        image_get = self.provider.compute.images.get(image_id)
+        print("Get Image - " + str(image_get))
+        self.assertIsNotNone(image_get)
+
+        # print("Before updating tag - " + str(image_get.name))
+        # image_get.name("NewTestImage")
+        # print("After updating tag - " + str(image_get.name))

+ 38 - 0
azure_test/test_azure_image_service.py

@@ -0,0 +1,38 @@
+import azure_test.helpers as helpers
+from azure_test.helpers import ProviderTestBase
+
+
+class AzureImageServiceTestCase(ProviderTestBase):
+    @helpers.skipIfNoService(['security.security_groups'])
+    def test_azure_images_list(self):
+        images_list = self.provider.compute.images.list()
+        print("List Images - " + str(images_list))
+        self.assertEqual(len(images_list), 2)
+
+    @helpers.skipIfNoService(['security.security_groups'])
+    def test_azure_images_get_exist(self):
+        image1_id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/' \
+                    'resourceGroups/CLOUDBRIDGE-AZURE/providers/' \
+                    'Microsoft.Compute/images/image1'
+        image_get = self.provider.compute.images.get(image1_id)
+        print("Get Image Exist - " + str(image_get))
+        self.assertIsNotNone(image_get)
+
+    @helpers.skipIfNoService(['security.security_groups'])
+    def test_azure_images_get_notExist(self):
+        image1_id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/' \
+                    'resourceGroups/CLOUDBRIDGE-AZURE/providers/' \
+                    'Microsoft.Compute/images/imageNotExist'
+        image_get = self.provider.compute.images.get(image1_id)
+        print("Get Image Not Exist- " + str(image_get))
+        self.assertIsNone(image_get)
+
+    @helpers.skipIfNoService(['security.security_groups'])
+    def test_azure_images_find(self):
+        image1_name = 'image1'
+        with self.assertRaises(NotImplementedError):
+            image_find = self.provider.compute.images \
+                .find(image1_name)
+            print("Find Image  - " + str(image_find))
+            self.assertEqual(
+                len(image_find), 1)

+ 8 - 0
cloudbridge/cloud/providers/azure/azure_client.py

@@ -261,3 +261,11 @@ class AzureClient(object):
     def list_vm(self):
         return self.compute_client.\
             virtual_machines.list(self.resource_group_name)
+
+    def list_images(self):
+        return self.compute_client.images. \
+            list_by_resource_group(self.resource_group_name)
+
+    def get_image(self, image_name):
+        return self.compute_client.images. \
+            get(self.resource_group_name, image_name)

+ 29 - 1
cloudbridge/cloud/providers/azure/mock_azure_client.py

@@ -5,7 +5,7 @@ from io import BytesIO
 
 from azure.common import AzureException
 from azure.mgmt.compute.models import CreationData, DataDisk, \
-    Disk, DiskCreateOption, ManagedDiskParameters, \
+    Disk, DiskCreateOption, Image, ManagedDiskParameters, \
     Snapshot, StorageProfile, VirtualMachine
 from azure.mgmt.network.models import NetworkSecurityGroup
 from azure.mgmt.network.models import SecurityRule
@@ -163,6 +163,22 @@ class MockAzureClient:
     vm1.storage_profile.data_disks = [data_dik]
     virtual_machines = [vm1]
 
+    image1 = Image(location='eastus')
+    image1.name = 'image1'
+    image1.tags = {'Name': 'image1'}
+    image1.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/' \
+                'resourceGroups/CLOUDBRIDGE-AZURE/providers/' \
+                'Microsoft.Compute/images/image1'
+
+    image2 = Image(location='eastus')
+    image2.name = 'image2'
+    image2.tags = {'Name': 'image2'}
+    image2.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
+                '/resourceGroups/CLOUDBRIDGE-AZURE' \
+                '/providers/Microsoft.Compute/images/image2'
+
+    images = [image1, image2]
+
     def __init__(self, provider):
         self._provider = provider
 
@@ -440,3 +456,15 @@ class MockAzureClient:
 
     def list_vm(self):
         return self.virtual_machines
+
+    def list_images(self):
+        return self.images
+
+    def get_image(self, name):
+        for image in self.images:
+            if image.name == name:
+                return image
+
+        response = Response()
+        response.status_code = 404
+        raise CloudError(response=response, error='Resource Not found')

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

@@ -6,8 +6,8 @@ from cloudbridge.cloud.interfaces import TestMockHelperMixin
 from cloudbridge.cloud.providers.azure.azure_client import AzureClient
 from cloudbridge.cloud.providers.azure.mock_azure_client import MockAzureClient
 from cloudbridge.cloud.providers.azure.services \
-    import AzureBlockStoreService, AzureObjectStoreService, \
-    AzureSecurityService
+    import AzureBlockStoreService, AzureComputeService, \
+    AzureObjectStoreService, AzureSecurityService
 
 
 from msrestazure.azure_exceptions import CloudError
@@ -83,11 +83,11 @@ class AzureCloudProvider(BaseCloudProvider):
         self._security = AzureSecurityService(self)
         self._object_store = AzureObjectStoreService(self)
         self._block_store = AzureBlockStoreService(self)
+        self._compute = AzureComputeService(self)
 
     @property
     def compute(self):
-        raise NotImplementedError(
-            "AzureCloudProvider does not implement this service")
+        return self._compute
 
     @property
     def network(self):

+ 99 - 3
cloudbridge/cloud/providers/azure/resources.py

@@ -8,11 +8,12 @@ from azure.common import AzureException
 
 
 from cloudbridge.cloud.base.resources import BaseAttachmentInfo, \
-    BaseBucket, BaseBucketObject, BaseSecurityGroup, \
-    BaseSecurityGroupRule, BaseSnapshot, BaseVolume, \
+    BaseBucket, BaseBucketObject, BaseMachineImage, \
+    BaseSecurityGroup, BaseSecurityGroupRule, BaseSnapshot, BaseVolume, \
     ClientPagedResultList
 from cloudbridge.cloud.interfaces import VolumeState
-from cloudbridge.cloud.interfaces.resources import Instance, SnapshotState
+from cloudbridge.cloud.interfaces.resources import Instance, \
+    MachineImageState, SnapshotState
 from cloudbridge.cloud.providers.azure import helpers as azure_helpers
 
 from msrestazure.azure_exceptions import CloudError
@@ -32,6 +33,9 @@ VOLUME_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/' \
 SNAPSHOT_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/' \
                        '{resourceGroupName}/providers/Microsoft.Compute/' \
                        'snapshots/{snapshotName}'
+IMAGE_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/' \
+                    '{resourceGroupName}/providers/Microsoft.Compute/' \
+                    'images/{imageName}'
 NETWORK_SECURITY_GROUP_RESOURCE_ID = '/subscriptions/{subscriptionId}/' \
                                      'resourceGroups/{resourceGroupName}/' \
                                      'providers/Microsoft.Network/' \
@@ -707,3 +711,95 @@ class AzureSnapshot(BaseSnapshot):
         return self._provider.block_store.volumes.\
             create(self.resource_name, self.size,
                    zone=placement, snapshot=self)
+
+
+class AzureMachineImage(BaseMachineImage):
+    IMAGE_STATE_MAP = {
+        'pending': MachineImageState.PENDING,
+        'available': MachineImageState.AVAILABLE,
+        'failed': MachineImageState.ERROR
+    }
+
+    def __init__(self, provider, image):
+        super(AzureMachineImage, self).__init__(provider)
+        self._image = image
+        self._description = None
+        self._status = self._image.provisioning_state
+        if not self._image.tags:
+            self._image.tags = {}
+
+    @property
+    def id(self):
+        """
+        Get the image identifier.
+
+        :rtype: ``str``
+        :return: ID for this instance as returned by the cloud middleware.
+        """
+        return self._image.id
+
+    @property
+    def resource_name(self):
+        return self._image.name
+
+    @property
+    def name(self):
+        """
+        Get the snapshot name.
+
+        .. note:: an instance must have a (case sensitive) tag ``Name``
+        """
+        return self._image.tags.get('Name', self._image.name)
+
+    @name.setter
+    # pylint:disable=arguments-differ
+    def name(self, value):
+        """
+        Set the snapshot name.
+        """
+        # self._snapshot.name = value
+        self._image.tags.update(Name=value)
+        self._provider.azure_client. \
+            update_snapshot_tags(self.resource_name,
+                                 self._image.tags)
+
+    @property
+    def description(self):
+        return self._image.tags.get('Description', None)
+
+        # @property
+        # def min_disk(self):
+        #     """
+        #     Returns the minimum size of the disk that's required to
+        #     boot this image (in GB)
+        #
+        #     :rtype: ``int``
+        #     :return: The minimum disk size needed by this image
+        #     """
+        #     bdm = self._ec2_image.block_device_mapping
+        #     return bdm[self._ec2_image.root_device_name].size
+        #
+        # def delete(self):
+        #     """
+        #     Delete this image
+        #     """
+        #     self._ec2_image.deregister(delete_snapshot=True)
+        #
+        # @property
+        # def state(self):
+        #     return AzureMachineImage.IMAGE_STATE_MAP.get(
+        #         self._ec2_image.state, MachineImageState.UNKNOWN)
+        #
+        # def refresh(self):
+        #     """
+        #     Refreshes the state of this instance by re-querying
+        #     the cloud provider
+        #     for its latest state.
+        #     """
+        #     image = self._provider.compute.images.get(self.id)
+        #     if image:
+        #         # pylint:disable=protected-access
+        #         self._ec2_image = image._ec2_image
+        #     else:
+        #         # image no longer exists
+        #         self._ec2_image.state = "unknown"

+ 63 - 6
cloudbridge/cloud/providers/azure/services.py

@@ -5,19 +5,22 @@ from azure.common import AzureException
 
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.base.services import BaseBlockStoreService, \
-    BaseObjectStoreService, BaseSecurityGroupService, \
-    BaseSecurityService, BaseSnapshotService, BaseVolumeService
+    BaseComputeService, BaseImageService, BaseObjectStoreService, \
+    BaseSecurityGroupService, BaseSecurityService, \
+    BaseSnapshotService, BaseVolumeService
 from cloudbridge.cloud.interfaces.resources import PlacementZone, \
     Snapshot, Volume
 from cloudbridge.cloud.providers.azure import helpers as azure_helpers
 
 from msrestazure.azure_exceptions import CloudError
 
-from .resources import AzureBucket, AzureSecurityGroup, \
+from .resources import AzureBucket, AzureMachineImage, \
+    AzureSecurityGroup, \
     AzureSnapshot, AzureVolume, \
-    NETWORK_SECURITY_GROUP_RESOURCE_ID, SECURITY_GROUP_NAME, \
-    SNAPSHOT_NAME, SNAPSHOT_RESOURCE_ID, VOLUME_NAME, \
-    VOLUME_RESOURCE_ID
+    IMAGE_NAME, IMAGE_RESOURCE_ID, \
+    NETWORK_SECURITY_GROUP_RESOURCE_ID, \
+    SECURITY_GROUP_NAME, SNAPSHOT_NAME, \
+    SNAPSHOT_RESOURCE_ID, VOLUME_NAME, VOLUME_RESOURCE_ID
 
 log = logging.getLogger(__name__)
 
@@ -292,3 +295,57 @@ class AzureSnapshotService(BaseSnapshotService):
         cb_snap = AzureSnapshot(self.provider, azure_snap)
 
         return cb_snap
+
+
+class AzureComputeService(BaseComputeService):
+    def __init__(self, provider):
+        super(AzureComputeService, self).__init__(provider)
+        # self._instance_type_svc = AzureInstanceTypesService(self.provider)
+        # self._instance_svc = AzureInstanceService(self.provider)
+        # self._region_svc = AzureRegionService(self.provider)
+        self._images_svc = AzureImageService(self.provider)
+
+    @property
+    def images(self):
+        return self._images_svc
+
+    @property
+    def instance_types(self):
+        raise NotImplementedError('AzureComputeService not '
+                                  'implemented this method')
+
+    @property
+    def instances(self):
+        raise NotImplementedError('AzureComputeService not '
+                                  'implemented this method')
+
+    @property
+    def regions(self):
+        raise NotImplementedError('AzureComputeService not '
+                                  'implemented this method')
+
+
+class AzureImageService(BaseImageService):
+    def __init__(self, provider):
+        super(AzureImageService, self).__init__(provider)
+
+    def get(self, image_id):
+        try:
+            params = azure_helpers.parse_url(IMAGE_RESOURCE_ID, image_id)
+            image = self.provider.azure_client. \
+                get_image(params.get(IMAGE_NAME))
+            return AzureMachineImage(self.provider, image)
+        except CloudError as cloudError:
+            log.exception(cloudError.message)
+            return None
+
+    def find(self, name, limit=None, marker=None):
+        raise NotImplementedError('AzureImageService not '
+                                  'implemented this method')
+
+    def list(self, limit=None, marker=None):
+        azure_images = self.provider.azure_client.list_images()
+        cb_images = [AzureMachineImage(self.provider, vol)
+                     for vol in azure_images]
+        return ClientPagedResultList(self.provider, cb_images,
+                                     limit=limit, marker=marker)

+ 2 - 3
test/test_azure_provider.py

@@ -3,9 +3,8 @@ from azure_test.helpers import ProviderTestBase
 
 class AzureProviderTestCase(ProviderTestBase):
     def test_azure_provider(self):
-        with self.assertRaises(Exception):
-            compute = self.provider.compute
-            self.assertTrue(compute is not None, 'Compute should not be None')
+        compute = self.provider.compute
+        self.assertTrue(compute is not None, 'Compute should not be None')
 
         with self.assertRaises(Exception):
             network = self.provider.network