HEX
Server: Apache/2.4.65 (Ubuntu)
System: Linux ielts-store-v2 6.8.0-1036-gcp #38~22.04.1-Ubuntu SMP Thu Aug 14 01:19:18 UTC 2025 x86_64
User: root (0)
PHP: 7.2.34-54+ubuntu20.04.1+deb.sury.org+1
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,
Upload Files
File: //snap/google-cloud-cli/current/lib/googlecloudsdk/command_lib/compute/reservations/util.py
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""Common utility functions to construct compute reservations message."""

from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals

from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.compute import flags as compute_flags
from googlecloudsdk.command_lib.compute import scope as compute_scope
from googlecloudsdk.command_lib.compute.resource_policies import util as maintenance_util
from googlecloudsdk.core.util import times
import six


def MakeReservationMessageFromArgs(messages, args, reservation_ref, resources):
  """Construct reservation message from args passed in."""
  accelerators = MakeGuestAccelerators(messages,
                                       getattr(args, 'accelerator', None))
  local_ssds = MakeLocalSsds(messages, getattr(args, 'local_ssd', None))
  share_settings = MakeShareSettingsWithArgs(
      messages, args, getattr(args, 'share_setting', None))
  source_instance_template_ref = (
      ResolveSourceInstanceTemplate(args, resources)
      if args.IsKnownAndSpecified('source_instance_template')
      else None
  )
  specific_reservation = MakeSpecificSKUReservationMessage(
      messages,
      args.vm_count,
      accelerators,
      local_ssds,
      args.machine_type,
      args.min_cpu_platform,
      getattr(args, 'location_hint', None),
      getattr(args, 'maintenance_freeze_duration', None),
      getattr(args, 'maintenance_interval', None),
      source_instance_template_ref,
  )
  resource_policies = MakeResourcePolicies(
      messages, reservation_ref, getattr(args, 'resource_policies', None),
      resources)

  scheduling_type = None
  if args.IsKnownAndSpecified('scheduling_type'):
    scheduling_type = getattr(args, 'scheduling_type', None)

  return MakeReservationMessage(
      messages,
      reservation_ref.Name(),
      share_settings,
      specific_reservation,
      resource_policies,
      args.require_specific_reservation,
      reservation_ref.zone,
      getattr(args, 'delete_at_time', None),
      getattr(args, 'delete_after_duration', None),
      getattr(args, 'reservation_sharing_policy', None),
      getattr(args, 'enable_emergent_maintenance', None),
      scheduling_type,
  )


def ResolveSourceInstanceTemplate(args, resources):
  return compute_flags.ResourceArgument(
      '--source-instance-template',
      resource_name='instance template',
      scope_flags_usage=compute_flags.ScopeFlagsUsage.DONT_USE_SCOPE_FLAGS,
      global_collection='compute.instanceTemplates',
      regional_collection='compute.regionInstanceTemplates',
  ).ResolveAsResource(
      args, resources, default_scope=compute_scope.ScopeEnum.GLOBAL
  )


def MakeGuestAccelerators(messages, accelerator_configs):
  """Constructs the repeated accelerator message objects."""
  if accelerator_configs is None:
    return []

  accelerators = []

  for a in accelerator_configs:
    m = messages.AcceleratorConfig(
        acceleratorCount=a['count'], acceleratorType=a['type'])
    accelerators.append(m)

  return accelerators


def MakeLocalSsds(messages, ssd_configs):
  """Constructs the repeated local_ssd message objects."""
  if ssd_configs is None:
    return []

  local_ssds = []
  disk_msg = (
      messages
      .AllocationSpecificSKUAllocationAllocatedInstancePropertiesReservedDisk)
  interface_msg = disk_msg.InterfaceValueValuesEnum
  for s in ssd_configs:
    if s['interface'].upper() == 'NVME':
      interface = interface_msg.NVME
    elif s['interface'].upper() == 'SCSI':
      interface = interface_msg.SCSI
    else:
      raise exceptions.InvalidArgumentException(
          '--local-ssd',
          'Must specify a valid interface (NVME, SCSI) for SSDs attached to the'
          ' instance.',
      )
    m = disk_msg(diskSizeGb=s['size'], interface=interface)
    partitions = s.get('count', 1)
    if partitions < 1:
      raise exceptions.InvalidArgumentException(
          '--local-ssd',
          'Must specify a valid count (>= 1) for SSDs attached to the '
          'reservation.',
      )
    local_ssds.extend([m] * partitions)

  return local_ssds


def MakeShareSettingsWithArgs(messages,
                              args,
                              setting_configs,
                              share_with='share_with'):
  """Constructs the share settings message object from raw args as input."""
  if setting_configs:
    if setting_configs == 'organization':
      return messages.ShareSettings(shareType=messages.ShareSettings
                                    .ShareTypeValueValuesEnum.ORGANIZATION)
    if setting_configs == 'local':
      if args.IsSpecified(share_with) and share_with != 'remove_share_with':
        raise exceptions.InvalidArgumentException(
            '--share_with',
            'The scope this reservation is to be shared with must not be '
            'specified with share setting local.')
      return messages.ShareSettings(
          shareType=messages.ShareSettings.ShareTypeValueValuesEnum.LOCAL)
    if setting_configs == 'projects':
      if not args.IsSpecified(share_with):
        raise exceptions.InvalidArgumentException(
            '--share_with',
            'The projects this reservation is to be shared with must be '
            'specified.')
      project_map = None
      if share_with != 'remove_share_with':
        project_map = MakeProjectMapFromProjectList(
            messages, getattr(args, share_with, None))
      return messages.ShareSettings(
          shareType=messages.ShareSettings.ShareTypeValueValuesEnum
          .SPECIFIC_PROJECTS,
          projectMap=project_map)
    if setting_configs == 'folders':
      if not args.IsSpecified(share_with):
        raise exceptions.InvalidArgumentException(
            '--share_with',
            'The folders this reservation is to be shared with must be '
            'specified.')
      return messages.ShareSettings(
          shareType=messages.ShareSettings.ShareTypeValueValuesEnum
          .DIRECT_PROJECTS_UNDER_SPECIFIC_FOLDERS,
          folderMap=MakeFolderMapFromFolderList(messages,
                                                getattr(args, share_with,
                                                        None)))
  else:
    if args.IsKnownAndSpecified(share_with):
      raise exceptions.InvalidArgumentException(
          '--share_setting',
          'Please specify share setting if specifying share with.')
    return None


def MakeShareSettingsWithDict(messages, dictionary, setting_configs):
  """Constructs the share settings message object from dictionary form of input."""
  if setting_configs:
    if setting_configs == 'organization':
      return messages.ShareSettings(shareType=messages.ShareSettings
                                    .ShareTypeValueValuesEnum.ORGANIZATION)
    if setting_configs == 'local':
      if 'share_with' in dictionary.keys():
        raise exceptions.InvalidArgumentException(
            '--share_with',
            'The scope this reservation is to be shared with must not be '
            'specified with share setting local.')
      return messages.ShareSettings(
          shareType=messages.ShareSettings.ShareTypeValueValuesEnum.LOCAL)
    if setting_configs == 'projects':
      if 'share_with' not in dictionary.keys():
        raise exceptions.InvalidArgumentException(
            '--share_with',
            'The projects this reservation is to be shared with must be '
            'specified.')
      return messages.ShareSettings(
          shareType=messages.ShareSettings.ShareTypeValueValuesEnum
          .SPECIFIC_PROJECTS,
          projectMap=MakeProjectMapFromProjectList(
              messages, dictionary.get('share_with', None)))
    if setting_configs == 'folders':
      if 'share_with' not in dictionary.keys():
        raise exceptions.InvalidArgumentException(
            '--share_with',
            'The folders this reservation is to be shared with must be '
            'specified.')
      return messages.ShareSettings(
          shareType=messages.ShareSettings.ShareTypeValueValuesEnum
          .DIRECT_PROJECTS_UNDER_SPECIFIC_FOLDERS,
          folderMap=MakeFolderMapFromFolderList(
              messages, dictionary.get('share_with', None)))
  else:
    if 'share_with' in dictionary.keys():
      raise exceptions.InvalidArgumentException(
          '--share_setting',
          'Please specify share setting if specifying share with.')
    return None


def MakeSpecificSKUReservationMessage(
    messages,
    vm_count,
    accelerators,
    local_ssds,
    machine_type,
    min_cpu_platform,
    location_hint=None,
    freeze_duration=None,
    freeze_interval=None,
    source_instance_template_ref=None,
):
  """Constructs a single specific sku reservation message object."""
  prop_msgs = (
      messages.AllocationSpecificSKUAllocationReservedInstanceProperties)
  if source_instance_template_ref:
    return messages.AllocationSpecificSKUReservation(
        count=vm_count,
        sourceInstanceTemplate=source_instance_template_ref.SelfLink(),
        instanceProperties=None,
    )
  else:
    instance_properties = prop_msgs(
        guestAccelerators=accelerators,
        localSsds=local_ssds,
        machineType=machine_type,
        minCpuPlatform=min_cpu_platform)
    if freeze_duration:
      instance_properties.maintenanceFreezeDurationHours = freeze_duration // 3600
    if freeze_interval:
      instance_properties.maintenanceInterval = (
          messages.AllocationSpecificSKUAllocationReservedInstanceProperties
          .MaintenanceIntervalValueValuesEnum(freeze_interval))
    if location_hint:
      instance_properties.locationHint = location_hint
    return messages.AllocationSpecificSKUReservation(
        count=vm_count, instanceProperties=instance_properties)


def MakeReservationMessage(
    messages,
    reservation_name,
    share_settings,
    specific_reservation,
    resource_policies,
    require_specific_reservation,
    reservation_zone,
    delete_at_time=None,
    delete_after_duration=None,
    reservation_sharing_policy=None,
    enable_emergent_maintenance=None,
    scheduling_type=None,
):
  """Constructs a single reservations message object."""
  reservation_message = messages.Reservation(
      name=reservation_name,
      specificReservation=specific_reservation,
      specificReservationRequired=require_specific_reservation,
      zone=reservation_zone)
  if share_settings:
    reservation_message.shareSettings = share_settings
  if resource_policies:
    reservation_message.resourcePolicies = resource_policies

  if delete_at_time:
    reservation_message.deleteAtTime = times.FormatDateTime(delete_at_time)

  if delete_after_duration:
    reservation_message.deleteAfterDuration = messages.Duration(
        seconds=delete_after_duration
    )

  if reservation_sharing_policy:
    reservation_message.reservationSharingPolicy = (
        MakeReservationSharingPolicyMessage(
            messages, reservation_sharing_policy
        )
    )

  if enable_emergent_maintenance is not None:
    reservation_message.enableEmergentMaintenance = enable_emergent_maintenance

  if scheduling_type is not None:
    reservation_message.schedulingType = (
        MakeSchedulingType(messages, scheduling_type)
    )

  return reservation_message


def MakeReservationSharingPolicyMessage(messages, reservation_sharing_policy):
  if reservation_sharing_policy == 'DISALLOW_ALL':
    return messages.AllocationReservationSharingPolicy(
        serviceShareType=messages.AllocationReservationSharingPolicy.ServiceShareTypeValueValuesEnum.DISALLOW_ALL
    )
  elif reservation_sharing_policy == 'ALLOW_ALL':
    return messages.AllocationReservationSharingPolicy(
        serviceShareType=messages.AllocationReservationSharingPolicy.ServiceShareTypeValueValuesEnum.ALLOW_ALL
    )
  else:
    return None


def MakeProjectMapFromProjectList(messages, projects):
  additional_properties = []
  for project in projects:
    additional_properties.append(
        messages.ShareSettings.ProjectMapValue.AdditionalProperty(
            key=project,
            value=messages.ShareSettingsProjectConfig(projectId=project)))
  return messages.ShareSettings.ProjectMapValue(
      additionalProperties=additional_properties)


def MakeFolderMapFromFolderList(messages, folders):
  additional_properties = []
  for folder in folders:
    additional_properties.append(
        messages.ShareSettings.FolderMapValue.AdditionalProperty(
            key=folder,
            value=messages.ShareSettingsFolderConfig(folderId=folder)))
  return messages.ShareSettings.FolderMapValue(
      additionalProperties=additional_properties)


def MakeResourcePolicies(messages, reservation_ref, resource_policy_dictionary,
                         resources):
  """Constructs the resource policies message objects."""
  if resource_policy_dictionary is None:
    return None

  return messages.Reservation.ResourcePoliciesValue(additionalProperties=[
      messages.Reservation.ResourcePoliciesValue.AdditionalProperty(
          key=key, value=MakeUrl(resources, value, reservation_ref))
      for key, value in sorted(six.iteritems(resource_policy_dictionary))
  ])


def MakeReservationsMaintenanceScope(messages, maintenance_scope):
  """Constructs the maintenance scope message object for reservations."""
  if maintenance_scope == 'all':
    return (
        messages.ReservationsPerformMaintenanceRequest.MaintenanceScopeValueValuesEnum.ALL
    )
  elif maintenance_scope == 'unused':
    return (
        messages.ReservationsPerformMaintenanceRequest.MaintenanceScopeValueValuesEnum.UNUSED_CAPACITY
    )
  elif maintenance_scope == 'running':
    return (
        messages.ReservationsPerformMaintenanceRequest.MaintenanceScopeValueValuesEnum.RUNNING_VMS
    )
  else:
    return None


def MakeReservationBlocksMaintenanceScope(messages, maintenance_scope):
  """Constructs the maintenance scope message object for reservation blocks."""
  if maintenance_scope == 'all':
    return (
        messages.ReservationsBlocksPerformMaintenanceRequest.MaintenanceScopeValueValuesEnum.ALL
    )
  elif maintenance_scope == 'unused':
    return (
        messages.ReservationsBlocksPerformMaintenanceRequest.MaintenanceScopeValueValuesEnum.UNUSED_CAPACITY
    )
  elif maintenance_scope == 'running':
    return (
        messages.ReservationsBlocksPerformMaintenanceRequest.MaintenanceScopeValueValuesEnum.RUNNING_VMS
    )
  else:
    return None


def MakeSchedulingType(messages, scheduling_type):
  """Constructs the scheduling type enum value."""
  if scheduling_type:
    if scheduling_type == 'GROUPED':
      return messages.Reservation.SchedulingTypeValueValuesEnum.GROUPED
    if scheduling_type == 'INDEPENDENT':
      return messages.Reservation.SchedulingTypeValueValuesEnum.INDEPENDENT
  return None


def MakeUrl(resources, value, reservation_ref):
  return maintenance_util.ParseResourcePolicyWithZone(
      resources,
      value,
      project=reservation_ref.project,
      zone=reservation_ref.zone).SelfLink()