Skip to content

Commit

Permalink
disk support uploading with security data
Browse files Browse the repository at this point in the history
  • Loading branch information
zhoxing-ms committed Jun 30, 2022
1 parent c72cdaf commit 7c83910
Show file tree
Hide file tree
Showing 8 changed files with 1,524 additions and 328 deletions.
9 changes: 9 additions & 0 deletions src/azure-cli/azure/cli/command_modules/vm/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@
- name: Create a disk and associate it with a disk access resource.
text: >
az disk create -g MyResourceGroup -n MyDisk --size-gb 10 --network-access-policy AllowPrivate --disk-access MyDiskAccessID
- name: Create a disk from the blob URI for VM guest state VHD.
text: >
az disk create -g MyResourceGroup -n MyDisk --size-gb 10 --security-data-uri GuestStateDiskVhdUri --security-type TrustedLaunch --hyper-v-generation V2
- name: Create a standard disk for uploading blobs.
text: >
az disk create -g MyResourceGroup -n MyDisk --size-gb 10 --upload-type Upload
- name: Create an OS disk for uploading along with VM guest state.
text: >
az disk create -g MyResourceGroup -n MyDisk --size-gb 10 --upload-type UploadWithSecurityData --security-type TrustedLaunch --hyper-v-generation V2
"""

helps['disk delete'] = """
Expand Down
14 changes: 12 additions & 2 deletions src/azure-cli/azure/cli/command_modules/vm/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,6 @@ def load_arguments(self, _):
c.argument('duration_in_seconds', help='Time duration in seconds until the SAS access expires', type=int)
if self.supported_api_version(min_api='2018-09-30', operation_group='disks'):
c.argument('access_level', arg_type=get_enum_type(['Read', 'Write']), default='Read', help='access level')
c.argument('for_upload', arg_type=get_three_state_flag(),
help='Create the {0} for uploading blobs later on through storage commands. Run "az {0} grant-access --access-level Write" to retrieve the {0}\'s SAS token.'.format(scope))
c.argument('hyper_v_generation', arg_type=hyper_v_gen_sku, help='The hypervisor generation of the Virtual Machine. Applicable to OS disks only.')
else:
c.ignore('access_level', 'for_upload', 'hyper_v_generation')
Expand Down Expand Up @@ -197,6 +195,16 @@ def load_arguments(self, _):
c.argument('data_access_auth_mode', arg_type=get_enum_type(['AzureActiveDirectory', 'None']), min_api='2021-12-01', help='Specify the auth mode when exporting or uploading to a disk or snapshot.')
# endregion

# region Disks
with self.argument_context('disk create', resource_type=ResourceType.MGMT_COMPUTE, operation_group='disks') as c:
c.argument('security_data_uri', min_api='2022-03-02', help='Please specify the blob URI of VHD to be imported into VM guest state')
c.argument('for_upload', arg_type=get_three_state_flag(), min_api='2018-09-30',
deprecate_info=c.deprecate(target='--for-upload', redirect='--upload-type Upload', hide=True),
help='Create the disk for uploading blobs. Replaced by "--upload-type Upload"')
c.argument('upload_type', arg_type=get_enum_type(['Upload', 'UploadWithSecurityData']), min_api='2018-09-30',
help="Create the disk for upload scenario. 'Upload' is for Standard disk only upload. 'UploadWithSecurityData' is for OS Disk upload along with VM Guest State. Please note the 'UploadWithSecurityData' is not valid for data disk upload, it only to be used for OS Disk upload at present.")
# endregion

# region Snapshots
with self.argument_context('snapshot', resource_type=ResourceType.MGMT_COMPUTE, operation_group='snapshots') as c:
c.argument('snapshot_name', existing_snapshot_name, id_part='name', completer=get_resource_name_completion_list('Microsoft.Compute/snapshots'))
Expand All @@ -208,6 +216,8 @@ def load_arguments(self, _):
c.argument('copy_start', arg_type=get_three_state_flag(), min_api='2021-04-01',
help='Create snapshot by using a deep copy process, where the resource creation is considered complete only after all data has been copied from the source.')
c.argument('architecture', arg_type=get_enum_type(self.get_models('Architecture', operation_group='snapshots')), min_api='2021-12-01', help='CPU architecture.')
c.argument('for_upload', arg_type=get_three_state_flag(), min_api='2018-09-30',
help='Create the snapshot for uploading blobs later on through storage commands. Run "az snapshot grant-access --access-level Write" to retrieve the snapshot\'s SAS token.')
# endregion

# region Images
Expand Down
35 changes: 35 additions & 0 deletions src/azure-cli/azure/cli/command_modules/vm/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -1755,6 +1755,8 @@ def process_disk_create_namespace(cmd, namespace):
validate_tags(namespace)
validate_edge_zone(cmd, namespace)
_validate_gallery_image_reference(cmd, namespace)
_validate_security_data_uri(namespace)
_validate_upload_type(cmd, namespace)
_validate_secure_vm_disk_encryption_set(namespace)
_validate_hyper_v_generation(namespace)
if namespace.source:
Expand All @@ -1770,6 +1772,39 @@ def process_disk_create_namespace(cmd, namespace):
raise ArgumentUsageError(usage_error)


def _validate_security_data_uri(namespace):
if not namespace.security_data_uri:
return

if not namespace.security_type:
return RequiredArgumentMissingError(
'Please specify --security-type when using the --security-data-uri parameter')

if not namespace.hyper_v_generation or namespace.hyper_v_generation != 'V2':
return ArgumentUsageError(
"Please specify --hyper-v-generation as 'V2' when using the --security-data-uri parameter")


def _validate_upload_type(cmd, namespace):
if not namespace.upload_type and namespace.for_upload:
namespace.upload_type = 'Upload'

if namespace.upload_type == 'UploadWithSecurityData':

if not cmd.supported_api_version(min_api='2021-08-01', operation_group='disks'):
raise ArgumentUsageError(
"'UploadWithSecurityData' is not supported in the current profile. "
"Please upgrade your profile with 'az cloud set --profile newerProfile' and try again")

if not namespace.security_type:
return RequiredArgumentMissingError(
"Please specify --security-type when the value of --upload-type is 'UploadWithSecurityData'")

if not namespace.hyper_v_generation or namespace.hyper_v_generation != 'V2':
return ArgumentUsageError(
"Please specify --hyper-v-generation as 'V2' the value of --upload-type is 'UploadWithSecurityData'")


def _validate_secure_vm_disk_encryption_set(namespace):
if 'secure_vm_disk_encryption_set' not in namespace:
return
Expand Down
47 changes: 35 additions & 12 deletions src/azure-cli/azure/cli/command_modules/vm/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,16 @@ def _get_sku_object(cmd, sku):
return sku


def _grant_access(cmd, resource_group_name, name, duration_in_seconds, is_disk, access_level):
def _grant_access(cmd, resource_group_name, name, duration_in_seconds, is_disk, access_level,
secure_vm_guest_state_sas=None):
AccessLevel, GrantAccessData = cmd.get_models('AccessLevel', 'GrantAccessData')
client = _compute_client_factory(cmd.cli_ctx)
op = client.disks if is_disk else client.snapshots
grant_access_data = GrantAccessData(
access=access_level or AccessLevel.read, duration_in_seconds=duration_in_seconds)
grant_access_data = GrantAccessData(access=access_level or AccessLevel.read,
duration_in_seconds=duration_in_seconds)
if secure_vm_guest_state_sas:
grant_access_data.get_secure_vm_guest_state_sas = secure_vm_guest_state_sas

return op.begin_grant_access(resource_group_name, name, grant_access_data)


Expand Down Expand Up @@ -297,8 +301,9 @@ def create_managed_disk(cmd, resource_group_name, disk_name, location=None, # p
network_access_policy=None, disk_access=None, logical_sector_size=None,
tier=None, enable_bursting=None, edge_zone=None, security_type=None, support_hibernation=None,
public_network_access=None, accelerated_network=None, architecture=None,
data_access_auth_mode=None, gallery_image_reference_type=None,
secure_vm_disk_encryption_set=None):
data_access_auth_mode=None, gallery_image_reference_type=None, security_data_uri=None,
upload_type=None, secure_vm_disk_encryption_set=None):

from msrestazure.tools import resource_id, is_valid_resource_id
from azure.cli.core.commands.client_factory import get_subscription_id

Expand All @@ -312,8 +317,10 @@ def create_managed_disk(cmd, resource_group_name, disk_name, location=None, # p
option = DiskCreateOption.copy
elif source_restore_point:
option = DiskCreateOption.restore
elif for_upload:
elif upload_type == 'Upload':
option = DiskCreateOption.upload
elif upload_type == 'UploadWithSecurityData':
option = DiskCreateOption.upload_prepared_secure
elif image_reference or gallery_image_reference:
option = DiskCreateOption.from_image
else:
Expand All @@ -326,8 +333,9 @@ def create_managed_disk(cmd, resource_group_name, disk_name, location=None, # p
subscription=subscription_id, resource_group=resource_group_name,
namespace='Microsoft.Storage', type='storageAccounts', name=storage_account_name)

if upload_size_bytes is not None and for_upload is not True:
raise CLIError('usage error: --upload-size-bytes should be used together with --for-upload')
if upload_size_bytes is not None and not upload_type:
raise RequiredArgumentMissingError(
'usage error: --upload-size-bytes should be used together with --upload-type')

if image_reference is not None:
if not is_valid_resource_id(image_reference):
Expand Down Expand Up @@ -360,10 +368,16 @@ def create_managed_disk(cmd, resource_group_name, disk_name, location=None, # p
source_resource_id=source_disk or source_snapshot or source_restore_point,
storage_account_id=source_storage_account_id,
upload_size_bytes=upload_size_bytes,
logical_sector_size=logical_sector_size)
logical_sector_size=logical_sector_size,
security_data_uri=security_data_uri)

if size_gb is None and upload_size_bytes is None and (option == DiskCreateOption.empty or for_upload):
raise CLIError('usage error: --size-gb or --upload-size-bytes required to create an empty disk')
if size_gb is None and upload_size_bytes is None:
if option == DiskCreateOption.empty:
raise RequiredArgumentMissingError(
'usage error: --size-gb or --upload-size-bytes required to create an empty disk')
if upload_type:
raise RequiredArgumentMissingError(
'usage error: --size-gb or --upload-size-bytes required to create a disk for upload')

if disk_encryption_set is not None and not is_valid_resource_id(disk_encryption_set):
disk_encryption_set = resource_id(
Expand Down Expand Up @@ -436,8 +450,17 @@ def create_managed_disk(cmd, resource_group_name, disk_name, location=None, # p


def grant_disk_access(cmd, resource_group_name, disk_name, duration_in_seconds, access_level=None):

secure_vm_guest_state_sas = None
if cmd.supported_api_version(min_api='2021-08-01', operation_group='disks'):
compute_client = _compute_client_factory(cmd.cli_ctx)
disk_info = compute_client.disks.get(resource_group_name, disk_name)
DiskCreateOption = cmd.get_models('DiskCreateOption', operation_group='disks')
if disk_info.creation_data and disk_info.creation_data.create_option == DiskCreateOption.upload_prepared_secure:
secure_vm_guest_state_sas = True

return _grant_access(cmd, resource_group_name, disk_name, duration_in_seconds, is_disk=True,
access_level=access_level)
access_level=access_level, secure_vm_guest_state_sas=secure_vm_guest_state_sas)


def list_managed_disks(cmd, resource_group_name=None):
Expand Down
Loading

0 comments on commit 7c83910

Please sign in to comment.