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

Initial implementation of create instance and launch config methods

vikramdoda 9 лет назад
Родитель
Сommit
51ee348b18

+ 61 - 31
azure_integration_test/test_integration_azure_instance_service.py

@@ -1,38 +1,68 @@
+import uuid
+
 import azure_integration_test.helpers as helpers
 
 from azure_integration_test.helpers import ProviderTestBase
 
 
 class AzureIntegrationInstanceServiceTestCase(ProviderTestBase):
-    @helpers.skipIfNoService(['compute.images'])
+    @helpers.skipIfNoService(['compute.instances'])
     def test_azure_instance_service(self):
-        instances_list = self.provider.compute.instances.list()
-        print("List Instances - " + str(instances_list))
-        print("Properties - ")
-        print("Id - " + str(instances_list[0].id))
-        print("name - " + str(instances_list[0].name))
-        print("public_ips - " + str(instances_list[0].public_ips))
-        print("private_ips - " + str(instances_list[0].private_ips))
-        print("instance_type_id - " + str(instances_list[0].instance_type_id))
-        print("instance_type - " + str(instances_list[0].instance_type))
-        print("image_id - " + str(instances_list[0].image_id))
-        print("zone_id - " + str(instances_list[0].zone_id))
-        print("security_groups - " +
-              str(instances_list[0].security_groups))
-        print("security_group_ids - " +
-              str(instances_list[0].security_group_ids))
-        print("key_pair_name - " + str(instances_list[0].key_pair_name))
-        print("state - " + str(instances_list[0].state))
-
-        print("Count - " + str(len(instances_list)))
-        self.assertTrue(len(instances_list) > 0)
-
-        instance_get = self.provider.compute.instances. \
-            get(instances_list[0].id)
-        print("Get Instance - " + str(instance_get))
-        self.assertIsNotNone(instance_get)
-
-        instance_find = self.provider.compute.instances. \
-            find(instances_list[0].name)
-        print("Find Instance - " + str(instance_find))
-        self.assertTrue(len(instance_find) > 0)
+        instance_name = 'CbAzure-inst-{0}'.format(uuid.uuid4().hex[:6])
+        image_name = 'CbAzure-img-{0}'.format(uuid.uuid4().hex[:6])
+        security_group_name = 'CbAzure-sg-{0}'.format(uuid.uuid4().hex[:6])
+        # key_pair_name = 'CbAzure-keypair-{0}'.format(uuid.uuid4().hex[:6])
+
+        image_id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
+                   '/resourceGroups/VM-TEST-RG/providers' \
+                   '/Microsoft.Compute/images/CbAzure-da80a6'
+
+        img = self.provider.compute.images.get(image_id)
+
+        self.assertIsNotNone(img)
+
+        # key_pair = self.provider.security.\
+        #     key_pairs.create(key_pair_name)
+        #
+        # self.assertIsNotNone(key_pair)
+        #
+        # with open('{0}.pem'.format(key_pair_name), 'w') as f:
+        #     f.write(key_pair.material)
+
+        inst_type = [t for t in self.provider.compute.instance_types.list()
+                     if t.name == 'Standard_DS1_v2'][0]
+
+        sg = self.provider.security.security_groups.\
+            create(security_group_name,
+                   'A security group used by CloudBridge', '')
+        sg.add_rule('tcp', 22, 22, '0.0.0.0/0')
+
+        subnet = self.provider.network.subnets.list()[1]
+
+        inst = self.provider.compute.instances.create(
+            name=instance_name, image=img, instance_type=inst_type,
+            subnet=subnet, zone=None,
+            key_pair=None, security_groups=None, user_data=None,
+            launch_config=None)
+
+        inst.wait_till_ready()
+
+        # floating_ip = self.provider.network.create_floating_ip()
+        #
+        # self.assertIsNotNone(floating_ip)
+        #
+        # inst.add_floating_ip(floating_ip.public_ip)
+        #
+        # inst.refresh()
+        #
+        # self.assertIsNotNone(inst.public_ips[0])
+
+        instance = self.provider.compute.\
+            instances.find(name=instance_name)[0]
+
+        self.assertIsNotNone(instance)
+
+        new_img = instance.create_image(image_name)
+        self.assertIsNotNone(new_img)
+
+        instance.terminate()

+ 59 - 0
azure_test/test_azure_instance_service.py

@@ -33,3 +33,62 @@ class AzureInstanceServiceTestCase(ProviderTestBase):
             find('VM1')
         print("Find Instance - " + str(instance_find))
         self.assertIsNotNone(instance_find)
+
+    @helpers.skipIfNoService(['block_store.snapshots'])
+    def test_azure_instance_create_and_get(self):
+        image_id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/' \
+                   'resourceGroups/CLOUDBRIDGE-AZURE/providers/' \
+                   'Microsoft.Compute/images/image3'
+
+        img = self.provider.compute.images.get(image_id)
+
+        self.assertIsNotNone(img)
+
+        # TODO: Add logic to get key pair
+        key_pair = None
+        # self.assertIsNotNone(key_pair)
+
+        inst_type = [t for t in self.provider.compute.instance_types.list()
+                     if t.name == 'Standard_DS1_v2'][0]
+        sg_id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
+                '/resourceGroups/CloudBridge-Azure' \
+                '/providers/Microsoft.Network/networkSecurityGroups/sg2'
+        sg = self.provider.security.\
+            security_groups.get(sg_id)
+
+        subnet = self.provider.network.subnets.list()[0]
+
+        lc = self.provider.compute.instances.create_launch_config()
+
+        lc.add_volume_device(
+            is_root=True,
+            source=img,
+            size=img.min_disk if img and img.min_disk else 2,
+            delete_on_terminate=True)
+
+        inst = self.provider.compute.instances.create(
+            name='test', image=img, instance_type=inst_type,
+            subnet=subnet, zone=None,
+            key_pair=key_pair, security_groups=[sg], user_data=None,
+            launch_config=lc)
+
+        self.assertIsNotNone(inst)
+
+        inst.reboot()
+
+        inst.name = 'newvmname'
+
+        self.assertEqual(inst.name, 'newvmname')
+
+        inst.add_security_group(sg)
+        inst.refresh()
+
+        # Check removing a security group from a running instance
+        inst.remove_security_group(sg)
+        inst.refresh()
+
+        img = inst.create_image('test_image')
+
+        self.assertIsNotNone(img)
+
+        inst.terminate()

+ 1 - 1
azure_test/test_azure_snapshots_service.py

@@ -73,7 +73,7 @@ class AzureSnapshotsServiceTestCase(ProviderTestBase):
             snapshot.name == "MySnapshot",
             "Snapshot name should be MySnapshot")
 
-        volume = snapshot.create_volume("MyVolume")
+        volume = snapshot.create_volume()
         self.assertTrue(
             volume is not None, "Snapshot not created")
         volume.delete()

+ 96 - 41
cloudbridge/cloud/providers/azure/azure_client.py

@@ -17,22 +17,17 @@ class AzureClient(object):
     def __init__(self, config):
         self._config = config
         self.subscription_id = config.get('azure_subscription_id')
-        credentials = ServicePrincipalCredentials(
+        self._credentials = ServicePrincipalCredentials(
             client_id=config.get('azure_client_Id'),
             secret=config.get('azure_secret'),
             tenant=config.get('azure_tenant')
         )
 
-        self._resource_client = ResourceManagementClient(credentials,
-                                                         self.subscription_id)
-        self._storage_client = StorageManagementClient(credentials,
-                                                       self.subscription_id)
-        self._network_management_client = NetworkManagementClient(
-            credentials, self.subscription_id)
-        self._subscription_client = SubscriptionClient(credentials)
-        self._compute_client = ComputeManagementClient(credentials,
-                                                       self.subscription_id)
-
+        self._resource_client = None
+        self._storage_client = None
+        self._network_management_client = None
+        self._subscription_client = None
+        self._compute_client = None
         self._access_key_result = None
         self._block_blob_service = None
 
@@ -57,24 +52,45 @@ class AzureClient(object):
     def region_name(self):
         return self._config.get('azure_region_name')
 
+    @property
+    def public_key_storage_table_name(self):
+        return self._config.get('azure_public_key_storage_table_name')
+
     @property
     def storage_client(self):
+        if not self._storage_client:
+            self._storage_client = \
+                StorageManagementClient(self._credentials,
+                                        self.subscription_id)
         return self._storage_client
 
     @property
     def subscription_client(self):
+        if not self._subscription_client:
+            self._subscription_client = SubscriptionClient(self._credentials)
         return self._subscription_client
 
     @property
     def resource_client(self):
+        if not self._resource_client:
+            self._resource_client = \
+                ResourceManagementClient(self._credentials,
+                                         self.subscription_id)
         return self._resource_client
 
     @property
     def compute_client(self):
+        if not self._compute_client:
+            self._compute_client = \
+                ComputeManagementClient(self._credentials,
+                                        self.subscription_id)
         return self._compute_client
 
     @property
     def network_management_client(self):
+        if not self._network_management_client:
+            self._network_management_client = NetworkManagementClient(
+                self._credentials, self.subscription_id)
         return self._network_management_client
 
     @property
@@ -270,25 +286,10 @@ class AzureClient(object):
             raw=True
         )
 
-    def get_vm(self, vm_name):
-        return self.compute_client.virtual_machines.get(
-            self.resource_group_name,
-            vm_name,
-            expand='instanceView'
-        )
-
-    def create_or_update_vm(self, vm_name, params):
-        return self.compute_client \
-            .virtual_machines.create_or_update(
-                self.resource_group_name,
-                vm_name,
-                params,
-                raw=True
-            )
-
-    def list_vm(self):
-        return self.compute_client. \
-            virtual_machines.list(self.resource_group_name)
+    def create_image(self, name, params):
+        return self.compute_client.images. \
+            create_or_update(self.resource_group_name, name,
+                             params, raw=True)
 
     def delete_image(self, name):
         self.compute_client.images. \
@@ -343,25 +344,79 @@ class AzureClient(object):
             )
         result_delete.wait()
 
-    def list_instances(self):
-        return self._compute_client.virtual_machines.list(
+    def list_vm(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(
+    def restart_vm(self, vm_name):
+        return self.compute_client.virtual_machines.restart(
             self.resource_group_name,
             vm_name
-        )
+        ).wait()
 
-    def terminate_instance(self, vm_name):
-        return self._compute_client.virtual_machines.power_off(
+    def delete_vm(self, vm_name):
+        return self.compute_client.virtual_machines.delete(
             self.resource_group_name,
             vm_name
-        )
+        ).wait()
 
-    def get_instance(self, vm_name):
-        return self._compute_client.virtual_machines.get(
+    def get_vm(self, vm_name):
+        return self.compute_client.virtual_machines.get(
             self.resource_group_name,
-            vm_name
+            vm_name,
+            expand='instanceView'
         )
+
+    def create_vm(self, vm_name, params):
+        return self.compute_client.virtual_machines. \
+            create_or_update(self.resource_group_name,
+                             vm_name, params, raw=True)
+
+    def deallocate_vm(self, vm_name):
+        self.compute_client. \
+            virtual_machines.deallocate(self.resource_group_name,
+                                        vm_name).wait()
+
+    def generalize_vm(self, vm_name):
+        self.compute_client.virtual_machines. \
+            generalize(self.resource_group_name, vm_name)
+
+    def start_vm(self, vm_name):
+        self.compute_client.virtual_machines. \
+            start(self.resource_group_name,
+                  vm_name).wait()
+
+    def update_vm_tags(self, vm_name, tags):
+        self.compute_client.virtual_machines. \
+            create_or_update(self.resource_group_name,
+                             vm_name, {'tags': tags})
+
+    def delete_nic(self, nic_name):
+        self.network_management_client. \
+            network_interfaces.delete(self.resource_group_name,
+                                      nic_name).wait()
+
+    def get_nic(self, name):
+        return self.network_management_client. \
+            network_interfaces.get(self.resource_group_name, name)
+
+    def create_nic(self, nic_name, params):
+        async_nic_creation = self.network_management_client. \
+            network_interfaces.create_or_update(
+                self.resource_group_name,
+                nic_name,
+                params
+            )
+        nic_info = async_nic_creation.result()
+
+        return nic_info
+
+    def get_public_ip(self, name):
+        return self.network_management_client. \
+            public_ip_addresses.get(self.resource_group_name, name)
+
+    def delete_public_ip(self, public_ip_name):
+        self.network_management_client. \
+            public_ip_addresses.delete(self.resource_group_name,
+                                       public_ip_name).wait()

+ 214 - 35
cloudbridge/cloud/providers/azure/mock_azure_client.py

@@ -6,10 +6,11 @@ from io import BytesIO
 from azure.common import AzureException
 from azure.mgmt.compute.models import CreationData, DataDisk, \
     Disk, DiskCreateOption, Image, ManagedDiskParameters, \
-    Snapshot, StorageProfile, VirtualMachine, \
+    NetworkProfile, OSDisk, Snapshot, StorageProfile, VirtualMachine, \
     VirtualMachineSize
 
-from azure.mgmt.network.models import AddressSpace, NetworkSecurityGroup
+from azure.mgmt.network.models import AddressSpace, NetworkInterface, \
+    NetworkSecurityGroup
 from azure.mgmt.network.models import SecurityRule
 from azure.mgmt.network.models import Subnet, VirtualNetwork
 from azure.mgmt.resource.resources.models import ResourceGroup
@@ -23,6 +24,10 @@ from msrestazure.azure_exceptions import CloudError
 from requests import Response
 
 
+class Expando(object):
+    pass
+
+
 class MockAzureClient:
     sg_rule1 = SecurityRule(protocol='*', source_address_prefix='100',
                             destination_address_prefix="*", access="Allow",
@@ -182,11 +187,29 @@ class MockAzureClient:
     snapshot2.account_type = ' Standard_LRS'
 
     snapshots = [snapshot1, snapshot2]
+
+    nic1 = NetworkInterface()
+    nic1.name = 'nic1'
+    nic1.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/' \
+              'resourceGroups/CLOUDBRIDGE-AZURE' \
+              '/providers/Microsoft.Network/' \
+              'networkInterfaces/nic1'
+
+    nic2 = NetworkInterface()
+    nic2.name = 'nic2'
+    nic2.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/' \
+              'resourceGroups/CLOUDBRIDGE-AZURE' \
+              '/providers/Microsoft.Network/' \
+              'networkInterfaces/nic2'
+
+    nics = [nic1, nic2]
+
     vm1 = VirtualMachine(location='eastus')
     vm1.name = 'VM1'
     vm1.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96'\
              '/resourceGroups/CLOUDBRIDGE-AZURE'\
              '/providers/Microsoft.Compute/virtualMachines/VM1'
+    vm1.provisioning_state = 'Succeeded'
     vm1.storage_profile = StorageProfile()
     vm1.tags = {'Name': 'VM1'}
     data_disk_id = '/subscriptions'\
@@ -198,15 +221,32 @@ class MockAzureClient:
                  lun=0, create_option='attach')
     vm1.storage_profile.data_disks = [data_dik]
 
+    vm1.storage_profile.os_disk = OSDisk(create_option='fromImage')
+    vm1.storage_profile.os_disk.managed_disk = \
+        ManagedDiskParameters(id='')
+    vm1.storage_profile.os_disk.disk_size_gb = 10
+
+    vm1.network_profile = NetworkProfile()
+    vm1.network_profile.network_interfaces = [nic1]
+
     vm2 = VirtualMachine(location='eastus')
     vm2.name = 'VM2'
     vm2.tags = {'Name': 'VM2'}
     vm2.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
              '/resourceGroups/CLOUDBRIDGE-AZURE' \
              '/providers/Microsoft.Compute/virtualMachines/VM2'
+    vm2.provisioning_state = 'Succeeded'
     vm2.storage_profile = StorageProfile()
     vm2.storage_profile.data_disks = [data_dik]
 
+    vm2.storage_profile.os_disk = OSDisk(create_option='fromImage')
+    vm2.storage_profile.os_disk.managed_disk = \
+        ManagedDiskParameters(id='')
+    vm2.storage_profile.os_disk.disk_size_gb = 10
+
+    vm2.network_profile = NetworkProfile()
+    vm2.network_profile.network_interfaces = [nic2]
+
     virtual_machines = [vm1, vm2]
 
     image1 = Image(location='eastus')
@@ -218,6 +258,10 @@ class MockAzureClient:
     image1.storage_profile = StorageProfile()
     image1.storage_profile.os_disk = ManagedDiskParameters(id='')
     image1.storage_profile.os_disk.disk_size_gb = 10
+    obj1 = Expando()
+    obj1.name = 'linux'
+    obj1.value = 'Linux'
+    image1.storage_profile.os_disk.os_type = obj1
 
     image2 = Image(location='eastus')
     image2.name = 'image2'
@@ -225,8 +269,31 @@ class MockAzureClient:
     image2.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
                 '/resourceGroups/CLOUDBRIDGE-AZURE' \
                 '/providers/Microsoft.Compute/images/image2'
+    image2.storage_profile = StorageProfile()
+    image2.storage_profile.os_disk = ManagedDiskParameters(id='')
+    image2.storage_profile.os_disk.disk_size_gb = 10
+
+    obj = Expando()
+    obj.name = 'linux'
+    obj.value = 'Linux'
+    image2.storage_profile.os_disk.os_type = obj
+
+    image3 = Image(location='eastus')
+    image3.name = 'image3'
+    image3.tags = {'Name': 'image3'}
+    image3.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
+                '/resourceGroups/CLOUDBRIDGE-AZURE' \
+                '/providers/Microsoft.Compute/images/image3'
+    image3.storage_profile = StorageProfile()
+    image3.storage_profile.os_disk = ManagedDiskParameters(id='')
+    image3.storage_profile.os_disk.disk_size_gb = 10
 
-    images = [image1, image2]
+    obj = Expando()
+    obj.name = 'linux'
+    obj.value = 'Linux'
+    image3.storage_profile.os_disk.os_type = obj
+
+    images = [image1, image2, image3]
 
     region1 = Location()
     region1.name = "westus2"
@@ -558,33 +625,80 @@ class MockAzureClient:
     def list_snapshots(self):
         return self.snapshots
 
-    def get_vm(self, vm_name):
-        for virtual_machine in self.virtual_machines:
-            if virtual_machine.name == vm_name:
-                return virtual_machine
+    def create_vm(self, vm_name, params):
+
+        if not isinstance(params, dict):
+            for data_disk in params.storage_profile.data_disks:
+                if isinstance(data_disk, dict):
+                    disk_id = data_disk.get('managed_disk').get('id')
+                    lun = data_disk.get('lun')
+                    create_option = data_disk.get('create_option')
+                    managed_disk = \
+                        ManagedDiskParameters(id=disk_id)
+                    params.storage_profile.data_disks.remove(data_disk)
+                    params.storage_profile.\
+                        data_disks\
+                        .append(DataDisk(managed_disk=managed_disk,
+                                lun=lun, create_option=create_option))
+
+            return params
+
+        vm = VirtualMachine(location='eastus')
+        vm.name = vm_name
+        vm.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
+                '/resourceGroups/CLOUDBRIDGE-AZURE' \
+                '/providers/Microsoft.Compute/virtualMachines/' + vm_name
+        vm.provisioning_state = 'Succeeded'
+        vm.storage_profile = StorageProfile()
+        vm.tags = {'Name': vm_name}
+        data_disk_id = '/subscriptions' \
+                       '/7904d702-e01c-4826-8519-f5a25c866a96' \
+                       '/resourceGroups/CLOUDBRIDGE-AZURE' \
+                       '/providers/Microsoft.Compute/disks/Volume2'
+        data_dik = \
+            DataDisk(managed_disk=ManagedDiskParameters(id=data_disk_id),
+                     lun=0, create_option='attach')
+        vm.storage_profile.data_disks = [data_dik]
+
+        vm.storage_profile.os_disk = OSDisk(create_option='fromImage')
+        os_disk_id = '/subscriptions' \
+                     '/7904d702-e01c-4826-8519-f5a25c866a96' \
+                     '/resourceGroups/CLOUDBRIDGE-AZURE' \
+                     '/providers/Microsoft.Compute/disks/os_disk'
+
+        vm.storage_profile.os_disk.managed_disk = \
+            ManagedDiskParameters(id=os_disk_id)
+        vm.storage_profile.os_disk.disk_size_gb = 10
+
+        os_disk = Disk(location='eastus', creation_data=None)
+        os_disk.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96' \
+                     '/resourceGroups/CLOUDBRIDGE-AZURE' \
+                     '/providers/Microsoft.Compute/disks/os_dsk'
+        os_disk.name = "os_disk"
+        os_disk.disk_size_gb = 30
+        os_disk.creation_data = \
+            CreationData(create_option=DiskCreateOption.empty)
+        os_disk.time_created = '20-04-2017'
+        os_disk.owner_id = None
+        os_disk.provisioning_state = 'Succeeded'
+        os_disk.tags = None
 
-        response = Response()
-        response.status_code = 404
-        raise CloudError(response=response, error='Resource Not found')
+        self.volumes.append(os_disk)
 
-    def create_or_update_vm(self, vm_name, params):
-        for data_disk in params.storage_profile.data_disks:
-            if isinstance(data_disk, dict):
-                disk_id = data_disk.get('managed_disk').get('id')
-                lun = data_disk.get('lun')
-                create_option = data_disk.get('create_option')
-                managed_disk = \
-                    ManagedDiskParameters(id=disk_id)
-                params.storage_profile.data_disks.remove(data_disk)
-                params.storage_profile.\
-                    data_disks\
-                    .append(DataDisk(managed_disk=managed_disk,
-                            lun=lun, create_option=create_option))
-
-        return params
+        nic = NetworkInterface()
+        nic.name = vm_name + '_NIC'
+        nic.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/' \
+                 'resourceGroups/CLOUDBRIDGE-AZURE' \
+                 '/providers/Microsoft.Network/' \
+                 'networkInterfaces/{0}_NIC'.format(vm_name)
 
-    def list_vm(self):
-        return self.virtual_machines
+        self.nics.append(nic)
+
+        vm.network_profile = NetworkProfile()
+        vm.network_profile.network_interfaces = [nic]
+
+        self.virtual_machines.append(vm)
+        return vm
 
     def list_images(self):
         return self.images
@@ -639,19 +753,84 @@ class MockAzureClient:
         subnet = self.get_subnet(network_name, subnet_name)
         self.subnets.remove(subnet)
 
-    def list_instances(self):
-        return self.virtual_machines
+    def create_image(self, name, params):
+        image = Image(location='eastus')
+        image.name = name
+        image.tags = {'Name': name}
+        image.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/' \
+                   'resourceGroups/CLOUDBRIDGE-AZURE/providers/' \
+                   'Microsoft.Compute/images/' + name
+        image.storage_profile = StorageProfile()
+        image.storage_profile.os_disk = ManagedDiskParameters(id='')
+        image.storage_profile.os_disk.disk_size_gb = 10
+        obj = Expando()
+        obj.name = 'linux'
+        obj.value = 'Linux'
+        image.storage_profile.os_disk.os_type = obj
+        self.images.append(image)
+        return image
+
+    def restart_vm(self, vm_name):
+        pass
 
-    def get_instance(self, vm_name):
-        for vm in self.virtual_machines:
-            if vm.name == vm_name:
-                return vm
+    def deallocate_vm(self, vm_name):
+        pass
+
+    def generalize_vm(self, vm_name):
+        pass
+
+    def start_vm(self, vm_name):
+        pass
+
+    def get_nic(self, name):
+        for nic in self.nics:
+            if nic.name == name:
+                return nic
         response = Response()
         response.status_code = 404
         raise CloudError(response=response, error='Resource Not found')
 
-    def reboot_instance(self, vm_name):
+    def create_nic(self, name, params):
+        nic = NetworkInterface()
+        nic.name = name
+        nic.id = '/subscriptions/7904d702-e01c-4826-8519-f5a25c866a96/' \
+                 'resourceGroups/CLOUDBRIDGE-AZURE' \
+                 '/providers/Microsoft.Network/' \
+                 'networkInterfaces/' + name
+        self.nics.append(nic)
+        return nic
+
+    def get_public_ip(self, name):
         pass
 
-    def terminate_instance(self, vm_name):
+    def update_vm_tags(self, vm_name, tags):
+        vm = self.get_vm(vm_name)
+        vm.tags = tags
+        return vm
+
+    def add_security_group_vm(self, vm_name, security_group_id):
         pass
+
+    def delete_security_group_vm(self, vm_name, security_group_id):
+        pass
+
+    def delete_vm(self, vm_name):
+        vm = self.get_vm(vm_name)
+        self.virtual_machines.remove(vm)
+
+    def delete_nic(self, nic_name):
+        pass
+
+    def delete_public_ip(self, public_ip_name):
+        self.get_public_ip(public_ip_name)
+
+    def list_vm(self):
+        return self.virtual_machines
+
+    def get_vm(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')

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

@@ -45,6 +45,10 @@ class AzureCloudProvider(BaseCloudProvider):
             'azure_storage_account_name', os.environ.get
             ('AZURE_STORAGE_ACCOUNT_NAME', 'cloudbridgeazure'))
 
+        self.default_user_name = self._get_config_value(
+            'azure_default_user_name', os.environ.get
+            ('AZURE_DEFAULT_USER_NAME', 'cbazureuser'))
+
         # create a dict with both optional and mandatory configuration values
         # to pass to the azureclient class, rather
         # than passing the provider object and taking a dependency.

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

@@ -4,25 +4,29 @@ DataTypes used by this provider
 import inspect
 import json
 import logging
+import time
 
 
 from azure.common import AzureException
 
+from azure.mgmt.network.models import NetworkSecurityGroup
+
 from cloudbridge.cloud.base.resources import BaseAttachmentInfo, \
-    BaseBucket, BaseBucketObject, BaseInstance, \
+    BaseBucket, BaseBucketObject, BaseInstance,\
     BaseInstanceType, \
-    BaseMachineImage, BaseNetwork, \
+    BaseLaunchConfig, BaseMachineImage, BaseNetwork, \
     BasePlacementZone, BaseRegion, \
     BaseSecurityGroup, BaseSecurityGroupRule, BaseSnapshot, BaseSubnet, \
     BaseVolume, ClientPagedResultList
-from cloudbridge.cloud.interfaces import VolumeState
+from cloudbridge.cloud.interfaces import InstanceState, VolumeState
 from cloudbridge.cloud.interfaces.resources import Instance, \
-    InstanceState, MachineImageState, \
-    NetworkState, SnapshotState
+    MachineImageState, NetworkState, SnapshotState
 from cloudbridge.cloud.providers.azure import helpers as azure_helpers
 
 from msrestazure.azure_exceptions import CloudError
 
+import pysftp
+
 log = logging.getLogger(__name__)
 
 NETWORK_RESOURCE_ID = '/subscriptions/{subscriptionId}/resourceGroups/' \
@@ -69,11 +73,13 @@ NETWORK_INTERFACE_RESOURCE_ID = '/subscriptions/{subscriptionId}/' \
                                 '/providers/Microsoft.Network/' \
                                 'networkInterfaces/{networkInterfaceName}'
 
+LOCATION_RESOURCE_ID = '/subscriptions/{subscriptionId}/' \
+                       'locations/{locationName}'
+
 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'
@@ -84,6 +90,7 @@ PUBLIC_IP_NAME = 'publicIpAddressName'
 ROUTE_TABLE_NAME = 'routeTableName'
 ROUTE_NAME = 'routeName'
 NETWORK_INTERFACE_NAME = 'networkInterfaceName'
+LOCATION_NAME = 'locationName'
 
 
 class AzureSecurityGroup(BaseSecurityGroup):
@@ -480,6 +487,10 @@ class AzureVolume(BaseVolume):
     def resource_name(self):
         return self._volume.name
 
+    @property
+    def tags(self):
+        return self._volume.tags
+
     @property
     def name(self):
         """
@@ -562,7 +573,7 @@ class AzureVolume(BaseVolume):
                 }
             })
             self._provider.azure_client \
-                .create_or_update_vm(params.get(VM_NAME), vm)
+                .create_vm(params.get(VM_NAME), vm)
             return True
         except CloudError as cloudError:
             log.exception(cloudError.message)
@@ -584,7 +595,7 @@ class AzureVolume(BaseVolume):
                 break
 
         if virtual_machine:
-            self._provider.azure_client.create_or_update_vm(
+            self._provider.azure_client.create_vm(
                 virtual_machine.name,
                 virtual_machine
             )
@@ -824,6 +835,10 @@ class AzureMachineImage(BaseMachineImage):
         """
         return self._image.storage_profile.os_disk.disk_size_gb
 
+    @property
+    def os_type(self):
+        return self._image.storage_profile.os_disk.os_type.value
+
     def delete(self):
         """
         Delete this image
@@ -1031,7 +1046,12 @@ class AzureSubnet(BaseSubnet):
 
     @property
     def zone(self):
-        return self._network.location
+        regions = [region
+                   for region in self._provider.
+                   compute.regions.list()
+                   if region.name == self._network.location]
+
+        return regions[0].zones[0]
 
     @property
     def cidr_block(self):
@@ -1053,26 +1073,73 @@ class AzureSubnet(BaseSubnet):
 
 
 class AzureInstance(BaseInstance):
+    # ref:
+    # http://docs.azure.amazon.com/AzureEC2/latest/UserGuide/ec2-instance-lifecycle.html
     INSTANCE_STATE_MAP = {
-        'pending': InstanceState.PENDING,
-        'running': InstanceState.RUNNING,
-        'shutting-down': InstanceState.CONFIGURING,
-        'terminated': InstanceState.TERMINATED,
-        'stopping': InstanceState.CONFIGURING,
-        'stopped': InstanceState.STOPPED
+        'InProgress': InstanceState.PENDING,
+        'Creating': InstanceState.PENDING,
+        'VM running': InstanceState.RUNNING,
+        'Updating': InstanceState.CONFIGURING,
+        'Deleted': InstanceState.TERMINATED,
+        'Stopping': InstanceState.CONFIGURING,
+        'Deleting': InstanceState.CONFIGURING,
+        'Stopped': InstanceState.STOPPED,
+        'Canceled': InstanceState.ERROR,
+        'Failed': InstanceState.ERROR,
+        'VM stopped': InstanceState.STOPPED,
+        'VM deallocated': InstanceState.STOPPED,
+        'VM deallocating': InstanceState.CONFIGURING,
+        'VM stopping': InstanceState.CONFIGURING,
+        'VM starting': InstanceState.CONFIGURING
     }
 
-    def __init__(self, provider, instance):
+    def __init__(self, provider, vm_instance):
         super(AzureInstance, self).__init__(provider)
-        self._instance = instance
-        self._state = self._instance.provisioning_state
+        self._vm = vm_instance
+        self._url_params = azure_helpers.\
+            parse_url(INSTANCE_RESOURCE_ID, vm_instance.id)
+        self.update_state()
+        self._get_network_attributes()
+        if not self._vm.tags:
+            self._vm.tags = {}
+
+    def _get_network_attributes(self):
+        self._private_ips = []
+        self._public_ips = []
+        self._security_group_ids = []
+        self._public_ip_ids = []
+        self._nic_ids = []
+        for nic in self._vm.network_profile.network_interfaces:
+            self._nic_ids.append(nic.id)
+            nic_params = azure_helpers.\
+                parse_url(NETWORK_INTERFACE_RESOURCE_ID, nic.id)
+            nic = self._provider.azure_client.\
+                get_nic(nic_params.get(NETWORK_INTERFACE_NAME))
+            if nic.network_security_group:
+                self._security_group_ids.append(nic.network_security_group.id)
+            if nic.ip_configurations:
+                for ip_config in nic.ip_configurations:
+                    self._private_ips.append(ip_config.private_ip_address)
+                    if ip_config.public_ip_address:
+                        url_params = azure_helpers.\
+                            parse_url(PUBLIC_IP_RESOURCE_ID,
+                                      ip_config.public_ip_address.id)
+                        public_ip = self._provider.\
+                            azure_client.\
+                            get_public_ip(url_params.get(PUBLIC_IP_NAME))
+                        self._public_ip_ids.append(public_ip.id)
+                        self._public_ips.append(public_ip.ip_address)
 
     @property
     def id(self):
         """
         Get the instance identifier.
         """
-        return self._instance.id
+        return self._vm.id
+
+    @property
+    def resource_name(self):
+        return self._vm.name
 
     @property
     def name(self):
@@ -1081,7 +1148,7 @@ class AzureInstance(BaseInstance):
 
         .. note:: an instance must have a (case sensitive) tag ``Name``
         """
-        return self._instance.name
+        return self._vm.tags.get('Name', self._vm.name)
 
     @name.setter
     # pylint:disable=arguments-differ
@@ -1089,28 +1156,30 @@ class AzureInstance(BaseInstance):
         """
         Set the instance name.
         """
-        self._instance.add_tag('Name', value)
+        self._vm.tags.update(Name=value)
+        self._provider.azure_client.\
+            update_vm_tags(self.resource_name, self._vm.tags)
 
     @property
     def public_ips(self):
         """
         Get all the public IP addresses for this instance.
         """
-        pass
+        return self._public_ips
 
     @property
     def private_ips(self):
         """
         Get all the private IP addresses for this instance.
         """
-        pass
+        return self._private_ips
 
     @property
     def instance_type_id(self):
         """
         Get the instance type name.
         """
-        return self._instance.hardware_profile.vm_size
+        return self._vm.hardware_profile.vm_size
 
     @property
     def instance_type(self):
@@ -1124,27 +1193,56 @@ class AzureInstance(BaseInstance):
         """
         Reboot this instance (using the cloud middleware API).
         """
-        self._provider.azure_client.reboot_instance(self.name)
+        self._provider.azure_client.restart_vm(self.resource_name)
 
     def terminate(self):
         """
         Permanently terminate this instance.
         """
-        self._provider.azure_client.terminate_instance(self.name)
+        self._provider.azure_client.deallocate_vm(self.resource_name)
+        self._provider.azure_client.delete_vm(self.resource_name)
+        for nic_id in self._nic_ids:
+            nic_id_params = azure_helpers.\
+                parse_url(NETWORK_INTERFACE_RESOURCE_ID, nic_id)
+            self._provider.azure_client.\
+                delete_nic(nic_id_params.get(NETWORK_INTERFACE_NAME))
+        for public_ip_id in self._public_ip_ids:
+            public_ip_id_params = azure_helpers.\
+                parse_url(PUBLIC_IP_RESOURCE_ID, public_ip_id)
+            self._provider.azure_client.\
+                delete_public_ip(public_ip_id_params.get(PUBLIC_IP_NAME))
+        for data_disk in self._vm.storage_profile.data_disks:
+            if data_disk.managed_disk:
+                disk_params = azure_helpers.\
+                    parse_url(VOLUME_RESOURCE_ID,
+                              data_disk.managed_disk.id)
+                disk = self._provider.azure_client.\
+                    get_disk(disk_params.get(VOLUME_NAME))
+                if disk and disk.tags \
+                        and disk.tags.get('delete_on_terminate',
+                                          'False') == 'True':
+                    self._provider.azure_client.\
+                        delete_disk(disk_params.get(VOLUME_NAME))
+        if self._vm.storage_profile.os_disk.managed_disk:
+            disk_params = azure_helpers. \
+                parse_url(VOLUME_RESOURCE_ID,
+                          self._vm.storage_profile.os_disk.managed_disk.id)
+            self._provider.azure_client. \
+                delete_disk(disk_params.get(VOLUME_NAME))
 
     @property
     def image_id(self):
         """
         Get the image ID for this insance.
         """
-        return self._instance.vm_id
+        return self._vm.storage_profile.image_reference.id
 
     @property
     def zone_id(self):
         """
         Get the placement zone id where this instance is running.
         """
-        return self._instance.location
+        return self._vm.location
 
     @property
     def security_groups(self):
@@ -1154,51 +1252,161 @@ class AzureInstance(BaseInstance):
         # boto instance.groups field returns a ``Group`` object so need to
         # convert that into a ``SecurityGroup`` object before creating a
         # cloudbridge SecurityGroup object
-        pass
+        return [self._provider.security.security_groups.get(group_id)
+                for group_id in self._security_group_ids]
 
     @property
     def security_group_ids(self):
         """
         Get the security groups IDs associated with this instance.
         """
-        pass
+        return self._security_group_ids
 
     @property
     def key_pair_name(self):
         """
         Get the name of the key pair associated with this instance.
         """
-        pass
+        return self._vm.tags.get('Key_Pair')
 
-    def create_image(self, name):
+    def create_image(self, name, private_key_path=None):
         """
         Create a new image based on this instance.
         """
-        pass
+
+        if not self._state == 'VM generalized':
+            if not self._state == 'VM running':
+                self._provider.azure_client.start_vm(self.resource_name)
+                time.sleep(60)
+                self._get_network_attributes()
+
+            if private_key_path:
+                self._deprovision(private_key_path)
+            self._provider.azure_client.deallocate_vm(self.resource_name)
+            self._provider.azure_client.generalize_vm(self.resource_name)
+
+        create_params = {
+            'location': self._provider.region_name,
+            'source_virtual_machine': {
+                'id': self.id
+            },
+            'tags': {'Name': name}
+        }
+        self._provider.azure_client.\
+            create_image(name, create_params)
+        image = self._provider.azure_client.\
+            get_image(name)
+
+        return AzureMachineImage(self._provider, image)
+
+    def _deprovision(self, private_key_path):
+        cnopts = pysftp.CnOpts()
+        cnopts.hostkeys = None
+
+        with pysftp.Connection(self.public_ips[0],
+                               username=self._provider.default_user_name,
+                               cnopts=cnopts,
+                               private_key=private_key_path) as sftp:
+            sftp.execute('sudo waagent -deprovision -force')
+            sftp.close()
 
     def add_floating_ip(self, ip_address):
-        """
-        Add an elastic IP address to this instance.
-        """
-        pass
+        try:
+            ip_addresses = [ip for ip in self._provider.
+                            azure_client.list_public_ips()
+                            if ip.ip_address and ip.ip_address == ip_address]
+            if len(ip_addresses) > 0:
+                """
+                Add an elastic IP address to this instance.
+                """
+                nic_params = azure_helpers. \
+                    parse_url(NETWORK_INTERFACE_RESOURCE_ID,
+                              self._vm.network_profile.
+                              network_interfaces[0].id)
+                nic_name = nic_params.get(NETWORK_INTERFACE_NAME)
+                nic = self._provider.azure_client.get_nic(nic_name)
+
+                nic.ip_configurations[0].public_ip_address = {
+                    'id': ip_addresses[0].id
+                }
+                self._provider.azure_client.\
+                    create_nic(nic_name, nic)
 
-    def remove_floating_ip(self, ip_address):
+                return True
+            return False
+        except CloudError as cloudError:
+            log.exception(cloudError.message)
+            return False
+
+    def remove_floating_ip(self, ip_address=None):
         """
         Remove a elastic IP address from this instance.
         """
-        pass
+        try:
+            nic_params = azure_helpers. \
+                parse_url(NETWORK_INTERFACE_RESOURCE_ID,
+                          self._vm.network_profile.network_interfaces[0].id)
+            nic_name = nic_params.get(NETWORK_INTERFACE_NAME)
+            nic = self._provider.azure_client.get_nic(nic_name)
+
+            nic.ip_configurations[0].public_ip_address = None
+            self._provider.azure_client. \
+                create_nic(nic_name, nic)
+            return True
+        except CloudError as cloudError:
+            log.exception(cloudError.message)
+            return False
 
     def add_security_group(self, sg):
-        """
-        Add a security group to this instance
-        """
-        pass
+        '''
+        :param sg:
+        :return: None
+
+        This method adds the security group to VM instance.
+        In Azure, security group added to Network interface.
+        Azure supports to add only one security group to
+        network interface, we are adding the provided security group 4
+        if not associated any security group to NIC
+        else replacing the existing security group.
+        '''
+
+        nic_id = \
+            self._vm.network_profile.network_interfaces[0].id
+        nic_params = azure_helpers.\
+            parse_url(NETWORK_INTERFACE_RESOURCE_ID, nic_id)
+        nic_name = nic_params.get(NETWORK_INTERFACE_NAME)
+        nic = self._provider.azure_client.get_nic(nic_name)
+        if not nic.network_security_group:
+            nic.network_security_group = NetworkSecurityGroup()
+
+        sg_id = sg.id if isinstance(sg, AzureSecurityGroup) else sg
+        nic.network_security_group.id = sg_id
+
+        self._provider.azure_client.\
+            create_nic(nic_name, nic)
 
     def remove_security_group(self, sg):
-        """
-        Remove a security group from this instance
-        """
-        pass
+        nic_id = \
+            self._vm.network_profile.network_interfaces[0].id
+        nic_params = azure_helpers. \
+            parse_url(NETWORK_INTERFACE_RESOURCE_ID, nic_id)
+        nic_name = nic_params.get(NETWORK_INTERFACE_NAME)
+        nic = self._provider.azure_client.get_nic(nic_name)
+        sg_id = sg.id if isinstance(sg, AzureSecurityGroup) else sg
+        if nic.network_security_group and \
+                nic.network_security_group.id == sg_id:
+            nic.network_security_group = None
+            self._provider.azure_client. \
+                create_nic(nic_name, nic)
+
+    def update_state(self):
+        if self._vm.instance_view and\
+                        len(self._vm.instance_view.statuses) > 1:
+            self._state = \
+                self._vm.instance_view.statuses[1].display_status
+        else:
+            self._state = \
+                self._vm.provisioning_state
 
     @property
     def state(self):
@@ -1210,7 +1418,25 @@ class AzureInstance(BaseInstance):
         Refreshes the state of this instance by re-querying the cloud provider
         for its latest state.
         """
-        pass
+        try:
+            self._vm = self._provider.\
+                azure_client.get_vm(self.resource_name)
+            if not self._vm.tags:
+                self._vm.tags = {}
+            self.update_state()
+            self._get_network_attributes()
+            print(self._state + ' : Vm state')
+        except (CloudError, ValueError) as cloudError:
+            log.exception(cloudError.message)
+            # The volume no longer exists and cannot be refreshed.
+            # set the status to unknown
+            self._state = 'unknown'
+
+
+class AzureLaunchConfig(BaseLaunchConfig):
+
+    def __init__(self, provider):
+        super(AzureLaunchConfig, self).__init__(provider)
 
 
 class AzureInstanceType(BaseInstanceType):
@@ -1262,4 +1488,7 @@ class AzureInstanceType(BaseInstanceType):
 
     @property
     def extra_data(self):
-        return None
+        return {
+                    'max_data_disk_count':
+                    self._inst_type.max_data_disk_count
+               }

+ 250 - 34
cloudbridge/cloud/providers/azure/services.py

@@ -12,24 +12,27 @@ from cloudbridge.cloud.base.services import BaseBlockStoreService, \
     BaseSecurityGroupService, \
     BaseSecurityService, BaseSnapshotService, \
     BaseSubnetService, BaseVolumeService
-from cloudbridge.cloud.interfaces.resources import Network,\
-    PlacementZone, Snapshot, Subnet, Volume
+from cloudbridge.cloud.interfaces import InvalidConfigurationException
+
+from cloudbridge.cloud.interfaces.resources import InstanceType, \
+    KeyPair, MachineImage, Network, PlacementZone, SecurityGroup, \
+    Snapshot, Subnet, Volume
+
 from cloudbridge.cloud.providers.azure import helpers as azure_helpers
 
 from msrestazure.azure_exceptions import CloudError
 
-from .resources import AzureBucket, AzureInstance, \
-    AzureInstanceType, \
-    AzureMachineImage, \
+from .resources import AzureBucket, \
+    AzureInstance, AzureInstanceType, \
+    AzureLaunchConfig, AzureMachineImage, \
     AzureNetwork, AzureRegion, AzureSecurityGroup, \
     AzureSnapshot, AzureSubnet, AzureVolume, \
-    IMAGE_NAME, IMAGE_RESOURCE_ID, \
-    INSTANCE_NAME, INSTANCE_RESOURCE_ID, \
-    NETWORK_NAME, NETWORK_RESOURCE_ID, \
-    NETWORK_SECURITY_GROUP_RESOURCE_ID, \
+    IMAGE_NAME, IMAGE_RESOURCE_ID, INSTANCE_RESOURCE_ID, \
+    LOCATION_NAME, LOCATION_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
+    VM_NAME, VOLUME_NAME, VOLUME_RESOURCE_ID
 
 log = logging.getLogger(__name__)
 
@@ -216,6 +219,11 @@ class AzureVolumeService(BaseVolumeService):
 
     def create(self, name, size, zone=None, snapshot=None, description=None):
         zone_id = zone.id if isinstance(zone, PlacementZone) else zone
+        zone_name = None
+        if zone_id:
+            zone_params = azure_helpers.\
+                parse_url(LOCATION_RESOURCE_ID, zone_id)
+            zone_name = zone_params.get(LOCATION_NAME)
         snapshot_id = snapshot.id if isinstance(
             snapshot, Snapshot) and snapshot else snapshot
         disk_name = "{0}-{1}".format(name, uuid.uuid4().hex[:6])
@@ -224,7 +232,8 @@ class AzureVolumeService(BaseVolumeService):
             tags.update(Description=description)
         if snapshot_id:
             params = {
-                'location': zone_id or self.provider.azure_client.region_name,
+                'location':
+                    zone_name or self.provider.azure_client.region_name,
                 'creation_data': {
                     'create_option': 'copy',
                     'source_uri': snapshot_id
@@ -236,7 +245,8 @@ class AzureVolumeService(BaseVolumeService):
 
         else:
             params = {
-                'location': zone_id or self.provider.azure_client.region_name,
+                'location':
+                    zone_name or self.provider.azure_client.region_name,
                 'disk_size_gb': size,
                 'creation_data': {
                     'create_option': 'empty'
@@ -343,45 +353,251 @@ class AzureInstanceService(BaseInstanceService):
     def __init__(self, provider):
         super(AzureInstanceService, self).__init__(provider)
 
-    def create(self, name=None):
-        raise NotImplementedError("AzureInstanceService"
-                                  " not implemented this method")
+    def create(self, name, image, instance_type, subnet, zone=None,
+               key_pair=None, security_groups=None, user_data=None,
+               launch_config=None, **kwargs):
+        if isinstance(image, MachineImage):
+            image_id = image.id
+        else:
+            image_id = image
+            image = self.provider.compute.images.get(image_id)
+        if key_pair:
+            if isinstance(key_pair, KeyPair):
+                key_pair_name = key_pair.name
+            else:
+                key_pair_name = key_pair
+                key_pair = self.provider.security.\
+                    key_pairs.get(key_pair_name)
+        # else:
+        #     raise Exception("Keypair required")
+
+        instance_size = instance_type.id if \
+            isinstance(instance_type, InstanceType) else instance_type
+        subnet = (self.provider.network.subnets.get(subnet)
+                  if isinstance(subnet, str) else subnet)
+        zone_id = zone.id if isinstance(zone, PlacementZone) else zone
+
+        subnet_id, zone_id, security_group_ids = \
+            self._resolve_launch_options(subnet, zone_id, security_groups)
+
+        zone_params = azure_helpers.parse_url(LOCATION_RESOURCE_ID, zone_id)
+
+        zone_name = None
+        if zone_id:
+            zone_name = zone_params.get(LOCATION_NAME)
+
+        if launch_config:
+            disks = self._process_block_device_mappings(launch_config,
+                                                        name, zone_id)
+        else:
+            disks = None
+
+        nic_params = {
+                'location': self._provider.region_name,
+                'ip_configurations': [{
+                    'name': 'MyIpConfig',
+                    'private_ip_allocation_method': 'Dynamic',
+                    'subnet': {
+                        'id': subnet_id
+                    }
+                }]
+            }
+
+        if security_groups:
+            nic_params['network_security_group'] = {
+                'id': security_group_ids[0]
+            }
+        nic_info = self.provider.azure_client.create_nic(
+            name + '_NIC',
+            nic_params
+        )
+
+        params = {
+            'location': zone_name or self._provider.region_name,
+            'os_profile': {
+                'admin_username': self.provider.default_user_name,
+                'admin_password': 'cbazureuser@123',
+                'computer_name': name
+            },
+            'hardware_profile': {
+                'vm_size': instance_size
+            },
+            'network_profile': {
+                'network_interfaces': [{
+                    'id': nic_info.id
+                }]
+            },
+            'storage_profile': {
+                'image_reference': {
+                    'id': image_id
+                },
+                "os_disk": {
+                    "name": name + '_Os_Disk',
+                    "create_option": "fromImage"
+                },
+                'data_disks': disks
+            },
+            'tags': {'Name': name}
+        }
+
+        if key_pair:
+            params['tags'].update(Key_Pair=key_pair_name)
+
+        if image.os_type == 'Linux' and key_pair:
+            params['os_profile']['linux_configuration'] = \
+                {
+                 "disable_password_authentication": True,
+                 "ssh": {
+                     "public_keys": [{
+                          "path":
+                          "/home/{}/.ssh/authorized_keys".format(
+                              self.provider.default_user_name),
+                          "key_data": key_pair.key
+                         }]
+                       }
+               }
+
+        instance_name = "{0}-{1}".format(name, uuid.uuid4().hex[:6])
+
+        self.provider.azure_client.create_vm(instance_name, params)
+        vm = self._provider.azure_client.get_vm(instance_name)
+        return AzureInstance(self.provider, vm)
+
+    def _resolve_launch_options(self, subnet=None, zone_id=None,
+                                security_groups=None):
+        """
+        Work out interdependent launch options.
+
+        Some launch options are required and interdependent so make sure
+        they conform to the interface contract.
+
+        :type subnet: ``Subnet``
+        :param subnet: Subnet object within which to launch.
+
+        :type zone_id: ``str``
+        :param zone_id: ID of the zone where the launch should happen.
+
+        :type security_groups: ``list`` of ``id``
+        :param zone_id: List of security group IDs.
+
+        :rtype: triplet of ``str``
+        :return: Subnet ID, zone ID and security group IDs for launch.
+
+        :raise ValueError: In case a conflicting combination is found.
+        """
+        if subnet:
+            # subnet's zone takes precedence
+            zone_id = subnet.zone.id
+        if isinstance(security_groups, list) and isinstance(
+                security_groups[0], SecurityGroup):
+            security_group_ids = [sg.id for sg in security_groups]
+        else:
+            security_group_ids = security_groups
+        return subnet.id, zone_id, security_group_ids
 
-    def create_launch_config(self, name=None):
-        raise NotImplementedError("AzureInstanceService"
-                                  " not implemented this method")
+    def _process_block_device_mappings(self, launch_config,
+                                       vm_name, zone=None):
+        """
+        Processes block device mapping information
+        and returns a Boto BlockDeviceMapping object. If new volumes
+        are requested (source is None and destination is VOLUME), they will be
+        created and the relevant volume ids included in the mapping.
+        """
+        disks = []
+        volumes_count = 0
+
+        def attach_volume(volume, delete_on_terminate):
+            disks.append({
+                'lun': volumes_count,
+                'name': volume.resource_name,
+                'create_option': 'attach',
+                'managed_disk': {
+                    'id': volume.id
+                }
+            })
+            delete_on_terminate = delete_on_terminate or False
+            volume.tags.update(delete_on_terminate=str(delete_on_terminate))
+            self.provider.azure_client.\
+                update_disk_tags(volume.resource_name, volume.tags)
+
+        # assign ephemeral devices from 0 onwards
+        # ephemeral_counter = 0
+
+        for device in launch_config.block_devices:
+            if device.is_volume and not device.is_root:
+                if isinstance(device.source, Snapshot):
+                    snapshot_vol = device.source.create_volume()
+                    attach_volume(snapshot_vol, device.delete_on_terminate)
+                elif isinstance(device.source, Volume):
+                    attach_volume(device.source, device.delete_on_terminate)
+                elif isinstance(device.source, MachineImage):
+                    # Not supported
+                    pass
+                else:
+                    # source is None, but destination is volume, therefore
+                    # create a blank volume. If the Zone is None, this
+                    # could fail since the volume and instance may be created
+                    # in two different zones.
+                    if not zone:
+                        raise InvalidConfigurationException(
+                            "A zone must be specified when launching with a"
+                            " new blank volume block device mapping.")
+                    vol_name = "{0}_disk".format(vm_name, uuid.uuid4().hex[:6])
+                    new_vol = self.provider.block_store.volumes.create(
+                        vol_name,
+                        device.size,
+                        zone)
+                    attach_volume(new_vol, device.delete_on_terminate)
+                # bd_type.delete_on_terminate = device.delete_on_terminate
+                # if device.size:
+                #     bd_type.size = device.size
+                volumes_count += 1
+
+            else:  # device is ephemeral
+                # bd_type.ephemeral_name = 'ephemeral%s' % ephemeral_counter
+                pass
+
+        return disks
+
+    def create_launch_config(self):
+        return AzureLaunchConfig(self.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,
+        instances = [AzureInstance(self.provider, inst)
+                     for inst in self.provider.azure_client.list_vm()]
+        return ClientPagedResultList(self.provider, instances,
                                      limit=limit, marker=marker)
 
     def get(self, instance_id):
+        """
+        Returns an instance given its id. Returns None
+        if the object does not exist.
+        """
         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)
+            params = azure_helpers.\
+                parse_url(INSTANCE_RESOURCE_ID, instance_id)
+            vm = self.provider.azure_client. \
+                get_vm(params.get(VM_NAME))
+            return AzureInstance(self.provider, vm)
         except CloudError as cloudError:
             log.exception(cloudError.message)
             return None
 
     def find(self, name, limit=None, marker=None):
         """
-         Searches for a instance by a given list of attributes.
+        Searches for an instance by a given list of attributes.
+
+        :rtype: ``object`` of :class:`.Instance`
+        :return: an Instance object
         """
-        filters = {'Name': name}
-        cb_instances = [AzureInstance(self.provider, instance)
-                        for instance in azure_helpers.filter(
-                self.provider.azure_client.list_instances(), filters)]
-        return ClientPagedResultList(self.provider, cb_instances,
+        filtr = {'Name': name}
+        instances = [AzureInstance(self.provider, inst)
+                     for inst in azure_helpers.filter(
+                self.provider.azure_client.list_vm(), filtr)]
+        return ClientPagedResultList(self.provider, instances,
                                      limit=limit, marker=marker)