def test_basic(self): scale_set = VirtualMachineScaleSet( 'eastus', { PRIORITY_TAG: '1', NO_SCHEDULE_TAINTS_TAG: json.dumps({'gpu': 'yes'}) }, sku=Sku('Standard_H16', capacity=1)) scale_set.name = 'test' scale_set.provisioning_state = 'Succeeded' scale_set.id = 'fake_id' compute_client = mock.Mock() compute_client.virtual_machine_scale_sets = mock.Mock() compute_client.virtual_machine_scale_sets.list = mock.Mock( return_value=[scale_set]) monitor_client = mock.Mock() monitor_client.activity_logs = mock.Mock() monitor_client.activity_logs.list = mock.Mock(return_value=[]) api = AzureWrapper(compute_client, monitor_client, None) resource_group = 'test_rg' expected = AzureScaleSet(scale_set.location, resource_group, scale_set.name, scale_set.sku.name, scale_set.sku.capacity, scale_set.provisioning_state, priority=1, no_schedule_taints={'gpu': 'yes'}) self.assertEqual([expected], api.list_scale_sets(resource_group)) compute_client.virtual_machine_scale_sets.list.assert_called_once_with( resource_group) monitor_client.activity_logs.list.assert_called_once()
def test_out_of_quota(self): scale_set = VirtualMachineScaleSet('eastus', {}, sku=Sku('Standard_H16', capacity=1)) scale_set.name = 'test' scale_set.provisioning_state = 'Succeeded' scale_set.id = 'fake_id' compute_client = mock.Mock() compute_client.virtual_machine_scale_sets = mock.Mock() compute_client.virtual_machine_scale_sets.list = mock.Mock(return_value=[scale_set]) reason = "Operation results in exceeding quota limits of Core. Maximum allowed: 800, Current in use: 784, Additional requested: 320." message = "{\"error\":{\"code\":\"OperationNotAllowed\",\"message\":\"" + reason + "\"}}" monitor_client = mock.Mock() monitor_client.activity_logs = mock.Mock() now = datetime.now(pytz.utc) monitor_client.activity_logs.list = mock.Mock(return_value=[EventData('Error', now, now, resource_id=scale_set.id, status=LocalizableString('Failed'), properties={'statusCode': 'Conflict', 'statusMessage': message})]) api = AzureWrapper(compute_client, monitor_client) resource_group = 'test_rg' expected = AzureScaleSet(scale_set.location, resource_group, scale_set.name, scale_set.sku.name, scale_set.sku.capacity, scale_set.provisioning_state, now + TIMEOUT_PERIOD, reason) acutal = api.list_scale_sets(resource_group) self.assertEqual([expected], acutal) compute_client.virtual_machine_scale_sets.list.assert_called_once_with(resource_group) monitor_client.activity_logs.list.assert_called_once()
def update_scale_set(self, scale_set: AzureScaleSet, new_capacity: int) -> Future: parameters = VirtualMachineScaleSet(scale_set.location, sku=Sku( name=scale_set.instance_type, capacity=new_capacity)) azure_op = self._compute_client.virtual_machine_scale_sets.create_or_update( scale_set.resource_group, scale_set.name, parameters=parameters) return AzureOperationPollerFutureAdapter(azure_op)
def scale_vmss(self, num_instances): print(f'Scaling VMSS {self.vmss.name} to {num_instances} instances...') update_params = VirtualMachineScaleSetUpdate( sku=Sku(name=self.vmss.sku.name, tier=self.vmss.sku.tier, capacity=num_instances)) update_oper = self.compute_client.virtual_machine_scale_sets.update( resource_group_name=self.resource_group, vm_scale_set_name=self.vmss_name, parameters=update_params) update_oper.wait() # Replace VMSS object with updated representation. self.vmss = update_oper.result()
def create_availabilityset(self): self.log("Creating availabilityset {0}".format(self.name)) try: paramsSku = Sku(name=self.sku) params = AvailabilitySet( location=self.location, tags=self.tags, platform_update_domain_count=self.platform_update_domain_count, platform_fault_domain_count=self.platform_fault_domain_count, sku=paramsSku) response = self.compute_client.availability_sets.create_or_update( self.resource_group, self.name, params) except CloudError as e: self.log('Error attempting to create the availability set.') self.fail("Error creating the availability set: {0}".format( str(e))) return availability_set_to_dict(response)
def exec_module(self, **kwargs): for key in list(self.module_arg_spec.keys()) + ['tags']: setattr(self, key, kwargs[key]) # make sure options are lower case self.remove_on_absent = set( [resource.lower() for resource in self.remove_on_absent]) changed = False results = dict() vmss = None disable_ssh_password = None vmss_dict = None virtual_network = None subnet = None resource_group = self.get_resource_group(self.resource_group) if not self.location: # Set default location self.location = resource_group.location if self.state == 'present': # Verify parameters and resolve any defaults if self.vm_size and not self.vm_size_is_valid(): self.fail( "Parameter error: vm_size {0} is not valid for your subscription and location." .format(self.vm_size)) # if self.virtual_network_name: # virtual_network = self.get_virtual_network(self.virtual_network_name) if self.ssh_public_keys: msg = "Parameter error: expecting ssh_public_keys to be a list of type dict where " \ "each dict contains keys: path, key_data." for key in self.ssh_public_keys: if not isinstance(key, dict): self.fail(msg) if not key.get('path') or not key.get('key_data'): self.fail(msg) if self.image: if not self.image.get('publisher') or not self.image.get('offer') or not self.image.get('sku') \ or not self.image.get('version'): self.error( "parameter error: expecting image to contain publisher, offer, sku and version keys." ) image_version = self.get_image_version() if self.image['version'] == 'latest': self.image['version'] = image_version.name self.log("Using image version {0}".format( self.image['version'])) disable_ssh_password = not self.ssh_password_enabled try: self.log("Fetching virtual machine scale set {0}".format( self.name)) vmss = self.compute_client.virtual_machine_scale_sets.get( self.resource_group, self.name) self.check_provisioning_state(vmss, self.state) vmss_dict = self.serialize_vmss(vmss) if self.state == 'present': differences = [] results = vmss_dict if self.os_disk_caching and \ self.os_disk_caching != vmss_dict['properties']['virtualMachineProfile']['storageProfile']['osDisk']['caching']: self.log( 'CHANGED: virtual machine scale set {0} - OS disk caching' .format(self.name)) differences.append('OS Disk caching') changed = True vmss_dict['properties']['virtualMachineProfile'][ 'storageProfile']['osDisk'][ 'caching'] = self.os_disk_caching if self.capacity and \ self.capacity != vmss_dict['sku']['capacity']: self.log( 'CHANGED: virtual machine scale set {0} - Capacity'. format(self.name)) differences.append('Capacity') changed = True vmss_dict['sku']['capacity'] = self.capacity if self.data_disks and \ len(self.data_disks) != len(vmss_dict['properties']['virtualMachineProfile']['storageProfile']['dataDisks']): self.log( 'CHANGED: virtual machine scale set {0} - Data Disks'. format(self.name)) differences.append('Data Disks') changed = True update_tags, vmss_dict['tags'] = self.update_tags( vmss_dict.get('tags', dict())) if update_tags: differences.append('Tags') changed = True self.differences = differences elif self.state == 'absent': self.log( "CHANGED: virtual machine scale set {0} exists and requested state is 'absent'" .format(self.name)) results = dict() changed = True except CloudError: self.log('Virtual machine scale set {0} does not exist'.format( self.name)) if self.state == 'present': self.log( "CHANGED: virtual machine scale set {0} does not exist but state is 'present'." .format(self.name)) changed = True self.results['changed'] = changed self.results['ansible_facts']['azure_vmss'] = results if self.check_mode: return self.results if changed: if self.state == 'present': if not vmss: # Create the VMSS self.log("Create virtual machine scale set {0}".format( self.name)) self.results['actions'].append('Created VMSS {0}'.format( self.name)) # Validate parameters if not self.admin_username: self.fail( "Parameter error: admin_username required when creating a virtual machine scale set." ) if self.os_type == 'Linux': if disable_ssh_password and not self.ssh_public_keys: self.fail( "Parameter error: ssh_public_keys required when disabling SSH password." ) if self.subnet_name: subnet = self.get_subnet(self.virtual_network_name, self.subnet_name) if not self.virtual_network_name: default_vnet = self.create_default_vnet() virtual_network = default_vnet.id if not self.short_hostname: self.short_hostname = self.name managed_disk = VirtualMachineScaleSetManagedDiskParameters( storage_account_type=self.managed_disk_type) vmss_resource = VirtualMachineScaleSet( self.location, tags=self.tags, upgrade_policy=UpgradePolicy(mode=self.upgrade_policy), sku=Sku( name=self.vm_size, capacity=self.capacity, tier=self.tier, ), virtual_machine_profile=VirtualMachineScaleSetVMProfile( os_profile=VirtualMachineScaleSetOSProfile( admin_username=self.admin_username, computer_name_prefix=self.short_hostname, ), storage_profile= VirtualMachineScaleSetStorageProfile( os_disk=VirtualMachineScaleSetOSDisk( managed_disk=managed_disk, create_option=DiskCreateOptionTypes. from_image, caching=self.os_disk_caching, ), image_reference=ImageReference( publisher=self.image['publisher'], offer=self.image['offer'], sku=self.image['sku'], version=self.image['version'], ), ), network_profile= VirtualMachineScaleSetNetworkProfile( network_interface_configurations=[ VirtualMachineScaleSetNetworkConfiguration( name=self.name, primary=True, ip_configurations=[ VirtualMachineScaleSetIPConfiguration( name='default', subnet=ApiEntityReference( id=subnet.id)) ]) ]))) if self.admin_password: vmss_resource.virtual_machine_profile.os_profile.admin_password = self.admin_password if self.os_type == 'Linux': vmss_resource.virtual_machine_profile.os_profile.linux_configuration = LinuxConfiguration( disable_password_authentication=disable_ssh_password ) if self.ssh_public_keys: ssh_config = SshConfiguration() ssh_config.public_keys = \ [SshPublicKey(path=key['path'], key_data=key['key_data']) for key in self.ssh_public_keys] vmss_resource.virtual_machine_profile.os_profile.linux_configuration.ssh = ssh_config if self.data_disks: data_disks = [] for data_disk in self.data_disks: data_disk_managed_disk = VirtualMachineScaleSetManagedDiskParameters( storage_account_type=data_disk[ 'managed_disk_type']) data_disk['caching'] = data_disk.get( 'caching', CachingTypes.read_only) data_disks.append( VirtualMachineScaleSetDataDisk( lun=data_disk['lun'], caching=data_disk['caching'], create_option=DiskCreateOptionTypes.empty, disk_size_gb=data_disk['disk_size_gb'], managed_disk=data_disk_managed_disk, )) vmss_resource.virtual_machine_profile.storage_profile.data_disks = data_disks self.log("Create virtual machine with parameters:") self.create_or_update_vmss(vmss_resource) elif self.differences and len(self.differences) > 0: self.log("Update virtual machine scale set {0}".format( self.name)) self.results['actions'].append('Updated VMSS {0}'.format( self.name)) vmss_resource = self.get_vmss() vmss_resource.virtual_machine_profile.storage_profile.os_disk.caching = self.os_disk_caching vmss_resource.sku.capacity = self.capacity data_disks = [] for data_disk in self.data_disks: data_disks.append( VirtualMachineScaleSetDataDisk( lun=data_disk['lun'], caching=data_disk['caching'], create_option=DiskCreateOptionTypes.empty, disk_size_gb=data_disk['disk_size_gb'], managed_disk= VirtualMachineScaleSetManagedDiskParameters( storage_account_type=data_disk[ 'managed_disk_type']), )) vmss_resource.virtual_machine_profile.storage_profile.data_disks = data_disks self.log("Update virtual machine with parameters:") self.create_or_update_vmss(vmss_resource) self.results['ansible_facts'][ 'azure_vmss'] = self.serialize_vmss(self.get_vmss()) elif self.state == 'absent': # delete the VM self.log("Delete virtual machine scale set {0}".format( self.name)) self.results['ansible_facts']['azure_vmss'] = None self.delete_vmss(vmss) # until we sort out how we want to do this globally del self.results['actions'] return self.results
def clone_vmss(vmScaleSetName, resourceGroupName, count): logging.info( "Collectiong Data from VM Scale Set {}".format(vmScaleSetName)) vmss_data = computeclient.virtual_machine_scale_sets.get( resourceGroupName, vmScaleSetName) StorageAccount = vmss_data.virtual_machine_profile.extension_profile.extensions[ 0].settings['StorageAccount'] logging.info( "Fetching Data from Storage Account {}".format(StorageAccount)) StorageAccountId = get_storage_account_info(resourceGroupName, StorageAccount) custom_data = get_user_data(StorageAccount) sku = Sku(name=vmss_data.sku.name, tier=vmss_data.sku.tier, capacity=0) os_profile = VirtualMachineScaleSetOSProfile( computer_name_prefix=vmss_data.virtual_machine_profile.os_profile. computer_name_prefix + str(count + 1), admin_username=vmss_data.virtual_machine_profile.os_profile. admin_username, windows_configuration=None, linux_configuration=vmss_data.virtual_machine_profile.os_profile. linux_configuration, custom_data=custom_data) virtual_machine_profile = VirtualMachineScaleSetVMProfile( os_profile=os_profile, storage_profile=vmss_data.virtual_machine_profile.storage_profile, #additional_capabilities=vmss_data.virtual_machine_profile.additional_capabilities, network_profile=vmss_data.virtual_machine_profile.network_profile, diagnostics_profile=vmss_data.virtual_machine_profile. diagnostics_profile) new_vmss_parameters = VirtualMachineScaleSet( location=vmss_data.location, tags=vmss_data.tags, sku=sku, plan=vmss_data.plan, upgrade_policy=vmss_data.upgrade_policy, virtual_machine_profile=virtual_machine_profile, overprovision=vmss_data.overprovision, do_not_run_extensions_on_overprovisioned_vms=vmss_data. do_not_run_extensions_on_overprovisioned_vms, single_placement_group=vmss_data.single_placement_group, zone_balance=vmss_data.zone_balance, platform_fault_domain_count=vmss_data.platform_fault_domain_count, identity=VirtualMachineScaleSetIdentity(type='SystemAssigned'), zones=vmss_data.zones) new_vm_scale_set = vmScaleSetName[:-1] + str(count + 1) logging.info( "Creating VM Scale Set with Name: {}".format(new_vm_scale_set)) new_vmss = computeclient.virtual_machine_scale_sets.create_or_update( resource_group_name=resourceGroupName, vm_scale_set_name=new_vm_scale_set, parameters=new_vmss_parameters) new_vmss.wait() new_vmss_data = new_vmss.result() new_vmss_id = new_vmss_data.id new_vmss_principal_id = new_vmss_data.identity.principal_id logging.info("Assiging Role - {} on Scope - {} for Prinicpal - {}".format( 'Owner', new_vmss_id, new_vmss_principal_id)) assign_role(new_vmss_id, 'Owner', new_vmss_principal_id) logging.info("Assiging Role - {} on Scope - {} for Prinicpal - {}".format( 'Storage Blob Data Contributor', StorageAccountId, new_vmss_principal_id)) assign_role(StorageAccountId, 'Storage Blob Data Contributor', new_vmss_principal_id) extension_settings = vmss_data.virtual_machine_profile.extension_profile.extensions[ 0].settings extension_settings['ladCfg']['diagnosticMonitorConfiguration']['metrics'][ 'resourceId'] = new_vmss_id logging.info( "Fetching SAS from Storage Account {}".format(StorageAccount)) sas_token = get_sas_token(resourceGroupName, StorageAccount) logging.info("SAS Token : {}".format(sas_token)) protected_settings = { 'storageAccountName': StorageAccount, 'storageAccountSasToken': sas_token } extension_profile = VirtualMachineScaleSetExtensionProfile(extensions=[ VirtualMachineScaleSetExtension( name=vmss_data.virtual_machine_profile.extension_profile. extensions[0].name, force_update_tag=vmss_data.virtual_machine_profile. extension_profile.extensions[0].force_update_tag, publisher=vmss_data.virtual_machine_profile.extension_profile. extensions[0].publisher, #type1=vmss_data.virtual_machine_profile.extension_profile.extensions[0].type, type=vmss_data.virtual_machine_profile.extension_profile. extensions[0].type, type_handler_version=vmss_data.virtual_machine_profile. extension_profile.extensions[0].type_handler_version, auto_upgrade_minor_version=vmss_data.virtual_machine_profile. extension_profile.extensions[0].auto_upgrade_minor_version, settings=extension_settings, protected_settings=protected_settings, provision_after_extensions=vmss_data.virtual_machine_profile. extension_profile.extensions[0].provision_after_extensions) ]) update_virtual_machine_profile = VirtualMachineScaleSetVMProfile( extension_profile=extension_profile) update_parameters = VirtualMachineScaleSet( location=vmss_data.location, virtual_machine_profile=update_virtual_machine_profile) logging.info( "Setting Linux Diagnositc Extension on VM Scale Set : {}".format( new_vm_scale_set)) new_vmss_update = computeclient.virtual_machine_scale_sets.create_or_update( resource_group_name=resourceGroupName, vm_scale_set_name=new_vm_scale_set, parameters=update_parameters) new_vmss_update.wait() ############# """ updatedsku = Sku( name = vmss_data.sku.name, tier = vmss_data.sku.tier, capacity = 2 ) updated_vmss_parameters = VirtualMachineScaleSet( location=vmss_data.location, sku=updatedsku ) new_vmss = computeclient.virtual_machine_scale_sets.create_or_update( resource_group_name=resourceGroupName, vm_scale_set_name=new_vm_scale_set, parameters=updated_vmss_parameters ) new_vmss.wait() """ ############# logging.info("Creating AutoScale Setting for VM Scale Set : {}".format( new_vm_scale_set)) create_autoscaling_settings(vmScaleSetName, new_vmss_id, resourceGroupName) logging.info("Creating Activity Log Alert for VM Scale Set : {}".format( new_vm_scale_set)) clone_activity_log(resourceGroupName, new_vmss_id) logging.info( "Finished Creating Activity Log Alert for VM Scale Set : {}".format( new_vm_scale_set)) logging.info("Successfully Cloned VM ScaleSet {} to create {}".format( vmScaleSetName, new_vm_scale_set))