# -*- coding: utf-8 -*- #
# Copyright 2017 Google LLC. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Command for creating instance templates running Docker images."""


from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import containers_utils
from googlecloudsdk.api_lib.compute import image_utils
from googlecloudsdk.api_lib.compute import instance_template_utils
from googlecloudsdk.api_lib.compute import instance_utils
from googlecloudsdk.api_lib.compute import metadata_utils
from googlecloudsdk.api_lib.compute import utils
from googlecloudsdk.api_lib.compute.instances.create import utils as create_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.compute import completers
from googlecloudsdk.command_lib.compute import flags
from googlecloudsdk.command_lib.compute.instance_templates import flags as instance_templates_flags
from googlecloudsdk.command_lib.compute.instances import flags as instances_flags
from googlecloudsdk.command_lib.compute.resource_policies import flags as maintenance_flags
from googlecloudsdk.command_lib.util.args import labels_util
from googlecloudsdk.core import log


def _Args(
    parser,
    release_track,
    container_mount_enabled=False,
    enable_guest_accelerators=False,
    support_multi_writer=True,
    support_region_instance_template=False,
    support_specific_then_x_affinity=False,
    support_any_reservation_then_fail_affinity=False,
    support_disk_labels=False,
    support_ipv6_only=False,
    support_flex_start=False,
    support_skip_guest_os_shutdown=False,
    support_workload_identity_config=False,
    support_vsock_mode=False,
):
  """Add flags shared by all release tracks."""
  parser.display_info.AddFormat(instance_templates_flags.DEFAULT_LIST_FORMAT)
  metadata_utils.AddMetadataArgs(parser)
  instances_flags.AddDiskArgs(
      parser, container_mount_enabled=container_mount_enabled
  )
  instances_flags.AddCreateDiskArgs(
      parser,
      container_mount_enabled=container_mount_enabled,
      support_multi_writer=support_multi_writer,
      support_disk_labels=support_disk_labels,
  )
  if release_track == base.ReleaseTrack.ALPHA:
    instances_flags.AddLocalSsdArgsWithSize(parser)
  elif release_track == base.ReleaseTrack.BETA:
    instances_flags.AddLocalSsdArgs(parser)
  instances_flags.AddCanIpForwardArgs(parser)
  instances_flags.AddContainerMountDiskFlag(parser)
  instances_flags.AddAddressArgs(
      parser,
      instances=False,
      containers=True,
      support_ipv6_only=support_ipv6_only,
  )
  instances_flags.AddMachineTypeArgs(parser)
  deprecate_maintenance_policy = release_track in [base.ReleaseTrack.ALPHA]
  instances_flags.AddMaintenancePolicyArgs(parser, deprecate_maintenance_policy)
  instances_flags.AddNoRestartOnFailureArgs(parser)
  instances_flags.AddPreemptibleVmArgs(parser)
  instances_flags.AddServiceAccountAndScopeArgs(parser, False)
  instances_flags.AddTagsArgs(parser)
  instances_flags.AddCustomMachineTypeArgs(parser)
  instances_flags.AddNetworkArgs(parser)
  instances_flags.AddKonletArgs(parser)
  instances_flags.AddImageArgs(parser)
  instances_flags.AddMinCpuPlatformArgs(parser, release_track)
  instances_flags.AddNetworkTierArgs(parser, instance=True)
  instances_flags.AddConfidentialComputeArgs(parser)
  instances_flags.AddShieldedInstanceConfigArgs(parser)
  instances_flags.AddIPv6AddressArgs(parser)
  instances_flags.AddIPv6PrefixLengthArgs(parser)
  labels_util.AddCreateLabelsFlags(parser)
  instances_flags.AddPrivateNetworkIpArgs(parser)
  instances_flags.AddStackTypeArgs(parser, support_ipv6_only)
  instances_flags.AddIpv6NetworkTierArgs(parser)
  instances_flags.AddInternalIPv6AddressArgs(parser)
  instances_flags.AddInternalIPv6PrefixLengthArgs(parser)
  maintenance_flags.AddResourcePoliciesArgs(
      parser, 'added to', 'instance-template'
  )
  instances_flags.AddReservationAffinityGroup(
      parser,
      group_text="""Specifies the reservation for instances created from this template.""",
      affinity_text="""The type of reservation for instances created from this template.""",
      support_specific_then_x_affinity=support_specific_then_x_affinity,
      support_any_reservation_then_fail_affinity=support_any_reservation_then_fail_affinity,
  )
  instances_flags.AddProvisioningModelVmArgs(
      parser, support_flex_start=support_flex_start
  )

  if enable_guest_accelerators:
    instances_flags.AddAcceleratorArgs(parser)

  flags.AddRegionFlag(
      parser, resource_type='instance template', operation_type='create'
  )

  if support_region_instance_template:
    parser.add_argument(
        '--subnet-region', help='Specifies the region of the subnetwork.'
    )

  parser.add_argument(
      '--description',
      help='Specifies a textual description for the instance template.',
  )

  CreateWithContainer.InstanceTemplateArg = (
      instance_templates_flags.MakeInstanceTemplateArg()
  )
  CreateWithContainer.InstanceTemplateArg.AddArgument(
      parser, operation_type='create'
  )

  parser.display_info.AddCacheUpdater(completers.InstanceTemplatesCompleter)
  if support_skip_guest_os_shutdown:
    instances_flags.AddSkipGuestOsShutdownArgs(parser)
  if support_workload_identity_config:
    instances_flags.AddWorkloadIdentityConfigArgs(parser)
  if support_vsock_mode:
    instances_flags.AddVsockModeArgs(parser)


@base.Deprecate(
    is_removed=False,
    warning=(
        'The option to deploy a container during VM creation using the'
        ' container startup agent is deprecated. Use alternative services to'
        ' run containers on your VMs. Learn more at'
        ' https://cloud.google.com/compute/docs/containers/migrate-containers.'
    ),
    error=(
        'The option to deploy a container during VM creation using the'
        ' container startup agent is deprecated. Use alternative services to'
        ' run containers on your VMs. Learn more at'
        ' https://cloud.google.com/compute/docs/containers/migrate-containers.'
    ),
)
# TODO(b/305707695):Change @base.DefaultUniverseOnly to
# @base.UniverseCompatible once b/305707695 is fixed.
# See go/gcloud-cli-running-tpc-tests.
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.PREVIEW)
class CreateWithContainer(base.CreateCommand):
  """Command for creating VM instance templates hosting Docker images."""

  _support_specific_then_x_affinity = False
  _support_any_reservation_then_fail_affinity = False
  _support_disk_labels = False
  _support_skip_guest_os_shutdown = True
  _support_workload_identity_config = False
  _support_vsock_mode = False

  @staticmethod
  def Args(parser):
    _Args(
        parser,
        base.ReleaseTrack.GA,
        container_mount_enabled=True,
        support_multi_writer=False,
        support_region_instance_template=False,
        support_specific_then_x_affinity=False,
        support_any_reservation_then_fail_affinity=False,
        support_disk_labels=False,
        support_ipv6_only=True,
        support_skip_guest_os_shutdown=True,
        support_workload_identity_config=False,
    )
    instances_flags.AddPrivateIpv6GoogleAccessArgForTemplate(
        parser, utils.COMPUTE_GA_API_VERSION
    )

  def _ValidateArgs(self, args):
    instances_flags.ValidateKonletArgs(args)
    instances_flags.ValidateDiskCommonFlags(args)
    instances_flags.ValidateServiceAccountAndScopeArgs(args)
    instances_flags.ValidateNicFlags(args)
    instances_flags.ValidateReservationAffinityGroup(args)
    if instance_utils.UseExistingBootDisk(args.disk or []):
      raise exceptions.InvalidArgumentException(
          '--disk', 'Boot disk specified for containerized VM.'
      )

  def _GetBootDiskSize(self, args):
    boot_disk_size_gb = utils.BytesToGb(args.boot_disk_size)
    utils.WarnIfDiskSizeIsTooSmall(boot_disk_size_gb, args.boot_disk_type)
    return boot_disk_size_gb

  def _GetInstanceTemplateRef(self, args, holder):
    return CreateWithContainer.InstanceTemplateArg.ResolveAsResource(
        args, holder.resources
    )

  def _GetUserMetadata(
      self,
      args,
      client,
      instance_template_ref,
      container_mount_disk_enabled=False,
      container_mount_disk=None,
  ):
    user_metadata = instance_utils.GetValidatedMetadata(args, client)
    return containers_utils.CreateKonletMetadataMessage(
        client.messages,
        args,
        instance_template_ref.Name(),
        user_metadata,
        container_mount_disk_enabled,
        container_mount_disk,
    )

  def _GetNetworkInterfaces(self, args, client, holder):
    if args.network_interface:
      return instance_template_utils.CreateNetworkInterfaceMessages(
          resources=holder.resources,
          scope_lister=flags.GetDefaultScopeLister(client),
          messages=client.messages,
          network_interface_arg=args.network_interface,
          subnet_region=args.region,
      )
    stack_type = getattr(args, 'stack_type', None)
    ipv6_network_tier = getattr(args, 'ipv6_network_tier', None)
    ipv6_address = getattr(args, 'ipv6_address', None)
    ipv6_prefix_length = getattr(args, 'ipv6_prefix_length', None)
    external_ipv6_address = getattr(args, 'external_ipv6_address', None)
    external_ipv6_prefix_length = getattr(
        args, 'external_ipv6_prefix_length', None
    )
    internal_ipv6_address = getattr(args, 'internal_ipv6_address', None)
    internal_ipv6_prefix_length = getattr(
        args, 'internal_ipv6_prefix_length', None
    )
    return [
        instance_template_utils.CreateNetworkInterfaceMessage(
            resources=holder.resources,
            scope_lister=flags.GetDefaultScopeLister(client),
            messages=client.messages,
            network=args.network,
            private_ip=args.private_network_ip,
            subnet_region=args.region,
            subnet=args.subnet,
            address=(
                instance_template_utils.EPHEMERAL_ADDRESS
                if not args.no_address and not args.address
                else args.address
            ),
            network_tier=getattr(args, 'network_tier', None),
            stack_type=stack_type,
            ipv6_network_tier=ipv6_network_tier,
            ipv6_address=ipv6_address,
            ipv6_prefix_length=ipv6_prefix_length,
            external_ipv6_address=external_ipv6_address,
            external_ipv6_prefix_length=external_ipv6_prefix_length,
            internal_ipv6_address=internal_ipv6_address,
            internal_ipv6_prefix_length=internal_ipv6_prefix_length,
        )
    ]

  def _GetScheduling(self, args, client):
    skip_guest_os_shutdown = None
    if self._support_skip_guest_os_shutdown and args.IsKnownAndSpecified(
        'skip_guest_os_shutdown'
    ):
      skip_guest_os_shutdown = args.skip_guest_os_shutdown
    vsock_mode = None
    if self._support_vsock_mode and args.IsSpecified('vsock_mode'):
      vsock_mode = args.vsock_mode
    return instance_utils.CreateSchedulingMessage(
        messages=client.messages,
        maintenance_policy=args.maintenance_policy,
        preemptible=args.preemptible,
        provisioning_model=args.provisioning_model,
        restart_on_failure=args.restart_on_failure,
        skip_guest_os_shutdown=skip_guest_os_shutdown,
        vsock_mode=vsock_mode,
    )

  def _GetServiceAccounts(self, args, client):
    if args.no_service_account:
      service_account = None
    else:
      service_account = args.service_account
    return instance_utils.CreateServiceAccountMessages(
        messages=client.messages,
        scopes=[] if args.no_scopes else args.scopes,
        service_account=service_account,
    )

  def _GetImageUri(self, args, client, holder, instance_template_ref):
    if (
        args.IsSpecified('image')
        or args.IsSpecified('image_family')
        or args.IsSpecified('image_project')
    ):
      image_expander = image_utils.ImageExpander(client, holder.resources)
      image_uri, _ = image_expander.ExpandImageFlag(
          user_project=instance_template_ref.project,
          image=args.image,
          image_family=args.image_family,
          image_project=args.image_project,
      )
      if holder.resources.Parse(image_uri).project != 'cos-cloud':
        log.warning(
            'This container deployment mechanism requires a '
            'Container-Optimized OS image in order to work. Select an '
            'image from a cos-cloud project (cos-stable, cos-beta, '
            'cos-dev image families).'
        )
    else:
      image_uri = containers_utils.ExpandKonletCosImageFlag(client)
    return image_uri

  def _GetMachineType(self, args):
    return instance_utils.InterpretMachineType(
        machine_type=args.machine_type,
        custom_cpu=args.custom_cpu,
        custom_memory=args.custom_memory,
        ext=getattr(args, 'custom_extensions', None),
        vm_type=getattr(args, 'custom_vm_type', None),
    )

  def _GetDisks(
      self,
      args,
      client,
      holder,
      instance_template_ref,
      image_uri,
      match_container_mount_disks=False,
  ):
    boot_disk_size_gb = self._GetBootDiskSize(args)
    # create boot disk through args.boot_disk_device_name
    create_boot_disk = not (
        instance_utils.UseExistingBootDisk(
            (args.disk or []) + (args.create_disk or [])
        )
    )
    return instance_template_utils.CreateDiskMessages(
        args,
        client,
        holder.resources,
        instance_template_ref.project,
        image_uri,
        boot_disk_size_gb,
        create_boot_disk=create_boot_disk,
        match_container_mount_disks=match_container_mount_disks,
        support_disk_labels=self._support_disk_labels,
    )

  def Run(self, args):
    """Issues an InstanceTemplates.Insert request.

    Args:
      args: the argparse arguments that this command was invoked with.

    Returns:
      an InstanceTemplate message object
    """
    self._ValidateArgs(args)
    instances_flags.ValidateNetworkTierArgs(args)

    holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
    container_mount_disk = instances_flags.GetValidatedContainerMountDisk(
        holder, args.container_mount_disk, args.disk, args.create_disk
    )

    client = holder.client
    instance_template_ref = self._GetInstanceTemplateRef(args, holder)
    image_uri = self._GetImageUri(args, client, holder, instance_template_ref)
    labels = containers_utils.GetLabelsMessageWithCosVersion(
        None, image_uri, holder.resources, client.messages.InstanceProperties
    )
    argument_labels = labels_util.ParseCreateArgs(
        args, client.messages.InstanceProperties.LabelsValue
    )
    if argument_labels:
      labels.additionalProperties.extend(argument_labels.additionalProperties)
    metadata = self._GetUserMetadata(
        args,
        client,
        instance_template_ref,
        container_mount_disk_enabled=True,
        container_mount_disk=container_mount_disk,
    )
    network_interfaces = self._GetNetworkInterfaces(args, client, holder)
    scheduling = self._GetScheduling(args, client)
    service_accounts = self._GetServiceAccounts(args, client)
    machine_type = self._GetMachineType(args)
    disks = self._GetDisks(
        args,
        client,
        holder,
        instance_template_ref,
        image_uri,
        match_container_mount_disks=True,
    )
    confidential_instance_config = (
        create_utils.BuildConfidentialInstanceConfigMessage(
            messages=client.messages,
            args=args,
            support_confidential_compute_type=True,
            support_confidential_compute_type_tdx=True,
        )
    )
    workload_identity_config = (
        instance_utils.CreateWorkloadIdentityConfigMessage(
            args, client.messages, self._support_workload_identity_config
        )
    )

    properties = client.messages.InstanceProperties(
        machineType=machine_type,
        disks=disks,
        canIpForward=args.can_ip_forward,
        confidentialInstanceConfig=confidential_instance_config,
        labels=labels,
        metadata=metadata,
        minCpuPlatform=args.min_cpu_platform,
        networkInterfaces=network_interfaces,
        serviceAccounts=service_accounts,
        scheduling=scheduling,
        tags=containers_utils.CreateTagsMessage(client.messages, args.tags),
    )

    if self._support_workload_identity_config and workload_identity_config:
      properties.workloadIdentityConfig = workload_identity_config

    if args.resource_policies:
      properties.resourcePolicies = args.resource_policies

    if args.private_ipv6_google_access_type is not None:
      properties.privateIpv6GoogleAccess = (
          instances_flags.GetPrivateIpv6GoogleAccessTypeFlagMapperForTemplate(
              client.messages
          ).GetEnumForChoice(args.private_ipv6_google_access_type)
      )

    shielded_instance_config_message = (
        create_utils.BuildShieldedInstanceConfigMessage(
            messages=client.messages, args=args
        )
    )
    if shielded_instance_config_message:
      properties.shieldedInstanceConfig = shielded_instance_config_message

    properties.reservationAffinity = instance_utils.GetReservationAffinity(
        args,
        client,
        support_specific_then_x_affinity=self._support_specific_then_x_affinity,
        support_any_reservation_then_fail_affinity=self._support_any_reservation_then_fail_affinity,
    )

    request = client.messages.ComputeInstanceTemplatesInsertRequest(
        instanceTemplate=client.messages.InstanceTemplate(
            properties=properties,
            description=args.description,
            name=instance_template_ref.Name(),
        ),
        project=instance_template_ref.project,
    )

    return client.MakeRequests(
        [(client.apitools_client.instanceTemplates, 'Insert', request)]
    )


@base.ReleaseTracks(base.ReleaseTrack.BETA)
class CreateWithContainerBeta(CreateWithContainer):
  """Command for creating VM instance templates hosting Docker images."""

  _support_specific_then_x_affinity = True
  _support_any_reservation_then_fail_affinity = True
  _support_disk_labels = True
  _support_skip_guest_os_shutdown = True
  _support_workload_identity_config = False

  @staticmethod
  def Args(parser):
    _Args(
        parser,
        base.ReleaseTrack.BETA,
        container_mount_enabled=True,
        enable_guest_accelerators=True,
        support_region_instance_template=False,
        support_specific_then_x_affinity=True,
        support_any_reservation_then_fail_affinity=True,
        support_disk_labels=True,
        support_ipv6_only=True,
        support_flex_start=True,
        support_skip_guest_os_shutdown=True,
        support_workload_identity_config=False,
        support_vsock_mode=False,
    )
    instances_flags.AddPrivateIpv6GoogleAccessArgForTemplate(
        parser, utils.COMPUTE_BETA_API_VERSION
    )

  def _ValidateArgs(self, args):
    super(CreateWithContainerBeta, self)._ValidateArgs(args)
    instances_flags.ValidateLocalSsdFlags(args)

  def Run(self, args):
    """Issues an InstanceTemplates.Insert request.

    Args:
      args: the argparse arguments that this command was invoked with.

    Returns:
      an InstanceTemplate message object
    """
    self._ValidateArgs(args)
    instances_flags.ValidateNetworkTierArgs(args)

    holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
    container_mount_disk = instances_flags.GetValidatedContainerMountDisk(
        holder, args.container_mount_disk, args.disk, args.create_disk
    )
    client = holder.client
    instance_template_ref = self._GetInstanceTemplateRef(args, holder)
    image_uri = self._GetImageUri(args, client, holder, instance_template_ref)
    labels = containers_utils.GetLabelsMessageWithCosVersion(
        None, image_uri, holder.resources, client.messages.InstanceProperties
    )
    argument_labels = labels_util.ParseCreateArgs(
        args, client.messages.InstanceProperties.LabelsValue
    )
    if argument_labels:
      labels.additionalProperties.extend(argument_labels.additionalProperties)

    metadata = self._GetUserMetadata(
        args,
        client,
        instance_template_ref,
        container_mount_disk_enabled=True,
        container_mount_disk=container_mount_disk,
    )
    network_interfaces = self._GetNetworkInterfaces(args, client, holder)
    scheduling = self._GetScheduling(args, client)
    service_accounts = self._GetServiceAccounts(args, client)
    machine_type = self._GetMachineType(args)
    disks = self._GetDisks(
        args,
        client,
        holder,
        instance_template_ref,
        image_uri,
        match_container_mount_disks=True,
    )
    confidential_instance_config = (
        create_utils.BuildConfidentialInstanceConfigMessage(
            messages=client.messages,
            args=args,
            support_confidential_compute_type=True,
            support_confidential_compute_type_tdx=True,
        )
    )
    guest_accelerators = (
        instance_template_utils.CreateAcceleratorConfigMessages(
            client.messages, getattr(args, 'accelerator', None)
        )
    )
    workload_identity_config = (
        instance_utils.CreateWorkloadIdentityConfigMessage(
            args, client.messages, self._support_workload_identity_config
        )
    )

    properties = client.messages.InstanceProperties(
        machineType=machine_type,
        disks=disks,
        canIpForward=args.can_ip_forward,
        confidentialInstanceConfig=confidential_instance_config,
        labels=labels,
        metadata=metadata,
        minCpuPlatform=args.min_cpu_platform,
        networkInterfaces=network_interfaces,
        serviceAccounts=service_accounts,
        scheduling=scheduling,
        tags=containers_utils.CreateTagsMessage(client.messages, args.tags),
        guestAccelerators=guest_accelerators,
    )

    if self._support_workload_identity_config and workload_identity_config:
      properties.workloadIdentityConfig = workload_identity_config

    if args.resource_policies:
      properties.resourcePolicies = args.resource_policies

    if args.private_ipv6_google_access_type is not None:
      properties.privateIpv6GoogleAccess = (
          instances_flags.GetPrivateIpv6GoogleAccessTypeFlagMapperForTemplate(
              client.messages
          ).GetEnumForChoice(args.private_ipv6_google_access_type)
      )

    shielded_instance_config_message = (
        create_utils.BuildShieldedInstanceConfigMessage(
            messages=client.messages, args=args
        )
    )
    if shielded_instance_config_message:
      properties.shieldedInstanceConfig = shielded_instance_config_message

    properties.reservationAffinity = instance_utils.GetReservationAffinity(
        args,
        client,
        support_specific_then_x_affinity=self._support_specific_then_x_affinity,
        support_any_reservation_then_fail_affinity=self._support_any_reservation_then_fail_affinity,
    )

    request = client.messages.ComputeInstanceTemplatesInsertRequest(
        instanceTemplate=client.messages.InstanceTemplate(
            properties=properties,
            description=args.description,
            name=instance_template_ref.Name(),
        ),
        project=instance_template_ref.project,
    )

    return client.MakeRequests(
        [(client.apitools_client.instanceTemplates, 'Insert', request)]
    )


@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class CreateWithContainerAlpha(CreateWithContainerBeta):
  """Command for creating VM instance templates hosting Docker images."""

  _support_specific_then_x_affinity = True
  _support_any_reservation_then_fail_affinity = True
  _support_disk_labels = True
  _support_ipv6_only = True
  _support_skip_guest_os_shutdown = True
  _support_workload_identity_config = True
  _support_vsock_mode = True

  @staticmethod
  def Args(parser):
    _Args(
        parser,
        base.ReleaseTrack.ALPHA,
        container_mount_enabled=True,
        enable_guest_accelerators=True,
        support_region_instance_template=True,
        support_specific_then_x_affinity=True,
        support_any_reservation_then_fail_affinity=True,
        support_disk_labels=True,
        support_ipv6_only=True,
        support_flex_start=True,
        support_skip_guest_os_shutdown=True,
        support_workload_identity_config=True,
        support_vsock_mode=True,
    )
    instances_flags.AddLocalNvdimmArgs(parser)
    instances_flags.AddPrivateIpv6GoogleAccessArgForTemplate(
        parser, utils.COMPUTE_ALPHA_API_VERSION
    )
    instances_flags.AddIPv6AddressAlphaArgs(parser)
    instances_flags.AddIPv6PrefixLengthAlphaArgs(parser)

  def Run(self, args):
    """Issues an InstanceTemplates.Insert request.

    Args:
      args: the argparse arguments that this command was invoked with.

    Returns:
      an InstanceTemplate message object
    """
    self._ValidateArgs(args)
    instances_flags.ValidateNetworkTierArgs(args)

    holder = base_classes.ComputeApiHolder(self.ReleaseTrack())
    container_mount_disk = instances_flags.GetValidatedContainerMountDisk(
        holder, args.container_mount_disk, args.disk, args.create_disk
    )

    client = holder.client
    instance_template_ref = self._GetInstanceTemplateRef(args, holder)
    image_uri = self._GetImageUri(args, client, holder, instance_template_ref)
    labels = containers_utils.GetLabelsMessageWithCosVersion(
        None, image_uri, holder.resources, client.messages.InstanceProperties
    )
    argument_labels = labels_util.ParseCreateArgs(
        args, client.messages.InstanceProperties.LabelsValue
    )
    if argument_labels:
      labels.additionalProperties.extend(argument_labels.additionalProperties)

    metadata = self._GetUserMetadata(
        args,
        client,
        instance_template_ref,
        container_mount_disk_enabled=True,
        container_mount_disk=container_mount_disk,
    )
    network_interfaces = self._GetNetworkInterfaces(args, client, holder)
    scheduling = self._GetScheduling(args, client)
    service_accounts = self._GetServiceAccounts(args, client)
    machine_type = self._GetMachineType(args)
    disks = self._GetDisks(
        args,
        client,
        holder,
        instance_template_ref,
        image_uri,
        match_container_mount_disks=True,
    )
    confidential_instance_config = (
        create_utils.BuildConfidentialInstanceConfigMessage(
            messages=client.messages,
            args=args,
            support_confidential_compute_type=True,
            support_confidential_compute_type_tdx=True,
        )
    )
    guest_accelerators = (
        instance_template_utils.CreateAcceleratorConfigMessages(
            client.messages, getattr(args, 'accelerator', None)
        )
    )
    workload_identity_config = (
        instance_utils.CreateWorkloadIdentityConfigMessage(
            args, client.messages, self._support_workload_identity_config
        )
    )

    properties = client.messages.InstanceProperties(
        machineType=machine_type,
        disks=disks,
        canIpForward=args.can_ip_forward,
        confidentialInstanceConfig=confidential_instance_config,
        labels=labels,
        metadata=metadata,
        minCpuPlatform=args.min_cpu_platform,
        networkInterfaces=network_interfaces,
        serviceAccounts=service_accounts,
        scheduling=scheduling,
        tags=containers_utils.CreateTagsMessage(client.messages, args.tags),
        guestAccelerators=guest_accelerators,
    )

    if self._support_workload_identity_config and workload_identity_config:
      properties.workloadIdentityConfig = workload_identity_config

    if args.resource_policies is not None:
      properties.resourcePolicies = args.resource_policies

    if args.private_ipv6_google_access_type is not None:
      properties.privateIpv6GoogleAccess = (
          instances_flags.GetPrivateIpv6GoogleAccessTypeFlagMapperForTemplate(
              client.messages
          ).GetEnumForChoice(args.private_ipv6_google_access_type)
      )

    shielded_instance_config_message = (
        create_utils.BuildShieldedInstanceConfigMessage(
            messages=client.messages, args=args
        )
    )
    if shielded_instance_config_message:
      properties.shieldedInstanceConfig = shielded_instance_config_message

    properties.reservationAffinity = instance_utils.GetReservationAffinity(
        args,
        client,
        support_specific_then_x_affinity=self._support_specific_then_x_affinity,
        support_any_reservation_then_fail_affinity=self._support_any_reservation_then_fail_affinity,
    )

    request = client.messages.ComputeInstanceTemplatesInsertRequest(
        instanceTemplate=client.messages.InstanceTemplate(
            properties=properties,
            description=args.description,
            name=instance_template_ref.Name(),
        ),
        project=instance_template_ref.project,
    )

    return client.MakeRequests(
        [(client.apitools_client.instanceTemplates, 'Insert', request)]
    )


CreateWithContainer.detailed_help = {
    'brief': """\
    Creates a Compute Engine a virtual machine instance template that runs
    a Docker container.
    """,
    'DESCRIPTION': """\
        *{command}* creates a Compute Engine virtual
        machine instance template that runs a container image. To create
        an instance template named 'instance-template-1' that runs the
        'busybox' image, run:

          $ {command} instance-template-1 \
             --container-image=gcr.io/google-containers/busybox

        For more examples, refer to the *EXAMPLES* section below.
        """,
    'EXAMPLES': """\
        To create a template named 'instance-template-1' that runs the
        gcr.io/google-containers/busybox image and executes 'echo "Hello world"'
        as a command, run:

          $ {command} instance-template-1 \
            --container-image=gcr.io/google-containers/busybox \
            --container-command='echo "Hello world"'

        To create a template running gcr.io/google-containers/busybox in
        privileged mode, run:

          $ {command} instance-template-1 \
            --container-image=gcr.io/google-containers/busybox \
            --container-privileged
        """,
}
