Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add non-premium disk option for repair VM #8486

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
3 changes: 3 additions & 0 deletions src/vm-repair/azext_vm_repair/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
- name: Create a repair VM from a source VM with an encrypted disk. The repair VM is created with the data disk unencrypted and accessible.
text: >
az vm repair create -g MyResourceGroup -n myVM --yes --repair-username <username> --repair-password <password> --unlock-encrypted-vm --encrypt-recovery-key <key>
- name: Create a repair VM with an OS Disk storage type of StandardSSD_LRS.
text: >
az vm repair create -g MyResourceGroup -n myVM --yes --repair-username <username> --repair-password <password> --os-disk-type StandardSSD_LRS
"""

helps['vm repair restore'] = """
Expand Down
1 change: 1 addition & 0 deletions src/vm-repair/azext_vm_repair/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def load_arguments(self, _):
c.argument('distro', help='Option to create repair vm from a specific linux distro (rhel7|rhel8|sles12|sles15|ubuntu20|centos7|centos8|oracle7)')
c.argument('yes', help='Option to skip prompt for associating public ip in no Tty mode')
c.argument('disable_trusted_launch', help='Option to disable Trusted Launch security type on the repair vm by setting the security type to Standard.')
c.argument('os_disk_type', help='Change the OS Disk storage type from the default of PremiumSSD_LRS.')

with self.argument_context('vm repair restore') as c:
c.argument('repair_vm_id', help='Repair VM resource id.')
Expand Down
21 changes: 10 additions & 11 deletions src/vm-repair/azext_vm_repair/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
logger = get_logger(__name__)


def create(cmd, vm_name, resource_group_name, repair_password=None, repair_username=None, repair_vm_name=None, copy_disk_name=None, repair_group_name=None, unlock_encrypted_vm=False, enable_nested=False, associate_public_ip=False, distro='ubuntu', yes=False, encrypt_recovery_key="", disable_trusted_launch=False):
def create(cmd, vm_name, resource_group_name, repair_password=None, repair_username=None, repair_vm_name=None, copy_disk_name=None, repair_group_name=None, unlock_encrypted_vm=False, enable_nested=False, associate_public_ip=False, distro='ubuntu', yes=False, encrypt_recovery_key="", disable_trusted_launch=False, os_disk_type=None):
"""
This function creates a repair VM.

Expand All @@ -75,19 +75,17 @@ def create(cmd, vm_name, resource_group_name, repair_password=None, repair_usern
- distro: The Linux distribution to use for the repair VM. Default is 'ubuntu'.
- yes: If True, confirmation prompts will be skipped. Default is False.
- encrypt_recovery_key: The Bitlocker recovery key to use for encrypting the VM. Default is an empty string.
- disable_trusted_launch: A flag parameter that, when used, sets the security type of the repair VM to Standard.
- disable_trusted_launch: A flag parameter that, when used, sets the security type of the repair VM to Standard.
- os_disk_type: A flag parameter that, when used, sets the OS disk type of the repair VM to the specified type.
"""

# A warning about a future breaking change.
logger.warning('After the November 2024 release, if the image of the source Windows VM is not found, the \'az vm repair create\' command will default to use a 2022-Datacenter image for the repair VM.')

# Logging all the command parameters, except the sensitive data.
# Mask sensitive information
masked_repair_password = '****' if repair_password else None
masked_repair_username = '****' if repair_username else None
masked_repair_encrypt_recovery_key = '****' if encrypt_recovery_key else None
logger.debug('vm repair create command parameters: vm_name: %s, resource_group_name: %s, repair_password: %s, repair_username: %s, repair_vm_name: %s, copy_disk_name: %s, repair_group_name: %s, unlock_encrypted_vm: %s, enable_nested: %s, associate_public_ip: %s, distro: %s, yes: %s, encrypt_recovery_key: %s, disable_trusted_launch: %s',
vm_name, resource_group_name, masked_repair_password, masked_repair_username, repair_vm_name, copy_disk_name, repair_group_name, unlock_encrypted_vm, enable_nested, associate_public_ip, distro, yes, masked_repair_encrypt_recovery_key, disable_trusted_launch)
logger.debug('vm repair create command parameters: vm_name: %s, resource_group_name: %s, repair_password: %s, repair_username: %s, repair_vm_name: %s, copy_disk_name: %s, repair_group_name: %s, unlock_encrypted_vm: %s, enable_nested: %s, associate_public_ip: %s, distro: %s, yes: %s, encrypt_recovery_key: %s, disable_trusted_launch: %s, os_disk_type: %s',
vm_name, resource_group_name, masked_repair_password, masked_repair_username, repair_vm_name, copy_disk_name, repair_group_name, unlock_encrypted_vm, enable_nested, associate_public_ip, distro, yes, masked_repair_encrypt_recovery_key, disable_trusted_launch, os_disk_type)

# Initializing a command helper object.
command = command_helper(logger, cmd, 'vm repair create')
Expand Down Expand Up @@ -205,8 +203,11 @@ def create(cmd, vm_name, resource_group_name, repair_password=None, repair_usern
logger.info('Creating resource group for repair VM and its resources...')
_call_az_command(create_resource_group_command)

# Check if user is changing the Repair VM os disk type
if os_disk_type:
create_repair_vm_command += ' --storage-sku {os_disk_type} '.format(os_disk_type=os_disk_type)

# Check if the source VM uses managed disks.
# Check if the source VM uses managed disks.
# If it does, the repair VM will also be created with managed disks.
if is_managed:
logger.info('Source VM uses managed disks. Creating repair VM with managed disks.\n')
Expand All @@ -218,7 +219,6 @@ def create(cmd, vm_name, resource_group_name, repair_password=None, repair_usern
# The command includes the resource group name, copy disk name, target disk name, SKU, location, and OS type.
copy_disk_command = 'az disk create -g {g} -n {n} --source {s} --sku {sku} --location {loc} --os-type {os_type} --query id -o tsv' \
.format(g=resource_group_name, n=copy_disk_name, s=target_disk_name, sku=disk_sku, loc=location, os_type=os_type)

# If the Hyper-V generation for the disk is available, append it to the copy disk command.
if hyperV_generation:
copy_disk_command += ' --hyper-v-generation {hyperV}'.format(hyperV=hyperV_generation)
Expand All @@ -233,12 +233,11 @@ def create(cmd, vm_name, resource_group_name, repair_password=None, repair_usern
if source_vm.zones:
zone = source_vm.zones[0]
copy_disk_command += ' --zone {zone}'.format(zone=zone)

# Execute the command to create a copy of the OS disk of the source VM.
logger.info('Copying OS disk of source VM...')
copy_disk_id = _call_az_command(copy_disk_command).strip('\n')


# Depending on the operating system of the source VM and whether it's encrypted, different steps are taken.
# If the source VM is not a Linux machine, create the repair VM.
# This is the case for Windows VMs, both encrypted and not encrypted.
Expand Down
1 change: 1 addition & 0 deletions src/vm-repair/azext_vm_repair/repair_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,7 @@ def _unlock_encrypted_vm_run(repair_vm_name, repair_group_name, is_linux, encryp
def _create_repair_vm(copy_disk_id, create_repair_vm_command, repair_password, repair_username, fix_uuid=False):

# logging parameters of the function individually
create_repair_vm_command += ' --storage-sku StandardSSD_LRS '
logger.info('Creating repair VM with command: {}'.format(create_repair_vm_command))
logger.info('copy_disk_id: {}'.format(copy_disk_id))
logger.info('fix_uuid: {}'.format(fix_uuid))
Expand Down
59 changes: 59 additions & 0 deletions src/vm-repair/azext_vm_repair/tests/latest/test_repair_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -1179,3 +1179,62 @@ def test_vmrepair_WinRunRepairVMIdafterRefactor(self, resource_group):

# Call Restore
self.cmd('vm repair restore -g {rg} -n {vm} --yes')

@pytest.mark.NonPremiumOSDisk
class WindowsNonPremiumOSDiskRepairVM(LiveScenarioTest):

@ResourceGroupPreparer(location='westus2')
def test_vmrepair_WinNonPremiumOSDiskRepairVM(self, resource_group):
import uuid
import secrets
import string
base_password = "Passw0rd2024"
guid_suffix = str(uuid.uuid4())
secure_password = base_password + guid_suffix
username_length = 8
secure_username = ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(username_length))
stnd_os_disk_type = "StandardSSD_LRS"
self.kwargs.update({
'vm': 'vm1',
'admin_password': secure_password,
'admin_username': secure_username,
'stnd_os_disk_type': stnd_os_disk_type
})

# Create test VM
self.cmd('vm create -g {rg} -n {vm} --admin-username {admin_username} --admin-password {admin_password} --image MicrosoftWindowsServer:WindowsServer:2022-datacenter-g2:latest')
vms = self.cmd('vm list -g {rg} -o json').get_output_in_json()
# Something wrong with vm create command if it fails here
assert len(vms) == 1

# Create Repair VM
repair_vm = self.cmd('vm repair create -g {rg} -n {vm} --repair-username {admin_username} --repair-password {admin_password} --yes --os-disk-type {stnd_os_disk_type} -o json').get_output_in_json()
assert repair_vm['status'] == STATUS_SUCCESS, repair_vm['error_message']
# Check repair VM
self.kwargs.update({
'vm': 'vm1',
'admin_password': secure_password,
'admin_username': secure_username,
'repair_resource_group': repair_vm['repair_resource_group']
})
repair_vms = self.cmd('vm list -g {repair_resource_group} -o json').get_output_in_json()
assert len(repair_vms) == 1
repair_vm = repair_vms[0]
repair_vm_id = repair_vm['id']
# Verify the image sku is the default sku
os_disk_type = repair_vm['storageProfile']['osDisk']['managedDisk']['storageAccountType']
assert os_disk_type == stnd_os_disk_type, "Os Disk Storage Account Type is not the expected value."

repair_vm_id = repair_vm['id']
self.kwargs.update({
'vm': 'vm1',
'admin_password': secure_password,
'admin_username': secure_username,
'repair_vm_id': repair_vm_id
})
# Run a script for testing repair-vm-id
result_run = self.cmd('vm repair run -g {rg} -n {vm} --run-id win-hello-world --repair-vm-id {repair_vm_id} --run-on-repair -o json').get_output_in_json()
assert result_run['status'] == STATUS_SUCCESS, result_run['error_message']

# Call Restore
self.cmd('vm repair restore -g {rg} -n {vm} --yes')
Loading