def test_attach_new_datadisk_custom_on_vm(self, mock_vm_set, mock_vm_get): #pylint: disable=line-too-long faked_vhd_uri = 'https://your_stoage_account_name.blob.core.windows.net/vhds/d1.vhd' faked_vhd_uri2 = 'https://your_stoage_account_name.blob.core.windows.net/vhds/d2.vhd' #stub to get the vm which has no datadisks vhd = VirtualHardDisk(faked_vhd_uri) existing_disk = DataDisk(lun=1, vhd=vhd, name='d1', create_option=DiskCreateOptionTypes.empty) vm = FakedVM(None, [existing_disk]) mock_vm_get.return_value = vm #execute attach_new_disk('rg1', 'vm1', VirtualHardDisk(faked_vhd_uri2), None, 'd2', 512, CachingTypes.read_write) #assert self.assertTrue(mock_vm_get.called) mock_vm_set.assert_called_once_with(vm) self.assertEqual(len(vm.storage_profile.data_disks), 2) data_disk = vm.storage_profile.data_disks[1] self.assertEqual(CachingTypes.read_write, data_disk.caching) self.assertEqual(DiskCreateOptionTypes.empty, data_disk.create_option) self.assertIsNone(data_disk.image) self.assertEqual( data_disk.lun, 0 ) #the existing disk has '1', so it verifes the second one be picked as '0' self.assertEqual(data_disk.vhd.uri, faked_vhd_uri2)
def get_storage(self, vhd_url, vhd_name): """ Get Storage for given VHD name and VHD URL""" vm_name = self.vm_json.get('name') vhd_name = "%s-osDisk-%s" % (vm_name, vhd_name) return StorageProfile( os_disk=OSDisk(name=vm_name, image=VirtualHardDisk(uri=vhd_url), vhd=VirtualHardDisk( uri='https://%s.blob.core.windows.net/%s/%s' % (self.storage_account, self.container_name, vhd_name)), disk_size_gb=64, create_option=DiskCreateOptionTypes.from_image, caching='ReadWrite', os_type=OperatingSystemTypes.linux))
def disk_attach(): # Delete VM print('Deleting VM and freeing OS disk from ' + orig_vm_name) print('OS Disk Location ' + orig_vm_os_disk) result = compute_client.virtual_machines.delete(sys.argv[2], orig_vm_name) result.wait() # Ensures no lingering lease issues time.sleep(5) # Attach OS disk to temporary VM print('Attaching original OS disk to {0}'.format(vm_name)) result = compute_client.virtual_machines.create_or_update( group_name, vm_name, VirtualMachine( location=orig_vm_location, storage_profile=StorageProfile( data_disks=[DataDisk( lun=0, caching=CachingTypes.none, create_option=DiskCreateOptionTypes.attach, name=orig_vm_name, vhd=VirtualHardDisk( uri=orig_vm_os_disk ) )] ) ) ) result.wait()
def test_deattach_disk_on_vm(self, mock_vm_set, mock_vm_get): # pylint: disable=line-too-long # stub to get the vm which has no datadisks faked_vhd_uri = 'https://your_stoage_account_name.blob.core.windows.net/vhds/d1.vhd' existing_disk = DataDisk(lun=1, vhd=VirtualHardDisk(faked_vhd_uri), name='d1', create_option=DiskCreateOptionTypes.empty) vm = FakedVM(None, [existing_disk]) mock_vm_get.return_value = vm # execute detach_disk('rg1', 'vm1', 'd1') # assert self.assertTrue(mock_vm_get.called) mock_vm_set.assert_called_once_with(vm) self.assertEqual(len(vm.storage_profile.data_disks), 0)
def test_attach_new_datadisk_default_on_vm(self, mock_vm_set, mock_vm_get): #pylint: disable=line-too-long faked_vhd_uri = 'https://your_stoage_account_name.blob.core.windows.net/vhds/d1.vhd' #stub to get the vm which has no datadisks vm = FakedVM(None, None) mock_vm_get.return_value = vm #execute attach_new_disk('rg1', 'vm1', VirtualHardDisk(faked_vhd_uri)) #assert self.assertTrue(mock_vm_get.called) mock_vm_set.assert_called_once_with(vm) self.assertEqual(len(vm.storage_profile.data_disks), 1) data_disk = vm.storage_profile.data_disks[0] self.assertIsNone(data_disk.caching) self.assertEqual(data_disk.create_option, DiskCreateOptionTypes.empty) self.assertIsNone(data_disk.image) self.assertEqual(data_disk.lun, 0) self.assertEqual(data_disk.name, 'd1') self.assertEqual(data_disk.vhd.uri, faked_vhd_uri)
def json_parse(self, compute_client): """Parses the local .json file for previously attached disks""" with open(self.json_path) as fp: ingest = json.load(fp) dd = [] for disk in ingest['storageProfile']['dataDisks']: a_disk = DataDisk(lun=disk['lun'], caching=disk['caching'].lower(), create_option=DiskCreateOptionTypes.attach, name=disk['name'], vhd=VirtualHardDisk(uri=disk['vhd']['uri'])) dd.append(a_disk) print( 'Attaching data disk {0} with name {1}, waiting until complete...' .format(a_disk.lun, a_disk.name)) result = compute_client.virtual_machines.create_or_update( self.rg_name, self.vm_name, VirtualMachine(location=ingest['location'], storage_profile=StorageProfile(data_disks=dd))) result.wait() print('All disks should be attached now.')
def create_virtual_machine(self, credentials, network_client, network_id, parameters, vm_network_name): """ Creates an Azure virtual machine using the network interface created. Args: credentials: A ServicePrincipalCredentials instance, that can be used to access or create any resources. network_client: A NetworkManagementClient instance. network_id: The network id of the network interface created. parameters: A dict, containing all the parameters necessary to authenticate this user with Azure. vm_network_name: The name of the virtual machine to use. """ resource_group = parameters[self.PARAM_RESOURCE_GROUP] storage_account = parameters[self.PARAM_STORAGE_ACCOUNT] zone = parameters[self.PARAM_ZONE] utils.log("Creating a Virtual Machine '{}'".format(vm_network_name)) subscription_id = str(parameters[self.PARAM_SUBSCRIBER_ID]) azure_instance_type = parameters[self.PARAM_INSTANCE_TYPE] compute_client = ComputeManagementClient(credentials, subscription_id) auth_keys_path = self.AUTHORIZED_KEYS_FILE.format(self.ADMIN_USERNAME) with open(auth_keys_path, 'r') as pub_ssh_key_fd: pub_ssh_key = pub_ssh_key_fd.read() public_keys = [SshPublicKey(path=auth_keys_path, key_data=pub_ssh_key)] ssh_config = SshConfiguration(public_keys=public_keys) linux_config = LinuxConfiguration(disable_password_authentication=True, ssh=ssh_config) os_profile = OSProfile(admin_username=self.ADMIN_USERNAME, computer_name=vm_network_name, linux_configuration=linux_config) hardware_profile = HardwareProfile(vm_size=azure_instance_type) network_profile = NetworkProfile( network_interfaces=[NetworkInterfaceReference(id=network_id)]) virtual_hd = VirtualHardDisk( uri='https://{0}.blob.core.windows.net/vhds/{1}.vhd'. format(storage_account, vm_network_name)) image_hd = VirtualHardDisk(uri=parameters[self.PARAM_IMAGE_ID]) os_type = OperatingSystemTypes.linux os_disk = OSDisk(os_type=os_type, caching=CachingTypes.read_write, create_option=DiskCreateOptionTypes.from_image, name=vm_network_name, vhd=virtual_hd, image=image_hd) compute_client.virtual_machines.create_or_update( resource_group, vm_network_name, VirtualMachine( location=zone, os_profile=os_profile, hardware_profile=hardware_profile, network_profile=network_profile, storage_profile=StorageProfile(os_disk=os_disk))) # Sleep until an IP address gets associated with the VM. while True: public_ip_address = network_client.public_ip_addresses.get(resource_group, vm_network_name) if public_ip_address.ip_address: utils.log('Azure VM is available at {}'. format(public_ip_address.ip_address)) break utils.log("Waiting {} second(s) for IP address to be available". format(self.SLEEP_TIME)) time.sleep(self.SLEEP_TIME)
def deploy_template(self, template, vm_name=None, **vm_settings): resource_group = vm_settings['resource_group'] location = vm_settings['region_api'] subnet = vm_settings['subnet_range'] address_space = vm_settings['address_space'] vnet_name = vm_settings['virtual_net'] vm_size = vm_settings['vm_size'] storage_container = vm_settings['storage_container'] # nsg_name = vm_settings['network_nsg'] # todo: check whether nsg is necessary at all # allocating public ip address for new vm public_ip_params = { 'location': location, 'public_ip_allocation_method': 'Dynamic' } public_ip = self.network_client.public_ip_addresses.create_or_update( resource_group_name=resource_group, public_ip_address_name=vm_name, parameters=public_ip_params).result() # creating virtual network virtual_networks = self.network_client.virtual_networks if vnet_name not in [ v.name for v in virtual_networks.list(resource_group) ]: vnet_params = { 'location': location, 'address_space': { 'address_prefixes': [ address_space, ] } } virtual_networks.create_or_update( resource_group_name=resource_group, virtual_network_name=vnet_name, parameters=vnet_params).result() # creating sub net subnet_name = 'default' subnets = self.network_client.subnets if subnet_name not in [ v.name for v in subnets.list(resource_group, vnet_name) ]: vsubnet = subnets.create_or_update( resource_group_name=resource_group, virtual_network_name=vnet_name, subnet_name='default', subnet_parameters={ 'address_prefix': subnet }).result() else: vsubnet = subnets.get(resource_group_name=resource_group, virtual_network_name=vnet_name, subnet_name='default') # creating network interface nic_params = { 'location': location, 'ip_configurations': [{ 'name': vm_name, 'public_ip_address': public_ip, 'subnet': { 'id': vsubnet.id } }] } nic = self.network_client.network_interfaces.create_or_update( resource_group_name=resource_group, network_interface_name=vm_name, parameters=nic_params).result() # preparing os disk # todo: replace with copy disk operation self.copy_blob_image(template, vm_name, vm_settings['storage_account'], vm_settings['template_container'], storage_container) image_uri = self.container_client.make_blob_url( container_name=storage_container, blob_name=vm_name) # creating virtual machine vm_parameters = { 'location': location, 'hardware_profile': { 'vm_size': getattr(VirtualMachineSizeTypes, vm_size) }, 'storage_profile': { 'os_disk': { 'os_type': 'Linux', 'name': vm_name, 'vhd': VirtualHardDisk(uri=image_uri + ".vhd"), 'create_option': DiskCreateOptionTypes.attach, } }, 'network_profile': { 'network_interfaces': [{ 'id': nic.id }] }, } vm = self.compute_client.virtual_machines.create_or_update( resource_group_name=resource_group, vm_name=vm_name, parameters=vm_parameters).result() self.wait_vm_running(vm.name, vm_settings['resource_group']) return vm.name
def deploy(self, vm_name, **vm_settings): # TODO: this method is huge, it should be broken up ... # TODO #2: check args of vm_settings better # TODO #3: possibly use compute images instead of blob images? resource_group = vm_settings.get('resource_group', self.system.resource_group) location = vm_settings.get('region_api', self.system.region) subnet = vm_settings['subnet_range'] address_space = vm_settings['address_space'] vnet_name = vm_settings['virtual_net'] vm_size = vm_settings['vm_size'] storage_container = vm_settings['storage_container'] # nsg_name = vm_settings['network_nsg'] # todo: check whether nsg is necessary at all # allocating public ip address for new vm public_ip_params = { 'location': location, 'public_ip_allocation_method': 'Dynamic' } public_ip = self.system.network_client.public_ip_addresses.create_or_update( resource_group_name=resource_group, public_ip_address_name=vm_name, parameters=public_ip_params).result() # creating virtual network virtual_networks = self.system.network_client.virtual_networks if vnet_name not in [ v.name for v in virtual_networks.list(resource_group) ]: vnet_params = { 'location': location, 'address_space': { 'address_prefixes': [address_space] } } virtual_networks.create_or_update( resource_group_name=resource_group, virtual_network_name=vnet_name, parameters=vnet_params).result() # creating sub net subnet_name = 'default' subnets = self.system.network_client.subnets if subnet_name not in [ v.name for v in subnets.list(resource_group, vnet_name) ]: vsubnet = subnets.create_or_update( resource_group_name=resource_group, virtual_network_name=vnet_name, subnet_name='default', subnet_parameters={ 'address_prefix': subnet }).result() else: vsubnet = subnets.get(resource_group_name=resource_group, virtual_network_name=vnet_name, subnet_name='default') # creating network interface nic_params = { 'location': location, 'ip_configurations': [{ 'name': vm_name, 'public_ip_address': public_ip, 'subnet': { 'id': vsubnet.id } }] } def _create_or_update_nic(): return self.system.network_client.network_interfaces.create_or_update( resource_group_name=resource_group, network_interface_name=vm_name, parameters=nic_params).result() try: nic = _create_or_update_nic() except CloudError: # Try one more time if we hit an error nic = _create_or_update_nic() # preparing os disk # todo: replace with copy disk operation self.system.copy_blob_image(self.name, vm_name, vm_settings['storage_account'], self._container, storage_container) image_uri = self.system.container_client.make_blob_url( container_name=storage_container, blob_name=vm_name) # creating virtual machine vm_parameters = { 'location': location, 'hardware_profile': { 'vm_size': getattr(VirtualMachineSizeTypes, vm_size) }, 'storage_profile': { 'os_disk': { 'os_type': 'Linux', # TODO: why is this hardcoded? 'name': vm_name, 'vhd': VirtualHardDisk(uri=image_uri + ".vhd"), 'create_option': DiskCreateOptionTypes.attach, } }, 'network_profile': { 'network_interfaces': [{ 'id': nic.id }] }, } vm = self.system.compute_client.virtual_machines.create_or_update( resource_group_name=resource_group, vm_name=vm_name, parameters=vm_parameters).result() vm = AzureInstance(system=self.system, name=vm.name, resource_group=vm_settings['resource_group'], raw=vm) vm.wait_for_state(VmState.RUNNING) return vm
def request_instance(call=None, kwargs=None): # pylint: disable=unused-argument ''' Request that Azure spin up a new instance ''' global compconn # pylint: disable=global-statement,invalid-name if not compconn: compconn = get_conn() vm_ = kwargs if vm_.get('driver') is None: vm_['driver'] = 'azurearm' if vm_.get('location') is None: vm_['location'] = get_location() if vm_.get('resource_group') is None: vm_['resource_group'] = config.get_cloud_config_value( 'resource_group', vm_, __opts__, search_global=True) if vm_.get('name') is None: vm_['name'] = config.get_cloud_config_value('name', vm_, __opts__, search_global=True) os_kwargs = {} userdata = None userdata_file = config.get_cloud_config_value('userdata_file', vm_, __opts__, search_global=False, default=None) if userdata_file is None: userdata = config.get_cloud_config_value('userdata', vm_, __opts__, search_global=False, default=None) else: if os.path.exists(userdata_file): with salt.utils.fopen(userdata_file, 'r') as fh_: userdata = fh_.read() if userdata is not None: os_kwargs['custom_data'] = base64.b64encode(userdata) iface_data = create_interface(kwargs=vm_) vm_['iface_id'] = iface_data['id'] disk_name = '{0}-vol0'.format(vm_['name']) vm_username = config.get_cloud_config_value( 'ssh_username', vm_, __opts__, search_global=True, default=config.get_cloud_config_value('win_username', vm_, __opts__, search_global=True)) vm_password = config.get_cloud_config_value( 'ssh_password', vm_, __opts__, search_global=True, default=config.get_cloud_config_value('win_password', vm_, __opts__, search_global=True)) win_installer = config.get_cloud_config_value('win_installer', vm_, __opts__, search_global=True) if vm_['image'].startswith('http'): # https://{storage_account}.blob.core.windows.net/{path}/{vhd} source_image = VirtualHardDisk(uri=vm_['image']) img_ref = None if win_installer: os_type = 'Windows' else: os_type = 'Linux' else: img_pub, img_off, img_sku, img_ver = vm_['image'].split('|') source_image = None os_type = None img_ref = ImageReference( publisher=img_pub, offer=img_off, sku=img_sku, version=img_ver, ) params = VirtualMachine( name=vm_['name'], location=vm_['location'], plan=None, hardware_profile=HardwareProfile(vm_size=getattr( VirtualMachineSizeTypes, vm_['size'].lower()), ), storage_profile=StorageProfile( os_disk=OSDisk( caching=CachingTypes.none, create_option=DiskCreateOptionTypes.from_image, name=disk_name, vhd=VirtualHardDisk( uri='https://{0}.blob.core.windows.net/vhds/{1}.vhd'. format( vm_['storage_account'], disk_name, ), ), os_type=os_type, image=source_image, ), image_reference=img_ref, ), os_profile=OSProfile(admin_username=vm_username, admin_password=vm_password, computer_name=vm_['name'], **os_kwargs), network_profile=NetworkProfile(network_interfaces=[ NetworkInterfaceReference(vm_['iface_id']), ], ), ) poller = compconn.virtual_machines.create_or_update( vm_['resource_group'], vm_['name'], params) poller.wait() try: return show_instance(vm_['name'], call='action') except CloudError: return {}
def temp_vm(): # Generate random value to avoid duplicate resource group hash = random.getrandbits(16) # Defining vars base_name = 'rescue' + str(hash) storage_name = base_name group_name = base_name vm_name = base_name vnet_name = base_name subnet_name = base_name nic_name = base_name os_disk_name = base_name pub_ip_name = base_name computer_name = base_name admin_username='******' admin_password='******' region = orig_vm_location image_publisher = 'Canonical' image_offer = 'UbuntuServer' image_sku = '16.04.0-LTS' image_version = 'latest' # Helper function to create a network interface and vnet def create_network_interface(network_client, region, group_name, interface_name, network_name, subnet_name, ip_name): result = network_client.virtual_networks.create_or_update( group_name, network_name, VirtualNetwork( location=region, address_space=AddressSpace( address_prefixes=[ '10.1.0.0/16', ], ), subnets=[ Subnet( name=subnet_name, address_prefix='10.1.0.0/24', ), ], ), ) print('Creating Virtual Network...') result.wait() # async operation subnet = network_client.subnets.get(group_name, network_name, subnet_name) result = network_client.public_ip_addresses.create_or_update( group_name, ip_name, PublicIPAddress( location=region, public_ip_allocation_method=IPAllocationMethod.dynamic, idle_timeout_in_minutes=4, ), ) print('Creating Subnet...') result.wait() # async operation # Creating Public IP public_ip_address = network_client.public_ip_addresses.get(group_name, ip_name) public_ip_id = public_ip_address.id print('Creating Public IP...') result.wait() # async operation result = network_client.network_interfaces.create_or_update( group_name, interface_name, NetworkInterface( location=region, ip_configurations=[ NetworkInterfaceIPConfiguration( name='default', private_ip_allocation_method=IPAllocationMethod.dynamic, subnet=subnet, public_ip_address=PublicIPAddress( id=public_ip_id, ), ), ], ), ) print('Creating Network Interface...') result.wait() # async operation network_interface = network_client.network_interfaces.get( group_name, interface_name, ) return network_interface.id # 1. Create a resource group print('Creating resource group ' + base_name + '...') result = res_client.resource_groups.create_or_update( group_name, ResourceGroup( location=region, ), ) # 2. Create a storage account print('Creating storage group ' + base_name + '...') result = storage_client.storage_accounts.create( group_name, storage_name, StorageAccountCreateParameters( location=region, sku=Sku(SkuName.premium_lrs), kind=Kind.storage, ), ) result.result() # 3. Create the network interface using a helper function (defined below) nic_id = create_network_interface( network_client, region, group_name, nic_name, vnet_name, subnet_name, pub_ip_name, ) # 4. Create the virtual machine print('Creating temporary VM ' + vm_name + '...') result = compute_client.virtual_machines.create_or_update( group_name, vm_name, VirtualMachine( location=region, os_profile=OSProfile( admin_username=admin_username, admin_password=admin_password, computer_name=computer_name, ), hardware_profile=HardwareProfile( vm_size='Standard_DS1_v2' ), network_profile=NetworkProfile( network_interfaces=[ NetworkInterfaceReference( id=nic_id, ), ], ), storage_profile=StorageProfile( os_disk=OSDisk( caching=CachingTypes.none, create_option=DiskCreateOptionTypes.from_image, name=os_disk_name, vhd=VirtualHardDisk( uri='https://{0}.blob.core.windows.net/vhds/{1}.vhd'.format( storage_name, os_disk_name, ), ), ), image_reference = ImageReference( publisher=image_publisher, offer=image_offer, sku=image_sku, version=image_version, ), ), ), ) result.wait() # async operation # Display the public ip address # You can now connect to the machine using SSH public_ip_address = network_client.public_ip_addresses.get(group_name, pub_ip_name) print('\n' + vm_name + ' has started.') print('VM\'s public IP is {}'.format(public_ip_address.ip_address)) print('SSH Username: '******'SSH Password ' + admin_password) print('ssh ' + admin_username + '@' + public_ip_address.ip_address) # The process of shutting down the VM, deleting it, then removing/attaching OS disk to the temp def disk_attach(): # Delete VM print('Deleting VM and freeing OS disk from ' + orig_vm_name) print('OS Disk Location ' + orig_vm_os_disk) result = compute_client.virtual_machines.delete(sys.argv[2], orig_vm_name) result.wait() # Ensures no lingering lease issues time.sleep(5) # Attach OS disk to temporary VM print('Attaching original OS disk to {0}'.format(vm_name)) result = compute_client.virtual_machines.create_or_update( group_name, vm_name, VirtualMachine( location=orig_vm_location, storage_profile=StorageProfile( data_disks=[DataDisk( lun=0, caching=CachingTypes.none, create_option=DiskCreateOptionTypes.attach, name=orig_vm_name, vhd=VirtualHardDisk( uri=orig_vm_os_disk ) )] ) ) ) result.wait() disk_attach()
def _attach_or_detach_disk(self, vm_name, vhd_name, vhd_size_in_gibs, lun, detach=False, allow_lun_0_detach=False, is_from_retry=False): vmcompute = self.get_vm(vm_name) if (not detach): vhd_url = self._storage_client.make_blob_url( self._disk_container, vhd_name + ".vhd") print("Attach disk name %s lun %s uri %s" % (vhd_name, lun, vhd_url)) disk = DataDisk(lun=lun, name=vhd_name, vhd=VirtualHardDisk(vhd_url), caching="None", create_option="attach", disk_size_gb=vhd_size_in_gibs) vmcompute.storage_profile.data_disks.append(disk) else: for i in range(len(vmcompute.storage_profile.data_disks)): disk = vmcompute.storage_profile.data_disks[i] if disk.name == vhd_name: if disk.lun == 0 and not allow_lun_0_detach: # lun-0 is special, throw an exception if attempting # to detach that disk. raise AzureOperationNotAllowed() print("Detach disk name %s lun %s uri %s" % (disk.name, disk.lun, disk.vhd.uri)) del vmcompute.storage_profile.data_disks[i] break result = self._update_vm(vm_name, vmcompute) start = time.time() while True: time.sleep(2) waited_sec = int(abs(time.time() - start)) if waited_sec > self._async_timeout: raise AzureAsynchronousTimeout() if not result.done(): continue updated = self.get_vm(vm_name) print("Waited for %s s provisioningState is %s" % (waited_sec, updated.provisioning_state)) if updated.provisioning_state == "Succeeded": print("Operation finshed") break if updated.provisioning_state == "Failed": print("Provisioning ended up in failed state.") # Recovery from failed disk atatch-detach operation. # For Attach Disk: Detach The Disk then Try To Attach Again # For Detach Disk: Call update again, which always sets a tag, # which forces the service to retry. # is_from_retry is checked so we are not stuck in a loop # calling ourself if not is_from_retry and not detach: print( "Detach disk %s after failure, then try attach again" % vhd_name) self._attach_or_detach_disk(vm_name, vhd_name, vhd_size_in_gibs, lun, detach=True, allow_lun_0_detach=True, is_from_retry=True) print("Retry disk action for disk %s" % vhd_name) result = self._update_vm(vm_name, vmcompute)