Skip to content
94 changes: 94 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 @@ -474,6 +474,51 @@
az image builder validator show -n myTemplate -g myGroup --defer
"""

helps['image builder optimizer'] = """
type: group
short-summary: Manage image builder template optimizer.
"""

helps['image builder optimizer add'] = """
type: command
short-summary: Add optimizer to an existing image builder template.
long-summary: Must be used with --defer
examples:
- name: Add optimizer for improving VM boot time by optimizing the final customized image output.
text: |
az image builder optimizer add -n myTemplate -g myGroup --type vmBoot --state Enabled --defer
"""

helps['image builder optimizer remove'] = """
type: command
short-summary: Remove optimizer from an existing image builder template.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
short-summary: Remove optimizer from an existing image builder template.
short-summary: Remove an optimizer from an existing image builder template.

long-summary: Must be used with --defer
examples:
- name: Remove optimizer from an existing image builder template.
text: |
az image builder optimizer remove -n myTemplate -g myGroup --type vmBoot --defer
"""

helps['image builder optimizer clear'] = """
type: command
short-summary: Remove all optimizers from an existing image builder template.
long-summary: Must be used with --defer
examples:
- name: Remove all optimizers from an existing image builder template.

@zhoxing-ms zhoxing-ms May 12, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
short-summary: Remove all optimizers from an existing image builder template.
long-summary: Must be used with --defer
examples:
- name: Remove all optimizers from an existing image builder template.
short-summary: Clear all optimizers from an existing image builder template.
long-summary: Must be used with --defer
examples:
- name: Clear all optimizers from an existing image builder template.

Just a small suggestion. The help message of clear should be distinguished from remove, so as to avoid confusion for customers

text: |
az image builder optimizer clear -n myTemplate -g myGroup --defer
"""

helps['image builder optimizer show'] = """
type: command
short-summary: Show optimizer of an existing image builder template.
long-summary: Must be used with --defer
examples:
- name: Show optimizer of an existing image builder template.
text: |
az image builder optimizer show -n myTemplate -g myGroup --defer
"""

helps['image builder identity'] = """
type: group
short-summary: Manage identities of an image builder template.
Expand Down Expand Up @@ -553,6 +598,10 @@
az image builder output add -n mytemplate -g my-group \\
--output-name my_vhd_image --is-vhd --defer

- name: Add a VHD distributor with specifying storage uri to an image template in the cli object cache.
text: |
az image builder output add -n mytemplate -g my-group \\
--output-name my_vhd_image --is-vhd --vhd-uri https://mystorageaccount.blob.core.windows.net/container/path_to_vhd_file --defer
"""

helps['image builder output clear'] = """
Expand All @@ -567,6 +616,51 @@
long-summary: Must be used with --defer
"""

helps['image builder output versioning'] = """
type: group
short-summary: Manage image builder template output versioner.
long-summary: >
Describe how to generate new x.y.z version number for distribution.
"""

helps['image builder output versioning set'] = """
type: command
short-summary: Set the image builder output versioner of an image builder template.
long-summary: Must be used with --defer.
examples:
- name: Set the image builder output versioner generating version number that will be latest based on existing version numbers.
text: |
az image builder output versioning set -n MyTemplate -g MyResourceGroup --output-name MyVhdImage --scheme Latest --defer

- name: Set the image builder output versioner generating version number that will be latest based on specified major version.
text: |
az image builder output versioning set -n MyTemplate -g MyResourceGroup --output-name MyVhdImage --scheme Latest --major 1 --defer

- name: Set the image builder output versioner generating version number based on version number of source image.
text: |
az image builder output versioning set -n MyTemplate -g MyResourceGroup --output-name MyVhdImage --scheme Source --defer
"""

helps['image builder output versioning remove'] = """
type: command
short-summary: Remove all versioning options on specified outputs.
long-summary: Must be used with --defer
examples:
- name: Remove the image builder output versioner of specified outputs.
text: |
az image builder output versioning remove -n MyTemplate -g MyResourceGroup --output-name MyVhdImage --defer
"""

helps['image builder output versioning show'] = """
type: command
short-summary: Show versioning options on specified outputs.
long-summary: Must be used with --defer
examples:
- name: Show the image builder output versioner of specified outputs.
text: |
az image builder output versioning show -n MyTemplate -g MyResourceGroup --output-name MyVhdImage --defer
"""

helps['image builder run'] = """
type: command
short-summary: Build an image builder template.
Expand Down
158 changes: 146 additions & 12 deletions src/azure-cli/azure/cli/command_modules/vm/_image_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,14 +402,14 @@ def create_image_template( # pylint: disable=too-many-locals, too-many-branches
source=None, scripts=None, checksum=None, managed_image_destinations=None,
shared_image_destinations=None, no_wait=False, image_template=None, identity=None,
vm_size=None, os_disk_size=None, vnet=None, subnet=None, proxy_vm_size=None, build_vm_identities=None,
staging_resource_group=None):
staging_resource_group=None, validator=None):
from azure.mgmt.imagebuilder.models import (ImageTemplate, ImageTemplateSharedImageVersionSource,
ImageTemplatePlatformImageSource, ImageTemplateManagedImageSource,
ImageTemplateShellCustomizer, ImageTemplatePowerShellCustomizer,
ImageTemplateManagedImageDistributor,
ImageTemplateSharedImageDistributor, ImageTemplateIdentity,
ComponentsVrq145SchemasImagetemplateidentityPropertiesUserassignedidentitiesAdditionalproperties, # pylint: disable=line-too-long
ImageTemplateVmProfile, VirtualNetworkConfig)
UserAssignedIdentity, ImageTemplateVmProfile, VirtualNetworkConfig,
ImageTemplatePropertiesValidate, ImageTemplateInVMValidator)

if image_template is not None:
logger.warning('You are using --image-template. All other parameters will be ignored.')
Expand Down Expand Up @@ -444,6 +444,8 @@ def create_image_template( # pylint: disable=too-many-locals, too-many-branches
content['identity'] = obj['identity']
if 'staging_resource_group' in obj:
content['staging_resource_group'] = obj['staging_resource_group']
if 'validate' in obj:
content['validate'] = obj['validate']
return client.virtual_machine_image_templates.begin_create_or_update(
parameters=content, resource_group_name=resource_group_name, image_template_name=image_template_name)

Expand Down Expand Up @@ -495,7 +497,7 @@ def create_image_template( # pylint: disable=too-many-locals, too-many-branches
if not is_valid_resource_id(ide):
ide = resource_id(subscription=subscription_id, resource_group=resource_group_name,
namespace='Microsoft.ManagedIdentity', type='userAssignedIdentities', name=ide)
user_assigned_identities[ide] = ComponentsVrq145SchemasImagetemplateidentityPropertiesUserassignedidentitiesAdditionalproperties() # pylint: disable=line-too-long
user_assigned_identities[ide] = UserAssignedIdentity() # pylint: disable=line-too-long
identity_body = ImageTemplateIdentity(type='UserAssigned', user_assigned_identities=user_assigned_identities)

# VM profile
Expand All @@ -511,12 +513,22 @@ def create_image_template( # pylint: disable=too-many-locals, too-many-branches
if subnet is not None:
vnet_config = VirtualNetworkConfig(subnet_id=subnet, proxy_vm_size=proxy_vm_size)
else:
raise RequiredArgumentMissingError('Usage error: --proxy-vm-size is only configurable when --subnet is specified.')
raise RequiredArgumentMissingError(
'Usage error: --proxy-vm-size is only configurable when --subnet is specified.')
vm_profile = ImageTemplateVmProfile(vm_size=vm_size, os_disk_size_gb=os_disk_size, user_assigned_identities=build_vm_identities, vnet_config=vnet_config) # pylint: disable=line-too-long

validate = None
if validator:
in_vm_validations = []
for item in validator:
validator_item = ImageTemplateInVMValidator()
validator_item.type = item
in_vm_validations.append(validator_item)
validate = ImageTemplatePropertiesValidate(in_vm_validations=in_vm_validations)

image_template = ImageTemplate(source=template_source, distribute=template_destinations,
location=location, build_timeout_in_minutes=build_timeout, tags=(tags or {}),
identity=identity_body, vm_profile=vm_profile,
identity=identity_body, vm_profile=vm_profile, validate=validate,
staging_resource_group=staging_resource_group)

if len(template_scripts) > 0:
Expand All @@ -528,7 +540,7 @@ def create_image_template( # pylint: disable=too-many-locals, too-many-branches

def assign_template_identity(cmd, client, resource_group_name, image_template_name, user_assigned=None):
from azure.mgmt.imagebuilder.models import (ImageTemplateIdentity, ImageTemplateUpdateParameters,
ComponentsVrq145SchemasImagetemplateidentityPropertiesUserassignedidentitiesAdditionalproperties) # pylint: disable=line-too-long
UserAssignedIdentity)

from azure.cli.core.commands.arm import assign_identity as assign_identity_helper

Expand All @@ -551,7 +563,7 @@ def setter(image_template):

updated_user_assigned = list(existing_user_identities.union(add_user_assigned))

default_user_identity = ComponentsVrq145SchemasImagetemplateidentityPropertiesUserassignedidentitiesAdditionalproperties() # pylint: disable=line-too-long
default_user_identity = UserAssignedIdentity() # pylint: disable=line-too-long
user_assigned_identities = dict.fromkeys(updated_user_assigned, default_user_identity)

image_template_identity = ImageTemplateIdentity(type='UserAssigned',
Expand Down Expand Up @@ -632,14 +644,14 @@ def show_build_output(client, resource_group_name, image_template_name, output_n


def add_template_output(cmd, client, resource_group_name, image_template_name, gallery_name=None, location=None, # pylint: disable=line-too-long, unused-argument
output_name=None, is_vhd=None, tags=None,
output_name=None, is_vhd=None, vhd_uri=None, tags=None,
gallery_image_definition=None, gallery_replication_regions=None,
managed_image=None, managed_image_location=None): # pylint: disable=line-too-long, unused-argument
managed_image=None, managed_image_location=None, versioning=None): # pylint: disable=line-too-long, unused-argument

_require_defer(cmd)

from azure.mgmt.imagebuilder.models import (ImageTemplateManagedImageDistributor, ImageTemplateVhdDistributor,
ImageTemplateSharedImageDistributor)
ImageTemplateSharedImageDistributor, DistributeVersioner)
existing_image_template = cached_get(cmd, client.virtual_machine_image_templates.get,
resource_group_name=resource_group_name,
image_template_name=image_template_name)
Expand All @@ -656,8 +668,12 @@ def add_template_output(cmd, client, resource_group_name, image_template_name, g
distributor = ImageTemplateSharedImageDistributor(
run_output_name=output_name or parsed['child_name_1'], gallery_image_id=gallery_image_definition,
replication_regions=gallery_replication_regions or [location])
if versioning:
versioner = DistributeVersioner()
versioner.scheme = versioning
distributor.versioning = versioner
elif is_vhd:
distributor = ImageTemplateVhdDistributor(run_output_name=output_name)
distributor = ImageTemplateVhdDistributor(run_output_name=output_name, uri=vhd_uri)

if distributor:
distributor.artifact_tags = tags or {}
Expand Down Expand Up @@ -715,6 +731,67 @@ def clear_template_output(cmd, client, resource_group_name, image_template_name)
resource_group_name=resource_group_name, image_template_name=image_template_name)


def set_template_output_versioning(cmd, client, resource_group_name, image_template_name, output_name, scheme, major=None): # pylint: disable=line-too-long, unused-argument

_require_defer(cmd)

from azure.mgmt.imagebuilder.models import DistributeVersionerLatest, DistributeVersionerSource
existing_image_template = cached_get(cmd, client.virtual_machine_image_templates.get,
resource_group_name=resource_group_name,
image_template_name=image_template_name)

distribute = [distribute for distribute in existing_image_template.distribute
if distribute.run_output_name.lower() == output_name.lower()] \
if existing_image_template.distribute else []

if not distribute:
raise CLIError("Output with output name {} not in image template distribute list.".format(output_name))

if scheme == 'Latest':
distribute[0].versioning = DistributeVersionerLatest(scheme=scheme, major=major)
else:
distribute[0].versioning = DistributeVersionerSource(scheme=scheme)

return cached_put(cmd, client.virtual_machine_image_templates.begin_create_or_update, parameters=existing_image_template, # pylint: disable=line-too-long
resource_group_name=resource_group_name, image_template_name=image_template_name)


def remove_template_output_versioning(cmd, client, resource_group_name, image_template_name, output_name):
_require_defer(cmd)

existing_image_template = cached_get(cmd, client.virtual_machine_image_templates.get,
resource_group_name=resource_group_name,
image_template_name=image_template_name)

distribute = [distribute for distribute in existing_image_template.distribute
if distribute.run_output_name.lower() == output_name.lower()] \
if existing_image_template.distribute else []

if not distribute:
raise CLIError("Output with output name {} not in image template distribute list.".format(output_name))

distribute[0].versioning = None

return cached_put(cmd, client.virtual_machine_image_templates.begin_create_or_update, parameters=existing_image_template, # pylint: disable=line-too-long
resource_group_name=resource_group_name, image_template_name=image_template_name)


def show_template_output_versioning(cmd, client, resource_group_name, image_template_name, output_name):
_require_defer(cmd)

existing_image_template = cached_get(cmd, client.virtual_machine_image_templates.get,
resource_group_name=resource_group_name,
image_template_name=image_template_name)
distribute = [distribute for distribute in existing_image_template.distribute
if distribute.run_output_name.lower() == output_name.lower()] \
if existing_image_template.distribute else []

if not distribute:
raise CLIError("Output with output name {} not in image template distribute list.".format(output_name))

return distribute[0].versioning


def add_template_customizer(cmd, client, resource_group_name, image_template_name, customizer_name, customizer_type,
script_url=None, inline_script=None, valid_exit_codes=None,
restart_command=None, restart_check_command=None, restart_timeout=None,
Expand Down Expand Up @@ -844,4 +921,61 @@ def show_template_validator(cmd, client, resource_group_name, image_template_nam
image_template_name=image_template_name)
return existing_image_template.validate


def add_template_optimizer(cmd, client, resource_group_name, image_template_name, optimizer_type=None, state=None):
_require_defer(cmd)
existing_image_template = cached_get(cmd, client.virtual_machine_image_templates.get,
resource_group_name=resource_group_name,
image_template_name=image_template_name)

from azure.mgmt.imagebuilder.models import ImageTemplatePropertiesOptimize, ImageTemplatePropertiesOptimizeVmBoot

if optimizer_type == "vmBoot":
vm_boot = ImageTemplatePropertiesOptimizeVmBoot(state=state)
image_template_properties_optimize = ImageTemplatePropertiesOptimize(vm_boot=vm_boot)
existing_image_template.optimize = image_template_properties_optimize

return cached_put(cmd, client.virtual_machine_image_templates.begin_create_or_update,
parameters=existing_image_template, resource_group_name=resource_group_name,
image_template_name=image_template_name)


def remove_template_optimizer(cmd, client, resource_group_name, image_template_name, optimizer_type=None):
_require_defer(cmd)
existing_image_template = cached_get(cmd, client.virtual_machine_image_templates.get,
resource_group_name=resource_group_name,
image_template_name=image_template_name)

if not existing_image_template.optimize:
raise ResourceNotFoundError("No optimize existing in this image template, no need to remove.")

if optimizer_type == "vmBoot":
existing_image_template.optimize.vm_boot = None

return cached_put(cmd, client.virtual_machine_image_templates.begin_create_or_update, parameters=existing_image_template, # pylint: disable=line-too-long
resource_group_name=resource_group_name, image_template_name=image_template_name)


def clear_template_optimizer(cmd, client, resource_group_name, image_template_name):
_require_defer(cmd)
existing_image_template = cached_get(cmd, client.virtual_machine_image_templates.get,
resource_group_name=resource_group_name,
image_template_name=image_template_name)

if not existing_image_template.optimize:
raise ResourceNotFoundError("No optimize existing in this image template, no need to clear.")

existing_image_template.optimize = None

return cached_put(cmd, client.virtual_machine_image_templates.begin_create_or_update, parameters=existing_image_template, # pylint: disable=line-too-long
resource_group_name=resource_group_name, image_template_name=image_template_name)


def show_template_optimizer(cmd, client, resource_group_name, image_template_name):
_require_defer(cmd)

existing_image_template = cached_get(cmd, client.virtual_machine_image_templates.get,
resource_group_name=resource_group_name,
image_template_name=image_template_name)
return existing_image_template.optimize
# endregion
Loading