def test_disable_encryption_error_cases_handling(self, mock_compute_client_factory, mock_vm_set):  # pylint: disable=unused-argument
        os_disk = OSDisk(None, OperatingSystemTypes.linux)
        existing_disk = DataDisk(lun=1, vhd='https://someuri', name='d1', create_option=DiskCreateOptionTypes.empty)
        vm = FakedVM(None, [existing_disk], os_disk=os_disk)
        vm_extension = VirtualMachineExtension('westus',
                                               settings={'SequenceVersion': 1},
                                               instance_view=VirtualMachineExtensionInstanceView(
                                                   statuses=[InstanceViewStatus(message='Encryption completed successfully')],
                                                   substatuses=[InstanceViewStatus(message='{"os":"Encrypted"}')]))
        vm_extension.provisioning_state = 'Succeeded'
        compute_client_mock = mock.MagicMock()
        compute_client_mock.virtual_machines.get.return_value = vm
        compute_client_mock.virtual_machine_extensions.get.return_value = vm_extension
        mock_compute_client_factory.return_value = compute_client_mock

        # throw on disabling encryption on OS disk of a linux VM
        with self.assertRaises(CLIError) as context:
            disable('rg1', 'vm1', 'OS')

        self.assertTrue("Only data disk is supported to disable on Linux VM" in str(context.exception))

        # throw on disabling encryption on data disk, but os disk is also encrypted
        with self.assertRaises(CLIError) as context:
            disable('rg1', 'vm1', 'DATA')

        self.assertTrue("Disabling encryption on data disk can render the VM unbootable" in str(context.exception))

        # works fine to disable encryption on daat disk when OS disk is never encrypted
        vm_extension.instance_view.substatuses[0].message = '{}'
        disable('rg1', 'vm1', 'DATA')
Example #2
0
    def image_vm(self, vm):
        group = parse_resource_id(vm.id)["resource_group"]
        tokens = self.freta.image.upload_sas(vm.name, "lime", "eastus")

        settings = {
            "fileUris": [
                "https://github.com/microsoft/avml/releases/download/v0.2.0/avml"
            ]
        }

        cmd = (
            "./avml --sas_block_size 20 --delete --compress --sas_url '%s' /root/image.lime.%f"
            % (tokens["image"]["sas_url"], time.time()))
        protected_settings = {"commandToExecute": cmd}

        version = self.get_extension_version(vm)

        extension = VirtualMachineExtension(
            location=vm.location,
            publisher=self.publisher,
            virtual_machine_extension_type=self.extension,
            settings=settings,
            protected_settings=protected_settings,
            type_handler_version=version,
            auto_upgrade_minor_version=False,
        )

        poller = self.az.virtual_machine_extensions.create_or_update(
            group, vm.name, self.extension, extension)
        print("imaging: {} ({})".format(repr(vm.name), tokens["image_id"]))
        return (tokens["image_id"], poller)
Example #3
0
def set_extension(
        resource_group_name, vm_name, vm_extension_name, publisher,
        version=None, settings=None,
        protected_settings=None, no_auto_upgrade=False):
    '''create/update extensions for a VM in a resource group. You can use
    'extension image list' to get extension details
    :param vm_extension_name: the name of the extension
    :param publisher: the name of extension publisher
    :param version: the version of extension.
    :param settings: public settings or a file path with such contents
    :param protected_settings: protected settings or a file path with such contents
    :param no_auto_upgrade: by doing this, extension system will not pick the highest minor version
    for the specified version number, and will not auto update to the latest build/revision number
    on any VM updates in future.
    '''
    vm = _vm_get(resource_group_name, vm_name)
    client = _compute_client_factory()

    from azure.mgmt.compute.models import VirtualMachineExtension

    protected_settings = load_json(protected_settings) if protected_settings else {}
    settings = load_json(settings) if settings else None

    #pylint: disable=no-member
    version = _normalize_extension_version(publisher, vm_extension_name, version, vm.location)

    ext = VirtualMachineExtension(vm.location,
                                  publisher=publisher,
                                  virtual_machine_extension_type=vm_extension_name,
                                  protected_settings=protected_settings,
                                  type_handler_version=version,
                                  settings=settings,
                                  auto_upgrade_minor_version=(not no_auto_upgrade))
    return client.virtual_machine_extensions.create_or_update(
        resource_group_name, vm_name, vm_extension_name, ext)
Example #4
0
def reset_windows_admin(
        resource_group_name, vm_name, username, password):
    '''Update the password.
    You can only change the password. Adding a new user is not supported.
    '''
    vm = _vm_get(resource_group_name, vm_name, 'instanceView')

    client = _compute_client_factory()

    from azure.mgmt.compute.models import VirtualMachineExtension

    extension_name = _WINDOWS_ACCESS_EXT
    publisher, version, auto_upgrade = _get_access_extension_upgrade_info(
        vm.resources, extension_name)

    ext = VirtualMachineExtension(vm.location,#pylint: disable=no-member
                                  publisher=publisher,
                                  virtual_machine_extension_type=extension_name,
                                  protected_settings={'Password': password},
                                  type_handler_version=version,
                                  settings={'UserName': username},
                                  auto_upgrade_minor_version=auto_upgrade)

    poller = client.virtual_machine_extensions.create_or_update(resource_group_name, vm_name,
                                                                _ACCESS_EXT_HANDLER_NAME, ext)
    return ExtensionUpdateLongRunningOperation('resetting admin', 'done')(poller)
Example #5
0
    def create_or_update_vmextension(self):
        '''
        Method calling the Azure SDK to create or update the VM extension.
        :return: void
        '''
        self.log("Creating VM extension {0}".format(self.name))
        try:
            params = VirtualMachineExtension(
                location=self.location,
                publisher=self.publisher,
                virtual_machine_extension_type=self.
                virtual_machine_extension_type,
                type_handler_version=self.type_handler_version,
                auto_upgrade_minor_version=self.auto_upgrade_minor_version,
                settings=self.settings,
                protected_settings=self.protected_settings)
            poller = self.compute_client.virtual_machine_extensions.create_or_update(
                self.resource_group, self.virtual_machine_name, self.name,
                params)
            response = self.get_poller_result(poller)
            return vmextension_to_dict(response)

        except CloudError as e:
            self.log('Error attempting to create the VM extension.')
            self.fail("Error creating the VM extension: {0}".format(str(e)))
Example #6
0
 def get_ext_props(self,
                   extension_data,
                   settings=None,
                   protected_settings=None,
                   auto_upgrade_minor_version=True,
                   force_update_tag=None) -> VirtualMachineExtension:
     return VirtualMachineExtension(
         location=self.vm_data.location,
         publisher=extension_data.publisher,
         type_properties_type=extension_data.ext_type,
         type_handler_version=extension_data.version,
         auto_upgrade_minor_version=auto_upgrade_minor_version,
         settings=settings,
         protected_settings=protected_settings,
         force_update_tag=force_update_tag)
    def create_windows_vm_script_extension(
        self,
        script_file_path,
        script_config,
        vm_name,
        resource_group_name,
        region,
        tags,
        wait_for_result=True,
    ):
        """Create Windows VM Script Extension.

        :param str script_file_path:
        :param str script_config:
        :param str vm_name:
        :param str resource_group_name:
        :param str region:
        :param dict[str, str] tags:
        :param bool wait_for_result:
        :return:
        """
        file_name = script_file_path.split("/")[-1]
        vm_extension = VirtualMachineExtension(
            location=region,
            publisher=self.VM_SCRIPT_WINDOWS_PUBLISHER,
            type_handler_version=self.VM_SCRIPT_WINDOWS_HANDLER_VERSION,
            virtual_machine_extension_type=self.
            VM_SCRIPT_WINDOWS_EXTENSION_TYPE,
            tags=tags,
            settings={
                "fileUris": [script_file_path],
                "commandToExecute":
                self.VM_SCRIPT_WINDOWS_COMMAND_TPL.format(
                    file_name=file_name, script_configuration=script_config),
            },
        )

        operation_poller = self._compute_client.virtual_machine_extensions.create_or_update(  # noqa: E501
            resource_group_name=resource_group_name,
            vm_name=vm_name,
            vm_extension_name=vm_name,
            extension_parameters=vm_extension,
        )

        if wait_for_result:
            return operation_poller.result()

        return operation_poller
    def create_linux_vm_script_extension(
        self,
        script_file_path,
        script_config,
        vm_name,
        resource_group_name,
        region,
        tags,
        wait_for_result=True,
    ):
        """Create Linux VM Script Extension.

        :param str script_file_path:
        :param str script_config:
        :param str vm_name:
        :param str resource_group_name:
        :param str region:
        :param dict[str, str] tags:
        :param bool wait_for_result:
        :return:
        """
        file_uris = [
            file_uri.strip() for file_uri in script_file_path.split(",")
        ]

        vm_extension = VirtualMachineExtension(
            location=region,
            publisher=self.VM_SCRIPT_LINUX_PUBLISHER,
            type_handler_version=self.VM_SCRIPT_LINUX_HANDLER_VERSION,
            virtual_machine_extension_type=self.VM_SCRIPT_LINUX_EXTENSION_TYPE,
            tags=tags,
            settings={
                "fileUris": file_uris,
                "commandToExecute": script_config
            },
        )

        operation_poller = self._compute_client.virtual_machine_extensions.create_or_update(  # noqa: E501
            resource_group_name=resource_group_name,
            vm_name=vm_name,
            vm_extension_name=vm_name,
            extension_parameters=vm_extension,
        )

        if wait_for_result:
            return operation_poller.result()

        return operation_poller
Example #9
0
def run(job=None, logger=None, service=None, server=None, **kwargs):
    """
    Install an extension on the specified server or server tier.
    Can be used as a server action, a service action, or a blueprint action.
    """
    # Change the following section when developing an action for a new extension.

    EXTENSION_NAME = "{{ extension_name }}"
    PUBLISHER = "{{ publisher }}"
    VERSION = "{{ version }}"
    settings = """{{ settings }}"""
    protected_settings = """{{ protected_settings }}"""

    set_progress("Adding {} extension to {}".format(EXTENSION_NAME, server))
    resource_handler = server.resource_handler.cast()
    if PUBLISHER == "":
        PUBLISHER = "Microsoft.Compute"
    if protected_settings == "":
        protected_settings = "{}"

    server_info = resource_handler.tech_specific_server_details(server)
    server_name = server.hostname
    resource_group_name = server_info.resource_group
    location = server_info.location

    w = resource_handler.get_api_wrapper()

    from azure.mgmt.compute.models import VirtualMachineExtension

    extension_parameters = VirtualMachineExtension(
        location=location,
        publisher=PUBLISHER,
        virtual_machine_extension_type=EXTENSION_NAME,
        type_handler_version=VERSION,
        settings=json.loads(settings),
        protected_settings=json.loads(protected_settings))
    poller = w.compute_client.virtual_machine_extensions.create_or_update(
        resource_group_name, server_name, EXTENSION_NAME, extension_parameters)
    poller.wait(timeout=240)

    has_failures = False
    status = "FAILURE" if has_failures else "SUCCESS"

    return status, "", ""
Example #10
0
def set_linux_user(resource_group_name,
                   vm_name,
                   username,
                   password=None,
                   ssh_key_value=None):
    '''create or update a user credential
    :param username: user name
    :param password: user password.
    :param ssh_key_value: SSH key file value or key file path
    '''
    vm = _vm_get(resource_group_name, vm_name, 'instanceView')
    client = _compute_client_factory()

    from azure.mgmt.compute.models import VirtualMachineExtension

    protected_settings = {}

    protected_settings['username'] = username
    if password:
        protected_settings['password'] = password
    elif not ssh_key_value and not password:  #default to ssh
        ssh_key_value = os.path.join(os.path.expanduser('~'), '.ssh',
                                     'id_rsa.pub')

    if ssh_key_value:
        protected_settings['ssh_key'] = read_content_if_is_file(ssh_key_value)

    extension_name = _LINUX_ACCESS_EXT
    publisher, version, auto_upgrade = _get_access_extension_upgrade_info(
        vm.resources, extension_name)

    ext = VirtualMachineExtension(
        vm.location,  #pylint: disable=no-member
        publisher=publisher,
        virtual_machine_extension_type=extension_name,
        protected_settings=protected_settings,
        type_handler_version=version,
        settings={},
        auto_upgrade_minor_version=auto_upgrade)

    poller = client.virtual_machine_extensions.create_or_update(
        resource_group_name, vm_name, _ACCESS_EXT_HANDLER_NAME, ext)
    return ExtensionUpdateLongRunningOperation('setting user', 'done')(poller)
Example #11
0
    def _prepare_linux_vm_script_extension(self, location, script_file,
                                           script_configurations, tags):
        """Prepare VirtualMachineExtension model for Linux custom script extension

        :param location: (str) Azure region
        :param script_file: (str) path to the script file(s) that will be downloaded to the virtual machine
        :param script_configurations: (str) additional information for the extension execution
        :param tags: (dict) Azure tags
        :return: azure.mgmt.compute.models.VirtualMachineExtension instance
        """
        file_uris = [file_uri.strip() for file_uri in script_file.split(",")]

        return VirtualMachineExtension(
            location=location,
            publisher=self.LINUX_PUBLISHER,
            type_handler_version=self.LINUX_HANDLER_VERSION,
            virtual_machine_extension_type=self.LINUX_EXTENSION_TYPE,
            tags=tags,
            settings={
                "fileUris": file_uris,
                "commandToExecute": script_configurations,
            })
Example #12
0
def delete_linux_user(
        resource_group_name, vm_name, username):
    '''Remove the user '''
    vm = _vm_get(resource_group_name, vm_name, 'instanceView')
    client = _compute_client_factory()

    from azure.mgmt.compute.models import VirtualMachineExtension

    extension_name = _LINUX_ACCESS_EXT
    publisher, version, auto_upgrade = _get_access_extension_upgrade_info(
        vm.resources, extension_name)

    ext = VirtualMachineExtension(vm.location,#pylint: disable=no-member
                                  publisher=publisher,
                                  virtual_machine_extension_type=extension_name,
                                  protected_settings={'remove_user':username},
                                  type_handler_version=version,
                                  settings={},
                                  auto_upgrade_minor_version=auto_upgrade)

    poller = client.virtual_machine_extensions.create_or_update(resource_group_name, vm_name,
                                                                _ACCESS_EXT_HANDLER_NAME, ext)
    return ExtensionUpdateLongRunningOperation('deleting user', 'done')(poller)
Example #13
0
    def _prepare_windows_vm_script_extension(self, location, script_file,
                                             script_configurations, tags):
        """Prepare VirtualMachineExtension model for Windows PowerShell script extension

        :param location: (str) Azure region
        :param script_file:
        :param script_configurations:
        :param tags: (dict) Azure tags
        :return: azure.mgmt.compute.models.VirtualMachineExtension instance
        """
        file_name = script_file.rstrip("/").split("/")[-1]
        exec_command = "powershell.exe -ExecutionPolicy Unrestricted -File {} {}".format(
            file_name, script_configurations)

        return VirtualMachineExtension(
            location=location,
            publisher=self.WINDOWS_PUBLISHER,
            type_handler_version=self.WINDOWS_HANDLER_VERSION,
            virtual_machine_extension_type=self.WINDOWS_EXTENSION_TYPE,
            tags=tags,
            settings={
                "fileUris": [script_file],
                "commandToExecute": exec_command,
            })
Example #14
0
def enable(
        resource_group_name,
        vm_name,  # pylint: disable=too-many-arguments,too-many-locals, too-many-statements
        aad_client_id,
        disk_encryption_keyvault,
        aad_client_secret=None,
        aad_client_cert_thumbprint=None,
        key_encryption_keyvault=None,
        key_encryption_key=None,
        key_encryption_algorithm='RSA-OAEP',
        volume_type=None):
    '''
    Enable disk encryption on OS disk, Data disks, or both
    :param str aad_client_id: Client ID of AAD app with permissions to write secrets to KeyVault
    :param str aad_client_secret: Client Secret of AAD app with permissions to
    write secrets to KeyVault
    :param str aad_client_cert_thumbprint: Thumbprint of AAD app certificate with permissions
    to write secrets to KeyVault
    :param str disk_encryption_keyvault:the KeyVault where generated encryption key will be placed
    :param str key_encryption_key: KeyVault key name or URL used to encrypt the disk encryption key
    :param str key_encryption_keyvault: the KeyVault containing the key encryption key
    used to encrypt the disk encryption key. If missing, CLI will use --disk-encryption-keyvault
    '''
    # pylint: disable=no-member
    compute_client = _compute_client_factory()
    vm = compute_client.virtual_machines.get(resource_group_name, vm_name)
    os_type = vm.storage_profile.os_disk.os_type.value
    is_linux = _is_linux_vm(os_type)
    extension = extension_info[os_type]

    # 1. First validate arguments

    if not aad_client_cert_thumbprint and not aad_client_secret:
        raise CLIError(
            'Please provide either --aad-client-id or --aad-client-cert-thumbprint'
        )

    if volume_type is None:
        if vm.storage_profile.data_disks:
            raise CLIError('VM has data disks, please supply --volume-type')
        else:
            volume_type = 'OS'

    # encryption is not supported on all linux distros, but service never tells you
    # so let us verify at the client side
    if is_linux:
        image_reference = getattr(vm.storage_profile, 'image_reference', None)
        if image_reference:
            result, message = _check_encrypt_is_supported(
                image_reference, volume_type)
            if not result:
                logger.warning(message)

    # sequence_version should be unique
    sequence_version = uuid.uuid4()

    # retrieve keyvault details
    disk_encryption_keyvault_url = _get_key_vault_base_url(
        (parse_resource_id(disk_encryption_keyvault))['name'])

    # disk encryption key itself can be further protected, so let us verify
    if key_encryption_key:
        key_encryption_keyvault = key_encryption_keyvault or disk_encryption_keyvault
        if '://' not in key_encryption_key:  # appears a key name
            key_encryption_key = _get_keyvault_key_url(
                (parse_resource_id(key_encryption_keyvault))['name'],
                key_encryption_key)

    # 2. we are ready to provision/update the disk encryption extensions
    # The following logic was mostly ported from xplat-cli
    public_config = {
        'AADClientID': aad_client_id,
        'AADClientCertThumbprint': aad_client_cert_thumbprint,
        'KeyVaultURL': disk_encryption_keyvault_url,
        'VolumeType': volume_type,
        'EncryptionOperation': 'EnableEncryption',
        'KeyEncryptionKeyURL': key_encryption_key,
        'KeyEncryptionAlgorithm': key_encryption_algorithm,
        'SequenceVersion': sequence_version,
    }
    private_config = {
        'AADClientSecret':
        aad_client_secret if is_linux else (aad_client_secret or '')
    }

    from azure.mgmt.compute.models import (VirtualMachineExtension,
                                           DiskEncryptionSettings,
                                           KeyVaultSecretReference,
                                           KeyVaultKeyReference, SubResource)

    ext = VirtualMachineExtension(
        vm.location,  # pylint: disable=no-member
        publisher=extension['publisher'],
        virtual_machine_extension_type=extension['name'],
        protected_settings=private_config,
        type_handler_version=extension['version'],
        settings=public_config,
        auto_upgrade_minor_version=True)

    poller = compute_client.virtual_machine_extensions.create_or_update(
        resource_group_name, vm_name, extension['name'], ext)
    poller.result()

    # verify the extension was ok
    extension_result = compute_client.virtual_machine_extensions.get(
        resource_group_name, vm_name, extension['name'], 'instanceView')
    if extension_result.provisioning_state != 'Succeeded':
        raise CLIError(
            'Extension needed for disk encryption was not provisioned correctly'
        )
    if not (extension_result.instance_view.statuses
            and extension_result.instance_view.statuses[0].message):
        raise CLIError(
            'Could not found url pointing to the secret for disk encryption')

    # 3. update VM's storage profile with the secrets
    status_url = extension_result.instance_view.statuses[0].message

    vm = compute_client.virtual_machines.get(resource_group_name, vm_name)
    secret_ref = KeyVaultSecretReference(
        secret_url=status_url,
        source_vault=SubResource(disk_encryption_keyvault))

    key_encryption_key_obj = None
    if key_encryption_key:
        key_encryption_key_obj = KeyVaultKeyReference(
            key_encryption_key, SubResource(key_encryption_keyvault))

    disk_encryption_settings = DiskEncryptionSettings(
        disk_encryption_key=secret_ref,
        key_encryption_key=key_encryption_key_obj,
        enabled=True)

    vm.storage_profile.os_disk.encryption_settings = disk_encryption_settings
    set_vm(vm)
    if is_linux and volume_type != _DATA_VOLUME_TYPE:
        # TODO: expose a 'wait' command to do the monitor and handle the reboot
        logger.warning(
            "The encryption request was accepted. Please use 'show' command to monitor "
            "the progress. If you see 'VMRestartPending', please restart the VM, and "
            "the encryption will finish shortly")
Example #15
0
def disable(resource_group_name, vm_name, volume_type=None, force=False):
    '''
    Disable disk encryption on OS disk, Data disks, or both
    '''
    compute_client = _compute_client_factory()
    vm = compute_client.virtual_machines.get(resource_group_name, vm_name)
    # pylint: disable=no-member
    os_type = vm.storage_profile.os_disk.os_type.value

    # 1. be nice, figure out the default volume type and also verify VM will not be busted
    is_linux = _is_linux_vm(os_type)
    if is_linux:
        if volume_type:
            if not force:
                if volume_type == _DATA_VOLUME_TYPE:
                    status = show(resource_group_name, vm_name)
                    if status['osDisk'] == _STATUS_ENCRYPTED:
                        raise CLIError(
                            "VM's OS disk is encrypted. Disabling encryption on data "
                            "disk can still cause VM unbootable. Use '--force' "
                            "to continue")
                else:
                    raise CLIError(
                        "Only data disk is supported to disable on Linux VM")
        else:
            volume_type = _DATA_VOLUME_TYPE
    elif volume_type is None:
        if vm.storage_profile.data_disks:
            raise CLIError("VM has data disks, please specify --volume-type")

    # sequence_version should be incremented since encryptions occurred before
    extension = extension_info[os_type]
    sequence_version = uuid.uuid4()

    # 2. update the disk encryption extension
    # The following logic was mostly ported from xplat-cli
    public_config = {
        'VolumeType': volume_type,
        'EncryptionOperation': 'DisableEncryption',
        'SequenceVersion': sequence_version,
    }

    from azure.mgmt.compute.models import (VirtualMachineExtension,
                                           DiskEncryptionSettings,
                                           KeyVaultSecretReference,
                                           KeyVaultKeyReference, SubResource)

    ext = VirtualMachineExtension(
        vm.location,  # pylint: disable=no-member
        publisher=extension['publisher'],
        virtual_machine_extension_type=extension['name'],
        type_handler_version=extension['version'],
        settings=public_config,
        auto_upgrade_minor_version=True)

    poller = compute_client.virtual_machine_extensions.create_or_update(
        resource_group_name, vm_name, extension['name'], ext)
    poller.result()

    # 3. Remove the secret from VM's storage profile
    extension_result = compute_client.virtual_machine_extensions.get(
        resource_group_name, vm_name, extension['name'], 'instanceView')
    if extension_result.provisioning_state != 'Succeeded':
        raise CLIError("Extension updating didn't succeed")

    vm = compute_client.virtual_machines.get(resource_group_name, vm_name)
    disk_encryption_settings = DiskEncryptionSettings(enabled=False)
    vm.storage_profile.os_disk.encryption_settings = disk_encryption_settings
    set_vm(vm)