Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions scripts/move-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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/

Expand Down
23 changes: 17 additions & 6 deletions src/azure-cli-core/azure/cli/core/commands/arm.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion src/azure-cli-core/azure/cli/core/profiles/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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']
}


Expand Down
20 changes: 18 additions & 2 deletions src/azure-cli-core/azure/cli/core/profiles/_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -105,20 +106,35 @@ 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',
ResourceType.MGMT_RESOURCE_RESOURCES: '2016-02-01',
ResourceType.MGMT_RESOURCE_SUBSCRIPTIONS: '2016-06-01',
ResourceType.DATA_STORAGE: '2015-04-05',
ResourceType.MGMT_NETWORK_DNS: '2016-04-01',
ResourceType.MGMT_AUTHORIZATION: SDKProfile('2015-07-01', {
'classic_administrators': '2015-06-01'
}),
ResourceType.DATA_STORAGE: '2015-04-05',
ResourceType.MGMT_KEYVAULT: '2016-10-01',
ResourceType.DATA_KEYVAULT: '2016-10-01'
},
'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_AUTHORIZATION: SDKProfile('2015-07-01', {
'classic_administrators': '2015-06-01'
}),
ResourceType.DATA_STORAGE: '2017-04-17',
ResourceType.DATA_COSMOS_TABLE: '2017-04-17',
ResourceType.MGMT_KEYVAULT: '2016-10-01',
ResourceType.DATA_KEYVAULT: '2016-10-01'
}
}

Expand Down
20 changes: 20 additions & 0 deletions src/azure-cli-core/azure/cli/core/tests/test_cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1760,9 +1766,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)
Expand All @@ -1771,6 +1780,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)

Expand Down Expand Up @@ -2050,6 +2061,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)
Expand Down