def test_when_alias_doc_is_missing(self, mock_get_active_cloud):
     from azure.cli.command_modules.vm._actions import load_images_from_aliases_doc
     p = mock.PropertyMock(side_effect=CloudEndpointNotSetException)
     mock_cloud = mock.MagicMock()
     type(mock_cloud.endpoints).vm_image_alias_doc = p
     mock_get_active_cloud.return_value = mock_cloud
     # assert
     with self.assertRaises(CLIError):
         load_images_from_aliases_doc()
Exemple #2
0
 def test_when_alias_doc_is_missing(self, mock_get_active_cloud):
     from azure.cli.command_modules.vm._actions import load_images_from_aliases_doc
     p = mock.PropertyMock(side_effect=CloudEndpointNotSetException)
     mock_cloud = mock.MagicMock()
     type(mock_cloud.endpoints).vm_image_alias_doc = p
     mock_get_active_cloud.return_value = mock_cloud
     # assert
     with self.assertRaises(CLIError):
         load_images_from_aliases_doc()
Exemple #3
0
def _validate_vm_create_storage_profile(namespace):

    from azure.cli.command_modules.vm._actions import load_images_from_aliases_doc

    image = namespace.image

    # 1 - Create native disk with VHD URI
    if image.lower().endswith('.vhd'):
        namespace.storage_profile = StorageProfile.SACustomImage
        if not namespace.os_type:
            raise CLIError('--os-type TYPE is required for a native OS VHD disk.')
        return

    # attempt to parse an URN
    urn_match = re.match('([^:]*):([^:]*):([^:]*):([^:]*)', image)
    if urn_match:
        namespace.os_publisher = urn_match.group(1)
        namespace.os_offer = urn_match.group(2)
        namespace.os_sku = urn_match.group(3)
        namespace.os_version = urn_match.group(4)
    else:
        images = load_images_from_aliases_doc()
        matched = next((x for x in images if x['urnAlias'].lower() == image.lower()), None)
        if matched is None:
            raise CLIError('Invalid image "{}". Please pick one from {}'.format(
                image, [x['urnAlias'] for x in images]))
        namespace.os_publisher = matched['publisher']
        namespace.os_offer = matched['offer']
        namespace.os_sku = matched['sku']
        namespace.os_version = matched['version']

    namespace.os_type = 'windows' if 'windows' in namespace.os_offer.lower() else 'linux'

    # 2 - Create native disk from PIR image
    namespace.storage_profile = StorageProfile.SAPirImage  # pylint: disable=redefined-variable-type
 def test_when_alias_doc_is_missing(self, mock_get_active_cloud):
     from azure.cli.command_modules.vm._actions import load_images_from_aliases_doc
     p = mock.PropertyMock(side_effect=CloudEndpointNotSetException(''))
     mock_cloud = mock.MagicMock()
     type(mock_cloud.endpoints).vm_image_alias_doc = p
     mock_get_active_cloud.return_value = mock_cloud
     # assert
     cli_ctx = DummyCli()
     cli_ctx.cloud = mock_cloud
     images = load_images_from_aliases_doc(cli_ctx)
     self.assertEqual(images[0], {'urnAlias': 'CentOS', 'publisher': 'OpenLogic',
                                  'offer': 'CentOS', 'sku': '7.5', 'version': 'latest'})
Exemple #5
0
def _parse_image_argument(namespace):
    """ Systematically determines what type is supplied for the --image parameter. Updates the
        namespace and returns the type for subsequent processing. """
    # 1 - easy check for URI
    if namespace.image.lower().endswith('.vhd'):
        return 'uri'

    # 2 - attempt to match an URN alias (most likely)
    from azure.cli.command_modules.vm._actions import load_images_from_aliases_doc
    images = load_images_from_aliases_doc()
    matched = next(
        (x
         for x in images if x['urnAlias'].lower() == namespace.image.lower()),
        None)
    if matched:
        namespace.os_publisher = matched['publisher']
        namespace.os_offer = matched['offer']
        namespace.os_sku = matched['sku']
        namespace.os_version = matched['version']
        return 'urn'

    # 3 - attempt to match an URN pattern
    urn_match = re.match('([^:]*):([^:]*):([^:]*):([^:]*)', namespace.image)
    if urn_match:
        namespace.os_publisher = urn_match.group(1)
        namespace.os_offer = urn_match.group(2)
        namespace.os_sku = urn_match.group(3)
        namespace.os_version = urn_match.group(4)
        return 'urn'

    # 4 - check if a fully-qualified ID (assumes it is an image ID)
    if is_valid_resource_id(namespace.image):
        return 'image_id'

    # 5 - check if an existing managed disk image resource
    compute_client = _compute_client_factory()
    try:
        compute_client.images.get(namespace.resource_group_name,
                                  namespace.image)
        namespace.image = _get_resource_id(namespace.image,
                                           namespace.resource_group_name,
                                           'images', 'Microsoft.Compute')
        return 'image_id'
    except CloudError:
        err = 'Invalid image "{}". Use a custom image name, id, or pick one from {}'
        raise CLIError(
            err.format(namespace.image, [x['urnAlias'] for x in images]))
def process_image_template_create_namespace(cmd, namespace):  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
    from azure.cli.core.commands.parameters import get_subscription_locations

    source = None
    scripts = []

    # default location to RG location.
    if not namespace.location:
        get_default_location_from_resource_group(cmd, namespace)

    # validate tags.
    validate_tags(namespace)

    # Validate and parse scripts
    if namespace.scripts:
        for ns_script in namespace.scripts:
            scripts.append(_parse_script(ns_script))

    # Validate and parse destination and locations
    destinations = []
    subscription_locations = get_subscription_locations(cmd.cli_ctx)
    location_names = [l.name for l in subscription_locations]
    location_display_names = [l.display_name for l in subscription_locations]

    if namespace.managed_image_destinations:
        for dest in namespace.managed_image_destinations:
            rid, location = _parse_image_destination(cmd, namespace.resource_group_name, dest, is_shared_image=False)
            location = _validate_location(location, location_names, location_display_names)
            destinations.append((_DestType.MANAGED_IMAGE, rid, location))

    if namespace.shared_image_destinations:
        for dest in namespace.shared_image_destinations:
            rid, locations = _parse_image_destination(cmd, namespace.resource_group_name, dest, is_shared_image=True)
            locations = [_validate_location(l, location_names, location_display_names) for l in locations]
            destinations.append((_DestType.SHARED_IMAGE_GALLERY, rid, locations))

    # Validate and parse source image
    # 1 - check if source is a URN. A urn e.g "Canonical:UbuntuServer:18.04-LTS:latest"
    urn_match = re.match('([^:]*):([^:]*):([^:]*):([^:]*)', namespace.source)
    if urn_match:  # if platform image urn
        source = {
            'publisher': urn_match.group(1),
            'offer': urn_match.group(2),
            'sku': urn_match.group(3),
            'version': urn_match.group(4),
            'type': _SourceType.PLATFORM_IMAGE
        }

        likely_linux = bool("windows" not in source["offer"].lower() and "windows" not in source["sku"].lower())

        logger.info("%s looks like a platform image URN", namespace.source)

    # 2 - check if a fully-qualified ID (assumes it is an image ID)
    elif is_valid_resource_id(namespace.source):

        parsed = parse_resource_id(namespace.source)
        image_type = parsed.get('type')
        image_resource_type = parsed.get('type')

        if not image_type:
            pass

        elif image_type.lower() == 'images':
            source = {
                'image_id': namespace.source,
                'type': _SourceType.MANAGED_IMAGE
            }
            logger.info("%s looks like a managed image id.", namespace.source)

        elif image_type == "galleries" and image_resource_type:
            source = {
                'image_version_id': namespace.source,
                'type': _SourceType.SIG_VERSION
            }
            logger.info("%s looks like a shared image version id.", namespace.source)

    # 3 - check if source is a Redhat iso uri. If so a checksum must be provided.
    elif urlparse(namespace.source).scheme and "://" in namespace.source and ".iso" in namespace.source.lower():
        if not namespace.checksum:
            raise CLIError("Must provide a checksum for source uri: {}".format(namespace.source))
        source = {
            'source_uri': namespace.source,
            'sha256_checksum': namespace.checksum,
            'type': _SourceType.ISO_URI
        }
        likely_linux = True

        logger.info("%s looks like a RedHat iso uri.", namespace.source)

    # 4 - check if source is a urn alias from the vmImageAliasDoc endpoint. See "az cloud show"
    if not source:
        from azure.cli.command_modules.vm._actions import load_images_from_aliases_doc
        images = load_images_from_aliases_doc(cmd.cli_ctx)
        matched = next((x for x in images if x['urnAlias'].lower() == namespace.source.lower()), None)
        if matched:
            source = {
                'publisher': matched['publisher'],
                'offer': matched['offer'],
                'sku': matched['sku'],
                'version': matched['version'],
                'type': _SourceType.PLATFORM_IMAGE
            }

        if "windows" not in source["offer"].lower() and "windows" not in source["sku"].lower():
            likely_linux = True

        logger.info("%s looks like a platform image alias.", namespace.source)

    # 5 - check if source is an existing managed disk image resource
    if not source:
        compute_client = _compute_client_factory(cmd.cli_ctx)
        try:
            image_name = namespace.source
            compute_client.images.get(namespace.resource_group_name, namespace.source)
            namespace.source = _get_resource_id(cmd.cli_ctx, namespace.source, namespace.resource_group_name,
                                                'images', 'Microsoft.Compute')
            source = {
                'image_id': namespace.source,
                'type': _SourceType.MANAGED_IMAGE
            }

            logger.info("%s, looks like a managed image name. Using resource ID: %s", image_name, namespace.source)  # pylint: disable=line-too-long
        except CloudError:
            pass

    if not source:
        err = 'Invalid image "{}". Use a valid image URN, managed image name or ID, ISO URI, ' \
              'or pick a platform image alias from {}.\nSee vm create -h for more information on specifying an image.'\
            .format(namespace.source, ", ".join([x['urnAlias'] for x in images]))
        raise CLIError(err)

    for script in scripts:
        if script["type"] is None:
            try:
                script["type"] = ScriptType.SHELL if likely_linux else ScriptType.POWERSHELL
                logger.info("For script %s, likely linux is %s.", script["script"], likely_linux)
            except NameError:
                raise CLIError("Unable to infer the type of script {}.".format(script["script"]))

    namespace.source_dict = source
    namespace.scripts_list = scripts
    namespace.destinations_lists = destinations
Exemple #7
0
def get_urn_aliases_completion_list(prefix, **kwargs):  # pylint: disable=unused-argument
    images = load_images_from_aliases_doc()
    return [i['urnAlias'] for i in images]
Exemple #8
0
def _parse_image_argument(namespace):
    """ Systematically determines what type is supplied for the --image parameter. Updates the
        namespace and returns the type for subsequent processing. """
    # 1 - easy check for URI
    if namespace.image.lower().endswith('.vhd'):
        return 'uri'

    # 2 - attempt to match an URN alias (most likely)
    from azure.cli.command_modules.vm._actions import load_images_from_aliases_doc
    images = load_images_from_aliases_doc()
    matched = next(
        (x
         for x in images if x['urnAlias'].lower() == namespace.image.lower()),
        None)
    if matched:
        namespace.os_publisher = matched['publisher']
        namespace.os_offer = matched['offer']
        namespace.os_sku = matched['sku']
        namespace.os_version = matched['version']
        return 'urn'

    # 3 - attempt to match an URN pattern
    urn_match = re.match('([^:]*):([^:]*):([^:]*):([^:]*)', namespace.image)
    if urn_match:
        namespace.os_publisher = urn_match.group(1)
        namespace.os_offer = urn_match.group(2)
        namespace.os_sku = urn_match.group(3)
        namespace.os_version = urn_match.group(4)
        try:
            compute_client = _compute_client_factory()
            if namespace.os_version.lower() == 'latest':
                top_one = compute_client.virtual_machine_images.list(
                    namespace.location,
                    namespace.os_publisher,
                    namespace.os_offer,
                    namespace.os_sku,
                    top=1,
                    orderby='name desc')
                if not top_one:
                    raise CLIError("Can't resolve the vesion of '{}'".format(
                        namespace.image))

                image_version = top_one[0].name
            else:
                image_version = namespace.os_version

            image = compute_client.virtual_machine_images.get(
                namespace.location, namespace.os_publisher, namespace.os_offer,
                namespace.os_sku, image_version)

            # pylint: disable=no-member
            if image.plan:
                namespace.plan_name = image.plan.name
                namespace.plan_product = image.plan.product
                namespace.plan_publisher = image.plan.publisher
        except CloudError as ex:
            logger.warning(
                "Querying the image of '%s' failed for an error '%s'. Configuring plan settings "
                "will be skipped", namespace.image, ex.message)
        return 'urn'

    # 4 - check if a fully-qualified ID (assumes it is an image ID)
    if is_valid_resource_id(namespace.image):
        return 'image_id'

    # 5 - check if an existing managed disk image resource
    compute_client = _compute_client_factory()
    try:
        compute_client.images.get(namespace.resource_group_name,
                                  namespace.image)
        namespace.image = _get_resource_id(namespace.image,
                                           namespace.resource_group_name,
                                           'images', 'Microsoft.Compute')
        return 'image_id'
    except CloudError:
        err = 'Invalid image "{}". Use a custom image name, id, or pick one from {}'
        raise CLIError(
            err.format(namespace.image, [x['urnAlias'] for x in images]))
Exemple #9
0
def _parse_image_argument(namespace):
    """ Systematically determines what type is supplied for the --image parameter. Updates the
        namespace and returns the type for subsequent processing. """
    # 1 - easy check for URI
    if namespace.image.lower().endswith('.vhd'):
        return 'uri'

    # 2 - attempt to match an URN alias (most likely)
    from azure.cli.command_modules.vm._actions import load_images_from_aliases_doc
    images = load_images_from_aliases_doc()
    matched = next((x for x in images if x['urnAlias'].lower() == namespace.image.lower()), None)
    if matched:
        namespace.os_publisher = matched['publisher']
        namespace.os_offer = matched['offer']
        namespace.os_sku = matched['sku']
        namespace.os_version = matched['version']
        return 'urn'

    # 3 - attempt to match an URN pattern
    urn_match = re.match('([^:]*):([^:]*):([^:]*):([^:]*)', namespace.image)
    if urn_match:
        namespace.os_publisher = urn_match.group(1)
        namespace.os_offer = urn_match.group(2)
        namespace.os_sku = urn_match.group(3)
        namespace.os_version = urn_match.group(4)
        try:
            compute_client = _compute_client_factory()
            if namespace.os_version.lower() == 'latest':
                top_one = compute_client.virtual_machine_images.list(namespace.location,
                                                                     namespace.os_publisher,
                                                                     namespace.os_offer,
                                                                     namespace.os_sku,
                                                                     top=1,
                                                                     orderby='name desc')
                if not top_one:
                    raise CLIError("Can't resolve the vesion of '{}'".format(namespace.image))

                image_version = top_one[0].name
            else:
                image_version = namespace.os_version

            image = compute_client.virtual_machine_images.get(namespace.location,
                                                              namespace.os_publisher,
                                                              namespace.os_offer,
                                                              namespace.os_sku,
                                                              image_version)

            # pylint: disable=no-member
            if image.plan:
                namespace.plan_name = image.plan.name
                namespace.plan_product = image.plan.product
                namespace.plan_publisher = image.plan.publisher
        except CloudError as ex:
            logger.warning("Querying the image of '%s' failed for an error '%s'. Configuring plan settings "
                           "will be skipped", namespace.image, ex.message)
        return 'urn'

    # 4 - check if a fully-qualified ID (assumes it is an image ID)
    if is_valid_resource_id(namespace.image):
        return 'image_id'

    # 5 - check if an existing managed disk image resource
    compute_client = _compute_client_factory()
    try:
        compute_client.images.get(namespace.resource_group_name, namespace.image)
        namespace.image = _get_resource_id(namespace.image, namespace.resource_group_name,
                                           'images', 'Microsoft.Compute')
        return 'image_id'
    except CloudError:
        err = 'Invalid image "{}". Use a custom image name, id, or pick one from {}'
        raise CLIError(err.format(namespace.image, [x['urnAlias'] for x in images]))
Exemple #10
0
def get_urn_aliases_completion_list(prefix, **kwargs):  # pylint: disable=unused-argument
    images = load_images_from_aliases_doc()
    return [i['urnAlias'] for i in images]
Exemple #11
0
def _validate_vm_create_storage_profile(namespace, for_scale_set=False):  # pylint: disable=too-many-branches, too-many-statements

    from azure.cli.command_modules.vm._actions import load_images_from_aliases_doc

    image = namespace.image or ''

    # do VM specific validating
    if not for_scale_set:
        if namespace.managed_os_disk:
            if namespace.image:
                raise CLIError(
                    "'--image' is not applicable when attach to an existing os disk"
                )
            if not namespace.os_type:
                raise CLIError(
                    '--os-type TYPE is required when attach to an existing os disk'
                )
        else:
            if not image:
                raise CLIError("Please provide parameter value to '--image'")

    if image.lower().endswith('.vhd'):
        if not namespace.os_type:
            raise CLIError(
                '--os-type TYPE is required for a native OS VHD disk.')

    valid_managed_skus = ['premium_lrs', 'standard_lrs']
    valid_unmanaged_skus = valid_managed_skus + [
        'standard_grs', 'standard_ragrs', 'standard_zrs'
    ]

    if namespace.use_unmanaged_disk:
        if namespace.storage_sku.lower() not in valid_unmanaged_skus:
            raise CLIError(
                "Invalid storage sku '{}', please choose from '{}'".format(
                    namespace.storage_sku, valid_unmanaged_skus))
        if namespace.data_disk_sizes_gb:
            raise CLIError(
                "'--data-disk-sizes-gb' is only applicable when use managed disks"
            )
        if '/images/' in namespace.image.lower():
            raise CLIError(
                "VM/VMSS created from a managed custom image must use managed disks"
            )
        if not for_scale_set and namespace.managed_os_disk:
            raise CLIError(
                "'--use-unmanaged-disk' is ignored when attach to a managed os disk"
            )
    else:
        if namespace.storage_sku.lower() not in valid_managed_skus:
            err = "invalid storage sku '{}' to use for managed os disks, please choose from '{}'"
            raise CLIError(
                err.format(namespace.storage_sku, valid_managed_skus))
        if for_scale_set and namespace.os_disk_name:
            raise CLIError(
                "'--os-disk-name' is not allowed for scale sets using managed disks"
            )
        if not for_scale_set and namespace.storage_account:
            raise CLIError(
                "'--storage-account' is only applicable when use unmanaged disk."
                " Please either remove it or turn on '--use-unmanaged-disk'")

    # attempt to parse an URN
    urn_match = re.match('([^:]*):([^:]*):([^:]*):([^:]*)', image)
    if urn_match:
        namespace.os_publisher = urn_match.group(1)
        namespace.os_offer = urn_match.group(2)
        namespace.os_sku = urn_match.group(3)
        namespace.os_version = urn_match.group(4)
        namespace.storage_profile = (StorageProfile.SAPirImage
                                     if namespace.use_unmanaged_disk else
                                     StorageProfile.ManagedPirImage)
    elif is_valid_resource_id(image):
        namespace.storage_profile = StorageProfile.ManagedCustomImage
    elif image.lower().endswith('.vhd'):
        # pylint: disable=redefined-variable-type
        namespace.storage_profile = StorageProfile.SACustomImage
    elif not for_scale_set and namespace.managed_os_disk:
        res = parse_resource_id(namespace.managed_os_disk)
        name = res['name']
        rg = res.get('resource_group', namespace.resource_group_name)
        namespace.managed_os_disk = resource_id(
            subscription=get_subscription_id(),
            resource_group=rg,
            namespace='Microsoft.Compute',
            type='disks',
            name=name)
        namespace.storage_profile = StorageProfile.ManagedSpecializedOSDisk
    else:
        images = load_images_from_aliases_doc()
        matched = next(
            (x for x in images if x['urnAlias'].lower() == image.lower()),
            None)
        if matched:
            namespace.os_publisher = matched['publisher']
            namespace.os_offer = matched['offer']
            namespace.os_sku = matched['sku']
            namespace.os_version = matched['version']
            namespace.storage_profile = (StorageProfile.SAPirImage
                                         if namespace.use_unmanaged_disk else
                                         StorageProfile.ManagedPirImage)
        else:
            # last try: is it a custom image name?
            compute_client = _compute_client_factory()
            try:
                compute_client.images.get(namespace.resource_group_name, image)
                image = namespace.image = _get_resource_id(
                    image, namespace.resource_group_name, 'images',
                    'Microsoft.Compute')
                namespace.storage_profile = StorageProfile.ManagedCustomImage
            except CloudError:
                err = 'Invalid image "{}". Use a custom image name, id, or pick one from {}'
                raise CLIError(
                    err.format(image, [x['urnAlias'] for x in images]))

    if namespace.storage_profile == StorageProfile.ManagedCustomImage:
        res = parse_resource_id(image)
        compute_client = _compute_client_factory()
        image_info = compute_client.images.get(res['resource_group'],
                                               res['name'])
        # pylint: disable=no-member
        namespace.os_type = image_info.storage_profile.os_disk.os_type.value
        namespace.image_data_disks = image_info.storage_profile.data_disks

    if not namespace.os_type:
        namespace.os_type = 'windows' if 'windows' in namespace.os_offer.lower(
        ) else 'linux'
Exemple #12
0
def get_urn_aliases_completion_list(cmd, prefix, namespace):  # pylint: disable=unused-argument
    images = load_images_from_aliases_doc(cmd.cli_ctx)
    return [i['urnAlias'] for i in images]
Exemple #13
0
def _validate_vm_create_storage_profile(namespace, for_scale_set=False):  # pylint: disable=too-many-branches, too-many-statements

    from azure.cli.command_modules.vm._actions import load_images_from_aliases_doc

    image = namespace.image or ''

    # do VM specific validating
    if not for_scale_set:
        if namespace.managed_os_disk:
            if namespace.image:
                raise CLIError("'--image' is not applicable when attach to an existing os disk")
            if not namespace.os_type:
                raise CLIError('--os-type TYPE is required when attach to an existing os disk')
        else:
            if not image:
                raise CLIError("Please provide parameter value to '--image'")

    if image.lower().endswith('.vhd'):
        if not namespace.os_type:
            raise CLIError('--os-type TYPE is required for a native OS VHD disk.')

    valid_managed_skus = ['premium_lrs', 'standard_lrs']
    valid_unmanaged_skus = valid_managed_skus + ['standard_grs', 'standard_ragrs', 'standard_zrs']

    if namespace.use_unmanaged_disk:
        if namespace.storage_sku.lower() not in valid_unmanaged_skus:
            raise CLIError("Invalid storage sku '{}', please choose from '{}'".format(
                namespace.storage_sku, valid_unmanaged_skus))
        if namespace.data_disk_sizes_gb:
            raise CLIError("'--data-disk-sizes-gb' is only applicable when use managed disks")
        if '/images/' in namespace.image.lower():
            raise CLIError("VM/VMSS created from a managed custom image must use managed disks")
        if not for_scale_set and namespace.managed_os_disk:
            raise CLIError("'--use-unmanaged-disk' is ignored when attach to a managed os disk")
    else:
        if namespace.storage_sku.lower() not in valid_managed_skus:
            err = "invalid storage sku '{}' to use for managed os disks, please choose from '{}'"
            raise CLIError(err.format(namespace.storage_sku, valid_managed_skus))
        if for_scale_set and namespace.os_disk_name:
            raise CLIError("'--os-disk-name' is not allowed for scale sets using managed disks")
        if not for_scale_set and namespace.storage_account:
            raise CLIError("'--storage-account' is only applicable when use unmanaged disk."
                           " Please either remove it or turn on '--use-unmanaged-disk'")

    # attempt to parse an URN
    urn_match = re.match('([^:]*):([^:]*):([^:]*):([^:]*)', image)
    if urn_match:
        namespace.os_publisher = urn_match.group(1)
        namespace.os_offer = urn_match.group(2)
        namespace.os_sku = urn_match.group(3)
        namespace.os_version = urn_match.group(4)
        namespace.storage_profile = (StorageProfile.SAPirImage
                                     if namespace.use_unmanaged_disk
                                     else StorageProfile.ManagedPirImage)
    elif is_valid_resource_id(image):
        namespace.storage_profile = StorageProfile.ManagedCustomImage
    elif image.lower().endswith('.vhd'):
        # pylint: disable=redefined-variable-type
        namespace.storage_profile = StorageProfile.SACustomImage
    elif not for_scale_set and namespace.managed_os_disk:
        res = parse_resource_id(namespace.managed_os_disk)
        name = res['name']
        rg = res.get('resource_group', namespace.resource_group_name)
        namespace.managed_os_disk = resource_id(
            subscription=get_subscription_id(),
            resource_group=rg,
            namespace='Microsoft.Compute',
            type='disks',
            name=name)
        namespace.storage_profile = StorageProfile.ManagedSpecializedOSDisk
    else:
        images = load_images_from_aliases_doc()
        matched = next((x for x in images if x['urnAlias'].lower() == image.lower()), None)
        if matched:
            namespace.os_publisher = matched['publisher']
            namespace.os_offer = matched['offer']
            namespace.os_sku = matched['sku']
            namespace.os_version = matched['version']
            namespace.storage_profile = (StorageProfile.SAPirImage
                                         if namespace.use_unmanaged_disk
                                         else StorageProfile.ManagedPirImage)
        else:
            # last try: is it a custom image name?
            compute_client = _compute_client_factory()
            try:
                compute_client.images.get(namespace.resource_group_name, image)
                image = namespace.image = _get_resource_id(image, namespace.resource_group_name,
                                                           'images', 'Microsoft.Compute')
                namespace.storage_profile = StorageProfile.ManagedCustomImage
            except CloudError:
                err = 'Invalid image "{}". Use a custom image name, id, or pick one from {}'
                raise CLIError(err.format(image, [x['urnAlias'] for x in images]))

    if namespace.storage_profile == StorageProfile.ManagedCustomImage:
        res = parse_resource_id(image)
        compute_client = _compute_client_factory()
        image_info = compute_client.images.get(res['resource_group'], res['name'])
        # pylint: disable=no-member
        namespace.os_type = image_info.storage_profile.os_disk.os_type.value
        namespace.image_data_disks = image_info.storage_profile.data_disks

    if not namespace.os_type:
        namespace.os_type = 'windows' if 'windows' in namespace.os_offer.lower() else 'linux'