From 4ee40ba99aa0f156f17a5f007cce738c26fa6079 Mon Sep 17 00:00:00 2001 From: Vishnu Priya Ananthu Sundaram Date: Fri, 3 Aug 2018 10:25:16 -0700 Subject: [PATCH 1/2] Initial Checkin for Hybrid profile from Bala --- scripts/move-tests.sh | 8 ++++++++ .../azure/cli/core/profiles/__init__.py | 3 ++- .../azure/cli/core/profiles/_shared.py | 18 ++++++++++++++++- .../azure/cli/core/tests/test_cloud.py | 20 +++++++++++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/scripts/move-tests.sh b/scripts/move-tests.sh index 272d07f2561..88a46bb1b1a 100755 --- a/scripts/move-tests.sh +++ b/scripts/move-tests.sh @@ -13,6 +13,14 @@ for test_folder in `find src/command_modules -name tests`; do cp -r $t/recordings/2017-03-09-profile/* $test_folder/profile_2017_03_09/recordings/ fi + if [ -d $t/recordings/2018-03-01-hybrid ]; then + mkdir -p $test_folder/hybrid_2018_03_01 + cp -r $t/* $test_folder/hybrid_2018_03_01 + rm -r $test_folder/hybrid_2018_03_01/recordings + mkdir -p $test_folder/hybrid_2018_03_01/recordings + cp -r $t/recordings/2018-03-01-hybrid/* $test_folder/hybrid_2018_03_01/recordings/ + fi + mkdir -p $test_folder/latest cp -r $t/* $test_folder/latest/ diff --git a/src/azure-cli-core/azure/cli/core/profiles/__init__.py b/src/azure-cli-core/azure/cli/core/profiles/__init__.py index 9aadd655d3d..98831b7bd70 100644 --- a/src/azure-cli-core/azure/cli/core/profiles/__init__.py +++ b/src/azure-cli-core/azure/cli/core/profiles/__init__.py @@ -87,7 +87,8 @@ def get_sdk(cli_ctx, resource_type, *attr_args, **kwargs): # API Profiles currently supported in the CLI. API_PROFILES = { 'latest': AZURE_API_PROFILES['latest'], - '2017-03-09-profile': AZURE_API_PROFILES['2017-03-09-profile'] + '2017-03-09-profile': AZURE_API_PROFILES['2017-03-09-profile'], + '2018-03-01-hybrid': AZURE_API_PROFILES['2018-03-01-hybrid'] } diff --git a/src/azure-cli-core/azure/cli/core/profiles/_shared.py b/src/azure-cli-core/azure/cli/core/profiles/_shared.py index d77795f6d0f..114300d75b5 100644 --- a/src/azure-cli-core/azure/cli/core/profiles/_shared.py +++ b/src/azure-cli-core/azure/cli/core/profiles/_shared.py @@ -42,6 +42,7 @@ class ResourceType(Enum): # pylint: disable=too-few-public-methods MGMT_RESOURCE_LINKS = ('azure.mgmt.resource.links', 'ManagementLinkClient') MGMT_RESOURCE_LOCKS = ('azure.mgmt.resource.locks', 'ManagementLockClient') MGMT_RESOURCE_POLICY = ('azure.mgmt.resource.policy', 'PolicyClient') + MGMT_KEYVAULT = ('azure.mgmt.keyvault', 'KeyVaultManagementClient') MGMT_RESOURCE_RESOURCES = ('azure.mgmt.resource.resources', 'ResourceManagementClient') MGMT_RESOURCE_SUBSCRIPTIONS = ('azure.mgmt.resource.subscriptions', 'SubscriptionClient') DATA_KEYVAULT = ('azure.keyvault', 'KeyVaultClient') @@ -103,7 +104,6 @@ def default_api_version(self): ResourceType.MGMT_STORAGE: '2016-01-01', ResourceType.MGMT_NETWORK: '2015-06-15', ResourceType.MGMT_COMPUTE: SDKProfile('2016-03-30'), - ResourceType.MGMT_RESOURCE_FEATURES: '2015-12-01', ResourceType.MGMT_RESOURCE_LINKS: '2016-09-01', ResourceType.MGMT_RESOURCE_LOCKS: '2015-01-01', ResourceType.MGMT_RESOURCE_POLICY: '2015-10-01-preview', @@ -115,6 +115,22 @@ def default_api_version(self): 'classic_administrators': '2015-06-01' }), ResourceType.DATA_STORAGE: '2015-04-05' + }, + '2018-03-01-hybrid': { + ResourceType.MGMT_STORAGE: '2016-01-01', + ResourceType.MGMT_NETWORK: '2017-10-01', + ResourceType.MGMT_COMPUTE: SDKProfile('2017-03-30'), + ResourceType.MGMT_RESOURCE_LINKS: '2018-02-01', + ResourceType.MGMT_RESOURCE_LOCKS: '2016-09-01', + ResourceType.MGMT_RESOURCE_POLICY: '2016-12-01', + ResourceType.MGMT_RESOURCE_RESOURCES: '2018-02-01', + ResourceType.MGMT_RESOURCE_SUBSCRIPTIONS: '2016-06-01', + ResourceType.MGMT_KEYVAULT: '2016-10-01', + ResourceType.MGMT_AUTHORIZATION: SDKProfile('2015-07-01', { + 'classic_administrators': '2015-06-01' + }), + ResourceType.DATA_STORAGE: '2017-04-17', + ResourceType.DATA_COSMOS_TABLE: '2017-04-17' } } diff --git a/src/azure-cli-core/azure/cli/core/tests/test_cloud.py b/src/azure-cli-core/azure/cli/core/tests/test_cloud.py index 810a5d23cb3..0c8be237bca 100644 --- a/src/azure-cli-core/azure/cli/core/tests/test_cloud.py +++ b/src/azure-cli-core/azure/cli/core/tests/test_cloud.py @@ -100,6 +100,26 @@ def test_add_get_cloud_with_profile(self): self.assertEqual(custom_clouds[0].endpoints.resource_manager, c.endpoints.resource_manager) self.assertEqual(custom_clouds[0].profile, c.profile) +def test_add_get_cloud_with_hybrid_profile(self): + cli = TestCli() + endpoint_rm = 'http://management.contoso.com' + endpoints = CloudEndpoints(resource_manager=endpoint_rm) + profile = '2018-03-01-hybrid' + c = Cloud('MyOwnCloud', endpoints=endpoints, profile=profile) + with mock.patch('azure.cli.core.cloud.CLOUD_CONFIG_FILE', tempfile.mkstemp()[1]) as\ + config_file: + add_cloud(cli, c) + config = cli.config.config_parser + config.read(config_file) + self.assertTrue(c.name in config.sections()) + self.assertEqual(config.get(c.name, 'endpoint_resource_manager'), endpoint_rm) + self.assertEqual(config.get(c.name, 'profile'), profile) + custom_clouds = get_custom_clouds(cli) + self.assertEqual(len(custom_clouds), 1) + self.assertEqual(custom_clouds[0].name, c.name) + self.assertEqual(custom_clouds[0].endpoints.resource_manager, c.endpoints.resource_manager) + self.assertEqual(custom_clouds[0].profile, c.profile) + def test_add_get_cloud_with_invalid_profile(self): # Cloud has profile that doesn't exist so an exception should be raised cli = DummyCli() From e6429975224b1264b801456fec1662eb0d6cc221 Mon Sep 17 00:00:00 2001 From: Vishnu Priya Ananthu Sundaram Date: Fri, 3 Aug 2018 11:46:09 -0700 Subject: [PATCH 2/2] Updates for Vm module to work against 2018-03-01-hybrid profile --- .../azure/cli/core/commands/arm.py | 23 ++++++++++++----- .../cli/command_modules/vm/_validators.py | 2 ++ .../azure/cli/command_modules/vm/custom.py | 25 ++++++++++++++----- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/azure-cli-core/azure/cli/core/commands/arm.py b/src/azure-cli-core/azure/cli/core/commands/arm.py index 966cac15fc2..a7073b6700c 100644 --- a/src/azure-cli-core/azure/cli/core/commands/arm.py +++ b/src/azure-cli-core/azure/cli/core/commands/arm.py @@ -989,6 +989,7 @@ def _find_property(instance, path): def assign_identity(cli_ctx, getter, setter, identity_role=None, identity_scope=None): import time from msrestazure.azure_exceptions import CloudError + from azure.cli.core.profiles import get_api_version # get resource = getter() @@ -997,21 +998,31 @@ def assign_identity(cli_ctx, getter, setter, identity_role=None, identity_scope= # create role assignment: if identity_scope: principal_id = resource.identity.principal_id + version = getattr(get_api_version(cli_ctx, ResourceType.MGMT_AUTHORIZATION), 'role_assignments') identity_role_id = resolve_role_id(cli_ctx, identity_role, identity_scope) - assignments_client = get_mgmt_service_client(cli_ctx, ResourceType.MGMT_AUTHORIZATION).role_assignments - RoleAssignmentCreateParameters = get_sdk(cli_ctx, ResourceType.MGMT_AUTHORIZATION, - 'RoleAssignmentCreateParameters', mod='models', - operation_group='role_assignments') + RoleAssignmentCreateParameters, RoleAssignmentProperties = get_sdk(cli_ctx, ResourceType.MGMT_AUTHORIZATION, + 'RoleAssignmentCreateParameters', + 'RoleAssignmentProperties', mod='models', + operation_group='role_assignments') + parameters = RoleAssignmentCreateParameters(role_definition_id=identity_role_id, principal_id=principal_id) + assignments_client = get_mgmt_service_client(cli_ctx, ResourceType.MGMT_AUTHORIZATION).role_assignments logger.info("Creating an assignment with a role '%s' on the scope of '%s'", identity_role_id, identity_scope) retry_times = 36 assignment_name = _gen_guid() for l in range(0, retry_times): try: - assignments_client.create(scope=identity_scope, role_assignment_name=assignment_name, - parameters=parameters) + if version == '2015-07-01': + properties = RoleAssignmentProperties(role_definition_id=identity_role_id, + principal_id=principal_id) + assignments_client = assignments_client.create(scope=identity_scope, + role_assignment_name=assignment_name, + properties=properties) + else: + assignments_client.create(scope=identity_scope, role_assignment_name=assignment_name, + parameters=parameters) break except CloudError as ex: if 'role assignment already exists' in ex.message: diff --git a/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py b/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py index 79d5bf54447..f9757b1ff85 100644 --- a/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py +++ b/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/_validators.py @@ -303,6 +303,8 @@ def _validate_location(cmd, namespace, zone_info, size_info): if zone_info: sku_infos = list_sku_info(cmd.cli_ctx, namespace.location) temp = next((x for x in sku_infos if x.name.lower() == size_info.lower()), None) + if not hasattr(temp, 'location_info'): + return if not temp or not [x for x in (temp.location_info or []) if x.zones]: raise CLIError("{}'s location can't be used to create the VM/VMSS because availablity zone is not yet " "supported. Please use '--location' to specify a capable one. 'az vm list-skus' can be " diff --git a/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/custom.py b/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/custom.py index 94a2e0d8cf8..6b92e99ff71 100644 --- a/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/custom.py +++ b/src/command_modules/azure-cli-vm/azure/cli/command_modules/vm/custom.py @@ -450,12 +450,16 @@ def setter(vm, external_identities=external_identities): for identity in external_identities: vm.identity.user_assigned_identities[identity] = VirtualMachineIdentityUserAssignedIdentitiesValue() - vm_patch = VirtualMachineUpdate() - vm_patch.identity = vm.identity - return patch_vm(cmd, resource_group_name, vm_name, vm_patch) + if VirtualMachineUpdate: + vm_patch = VirtualMachineUpdate() + vm_patch.identity = vm.identity + return patch_vm(cmd, resource_group_name, vm_name, vm_patch) + return set_vm(cmd, vm) assign_identity_helper(cmd.cli_ctx, getter, setter, identity_role=identity_role_id, identity_scope=identity_scope) vm = client.virtual_machines.get(resource_group_name, vm_name) + if not hasattr(vm.identity, 'user_assigned_identities'): + vm.identity.user_assigned_identities = None return _construct_identity_info(identity_scope, identity_role, vm.identity.principal_id, vm.identity.user_assigned_identities) @@ -665,6 +669,8 @@ def create_vm(cmd, vm_name, resource_group_name, image=None, size='Standard_DS1_ if assign_identity is not None: if enable_local_identity and not identity_scope: _show_missing_access_warning(resource_group_name, vm_name, 'vm') + if not hasattr(vm.identity, 'user_assigned_identities'): + vm.identity.user_assigned_identities = None setattr(vm, 'identity', _construct_identity_info(identity_scope, identity_role, vm.identity.principal_id, vm.identity.user_assigned_identities)) return vm @@ -1750,9 +1756,12 @@ def setter(vmss, external_identities=external_identities): vmss.identity.user_assigned_identities = {} for identity in external_identities: vmss.identity.user_assigned_identities[identity] = IdentityUserAssignedIdentitiesValue() - vmss_patch = VirtualMachineScaleSetUpdate() - vmss_patch.identity = vmss.identity - poller = client.virtual_machine_scale_sets.update(resource_group_name, vmss_name, vmss_patch) + if VirtualMachineScaleSetUpdate: + vmss_patch = VirtualMachineScaleSetUpdate() + vmss_patch.identity = vmss.identity + poller = client.virtual_machine_scale_sets.update(resource_group_name, vmss_name, vmss_patch) + else: + poller = client.virtual_machine_scale_sets.create_or_update(resource_group_name, vmss_name, vmss) return LongRunningOperation(cmd.cli_ctx)(poller) assign_identity_helper(cmd.cli_ctx, getter, setter, identity_role=identity_role_id, identity_scope=identity_scope) @@ -1761,6 +1770,8 @@ def setter(vmss, external_identities=external_identities): logger.warning("With manual upgrade mode, you will need to run 'az vmss update-instances -g %s -n %s " "--instance-ids *' to propagate the change", resource_group_name, vmss_name) + if not hasattr(vmss.identity, 'user_assigned_identities'): + vmss.identity.user_assigned_identities = None return _construct_identity_info(identity_scope, identity_role, vmss.identity.principal_id, vmss.identity.user_assigned_identities) @@ -2040,6 +2051,8 @@ def _get_public_ip_address_allocation(value, sku): vmss_info = get_vmss(cmd, resource_group_name, vmss_name) if enable_local_identity and not identity_scope: _show_missing_access_warning(resource_group_name, vmss_name, 'vmss') + if not hasattr(vmss_info.identity, 'user_assigned_identities'): + vmss_info.identity.user_assigned_identities = None deployment_result['vmss']['identity'] = _construct_identity_info(identity_scope, identity_role, vmss_info.identity.principal_id, vmss_info.identity.user_assigned_identities)