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

Added Region Service code changes

chandraMsekhar 9 лет назад
Родитель
Сommit
cf7bb5f5b9

+ 41 - 0
azure_integration_test/test_integration_azure_region_service.py

@@ -0,0 +1,41 @@
+import azure_integration_test.helpers as helpers
+
+from cloudbridge.cloud.providers.azure.resources import AzureRegion
+
+
+class AzureIntegrationRegionServiceTestCase(helpers.ProviderTestBase):
+    def test_azure_integration_region_service_list(self):
+        regions = self.provider.compute.regions.list()
+        self.assertIsNotNone(regions)
+        for region in regions:
+            print(region.id)
+            print(region.name)
+            print(region.zones)
+            self.assertIsInstance(
+                region,
+                AzureRegion,
+                "regions.list() should return a cloudbridge Region")
+            self.assertTrue(
+                region.name,
+                "Region name should be a non-empty string")
+
+    def test_azure_integration_region_service_get(self):
+        region_id = "/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/" \
+                    "locations/koreasouth"
+        region = self.provider.compute.regions.get(region_id)
+        self.assertIsNotNone(region)
+        self.assertEqual(region.name, "koreasouth")
+
+    def test_azure_integration_region_service_get_invalid_region_id(self):
+        region_id = "/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/" \
+                    "locations/invalid"
+        region = self.provider.compute.regions.get(region_id)
+        self.assertIsNone(region)
+
+    def test_azure_integration_region_service_current(self):
+        current_region_name = self.provider.region_name
+        print("current region: " + current_region_name)
+        region = self.provider.compute.regions.current
+        self.assertIsNotNone(region)
+        print("Region service returned Region name:" + region.name)
+        self.assertEqual(region.name, current_region_name)

+ 47 - 0
azure_test/test_azure_region_service.py

@@ -0,0 +1,47 @@
+from azure_test.helpers import ProviderTestBase
+
+from cloudbridge.cloud.providers.azure.resources import AzureRegion
+
+
+class AzureRegionServiceTestCase(ProviderTestBase):
+    def test_azure_region_service_list(self):
+        regions = self.provider.compute.regions.list()
+        self.assertIsNotNone(regions)
+        self.assertEqual(
+            len(regions), 3)
+        print("Region List - " + str(regions))
+        for region in regions:
+            print(region.id)
+            print(region.name)
+            print(region.zones)
+            self.assertIsInstance(
+                region,
+                AzureRegion,
+                "regions.list() should return a cloudbridge Region")
+            self.assertTrue(
+                region.name,
+                "Region name should be a non-empty string")
+
+    def test_azure_region_service_get(self):
+        region_id = "/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/" \
+                    "locations/westus2"
+        region = self.provider.compute.regions.get(region_id)
+        self.assertIsNotNone(region)
+        self.assertEqual(region.name, "westus2")
+        self.assertEqual(region.zones[0].id, region.id)
+        self.assertEqual(region.zones[0].name, region.name)
+        self.assertEqual(region.zones[0].region_name, region.name)
+
+    def test_azure_region_service_get_invalid_region_id(self):
+        region_id = "/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/" \
+                    "locations/invalid"
+        region = self.provider.compute.regions.get(region_id)
+        self.assertIsNone(region)
+
+    def test_azure_region_service_current(self):
+        current_region_name = self.provider.region_name
+        print("current region: " + current_region_name)
+        region = self.provider.compute.regions.current
+        self.assertIsNotNone(region)
+        print("Region service returned Region name:" + region.name)
+        self.assertEqual(region.name, current_region_name)

+ 18 - 18
cloudbridge/cloud/providers/azure/mock_azure_client.py

@@ -6,13 +6,12 @@ from io import BytesIO
 from azure.common import AzureException
 from azure.mgmt.compute.models import CreationData, DataDisk, \
     Disk, DiskCreateOption, Image, ManagedDiskParameters, \
-    Snapshot, StorageProfile, VirtualMachine, \
-    VirtualMachineSize
-
+    Snapshot, StorageProfile, VirtualMachine
 from azure.mgmt.network.models import NetworkSecurityGroup
 from azure.mgmt.network.models import SecurityRule
 from azure.mgmt.network.models import VirtualNetwork
 from azure.mgmt.resource.resources.models import ResourceGroup
+from azure.mgmt.resource.subscriptions.models import Location
 from azure.mgmt.storage.models import StorageAccount
 from azure.storage.blob.models import Blob, BlobProperties, \
     Container
@@ -211,21 +210,22 @@ class MockAzureClient:
 
     images = [image1, image2]
 
-    instance_type1 = VirtualMachineSize()
-    instance_type1.name = "instance_type1"
-    instance_type1.number_of_cores = 1
-    instance_type1.os_disk_size_in_mb = 100
-    instance_type1.memory_in_mb = 1000
-    instance_type1.max_data_disk_count = 1
+    region1 = Location()
+    region1.name = "westus2"
+    region1.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/' \
+                 'locations/westus2'
+
+    region2 = Location()
+    region2.name = "koreasouth"
+    region2.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/' \
+                 'locations/koreasouth'
 
-    instance_type2 = VirtualMachineSize()
-    instance_type2.name = "instance_type2"
-    instance_type2.number_of_cores = 2
-    instance_type2.os_disk_size_in_mb = 200
-    instance_type2.memory_in_mb = 2000
-    instance_type2.max_data_disk_count = 2
+    region3 = Location()
+    region3.name = "eastus"
+    region3.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/' \
+                 'locations/eastus'
 
-    instance_types = [instance_type1, instance_type2]
+    regions = [region1, region2, region3]
 
     def __init__(self, provider):
         self._provider = provider
@@ -542,5 +542,5 @@ class MockAzureClient:
         img = self.get_image(name)
         self.images.remove(img)
 
-    def list_instance_types(self):
-        return self.instance_types
+    def list_locations(self):
+        return self.regions

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

@@ -8,10 +8,9 @@ from azure.common import AzureException
 
 
 from cloudbridge.cloud.base.resources import BaseAttachmentInfo, \
-    BaseBucket, BaseBucketObject, BaseMachineImage, BaseNetwork,\
-    BaseInstanceType, BaseMachineImage, \
-    BaseSecurityGroup, BaseSecurityGroupRule, BaseSnapshot, BaseVolume, \
-    ClientPagedResultList
+    BaseBucket, BaseBucketObject, BaseMachineImage, BaseNetwork, \
+    BasePlacementZone, BaseRegion, BaseSecurityGroup, BaseSecurityGroupRule, \
+    BaseSnapshot, BaseVolume, ClientPagedResultList
 from cloudbridge.cloud.interfaces import VolumeState
 from cloudbridge.cloud.interfaces.resources import Instance, \
     MachineImageState, NetworkState, SnapshotState
@@ -863,45 +862,63 @@ class AzureNetwork(BaseNetwork):
             return False
 
 
-class AzureInstanceType(BaseInstanceType):
+class AzureRegion(BaseRegion):
 
-    def __init__(self, provider, instance_type):
-        super(AzureInstanceType, self).__init__(provider)
-        self._inst_type = instance_type
+    def __init__(self, provider, azure_region):
+        super(AzureRegion, self).__init__(provider)
+        self._azure_region = azure_region
 
-    # @property
-    # def id(self):
-    #     return str(self._inst_dict['instance_type'])
+    @property
+    def id(self):
+        return self._azure_region.id
 
     @property
     def name(self):
-        return self._inst_type.name
-
-    # @property
-    # def family(self):
-    #     return self._inst_type.get('family')
+        return self._azure_region.name
 
     @property
-    def vcpus(self):
-        return self._inst_type.number_of_cores
+    def zones(self):
+        """
+            Access information about placement zones within this region.
+        """
+        # As Azure does not have zones feature, mapping the region
+        # information in the zones.
+        return [AzurePlacementZone(self._provider,
+                                   self._azure_region.id,
+                                   self._azure_region.name)]
 
-    @property
-    def ram(self):
-        return self._inst_type.memory_in_mb
 
-    @property
-    def size_root_disk(self):
-        return 0
+class AzurePlacementZone(BasePlacementZone):
+
+    def __init__(self, provider, zone, region):
+        super(AzurePlacementZone, self).__init__(provider)
+        self._azure_zone = zone
+        self._azure_region = region
 
     @property
-    def size_ephemeral_disks(self):
-        return self._inst_type.os_disk_size_in_mb/1024
+    def id(self):
+        """
+            Get the zone id
+            :rtype: ``str``
+            :return: ID for this zone as returned by the cloud middleware.
+        """
+        return self._azure_zone
 
     @property
-    def num_ephemeral_disks(self):
-        return self._inst_type.max_data_disk_count
+    def name(self):
+        """
+            Get the zone name.
+            :rtype: ``str``
+            :return: Name for this zone as returned by the cloud middleware.
+        """
+        return self._azure_region
 
-    # @property
-    # def extra_data(self):
-    #     return {key: val for key, val in enumerate(self._inst_type)
-    #             if key not in ["instance_type", "family", "vCPU", "memory"]}
+    @property
+    def region_name(self):
+        """
+            Get the region that this zone belongs to.
+            :rtype: ``str``
+            :return: Name of this zone's region as returned by the
+            cloud middleware
+        """
+        return self._azure_region

+ 52 - 3
cloudbridge/cloud/providers/azure/services.py

@@ -5,19 +5,30 @@ from azure.common import AzureException
 
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.base.services import BaseBlockStoreService, \
+<<<<<<< HEAD
     BaseComputeService, BaseImageService, BaseInstanceTypesService, \
     BaseNetworkService, BaseObjectStoreService, \
     BaseSecurityGroupService, BaseSecurityService, \
     BaseSnapshotService, BaseVolumeService
+=======
+    BaseComputeService, BaseImageService, BaseNetworkService, \
+    BaseObjectStoreService, BaseRegionService, BaseSecurityGroupService, \
+    BaseSecurityService, BaseSnapshotService, BaseVolumeService
+>>>>>>> 6ea3953... Added Region Service code changes
 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
 
+<<<<<<< HEAD
 from .resources import AzureBucket, AzureInstanceType,\
     AzureMachineImage, AzureNetwork, \
     AzureSecurityGroup, \
+=======
+from .resources import AzureBucket, AzureMachineImage, \
+    AzureNetwork, AzureRegion, AzureSecurityGroup, \
+>>>>>>> 6ea3953... Added Region Service code changes
     AzureSnapshot, AzureVolume, \
     IMAGE_NAME, IMAGE_RESOURCE_ID, \
     NETWORK_NAME, NETWORK_RESOURCE_ID, \
@@ -305,7 +316,7 @@ class AzureComputeService(BaseComputeService):
         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._region_svc = AzureRegionService(self.provider)
         self._images_svc = AzureImageService(self.provider)
 
     @property
@@ -323,8 +334,7 @@ class AzureComputeService(BaseComputeService):
 
     @property
     def regions(self):
-        raise NotImplementedError('AzureComputeService not '
-                                  'implemented this method')
+        return self._region_svc
 
 
 class AzureImageService(BaseImageService):
@@ -438,8 +448,13 @@ class AzureNetworkService(BaseNetworkService):
 
     def delete(self, network_id):
         """
+<<<<<<< HEAD
                 Delete an existing network.
                 """
+=======
+            Delete an existing network.
+            """
+>>>>>>> 6ea3953... Added Region Service code changes
         try:
             params = azure_helpers.parse_url(NETWORK_RESOURCE_ID, network_id)
             network = self.provider.azure_client. \
@@ -449,3 +464,37 @@ class AzureNetworkService(BaseNetworkService):
             log.exception(cloudError.message)
             return False
 
+<<<<<<< HEAD
+=======
+
+class AzureRegionService(BaseRegionService):
+    def __init__(self, provider):
+        super(AzureRegionService, self).__init__(provider)
+
+    def get(self, region_id):
+        region = None
+        for azureRegion in self.provider.azure_client.list_locations():
+            if azureRegion.id == region_id:
+                region = AzureRegion(self.provider, azureRegion)
+                break
+        return region
+
+    def list(self, limit=None, marker=None):
+        regions = [AzureRegion(self.provider, region)
+                   for region in self.provider.azure_client.list_locations()]
+        return ClientPagedResultList(self.provider, regions,
+                                     limit=limit, marker=marker)
+
+    @property
+    def current(self):
+        region = None
+        # aws sets the name returned from the aws sdk to both the id & name
+        # of BaseRegion and as such calling get() with the id works
+        # but Azure sdk returns both id & name and are set to
+        # the BaseRegion properties
+        for azureRegion in self.provider.azure_client.list_locations():
+            if azureRegion.name == self.provider.region_name:
+                region = AzureRegion(self.provider, azureRegion)
+                break
+        return region
+>>>>>>> 6ea3953... Added Region Service code changes

+ 40 - 104
test/helpers.py

@@ -1,14 +1,16 @@
-from contextlib import contextmanager
+import functools
 import os
 import sys
 import unittest
-import functools
-from six import reraise
+
+from contextlib import contextmanager
 
 from cloudbridge.cloud.factory import CloudProviderFactory
 from cloudbridge.cloud.interfaces import InstanceState
 from cloudbridge.cloud.interfaces import TestMockHelperMixin
 
+from six import reraise
+
 
 def parse_bool(val):
     if val:
@@ -19,7 +21,7 @@ def parse_bool(val):
 
 @contextmanager
 def cleanup_action(cleanup_func):
-    """n csdmmnd
+    """
     Context manager to carry out a given
     cleanup action after carrying out a set
     of tasks, or when an exception occurs.
@@ -82,7 +84,10 @@ TEST_DATA_CONFIG = {
         "image": os.environ.get('CB_IMAGE_OS',
                                 '842b949c-ea76-48df-998d-8a41f2626243'),
         "instance_type": os.environ.get('CB_INSTANCE_TYPE_OS', 'm1.tiny'),
-        "placement": os.environ.get('CB_PLACEMENT_OS', 'zone-r6'),
+        "placement": os.environ.get('CB_PLACEMENT_OS', 'nova'),
+    },
+    "AzureCloudProvider": {
+        "placement": "eastus"
     }
 }
 
@@ -92,6 +97,8 @@ def get_provider_test_data(provider, key):
         return TEST_DATA_CONFIG.get("AWSCloudProvider").get(key)
     elif "OpenStackCloudProvider" in provider.name:
         return TEST_DATA_CONFIG.get("OpenStackCloudProvider").get(key)
+    elif "AzureCloudProvider" in provider.name:
+        return TEST_DATA_CONFIG.get("AzureCloudProvider").get(key)
     return None
 
 
@@ -143,31 +150,31 @@ def get_test_instance(provider, name, key_pair=None, security_groups=None,
     return instance
 
 
+def get_test_fixtures_folder():
+    return os.path.join(os.path.dirname(__file__), 'fixtures/')
+
+
+def delete_test_instance(instance):
+    if instance:
+        instance.terminate()
+        instance.wait_for([InstanceState.TERMINATED, InstanceState.UNKNOWN],
+                          terminal_states=[InstanceState.ERROR])
+
+
 def cleanup_test_resources(instance=None, network=None, security_group=None,
                            key_pair=None):
+    """Clean up any combination of supplied resources."""
     with cleanup_action(lambda: delete_test_network(network)
                         if network else None):
         with cleanup_action(lambda: key_pair.delete() if key_pair else None):
             with cleanup_action(lambda: security_group.delete()
                                 if security_group else None):
-                instance.terminate()
-                instance.wait_for(
-                    [InstanceState.TERMINATED, InstanceState.UNKNOWN],
-                    terminal_states=[InstanceState.ERROR])
-
+                delete_test_instance(instance)
 
-class ProviderTestBase(object):
 
-    """
-    A dummy base class for Test Cases. Does not inherit from unittest.TestCase
-    to avoid confusing test discovery by unittest and nose2. unittest.TestCase
-    is injected as a base class by the generator, so calling the unittest
-    constructor works correctly.
-    """
+class ProviderTestBase(unittest.TestCase):
 
-    def __init__(self, methodName, provider):
-        unittest.TestCase.__init__(self, methodName=methodName)
-        self.provider = provider
+    _provider = None
 
     def setUp(self):
         if isinstance(self.provider, TestMockHelperMixin):
@@ -176,17 +183,7 @@ class ProviderTestBase(object):
     def tearDown(self):
         if isinstance(self.provider, TestMockHelperMixin):
             self.provider.tearDownMock()
-
-
-class ProviderTestCaseGenerator():
-
-    """
-    Generates test cases for all provider - testcase combinations.
-    Detailed docs at test/__init__.py
-    """
-
-    def __init__(self, test_classes):
-        self.all_test_classes = test_classes
+        self._provider = None
 
     def get_provider_wait_interval(self, provider_class):
         if issubclass(provider_class, TestMockHelperMixin):
@@ -194,80 +191,19 @@ class ProviderTestCaseGenerator():
         else:
             return 1
 
-    def create_provider_instance(self, provider_class):
-        """
-        Instantiate a default provider instance. All required connection
-        settings are expected to be set as environment variables.
-        """
+    def create_provider_instance(self):
+        provider_name = os.environ.get("CB_TEST_PROVIDER", "aws")
+        use_mock_drivers = parse_bool(
+            os.environ.get("CB_USE_MOCK_PROVIDERS", "True"))
+        factory = CloudProviderFactory()
+        provider_class = factory.get_provider_class(provider_name,
+                                                    get_mock=use_mock_drivers)
         config = {'default_wait_interval':
                   self.get_provider_wait_interval(provider_class)}
         return provider_class(config)
 
-    def generate_new_test_class(self, name, testcase_class):
-        """
-        Generates a new type which inherits from the given testcase_class and
-        unittest.TestCase
-        """
-        class_name = "{0}{1}".format(name, testcase_class.__name__)
-        return type(class_name, (testcase_class, unittest.TestCase), {})
-
-    def generate_test_suite_for_provider_testcase(
-            self, provider_class, testcase_class):
-        """
-        Generate and return a suite of tests for a specific provider class and
-        testcase combination
-        """
-        testloader = unittest.TestLoader()
-        testnames = testloader.getTestCaseNames(testcase_class)
-        suite = unittest.TestSuite()
-        for name in testnames:
-            generated_cls = self.generate_new_test_class(
-                provider_class.__name__,
-                testcase_class)
-            suite.addTest(
-                generated_cls(
-                    name,
-                    self.create_provider_instance(provider_class)))
-        return suite
-
-    def generate_test_suite_for_provider(self, provider_class):
-        """
-        Generate and return a suite of all available tests for a given provider
-        class
-        """
-        suite = unittest.TestSuite()
-        suites = [
-            self.generate_test_suite_for_provider_testcase(
-                provider_class, test_class)
-            for test_class in self.all_test_classes]
-        for s in suites:
-            suite.addTest(s)
-        return suite
-
-    def generate_tests(self):
-        """
-        Generate and return a suite of tests for all provider and test class
-        combinations
-        """
-        factory = CloudProviderFactory()
-        use_mock_drivers = parse_bool(
-            os.environ.get("CB_USE_MOCK_PROVIDERS", True))
-        provider_name = os.environ.get("CB_TEST_PROVIDER", "azure")
-        if provider_name:
-            provider_classes = [
-                factory.get_provider_class(
-                    provider_name,
-                    get_mock=use_mock_drivers)]
-            if not provider_classes[0]:
-                raise ValueError(
-                    "Could not find specified test provider %s" %
-                    provider_name)
-        else:
-            provider_classes = factory.get_all_provider_classes(
-                get_mock=use_mock_drivers)
-        suite = unittest.TestSuite()
-        suites = [
-            self.generate_test_suite_for_provider(p) for p in provider_classes]
-        for s in suites:
-            suite.addTest(s)
-        return suite
+    @property
+    def provider(self):
+        if not self._provider:
+            self._provider = self.create_provider_instance()
+        return self._provider

+ 2 - 3
test/test_azure_provider.py

@@ -16,9 +16,8 @@ class AzureProviderTestCase(ProviderTestBase):
         self.assertTrue(compute.instance_types is not None,
                         'Instance types should not be none')
 
-        with self.assertRaises(NotImplementedError):
-            self.assertTrue(compute.regions is not None,
-                            'Regions should not be none')
+        self.assertTrue(compute.regions is not None,
+                        'Regions should not be none')
 
         network = self.provider.network
         self.assertTrue(network is not None,