# -*- coding: utf-8 -*- #
# Copyright 2014 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."""


import collections
import json

from googlecloudsdk.api_lib.compute import base_classes
from googlecloudsdk.api_lib.compute import constants
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 partner_metadata_utils
from googlecloudsdk.api_lib.compute import 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 import resource_manager_tags_utils
from googlecloudsdk.command_lib.compute.instance_templates import flags as instance_templates_flags
from googlecloudsdk.command_lib.compute.instance_templates import mesh_util
from googlecloudsdk.command_lib.compute.instance_templates import service_proxy_aux_data
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.compute.sole_tenancy import flags as sole_tenancy_flags
from googlecloudsdk.command_lib.compute.sole_tenancy import util as sole_tenancy_util
from googlecloudsdk.command_lib.util.apis import arg_utils
from googlecloudsdk.command_lib.util.args import labels_util
from googlecloudsdk.core import log
import six


def _CommonArgs(
    parser,
    release_track,
    support_source_instance,
    support_local_ssd_size=False,
    support_kms=False,
    support_multi_writer=False,
    support_mesh=False,
    support_host_error_timeout_seconds=False,
    support_numa_node_count=False,
    support_visible_core_count=False,
    support_max_run_duration=False,
    support_region_instance_template=False,
    support_subnet_region=False,
    support_replica_zones=True,
    support_local_ssd_recovery_timeout=False,
    support_network_queue_count=False,
    support_maintenance_interval=False,
    support_specific_then_x_affinity=False,
    support_any_reservation_then_fail_affinity=False,
    support_graceful_shutdown=False,
    support_ipv6_only=False,
    support_vlan_nic=True,
    support_watchdog_timer=False,
    support_disk_labels=False,
    support_igmp_query=False,
    support_flex_start=False,
    support_display_device=False,
    support_skip_guest_os_shutdown=False,
    support_preemption_notice_duration=False,
    support_enable_vpc_scoped_dns=False,
    support_workload_identity_config=False,
    support_alias_ipv6_ranges=False,
    support_dns64_eligible=False,
    support_nat64_eligible=False,
):
  """Adding arguments applicable for creating instance templates."""
  parser.display_info.AddFormat(instance_templates_flags.DEFAULT_LIST_FORMAT)
  metadata_utils.AddMetadataArgs(parser)
  instances_flags.AddDiskArgs(parser, enable_kms=support_kms)
  instances_flags.AddCreateDiskArgs(
      parser,
      enable_kms=support_kms,
      support_boot=True,
      support_multi_writer=support_multi_writer,
      support_replica_zones=support_replica_zones,
      support_disk_labels=support_disk_labels,
  )
  if support_local_ssd_size:
    instances_flags.AddLocalSsdArgsWithSize(parser)
  else:
    instances_flags.AddLocalSsdArgs(parser)
  instances_flags.AddCanIpForwardArgs(parser)
  instances_flags.AddAddressArgs(
      parser,
      instances=False,
      support_network_queue_count=support_network_queue_count,
      support_vlan_nic=support_vlan_nic,
      support_ipv6_only=support_ipv6_only,
      support_igmp_query=support_igmp_query,
      support_enable_vpc_scoped_dns=support_enable_vpc_scoped_dns,
      support_alias_ipv6_ranges=support_alias_ipv6_ranges,
      support_dns64_eligible=support_dns64_eligible,
      support_nat64_eligible=support_nat64_eligible,
  )
  instances_flags.AddAcceleratorArgs(parser)
  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.AddImageArgs(parser)
  instances_flags.AddNetworkArgs(parser)
  instances_flags.AddShieldedInstanceConfigArgs(parser)
  labels_util.AddCreateLabelsFlags(parser)
  instances_flags.AddNetworkTierArgs(parser, instance=True)
  instances_flags.AddPrivateNetworkIpArgs(parser)
  instances_flags.AddMinNodeCpuArg(parser)
  instances_flags.AddNestedVirtualizationArgs(parser)
  instances_flags.AddThreadsPerCoreArgs(parser)
  instances_flags.AddEnableUefiNetworkingArgs(parser)
  instances_flags.AddResourceManagerTagsArgs(parser)
  if support_numa_node_count:
    instances_flags.AddNumaNodeCountArgs(parser)
  instances_flags.AddStackTypeArgs(parser, support_ipv6_only)
  instances_flags.AddIpv6NetworkTierArgs(parser)
  maintenance_flags.AddResourcePoliciesArgs(
      parser, 'added to', 'instance-template'
  )
  instances_flags.AddProvisioningModelVmArgs(
      parser,
      support_flex_start=support_flex_start,
  )
  instances_flags.AddInstanceTerminationActionVmArgs(parser)
  instances_flags.AddIPv6AddressArgs(parser)
  instances_flags.AddIPv6PrefixLengthArgs(parser)
  instances_flags.AddInternalIPv6AddressArgs(parser)
  instances_flags.AddInternalIPv6PrefixLengthArgs(parser)
  if support_watchdog_timer:
    instances_flags.AddWatchdogTimerArg(parser)

  if support_max_run_duration:
    instances_flags.AddMaxRunDurationVmArgs(parser)
    instances_flags.AddDiscardLocalSsdVmArgs(parser)

  if support_preemption_notice_duration:
    instances_flags.AddPreemptionNoticeDurationArgs(parser)

  instance_templates_flags.AddServiceProxyConfigArgs(
      parser, release_track=release_track
  )
  if support_mesh:
    instance_templates_flags.AddMeshArgs(parser)

  sole_tenancy_flags.AddNodeAffinityFlagToParser(parser)

  instances_flags.AddLocationHintArg(parser)

  if support_visible_core_count:
    instances_flags.AddVisibleCoreCountArgs(parser)

  instances_flags.AddNetworkPerformanceConfigsArgs(parser)

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

  flags.AddRegionFlag(
      parser, resource_type='subnetwork', operation_type='attach'
  )

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

  Create.InstanceTemplateArg = (
      instance_templates_flags.MakeInstanceTemplateArg()
  )
  Create.InstanceTemplateArg.AddArgument(parser, operation_type='create')
  if support_source_instance:
    instance_templates_flags.MakeSourceInstanceArg().AddArgument(parser)
    instance_templates_flags.AddConfigureDiskArgs(parser)

  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,
  )

  parser.display_info.AddCacheUpdater(completers.InstanceTemplatesCompleter)
  if support_host_error_timeout_seconds:
    instances_flags.AddHostErrorTimeoutSecondsArgs(parser)

  if support_local_ssd_recovery_timeout:
    instances_flags.AddLocalSsdRecoveryTimeoutArgs(parser)

  if support_maintenance_interval:
    instances_flags.AddMaintenanceIntervalArgs(parser)

  if support_graceful_shutdown:
    instances_flags.AddGracefulShutdownArgs(parser, is_create=True)

  instances_flags.AddTurboModeArgs(parser)
  if support_display_device:
    instances_flags.AddDisplayDeviceArg(parser)
  if support_skip_guest_os_shutdown:
    instances_flags.AddSkipGuestOsShutdownArgs(parser)
  if support_workload_identity_config:
    instances_flags.AddWorkloadIdentityConfigArgs(parser)


def _ValidateInstancesFlags(
    args, support_kms=False, support_max_run_duration=False
):
  """Validate flags for instance template that affects instance creation.

  Args:
      args: argparse.Namespace, An object that contains the values for the
        arguments specified in the .Args() method.
      support_kms: If KMS is supported.
      support_max_run_duration: max-run-durrations is supported in instance
        scheduling.
  """
  instances_flags.ValidateDiskCommonFlags(args)
  instances_flags.ValidateDiskBootFlags(args, enable_kms=support_kms)
  instances_flags.ValidateCreateDiskFlags(args)
  instances_flags.ValidateLocalSsdFlags(args)
  instances_flags.ValidateNicFlags(args)
  instances_flags.ValidateServiceAccountAndScopeArgs(args)
  instances_flags.ValidateAcceleratorArgs(args)
  instances_flags.ValidateReservationAffinityGroup(args)
  instances_flags.ValidateNetworkPerformanceConfigsArgs(args)
  instances_flags.ValidateInstanceScheduling(
      args, support_max_run_duration=support_max_run_duration
  )


def _AddSourceInstanceToTemplate(
    compute_api, args, instance_template, support_source_instance
):
  """Set the source instance for the template."""

  if not support_source_instance or not args.source_instance:
    return
  source_instance_arg = instance_templates_flags.MakeSourceInstanceArg()
  source_instance_ref = source_instance_arg.ResolveAsResource(
      args, compute_api.resources
  )
  instance_template.sourceInstance = source_instance_ref.SelfLink()
  if args.configure_disk:
    messages = compute_api.client.messages
    instance_template.sourceInstanceParams = messages.SourceInstanceParams()
    for disk in args.configure_disk:
      disk_config = messages.DiskInstantiationConfig()
      # device-name is required argument with --configure-disk
      disk_config.deviceName = disk.get('device-name')
      disk_config.autoDelete = disk.get('auto-delete')
      instantiate_from = disk.get('instantiate-from')
      if instantiate_from:
        disk_config.instantiateFrom = (
            messages.DiskInstantiationConfig.InstantiateFromValueValuesEnum(
                disk.get('instantiate-from').upper().replace('-', '_')
            )
        )
      disk_config.customImage = disk.get('custom-image')
      instance_template.sourceInstanceParams.diskConfigs.append(disk_config)

  instance_template.properties = None


def BuildShieldedInstanceConfigMessage(messages, args):
  """Common routine for creating instance template.

  Build a shielded VM config message.

  Args:
      messages: The client messages.
      args: the arguments passed to the test.

  Returns:
      A shielded VM config message.
  """
  # Set the default values for ShieldedInstanceConfig parameters

  shielded_instance_config_message = None
  enable_secure_boot = None
  enable_vtpm = None
  enable_integrity_monitoring = None
  if not (
      hasattr(args, 'shielded_vm_secure_boot')
      or hasattr(args, 'shielded_vm_vtpm')
      or hasattr(args, 'shielded_vm_integrity_monitoring')
  ):
    return shielded_instance_config_message

  if (
      not args.IsSpecified('shielded_vm_secure_boot')
      and not args.IsSpecified('shielded_vm_vtpm')
      and not args.IsSpecified('shielded_vm_integrity_monitoring')
  ):
    return shielded_instance_config_message

  if args.shielded_vm_secure_boot is not None:
    enable_secure_boot = args.shielded_vm_secure_boot
  if args.shielded_vm_vtpm is not None:
    enable_vtpm = args.shielded_vm_vtpm
  if args.shielded_vm_integrity_monitoring is not None:
    enable_integrity_monitoring = args.shielded_vm_integrity_monitoring
  # compute message for shielded VM configuration.
  shielded_instance_config_message = (
      instance_utils.CreateShieldedInstanceConfigMessage(
          messages, enable_secure_boot, enable_vtpm, enable_integrity_monitoring
      )
  )

  return shielded_instance_config_message


def BuildConfidentialInstanceConfigMessage(
    messages, args, support_confidential_compute_type=False,
    support_confidential_compute_type_tdx=False, support_snp_svsm=False):
  """Builds a confidential instance configuration message."""
  return instance_utils.CreateConfidentialInstanceMessage(
      messages, args, support_confidential_compute_type,
      support_confidential_compute_type_tdx, support_snp_svsm)


def PackageLabels(labels_cls, labels):
  # Sorted for test stability
  return labels_cls(
      additionalProperties=[
          labels_cls.AdditionalProperty(key=key, value=value)
          for key, value in sorted(six.iteritems(labels))
      ]
  )


# Function copied from labels_util.
# Temporary fix for adoption tracking of Managed Envoy.
# TODO(b/146051298) Remove this fix when structured metadata is available.
def ParseCreateArgsWithServiceProxy(args, labels_cls, labels_dest='labels'):
  """Initializes labels based on args and the given class."""
  labels = getattr(args, labels_dest)
  if getattr(args, 'service_proxy', False):
    if labels is None:
      labels = collections.OrderedDict()
    labels['gce-service-proxy'] = 'on'

  if labels is None:
    return None
  return PackageLabels(labels_cls, labels)


def AddScopesForServiceProxy(args):
  if getattr(args, 'service_proxy', False):
    if args.scopes is None:
      args.scopes = constants.DEFAULT_SCOPES[:]

    if (
        'cloud-platform' not in args.scopes
        and 'https://www.googleapis.com/auth/cloud-platform' not in args.scopes
    ):
      args.scopes.append('cloud-platform')


def AddServiceProxyArgsToMetadata(args):
  """Inserts the Service Proxy arguments provided by the user to the instance metadata.

  Args:
      args: argparse.Namespace, An object that contains the values for the
        arguments specified in the .Args() method.
  """
  if getattr(args, 'service_proxy', False):
    service_proxy_config = collections.OrderedDict()
    proxy_spec = collections.OrderedDict()

    service_proxy_config['_disclaimer'] = service_proxy_aux_data.DISCLAIMER
    service_proxy_config['api-version'] = '0.2'

    # add --service-proxy flag data to metadata.
    if 'serving-ports' in args.service_proxy:
      # convert list of strings to list of integers.
      serving_ports = list(
          map(int, args.service_proxy['serving-ports'].split(';'))
      )
      # find unique ports by converting list of integers to set of integers.
      unique_serving_ports = set(serving_ports)
      # convert it back to list of integers.
      # this is done to make it JSON serializable.
      serving_ports = list(unique_serving_ports)
      service_proxy_config['service'] = {
          'serving-ports': serving_ports,
      }

    if 'proxy-port' in args.service_proxy:
      proxy_spec['proxy-port'] = args.service_proxy['proxy-port']

    if 'tracing' in args.service_proxy:
      proxy_spec['tracing'] = args.service_proxy['tracing']

    if 'access-log' in args.service_proxy:
      proxy_spec['access-log'] = args.service_proxy['access-log']

    if 'use-regional-control-plane' in args.service_proxy:
      proxy_spec['regional-control-plane'] = True

    proxy_spec['network'] = args.service_proxy.get('network', '')

    if 'scope' in args.service_proxy:
      proxy_spec['scope'] = args.service_proxy['scope']

    if 'mesh' in args.service_proxy:
      proxy_spec['mesh'] = args.service_proxy['mesh']

    if 'project-number' in args.service_proxy:
      proxy_spec['project-number'] = args.service_proxy['project-number']

    if 'source' in args.service_proxy:
      proxy_spec['primary-source'] = args.service_proxy['source']
      proxy_spec['secondary-source'] = args.service_proxy['source']

    traffic_interception = collections.OrderedDict()
    if 'intercept-all-outbound-traffic' in args.service_proxy:
      traffic_interception['intercept-all-outbound'] = True
      if 'exclude-outbound-ip-ranges' in args.service_proxy:
        traffic_interception['exclude-outbound-ip-ranges'] = args.service_proxy[
            'exclude-outbound-ip-ranges'
        ].split(';')
      if 'exclude-outbound-port-ranges' in args.service_proxy:
        traffic_interception['exclude-outbound-port-ranges'] = (
            args.service_proxy['exclude-outbound-port-ranges'].split(';')
        )
    if 'intercept-dns' in args.service_proxy:
      traffic_interception['intercept-dns'] = True
    if traffic_interception:
      service_proxy_config['traffic-interception'] = traffic_interception

    if getattr(args, 'service_proxy_xds_version', False):
      proxy_spec['xds-version'] = args.service_proxy_xds_version

    # add --service-proxy-labels flag data to metadata.
    if getattr(args, 'service_proxy_labels', False):
      service_proxy_config['labels'] = args.service_proxy_labels

    args.metadata['enable-osconfig'] = 'true'
    gce_software_declaration = collections.OrderedDict()
    service_proxy_agent_recipe = collections.OrderedDict()

    service_proxy_agent_recipe['name'] = 'install-gce-service-proxy-agent'
    service_proxy_agent_recipe['desired_state'] = 'INSTALLED'

    if getattr(args, 'service_proxy_agent_location', False):
      service_proxy_agent_recipe['installSteps'] = [{
          'scriptRun': {
              'script': (
                  service_proxy_aux_data.startup_script_with_location_template
                  % args.service_proxy_agent_location
              )
          }
      }]
    else:
      service_proxy_agent_recipe['installSteps'] = [
          {'scriptRun': {'script': service_proxy_aux_data.startup_script}}
      ]

    gce_software_declaration['softwareRecipes'] = [service_proxy_agent_recipe]

    args.metadata['gce-software-declaration'] = json.dumps(
        gce_software_declaration
    )
    args.metadata['enable-guest-attributes'] = 'TRUE'

    if proxy_spec:
      service_proxy_config['proxy-spec'] = proxy_spec

    args.metadata['gce-service-proxy'] = json.dumps(service_proxy_config)


def ConfigureMeshTemplate(args, instance_template_ref, network_interfaces):
  """Adds Anthos Service Mesh configuration into the instance template.

  Args:
      args: argparse.Namespace, An object that contains the values for the
        arguments specified in the .Args() method.
      instance_template_ref: Reference to the current instance template to be
        created.
      network_interfaces: network interfaces configured for the instance
        template.
  """

  if getattr(args, 'mesh', False):
    # Add the required scopes.
    if args.scopes is None:
      args.scopes = constants.DEFAULT_SCOPES[:]
    if (
        'cloud-platform' not in args.scopes
        and 'https://www.googleapis.com/auth/cloud-platform' not in args.scopes
    ):
      args.scopes.append('cloud-platform')

    workload_namespace, workload_name = mesh_util.ParseWorkload(
        args.mesh['workload']
    )
    with mesh_util.KubernetesClient(
        gke_cluster=args.mesh['gke-cluster']
    ) as kube_client:
      log.status.Print(
          'Verifying GKE cluster and Anthos Service Mesh installation...'
      )
      namespaces = ['default', 'istio-system', workload_namespace]
      if kube_client.NamespacesExist(
          *namespaces
      ) and kube_client.HasNamespaceReaderPermissions(*namespaces):
        membership_manifest = kube_client.GetMembershipCR()
        # Verify Identity Provider CR existence only.
        _ = kube_client.GetIdentityProviderCR()

        namespace_manifest = kube_client.GetNamespace(workload_namespace)
        workload_manifest = kube_client.GetWorkloadGroupCR(
            workload_namespace, workload_name
        )
        mesh_util.VerifyWorkloadSetup(workload_manifest)

        asm_revision = mesh_util.RetrieveWorkloadRevision(namespace_manifest)
        mesh_config = kube_client.RetrieveMeshConfig(asm_revision)

        log.status.Print(
            'Configuring the instance template for Anthos Service Mesh...'
        )
        project_id = instance_template_ref.project
        mesh_util.ConfigureInstanceTemplate(
            args,
            kube_client,
            project_id,
            network_interfaces[0].network,
            workload_namespace,
            workload_name,
            workload_manifest,
            membership_manifest,
            asm_revision,
            mesh_config,
        )


def _RunCreate(
    compute_api,
    args,
    support_source_instance,
    support_kms=False,
    support_post_key_revocation_action_type=False,
    support_multi_writer=False,
    support_mesh=False,
    support_host_error_timeout_seconds=False,
    support_numa_node_count=False,
    support_visible_core_count=False,
    support_max_run_duration=False,
    support_region_instance_template=False,
    support_subnet_region=False,
    support_confidential_compute_type=False,
    support_confidential_compute_type_tdx=False,
    support_snp_svsm=False,
    support_ipv6_reservation=False,
    support_internal_ipv6_reservation=False,
    support_replica_zones=True,
    support_local_ssd_recovery_timeout=False,
    support_performance_monitoring_unit=False,
    support_partner_metadata=False,
    support_maintenance_interval=False,
    support_specific_then_x_affinity=False,
    support_any_reservation_then_fail_affinity=False,
    support_graceful_shutdown=False,
    support_watchdog_timer=False,
    support_disk_labels=False,
    support_display_device=False,
    support_skip_guest_os_shutdown=False,
    support_preemption_notice_duration=False,
    support_enable_vpc_scoped_dns=False,
    support_workload_identity_config=False,
    support_alias_ipv6_ranges=False,
    support_dns64_eligible=False,
    support_nat64_eligible=False,
):
  """Common routine for creating instance template.

  This is shared between various release tracks.

  Args:
      compute_api: The compute api.
      args: argparse.Namespace, An object that contains the values for the
        arguments specified in the .Args() method.
      support_source_instance: indicates whether source instance is supported.
      support_kms: Indicate whether KMS is integrated or not.
      support_post_key_revocation_action_type: Indicate whether
        post_key_revocation_action_type is supported.
      support_multi_writer: Indicates whether a disk can have multiple writers.
      support_mesh: Indicates whether adding VM to a Anthos Service Mesh is
        supported.
      support_host_error_timeout_seconds: Indicate the timeout in seconds for
        host error detection.
      support_numa_node_count: Indicates whether setting NUMA node count is
        supported.
      support_visible_core_count: Indicates whether setting a custom visible
      support_max_run_duration: Indicate whether max-run-duration or
        termination-time is supported.
      support_region_instance_template: Indicate whether create region instance
        template is supported.
      support_subnet_region: Indicate whether subnet_region flag enhancement
        should be supported.
      support_confidential_compute_type: Indicate what confidential compute type
        is used.
      support_confidential_compute_type_tdx: Indicate if confidential compute
        type 'TDX' is supported.
      support_snp_svsm: Indicate whether Secure VM Service Module (SVSM) is
        supported on AMD SEV-SNP VMs.
      support_ipv6_reservation: Indicate the external IPv6 address is supported.
      support_internal_ipv6_reservation: Indicate the internal IPv6 address is
        supported.
      support_replica_zones: Indicate the replicaZones param is supported for
        create-on-create disk.
      support_local_ssd_recovery_timeout: Indicate whether the local SSD
        recovery timeout is set.
      support_performance_monitoring_unit: Indicate whether the PMU is
        supported.
      support_partner_metadata: Indicate whether partner metadata is supported.
      support_maintenance_interval: Indicate whether maintenance interval was
        set.
      support_specific_then_x_affinity: Indicate whether specific_then_x was
        set.
      support_any_reservation_then_fail_affinity: Indicate whether
        any_reservation_then_fail was set.
      support_graceful_shutdown: Indicate whether graceful shutdown is
        supported.
      support_watchdog_timer: Indicate whether the watchdog timer is supported.
      support_disk_labels: Indicate whether disk labels are supported.
      support_display_device: Indicate whether display device is supported.
      support_skip_guest_os_shutdown: Indicate whether skip guest os shutdown is
        supported.
      support_preemption_notice_duration: Indicate whether preemption notice
        duration is supported.
      support_enable_vpc_scoped_dns: Indicate whether enable-vpc-scoped-dns is
        supported.
      support_workload_identity_config: Indicate whether workload identity
        config is supported.
      support_alias_ipv6_ranges: Indicate whether alias ipv6 range is supported.
    support_dns64_eligible: Indicate whether dns64 is supported.
    support_nat64_eligible: Indicate whether nat64 is supported.

  Returns:
      A resource object dispatched by display.Displayer().
  """
  _ValidateInstancesFlags(
      args,
      support_kms=support_kms,
      support_max_run_duration=support_max_run_duration,
  )
  instances_flags.ValidateNetworkTierArgs(args)

  instance_templates_flags.ValidateServiceProxyFlags(args)
  if support_source_instance:
    instance_templates_flags.ValidateSourceInstanceFlags(args)
  if support_mesh:
    instance_templates_flags.ValidateMeshFlag(args)

  if support_region_instance_template:
    subnet_region_flag = 'region'
    if support_subnet_region:
      subnet_region_flag = 'subnet_region'
    instance_template_region = getattr(args, 'instance_template_region', None)
    subnet_region = getattr(args, subnet_region_flag, None)
    if (subnet_region is not None
        and instance_template_region is not None
        and instance_template_region != subnet_region):
      raise exceptions.InvalidArgumentException(
          '--instance-template-region',
          'Values of `--instance-template-region` and `--{}` must match'.format(
              subnet_region_flag))

  client = compute_api.client

  boot_disk_size_gb = utils.BytesToGb(args.boot_disk_size)
  utils.WarnIfDiskSizeIsTooSmall(boot_disk_size_gb, args.boot_disk_type)

  instance_template_ref = Create.InstanceTemplateArg.ResolveAsResource(
      args, compute_api.resources
  )

  AddScopesForServiceProxy(args)
  AddServiceProxyArgsToMetadata(args)

  if hasattr(args, 'network_interface') and args.network_interface:
    if support_subnet_region:
      subnet_region = getattr(args, 'subnet_region', None)
    else:
      subnet_region = getattr(args, 'region', None)
    network_interfaces = (
        instance_template_utils.CreateNetworkInterfaceMessages
    )(
        resources=compute_api.resources,
        scope_lister=flags.GetDefaultScopeLister(client),
        messages=client.messages,
        network_interface_arg=args.network_interface,
        subnet_region=subnet_region,
        support_enable_vpc_scoped_dns=support_enable_vpc_scoped_dns,
        support_alias_ipv6_ranges=support_alias_ipv6_ranges,
        support_dns64_eligible=support_dns64_eligible,
        support_nat64_eligible=support_nat64_eligible,
    )
  else:
    network_tier = getattr(args, 'network_tier', None)
    stack_type = getattr(args, 'stack_type', None)
    ipv6_network_tier = getattr(args, 'ipv6_network_tier', None)
    external_ipv6_address = getattr(args, 'external_ipv6_address', None)
    external_ipv6_prefix_length = getattr(
        args, 'external_ipv6_prefix_length', None
    )
    ipv6_address = None
    ipv6_prefix_length = None
    internal_ipv6_address = None
    internal_ipv6_prefix_length = None

    if support_subnet_region:
      subnet_region = getattr(args, 'subnet_region', None)
    else:
      subnet_region = getattr(args, 'region', None)

    if support_ipv6_reservation:
      ipv6_address = getattr(args, 'ipv6_address', None)
      ipv6_prefix_length = getattr(args, 'ipv6_prefix_length', None)

    if support_internal_ipv6_reservation:
      internal_ipv6_address = getattr(args, 'internal_ipv6_address', None)
      internal_ipv6_prefix_length = getattr(
          args, 'internal_ipv6_prefix_length', None
      )

    network_interfaces = [
        instance_template_utils.CreateNetworkInterfaceMessage(
            resources=compute_api.resources,
            scope_lister=flags.GetDefaultScopeLister(client),
            messages=client.messages,
            network=args.network,
            private_ip=args.private_network_ip,
            subnet_region=subnet_region,
            subnet=args.subnet,
            address=(
                instance_template_utils.EPHEMERAL_ADDRESS
                if not args.no_address and not args.address
                else args.address
            ),
            network_tier=network_tier,
            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,
        )
    ]

  if support_mesh:
    ConfigureMeshTemplate(args, instance_template_ref, network_interfaces)

  metadata = metadata_utils.ConstructMetadataMessage(
      client.messages,
      metadata=args.metadata,
      metadata_from_file=args.metadata_from_file,
  )

  # Compute the shieldedInstanceConfig message.
  shieldedinstance_config_message = BuildShieldedInstanceConfigMessage(
      messages=client.messages, args=args
  )

  confidential_instance_config_message = BuildConfidentialInstanceConfigMessage(
      messages=client.messages,
      args=args,
      support_confidential_compute_type=support_confidential_compute_type,
      support_confidential_compute_type_tdx=(
          support_confidential_compute_type_tdx
      ),
      support_snp_svsm=support_snp_svsm,
  )

  node_affinities = sole_tenancy_util.GetSchedulingNodeAffinityListFromArgs(
      args, client.messages
  )

  location_hint = None
  if args.IsSpecified('location_hint'):
    location_hint = args.location_hint

  provisioning_model = None
  if hasattr(args, 'provisioning_model') and args.IsSpecified(
      'provisioning_model'
  ):
    provisioning_model = args.provisioning_model

  termination_action = None
  if hasattr(args, 'instance_termination_action') and args.IsSpecified(
      'instance_termination_action'
  ):
    termination_action = args.instance_termination_action

  max_run_duration = None
  if hasattr(args, 'max_run_duration') and args.IsSpecified('max_run_duration'):
    max_run_duration = args.max_run_duration

  termination_time = None
  if hasattr(args, 'termination_time') and args.IsSpecified('termination_time'):
    termination_time = args.termination_time

  discard_local_ssds_at_termination_timestamp = None
  if hasattr(
      args, 'discard_local_ssds_at_termination_timestamp'
  ) and args.IsSpecified('discard_local_ssds_at_termination_timestamp'):
    discard_local_ssds_at_termination_timestamp = (
        args.discard_local_ssds_at_termination_timestamp
    )

  host_error_timeout_seconds = None
  if support_host_error_timeout_seconds and args.IsSpecified(
      'host_error_timeout_seconds'
  ):
    host_error_timeout_seconds = args.host_error_timeout_seconds

  local_ssd_recovery_timeout = None
  if support_local_ssd_recovery_timeout and args.IsSpecified(
      'local_ssd_recovery_timeout'
  ):
    local_ssd_recovery_timeout = args.local_ssd_recovery_timeout

  should_set_maintenance_interval = (
      support_maintenance_interval and args.IsSpecified('maintenance_interval')
  )
  maintenance_interval = (
      args.maintenance_interval if should_set_maintenance_interval else None
  )

  graceful_shutdown = instance_utils.ExtractGracefulShutdownFromArgs(
      args, support_graceful_shutdown
  )

  skip_guest_os_shutdown = None
  if (
      support_skip_guest_os_shutdown
      and args.IsKnownAndSpecified('skip_guest_os_shutdown')
  ):
    skip_guest_os_shutdown = args.skip_guest_os_shutdown

  preemption_notice_duration = None
  if support_preemption_notice_duration and args.IsSpecified(
      'preemption_notice_duration'
  ):
    preemption_notice_duration = args.preemption_notice_duration

  scheduling = instance_utils.CreateSchedulingMessage(
      messages=client.messages,
      maintenance_policy=args.maintenance_policy,
      preemptible=args.preemptible,
      restart_on_failure=args.restart_on_failure,
      node_affinities=node_affinities,
      min_node_cpu=args.min_node_cpu,
      location_hint=location_hint,
      provisioning_model=provisioning_model,
      instance_termination_action=termination_action,
      host_error_timeout_seconds=host_error_timeout_seconds,
      max_run_duration=max_run_duration,
      termination_time=termination_time,
      local_ssd_recovery_timeout=local_ssd_recovery_timeout,
      maintenance_interval=maintenance_interval,
      graceful_shutdown=graceful_shutdown,
      discard_local_ssds_at_termination_timestamp=discard_local_ssds_at_termination_timestamp,
      skip_guest_os_shutdown=skip_guest_os_shutdown,
      preemption_notice_duration=preemption_notice_duration,
  )

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

  # create boot disk through args.boot_disk_device_name
  create_boot_disk = not (
      instance_utils.UseExistingBootDisk(
          (args.disk or []) + (args.create_disk or [])
      )
  )
  if create_boot_disk:
    image_expander = image_utils.ImageExpander(client, compute_api.resources)
    try:
      image_uri, _ = image_expander.ExpandImageFlag(
          user_project=instance_template_ref.project,
          image=args.image,
          image_family=args.image_family,
          image_project=args.image_project,
          return_image_resource=True,
      )
    except utils.ImageNotFoundError as e:
      if args.IsSpecified('image_project'):
        raise e
      image_uri, _ = image_expander.ExpandImageFlag(
          user_project=instance_template_ref.project,
          image=args.image,
          image_family=args.image_family,
          image_project=args.image_project,
          return_image_resource=False,
      )
      raise utils.ImageNotFoundError(
          'The resource [{}] was not found. Is the image located in another '
          'project? Use the --image-project flag to specify the '
          'project where the image is located.'.format(image_uri)
      )
  else:
    image_uri = None

  if args.tags:
    tags = client.messages.Tags(items=args.tags)
  else:
    tags = None

  disks = instance_template_utils.CreateDiskMessages(
      args,
      client,
      compute_api.resources,
      instance_template_ref.project,
      image_uri,
      boot_disk_size_gb=boot_disk_size_gb,
      create_boot_disk=create_boot_disk,
      support_kms=support_kms,
      support_multi_writer=support_multi_writer,
      support_replica_zones=support_replica_zones,
      support_disk_labels=support_disk_labels,
  )

  machine_type = 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),
  )

  guest_accelerators = instance_template_utils.CreateAcceleratorConfigMessages(
      client.messages, getattr(args, 'accelerator', None)
  )

  workload_identity_config = instance_utils.CreateWorkloadIdentityConfigMessage(
      args, client.messages, support_workload_identity_config
  )

  if support_region_instance_template and args.IsSpecified(
      'instance_template_region'
  ):
    instance_template = client.messages.InstanceTemplate(
        properties=client.messages.InstanceProperties(
            machineType=machine_type,
            disks=disks,
            canIpForward=args.can_ip_forward,
            metadata=metadata,
            minCpuPlatform=args.min_cpu_platform,
            networkInterfaces=network_interfaces,
            serviceAccounts=service_accounts,
            scheduling=scheduling,
            tags=tags,
            guestAccelerators=guest_accelerators,
        ),
        description=args.description,
        name=instance_template_ref.Name(),
        region=getattr(args, 'instance_template_region', None),
    )
  else:
    instance_template = client.messages.InstanceTemplate(
        properties=client.messages.InstanceProperties(
            machineType=machine_type,
            disks=disks,
            canIpForward=args.can_ip_forward,
            metadata=metadata,
            minCpuPlatform=args.min_cpu_platform,
            networkInterfaces=network_interfaces,
            serviceAccounts=service_accounts,
            scheduling=scheduling,
            tags=tags,
            guestAccelerators=guest_accelerators,
        ),
        description=args.description,
        name=instance_template_ref.Name(),
    )

  if support_workload_identity_config and workload_identity_config:
    instance_template.properties.workloadIdentityConfig = (
        workload_identity_config
    )

  instance_template.properties.shieldedInstanceConfig = (
      shieldedinstance_config_message
  )

  instance_template.properties.reservationAffinity = (
      instance_utils.GetReservationAffinity(
          args,
          client,
          support_specific_then_x_affinity,
          support_any_reservation_then_fail_affinity,
      )
  )

  instance_template.properties.confidentialInstanceConfig = (
      confidential_instance_config_message
  )

  if args.IsSpecified('network_performance_configs'):
    instance_template.properties.networkPerformanceConfig = (
        instance_utils.GetNetworkPerformanceConfig(args, client)
    )

  if args.IsSpecified('resource_policies'):
    instance_template.properties.resourcePolicies = getattr(
        args, 'resource_policies', []
    )

  if support_post_key_revocation_action_type and args.IsSpecified(
      'post_key_revocation_action_type'
  ):
    instance_template.properties.postKeyRevocationActionType = arg_utils.ChoiceToEnum(
        args.post_key_revocation_action_type,
        client.messages.InstanceProperties.PostKeyRevocationActionTypeValueValuesEnum,
    )

  if args.IsSpecified('key_revocation_action_type'):
    instance_template.properties.keyRevocationActionType = arg_utils.ChoiceToEnum(
        args.key_revocation_action_type,
        client.messages.InstanceProperties.KeyRevocationActionTypeValueValuesEnum,
    )

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

  # Create an AdvancedMachineFeatures message if any of the features requiring
  # one have been specified.
  has_visible_core_count = (
      support_visible_core_count and args.visible_core_count is not None
  )
  if (
      args.enable_nested_virtualization is not None
      or args.threads_per_core is not None
      or (support_numa_node_count and args.numa_node_count is not None)
      or has_visible_core_count
      or args.enable_uefi_networking is not None
      or (
          support_performance_monitoring_unit
          and args.performance_monitoring_unit
      )
      or (support_watchdog_timer and (args.enable_watchdog_timer is not None))
      or (args.turbo_mode is not None)
  ):
    visible_core_count = (
        args.visible_core_count if has_visible_core_count else None
    )

    instance_template.properties.advancedMachineFeatures = (
        instance_utils.CreateAdvancedMachineFeaturesMessage(
            client.messages,
            args.enable_nested_virtualization,
            args.threads_per_core,
            args.numa_node_count if support_numa_node_count else None,
            visible_core_count,
            args.enable_uefi_networking,
            args.performance_monitoring_unit
            if support_performance_monitoring_unit
            else None,
            enable_watchdog_timer=args.enable_watchdog_timer
            if support_watchdog_timer
            else None,
            turbo_mode=args.turbo_mode,
        )
    )

  if args.resource_manager_tags:
    ret_resource_manager_tags = (
        resource_manager_tags_utils.GetResourceManagerTags(
            args.resource_manager_tags
        )
    )
    if ret_resource_manager_tags is not None:
      properties = client.messages.InstanceProperties
      instance_template.properties.resourceManagerTags = (
          properties.ResourceManagerTagsValue(
              additionalProperties=[
                  properties.ResourceManagerTagsValue.AdditionalProperty(
                      key=key, value=value)
                  for key, value in sorted(
                      six.iteritems(ret_resource_manager_tags))])
      )

  if support_partner_metadata and (
      args.partner_metadata or args.partner_metadata_from_file
  ):
    properties = client.messages.InstanceProperties
    partner_metadata_dict = partner_metadata_utils.CreatePartnerMetadataDict(
        args
    )
    partner_metadata_utils.ValidatePartnerMetadata(partner_metadata_dict)
    partner_metadata_message = properties.PartnerMetadataValue()
    for namespace, structured_entries in partner_metadata_dict.items():
      partner_metadata_message.additionalProperties.append(
          properties.PartnerMetadataValue.AdditionalProperty(
              key=namespace,
              value=partner_metadata_utils.ConvertStructuredEntries(
                  structured_entries, client.messages
              ),
          )
      )
    instance_template.properties.partnerMetadata = partner_metadata_message

  if support_display_device and args.IsSpecified('enable_display_device'):
    instance_template.properties.displayDevice = (
        client.messages.DisplayDevice(enableDisplay=args.enable_display_device)
    )

  request = client.messages.ComputeInstanceTemplatesInsertRequest(
      instanceTemplate=instance_template, project=instance_template_ref.project
  )

  if support_region_instance_template and args.IsSpecified(
      'instance_template_region'
  ):
    request = client.messages.ComputeRegionInstanceTemplatesInsertRequest(
        instanceTemplate=instance_template,
        project=instance_template_ref.project,
        region=instance_template.region,
    )

  request.instanceTemplate.properties.labels = ParseCreateArgsWithServiceProxy(
      args, client.messages.InstanceProperties.LabelsValue
  )

  _AddSourceInstanceToTemplate(
      compute_api, args, instance_template, support_source_instance
  )

  if support_region_instance_template and args.IsSpecified(
      'instance_template_region'
  ):
    return client.MakeRequests(
        [(client.apitools_client.regionInstanceTemplates, 'Insert', request)]
    )
  else:
    return client.MakeRequests(
        [(client.apitools_client.instanceTemplates, 'Insert', request)]
    )


# 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 Create(base.CreateCommand):
  """Create a Compute Engine virtual machine instance template.

  *{command}* facilitates the creation of Compute Engine
  virtual machine instance templates. For example, running:

      $ {command} INSTANCE-TEMPLATE

  will create one instance templates called 'INSTANCE-TEMPLATE'.

  Instance templates are global resources, and can be used to create
  instances in any zone.
  """

  # TODO(b/445859137): clean up flags which are true in all tracks.
  _support_source_instance = True
  _support_kms = True
  _support_post_key_revocation_action_type = False
  _support_multi_writer = False
  _support_mesh = False
  _support_numa_node_count = False
  _support_visible_core_count = True
  _support_max_run_duration = True
  _support_region_instance_template = True
  _support_subnet_region = False
  _support_confidential_compute_type = True
  _support_confidential_compute_type_tdx = True
  _support_snp_svsm = False
  _support_replica_zones = True
  _support_local_ssd_size = True
  _support_network_queue_count = True
  _support_performance_monitoring_unit = True
  _support_internal_ipv6_reservation = True
  _support_partner_metadata = False
  _support_local_ssd_recovery_timeout = True
  _support_specific_then_x_affinity = False
  _support_any_reservation_then_fail_affinity = False
  _support_graceful_shutdown = False
  _support_vlan_nic = True
  _support_watchdog_timer = False
  _support_disk_labels = False
  _support_ipv6_only = True
  _support_igmp_query = False
  _support_host_error_timeout_seconds = True
  _support_flex_start = True
  _support_display_device = False
  _support_skip_guest_os_shutdown = True
  _support_preemption_notice_duration = False
  _support_enable_vpc_scoped_dns = False
  _support_workload_identity_config = False
  _support_alias_ipv6_ranges = False
  _support_dns64_eligible = False
  _support_nat64_eligible = False

  @classmethod
  def Args(cls, parser):
    _CommonArgs(
        parser,
        release_track=base.ReleaseTrack.GA,
        support_source_instance=cls._support_source_instance,
        support_kms=cls._support_kms,
        support_multi_writer=cls._support_multi_writer,
        support_mesh=cls._support_mesh,
        support_numa_node_count=cls._support_numa_node_count,
        support_visible_core_count=cls._support_visible_core_count,
        support_max_run_duration=cls._support_max_run_duration,
        support_region_instance_template=cls._support_region_instance_template,
        support_subnet_region=cls._support_subnet_region,
        support_replica_zones=cls._support_replica_zones,
        support_local_ssd_size=cls._support_local_ssd_size,
        support_network_queue_count=cls._support_network_queue_count,
        support_local_ssd_recovery_timeout=cls._support_local_ssd_recovery_timeout,
        support_specific_then_x_affinity=cls._support_specific_then_x_affinity,
        support_any_reservation_then_fail_affinity=cls._support_any_reservation_then_fail_affinity,
        support_graceful_shutdown=cls._support_graceful_shutdown,
        support_vlan_nic=cls._support_vlan_nic,
        support_watchdog_timer=cls._support_watchdog_timer,
        support_disk_labels=cls._support_disk_labels,
        support_ipv6_only=cls._support_ipv6_only,
        support_igmp_query=cls._support_igmp_query,
        support_host_error_timeout_seconds=cls._support_host_error_timeout_seconds,
        support_flex_start=cls._support_flex_start,
        support_display_device=cls._support_display_device,
        support_skip_guest_os_shutdown=cls._support_skip_guest_os_shutdown,
        support_preemption_notice_duration=cls._support_preemption_notice_duration,
        support_enable_vpc_scoped_dns=cls._support_enable_vpc_scoped_dns,
        support_workload_identity_config=cls._support_workload_identity_config,
        support_alias_ipv6_ranges=cls._support_alias_ipv6_ranges,
        support_dns64_eligible=cls._support_dns64_eligible,
        support_nat64_eligible=cls._support_nat64_eligible,
    )
    instances_flags.AddMinCpuPlatformArgs(parser, base.ReleaseTrack.GA)
    instances_flags.AddPrivateIpv6GoogleAccessArgForTemplate(
        parser, utils.COMPUTE_GA_API_VERSION
    )
    instances_flags.AddConfidentialComputeArgs(
        parser,
        support_confidential_compute_type=cls._support_confidential_compute_type,
        support_confidential_compute_type_tdx=cls._support_confidential_compute_type_tdx,
        support_snp_svsm=cls._support_snp_svsm,
    )
    instance_templates_flags.AddKeyRevocationActionTypeArgs(parser)
    instances_flags.AddPerformanceMonitoringUnitArgs(parser)

  def Run(self, args):
    """Creates and runs an InstanceTemplates.Insert request.

    Args:
      args: argparse.Namespace, An object that contains the values for the
        arguments specified in the .Args() method.

    Returns:
      A resource object dispatched by display.Displayer().
    """
    return _RunCreate(
        base_classes.ComputeApiHolder(base.ReleaseTrack.GA),
        args,
        support_source_instance=self._support_source_instance,
        support_kms=self._support_kms,
        support_post_key_revocation_action_type=self._support_post_key_revocation_action_type,
        support_multi_writer=self._support_multi_writer,
        support_mesh=self._support_mesh,
        support_numa_node_count=self._support_numa_node_count,
        support_visible_core_count=self._support_visible_core_count,
        support_max_run_duration=self._support_max_run_duration,
        support_region_instance_template=self._support_region_instance_template,
        support_subnet_region=self._support_subnet_region,
        support_confidential_compute_type=self._support_confidential_compute_type,
        support_confidential_compute_type_tdx=self._support_confidential_compute_type_tdx,
        support_snp_svsm=self._support_snp_svsm,
        support_replica_zones=self._support_replica_zones,
        support_performance_monitoring_unit=self._support_performance_monitoring_unit,
        support_internal_ipv6_reservation=self._support_internal_ipv6_reservation,
        support_partner_metadata=self._support_partner_metadata,
        support_local_ssd_recovery_timeout=self._support_local_ssd_recovery_timeout,
        support_specific_then_x_affinity=self._support_specific_then_x_affinity,
        support_any_reservation_then_fail_affinity=self._support_any_reservation_then_fail_affinity,
        support_graceful_shutdown=self._support_graceful_shutdown,
        support_watchdog_timer=self._support_watchdog_timer,
        support_disk_labels=self._support_disk_labels,
        support_host_error_timeout_seconds=self._support_host_error_timeout_seconds,
        support_display_device=self._support_display_device,
        support_skip_guest_os_shutdown=self._support_skip_guest_os_shutdown,
        support_preemption_notice_duration=self._support_preemption_notice_duration,
        support_enable_vpc_scoped_dns=self._support_enable_vpc_scoped_dns,
        support_workload_identity_config=self._support_workload_identity_config,
        support_alias_ipv6_ranges=self._support_alias_ipv6_ranges,
    )


@base.ReleaseTracks(base.ReleaseTrack.BETA)
class CreateBeta(Create):
  """Create a Compute Engine virtual machine instance template.

  *{command}* facilitates the creation of Compute Engine
  virtual machine instance templates. For example, running:

      $ {command} INSTANCE-TEMPLATE

  will create one instance templates called 'INSTANCE-TEMPLATE'.

  Instance templates are global resources, and can be used to create
  instances in any zone.
  """

  _support_source_instance = True
  _support_kms = True
  _support_post_key_revocation_action_type = True
  _support_multi_writer = True
  _support_mesh = True
  _support_host_error_timeout_seconds = True
  _support_numa_node_count = False
  _support_visible_core_count = True
  _support_max_run_duration = True
  _support_region_instance_template = True
  _support_subnet_region = False
  _support_confidential_compute_type = True
  _support_confidential_compute_type_tdx = True
  _support_snp_svsm = False
  _support_replica_zones = True
  _support_local_ssd_recovery_timeout = True
  _support_local_ssd_size = True
  _support_network_queue_count = True
  _support_performance_monitoring_unit = True
  _support_internal_ipv6_reservation = True
  _support_partner_metadata = True
  _support_maintenance_interval = True
  _support_specific_then_x_affinity = True
  _support_any_reservation_then_fail_affinity = True
  _support_graceful_shutdown = True
  _support_vlan_nic = True
  _support_watchdog_timer = False
  _support_disk_labels = True
  _support_ipv6_only = True
  _support_igmp_query = False
  _support_flex_start = True
  _support_display_device = True
  _support_skip_guest_os_shutdown = True
  _support_preemption_notice_duration = True
  _support_enable_vpc_scoped_dns = False
  _support_workload_identity_config = False
  _support_alias_ipv6_ranges = True
  _support_dns64_eligible = False
  _support_nat64_eligible = False

  @classmethod
  def Args(cls, parser):
    _CommonArgs(
        parser,
        release_track=base.ReleaseTrack.BETA,
        support_local_ssd_size=cls._support_local_ssd_size,
        support_source_instance=cls._support_source_instance,
        support_kms=cls._support_kms,
        support_multi_writer=cls._support_multi_writer,
        support_mesh=cls._support_mesh,
        support_host_error_timeout_seconds=cls._support_host_error_timeout_seconds,
        support_visible_core_count=cls._support_visible_core_count,
        support_max_run_duration=cls._support_max_run_duration,
        support_region_instance_template=cls._support_region_instance_template,
        support_subnet_region=cls._support_subnet_region,
        support_replica_zones=cls._support_replica_zones,
        support_local_ssd_recovery_timeout=cls._support_local_ssd_recovery_timeout,
        support_network_queue_count=cls._support_network_queue_count,
        support_maintenance_interval=cls._support_maintenance_interval,
        support_specific_then_x_affinity=cls._support_specific_then_x_affinity,
        support_any_reservation_then_fail_affinity=cls._support_any_reservation_then_fail_affinity,
        support_graceful_shutdown=cls._support_graceful_shutdown,
        support_vlan_nic=cls._support_vlan_nic,
        support_watchdog_timer=cls._support_watchdog_timer,
        support_disk_labels=cls._support_disk_labels,
        support_ipv6_only=cls._support_ipv6_only,
        support_igmp_query=cls._support_igmp_query,
        support_flex_start=cls._support_flex_start,
        support_display_device=cls._support_display_device,
        support_skip_guest_os_shutdown=cls._support_skip_guest_os_shutdown,
        support_preemption_notice_duration=cls._support_preemption_notice_duration,
        support_enable_vpc_scoped_dns=cls._support_enable_vpc_scoped_dns,
        support_workload_identity_config=cls._support_workload_identity_config,
        support_alias_ipv6_ranges=cls._support_alias_ipv6_ranges,
        support_dns64_eligible=cls._support_dns64_eligible,
        support_nat64_eligible=cls._support_nat64_eligible,
    )
    instances_flags.AddMinCpuPlatformArgs(parser, base.ReleaseTrack.BETA)
    instances_flags.AddPrivateIpv6GoogleAccessArgForTemplate(
        parser, utils.COMPUTE_BETA_API_VERSION
    )
    instances_flags.AddConfidentialComputeArgs(
        parser,
        support_confidential_compute_type=cls
        ._support_confidential_compute_type,
        support_confidential_compute_type_tdx=cls
        ._support_confidential_compute_type_tdx, support_snp_svsm=cls._support_snp_svsm)
    instances_flags.AddPostKeyRevocationActionTypeArgs(parser)
    instance_templates_flags.AddKeyRevocationActionTypeArgs(parser)
    instances_flags.AddPerformanceMonitoringUnitArgs(parser)
    partner_metadata_utils.AddPartnerMetadataArgs(parser)

  def Run(self, args):
    """Creates and runs an InstanceTemplates.Insert request.

    Args:
      args: argparse.Namespace, An object that contains the values for the
        arguments specified in the .Args() method.

    Returns:
      A resource object dispatched by display.Displayer().
    """
    return _RunCreate(
        base_classes.ComputeApiHolder(base.ReleaseTrack.BETA),
        args=args,
        support_source_instance=self._support_source_instance,
        support_kms=self._support_kms,
        support_post_key_revocation_action_type=self._support_post_key_revocation_action_type,
        support_multi_writer=self._support_multi_writer,
        support_mesh=self._support_mesh,
        support_host_error_timeout_seconds=self._support_host_error_timeout_seconds,
        support_numa_node_count=self._support_numa_node_count,
        support_visible_core_count=self._support_visible_core_count,
        support_max_run_duration=self._support_max_run_duration,
        support_region_instance_template=self._support_region_instance_template,
        support_subnet_region=self._support_subnet_region,
        support_confidential_compute_type=self._support_confidential_compute_type,
        support_confidential_compute_type_tdx=self._support_confidential_compute_type_tdx,
        support_snp_svsm=self._support_snp_svsm,
        support_replica_zones=self._support_replica_zones,
        support_local_ssd_recovery_timeout=self._support_local_ssd_recovery_timeout,
        support_performance_monitoring_unit=self._support_performance_monitoring_unit,
        support_internal_ipv6_reservation=self._support_internal_ipv6_reservation,
        support_partner_metadata=self._support_partner_metadata,
        support_maintenance_interval=self._support_maintenance_interval,
        support_specific_then_x_affinity=self._support_specific_then_x_affinity,
        support_any_reservation_then_fail_affinity=self._support_any_reservation_then_fail_affinity,
        support_graceful_shutdown=self._support_graceful_shutdown,
        support_watchdog_timer=self._support_watchdog_timer,
        support_disk_labels=self._support_disk_labels,
        support_display_device=self._support_display_device,
        support_skip_guest_os_shutdown=self._support_skip_guest_os_shutdown,
        support_preemption_notice_duration=self._support_preemption_notice_duration,
        support_enable_vpc_scoped_dns=self._support_enable_vpc_scoped_dns,
        support_workload_identity_config=self._support_workload_identity_config,
        support_alias_ipv6_ranges=self._support_alias_ipv6_ranges,
        support_dns64_eligible=True,
        support_nat64_eligible=True,
    )


@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class CreateAlpha(Create):
  """Create a Compute Engine virtual machine instance template.

  *{command}* facilitates the creation of Compute Engine
  virtual machine instance templates. For example, running:

      $ {command} INSTANCE-TEMPLATE

  will create one instance templates called 'INSTANCE-TEMPLATE'.

  Instance templates are global resources, and can be used to create
  instances in any zone.
  """

  _support_source_instance = True
  _support_kms = True
  _support_post_key_revocation_action_type = True
  _support_multi_writer = True
  _support_mesh = True
  _support_host_error_timeout_seconds = True
  _support_numa_node_count = True
  _support_visible_core_count = True
  _support_max_run_duration = True
  _support_region_instance_template = True
  _support_subnet_region = True
  _support_confidential_compute_type = True
  _support_confidential_compute_type_tdx = True
  _support_snp_svsm = True
  _support_replica_zones = True
  _support_local_ssd_recovery_timeout = True
  _support_network_queue_count = True
  _support_local_ssd_size = True
  _support_performance_monitoring_unit = True
  _support_internal_ipv6_reservation = True
  _support_partner_metadata = True
  _support_maintenance_interval = True
  _support_specific_then_x_affinity = True
  _support_any_reservation_then_fail_affinity = True
  _support_graceful_shutdown = True
  _support_vlan_nic = True
  _support_ipv6_only = True
  _support_watchdog_timer = True
  _support_disk_labels = True
  _support_igmp_query = True
  _support_flex_start = True
  _support_display_device = True
  _support_skip_guest_os_shutdown = True
  _support_preemption_notice_duration = True
  _support_enable_vpc_scoped_dns = True
  _support_workload_identity_config = True
  _support_alias_ipv6_ranges = True
  _support_dns64_eligible = True
  _support_nat64_eligible = True

  @classmethod
  def Args(cls, parser):
    _CommonArgs(
        parser,
        release_track=base.ReleaseTrack.ALPHA,
        support_local_ssd_size=cls._support_local_ssd_size,
        support_source_instance=cls._support_source_instance,
        support_kms=cls._support_kms,
        support_multi_writer=cls._support_multi_writer,
        support_mesh=cls._support_mesh,
        support_host_error_timeout_seconds=cls._support_host_error_timeout_seconds,
        support_numa_node_count=cls._support_numa_node_count,
        support_visible_core_count=cls._support_visible_core_count,
        support_max_run_duration=cls._support_max_run_duration,
        support_region_instance_template=cls._support_region_instance_template,
        support_subnet_region=cls._support_subnet_region,
        support_replica_zones=cls._support_replica_zones,
        support_local_ssd_recovery_timeout=cls._support_local_ssd_recovery_timeout,
        support_network_queue_count=cls._support_network_queue_count,
        support_maintenance_interval=cls._support_maintenance_interval,
        support_specific_then_x_affinity=cls._support_specific_then_x_affinity,
        support_any_reservation_then_fail_affinity=cls._support_any_reservation_then_fail_affinity,
        support_graceful_shutdown=cls._support_graceful_shutdown,
        support_ipv6_only=cls._support_ipv6_only,
        support_vlan_nic=cls._support_vlan_nic,
        support_watchdog_timer=cls._support_watchdog_timer,
        support_disk_labels=cls._support_disk_labels,
        support_igmp_query=cls._support_igmp_query,
        support_flex_start=cls._support_flex_start,
        support_display_device=cls._support_display_device,
        support_skip_guest_os_shutdown=cls._support_skip_guest_os_shutdown,
        support_preemption_notice_duration=cls._support_preemption_notice_duration,
        support_enable_vpc_scoped_dns=cls._support_enable_vpc_scoped_dns,
        support_workload_identity_config=cls._support_workload_identity_config,
        support_alias_ipv6_ranges=cls._support_alias_ipv6_ranges,
        support_dns64_eligible=cls._support_dns64_eligible,
        support_nat64_eligible=cls._support_nat64_eligible,
    )
    instances_flags.AddLocalNvdimmArgs(parser)
    instances_flags.AddMinCpuPlatformArgs(parser, base.ReleaseTrack.ALPHA)
    instances_flags.AddConfidentialComputeArgs(
        parser,
        support_confidential_compute_type=cls._support_confidential_compute_type,
        support_confidential_compute_type_tdx=cls._support_confidential_compute_type_tdx,
        support_snp_svsm=cls._support_snp_svsm,
    )
    instances_flags.AddPrivateIpv6GoogleAccessArgForTemplate(
        parser, utils.COMPUTE_ALPHA_API_VERSION
    )
    instances_flags.AddPostKeyRevocationActionTypeArgs(parser)
    instances_flags.AddIPv6AddressAlphaArgs(parser)
    instances_flags.AddIPv6PrefixLengthAlphaArgs(parser)
    instance_templates_flags.AddKeyRevocationActionTypeArgs(parser)
    instances_flags.AddPerformanceMonitoringUnitArgs(parser)
    partner_metadata_utils.AddPartnerMetadataArgs(parser)

  def Run(self, args):
    """Creates and runs an InstanceTemplates.Insert request.

    Args:
      args: argparse.Namespace, An object that contains the values for the
        arguments specified in the .Args() method.

    Returns:
      A resource object dispatched by display.Displayer().
    """
    return _RunCreate(
        base_classes.ComputeApiHolder(base.ReleaseTrack.ALPHA),
        args=args,
        support_source_instance=self._support_source_instance,
        support_kms=self._support_kms,
        support_post_key_revocation_action_type=self._support_post_key_revocation_action_type,
        support_multi_writer=self._support_multi_writer,
        support_mesh=self._support_mesh,
        support_host_error_timeout_seconds=self._support_host_error_timeout_seconds,
        support_numa_node_count=self._support_numa_node_count,
        support_visible_core_count=self._support_visible_core_count,
        support_max_run_duration=self._support_max_run_duration,
        support_region_instance_template=self._support_region_instance_template,
        support_subnet_region=self._support_subnet_region,
        support_confidential_compute_type=self._support_confidential_compute_type,
        support_confidential_compute_type_tdx=self._support_confidential_compute_type_tdx,
        support_snp_svsm=self._support_snp_svsm,
        support_replica_zones=self._support_replica_zones,
        support_local_ssd_recovery_timeout=self._support_local_ssd_recovery_timeout,
        support_performance_monitoring_unit=self._support_performance_monitoring_unit,
        support_internal_ipv6_reservation=self._support_internal_ipv6_reservation,
        support_partner_metadata=self._support_partner_metadata,
        support_maintenance_interval=self._support_maintenance_interval,
        support_specific_then_x_affinity=self._support_specific_then_x_affinity,
        support_any_reservation_then_fail_affinity=self._support_any_reservation_then_fail_affinity,
        support_graceful_shutdown=self._support_graceful_shutdown,
        support_watchdog_timer=self._support_watchdog_timer,
        support_disk_labels=self._support_disk_labels,
        support_display_device=self._support_display_device,
        support_skip_guest_os_shutdown=self._support_skip_guest_os_shutdown,
        support_preemption_notice_duration=self._support_preemption_notice_duration,
        support_enable_vpc_scoped_dns=self._support_enable_vpc_scoped_dns,
        support_workload_identity_config=self._support_workload_identity_config,
        support_alias_ipv6_ranges=self._support_alias_ipv6_ranges,
        support_dns64_eligible=True,
        support_nat64_eligible=True,
    )


DETAILED_HELP = {
    'brief': 'Create a Compute Engine virtual machine instance template.',
    'DESCRIPTION': (
        '*{command}* facilitates the creation of Compute Engine '
        'virtual machine instance templates. Instance '
        'templates are global resources, and can be used to create '
        'instances in any zone.'
    ),
    'EXAMPLES': """\
        To create an instance template named 'INSTANCE-TEMPLATE' with the 'n2'
        vm type, '9GB' memory, and 2 CPU cores, run:

          $ {command} INSTANCE-TEMPLATE --custom-vm-type=n2 --custom-cpu=2 --custom-memory=9GB
        """,
}

Create.detailed_help = DETAILED_HELP
