From 9460f6e8f5f6f031795f8a55f060c1549480c786 Mon Sep 17 00:00:00 2001 From: yugangw-msft Date: Wed, 31 Jan 2018 15:38:37 -0800 Subject: [PATCH 1/9] initial code --- src/aem/aem/__init__.py | 36 +++ src/aem/aem/_help.py | 26 ++ src/aem/aem/azext_metadata.json | 3 + src/aem/aem/custom.py | 533 ++++++++++++++++++++++++++++++++ src/aem/readme.md | 22 ++ src/aem/setup.cfg | 2 + src/aem/setup.py | 42 +++ 7 files changed, 664 insertions(+) create mode 100644 src/aem/aem/__init__.py create mode 100644 src/aem/aem/_help.py create mode 100644 src/aem/aem/azext_metadata.json create mode 100644 src/aem/aem/custom.py create mode 100644 src/aem/readme.md create mode 100644 src/aem/setup.cfg create mode 100644 src/aem/setup.py diff --git a/src/aem/aem/__init__.py b/src/aem/aem/__init__.py new file mode 100644 index 00000000000..03c73f2040d --- /dev/null +++ b/src/aem/aem/__init__.py @@ -0,0 +1,36 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from azure.cli.core import AzCommandsLoader + +import azext_imagecopy._help # pylint: disable=unused-import + + +class AEMCommandsLoader(AzCommandsLoader): + + def __init__(self, cli_ctx=None): + from azure.cli.core.commands import CliCommandType + aem_custom = CliCommandType( + operations_tmpl='azext_aem.custom#{}') + super(AEMCommandsLoader, self).__init__(cli_ctx=cli_ctx, + custom_command_type=aem_custom) + + def load_command_table(self, _): + with self.command_group('vm aem') as g: + g.custom_command('set', 'set_aem') + g.custom_command('delete', 'delete_aem') + g.custom_command('verify', 'verify_aem') + + return self.command_table + + def load_arguments(self, _): + with self.argument_context('vm aem') as c: + c.argument('skip_storage_check', action='store_true', + help='Disables the test for table content') + c.argument('wait_time_in_minutes', type=int, + help='Time that should be waited for the Strorage Metrics or Diagnostics data to be available in minutes') + + +COMMAND_LOADER_CLS = ImageCopyCommandsLoader diff --git a/src/aem/aem/_help.py b/src/aem/aem/_help.py new file mode 100644 index 00000000000..edccd4d7af8 --- /dev/null +++ b/src/aem/aem/_help.py @@ -0,0 +1,26 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from knack.help_files import helps + +helps['aem'] = """ + type: command + short-summary: Manage Azure Enhanced Monitoring Extension for SAP +""" + +helps['aem set'] = """ + type: command + short-summary: Configure Azure Enhanced Monitoring Extension +""" + +helps['aem delete'] = """ + type: command + short-summary: Remove Azure Enhanced Monitoring Extension +""" + +helps['aem verify'] = """ + type: command + short-summary: Verify Azure Enhanced Monitoring Extensions configured correctly +""" diff --git a/src/aem/aem/azext_metadata.json b/src/aem/aem/azext_metadata.json new file mode 100644 index 00000000000..bbe67260f34 --- /dev/null +++ b/src/aem/aem/azext_metadata.json @@ -0,0 +1,3 @@ +{ + "azext.minCliCoreVersion": "2.0.24" +} \ No newline at end of file diff --git a/src/aem/aem/custom.py b/src/aem/aem/custom.py new file mode 100644 index 00000000000..b657385a6d5 --- /dev/null +++ b/src/aem/aem/custom.py @@ -0,0 +1,533 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- +from knack.util import CLIError +from knack.log import get_logger + +from azure.cli.core.profiles import ResourceType, get_sdk +from azure.cli.core.commands.client_factory import get_mgmt_service_client, get_data_service_client + +logger = get_logger(__name__) + +aem_extension_info = { + 'Linux': { + 'publisher': 'Microsoft.OSTCExtensions', + 'name': 'AzureEnhancedMonitorForLinux', + 'version': '3.0' + }, + 'Windows': { + 'publisher': 'Microsoft.AzureCAT.AzureEnhancedMonitoring', + 'name': 'AzureCATExtensionHandler', + 'version': '2.2' + } +} + + +def set_aem(cmd, resource_group_name, vm_name, skip_storage_analytics=False): + aem = EnhancedMonitoring(cmd, resource_group_name, vm_name, + vm_client=get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_COMPUTE), + storage_client=get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_STORAGE), + skip_storage_analytics=skip_storage_analytics) + aem.enable() + + +def delete_aem(cmd, resource_group_name, vm_name): + aem = EnhancedMonitoring(cmd, resource_group_name, vm_name, + vm_client=get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_COMPUTE), + storage_client=None) + aem.delete() + + +def verify_aem(cmd, resource_group_name, vm_name, wait_time_in_minutes=15, skip_storage_check=False): + aem = EnhancedMonitoring(cmd, resource_group_name, vm_name, + vm_client=get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_COMPUTE), + storage_client=get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_STORAGE)) + aem.verify(skip_storage_check, wait_time_in_minutes) # TODO: better name and set up the flag param + + +class EnhancedMonitoring(object): + def __init__(self, cmd, resource_group, vm_name, vm_client, + storage_client, skip_storage_analytics=None): + self._vm_client = vm_client + self._storage_client = storage_client # TODO: remove those amnd just leverage cmd + self.resource_group = resource_group + self._cmd = cmd + self.vm = vm_client.virtual_machines.get(resource_group, vm_name, expand='instanceView') + # TODO: put it under api-version check on 2016-04-30preview+ + self._extension = (aem_extension_info['Linux'] if bool(self.vm.os_profile.linux_configuration) + else aem_extension_info['Windows']) + self._skip_storage_analytics = skip_storage_analytics + + def enable(self): + # TODO make sure we do need to handle such old vm sizes + pub_cfg, pri_cfg = self._build_extension_cfgs(self._get_disk_info()) + VirtualMachineExtension = self._cmd.get_models('VirtualMachineExtension') + existing_ext = self._get_aem_extension() + if existing_ext: + extension_instance_name = existing_ext.name + else: + extension_instance_name = self._extension['name'] + existing_ext = VirtualMachineExtension(self.vm.location, + publisher=self._extension['publisher'], + virtual_machine_extension_type=self._extension['name'], + protected_settings={ + 'cfg': [{'key': k, 'value': pri_cfg[k]} for k in pri_cfg] + }, + type_handler_version=self._extension['version'], + settings={ + 'cfg': [{'key': k, 'value': pub_cfg[k]} for k in pub_cfg] + }, + auto_upgrade_minor_version=True) + return self._vm_client.virtual_machine_extensions.create_or_update(self.resource_group, self.vm.name, + extension_instance_name, existing_ext) + + def delete(self): + existing_ext = self._get_aem_extension() + if not existing_ext: + raise CLIError("'{}' is not installed".format(self._extension['name'])) + return self._vm_client.virtual_machine_extensions.delete(self.resource_group, self.vm.name, + existing_ext.name) + + def verify(self, skip_storage_check, wait_time_in_minutes): + import datetime + aem_ext = self._get_aem_extension() + result = {} + succ_word, fail_word = 'OK', 'Not OK' + logger.info('Azure Enhanced Monitoring Extension for SAP Installation check: %s', + succ_word if aem_ext else fail_word) + disk_info = self._get_disk_info() + managed_disk = disk_info['managed_disk'] + # os disk + logger.info('Storage Metrics check...') + if not skip_storage_check: + unmanaged_disks = [] if managed_disk else [disk_info['os_disk']] + disk_info['data_disks'] + for disk in unmanaged_disks: + storage_account_name = disk['account_name'] + logger.info("\tStorage Metrics check for '%s'...", storage_account_name) + if disk['is_premium']: + logger.info("\t\tStorage Metrics not available for Premium Storage account '%s'...", + storage_account_name) + else: + logger.info("\t\tStorage Metrics configuration check for '%s'...", storage_account_name) + storage_client = self._get_storage_client(storage_account_name, disk['key']) + service_properties = storage_client.get_blob_service_properties() + storage_cfg_ok = self._check_storage_analytics(service_properties) + logger.warning('Metrics configuration check: %s', succ_word if storage_cfg_ok else fail_word) + if storage_cfg_ok: + filter_str = "Timestamp gt datetime'{}'".format( + (datetime.datetime.utcnow() + datetime.timedelta(minutes=-5)).isoformat()) + + result = self._check_table_and_content(storage_account_name, disk['key'], + '$MetricsMinutePrimaryTransactionsBlob', filter_str, + '.', wait_time_in_minutes) # TODO: need to print ... + step = 'Storage Metrics data check for {}'.format(storage_account_name) + result[step] = result + + logger.warning('Azure Enhanced Monitoring Extension for SAP public configuration check...') + extected, _ = self._build_extension_cfgs(disk_info) + public_cfg = {x['key']:x['value'] for x in self.vm.resources[0].settings['cfg']} # TODO: exclude wad check? + diffs = {k:[extected[k], public_cfg.get(k, None)] for k in extected if extected[k] != public_cfg.get(k, None)} + if diffs: + for err in diffs: + logger.error("\tError: Expected: '%s' Actual: '%s'", diffs[err][0], diffs[err][1]) + else: + logger.warning('Configuration OK') + + def _build_extension_cfgs(self, disk_info): + vm_size = str(self.vm.hardware_profile.vm_size) + pub_cfg = pri_cfg = {} + vm_size_mapping = { + 'ExtraSmall': 'ExtraSmall (A0)', + 'Standard_A0': 'ExtraSmall (A0)', + 'Basic_A0': 'ExtraSmall (A0)', + 'Small': 'Small (A1)', + 'Medium': 'Medium (A2)', + 'Large': 'Large (A3)', + 'ExtraLarge': 'ExtraLarge (A4)' + } + pub_cfg.update({ + 'vmsize': vm_size_mapping.get(vm_size, vm_size), # TODO: should be 'vm.size'? + 'vm.role': 'IaaS', + 'vm.memory.isovercommitted': 0, + 'vm.cpu.isovercommitted': 1 if vm_size == 'ExtraSmall (A0)' else 0, + 'script.version': '3.0.0.0', + 'verbose': '0', + 'href': 'http://aka.ms/sapaem' + }) + vm_sla_mappings = EnhancedMonitoring._populate_vm_sla_mappings() + vm_sla = vm_sla_mappings.get(vm_size) + if vm_sla: + pub_cfg.update({ + 'vm.sla.throughput': vm_sla['TP'], + 'vm.sla.iops': vm_sla['IOPS'] + }) + + managed_disk = disk_info['managed_disk'] + + # os disk + os_disk = disk_info['os_disk'] + if os_disk['is_premium']: + sla = EnhancedMonitoring._get_disk_sla(os_disk['size']) + pub_cfg.update({ + 'osdisk.type': 'Premium', + 'osdisk.sla.throughput': sla['TP'], + 'osdisk.sla.iops': sla['IOPS'], + }) + if managed_disk and not os_disk['is_premium']: + logger.warning('Standard Managed Disks are not supported. ' + 'Extension will be installed but no disk metrics will be available.') + else: + pub_cfg.update({ + 'osdisk.name': os_disk['name'], + 'osdisk.caching': os_disk['caching'], + }) + if not managed_disk: + pub_cfg.update({ + 'osdisk.account': os_disk['account_name'] + }) + if not os_disk['is_premium']: + pub_cfg.update({ + 'osdisk.type': 'Standard', + 'osdisk.connminute': os_disk['account_name'] + '.minute', + 'osdisk.connhour': os_disk['account_name'] + '.hour', + }) + # data disks + for i, disk in enumerate(disk_info['data_disks']): + suffix = '.' + str(i + 1) + if disk['is_premium']: + sla = EnhancedMonitoring._get_disk_sla(disk['size']) + pub_cfg.update({ + 'disk.type' + suffix: 'Premium', + 'disk.sla.throughput' + suffix: sla['TP'], + 'disk.sla.iops' + suffix: sla['IOPS'], + }) + + if managed_disk and not disk['is_premium']: + logger.warning('Standard Managed Disks are not supported. ' + 'Extension will be installed but no disk metrics will be available.') + else: + pub_cfg.update({ + 'disk.lun' + suffix: disk['lun'], + 'disk.name' + suffix: disk['name'], + 'disk.caching' + suffix: disk['caching'], + }) + if not managed_disk: + pub_cfg.update({ + 'disk.account' + suffix: disk['account_name'] + }) + if not os_disk['is_premium']: + pub_cfg.update({ + 'disk.type' + suffix: 'Standard', + 'disk.connminute' + suffix: disk['account_name'] + '.minute', + 'disk.connhour' + suffix: disk['account_name'] + '.hour', + }) + + if not managed_disk: + unmanaged_disks = [disk_info['os_disk']] + disk_info['data_disks'] + for disk in unmanaged_disks: + account_name = disk['account_name'] + if disk['is_premium']: + logger.info('[INFO] %s is skipped - Storage Account Metrics are not available ' + 'for Premium Type Storage.', disk['name']) + pub_cfg.update({ + account_name + '.hour.ispremium': 1, + account_name + '.minute.ispremium': 1, + }) + else: + if not self._skip_storage_analytics: + self._enable_storage_analytics(account_name, disk['key']) + pri_cfg.update({ + account_name + '.hour.key': disk['key'], + account_name + '.minute.key': disk['key'], + }) + pub_cfg.update({ + account_name + '.hour.uri': disk['table_endpoint'] + '$MetricsHourPrimaryTransactionsBlob', + account_name + '.minute.uri': disk['table_endpoint'] + '$MetricsMinutePrimaryTransactionsBlob', + account_name + '.hour.name': disk['account_name'], + account_name + '.minute.name': disk['account_name'] + }) + + pub_cfg['wad.isenabled'] = 0 + return pub_cfg, pri_cfg + + def _get_aem_extension(self): + existing_ext = None + if self.vm.instance_view.extensions: + full_type_name = '.'.join([self._extension['publisher'], self._extension['name']]) + existing_ext = next((x for x in self.vm.instance_view.extensions + if x.type and (x.type.lower() == full_type_name.lower())), None) + return existing_ext + + def _get_disk_info(self): + from msrestazure.tools import parse_resource_id + disks_info = {} + disks_info['managed_disk'] = bool(getattr(self.vm.storage_profile.os_disk, 'managed_disk', None)) + if disks_info['managed_disk']: + res_info = parse_resource_id(self.vm.storage_profile.os_disk.managed_disk.id) + disk = self._vm_client.disks.get(res_info['resource_group'], res_info['name']) + disks_info['os_disk'] = { + 'name': disk.name, + 'size': disk.disk_size_gb, + 'is_premium': disk.sku.tier.lower() == 'premium', + 'caching': self.vm.storage_profile.os_disk.caching.value, + } + disks_info['data_disks'] = [] + for data_disk in self.vm.storage_profile.data_disks: + res_info = parse_resource_id(data_disk.managed_disk.id) + disk = self._vm_client.disks.get(res_info['resource_group'], res_info['name']) + disks_info['data_disks'].append({ + 'name': disk.name, + 'size': disk.disk_size_gb, + 'is_premium': disk.sku.tier.lower() == 'premium', + 'caching': data_disk.caching.value, + 'lun': data_disk.lun + }) + else: + storage_accounts = list(self._storage_client.storage_accounts.list()) + blob_uri = self.vm.storage_profile.os_disk.vhd.uri + parts = list(filter(None, blob_uri.split('/'))) + storage_account_name = parts[1].split('.')[0] + disk_name, container_name = parts[-1], parts[-2] + storage_account = [x for x in storage_accounts if x.name.lower() == storage_account_name.lower()][0] + key = self._storage_client.storage_accounts.list_keys(parse_resource_id(storage_account.id)['resource_group'], + storage_account.name).keys[0].value + disks_info['os_disk'] = { + 'name': disk_name, + 'account_name': storage_account_name, + 'table_endpoint': storage_account.primary_endpoints.table, # TODO WARN if unavailable + 'is_premium': storage_account.sku.tier.value.lower() == 'premium', + 'caching': self.vm.storage_profile.os_disk.caching.value, + 'key': key + } + if disks_info['os_disk']['is_premium']: + disks_info['os_disk']['size'] = self._get_blob_size(storage_account.name, container_name, + disk_name, key) + + disks_info['data_disks'] = [] + for data_disk in self.vm.storage_profile.data_disks: + blob_uri = data_disk.vhd.uri + parts = list(filter(None, blob_uri.split('/'))) + storage_account_name = parts[1].split('.')[0] + disk_name, container_name = parts[-1], parts[-2] # TODO: consider urlparse + storage_account = [x for x in storage_accounts if x.name.lower() == storage_account_name.lower()][0] + key = self._storage_client.storage_accounts.list_keys(parse_resource_id(storage_account.id)['resource_group'], + storage_account.name).keys[0].value + is_premium = storage_account.sku.tier.value.lower() == 'premium' + disks_info['data_disks'].append({ + 'name': disk_name, + 'account_name': storage_account_name, + 'table_endpoint': storage_account.primary_endpoints.table, + 'is_premium': is_premium, + 'caching': self.vm.storage_profile.os_disk.caching.value, + 'key': key, + 'lun': data_disk.lun + }) + if is_premium: + disks_info['data_disks'][-1]['size'] = self._get_blob_size(storage_account.name, container_name, + disk_name, key) + + return disks_info + + def _get_blob_size(self, storage_account_name, container, blob, key): + storage_client = self._get_storage_client(storage_account_name, key) + return int(storage_client.get_blob_properties(container, blob).properties.content_length / (1 << 30)) + + def _get_storage_client(self, storage_account_name, key): + BlockBlobService = get_sdk(self._cmd.cli_ctx, ResourceType.DATA_STORAGE, 'blob.blockblobservice#BlockBlobService') + return get_data_service_client( + self._cmd.cli_ctx, + BlockBlobService, + storage_account_name, + key, + endpoint_suffix=self._cmd.cli_ctx.cloud.suffixes.storage_endpoint) # pylint: disable=no-member + + def _enable_storage_analytics(self, storage_account_name, key): + # TODO: whether this checking is enough and WORKING + storage_client = self._get_storage_client(storage_account_name, key) + service_properties = storage_client.get_blob_service_properties() + if not self._check_storage_analytics(service_properties): + t_logging, t_retention_policy, t_metrics = get_sdk(self._cmd.cli_ctx, ResourceType.DATA_STORAGE, 'Logging', + 'RetentionPolicy', 'Metrics', mod='common.models') + retention_policy = t_retention_policy(enabled=True, days=13) + logging = t_logging(delete=True, read=True, write=True, retention_policy=retention_policy) + minute_metrics = t_metrics(enabled=True, include_apis=True, retention_policy=retention_policy) + if service_properties.hour_metrics: # TODO ensure null reference + service_properties.hour_metrics.retention_policy.days = 13 + storage_client.set_blob_service_properties(logging, minute_metrics=minute_metrics, + hour_metrics=service_properties.hour_metrics) + + def _check_storage_analytics(self, service_properties): + return (service_properties and service_properties.logging and + service_properties.minute_metrics and service_properties.minute_metrics.include_apis and + service_properties.minute_metrics.retention_policy.days) + + def _check_table_and_content(self, storage_account_name, key, table_name, + filter_string, wait_char, timeout_in_minutes): + import time + TableService = get_sdk(self._cmd.cli_ctx, ResourceType.DATA_COSMOS_TABLE, 'table#TableService') + table_client = get_data_service_client( + self._cmd.cli_ctx, + TableService, + storage_account_name, + key, + endpoint_suffix=self._cmd.cli_ctx.cloud.suffixes.storage_endpoint) + + seconds = 60 * timeout_in_minutes + waited = 0 + while waited < seconds: + try: + entities = table_client.query_entities(table_name, filter_string) + if entities: + return True + except Exception as ex: + pass + time.sleep(15) + waited += 15 + + return False + + @staticmethod + def _get_disk_sla(disk_size): + sla = {} + if 0 < disk_size <= 32: + # P4 + sla['IOPS'] = 120 + sla['TP'] = 125 + elif 0 < disk_size <= 64: + # P6 + sla['IOPS'] = 240 + sla['TP'] = 50 + elif 0 < disk_size <= 128: + # P10 + sla['IOPS'] = 500 + sla['TP'] = 100 + elif 0 < disk_size <= 512: + # P20 + sla['IOPS'] = 2300 + sla['TP'] = 150 + elif 0 < disk_size <= 1024: + # P30 + sla['IOPS'] = 5000 + sla['TP'] = 200 + elif 0 < disk_size <= 2048: + # P40 + sla['IOPS'] = 7500 + sla['TP'] = 250 + elif 0 < disk_size <= 4095: + # P50 + sla['IOPS'] = 7500 + sla['TP'] = 250 + else: + raise CLIError("unsupported disk size for Premium Storage: '{}'".format(disk_size)) + return sla + + @staticmethod + def _populate_vm_sla_mappings(): + # TODO, figure out the deal for sizes not in the list + mapping = {} + mapping['Standard_DS1'] = { + 'IOPS': 3200, + 'TP': 32, + } + mapping.update(dict.fromkeys(['Standard_DS1_v2', 'Standard_D2s_v3', 'Standard_E2s_v3'], { + 'IOPS': 3200, + 'TP': 48, + })) + mapping['Standard_DS2'] = { + 'IOPS': 6400, + 'TP': 64, + } + mapping.update(dict.fromkeys(['Standard_DS2_v2', 'Standard_D4s_v3', 'Standard_E4s_v3'], { + 'IOPS': 6400, + 'TP': 96, + })) + mapping['Standard_DS3'] = { + 'IOPS': 12800, + 'TP': 128, + } + mapping.update(dict.fromkeys(['Standard_DS3_v2', 'Standard_D8s_v3', 'Standard_E8s_v3'], { + 'IOPS': 12800, + 'TP': 192, + })) + mapping['Standard_DS4'] = { + 'IOPS': 25600, + 'TP': 256, + } + mapping.update(dict.fromkeys(['Standard_DS4_v2', 'Standard_D16s_v3', 'Standard_E16s_v3'], { + 'IOPS': 25600, + 'TP': 384, + })) + mapping.update(dict.fromkeys(['Standard_DS5_v2', 'Standard_D32s_v3'], { + 'IOPS': 51200, + 'TP': 768, + })) + mapping['Standard_DS11'] = { + 'IOPS': 6400, + 'TP': 64, + } + mapping['Standard_DS11_v2'] = { + 'IOPS': 6400, + 'TP': 96, + } + mapping['Standard_DS12'] = { + 'IOPS': 12800, + 'TP': 128, + } + mapping['Standard_DS12_v2'] = { + 'IOPS': 12800, + 'TP': 192, + } + mapping['Standard_DS13'] = { + 'IOPS': 25600, + 'TP': 256, + } + mapping['Standard_DS13_v2'] = { + 'IOPS': 25600, + 'TP': 384, + } + mapping['Standard_DS14'] = { + 'IOPS': 51200, + 'TP': 512, + } + mapping.update(dict.fromkeys(['Standard_DS14_v2', 'Standard_E32s_v3'], { + 'IOPS': 51200, + 'TP': 768, + })) + mapping['Standard_DS15_v2'] = { + 'IOPS': 64000, + 'TP': 960, + } + mapping['Standard_GS1'] = { + 'IOPS': 5000, + 'TP': 125, + } + mapping['Standard_GS2'] = { + 'IOPS': 10000, + 'TP': 250, + } + mapping['Standard_GS3'] = { + 'IOPS': 20000, + 'TP': 500, + } + mapping['Standard_GS4'] = { + 'IOPS': 40000, + 'TP': 1000, + } + mapping['Standard_GS5'] = { + 'IOPS': 80000, + 'TP': 2000, + } + mapping.update(dict.fromkeys(['Standard_M64ms', 'Standard_M64s'], { + 'IOPS': 40000, + 'TP': 1000, + })) + mapping['Standard_M128s'] = { + 'IOPS': 80000, + 'TP': 2000, + } + mapping.update(dict.fromkeys(['Standard_E64s_v3', 'Standard_D64s_v3'], { + 'IOPS': 80000, + 'TP': 1200, + })) + return mapping diff --git a/src/aem/readme.md b/src/aem/readme.md new file mode 100644 index 00000000000..5d23f590872 --- /dev/null +++ b/src/aem/readme.md @@ -0,0 +1,22 @@ +# Azure CLI Monitoring Extension # +This is an extension to azure cli which provides command to configure, verify and remove . + +The extension simplifies the process and also enables you to save time by copying to multiple regions in parallel. + +## How to use ## +First, install the extension: +``` +az extension add --name aem +``` + +Then, call it as you would any other az command: +``` +az image copy --source-resource-group mySources-rg --source-object-name myImage --target-location uksouth northeurope --target-resource-group "images-repo-rg" --cleanup +``` + +One thing you should keep in mind is that we are relying on the source os disk as the actual source for the copy. So, when you "capture" a new image off a vm in Azure, don't delete the os disk if your intention is to copy it to other regions. + +Other options and examples of using the extensions can be viewed with the help command: +``` +az image copy --help +``` \ No newline at end of file diff --git a/src/aem/setup.cfg b/src/aem/setup.cfg new file mode 100644 index 00000000000..3c6e79cf31d --- /dev/null +++ b/src/aem/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal=1 diff --git a/src/aem/setup.py b/src/aem/setup.py new file mode 100644 index 00000000000..2e8c5f59c94 --- /dev/null +++ b/src/aem/setup.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from codecs import open +from setuptools import setup, find_packages + +VERSION = "0.0.1" + +CLASSIFIERS = [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Intended Audience :: System Administrators', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'License :: OSI Approved :: MIT License', +] + +DEPENDENCIES = [] + +setup( + name='aem', + version=VERSION, + description='CLI Extension to managed Azure Enhanced Monitoring Extension for SAP', + long_description='N/A', + license='MIT', + author='Yugang Wang', + author_email='yugangw@microsoft.com', + url='https://github.com/Azure/azure-cli-extensions', + classifiers=CLASSIFIERS, + package_data={'azext_aem': ['azext_metadata.json']}, + packages=find_packages(), + install_requires=DEPENDENCIES +) From b9a6a01ce9c23cb87a48f7823388358d089cd9d1 Mon Sep 17 00:00:00 2001 From: Yugang Wang Date: Wed, 31 Jan 2018 22:03:17 -0800 Subject: [PATCH 2/9] copy code over --- src/aem/aem/__init__.py | 4 +- src/aem/aem/custom.py | 125 +- src/aem/aem/tests/__init__.py | 4 + .../latest/test_vm_aem_configure.yaml | 1206 +++++++++++++++++ src/aem/aem/tests/test_aem_commands.py | 18 + src/aem/readme.md | 15 +- 6 files changed, 1302 insertions(+), 70 deletions(-) create mode 100644 src/aem/aem/tests/__init__.py create mode 100644 src/aem/aem/tests/recordings/latest/test_vm_aem_configure.yaml create mode 100644 src/aem/aem/tests/test_aem_commands.py diff --git a/src/aem/aem/__init__.py b/src/aem/aem/__init__.py index 03c73f2040d..0d5de58439b 100644 --- a/src/aem/aem/__init__.py +++ b/src/aem/aem/__init__.py @@ -5,7 +5,7 @@ from azure.cli.core import AzCommandsLoader -import azext_imagecopy._help # pylint: disable=unused-import +import azext_aem._help # pylint: disable=unused-import class AEMCommandsLoader(AzCommandsLoader): @@ -33,4 +33,4 @@ def load_arguments(self, _): help='Time that should be waited for the Strorage Metrics or Diagnostics data to be available in minutes') -COMMAND_LOADER_CLS = ImageCopyCommandsLoader +COMMAND_LOADER_CLS = AEMCommandsLoader diff --git a/src/aem/aem/custom.py b/src/aem/aem/custom.py index b657385a6d5..5c4178e4f27 100644 --- a/src/aem/aem/custom.py +++ b/src/aem/aem/custom.py @@ -43,24 +43,23 @@ def verify_aem(cmd, resource_group_name, vm_name, wait_time_in_minutes=15, skip_ aem = EnhancedMonitoring(cmd, resource_group_name, vm_name, vm_client=get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_COMPUTE), storage_client=get_mgmt_service_client(cmd.cli_ctx, ResourceType.MGMT_STORAGE)) - aem.verify(skip_storage_check, wait_time_in_minutes) # TODO: better name and set up the flag param + aem.verify(skip_storage_check, wait_time_in_minutes) class EnhancedMonitoring(object): def __init__(self, cmd, resource_group, vm_name, vm_client, storage_client, skip_storage_analytics=None): self._vm_client = vm_client - self._storage_client = storage_client # TODO: remove those amnd just leverage cmd - self.resource_group = resource_group + self._storage_client = storage_client + self._resource_group = resource_group self._cmd = cmd - self.vm = vm_client.virtual_machines.get(resource_group, vm_name, expand='instanceView') + self._vm = vm_client.virtual_machines.get(resource_group, vm_name, expand='instanceView') # TODO: put it under api-version check on 2016-04-30preview+ - self._extension = (aem_extension_info['Linux'] if bool(self.vm.os_profile.linux_configuration) + self._extension = (aem_extension_info['Linux'] if bool(self._vm.os_profile.linux_configuration) else aem_extension_info['Windows']) self._skip_storage_analytics = skip_storage_analytics def enable(self): - # TODO make sure we do need to handle such old vm sizes pub_cfg, pri_cfg = self._build_extension_cfgs(self._get_disk_info()) VirtualMachineExtension = self._cmd.get_models('VirtualMachineExtension') existing_ext = self._get_aem_extension() @@ -68,7 +67,7 @@ def enable(self): extension_instance_name = existing_ext.name else: extension_instance_name = self._extension['name'] - existing_ext = VirtualMachineExtension(self.vm.location, + existing_ext = VirtualMachineExtension(self._vm.location, publisher=self._extension['publisher'], virtual_machine_extension_type=self._extension['name'], protected_settings={ @@ -79,63 +78,78 @@ def enable(self): 'cfg': [{'key': k, 'value': pub_cfg[k]} for k in pub_cfg] }, auto_upgrade_minor_version=True) - return self._vm_client.virtual_machine_extensions.create_or_update(self.resource_group, self.vm.name, + return self._vm_client.virtual_machine_extensions.create_or_update(self._resource_group, self._vm.name, extension_instance_name, existing_ext) def delete(self): existing_ext = self._get_aem_extension() if not existing_ext: raise CLIError("'{}' is not installed".format(self._extension['name'])) - return self._vm_client.virtual_machine_extensions.delete(self.resource_group, self.vm.name, + return self._vm_client.virtual_machine_extensions.delete(self._resource_group, self._vm.name, existing_ext.name) def verify(self, skip_storage_check, wait_time_in_minutes): import datetime + success = True aem_ext = self._get_aem_extension() result = {} succ_word, fail_word = 'OK', 'Not OK' - logger.info('Azure Enhanced Monitoring Extension for SAP Installation check: %s', - succ_word if aem_ext else fail_word) + if aem_ext: + logger.warning('Azure Enhanced Monitoring Extension for SAP Installation check: %s', succ_word) + else: + raise CLIError('Azure Enhanced Monitoring Extension for SAP was not installed') disk_info = self._get_disk_info() managed_disk = disk_info['managed_disk'] # os disk - logger.info('Storage Metrics check...') + logger.warning('Storage Metrics check...') if not skip_storage_check: unmanaged_disks = [] if managed_disk else [disk_info['os_disk']] + disk_info['data_disks'] for disk in unmanaged_disks: storage_account_name = disk['account_name'] - logger.info("\tStorage Metrics check for '%s'...", storage_account_name) + logger.warning("\tStorage Metrics check for '%s'...", storage_account_name) if disk['is_premium']: - logger.info("\t\tStorage Metrics not available for Premium Storage account '%s'...", - storage_account_name) + logger.warning("\t\tStorage Metrics not available for Premium Storage account '%s'...", + storage_account_name) else: - logger.info("\t\tStorage Metrics configuration check for '%s'...", storage_account_name) + logger.warning("\t\tStorage Metrics configuration check for '%s'...", storage_account_name) storage_client = self._get_storage_client(storage_account_name, disk['key']) service_properties = storage_client.get_blob_service_properties() - storage_cfg_ok = self._check_storage_analytics(service_properties) - logger.warning('Metrics configuration check: %s', succ_word if storage_cfg_ok else fail_word) + storage_cfg_ok = EnhancedMonitoring._check_storage_analytics(service_properties) + if storage_cfg_ok: + logger.warning('\t\tStorage Metrics configuration check: %s', succ_word) + else: + success = False + logger.error('\t\tMetrics configuration check: %s', fail_word) if storage_cfg_ok: + logger.warning("\t\tStorage Metrics data check for '%s'. Wait up to %s minutes ...", + storage_account_name, wait_time_in_minutes) filter_str = "Timestamp gt datetime'{}'".format( (datetime.datetime.utcnow() + datetime.timedelta(minutes=-5)).isoformat()) - result = self._check_table_and_content(storage_account_name, disk['key'], '$MetricsMinutePrimaryTransactionsBlob', filter_str, - '.', wait_time_in_minutes) # TODO: need to print ... - step = 'Storage Metrics data check for {}'.format(storage_account_name) - result[step] = result + wait_time_in_minutes) + if result: + logger.warning("\t\tStorage Metrics data check '%s': %s", storage_account_name, succ_word) + else: + success = False + logger.error("\t\tStorage Metrics data check '%s': %s", storage_account_name, fail_word) logger.warning('Azure Enhanced Monitoring Extension for SAP public configuration check...') extected, _ = self._build_extension_cfgs(disk_info) - public_cfg = {x['key']:x['value'] for x in self.vm.resources[0].settings['cfg']} # TODO: exclude wad check? - diffs = {k:[extected[k], public_cfg.get(k, None)] for k in extected if extected[k] != public_cfg.get(k, None)} + public_cfg = {x['key']: x['value'] for x in self._vm.resources[0].settings['cfg']} + diffs = {k: [extected[k], public_cfg.get(k, None)] for k in extected if extected[k] != public_cfg.get(k, None)} if diffs: + success = False for err in diffs: - logger.error("\tError: Expected: '%s' Actual: '%s'", diffs[err][0], diffs[err][1]) + logger.error("\tConfiguration Error: Expected: '%s' Actual: '%s'", diffs[err][0], diffs[err][1]) else: logger.warning('Configuration OK') + if not success: + raise CLIError('Configuration Not OK.') + def _build_extension_cfgs(self, disk_info): - vm_size = str(self.vm.hardware_profile.vm_size) + vm_size = str(self._vm.hardware_profile.vm_size) pub_cfg = pri_cfg = {} vm_size_mapping = { 'ExtraSmall': 'ExtraSmall (A0)', @@ -147,7 +161,7 @@ def _build_extension_cfgs(self, disk_info): 'ExtraLarge': 'ExtraLarge (A4)' } pub_cfg.update({ - 'vmsize': vm_size_mapping.get(vm_size, vm_size), # TODO: should be 'vm.size'? + 'vmsize': vm_size_mapping.get(vm_size, vm_size), 'vm.role': 'IaaS', 'vm.memory.isovercommitted': 0, 'vm.cpu.isovercommitted': 1 if vm_size == 'ExtraSmall (A0)' else 0, @@ -253,27 +267,27 @@ def _build_extension_cfgs(self, disk_info): def _get_aem_extension(self): existing_ext = None - if self.vm.instance_view.extensions: + if self._vm.instance_view.extensions: full_type_name = '.'.join([self._extension['publisher'], self._extension['name']]) - existing_ext = next((x for x in self.vm.instance_view.extensions + existing_ext = next((x for x in self._vm.instance_view.extensions if x.type and (x.type.lower() == full_type_name.lower())), None) return existing_ext def _get_disk_info(self): from msrestazure.tools import parse_resource_id disks_info = {} - disks_info['managed_disk'] = bool(getattr(self.vm.storage_profile.os_disk, 'managed_disk', None)) + disks_info['managed_disk'] = bool(getattr(self._vm.storage_profile.os_disk, 'managed_disk', None)) if disks_info['managed_disk']: - res_info = parse_resource_id(self.vm.storage_profile.os_disk.managed_disk.id) + res_info = parse_resource_id(self._vm.storage_profile.os_disk.managed_disk.id) disk = self._vm_client.disks.get(res_info['resource_group'], res_info['name']) disks_info['os_disk'] = { 'name': disk.name, 'size': disk.disk_size_gb, 'is_premium': disk.sku.tier.lower() == 'premium', - 'caching': self.vm.storage_profile.os_disk.caching.value, + 'caching': self._vm.storage_profile.os_disk.caching.value, } disks_info['data_disks'] = [] - for data_disk in self.vm.storage_profile.data_disks: + for data_disk in self._vm.storage_profile.data_disks: res_info = parse_resource_id(data_disk.managed_disk.id) disk = self._vm_client.disks.get(res_info['resource_group'], res_info['name']) disks_info['data_disks'].append({ @@ -285,19 +299,19 @@ def _get_disk_info(self): }) else: storage_accounts = list(self._storage_client.storage_accounts.list()) - blob_uri = self.vm.storage_profile.os_disk.vhd.uri + blob_uri = self._vm.storage_profile.os_disk.vhd.uri parts = list(filter(None, blob_uri.split('/'))) storage_account_name = parts[1].split('.')[0] disk_name, container_name = parts[-1], parts[-2] storage_account = [x for x in storage_accounts if x.name.lower() == storage_account_name.lower()][0] - key = self._storage_client.storage_accounts.list_keys(parse_resource_id(storage_account.id)['resource_group'], - storage_account.name).keys[0].value + rg = parse_resource_id(storage_account.id)['resource_group'] + key = self._storage_client.storage_accounts.list_keys(rg, storage_account.name).keys[0].value disks_info['os_disk'] = { 'name': disk_name, 'account_name': storage_account_name, - 'table_endpoint': storage_account.primary_endpoints.table, # TODO WARN if unavailable + 'table_endpoint': storage_account.primary_endpoints.table, 'is_premium': storage_account.sku.tier.value.lower() == 'premium', - 'caching': self.vm.storage_profile.os_disk.caching.value, + 'caching': self._vm.storage_profile.os_disk.caching.value, 'key': key } if disks_info['os_disk']['is_premium']: @@ -305,21 +319,21 @@ def _get_disk_info(self): disk_name, key) disks_info['data_disks'] = [] - for data_disk in self.vm.storage_profile.data_disks: + for data_disk in self._vm.storage_profile.data_disks: blob_uri = data_disk.vhd.uri parts = list(filter(None, blob_uri.split('/'))) storage_account_name = parts[1].split('.')[0] - disk_name, container_name = parts[-1], parts[-2] # TODO: consider urlparse + disk_name, container_name = parts[-1], parts[-2] storage_account = [x for x in storage_accounts if x.name.lower() == storage_account_name.lower()][0] - key = self._storage_client.storage_accounts.list_keys(parse_resource_id(storage_account.id)['resource_group'], - storage_account.name).keys[0].value + rg = parse_resource_id(storage_account.id)['resource_group'] + key = self._storage_client.storage_accounts.list_keys(rg, storage_account.name).keys[0].value is_premium = storage_account.sku.tier.value.lower() == 'premium' disks_info['data_disks'].append({ 'name': disk_name, 'account_name': storage_account_name, 'table_endpoint': storage_account.primary_endpoints.table, 'is_premium': is_premium, - 'caching': self.vm.storage_profile.os_disk.caching.value, + 'caching': self._vm.storage_profile.os_disk.caching.value, 'key': key, 'lun': data_disk.lun }) @@ -334,7 +348,8 @@ def _get_blob_size(self, storage_account_name, container, blob, key): return int(storage_client.get_blob_properties(container, blob).properties.content_length / (1 << 30)) def _get_storage_client(self, storage_account_name, key): - BlockBlobService = get_sdk(self._cmd.cli_ctx, ResourceType.DATA_STORAGE, 'blob.blockblobservice#BlockBlobService') + BlockBlobService = get_sdk(self._cmd.cli_ctx, ResourceType.DATA_STORAGE, + 'blob.blockblobservice#BlockBlobService') return get_data_service_client( self._cmd.cli_ctx, BlockBlobService, @@ -343,27 +358,27 @@ def _get_storage_client(self, storage_account_name, key): endpoint_suffix=self._cmd.cli_ctx.cloud.suffixes.storage_endpoint) # pylint: disable=no-member def _enable_storage_analytics(self, storage_account_name, key): - # TODO: whether this checking is enough and WORKING storage_client = self._get_storage_client(storage_account_name, key) service_properties = storage_client.get_blob_service_properties() - if not self._check_storage_analytics(service_properties): + if not EnhancedMonitoring._check_storage_analytics(service_properties): t_logging, t_retention_policy, t_metrics = get_sdk(self._cmd.cli_ctx, ResourceType.DATA_STORAGE, 'Logging', 'RetentionPolicy', 'Metrics', mod='common.models') retention_policy = t_retention_policy(enabled=True, days=13) logging = t_logging(delete=True, read=True, write=True, retention_policy=retention_policy) minute_metrics = t_metrics(enabled=True, include_apis=True, retention_policy=retention_policy) - if service_properties.hour_metrics: # TODO ensure null reference + if getattr(service_properties, 'hour_metrics', None): service_properties.hour_metrics.retention_policy.days = 13 storage_client.set_blob_service_properties(logging, minute_metrics=minute_metrics, hour_metrics=service_properties.hour_metrics) - def _check_storage_analytics(self, service_properties): + @staticmethod + def _check_storage_analytics(service_properties): return (service_properties and service_properties.logging and service_properties.minute_metrics and service_properties.minute_metrics.include_apis and service_properties.minute_metrics.retention_policy.days) def _check_table_and_content(self, storage_account_name, key, table_name, - filter_string, wait_char, timeout_in_minutes): + filter_string, timeout_in_minutes): import time TableService = get_sdk(self._cmd.cli_ctx, ResourceType.DATA_COSMOS_TABLE, 'table#TableService') table_client = get_data_service_client( @@ -376,12 +391,11 @@ def _check_table_and_content(self, storage_account_name, key, table_name, seconds = 60 * timeout_in_minutes waited = 0 while waited < seconds: - try: - entities = table_client.query_entities(table_name, filter_string) - if entities: - return True - except Exception as ex: - pass + entities = table_client.query_entities(table_name, filter_string) + if entities.items: + return True + logger.warning("\t\t\tWait %s seconds for table '%s' has date propagated ...", + 15, table_name) time.sleep(15) waited += 15 @@ -424,7 +438,6 @@ def _get_disk_sla(disk_size): @staticmethod def _populate_vm_sla_mappings(): - # TODO, figure out the deal for sizes not in the list mapping = {} mapping['Standard_DS1'] = { 'IOPS': 3200, diff --git a/src/aem/aem/tests/__init__.py b/src/aem/aem/tests/__init__.py new file mode 100644 index 00000000000..34913fb394d --- /dev/null +++ b/src/aem/aem/tests/__init__.py @@ -0,0 +1,4 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- diff --git a/src/aem/aem/tests/recordings/latest/test_vm_aem_configure.yaml b/src/aem/aem/tests/recordings/latest/test_vm_aem_configure.yaml new file mode 100644 index 00000000000..5a1fbc93d7e --- /dev/null +++ b/src/aem/aem/tests/recordings/latest/test_vm_aem_configure.yaml @@ -0,0 +1,1206 @@ +interactions: +- request: + body: '{"tags": {"use": "az-test"}, "location": "westus"}' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [group create] + Connection: [keep-alive] + Content-Length: ['50'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 resourcemanagementclient/1.2.1 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2017-05-10 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001","name":"clitest.rg000001","location":"westus","tags":{"use":"az-test"},"properties":{"provisioningState":"Succeeded"}}'} + headers: + cache-control: [no-cache] + content-length: ['328'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:26:16 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-ms-ratelimit-remaining-subscription-writes: ['1199'] + status: {code: 201, message: Created} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 resourcemanagementclient/1.2.1 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2017-05-10 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001","name":"clitest.rg000001","location":"westus","tags":{"use":"az-test"},"properties":{"provisioningState":"Succeeded"}}'} + headers: + cache-control: [no-cache] + content-length: ['328'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:26:20 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + User-Agent: [python-requests/2.17.0] + method: GET + uri: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/arm-compute/quickstart-templates/aliases.json + response: + body: {string: "{\n \"$schema\":\"http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json\"\ + ,\n \"contentVersion\":\"1.0.0.0\",\n \"parameters\":{},\n \"variables\"\ + :{},\n \"resources\":[],\n\n \"outputs\":{\n \"aliases\":{\n \"\ + type\":\"object\",\n \"value\":{\n\n \"Linux\":{\n \"\ + CentOS\":{\n \"publisher\":\"OpenLogic\",\n \"offer\"\ + :\"CentOS\",\n \"sku\":\"7.3\",\n \"version\":\"latest\"\ + \n },\n \"CoreOS\":{\n \"publisher\":\"CoreOS\"\ + ,\n \"offer\":\"CoreOS\",\n \"sku\":\"Stable\",\n \ + \ \"version\":\"latest\"\n },\n \"Debian\":{\n\ + \ \"publisher\":\"credativ\",\n \"offer\":\"Debian\"\ + ,\n \"sku\":\"8\",\n \"version\":\"latest\"\n \ + \ },\n \"openSUSE-Leap\": {\n \"publisher\":\"SUSE\"\ + ,\n \"offer\":\"openSUSE-Leap\",\n \"sku\":\"42.2\"\ + ,\n \"version\": \"latest\"\n },\n \"RHEL\":{\n\ + \ \"publisher\":\"RedHat\",\n \"offer\":\"RHEL\",\n\ + \ \"sku\":\"7.3\",\n \"version\":\"latest\"\n \ + \ },\n \"SLES\":{\n \"publisher\":\"SUSE\",\n \ + \ \"offer\":\"SLES\",\n \"sku\":\"12-SP2\",\n \ + \ \"version\":\"latest\"\n },\n \"UbuntuLTS\":{\n \ + \ \"publisher\":\"Canonical\",\n \"offer\":\"UbuntuServer\"\ + ,\n \"sku\":\"16.04-LTS\",\n \"version\":\"latest\"\n\ + \ }\n },\n\n \"Windows\":{\n \"Win2016Datacenter\"\ + :{\n \"publisher\":\"MicrosoftWindowsServer\",\n \"\ + offer\":\"WindowsServer\",\n \"sku\":\"2016-Datacenter\",\n \ + \ \"version\":\"latest\"\n },\n \"Win2012R2Datacenter\"\ + :{\n \"publisher\":\"MicrosoftWindowsServer\",\n \"\ + offer\":\"WindowsServer\",\n \"sku\":\"2012-R2-Datacenter\",\n\ + \ \"version\":\"latest\"\n },\n \"Win2012Datacenter\"\ + :{\n \"publisher\":\"MicrosoftWindowsServer\",\n \"\ + offer\":\"WindowsServer\",\n \"sku\":\"2012-Datacenter\",\n \ + \ \"version\":\"latest\"\n },\n \"Win2008R2SP1\"\ + :{\n \"publisher\":\"MicrosoftWindowsServer\",\n \"\ + offer\":\"WindowsServer\",\n \"sku\":\"2008-R2-SP1\",\n \ + \ \"version\":\"latest\"\n }\n }\n }\n }\n }\n\ + }\n"} + headers: + accept-ranges: [bytes] + access-control-allow-origin: ['*'] + cache-control: [max-age=300] + connection: [keep-alive] + content-length: ['2235'] + content-security-policy: [default-src 'none'; style-src 'unsafe-inline'; sandbox] + content-type: [text/plain; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:26:21 GMT'] + etag: ['"d6824855d13e27c5258a680eb60f635d088fd05e"'] + expires: ['Thu, 01 Feb 2018 05:31:21 GMT'] + source-age: ['0'] + strict-transport-security: [max-age=31536000] + vary: ['Authorization,Accept-Encoding'] + via: [1.1 varnish] + x-cache: [MISS] + x-cache-hits: ['0'] + x-content-type-options: [nosniff] + x-fastly-request-id: [5325200711aee35bac1bb8ebb0b970d6b9e3b799] + x-frame-options: [deny] + x-geo-block-list: [''] + x-github-request-id: ['0BD0:2A988:1A76B76:1B6DF16:5A72A4FD'] + x-served-by: [cache-sea1043-SEA] + x-timer: ['S1517462781.434213,VS0,VE86'] + x-xss-protection: [1; mode=block] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 networkmanagementclient/1.7.0 Azure-SDK-For-Python AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/virtualNetworks?api-version=2017-11-01 + response: + body: {string: '{"value":[]}'} + headers: + cache-control: [no-cache] + content-length: ['12'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:26:25 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: 'b''{"properties": {"mode": "Incremental", "parameters": {}, "template": + {"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "variables": {}, "parameters": {}, "outputs": {}, "contentVersion": "1.0.0.0", + "resources": [{"tags": {}, "properties": {"addressSpace": {"addressPrefixes": + ["10.0.0.0/16"]}, "subnets": [{"properties": {"addressPrefix": "10.0.0.0/24"}, + "name": "vm1Subnet"}]}, "type": "Microsoft.Network/virtualNetworks", "location": + "westus", "dependsOn": [], "apiVersion": "2015-06-15", "name": "vm1VNET"}, {"tags": + {}, "properties": {"securityRules": [{"properties": {"access": "Allow", "sourcePortRange": + "*", "sourceAddressPrefix": "*", "priority": 1000, "direction": "Inbound", "protocol": + "Tcp", "destinationAddressPrefix": "*", "destinationPortRange": "22"}, "name": + "default-allow-ssh"}]}, "type": "Microsoft.Network/networkSecurityGroups", "location": + "westus", "dependsOn": [], "apiVersion": "2015-06-15", "name": "vm1NSG"}, {"tags": + {}, "properties": {"publicIPAllocationMethod": "dynamic"}, "type": "Microsoft.Network/publicIPAddresses", + "location": "westus", "dependsOn": [], "apiVersion": "2017-11-01", "name": "vm1PublicIP"}, + {"tags": {}, "properties": {"networkSecurityGroup": {"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkSecurityGroups/vm1NSG"}, + "ipConfigurations": [{"properties": {"privateIPAllocationMethod": "Dynamic", + "subnet": {"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/virtualNetworks/vm1VNET/subnets/vm1Subnet"}, + "publicIPAddress": {"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/publicIPAddresses/vm1PublicIP"}}, + "name": "ipconfigvm1"}]}, "type": "Microsoft.Network/networkInterfaces", "location": + "westus", "dependsOn": ["Microsoft.Network/virtualNetworks/vm1VNET", "Microsoft.Network/networkSecurityGroups/vm1NSG", + "Microsoft.Network/publicIpAddresses/vm1PublicIP"], "apiVersion": "2015-06-15", + "name": "vm1VMNic"}, {"tags": {}, "properties": {"hardwareProfile": {"vmSize": + "Standard_DS1_v2"}, "osProfile": {"linuxConfiguration": {"ssh": {"publicKeys": + [{"path": "/home/yugangw2/.ssh/authorized_keys", "keyData": "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6ynxWeY589bvuJVjtobA+qIlWQwycoeRTYNyEUssLQdCWq7YRUxBhXZzf8O8qe8vz8JsxIgX2ynyn9mxNGAi16gDpkjM9jZ7ATfS4fnuugtx3khjbCOBUJ2A/5GcAwErCZwJ8aaRmuLaG26h9JJaP+amPCty6qXo3i6wnoE3PGy6UyDMr4mdPMT3K1IeWr71GiZ7lTEaBCDclFA628QE4VT0fuGcG/qnm6Q0cLZsyARtYCnTRZGyA+4aWTn/jDBlQY0cgH67nTtimUjkiS67Gd64xA/lri0ybb+ZzwGOxU3QysoYGvDl2TatYHjacS8h1la8qHVTe00Nj7K/NC/z3Q== + yugangw2@YUGANGLP2\\n"}]}, "disablePasswordAuthentication": true}, "computerName": + "vm1", "adminUsername": "yugangw2"}, "networkProfile": {"networkInterfaces": + [{"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic"}]}, + "storageProfile": {"osDisk": {"managedDisk": {"storageAccountType": null}, "caching": + "ReadWrite", "createOption": "fromImage", "name": null}, "imageReference": {"offer": + "CentOS", "sku": "7.3", "publisher": "OpenLogic", "version": "latest"}}}, "type": + "Microsoft.Compute/virtualMachines", "location": "westus", "dependsOn": ["Microsoft.Network/networkInterfaces/vm1VMNic"], + "apiVersion": "2017-12-01", "name": "vm1"}]}}}''' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm create] + Connection: [keep-alive] + Content-Length: ['3671'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 resourcemanagementclient/1.2.1 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001/providers/Microsoft.Resources/deployments/mock-deployment?api-version=2017-05-10 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Resources/deployments/vm_deploy_ABZR5AXBdvjprntE9cLPFAewoavFhzKh","name":"vm_deploy_ABZR5AXBdvjprntE9cLPFAewoavFhzKh","properties":{"templateHash":"5060802645681985270","parameters":{},"mode":"Incremental","provisioningState":"Accepted","timestamp":"2018-02-01T05:26:28.4911493Z","duration":"PT0.5004042S","correlationId":"0cf24b3e-4f5a-4b31-b9fc-ba97b1fe41ba","providers":[{"namespace":"Microsoft.Network","resourceTypes":[{"resourceType":"virtualNetworks","locations":["westus"]},{"resourceType":"networkSecurityGroups","locations":["westus"]},{"resourceType":"publicIPAddresses","locations":["westus"]},{"resourceType":"networkInterfaces","locations":["westus"]}]},{"namespace":"Microsoft.Compute","resourceTypes":[{"resourceType":"virtualMachines","locations":["westus"]}]}],"dependencies":[{"dependsOn":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/virtualNetworks/vm1VNET","resourceType":"Microsoft.Network/virtualNetworks","resourceName":"vm1VNET"},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkSecurityGroups/vm1NSG","resourceType":"Microsoft.Network/networkSecurityGroups","resourceName":"vm1NSG"},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/publicIPAddresses/vm1PublicIP","resourceType":"Microsoft.Network/publicIPAddresses","resourceName":"vm1PublicIP"}],"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic","resourceType":"Microsoft.Network/networkInterfaces","resourceName":"vm1VMNic"},{"dependsOn":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic","resourceType":"Microsoft.Network/networkInterfaces","resourceName":"vm1VMNic"}],"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1","resourceType":"Microsoft.Compute/virtualMachines","resourceName":"vm1"}]}}'} + headers: + azure-asyncoperation: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001/providers/Microsoft.Resources/deployments/vm_deploy_ABZR5AXBdvjprntE9cLPFAewoavFhzKh/operationStatuses/08586841440974868944?api-version=2017-05-10'] + cache-control: [no-cache] + content-length: ['2701'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:26:28 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-ms-ratelimit-remaining-subscription-writes: ['1195'] + status: {code: 201, message: Created} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 resourcemanagementclient/1.2.1 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001/providers/Microsoft.Resources/deployments/mock-deployment/operationStatuses/08586841440974868944?api-version=2017-05-10 + response: + body: {string: '{"status":"Running"}'} + headers: + cache-control: [no-cache] + content-length: ['20'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:27:00 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 resourcemanagementclient/1.2.1 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001/providers/Microsoft.Resources/deployments/mock-deployment/operationStatuses/08586841440974868944?api-version=2017-05-10 + response: + body: {string: '{"status":"Running"}'} + headers: + cache-control: [no-cache] + content-length: ['20'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:27:30 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 resourcemanagementclient/1.2.1 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001/providers/Microsoft.Resources/deployments/mock-deployment/operationStatuses/08586841440974868944?api-version=2017-05-10 + response: + body: {string: '{"status":"Running"}'} + headers: + cache-control: [no-cache] + content-length: ['20'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:28:01 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 resourcemanagementclient/1.2.1 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001/providers/Microsoft.Resources/deployments/mock-deployment/operationStatuses/08586841440974868944?api-version=2017-05-10 + response: + body: {string: '{"status":"Running"}'} + headers: + cache-control: [no-cache] + content-length: ['20'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:28:33 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 resourcemanagementclient/1.2.1 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001/providers/Microsoft.Resources/deployments/mock-deployment/operationStatuses/08586841440974868944?api-version=2017-05-10 + response: + body: {string: '{"status":"Succeeded"}'} + headers: + cache-control: [no-cache] + content-length: ['22'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:29:04 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 resourcemanagementclient/1.2.1 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001/providers/Microsoft.Resources/deployments/mock-deployment?api-version=2017-05-10 + response: + body: {string: '{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Resources/deployments/vm_deploy_ABZR5AXBdvjprntE9cLPFAewoavFhzKh","name":"vm_deploy_ABZR5AXBdvjprntE9cLPFAewoavFhzKh","properties":{"templateHash":"5060802645681985270","parameters":{},"mode":"Incremental","provisioningState":"Succeeded","timestamp":"2018-02-01T05:28:39.6757399Z","duration":"PT2M11.6849948S","correlationId":"0cf24b3e-4f5a-4b31-b9fc-ba97b1fe41ba","providers":[{"namespace":"Microsoft.Network","resourceTypes":[{"resourceType":"virtualNetworks","locations":["westus"]},{"resourceType":"networkSecurityGroups","locations":["westus"]},{"resourceType":"publicIPAddresses","locations":["westus"]},{"resourceType":"networkInterfaces","locations":["westus"]}]},{"namespace":"Microsoft.Compute","resourceTypes":[{"resourceType":"virtualMachines","locations":["westus"]}]}],"dependencies":[{"dependsOn":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/virtualNetworks/vm1VNET","resourceType":"Microsoft.Network/virtualNetworks","resourceName":"vm1VNET"},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkSecurityGroups/vm1NSG","resourceType":"Microsoft.Network/networkSecurityGroups","resourceName":"vm1NSG"},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/publicIPAddresses/vm1PublicIP","resourceType":"Microsoft.Network/publicIPAddresses","resourceName":"vm1PublicIP"}],"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic","resourceType":"Microsoft.Network/networkInterfaces","resourceName":"vm1VMNic"},{"dependsOn":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic","resourceType":"Microsoft.Network/networkInterfaces","resourceName":"vm1VMNic"}],"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1","resourceType":"Microsoft.Compute/virtualMachines","resourceName":"vm1"}],"outputs":{},"outputResources":[{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1"},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic"},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkSecurityGroups/vm1NSG"},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/publicIPAddresses/vm1PublicIP"},{"id":"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/virtualNetworks/vm1VNET"}]}}'} + headers: + cache-control: [no-cache] + content-length: ['3768'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:29:05 GMT'] + expires: ['-1'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 computemanagementclient/3.1.0rc3 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1?api-version=2017-12-01&$expand=instanceView + response: + body: {string: "{\r\n \"properties\": {\r\n \"vmId\": \"78b73b6e-04f6-4f4d-91b0-056e145b17f8\"\ + ,\r\n \"hardwareProfile\": {\r\n \"vmSize\": \"Standard_DS1_v2\"\r\ + \n },\r\n \"storageProfile\": {\r\n \"imageReference\": {\r\n \ + \ \"publisher\": \"OpenLogic\",\r\n \"offer\": \"CentOS\",\r\n\ + \ \"sku\": \"7.3\",\r\n \"version\": \"latest\"\r\n },\r\ + \n \"osDisk\": {\r\n \"osType\": \"Linux\",\r\n \"name\"\ + : \"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\",\r\n \"createOption\"\ + : \"FromImage\",\r\n \"caching\": \"ReadWrite\",\r\n \"managedDisk\"\ + : {\r\n \"storageAccountType\": \"Premium_LRS\",\r\n \"\ + id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/disks/vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"\ + \r\n },\r\n \"diskSizeGB\": 31\r\n },\r\n \"dataDisks\"\ + : []\r\n },\r\n \"osProfile\": {\r\n \"computerName\": \"vm1\"\ + ,\r\n \"adminUsername\": \"yugangw2\",\r\n \"linuxConfiguration\"\ + : {\r\n \"disablePasswordAuthentication\": true,\r\n \"ssh\"\ + : {\r\n \"publicKeys\": [\r\n {\r\n \"path\"\ + : \"/home/yugangw2/.ssh/authorized_keys\",\r\n \"keyData\": \"\ + ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6ynxWeY589bvuJVjtobA+qIlWQwycoeRTYNyEUssLQdCWq7YRUxBhXZzf8O8qe8vz8JsxIgX2ynyn9mxNGAi16gDpkjM9jZ7ATfS4fnuugtx3khjbCOBUJ2A/5GcAwErCZwJ8aaRmuLaG26h9JJaP+amPCty6qXo3i6wnoE3PGy6UyDMr4mdPMT3K1IeWr71GiZ7lTEaBCDclFA628QE4VT0fuGcG/qnm6Q0cLZsyARtYCnTRZGyA+4aWTn/jDBlQY0cgH67nTtimUjkiS67Gd64xA/lri0ybb+ZzwGOxU3QysoYGvDl2TatYHjacS8h1la8qHVTe00Nj7K/NC/z3Q==\ + \ yugangw2@YUGANGLP2\\n\"\r\n }\r\n ]\r\n }\r\n\ + \ },\r\n \"secrets\": []\r\n },\r\n \"networkProfile\": {\"\ + networkInterfaces\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic\"\ + }]},\r\n \"provisioningState\": \"Succeeded\",\r\n \"instanceView\"\ + : {\r\n \"computerName\": \"vm1\",\r\n \"osName\": \"centos\",\r\ + \n \"osVersion\": \"7.3.1611\",\r\n \"vmAgent\": {\r\n \"\ + vmAgentVersion\": \"2.2.20\",\r\n \"statuses\": [\r\n {\r\n\ + \ \"code\": \"ProvisioningState/succeeded\",\r\n \"\ + level\": \"Info\",\r\n \"displayStatus\": \"Ready\",\r\n \ + \ \"message\": \"Guest Agent is running\",\r\n \"time\": \"\ + 2018-02-01T05:29:04+00:00\"\r\n }\r\n ],\r\n \"extensionHandlers\"\ + : []\r\n },\r\n \"disks\": [\r\n {\r\n \"name\"\ + : \"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\",\r\n \"statuses\"\ + : [\r\n {\r\n \"code\": \"ProvisioningState/succeeded\"\ + ,\r\n \"level\": \"Info\",\r\n \"displayStatus\"\ + : \"Provisioning succeeded\",\r\n \"time\": \"2018-02-01T05:26:58.4192136+00:00\"\ + \r\n }\r\n ]\r\n }\r\n ],\r\n \"statuses\"\ + : [\r\n {\r\n \"code\": \"ProvisioningState/succeeded\",\r\ + \n \"level\": \"Info\",\r\n \"displayStatus\": \"Provisioning\ + \ succeeded\",\r\n \"time\": \"2018-02-01T05:28:34.9429154+00:00\"\ + \r\n },\r\n {\r\n \"code\": \"PowerState/running\"\ + ,\r\n \"level\": \"Info\",\r\n \"displayStatus\": \"VM running\"\ + \r\n }\r\n ]\r\n }\r\n },\r\n \"type\": \"Microsoft.Compute/virtualMachines\"\ + ,\r\n \"location\": \"westus\",\r\n \"tags\": {},\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1\"\ + ,\r\n \"name\": \"vm1\"\r\n}"} + headers: + cache-control: [no-cache] + content-length: ['3565'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:29:14 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-resource: ['Microsoft.Compute/LowCostGet3Min;4793,Microsoft.Compute/LowCostGet30Min;38366'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 networkmanagementclient/1.7.0 Azure-SDK-For-Python AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic?api-version=2017-11-01 + response: + body: {string: "{\r\n \"name\": \"vm1VMNic\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic\"\ + ,\r\n \"etag\": \"W/\\\"42a57a54-ab48-4797-83c2-91fe7eac1fb7\\\"\",\r\n \ + \ \"location\": \"westus\",\r\n \"tags\": {},\r\n \"properties\": {\r\n\ + \ \"provisioningState\": \"Succeeded\",\r\n \"resourceGuid\": \"e9e695a4-6f50-4ef4-afa2-c66aa90a60e6\"\ + ,\r\n \"ipConfigurations\": [\r\n {\r\n \"name\": \"ipconfigvm1\"\ + ,\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic/ipConfigurations/ipconfigvm1\"\ + ,\r\n \"etag\": \"W/\\\"42a57a54-ab48-4797-83c2-91fe7eac1fb7\\\"\"\ + ,\r\n \"properties\": {\r\n \"provisioningState\": \"Succeeded\"\ + ,\r\n \"privateIPAddress\": \"10.0.0.4\",\r\n \"privateIPAllocationMethod\"\ + : \"Dynamic\",\r\n \"publicIPAddress\": {\r\n \"id\":\ + \ \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/publicIPAddresses/vm1PublicIP\"\ + \r\n },\r\n \"subnet\": {\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/virtualNetworks/vm1VNET/subnets/vm1Subnet\"\ + \r\n },\r\n \"primary\": true,\r\n \"privateIPAddressVersion\"\ + : \"IPv4\"\r\n }\r\n }\r\n ],\r\n \"dnsSettings\": {\r\n\ + \ \"dnsServers\": [],\r\n \"appliedDnsServers\": [],\r\n \"\ + internalDomainNameSuffix\": \"o5snisznbmauvdm0g2ua0lubag.dx.internal.cloudapp.net\"\ + \r\n },\r\n \"macAddress\": \"00-0D-3A-36-DC-3B\",\r\n \"enableAcceleratedNetworking\"\ + : false,\r\n \"enableIPForwarding\": false,\r\n \"networkSecurityGroup\"\ + : {\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkSecurityGroups/vm1NSG\"\ + \r\n },\r\n \"primary\": true,\r\n \"virtualMachine\": {\r\n \ + \ \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1\"\ + \r\n },\r\n \"virtualNetworkTapProvisioningState\": \"NotProvisioned\"\ + \r\n },\r\n \"type\": \"Microsoft.Network/networkInterfaces\"\r\n}"} + headers: + cache-control: [no-cache] + content-length: ['2556'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:29:15 GMT'] + etag: [W/"42a57a54-ab48-4797-83c2-91fe7eac1fb7"] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm create] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 networkmanagementclient/1.7.0 Azure-SDK-For-Python AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/publicIPAddresses/vm1PublicIP?api-version=2017-11-01 + response: + body: {string: "{\r\n \"name\": \"vm1PublicIP\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/publicIPAddresses/vm1PublicIP\"\ + ,\r\n \"etag\": \"W/\\\"f50ecb0b-31c9-4096-a6fc-7ec3a14f5cad\\\"\",\r\n \ + \ \"location\": \"westus\",\r\n \"tags\": {},\r\n \"properties\": {\r\n\ + \ \"provisioningState\": \"Succeeded\",\r\n \"resourceGuid\": \"95db6482-0cbe-4f02-be10-84b7581a6a07\"\ + ,\r\n \"ipAddress\": \"13.91.51.50\",\r\n \"publicIPAddressVersion\"\ + : \"IPv4\",\r\n \"publicIPAllocationMethod\": \"Dynamic\",\r\n \"idleTimeoutInMinutes\"\ + : 4,\r\n \"ipTags\": [],\r\n \"ipConfiguration\": {\r\n \"id\"\ + : \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic/ipConfigurations/ipconfigvm1\"\ + \r\n }\r\n },\r\n \"type\": \"Microsoft.Network/publicIPAddresses\",\r\ + \n \"sku\": {\r\n \"name\": \"Basic\"\r\n }\r\n}"} + headers: + cache-control: [no-cache] + content-length: ['995'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:29:17 GMT'] + etag: [W/"f50ecb0b-31c9-4096-a6fc-7ec3a14f5cad"] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm aem set] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 computemanagementclient/3.1.0rc3 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1?api-version=2017-12-01&$expand=instanceView + response: + body: {string: "{\r\n \"properties\": {\r\n \"vmId\": \"78b73b6e-04f6-4f4d-91b0-056e145b17f8\"\ + ,\r\n \"hardwareProfile\": {\r\n \"vmSize\": \"Standard_DS1_v2\"\r\ + \n },\r\n \"storageProfile\": {\r\n \"imageReference\": {\r\n \ + \ \"publisher\": \"OpenLogic\",\r\n \"offer\": \"CentOS\",\r\n\ + \ \"sku\": \"7.3\",\r\n \"version\": \"latest\"\r\n },\r\ + \n \"osDisk\": {\r\n \"osType\": \"Linux\",\r\n \"name\"\ + : \"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\",\r\n \"createOption\"\ + : \"FromImage\",\r\n \"caching\": \"ReadWrite\",\r\n \"managedDisk\"\ + : {\r\n \"storageAccountType\": \"Premium_LRS\",\r\n \"\ + id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/disks/vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"\ + \r\n },\r\n \"diskSizeGB\": 31\r\n },\r\n \"dataDisks\"\ + : []\r\n },\r\n \"osProfile\": {\r\n \"computerName\": \"vm1\"\ + ,\r\n \"adminUsername\": \"yugangw2\",\r\n \"linuxConfiguration\"\ + : {\r\n \"disablePasswordAuthentication\": true,\r\n \"ssh\"\ + : {\r\n \"publicKeys\": [\r\n {\r\n \"path\"\ + : \"/home/yugangw2/.ssh/authorized_keys\",\r\n \"keyData\": \"\ + ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6ynxWeY589bvuJVjtobA+qIlWQwycoeRTYNyEUssLQdCWq7YRUxBhXZzf8O8qe8vz8JsxIgX2ynyn9mxNGAi16gDpkjM9jZ7ATfS4fnuugtx3khjbCOBUJ2A/5GcAwErCZwJ8aaRmuLaG26h9JJaP+amPCty6qXo3i6wnoE3PGy6UyDMr4mdPMT3K1IeWr71GiZ7lTEaBCDclFA628QE4VT0fuGcG/qnm6Q0cLZsyARtYCnTRZGyA+4aWTn/jDBlQY0cgH67nTtimUjkiS67Gd64xA/lri0ybb+ZzwGOxU3QysoYGvDl2TatYHjacS8h1la8qHVTe00Nj7K/NC/z3Q==\ + \ yugangw2@YUGANGLP2\\n\"\r\n }\r\n ]\r\n }\r\n\ + \ },\r\n \"secrets\": []\r\n },\r\n \"networkProfile\": {\"\ + networkInterfaces\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic\"\ + }]},\r\n \"provisioningState\": \"Succeeded\",\r\n \"instanceView\"\ + : {\r\n \"computerName\": \"vm1\",\r\n \"osName\": \"centos\",\r\ + \n \"osVersion\": \"7.3.1611\",\r\n \"vmAgent\": {\r\n \"\ + vmAgentVersion\": \"2.2.20\",\r\n \"statuses\": [\r\n {\r\n\ + \ \"code\": \"ProvisioningState/succeeded\",\r\n \"\ + level\": \"Info\",\r\n \"displayStatus\": \"Ready\",\r\n \ + \ \"message\": \"Guest Agent is running\",\r\n \"time\": \"\ + 2018-02-01T05:29:16+00:00\"\r\n }\r\n ],\r\n \"extensionHandlers\"\ + : []\r\n },\r\n \"disks\": [\r\n {\r\n \"name\"\ + : \"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\",\r\n \"statuses\"\ + : [\r\n {\r\n \"code\": \"ProvisioningState/succeeded\"\ + ,\r\n \"level\": \"Info\",\r\n \"displayStatus\"\ + : \"Provisioning succeeded\",\r\n \"time\": \"2018-02-01T05:26:58.4192136+00:00\"\ + \r\n }\r\n ]\r\n }\r\n ],\r\n \"statuses\"\ + : [\r\n {\r\n \"code\": \"ProvisioningState/succeeded\",\r\ + \n \"level\": \"Info\",\r\n \"displayStatus\": \"Provisioning\ + \ succeeded\",\r\n \"time\": \"2018-02-01T05:28:34.9429154+00:00\"\ + \r\n },\r\n {\r\n \"code\": \"PowerState/running\"\ + ,\r\n \"level\": \"Info\",\r\n \"displayStatus\": \"VM running\"\ + \r\n }\r\n ]\r\n }\r\n },\r\n \"type\": \"Microsoft.Compute/virtualMachines\"\ + ,\r\n \"location\": \"westus\",\r\n \"tags\": {},\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1\"\ + ,\r\n \"name\": \"vm1\"\r\n}"} + headers: + cache-control: [no-cache] + content-length: ['3565'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:29:26 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-resource: ['Microsoft.Compute/LowCostGet3Min;4792,Microsoft.Compute/LowCostGet30Min;38365'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm aem set] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 computemanagementclient/3.1.0rc3 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/disks/vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389?api-version=2017-03-30 + response: + body: {string: "{\r\n \"managedBy\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1\"\ + ,\r\n \"sku\": {\r\n \"name\": \"Premium_LRS\",\r\n \"tier\": \"Premium\"\ + \r\n },\r\n \"properties\": {\r\n \"osType\": \"Linux\",\r\n \"creationData\"\ + : {\r\n \"createOption\": \"FromImage\",\r\n \"imageReference\"\ + : {\r\n \"id\": \"/Subscriptions/00000000-0000-0000-0000-000000000000/Providers/Microsoft.Compute/Locations/westus/Publishers/OpenLogic/ArtifactTypes/VMImage/Offers/CentOS/Skus/7.3/Versions/7.3.20170925\"\ + \r\n }\r\n },\r\n \"diskSizeGB\": 31,\r\n \"timeCreated\": \"\ + 2018-02-01T05:26:57.0127133+00:00\",\r\n \"provisioningState\": \"Succeeded\"\ + ,\r\n \"diskState\": \"Attached\"\r\n },\r\n \"type\": \"Microsoft.Compute/disks\"\ + ,\r\n \"location\": \"westus\",\r\n \"tags\": {},\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/disks/vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"\ + ,\r\n \"name\": \"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"\r\n}"} + headers: + cache-control: [no-cache] + content-length: ['1157'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:29:27 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-resource: ['Microsoft.Compute/LowCostGet3Min;4999,Microsoft.Compute/LowCostGet30Min;19996'] + status: {code: 200, message: OK} +- request: + body: '{"properties": {"publisher": "Microsoft.OSTCExtensions", "autoUpgradeMinorVersion": + true, "type": "AzureEnhancedMonitorForLinux", "settings": {"cfg": [{"key": "wad.isenabled", + "value": 0}, {"key": "osdisk.name", "value": "vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389"}, + {"key": "script.version", "value": "3.0.0.0"}, {"key": "vm.cpu.isovercommitted", + "value": 0}, {"key": "osdisk.type", "value": "Premium"}, {"key": "osdisk.caching", + "value": "ReadWrite"}, {"key": "vm.sla.throughput", "value": 48}, {"key": "vm.memory.isovercommitted", + "value": 0}, {"key": "osdisk.sla.iops", "value": 120}, {"key": "vm.sla.iops", + "value": 3200}, {"key": "vmsize", "value": "Standard_DS1_v2"}, {"key": "href", + "value": "http://aka.ms/sapaem"}, {"key": "vm.role", "value": "IaaS"}, {"key": + "verbose", "value": "0"}, {"key": "osdisk.sla.throughput", "value": 125}]}, + "typeHandlerVersion": "3.0", "protectedSettings": {"cfg": [{"key": "wad.isenabled", + "value": 0}, {"key": "osdisk.name", "value": "vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389"}, + {"key": "script.version", "value": "3.0.0.0"}, {"key": "vm.cpu.isovercommitted", + "value": 0}, {"key": "osdisk.type", "value": "Premium"}, {"key": "osdisk.caching", + "value": "ReadWrite"}, {"key": "vm.sla.throughput", "value": 48}, {"key": "vm.memory.isovercommitted", + "value": 0}, {"key": "osdisk.sla.iops", "value": 120}, {"key": "vm.sla.iops", + "value": 3200}, {"key": "vmsize", "value": "Standard_DS1_v2"}, {"key": "href", + "value": "http://aka.ms/sapaem"}, {"key": "vm.role", "value": "IaaS"}, {"key": + "verbose", "value": "0"}, {"key": "osdisk.sla.throughput", "value": 125}]}}, + "location": "westus"}' + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm aem set] + Connection: [keep-alive] + Content-Length: ['1630'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 computemanagementclient/3.1.0rc3 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: PUT + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1/extensions/AzureEnhancedMonitorForLinux?api-version=2017-12-01 + response: + body: {string: "{\r\n \"properties\": {\r\n \"publisher\": \"Microsoft.OSTCExtensions\"\ + ,\r\n \"type\": \"AzureEnhancedMonitorForLinux\",\r\n \"typeHandlerVersion\"\ + : \"3.0\",\r\n \"autoUpgradeMinorVersion\": true,\r\n \"settings\":\ + \ {\"cfg\":[{\"key\":\"wad.isenabled\",\"value\":0},{\"key\":\"osdisk.name\"\ + ,\"value\":\"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"},{\"key\":\"\ + script.version\",\"value\":\"3.0.0.0\"},{\"key\":\"vm.cpu.isovercommitted\"\ + ,\"value\":0},{\"key\":\"osdisk.type\",\"value\":\"Premium\"},{\"key\":\"\ + osdisk.caching\",\"value\":\"ReadWrite\"},{\"key\":\"vm.sla.throughput\",\"\ + value\":48},{\"key\":\"vm.memory.isovercommitted\",\"value\":0},{\"key\":\"\ + osdisk.sla.iops\",\"value\":120},{\"key\":\"vm.sla.iops\",\"value\":3200},{\"\ + key\":\"vmsize\",\"value\":\"Standard_DS1_v2\"},{\"key\":\"href\",\"value\"\ + :\"http://aka.ms/sapaem\"},{\"key\":\"vm.role\",\"value\":\"IaaS\"},{\"key\"\ + :\"verbose\",\"value\":\"0\"},{\"key\":\"osdisk.sla.throughput\",\"value\"\ + :125}]},\r\n \"provisioningState\": \"Creating\"\r\n },\r\n \"type\"\ + : \"Microsoft.Compute/virtualMachines/extensions\",\r\n \"location\": \"\ + westus\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1/extensions/AzureEnhancedMonitorForLinux\"\ + ,\r\n \"name\": \"AzureEnhancedMonitorForLinux\"\r\n}"} + headers: + azure-asyncoperation: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Compute/locations/westus/operations/74c1258a-ce8c-491a-bbe9-35cb765723d1?api-version=2017-12-01'] + cache-control: [no-cache] + content-length: ['1263'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:29:30 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-ms-ratelimit-remaining-resource: ['Microsoft.Compute/UpdateVM3Min;239,Microsoft.Compute/UpdateVM30Min;1196'] + x-ms-ratelimit-remaining-subscription-writes: ['1190'] + status: {code: 201, message: Created} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm aem set] + Connection: [keep-alive] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 computemanagementclient/3.1.0rc3 Azure-SDK-For-Python + AZURECLI/2.0.27] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Compute/locations/westus/operations/74c1258a-ce8c-491a-bbe9-35cb765723d1?api-version=2017-12-01 + response: + body: {string: "{\r\n \"startTime\": \"2018-02-01T05:29:30.255414+00:00\",\r\n\ + \ \"endTime\": \"2018-02-01T05:29:49.0991618+00:00\",\r\n \"status\": \"\ + Succeeded\",\r\n \"name\": \"74c1258a-ce8c-491a-bbe9-35cb765723d1\"\r\n}"} + headers: + cache-control: [no-cache] + content-length: ['183'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:30:49 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-resource: ['Microsoft.Compute/GetOperation3Min;11991,Microsoft.Compute/GetOperation30Min;23964'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm aem set] + Connection: [keep-alive] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 computemanagementclient/3.1.0rc3 Azure-SDK-For-Python + AZURECLI/2.0.27] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1/extensions/AzureEnhancedMonitorForLinux?api-version=2017-12-01 + response: + body: {string: "{\r\n \"properties\": {\r\n \"publisher\": \"Microsoft.OSTCExtensions\"\ + ,\r\n \"type\": \"AzureEnhancedMonitorForLinux\",\r\n \"typeHandlerVersion\"\ + : \"3.0\",\r\n \"autoUpgradeMinorVersion\": true,\r\n \"settings\":\ + \ {\"cfg\":[{\"key\":\"wad.isenabled\",\"value\":0},{\"key\":\"osdisk.name\"\ + ,\"value\":\"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"},{\"key\":\"\ + script.version\",\"value\":\"3.0.0.0\"},{\"key\":\"vm.cpu.isovercommitted\"\ + ,\"value\":0},{\"key\":\"osdisk.type\",\"value\":\"Premium\"},{\"key\":\"\ + osdisk.caching\",\"value\":\"ReadWrite\"},{\"key\":\"vm.sla.throughput\",\"\ + value\":48},{\"key\":\"vm.memory.isovercommitted\",\"value\":0},{\"key\":\"\ + osdisk.sla.iops\",\"value\":120},{\"key\":\"vm.sla.iops\",\"value\":3200},{\"\ + key\":\"vmsize\",\"value\":\"Standard_DS1_v2\"},{\"key\":\"href\",\"value\"\ + :\"http://aka.ms/sapaem\"},{\"key\":\"vm.role\",\"value\":\"IaaS\"},{\"key\"\ + :\"verbose\",\"value\":\"0\"},{\"key\":\"osdisk.sla.throughput\",\"value\"\ + :125}]},\r\n \"provisioningState\": \"Succeeded\"\r\n },\r\n \"type\"\ + : \"Microsoft.Compute/virtualMachines/extensions\",\r\n \"location\": \"\ + westus\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1/extensions/AzureEnhancedMonitorForLinux\"\ + ,\r\n \"name\": \"AzureEnhancedMonitorForLinux\"\r\n}"} + headers: + cache-control: [no-cache] + content-length: ['1264'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:30:49 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-resource: ['Microsoft.Compute/LowCostGet3Min;4790,Microsoft.Compute/LowCostGet30Min;38363'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm aem verify] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 computemanagementclient/3.1.0rc3 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1?api-version=2017-12-01&$expand=instanceView + response: + body: {string: "{\r\n \"properties\": {\r\n \"vmId\": \"78b73b6e-04f6-4f4d-91b0-056e145b17f8\"\ + ,\r\n \"hardwareProfile\": {\r\n \"vmSize\": \"Standard_DS1_v2\"\r\ + \n },\r\n \"storageProfile\": {\r\n \"imageReference\": {\r\n \ + \ \"publisher\": \"OpenLogic\",\r\n \"offer\": \"CentOS\",\r\n\ + \ \"sku\": \"7.3\",\r\n \"version\": \"latest\"\r\n },\r\ + \n \"osDisk\": {\r\n \"osType\": \"Linux\",\r\n \"name\"\ + : \"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\",\r\n \"createOption\"\ + : \"FromImage\",\r\n \"caching\": \"ReadWrite\",\r\n \"managedDisk\"\ + : {\r\n \"storageAccountType\": \"Premium_LRS\",\r\n \"\ + id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/disks/vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"\ + \r\n },\r\n \"diskSizeGB\": 31\r\n },\r\n \"dataDisks\"\ + : []\r\n },\r\n \"osProfile\": {\r\n \"computerName\": \"vm1\"\ + ,\r\n \"adminUsername\": \"yugangw2\",\r\n \"linuxConfiguration\"\ + : {\r\n \"disablePasswordAuthentication\": true,\r\n \"ssh\"\ + : {\r\n \"publicKeys\": [\r\n {\r\n \"path\"\ + : \"/home/yugangw2/.ssh/authorized_keys\",\r\n \"keyData\": \"\ + ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6ynxWeY589bvuJVjtobA+qIlWQwycoeRTYNyEUssLQdCWq7YRUxBhXZzf8O8qe8vz8JsxIgX2ynyn9mxNGAi16gDpkjM9jZ7ATfS4fnuugtx3khjbCOBUJ2A/5GcAwErCZwJ8aaRmuLaG26h9JJaP+amPCty6qXo3i6wnoE3PGy6UyDMr4mdPMT3K1IeWr71GiZ7lTEaBCDclFA628QE4VT0fuGcG/qnm6Q0cLZsyARtYCnTRZGyA+4aWTn/jDBlQY0cgH67nTtimUjkiS67Gd64xA/lri0ybb+ZzwGOxU3QysoYGvDl2TatYHjacS8h1la8qHVTe00Nj7K/NC/z3Q==\ + \ yugangw2@YUGANGLP2\\n\"\r\n }\r\n ]\r\n }\r\n\ + \ },\r\n \"secrets\": []\r\n },\r\n \"networkProfile\": {\"\ + networkInterfaces\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic\"\ + }]},\r\n \"provisioningState\": \"Succeeded\",\r\n \"instanceView\"\ + : {\r\n \"computerName\": \"vm1\",\r\n \"osName\": \"centos\",\r\ + \n \"osVersion\": \"7.3.1611\",\r\n \"vmAgent\": {\r\n \"\ + vmAgentVersion\": \"2.2.20\",\r\n \"statuses\": [\r\n {\r\n\ + \ \"code\": \"ProvisioningState/succeeded\",\r\n \"\ + level\": \"Info\",\r\n \"displayStatus\": \"Ready\",\r\n \ + \ \"message\": \"Guest Agent is running\",\r\n \"time\": \"\ + 2018-02-01T05:30:51+00:00\"\r\n }\r\n ],\r\n \"extensionHandlers\"\ + : [\r\n {\r\n \"type\": \"Microsoft.OSTCExtensions.AzureEnhancedMonitorForLinux\"\ + ,\r\n \"typeHandlerVersion\": \"3.0.1.0\",\r\n \"status\"\ + : {\r\n \"code\": \"ProvisioningState/succeeded\",\r\n \ + \ \"level\": \"Info\",\r\n \"displayStatus\": \"Ready\"\ + ,\r\n \"message\": \"Plugin enabled\"\r\n }\r\n \ + \ }\r\n ]\r\n },\r\n \"disks\": [\r\n {\r\n\ + \ \"name\": \"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\",\r\n\ + \ \"statuses\": [\r\n {\r\n \"code\": \"\ + ProvisioningState/succeeded\",\r\n \"level\": \"Info\",\r\n \ + \ \"displayStatus\": \"Provisioning succeeded\",\r\n \ + \ \"time\": \"2018-02-01T05:26:58.4192136+00:00\"\r\n }\r\n\ + \ ]\r\n }\r\n ],\r\n \"extensions\": [\r\n \ + \ {\r\n \"name\": \"AzureEnhancedMonitorForLinux\",\r\n \ + \ \"type\": \"Microsoft.OSTCExtensions.AzureEnhancedMonitorForLinux\",\r\ + \n \"typeHandlerVersion\": \"3.0.1.0\",\r\n \"statuses\"\ + : [\r\n {\r\n \"code\": \"ProvisioningState/succeeded\"\ + ,\r\n \"level\": \"Info\",\r\n \"displayStatus\"\ + : \"Provisioning succeeded\",\r\n \"message\": \"deploymentId=7d8658a5-de26-4c21-ab5f-3c8c7bb539e4\ + \ roleInstance=_vm1 OK\"\r\n }\r\n ]\r\n }\r\n\ + \ ],\r\n \"statuses\": [\r\n {\r\n \"code\": \"\ + ProvisioningState/succeeded\",\r\n \"level\": \"Info\",\r\n \ + \ \"displayStatus\": \"Provisioning succeeded\",\r\n \"time\"\ + : \"2018-02-01T05:29:49.0835512+00:00\"\r\n },\r\n {\r\n \ + \ \"code\": \"PowerState/running\",\r\n \"level\": \"Info\"\ + ,\r\n \"displayStatus\": \"VM running\"\r\n }\r\n ]\r\ + \n }\r\n },\r\n \"resources\": [\r\n {\r\n \"properties\": {\r\ + \n \"publisher\": \"Microsoft.OSTCExtensions\",\r\n \"type\"\ + : \"AzureEnhancedMonitorForLinux\",\r\n \"typeHandlerVersion\": \"\ + 3.0\",\r\n \"autoUpgradeMinorVersion\": true,\r\n \"settings\"\ + : {\"cfg\":[{\"key\":\"wad.isenabled\",\"value\":0},{\"key\":\"osdisk.name\"\ + ,\"value\":\"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"},{\"key\":\"\ + script.version\",\"value\":\"3.0.0.0\"},{\"key\":\"vm.cpu.isovercommitted\"\ + ,\"value\":0},{\"key\":\"osdisk.type\",\"value\":\"Premium\"},{\"key\":\"\ + osdisk.caching\",\"value\":\"ReadWrite\"},{\"key\":\"vm.sla.throughput\",\"\ + value\":48},{\"key\":\"vm.memory.isovercommitted\",\"value\":0},{\"key\":\"\ + osdisk.sla.iops\",\"value\":120},{\"key\":\"vm.sla.iops\",\"value\":3200},{\"\ + key\":\"vmsize\",\"value\":\"Standard_DS1_v2\"},{\"key\":\"href\",\"value\"\ + :\"http://aka.ms/sapaem\"},{\"key\":\"vm.role\",\"value\":\"IaaS\"},{\"key\"\ + :\"verbose\",\"value\":\"0\"},{\"key\":\"osdisk.sla.throughput\",\"value\"\ + :125}]},\r\n \"provisioningState\": \"Succeeded\"\r\n },\r\n \ + \ \"type\": \"Microsoft.Compute/virtualMachines/extensions\",\r\n \ + \ \"location\": \"westus\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1/extensions/AzureEnhancedMonitorForLinux\"\ + ,\r\n \"name\": \"AzureEnhancedMonitorForLinux\"\r\n }\r\n ],\r\n\ + \ \"type\": \"Microsoft.Compute/virtualMachines\",\r\n \"location\": \"\ + westus\",\r\n \"tags\": {},\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1\"\ + ,\r\n \"name\": \"vm1\"\r\n}"} + headers: + cache-control: [no-cache] + content-length: ['5818'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:30:54 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-resource: ['Microsoft.Compute/LowCostGet3Min;4789,Microsoft.Compute/LowCostGet30Min;38362'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm aem verify] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 computemanagementclient/3.1.0rc3 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/disks/vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389?api-version=2017-03-30 + response: + body: {string: "{\r\n \"managedBy\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1\"\ + ,\r\n \"sku\": {\r\n \"name\": \"Premium_LRS\",\r\n \"tier\": \"Premium\"\ + \r\n },\r\n \"properties\": {\r\n \"osType\": \"Linux\",\r\n \"creationData\"\ + : {\r\n \"createOption\": \"FromImage\",\r\n \"imageReference\"\ + : {\r\n \"id\": \"/Subscriptions/00000000-0000-0000-0000-000000000000/Providers/Microsoft.Compute/Locations/westus/Publishers/OpenLogic/ArtifactTypes/VMImage/Offers/CentOS/Skus/7.3/Versions/7.3.20170925\"\ + \r\n }\r\n },\r\n \"diskSizeGB\": 31,\r\n \"timeCreated\": \"\ + 2018-02-01T05:26:57.0127133+00:00\",\r\n \"provisioningState\": \"Succeeded\"\ + ,\r\n \"diskState\": \"Attached\"\r\n },\r\n \"type\": \"Microsoft.Compute/disks\"\ + ,\r\n \"location\": \"westus\",\r\n \"tags\": {},\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/disks/vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"\ + ,\r\n \"name\": \"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"\r\n}"} + headers: + cache-control: [no-cache] + content-length: ['1157'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:31:02 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-resource: ['Microsoft.Compute/LowCostGet3Min;4997,Microsoft.Compute/LowCostGet30Min;19995'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm aem delete] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 computemanagementclient/3.1.0rc3 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1?api-version=2017-12-01&$expand=instanceView + response: + body: {string: "{\r\n \"properties\": {\r\n \"vmId\": \"78b73b6e-04f6-4f4d-91b0-056e145b17f8\"\ + ,\r\n \"hardwareProfile\": {\r\n \"vmSize\": \"Standard_DS1_v2\"\r\ + \n },\r\n \"storageProfile\": {\r\n \"imageReference\": {\r\n \ + \ \"publisher\": \"OpenLogic\",\r\n \"offer\": \"CentOS\",\r\n\ + \ \"sku\": \"7.3\",\r\n \"version\": \"latest\"\r\n },\r\ + \n \"osDisk\": {\r\n \"osType\": \"Linux\",\r\n \"name\"\ + : \"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\",\r\n \"createOption\"\ + : \"FromImage\",\r\n \"caching\": \"ReadWrite\",\r\n \"managedDisk\"\ + : {\r\n \"storageAccountType\": \"Premium_LRS\",\r\n \"\ + id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/disks/vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"\ + \r\n },\r\n \"diskSizeGB\": 31\r\n },\r\n \"dataDisks\"\ + : []\r\n },\r\n \"osProfile\": {\r\n \"computerName\": \"vm1\"\ + ,\r\n \"adminUsername\": \"yugangw2\",\r\n \"linuxConfiguration\"\ + : {\r\n \"disablePasswordAuthentication\": true,\r\n \"ssh\"\ + : {\r\n \"publicKeys\": [\r\n {\r\n \"path\"\ + : \"/home/yugangw2/.ssh/authorized_keys\",\r\n \"keyData\": \"\ + ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6ynxWeY589bvuJVjtobA+qIlWQwycoeRTYNyEUssLQdCWq7YRUxBhXZzf8O8qe8vz8JsxIgX2ynyn9mxNGAi16gDpkjM9jZ7ATfS4fnuugtx3khjbCOBUJ2A/5GcAwErCZwJ8aaRmuLaG26h9JJaP+amPCty6qXo3i6wnoE3PGy6UyDMr4mdPMT3K1IeWr71GiZ7lTEaBCDclFA628QE4VT0fuGcG/qnm6Q0cLZsyARtYCnTRZGyA+4aWTn/jDBlQY0cgH67nTtimUjkiS67Gd64xA/lri0ybb+ZzwGOxU3QysoYGvDl2TatYHjacS8h1la8qHVTe00Nj7K/NC/z3Q==\ + \ yugangw2@YUGANGLP2\\n\"\r\n }\r\n ]\r\n }\r\n\ + \ },\r\n \"secrets\": []\r\n },\r\n \"networkProfile\": {\"\ + networkInterfaces\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic\"\ + }]},\r\n \"provisioningState\": \"Succeeded\",\r\n \"instanceView\"\ + : {\r\n \"computerName\": \"vm1\",\r\n \"osName\": \"centos\",\r\ + \n \"osVersion\": \"7.3.1611\",\r\n \"vmAgent\": {\r\n \"\ + vmAgentVersion\": \"2.2.20\",\r\n \"statuses\": [\r\n {\r\n\ + \ \"code\": \"ProvisioningState/succeeded\",\r\n \"\ + level\": \"Info\",\r\n \"displayStatus\": \"Ready\",\r\n \ + \ \"message\": \"Guest Agent is running\",\r\n \"time\": \"\ + 2018-02-01T05:31:06+00:00\"\r\n }\r\n ],\r\n \"extensionHandlers\"\ + : [\r\n {\r\n \"type\": \"Microsoft.OSTCExtensions.AzureEnhancedMonitorForLinux\"\ + ,\r\n \"typeHandlerVersion\": \"3.0.1.0\",\r\n \"status\"\ + : {\r\n \"code\": \"ProvisioningState/succeeded\",\r\n \ + \ \"level\": \"Info\",\r\n \"displayStatus\": \"Ready\"\ + ,\r\n \"message\": \"Plugin enabled\"\r\n }\r\n \ + \ }\r\n ]\r\n },\r\n \"disks\": [\r\n {\r\n\ + \ \"name\": \"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\",\r\n\ + \ \"statuses\": [\r\n {\r\n \"code\": \"\ + ProvisioningState/succeeded\",\r\n \"level\": \"Info\",\r\n \ + \ \"displayStatus\": \"Provisioning succeeded\",\r\n \ + \ \"time\": \"2018-02-01T05:26:58.4192136+00:00\"\r\n }\r\n\ + \ ]\r\n }\r\n ],\r\n \"extensions\": [\r\n \ + \ {\r\n \"name\": \"AzureEnhancedMonitorForLinux\",\r\n \ + \ \"type\": \"Microsoft.OSTCExtensions.AzureEnhancedMonitorForLinux\",\r\ + \n \"typeHandlerVersion\": \"3.0.1.0\",\r\n \"statuses\"\ + : [\r\n {\r\n \"code\": \"ProvisioningState/succeeded\"\ + ,\r\n \"level\": \"Info\",\r\n \"displayStatus\"\ + : \"Provisioning succeeded\",\r\n \"message\": \"deploymentId=7d8658a5-de26-4c21-ab5f-3c8c7bb539e4\ + \ roleInstance=_vm1 OK\"\r\n }\r\n ]\r\n }\r\n\ + \ ],\r\n \"statuses\": [\r\n {\r\n \"code\": \"\ + ProvisioningState/succeeded\",\r\n \"level\": \"Info\",\r\n \ + \ \"displayStatus\": \"Provisioning succeeded\",\r\n \"time\"\ + : \"2018-02-01T05:29:49.0835512+00:00\"\r\n },\r\n {\r\n \ + \ \"code\": \"PowerState/running\",\r\n \"level\": \"Info\"\ + ,\r\n \"displayStatus\": \"VM running\"\r\n }\r\n ]\r\ + \n }\r\n },\r\n \"resources\": [\r\n {\r\n \"properties\": {\r\ + \n \"publisher\": \"Microsoft.OSTCExtensions\",\r\n \"type\"\ + : \"AzureEnhancedMonitorForLinux\",\r\n \"typeHandlerVersion\": \"\ + 3.0\",\r\n \"autoUpgradeMinorVersion\": true,\r\n \"settings\"\ + : {\"cfg\":[{\"key\":\"wad.isenabled\",\"value\":0},{\"key\":\"osdisk.name\"\ + ,\"value\":\"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"},{\"key\":\"\ + script.version\",\"value\":\"3.0.0.0\"},{\"key\":\"vm.cpu.isovercommitted\"\ + ,\"value\":0},{\"key\":\"osdisk.type\",\"value\":\"Premium\"},{\"key\":\"\ + osdisk.caching\",\"value\":\"ReadWrite\"},{\"key\":\"vm.sla.throughput\",\"\ + value\":48},{\"key\":\"vm.memory.isovercommitted\",\"value\":0},{\"key\":\"\ + osdisk.sla.iops\",\"value\":120},{\"key\":\"vm.sla.iops\",\"value\":3200},{\"\ + key\":\"vmsize\",\"value\":\"Standard_DS1_v2\"},{\"key\":\"href\",\"value\"\ + :\"http://aka.ms/sapaem\"},{\"key\":\"vm.role\",\"value\":\"IaaS\"},{\"key\"\ + :\"verbose\",\"value\":\"0\"},{\"key\":\"osdisk.sla.throughput\",\"value\"\ + :125}]},\r\n \"provisioningState\": \"Succeeded\"\r\n },\r\n \ + \ \"type\": \"Microsoft.Compute/virtualMachines/extensions\",\r\n \ + \ \"location\": \"westus\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1/extensions/AzureEnhancedMonitorForLinux\"\ + ,\r\n \"name\": \"AzureEnhancedMonitorForLinux\"\r\n }\r\n ],\r\n\ + \ \"type\": \"Microsoft.Compute/virtualMachines\",\r\n \"location\": \"\ + westus\",\r\n \"tags\": {},\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1\"\ + ,\r\n \"name\": \"vm1\"\r\n}"} + headers: + cache-control: [no-cache] + content-length: ['5818'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:31:12 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-resource: ['Microsoft.Compute/LowCostGet3Min;4788,Microsoft.Compute/LowCostGet30Min;38361'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm aem delete] + Connection: [keep-alive] + Content-Length: ['0'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 computemanagementclient/3.1.0rc3 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: DELETE + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1/extensions/AzureEnhancedMonitorForLinux?api-version=2017-12-01 + response: + body: {string: ''} + headers: + azure-asyncoperation: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Compute/locations/westus/operations/1fce6e8d-75a2-4fbf-8914-caa05be1b40b?api-version=2017-12-01'] + cache-control: [no-cache] + content-length: ['0'] + date: ['Thu, 01 Feb 2018 05:31:13 GMT'] + expires: ['-1'] + location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Compute/locations/westus/operations/1fce6e8d-75a2-4fbf-8914-caa05be1b40b?monitor=true&api-version=2017-12-01'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-ms-ratelimit-remaining-resource: ['Microsoft.Compute/UpdateVM3Min;238,Microsoft.Compute/UpdateVM30Min;1195'] + x-ms-ratelimit-remaining-subscription-writes: ['1199'] + status: {code: 202, message: Accepted} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm aem verify] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 computemanagementclient/3.1.0rc3 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1?api-version=2017-12-01&$expand=instanceView + response: + body: {string: "{\r\n \"properties\": {\r\n \"vmId\": \"78b73b6e-04f6-4f4d-91b0-056e145b17f8\"\ + ,\r\n \"hardwareProfile\": {\r\n \"vmSize\": \"Standard_DS1_v2\"\r\ + \n },\r\n \"storageProfile\": {\r\n \"imageReference\": {\r\n \ + \ \"publisher\": \"OpenLogic\",\r\n \"offer\": \"CentOS\",\r\n\ + \ \"sku\": \"7.3\",\r\n \"version\": \"latest\"\r\n },\r\ + \n \"osDisk\": {\r\n \"osType\": \"Linux\",\r\n \"name\"\ + : \"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\",\r\n \"createOption\"\ + : \"FromImage\",\r\n \"caching\": \"ReadWrite\",\r\n \"managedDisk\"\ + : {\r\n \"storageAccountType\": \"Premium_LRS\",\r\n \"\ + id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/disks/vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"\ + \r\n },\r\n \"diskSizeGB\": 31\r\n },\r\n \"dataDisks\"\ + : []\r\n },\r\n \"osProfile\": {\r\n \"computerName\": \"vm1\"\ + ,\r\n \"adminUsername\": \"yugangw2\",\r\n \"linuxConfiguration\"\ + : {\r\n \"disablePasswordAuthentication\": true,\r\n \"ssh\"\ + : {\r\n \"publicKeys\": [\r\n {\r\n \"path\"\ + : \"/home/yugangw2/.ssh/authorized_keys\",\r\n \"keyData\": \"\ + ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6ynxWeY589bvuJVjtobA+qIlWQwycoeRTYNyEUssLQdCWq7YRUxBhXZzf8O8qe8vz8JsxIgX2ynyn9mxNGAi16gDpkjM9jZ7ATfS4fnuugtx3khjbCOBUJ2A/5GcAwErCZwJ8aaRmuLaG26h9JJaP+amPCty6qXo3i6wnoE3PGy6UyDMr4mdPMT3K1IeWr71GiZ7lTEaBCDclFA628QE4VT0fuGcG/qnm6Q0cLZsyARtYCnTRZGyA+4aWTn/jDBlQY0cgH67nTtimUjkiS67Gd64xA/lri0ybb+ZzwGOxU3QysoYGvDl2TatYHjacS8h1la8qHVTe00Nj7K/NC/z3Q==\ + \ yugangw2@YUGANGLP2\\n\"\r\n }\r\n ]\r\n }\r\n\ + \ },\r\n \"secrets\": []\r\n },\r\n \"networkProfile\": {\"\ + networkInterfaces\":[{\"id\":\"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Network/networkInterfaces/vm1VMNic\"\ + }]},\r\n \"provisioningState\": \"Updating\",\r\n \"instanceView\":\ + \ {\r\n \"computerName\": \"vm1\",\r\n \"osName\": \"centos\",\r\ + \n \"osVersion\": \"7.3.1611\",\r\n \"vmAgent\": {\r\n \"\ + vmAgentVersion\": \"2.2.20\",\r\n \"statuses\": [\r\n {\r\n\ + \ \"code\": \"ProvisioningState/succeeded\",\r\n \"\ + level\": \"Info\",\r\n \"displayStatus\": \"Ready\",\r\n \ + \ \"message\": \"Guest Agent is running\",\r\n \"time\": \"\ + 2018-02-01T05:31:16+00:00\"\r\n }\r\n ],\r\n \"extensionHandlers\"\ + : [\r\n {\r\n \"type\": \"Microsoft.OSTCExtensions.AzureEnhancedMonitorForLinux\"\ + ,\r\n \"typeHandlerVersion\": \"3.0.1.0\",\r\n \"status\"\ + : {\r\n \"code\": \"ProvisioningState/succeeded\",\r\n \ + \ \"level\": \"Info\",\r\n \"displayStatus\": \"Ready\"\ + ,\r\n \"message\": \"Plugin enabled\"\r\n }\r\n \ + \ }\r\n ]\r\n },\r\n \"disks\": [\r\n {\r\n\ + \ \"name\": \"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\",\r\n\ + \ \"statuses\": [\r\n {\r\n \"code\": \"\ + ProvisioningState/succeeded\",\r\n \"level\": \"Info\",\r\n \ + \ \"displayStatus\": \"Provisioning succeeded\",\r\n \ + \ \"time\": \"2018-02-01T05:26:58.4192136+00:00\"\r\n }\r\n\ + \ ]\r\n }\r\n ],\r\n \"extensions\": [\r\n \ + \ {\r\n \"name\": \"AzureEnhancedMonitorForLinux\",\r\n \ + \ \"type\": \"Microsoft.OSTCExtensions.AzureEnhancedMonitorForLinux\",\r\ + \n \"typeHandlerVersion\": \"3.0.1.0\",\r\n \"statuses\"\ + : [\r\n {\r\n \"code\": \"ProvisioningState/succeeded\"\ + ,\r\n \"level\": \"Info\",\r\n \"displayStatus\"\ + : \"Provisioning succeeded\",\r\n \"message\": \"deploymentId=7d8658a5-de26-4c21-ab5f-3c8c7bb539e4\ + \ roleInstance=_vm1 OK\"\r\n }\r\n ]\r\n }\r\n\ + \ ],\r\n \"statuses\": [\r\n {\r\n \"code\": \"\ + ProvisioningState/updating\",\r\n \"level\": \"Info\",\r\n \ + \ \"displayStatus\": \"Updating\"\r\n },\r\n {\r\n \ + \ \"code\": \"PowerState/running\",\r\n \"level\": \"Info\",\r\ + \n \"displayStatus\": \"VM running\"\r\n }\r\n ]\r\n\ + \ }\r\n },\r\n \"resources\": [\r\n {\r\n \"properties\": {\r\ + \n \"publisher\": \"Microsoft.OSTCExtensions\",\r\n \"type\"\ + : \"AzureEnhancedMonitorForLinux\",\r\n \"typeHandlerVersion\": \"\ + 3.0\",\r\n \"autoUpgradeMinorVersion\": true,\r\n \"settings\"\ + : {\"cfg\":[{\"key\":\"wad.isenabled\",\"value\":0},{\"key\":\"osdisk.name\"\ + ,\"value\":\"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"},{\"key\":\"\ + script.version\",\"value\":\"3.0.0.0\"},{\"key\":\"vm.cpu.isovercommitted\"\ + ,\"value\":0},{\"key\":\"osdisk.type\",\"value\":\"Premium\"},{\"key\":\"\ + osdisk.caching\",\"value\":\"ReadWrite\"},{\"key\":\"vm.sla.throughput\",\"\ + value\":48},{\"key\":\"vm.memory.isovercommitted\",\"value\":0},{\"key\":\"\ + osdisk.sla.iops\",\"value\":120},{\"key\":\"vm.sla.iops\",\"value\":3200},{\"\ + key\":\"vmsize\",\"value\":\"Standard_DS1_v2\"},{\"key\":\"href\",\"value\"\ + :\"http://aka.ms/sapaem\"},{\"key\":\"vm.role\",\"value\":\"IaaS\"},{\"key\"\ + :\"verbose\",\"value\":\"0\"},{\"key\":\"osdisk.sla.throughput\",\"value\"\ + :125}]},\r\n \"provisioningState\": \"Deleting\"\r\n },\r\n \ + \ \"type\": \"Microsoft.Compute/virtualMachines/extensions\",\r\n \ + \ \"location\": \"westus\",\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1/extensions/AzureEnhancedMonitorForLinux\"\ + ,\r\n \"name\": \"AzureEnhancedMonitorForLinux\"\r\n }\r\n ],\r\n\ + \ \"type\": \"Microsoft.Compute/virtualMachines\",\r\n \"location\": \"\ + westus\",\r\n \"tags\": {},\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1\"\ + ,\r\n \"name\": \"vm1\"\r\n}"} + headers: + cache-control: [no-cache] + content-length: ['5745'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:31:24 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-resource: ['Microsoft.Compute/LowCostGet3Min;4787,Microsoft.Compute/LowCostGet30Min;38360'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [vm aem verify] + Connection: [keep-alive] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 computemanagementclient/3.1.0rc3 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: GET + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/disks/vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389?api-version=2017-03-30 + response: + body: {string: "{\r\n \"managedBy\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/virtualMachines/vm1\"\ + ,\r\n \"sku\": {\r\n \"name\": \"Premium_LRS\",\r\n \"tier\": \"Premium\"\ + \r\n },\r\n \"properties\": {\r\n \"osType\": \"Linux\",\r\n \"creationData\"\ + : {\r\n \"createOption\": \"FromImage\",\r\n \"imageReference\"\ + : {\r\n \"id\": \"/Subscriptions/00000000-0000-0000-0000-000000000000/Providers/Microsoft.Compute/Locations/westus/Publishers/OpenLogic/ArtifactTypes/VMImage/Offers/CentOS/Skus/7.3/Versions/7.3.20170925\"\ + \r\n }\r\n },\r\n \"diskSizeGB\": 31,\r\n \"timeCreated\": \"\ + 2018-02-01T05:26:57.0127133+00:00\",\r\n \"provisioningState\": \"Succeeded\"\ + ,\r\n \"diskState\": \"Attached\"\r\n },\r\n \"type\": \"Microsoft.Compute/disks\"\ + ,\r\n \"location\": \"westus\",\r\n \"tags\": {},\r\n \"id\": \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/clitest.rg000001/providers/Microsoft.Compute/disks/vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"\ + ,\r\n \"name\": \"vm1_OsDisk_1_ac40b08bb2a04222b4716d16c8250389\"\r\n}"} + headers: + cache-control: [no-cache] + content-length: ['1157'] + content-type: [application/json; charset=utf-8] + date: ['Thu, 01 Feb 2018 05:31:25 GMT'] + expires: ['-1'] + pragma: [no-cache] + server: [Microsoft-HTTPAPI/2.0, Microsoft-HTTPAPI/2.0] + strict-transport-security: [max-age=31536000; includeSubDomains] + transfer-encoding: [chunked] + vary: [Accept-Encoding] + x-ms-ratelimit-remaining-resource: ['Microsoft.Compute/LowCostGet3Min;4996,Microsoft.Compute/LowCostGet30Min;19994'] + status: {code: 200, message: OK} +- request: + body: null + headers: + Accept: [application/json] + Accept-Encoding: ['gzip, deflate'] + CommandName: [group delete] + Connection: [keep-alive] + Content-Length: ['0'] + Content-Type: [application/json; charset=utf-8] + User-Agent: [python/3.5.3 (Windows-10-10.0.16299-SP0) requests/2.17.0 msrest/0.4.23 + msrest_azure/0.4.19 resourcemanagementclient/1.2.1 Azure-SDK-For-Python + AZURECLI/2.0.27] + accept-language: [en-US] + method: DELETE + uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/clitest.rg000001?api-version=2017-05-10 + response: + body: {string: ''} + headers: + cache-control: [no-cache] + content-length: ['0'] + date: ['Thu, 01 Feb 2018 05:31:31 GMT'] + expires: ['-1'] + location: ['https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/operationresults/eyJqb2JJZCI6IlJFU09VUkNFR1JPVVBERUxFVElPTkpPQi1DTElURVNUOjJFUkdOVFJKSFZISEdZTDNJVVZESEJJTVVETEdQQ1VKSkNUQ1lUTnxFMzA3MDFBNzVFQ0NGQTFFLVdFU1RVUyIsImpvYkxvY2F0aW9uIjoid2VzdHVzIn0?api-version=2017-05-10'] + pragma: [no-cache] + strict-transport-security: [max-age=31536000; includeSubDomains] + x-ms-ratelimit-remaining-subscription-writes: ['1199'] + status: {code: 202, message: Accepted} +version: 1 diff --git a/src/aem/aem/tests/test_aem_commands.py b/src/aem/aem/tests/test_aem_commands.py new file mode 100644 index 00000000000..06499e02e5b --- /dev/null +++ b/src/aem/aem/tests/test_aem_commands.py @@ -0,0 +1,18 @@ +# -------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# -------------------------------------------------------------------------------------------- + +from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer) + +class VMAEM(ScenarioTest): + @ResourceGroupPreparer() + def test_vm_aem_configure(self, resource_group): + self.kwargs.update({ + 'vm': 'vm1', + }) + self.cmd('vm create -g {rg} -n {vm} --image centos') + self.cmd('vm aem set -g {rg} -n {vm}') + self.cmd('vm aem verify -g {rg} -n {vm}') + self.cmd('vm aem delete -g {rg} -n {vm}') + self.cmd('vm aem verify -g {rg} -n {vm}', expect_failure=True) diff --git a/src/aem/readme.md b/src/aem/readme.md index 5d23f590872..3f919e3f9a3 100644 --- a/src/aem/readme.md +++ b/src/aem/readme.md @@ -1,7 +1,5 @@ -# Azure CLI Monitoring Extension # -This is an extension to azure cli which provides command to configure, verify and remove . - -The extension simplifies the process and also enables you to save time by copying to multiple regions in parallel. +# Azure CLI Enhanced Monitoring Extension # +This is an extension to azure cli which provides command to configure, verify and remove Azure Enhanced Monitoring Extension for SAP ## How to use ## First, install the extension: @@ -11,12 +9,5 @@ az extension add --name aem Then, call it as you would any other az command: ``` -az image copy --source-resource-group mySources-rg --source-object-name myImage --target-location uksouth northeurope --target-resource-group "images-repo-rg" --cleanup -``` - -One thing you should keep in mind is that we are relying on the source os disk as the actual source for the copy. So, when you "capture" a new image off a vm in Azure, don't delete the os disk if your intention is to copy it to other regions. - -Other options and examples of using the extensions can be viewed with the help command: -``` -az image copy --help +az vm aem set --resource-group rg --name vm1 ``` \ No newline at end of file From f1ca0d1b893d172029e4a2e5095f06b517dc487b Mon Sep 17 00:00:00 2001 From: Yugang Wang Date: Wed, 31 Jan 2018 22:34:19 -0800 Subject: [PATCH 3/9] wip --- src/aem/{aem => azext_aem}/__init__.py | 13 ++++++++++++- src/aem/{aem => azext_aem}/_help.py | 10 +++++----- src/aem/{aem => azext_aem}/azext_metadata.json | 0 src/aem/{aem => azext_aem}/custom.py | 0 src/aem/{aem => azext_aem}/tests/__init__.py | 0 .../recordings/latest/test_vm_aem_configure.yaml | 0 .../{aem => azext_aem}/tests/test_aem_commands.py | 0 src/aem/readme.md | 2 +- 8 files changed, 18 insertions(+), 7 deletions(-) rename src/aem/{aem => azext_aem}/__init__.py (59%) rename src/aem/{aem => azext_aem}/_help.py (85%) rename src/aem/{aem => azext_aem}/azext_metadata.json (100%) rename src/aem/{aem => azext_aem}/custom.py (100%) rename src/aem/{aem => azext_aem}/tests/__init__.py (100%) rename src/aem/{aem => azext_aem}/tests/recordings/latest/test_vm_aem_configure.yaml (100%) rename src/aem/{aem => azext_aem}/tests/test_aem_commands.py (100%) diff --git a/src/aem/aem/__init__.py b/src/aem/azext_aem/__init__.py similarity index 59% rename from src/aem/aem/__init__.py rename to src/aem/azext_aem/__init__.py index 0d5de58439b..c2a5dec0cc2 100644 --- a/src/aem/aem/__init__.py +++ b/src/aem/azext_aem/__init__.py @@ -26,11 +26,22 @@ def load_command_table(self, _): return self.command_table def load_arguments(self, _): + from knack.arguments import CLIArgumentType + from azure.cli.core.commands.parameters import get_resource_name_completion_list + name_arg_type = CLIArgumentType(options_list=['--name', '-n'], metavar='NAME') + existing_vm_name = CLIArgumentType(overrides=name_arg_type, + configured_default='vm', + help="The name of the Virtual Machine. You can configure the default using `az configure --defaults vm=`", + completer=get_resource_name_completion_list('Microsoft.Compute/virtualMachines'), id_part='name') + with self.argument_context('vm aem') as c: + c.argument('vm_name', existing_vm_name) c.argument('skip_storage_check', action='store_true', help='Disables the test for table content') + c.argument('skip_storage_analytics', action='store_true', + help='skip enabling analytics on storage accounts') c.argument('wait_time_in_minutes', type=int, - help='Time that should be waited for the Strorage Metrics or Diagnostics data to be available in minutes') + help='Maximum minutes to wait for the storage metrics to be available') COMMAND_LOADER_CLS = AEMCommandsLoader diff --git a/src/aem/aem/_help.py b/src/aem/azext_aem/_help.py similarity index 85% rename from src/aem/aem/_help.py rename to src/aem/azext_aem/_help.py index edccd4d7af8..31a7a651c9d 100644 --- a/src/aem/aem/_help.py +++ b/src/aem/azext_aem/_help.py @@ -5,22 +5,22 @@ from knack.help_files import helps -helps['aem'] = """ - type: command +helps['vm aem'] = """ + type: group short-summary: Manage Azure Enhanced Monitoring Extension for SAP """ -helps['aem set'] = """ +helps['vm aem set'] = """ type: command short-summary: Configure Azure Enhanced Monitoring Extension """ -helps['aem delete'] = """ +helps['vm aem delete'] = """ type: command short-summary: Remove Azure Enhanced Monitoring Extension """ -helps['aem verify'] = """ +helps['vm aem verify'] = """ type: command short-summary: Verify Azure Enhanced Monitoring Extensions configured correctly """ diff --git a/src/aem/aem/azext_metadata.json b/src/aem/azext_aem/azext_metadata.json similarity index 100% rename from src/aem/aem/azext_metadata.json rename to src/aem/azext_aem/azext_metadata.json diff --git a/src/aem/aem/custom.py b/src/aem/azext_aem/custom.py similarity index 100% rename from src/aem/aem/custom.py rename to src/aem/azext_aem/custom.py diff --git a/src/aem/aem/tests/__init__.py b/src/aem/azext_aem/tests/__init__.py similarity index 100% rename from src/aem/aem/tests/__init__.py rename to src/aem/azext_aem/tests/__init__.py diff --git a/src/aem/aem/tests/recordings/latest/test_vm_aem_configure.yaml b/src/aem/azext_aem/tests/recordings/latest/test_vm_aem_configure.yaml similarity index 100% rename from src/aem/aem/tests/recordings/latest/test_vm_aem_configure.yaml rename to src/aem/azext_aem/tests/recordings/latest/test_vm_aem_configure.yaml diff --git a/src/aem/aem/tests/test_aem_commands.py b/src/aem/azext_aem/tests/test_aem_commands.py similarity index 100% rename from src/aem/aem/tests/test_aem_commands.py rename to src/aem/azext_aem/tests/test_aem_commands.py diff --git a/src/aem/readme.md b/src/aem/readme.md index 3f919e3f9a3..60371a0188f 100644 --- a/src/aem/readme.md +++ b/src/aem/readme.md @@ -1,5 +1,5 @@ # Azure CLI Enhanced Monitoring Extension # -This is an extension to azure cli which provides command to configure, verify and remove Azure Enhanced Monitoring Extension for SAP +This is an extension to azure cli which provides commands to configure, verify and remove Azure Enhanced Monitoring Extension for SAP ## How to use ## First, install the extension: From 79807fe2383d8ba13239468313831db77a29209e Mon Sep 17 00:00:00 2001 From: Yugang Wang Date: Thu, 1 Feb 2018 13:10:42 -0800 Subject: [PATCH 4/9] fix a few lint errors --- src/aem/azext_aem/__init__.py | 1 + src/aem/azext_aem/tests/test_aem_commands.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/aem/azext_aem/__init__.py b/src/aem/azext_aem/__init__.py index c2a5dec0cc2..7aa77fc51e8 100644 --- a/src/aem/azext_aem/__init__.py +++ b/src/aem/azext_aem/__init__.py @@ -26,6 +26,7 @@ def load_command_table(self, _): return self.command_table def load_arguments(self, _): + # pylint: disable=line-too-long from knack.arguments import CLIArgumentType from azure.cli.core.commands.parameters import get_resource_name_completion_list name_arg_type = CLIArgumentType(options_list=['--name', '-n'], metavar='NAME') diff --git a/src/aem/azext_aem/tests/test_aem_commands.py b/src/aem/azext_aem/tests/test_aem_commands.py index 06499e02e5b..ed6d395bea9 100644 --- a/src/aem/azext_aem/tests/test_aem_commands.py +++ b/src/aem/azext_aem/tests/test_aem_commands.py @@ -5,7 +5,9 @@ from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer) +# pylint: disable=unused-argument,too-few-public-methods class VMAEM(ScenarioTest): + @ResourceGroupPreparer() def test_vm_aem_configure(self, resource_group): self.kwargs.update({ @@ -15,4 +17,4 @@ def test_vm_aem_configure(self, resource_group): self.cmd('vm aem set -g {rg} -n {vm}') self.cmd('vm aem verify -g {rg} -n {vm}') self.cmd('vm aem delete -g {rg} -n {vm}') - self.cmd('vm aem verify -g {rg} -n {vm}', expect_failure=True) + self.cmd('vm aem verify -g {rg} -n {vm}') From ac8267a7836f674c08123a7db486dc063b5b4371 Mon Sep 17 00:00:00 2001 From: Yugang Wang Date: Fri, 2 Feb 2018 10:45:31 -0800 Subject: [PATCH 5/9] address review feedback --- src/aem/azext_aem/__init__.py | 2 +- src/aem/azext_aem/custom.py | 28 ++++++++++++++-------------- src/aem/setup.py | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/aem/azext_aem/__init__.py b/src/aem/azext_aem/__init__.py index 7aa77fc51e8..5cdbadbb478 100644 --- a/src/aem/azext_aem/__init__.py +++ b/src/aem/azext_aem/__init__.py @@ -18,7 +18,7 @@ def __init__(self, cli_ctx=None): custom_command_type=aem_custom) def load_command_table(self, _): - with self.command_group('vm aem') as g: + with self.command_group('vm aem', min_api='2016-04-30-preview') as g: g.custom_command('set', 'set_aem') g.custom_command('delete', 'delete_aem') g.custom_command('verify', 'verify_aem') diff --git a/src/aem/azext_aem/custom.py b/src/aem/azext_aem/custom.py index 5c4178e4f27..f92a97f3906 100644 --- a/src/aem/azext_aem/custom.py +++ b/src/aem/azext_aem/custom.py @@ -54,7 +54,6 @@ def __init__(self, cmd, resource_group, vm_name, vm_client, self._resource_group = resource_group self._cmd = cmd self._vm = vm_client.virtual_machines.get(resource_group, vm_name, expand='instanceView') - # TODO: put it under api-version check on 2016-04-30preview+ self._extension = (aem_extension_info['Linux'] if bool(self._vm.os_profile.linux_configuration) else aem_extension_info['Windows']) self._skip_storage_analytics = skip_storage_analytics @@ -63,10 +62,7 @@ def enable(self): pub_cfg, pri_cfg = self._build_extension_cfgs(self._get_disk_info()) VirtualMachineExtension = self._cmd.get_models('VirtualMachineExtension') existing_ext = self._get_aem_extension() - if existing_ext: - extension_instance_name = existing_ext.name - else: - extension_instance_name = self._extension['name'] + extension_instance_name = existing_ext.name if existing_ext else self._extension['name'] existing_ext = VirtualMachineExtension(self._vm.location, publisher=self._extension['publisher'], virtual_machine_extension_type=self._extension['name'], @@ -79,7 +75,8 @@ def enable(self): }, auto_upgrade_minor_version=True) return self._vm_client.virtual_machine_extensions.create_or_update(self._resource_group, self._vm.name, - extension_instance_name, existing_ext) + extension_instance_name, + existing_ext) def delete(self): existing_ext = self._get_aem_extension() @@ -160,8 +157,9 @@ def _build_extension_cfgs(self, disk_info): 'Large': 'Large (A3)', 'ExtraLarge': 'ExtraLarge (A4)' } + vm_size_mapping.get(vm_size, vm_size) pub_cfg.update({ - 'vmsize': vm_size_mapping.get(vm_size, vm_size), + 'vmsize': vm_size, 'vm.role': 'IaaS', 'vm.memory.isovercommitted': 0, 'vm.cpu.isovercommitted': 1 if vm_size == 'ExtraSmall (A0)' else 0, @@ -242,8 +240,8 @@ def _build_extension_cfgs(self, disk_info): for disk in unmanaged_disks: account_name = disk['account_name'] if disk['is_premium']: - logger.info('[INFO] %s is skipped - Storage Account Metrics are not available ' - 'for Premium Type Storage.', disk['name']) + logger.info("'%s' is skipped - Storage Account Metrics are not available " + "for Premium Type Storage.", disk['name']) pub_cfg.update({ account_name + '.hour.ispremium': 1, account_name + '.minute.ispremium': 1, @@ -303,7 +301,7 @@ def _get_disk_info(self): parts = list(filter(None, blob_uri.split('/'))) storage_account_name = parts[1].split('.')[0] disk_name, container_name = parts[-1], parts[-2] - storage_account = [x for x in storage_accounts if x.name.lower() == storage_account_name.lower()][0] + storage_account = next(x for x in storage_accounts if x.name.lower() == storage_account_name.lower()) rg = parse_resource_id(storage_account.id)['resource_group'] key = self._storage_client.storage_accounts.list_keys(rg, storage_account.name).keys[0].value disks_info['os_disk'] = { @@ -324,7 +322,7 @@ def _get_disk_info(self): parts = list(filter(None, blob_uri.split('/'))) storage_account_name = parts[1].split('.')[0] disk_name, container_name = parts[-1], parts[-2] - storage_account = [x for x in storage_accounts if x.name.lower() == storage_account_name.lower()][0] + storage_account = next(x for x in storage_accounts if x.name.lower() == storage_account_name.lower()) rg = parse_resource_id(storage_account.id)['resource_group'] key = self._storage_client.storage_accounts.list_keys(rg, storage_account.name).keys[0].value is_premium = storage_account.sku.tier.value.lower() == 'premium' @@ -345,6 +343,7 @@ def _get_disk_info(self): def _get_blob_size(self, storage_account_name, container, blob, key): storage_client = self._get_storage_client(storage_account_name, key) + # convert to GB return int(storage_client.get_blob_properties(container, blob).properties.content_length / (1 << 30)) def _get_storage_client(self, storage_account_name, key): @@ -380,6 +379,7 @@ def _check_storage_analytics(service_properties): def _check_table_and_content(self, storage_account_name, key, table_name, filter_string, timeout_in_minutes): import time + sleep_period = 15 TableService = get_sdk(self._cmd.cli_ctx, ResourceType.DATA_COSMOS_TABLE, 'table#TableService') table_client = get_data_service_client( self._cmd.cli_ctx, @@ -395,9 +395,9 @@ def _check_table_and_content(self, storage_account_name, key, table_name, if entities.items: return True logger.warning("\t\t\tWait %s seconds for table '%s' has date propagated ...", - 15, table_name) - time.sleep(15) - waited += 15 + sleep_period, table_name) + time.sleep(sleep_period) + waited += sleep_period return False diff --git a/src/aem/setup.py b/src/aem/setup.py index 2e8c5f59c94..a0eb4a5c8fc 100644 --- a/src/aem/setup.py +++ b/src/aem/setup.py @@ -37,6 +37,6 @@ url='https://github.com/Azure/azure-cli-extensions', classifiers=CLASSIFIERS, package_data={'azext_aem': ['azext_metadata.json']}, - packages=find_packages(), + packages=find_packages(exclude=["tests"]), install_requires=DEPENDENCIES ) From 0eef5ae49c801f5c1f13a7cdc325f79cad8b81b4 Mon Sep 17 00:00:00 2001 From: Yugang Wang Date: Fri, 2 Feb 2018 10:53:46 -0800 Subject: [PATCH 6/9] add code owner --- .github/CODEOWNERS | 4 +++- scripts/ci/test_static.sh | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6aa73ed9190..5c81da022d1 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,4 +8,6 @@ /src/eventhubs/ @v-ajnava -/src/webapps/ @panchagnula \ No newline at end of file +/src/webapps/ @panchagnula + +/src/aem/ @yugangw-msft \ No newline at end of file diff --git a/scripts/ci/test_static.sh b/scripts/ci/test_static.sh index affa3023c92..15017299cb8 100755 --- a/scripts/ci/test_static.sh +++ b/scripts/ci/test_static.sh @@ -5,7 +5,7 @@ proc_number=`python -c 'import multiprocessing; print(multiprocessing.cpu_count( # Run pylint/flake8 on extensions # - We ignore 'models', 'operations' and files with suffix '_management_client.py' as they typically come from vendored Azure SDKs -pylint ./src/*/azext_*/ --ignore=models,operations,service_bus_management_client --ignore-patterns=[a-zA-Z_]+_management_client.py --rcfile=./pylintrc -j $proc_number +pylint ./src/*/azext_*/ --ignore=models,operations,service_bus_management_client,msrestazure.tools --ignore-patterns=[a-zA-Z_]+_management_client.py --rcfile=./pylintrc -j $proc_number flake8 --statistics --exclude=models,operations,*_management_client.py --append-config=./.flake8 ./src/*/azext_*/ # Run pylint/flake8 on CI files From 2be45834d1217ceebe559b4aa44bf4992be8e09a Mon Sep 17 00:00:00 2001 From: yugangw-msft Date: Fri, 2 Feb 2018 12:43:06 -0800 Subject: [PATCH 7/9] fix lint error --- src/aem/azext_aem/custom.py | 2 +- src/aem/azext_aem/tests/test_aem_commands.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/aem/azext_aem/custom.py b/src/aem/azext_aem/custom.py index f92a97f3906..e5af39e1e5d 100644 --- a/src/aem/azext_aem/custom.py +++ b/src/aem/azext_aem/custom.py @@ -272,7 +272,7 @@ def _get_aem_extension(self): return existing_ext def _get_disk_info(self): - from msrestazure.tools import parse_resource_id + from msrestazure.tools import parse_resource_id # pylint: disable=import-error disks_info = {} disks_info['managed_disk'] = bool(getattr(self._vm.storage_profile.os_disk, 'managed_disk', None)) if disks_info['managed_disk']: diff --git a/src/aem/azext_aem/tests/test_aem_commands.py b/src/aem/azext_aem/tests/test_aem_commands.py index ed6d395bea9..f2e7fa1f597 100644 --- a/src/aem/azext_aem/tests/test_aem_commands.py +++ b/src/aem/azext_aem/tests/test_aem_commands.py @@ -6,6 +6,8 @@ from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer) # pylint: disable=unused-argument,too-few-public-methods + + class VMAEM(ScenarioTest): @ResourceGroupPreparer() From 1cf713db845e9b921324538b81d59f4a9d574505 Mon Sep 17 00:00:00 2001 From: yugangw-msft Date: Fri, 2 Feb 2018 13:24:10 -0800 Subject: [PATCH 8/9] revert unnecessary script change --- scripts/ci/test_static.sh | 2 +- src/aem/azext_aem/custom.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/ci/test_static.sh b/scripts/ci/test_static.sh index 15017299cb8..affa3023c92 100755 --- a/scripts/ci/test_static.sh +++ b/scripts/ci/test_static.sh @@ -5,7 +5,7 @@ proc_number=`python -c 'import multiprocessing; print(multiprocessing.cpu_count( # Run pylint/flake8 on extensions # - We ignore 'models', 'operations' and files with suffix '_management_client.py' as they typically come from vendored Azure SDKs -pylint ./src/*/azext_*/ --ignore=models,operations,service_bus_management_client,msrestazure.tools --ignore-patterns=[a-zA-Z_]+_management_client.py --rcfile=./pylintrc -j $proc_number +pylint ./src/*/azext_*/ --ignore=models,operations,service_bus_management_client --ignore-patterns=[a-zA-Z_]+_management_client.py --rcfile=./pylintrc -j $proc_number flake8 --statistics --exclude=models,operations,*_management_client.py --append-config=./.flake8 ./src/*/azext_*/ # Run pylint/flake8 on CI files diff --git a/src/aem/azext_aem/custom.py b/src/aem/azext_aem/custom.py index e5af39e1e5d..b59d91d735d 100644 --- a/src/aem/azext_aem/custom.py +++ b/src/aem/azext_aem/custom.py @@ -132,9 +132,10 @@ def verify(self, skip_storage_check, wait_time_in_minutes): logger.error("\t\tStorage Metrics data check '%s': %s", storage_account_name, fail_word) logger.warning('Azure Enhanced Monitoring Extension for SAP public configuration check...') - extected, _ = self._build_extension_cfgs(disk_info) + expected, _ = self._build_extension_cfgs(disk_info) + expected.pop('wad.isenabled') public_cfg = {x['key']: x['value'] for x in self._vm.resources[0].settings['cfg']} - diffs = {k: [extected[k], public_cfg.get(k, None)] for k in extected if extected[k] != public_cfg.get(k, None)} + diffs = {k: [expected[k], public_cfg.get(k, None)] for k in expected if expected[k] != public_cfg.get(k, None)} if diffs: success = False for err in diffs: From f3c712f1f415bebab0127d4d3b8cfaf9b3b23bfb Mon Sep 17 00:00:00 2001 From: yugangw-msft Date: Fri, 2 Feb 2018 14:14:55 -0800 Subject: [PATCH 9/9] fix an incorrect usage of get_models --- src/aem/azext_aem/_help.py | 1 + src/aem/azext_aem/custom.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/aem/azext_aem/_help.py b/src/aem/azext_aem/_help.py index 31a7a651c9d..38c6f74447f 100644 --- a/src/aem/azext_aem/_help.py +++ b/src/aem/azext_aem/_help.py @@ -13,6 +13,7 @@ helps['vm aem set'] = """ type: command short-summary: Configure Azure Enhanced Monitoring Extension + long-summary: It can take up to 15 minutes for the monitoring data to appear in the SAP system """ helps['vm aem delete'] = """ diff --git a/src/aem/azext_aem/custom.py b/src/aem/azext_aem/custom.py index b59d91d735d..091ba5599ab 100644 --- a/src/aem/azext_aem/custom.py +++ b/src/aem/azext_aem/custom.py @@ -60,7 +60,9 @@ def __init__(self, cmd, resource_group, vm_name, vm_client, def enable(self): pub_cfg, pri_cfg = self._build_extension_cfgs(self._get_disk_info()) - VirtualMachineExtension = self._cmd.get_models('VirtualMachineExtension') + VirtualMachineExtension = self._cmd.get_models('VirtualMachineExtension', + resource_type=ResourceType.MGMT_COMPUTE, + operation_group='virtual_machine_extensions') existing_ext = self._get_aem_extension() extension_instance_name = existing_ext.name if existing_ext else self._extension['name'] existing_ext = VirtualMachineExtension(self._vm.location,