jatin 9 лет назад
Родитель
Сommit
ad2a0a8908

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

@@ -342,3 +342,26 @@ class AzureClient(object):
                 subnet_name
             )
         result_delete.wait()
+
+    def list_instances(self):
+        return self._compute_client.virtual_machines.list(
+            self.resource_group_name
+        )
+
+    def reboot_instance(self, vm_name):
+        return self._compute_client.virtual_machines.restart(
+            self.resource_group_name,
+            vm_name
+        )
+
+    def terminate_instance(self, vm_name):
+        return self._compute_client.virtual_machines.power_off(
+            self.resource_group_name,
+            vm_name
+        )
+
+    def get_instance(self, vm_name):
+        return self._compute_client.virtual_machines.get(
+            self.resource_group_name,
+            vm_name
+        )

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

@@ -197,7 +197,17 @@ class MockAzureClient:
         DataDisk(managed_disk=ManagedDiskParameters(id=data_disk_id),
                  lun=0, create_option='attach')
     vm1.storage_profile.data_disks = [data_dik]
-    virtual_machines = [vm1]
+
+    vm2 = VirtualMachine(location='eastus')
+    vm2.name = 'VM2'
+
+    vm2.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
+             '/resourceGroups/CLOUDBRIDGE-AZURE' \
+             '/providers/Microsoft.Compute/virtualMachines/VM2'
+    vm2.storage_profile = StorageProfile()
+    vm2.storage_profile.data_disks = [data_dik]
+
+    virtual_machines = [vm1, vm2]
 
     image1 = Image(location='eastus')
     image1.name = 'image1'
@@ -628,3 +638,20 @@ class MockAzureClient:
     def delete_subnet(self, network_name, subnet_name):
         subnet = self.get_subnet(network_name, subnet_name)
         self.subnets.remove(subnet)
+
+    def list_instances(self):
+        return self.virtual_machines
+
+    def get_instance(self, vm_name):
+        for vm in self.virtual_machines:
+            if vm.name == vm_name:
+                return vm
+        response = Response()
+        response.status_code = 404
+        raise CloudError(response=response, error='Resource Not found')
+
+    def reboot_instance(self, vm_name):
+        pass
+
+    def terminate_instance(self, vm_name):
+        pass

+ 166 - 2
cloudbridge/cloud/providers/azure/resources.py

@@ -7,14 +7,16 @@ import json
 from azure.common import AzureException
 
 from cloudbridge.cloud.base.resources import BaseAttachmentInfo, \
-    BaseBucket, BaseBucketObject, BaseInstanceType, \
+    BaseBucket, BaseBucketObject, BaseInstance, \
+    BaseInstanceType, \
     BaseMachineImage, BaseNetwork, \
     BasePlacementZone, BaseRegion, \
     BaseSecurityGroup, BaseSecurityGroupRule, BaseSnapshot, BaseSubnet, \
     BaseVolume, ClientPagedResultList
 from cloudbridge.cloud.interfaces import VolumeState
 from cloudbridge.cloud.interfaces.resources import Instance, \
-    MachineImageState, NetworkState, SnapshotState
+    InstanceState, MachineImageState, \
+    NetworkState, SnapshotState
 from cloudbridge.cloud.providers.azure import helpers as azure_helpers
 
 from msrestazure.azure_exceptions import CloudError
@@ -67,6 +69,7 @@ RESOURCE_GROUP_NAME = 'resourceGroupName'
 SUBSCRIPTION_ID = 'subscriptionId'
 NETWORK_NAME = 'virtualNetworkName'
 IMAGE_NAME = 'imageName'
+INSTANCE_NAME = 'vmName'
 VM_NAME = 'vmName'
 VOLUME_NAME = 'diskName'
 SNAPSHOT_NAME = 'snapshotName'
@@ -1024,6 +1027,167 @@ class AzureSubnet(BaseSubnet):
             return False
 
 
+class AzureInstance(BaseInstance):
+    INSTANCE_STATE_MAP = {
+        'pending': InstanceState.PENDING,
+        'running': InstanceState.RUNNING,
+        'shutting-down': InstanceState.CONFIGURING,
+        'terminated': InstanceState.TERMINATED,
+        'stopping': InstanceState.CONFIGURING,
+        'stopped': InstanceState.STOPPED
+    }
+
+    def __init__(self, provider, instance):
+        super(AzureInstance, self).__init__(provider)
+        self._instance = instance
+        self._state = self._instance.provisioning_state
+
+    @property
+    def id(self):
+        """
+        Get the instance identifier.
+        """
+        return self._instance.id
+
+    @property
+    def name(self):
+        """
+        Get the instance name.
+
+        .. note:: an instance must have a (case sensitive) tag ``Name``
+        """
+        return self._instance.name
+
+    @name.setter
+    # pylint:disable=arguments-differ
+    def name(self, value):
+        """
+        Set the instance name.
+        """
+        self._instance.add_tag('Name', value)
+
+    @property
+    def public_ips(self):
+        """
+        Get all the public IP addresses for this instance.
+        """
+        pass
+
+    @property
+    def private_ips(self):
+        """
+        Get all the private IP addresses for this instance.
+        """
+        pass
+
+    @property
+    def instance_type_id(self):
+        """
+        Get the instance type name.
+        """
+        return self._instance.hardware_profile.vm_size
+
+    @property
+    def instance_type(self):
+        """
+        Get the instance type.
+        """
+        return self._provider.compute.instance_types.find(
+            name=self.instance_type_id)[0]
+
+    def reboot(self):
+        """
+        Reboot this instance (using the cloud middleware API).
+        """
+        self._provider.azure_client.reboot_instance(self.name)
+
+    def terminate(self):
+        """
+        Permanently terminate this instance.
+        """
+        self._provider.azure_client.terminate_instance(self.name)
+
+    @property
+    def image_id(self):
+        """
+        Get the image ID for this insance.
+        """
+        return self._instance.vm_id
+
+    @property
+    def zone_id(self):
+        """
+        Get the placement zone id where this instance is running.
+        """
+        return self._instance.location
+
+    @property
+    def security_groups(self):
+        """
+        Get the security groups associated with this instance.
+        """
+        # boto instance.groups field returns a ``Group`` object so need to
+        # convert that into a ``SecurityGroup`` object before creating a
+        # cloudbridge SecurityGroup object
+        pass
+
+    @property
+    def security_group_ids(self):
+        """
+        Get the security groups IDs associated with this instance.
+        """
+        pass
+
+    @property
+    def key_pair_name(self):
+        """
+        Get the name of the key pair associated with this instance.
+        """
+        pass
+
+    def create_image(self, name):
+        """
+        Create a new image based on this instance.
+        """
+        pass
+
+    def add_floating_ip(self, ip_address):
+        """
+        Add an elastic IP address to this instance.
+        """
+        pass
+
+    def remove_floating_ip(self, ip_address):
+        """
+        Remove a elastic IP address from this instance.
+        """
+        pass
+
+    def add_security_group(self, sg):
+        """
+        Add a security group to this instance
+        """
+        pass
+
+    def remove_security_group(self, sg):
+        """
+        Remove a security group from this instance
+        """
+        pass
+
+    @property
+    def state(self):
+        return AzureInstance.INSTANCE_STATE_MAP.get(
+            self._state, InstanceState.UNKNOWN)
+
+    def refresh(self):
+        """
+        Refreshes the state of this instance by re-querying the cloud provider
+        for its latest state.
+        """
+        pass
+
+
 class AzureInstanceType(BaseInstanceType):
 
     def __init__(self, provider, instance_type):

+ 37 - 7
cloudbridge/cloud/providers/azure/services.py

@@ -5,7 +5,8 @@ from azure.common import AzureException
 
 from cloudbridge.cloud.base.resources import ClientPagedResultList
 from cloudbridge.cloud.base.services import BaseBlockStoreService, \
-    BaseComputeService, BaseImageService, BaseInstanceTypesService, \
+    BaseComputeService, BaseImageService, BaseInstanceService, \
+    BaseInstanceTypesService, \
     BaseNetworkService, \
     BaseObjectStoreService, BaseRegionService, \
     BaseSecurityGroupService, \
@@ -17,12 +18,15 @@ from cloudbridge.cloud.providers.azure import helpers as azure_helpers
 
 from msrestazure.azure_exceptions import CloudError
 
-from .resources import AzureBucket, AzureInstanceType, \
+from .resources import AzureBucket, AzureInstance, \
+    AzureInstanceType, \
     AzureMachineImage, \
     AzureNetwork, AzureRegion, AzureSecurityGroup, \
     AzureSnapshot, AzureSubnet, AzureVolume, \
-    IMAGE_NAME, IMAGE_RESOURCE_ID, NETWORK_NAME, \
-    NETWORK_RESOURCE_ID, NETWORK_SECURITY_GROUP_RESOURCE_ID, \
+    IMAGE_NAME, IMAGE_RESOURCE_ID, \
+    INSTANCE_NAME, INSTANCE_RESOURCE_ID, \
+    NETWORK_NAME, NETWORK_RESOURCE_ID, \
+    NETWORK_SECURITY_GROUP_RESOURCE_ID, \
     SECURITY_GROUP_NAME, SNAPSHOT_NAME, \
     SNAPSHOT_RESOURCE_ID, SUBNET_NAME, SUBNET_RESOURCE_ID, \
     VOLUME_NAME, VOLUME_RESOURCE_ID
@@ -314,7 +318,7 @@ 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._instance_svc = AzureInstanceService(self.provider)
         self._region_svc = AzureRegionService(self.provider)
         self._images_svc = AzureImageService(self.provider)
 
@@ -328,14 +332,40 @@ class AzureComputeService(BaseComputeService):
 
     @property
     def instances(self):
-        raise NotImplementedError('AzureComputeService not '
-                                  'implemented this method')
+        return self._instance_svc
 
     @property
     def regions(self):
         return self._region_svc
 
 
+class AzureInstanceService(BaseInstanceService):
+    def __init__(self, provider):
+        super(AzureInstanceService, self).__init__(provider)
+
+    def list(self, limit=None, marker=None):
+        """
+        List all instances.
+        """
+
+        azure_instances = [instance for instance in
+                           self.provider.azure_client.list_instances()]
+        cb_instances = [AzureInstance(self.provider, instance)
+                        for instance in azure_instances]
+        return ClientPagedResultList(self.provider, cb_instances,
+                                     limit=limit, marker=marker)
+
+    def get(self, instance_id):
+        try:
+            params = azure_helpers.parse_url(INSTANCE_RESOURCE_ID, instance_id)
+            instance = self.provider.azure_client. \
+                get_instance(params.get(INSTANCE_NAME))
+            return AzureInstance(self.provider, instance)
+        except CloudError as cloudError:
+            log.exception(cloudError.message)
+            return None
+
+
 class AzureImageService(BaseImageService):
     def __init__(self, provider):
         super(AzureImageService, self).__init__(provider)

+ 2 - 3
test/test_azure_provider.py

@@ -9,9 +9,8 @@ class AzureProviderTestCase(ProviderTestBase):
         self.assertTrue(compute.images is not None,
                         'Images should not be none')
 
-        with self.assertRaises(NotImplementedError):
-            self.assertTrue(compute.instances is not None,
-                            'Instances should not be none')
+        self.assertTrue(compute.instances is not None,
+                        'Instances should not be none')
 
         self.assertTrue(compute.instance_types is not None,
                         'Instance types should not be none')