Skip to content

Commit 7663528

Browse files
{Compute} az vm secret: Migrate command group to aaz-based implementation (#32626)
1 parent 25fb061 commit 7663528

4 files changed

Lines changed: 1068 additions & 817 deletions

File tree

src/azure-cli/azure/cli/command_modules/vm/custom.py

Lines changed: 88 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,12 +1419,12 @@ def get_vm_to_update_by_aaz(cmd, resource_group_name, vm_name):
14191419
from .operations.vm import VMShow
14201420

14211421
vm = VMShow(cli_ctx=cmd.cli_ctx)(command_args={
1422-
'resource_group': resource_group_name,
1422+
"resource_group": resource_group_name,
14231423
"vm_name": vm_name
14241424
})
14251425

14261426
# To avoid unnecessary permission check of image
1427-
storage_profile = vm.get('storageProfile', {})
1427+
storage_profile = vm.get("storageProfile", {})
14281428
storage_profile["imageReference"] = None
14291429

14301430
return vm
@@ -1739,6 +1739,40 @@ def set_vm(cmd, instance, lro_operation=None, no_wait=False):
17391739
return LongRunningOperation(cmd.cli_ctx)(poller)
17401740

17411741

1742+
# Notes: vm format is in snake_case
1743+
def set_vm_by_aaz(cmd, vm, no_wait=False):
1744+
from .aaz.latest.vm import Create as _VMCreate
1745+
1746+
parsed_id = _parse_rg_name(vm["id"])
1747+
vm["resource_group"] = parsed_id[0]
1748+
vm["vm_name"] = parsed_id[1]
1749+
vm["no_wait"] = no_wait
1750+
1751+
class SetVM(_VMCreate):
1752+
def _output(self, *args, **kwargs):
1753+
from azure.cli.core.aaz import AAZUndefined, has_value
1754+
1755+
# Resolve flatten conflict
1756+
# When the type field conflicts, the type in inner layer is ignored and the outer layer is applied
1757+
if has_value(self.ctx.vars.instance.resources):
1758+
for resource in self.ctx.vars.instance.resources:
1759+
if has_value(resource.type):
1760+
resource.type = AAZUndefined
1761+
1762+
result = self.deserialize_output(self.ctx.vars.instance, client_flatten=True)
1763+
if result.get('osProfile', {}).get('secrets', []):
1764+
for secret in result['osProfile']['secrets']:
1765+
for cert in secret.get('vaultCertificates', []):
1766+
if not cert.get('certificateStore'):
1767+
cert['certificateStore'] = None
1768+
return result
1769+
1770+
vm = LongRunningOperation(cmd.cli_ctx)(
1771+
SetVM(cli_ctx=cmd.cli_ctx)(command_args=vm))
1772+
1773+
return vm
1774+
1775+
17421776
def patch_vm(cmd, resource_group_name, vm_name, vm):
17431777
client = _compute_client_factory(cmd.cli_ctx)
17441778
poller = client.virtual_machines.begin_update(resource_group_name, vm_name, vm)
@@ -3288,51 +3322,75 @@ def get_vm_format_secret(cmd, secrets, certificate_store=None, keyvault=None, re
32883322
def add_vm_secret(cmd, resource_group_name, vm_name, keyvault, certificate, certificate_store=None):
32893323
from azure.mgmt.core.tools import parse_resource_id
32903324
from ._vm_utils import create_data_plane_keyvault_certificate_client, get_key_vault_base_url
3291-
VaultSecretGroup, SubResource, VaultCertificate = cmd.get_models(
3292-
'VaultSecretGroup', 'SubResource', 'VaultCertificate')
3293-
vm = get_vm_to_update(cmd, resource_group_name, vm_name)
3325+
from .operations.vm import convert_show_result_to_snake_case
3326+
vm = get_vm_to_update_by_aaz(cmd, resource_group_name, vm_name)
3327+
vm = convert_show_result_to_snake_case(vm)
32943328

32953329
if '://' not in certificate: # has a cert name rather a full url?
32963330
keyvault_client = create_data_plane_keyvault_certificate_client(
32973331
cmd.cli_ctx, get_key_vault_base_url(cmd.cli_ctx, parse_resource_id(keyvault)['name']))
32983332
cert_info = keyvault_client.get_certificate(certificate)
32993333
certificate = cert_info.secret_id
33003334

3301-
if not _is_linux_os(vm):
3335+
if not _is_linux_os_by_aaz(vm):
33023336
certificate_store = certificate_store or 'My'
33033337
elif certificate_store:
33043338
raise CLIError('Usage error: --certificate-store is only applicable on Windows VM')
3305-
vault_cert = VaultCertificate(certificate_url=certificate, certificate_store=certificate_store)
3306-
vault_secret_group = next((x for x in vm.os_profile.secrets
3307-
if x.source_vault and x.source_vault.id.lower() == keyvault.lower()), None)
3339+
vault_cert = {
3340+
'certificate_store': certificate_store,
3341+
'certificate_url': certificate
3342+
}
3343+
vault_secret_group = next((x for x in vm.get('os_profile', {}).get('secrets', [])
3344+
if x.get('source_vault', {}).get('id', '').lower() == keyvault.lower()), None)
33083345
if vault_secret_group:
3309-
vault_secret_group.vault_certificates.append(vault_cert)
3346+
certs = vault_secret_group.get('vault_certificates', [])
3347+
certs.append(vault_cert)
3348+
vault_secret_group['vault_certificates'] = certs
33103349
else:
3311-
vault_secret_group = VaultSecretGroup(source_vault=SubResource(id=keyvault), vault_certificates=[vault_cert])
3312-
vm.os_profile.secrets.append(vault_secret_group)
3313-
vm = set_vm(cmd, vm)
3314-
return vm.os_profile.secrets
3350+
vault_secret_group = {
3351+
'source_vault': {
3352+
'id': keyvault
3353+
},
3354+
'vault_certificates': [vault_cert]
3355+
}
3356+
3357+
if not vm.get('os_profile'):
3358+
vm['os_profile'] = {'secret': []}
3359+
3360+
if not vm.get('os_profile').get('secrets'):
3361+
vm['os_profile']['secrets'] = []
3362+
3363+
vm['os_profile']['secrets'].append(vault_secret_group)
3364+
3365+
vm = set_vm_by_aaz(cmd, vm)
3366+
return vm.get('osProfile', {}).get('secrets', [])
33153367

33163368

33173369
def list_vm_secrets(cmd, resource_group_name, vm_name):
3318-
vm = get_vm(cmd, resource_group_name, vm_name)
3319-
if vm.os_profile:
3320-
return vm.os_profile.secrets
3321-
return []
3370+
vm = get_vm_by_aaz(cmd, resource_group_name, vm_name)
3371+
3372+
if vm.get('osProfile', {}).get('secrets', []):
3373+
for secret in vm['osProfile']['secrets']:
3374+
for cert in secret.get('vaultCertificates', []):
3375+
if not cert.get('certificateStore'):
3376+
cert['certificateStore'] = None
3377+
3378+
return vm.get('osProfile', {}).get('secrets', [])
33223379

33233380

33243381
def remove_vm_secret(cmd, resource_group_name, vm_name, keyvault, certificate=None):
3325-
vm = get_vm_to_update(cmd, resource_group_name, vm_name)
3382+
from .operations.vm import convert_show_result_to_snake_case
3383+
vm = get_vm_to_update_by_aaz(cmd, resource_group_name, vm_name)
33263384

33273385
# support 2 kinds of filter:
33283386
# a. if only keyvault is supplied, we delete its whole vault group.
33293387
# b. if both keyvault and certificate are supplied, we only delete the specific cert entry.
33303388

3331-
to_keep = vm.os_profile.secrets
3389+
to_keep = vm.get('osProfile', {}).get('secrets', [])
33323390
keyvault_matched = []
33333391
if keyvault:
33343392
keyvault = keyvault.lower()
3335-
keyvault_matched = [x for x in to_keep if x.source_vault and x.source_vault.id.lower() == keyvault]
3393+
keyvault_matched = [x for x in to_keep if x.get('sourceVault', {}).get('id', '').lower() == keyvault]
33363394

33373395
if keyvault and not certificate:
33383396
to_keep = [x for x in to_keep if x not in keyvault_matched]
@@ -3342,13 +3400,15 @@ def remove_vm_secret(cmd, resource_group_name, vm_name, keyvault, certificate=No
33423400
if '://' not in cert_url_pattern: # just a cert name?
33433401
cert_url_pattern = '/' + cert_url_pattern + '/'
33443402
for x in temp:
3345-
x.vault_certificates = ([v for v in x.vault_certificates
3346-
if not (v.certificate_url and cert_url_pattern in v.certificate_url.lower())])
3347-
to_keep = [x for x in to_keep if x.vault_certificates] # purge all groups w/o any cert entries
3348-
3349-
vm.os_profile.secrets = to_keep
3350-
vm = set_vm(cmd, vm)
3351-
return vm.os_profile.secrets
3403+
x['vaultCertificates'] = [v for v in x.get('vaultCertificates')
3404+
if not (v.get('certificateUrl') and
3405+
cert_url_pattern in v.get('certificateUrl', '').lower())]
3406+
to_keep = [x for x in to_keep if x.get('vaultCertificates')] # purge all groups w/o any cert entries
3407+
3408+
vm['osProfile']['secrets'] = to_keep
3409+
vm = convert_show_result_to_snake_case(vm)
3410+
vm = set_vm_by_aaz(cmd, vm)
3411+
return vm.get('osProfile', {}).get('secrets', [])
33523412
# endregion
33533413

33543414

src/azure-cli/azure/cli/command_modules/vm/operations/vm.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ def __call__(self, *args, **kwargs):
262262

263263
def convert_show_result_to_snake_case(result):
264264
new_result = {}
265+
if "id" in result:
266+
new_result["id"] = result["id"]
265267
if "extendedLocation" in result:
266268
new_result["extended_location"] = result["extendedLocation"]
267269
if "identity" in result:

0 commit comments

Comments
 (0)