# -*- coding: utf-8 -*- # # Copyright 2022 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. """Flags for data-catalog commands.""" from __future__ import absolute_import from __future__ import division from __future__ import unicode_literals import sys from googlecloudsdk.api_lib.util import apis from googlecloudsdk.calliope import arg_parsers from googlecloudsdk.calliope import base from googlecloudsdk.calliope import exceptions from googlecloudsdk.calliope.concepts import concepts from googlecloudsdk.command_lib.util.apis import arg_utils from googlecloudsdk.command_lib.util.apis import yaml_data from googlecloudsdk.command_lib.util.concepts import concept_parsers from googlecloudsdk.command_lib.util.concepts import presentation_specs FILTER_FLAG_NO_SORTBY_DOC = base.Argument( '--filter', metavar='EXPRESSION', require_coverage_in_tests=False, category=base.LIST_COMMAND_FLAGS, help="""\ Apply a Boolean filter _EXPRESSION_ to each resource item to be listed. If the expression evaluates `True`, then that item is listed. For more details and examples of filter expressions, run $ gcloud topic filters. This flag interacts with other flags that are applied in this order: *--flatten*, *--filter*, *--limit*.""") LIMIT_FLAG_NO_SORTBY_DOC = base.Argument( '--limit', type=arg_parsers.BoundedInt(1, sys.maxsize, unlimited=True), require_coverage_in_tests=False, category=base.LIST_COMMAND_FLAGS, help="""\ Maximum number of resources to list. The default is *unlimited*. This flag interacts with other flags that are applied in this order: *--flatten*, *--filter*, *--limit*. """) VOLUME_SNAPSHOT_AUTO_DELETE_BEHAVIOR_MAPPER = arg_utils.ChoiceEnumMapper( arg_name='--snapshot-auto-delete', message_enum=apis.GetMessagesModule( 'baremetalsolution', 'v2').Volume.SnapshotAutoDeleteBehaviorValueValuesEnum, custom_mappings={ 'NEWEST_FIRST': ('newest-first', 'Delete the newest snapshot first.'), 'OLDEST_FIRST': ('oldest-first', 'Delete the oldest snapshot first.'), 'DISABLED': ('disabled', ("Don't delete any snapshots. This disables " 'new snapshot creation as long as the ' 'snapshot reserved space is full.')), }, required=False, help_str='Behavior of the disk when snapshot reserved space is full.') ASYNC_FLAG_DEFAULT_TRUE = base.Argument( '--async', action='store_true', dest='async_', default=True, help="""\ Return immediately, without waiting for the operation in progress to complete.""") IP_RESERVATION_SPEC = { 'start-address': str, 'end-address': str, 'note': str } IP_RESERVATION_KEY_SPEC = { 'start-address': str, 'end-address': str, } NFS_ALLOWED_CLIENTS_HELP_TEXT = """ Adds an allowed client to the NFS share. This flag can be repeated to specify multiple allowed clients. *network*::: The name of the network to allow. *network-project-id*::: The project ID of the allowed client network. If not present, the project ID of the NFS share will be used. *cidr*::: The subnet of IP addresses permitted to access the NFS share. *mount-permissions*::: The mount permissions for the allowed client. ``MOUNT_PERMISSIONS'' must be one of: `READ_ONLY`, `READ_WRITE`. *allow-dev*::: If ``yes'', allows creation of devices. *allow-suid*::: If ``yes'', allows SUID. *enable-root-squash*::: If ``yes'', enables root squashing which is a special mapping of the remote superuser (root) identity when using identity authentication . """ def _ValidateNFSMountPermissions(mount_permissions_input): """Validates NFS mount permissions field, throws exception if invalid.""" mount_permissions = mount_permissions_input.upper() if mount_permissions not in NFS_MOUNT_PERMISSIONS_CHOICES: raise exceptions.InvalidArgumentException( '--allowed-client', 'Invalid value {} for mount-permissions'.format( mount_permissions_input)) return mount_permissions NFS_ALLOWED_CLIENT_SPEC = { 'network': str, 'network-project-id': str, 'cidr': str, 'mount-permissions': _ValidateNFSMountPermissions, 'allow-dev': arg_parsers.ArgBoolean(), 'allow-suid': arg_parsers.ArgBoolean(), 'enable-root-squash': arg_parsers.ArgBoolean(), } REQUIRED_NFS_ALLOWED_CLIENT_KEYS = [ # Only network-project-id is optional. 'network', 'cidr', 'mount-permissions', 'allow-dev', 'allow-suid', 'enable-root-squash', ] NFS_MOUNT_PERMISSIONS_CHOICES = ('READ_ONLY', 'READ_WRITE') REMOVE_NFS_ALLOWED_CLIENT_SPEC = { 'network': str, 'network-project-id': str, 'cidr': str, } REQUIRED_REMOVE_NFS_ALLOWED_CLIENT_KEYS = [ # Only network-project-id is optional. 'network', 'cidr', ] def AddInstanceArgToParser(parser, positional=False): """Sets up an argument for the instance resource.""" if positional: name = 'instance' else: name = '--instance' instance_data = yaml_data.ResourceYAMLData.FromPath( 'bms.instance') resource_spec = concepts.ResourceSpec.FromYaml(instance_data.GetData()) presentation_spec = presentation_specs.ResourcePresentationSpec( name=name, concept_spec=resource_spec, required=True, group_help='instance.') return concept_parsers.ConceptParser([presentation_spec]).AddToParser(parser) def AddRegionArgToParser(parser, positional=False): """Parses region flag.""" region_data = yaml_data.ResourceYAMLData.FromPath('bms.region') resource_spec = concepts.ResourceSpec.FromYaml(region_data.GetData()) if positional: name = 'region' else: name = '--region' presentation_spec = presentation_specs.ResourcePresentationSpec( name=name, concept_spec=resource_spec, required=False, group_help='region.') return concept_parsers.ConceptParser([presentation_spec]).AddToParser(parser) def AddVolumeArgToParser(parser, positional=False, group_help_text=None): """Sets up an argument for the instance resource.""" if positional: name = 'volume' else: name = '--volume' volume_data = yaml_data.ResourceYAMLData.FromPath( 'bms.volume') resource_spec = concepts.ResourceSpec.FromYaml(volume_data.GetData()) presentation_spec = presentation_specs.ResourcePresentationSpec( name=name, concept_spec=resource_spec, required=True, group_help=group_help_text or 'volume.') return concept_parsers.ConceptParser([presentation_spec]).AddToParser(parser) def AddSnapshotSchedulePolicyArgToParser(parser, positional=False, required=True, name=None, group=None): """Sets up an argument for the snapshot schedule policy resource.""" if not name: if positional: name = 'snapshot_schedule_policy' else: name = '--snapshot-schedule-policy' policy_data = yaml_data.ResourceYAMLData.FromPath( 'bms.snapshot_schedule_policy') resource_spec = concepts.ResourceSpec.FromYaml(policy_data.GetData()) presentation_spec = presentation_specs.ResourcePresentationSpec( name=name, group=group, concept_spec=resource_spec, required=required, flag_name_overrides={'region': ''}, group_help='snapshot_schedule_policy.') return concept_parsers.ConceptParser([presentation_spec]).AddToParser(parser) def AddSnapshotScheduleArgListToParser(parser, required=True): """Sets up an argument for a snapshot schedule.""" spec = { 'crontab_spec': str, 'retention_count': int, 'prefix': str, } parser.add_argument( '--schedule', required=required, type=arg_parsers.ArgDict(spec=spec, max_length=len(spec), required_keys=spec.keys()), action='append', metavar='CRONTAB_SPEC,RETENTION_COUNT,PREFIX', help=""" Adds a schedule for taking snapshots of volumes under this policy. This flag may be repeated to specify up to 5 schedules. *crontab_spec*::: Specification of the times at which snapshots will be taken. This should be in Crontab format: http://en.wikipedia.org/wiki/Cron#Overview *retention_count*::: The maximum number of snapshots to retain in this schedule. *prefix*::: Value to append to the name of snapshots created by this schedule. """, ) def AddNetworkArgToParser(parser, positional=False): """Sets up an argument for the network resource.""" if positional: name = 'network' else: name = '--network' policy_data = yaml_data.ResourceYAMLData.FromPath( 'bms.network') resource_spec = concepts.ResourceSpec.FromYaml(policy_data.GetData()) presentation_spec = presentation_specs.ResourcePresentationSpec( name=name, concept_spec=resource_spec, required=True, group_help='network.') return concept_parsers.ConceptParser([presentation_spec]).AddToParser(parser) def AddLunArgToParser(parser): """Sets up an argument for a volume snapshot policy.""" name = 'lun' snapshot_data = yaml_data.ResourceYAMLData.FromPath('bms.lun') resource_spec = concepts.ResourceSpec.FromYaml(snapshot_data.GetData()) presentation_spec = presentation_specs.ResourcePresentationSpec( name=name, concept_spec=resource_spec, required=True, group_help='lun.') return concept_parsers.ConceptParser([presentation_spec]).AddToParser(parser) def AddVolumeSnapshotArgToParser(parser, positional=False): """Sets up an argument for a volume snapshot policy.""" if positional: name = 'snapshot' else: name = '--snapshot' snapshot_data = yaml_data.ResourceYAMLData.FromPath('bms.snapshot') resource_spec = concepts.ResourceSpec.FromYaml(snapshot_data.GetData()) presentation_spec = presentation_specs.ResourcePresentationSpec( name=name, concept_spec=resource_spec, required=True, group_help='snapshot.') return concept_parsers.ConceptParser([presentation_spec]).AddToParser(parser) def AddVolumeSnapshotAutoDeleteBehaviorArgToParser(parser): """Sets up an argument for a volume snapshot auto-delete-behavior enum.""" VOLUME_SNAPSHOT_AUTO_DELETE_BEHAVIOR_MAPPER.choice_arg.AddToParser(parser) def AddNfsShareArgToParser(parser, positional=False): """Sets up an argument for an nfs-share resource.""" if positional: name = 'nfs_share' else: name = '--nfs_share' nfs_data = yaml_data.ResourceYAMLData.FromPath( 'bms.nfs_share') resource_spec = concepts.ResourceSpec.FromYaml(nfs_data.GetData()) presentation_spec = presentation_specs.ResourcePresentationSpec( name=name, concept_spec=resource_spec, required=True, group_help='nfs_share.') return concept_parsers.ConceptParser([presentation_spec]).AddToParser(parser) def AddOsImageArgToParser(parser, positional=False): """Sets up an argument for an os-image resource.""" if positional: name = 'os_image' else: name = '--os-image' os_image_data = yaml_data.ResourceYAMLData.FromPath( 'bms.os_image') resource_spec = concepts.ResourceSpec.FromYaml(os_image_data.GetData()) presentation_spec = presentation_specs.ResourcePresentationSpec( name=name, concept_spec=resource_spec, required=True, group_help='os_image.') return concept_parsers.ConceptParser([presentation_spec]).AddToParser(parser) def AddSerialConsoleSshKeyArgToParser(parser, positional=False, name=None): """Sets up an argument for the serial-console-ssh-key resource.""" name = 'serial_console_ssh_key' if positional else '--serial-console-ssh-key' ssh_key_data = yaml_data.ResourceYAMLData.FromPath( 'bms.serial_console_ssh_key' ) resource_spec = concepts.ResourceSpec.FromYaml(ssh_key_data.GetData()) presentation_spec = presentation_specs.ResourcePresentationSpec( name=name, concept_spec=resource_spec, required=True, flag_name_overrides={'region': ''}, group_help='serial_console_ssh_key.', ) return concept_parsers.ConceptParser([presentation_spec]).AddToParser(parser) def AddProvisioningSshKeyArgToParser( parser, positional=False, name=None, required=True, plural=False ): group_parser = parser.add_mutually_exclusive_group(required=required) AddSshKeyArgToParser( group_parser, positional=positional, name=name, plural=plural, required=required, ) AddClearSshKeyToParser(group_parser) def AddSshKeyArgToParser( parser, positional=False, name=None, required=True, plural=False ): """Sets up an argument for the ssh-key resource.""" name = 'ssh_key' if positional else '--ssh-key' ssh_key_data = yaml_data.ResourceYAMLData.FromPath('bms.ssh_key') resource_spec = concepts.ResourceSpec.FromYaml(ssh_key_data.GetData()) presentation_spec = presentation_specs.ResourcePresentationSpec( name=name if not plural else f'{name}s', concept_spec=resource_spec, required=required, flag_name_overrides={'region': ''}, group_help='ssh_key.', plural=plural, ) return concept_parsers.ConceptParser([presentation_spec]).AddToParser(parser) def AddClearSshKeyToParser(parser): parser.add_argument( '--clear-ssh-keys', action='store_true', help="""Provisions the instance without any SSH keys.""", required=False, ) def AddNewNameArgToParser(parser, obj_name): parser.add_argument( '--new-name', type=str, help="""New {name} name for renaming an already existing {name}.""".format( name=obj_name), required=True) def AddInstanceOsImageToParser(parser, hidden, required): parser.add_argument( '--os-image', type=str, help=""" OS image to install on the server. To list all OS image codes supported by BMS, run: $ gcloud bms os-images list """, hidden=hidden, required=required, ) def AddInstanceEnableHyperthreadingToParser(parser, hidden): parser.add_argument( '--enable-hyperthreading', action=arg_parsers.StoreTrueFalseAction, help="""Enable hyperthreading for the server.""", hidden=hidden) def AddNetworkIpReservationToParser(parser, hidden): """Adds the flags for network IP range reservation to parser.""" group_arg = parser.add_mutually_exclusive_group(required=False) group_arg.add_argument( '--add-ip-range-reservation', type=arg_parsers.ArgDict(spec=IP_RESERVATION_SPEC), metavar='PROPERTY=VALUE', help=""" Add a reservation of a range of IP addresses in the network. *start_address*::: The first address of this reservation block. Must be specified as a single IPv4 address, e.g. `10.1.2.2`. *end_address*::: The last address of this reservation block, inclusive. I.e., for cases when reservations are only single addresses, end_address and start_address will be the same. Must be specified as a single IPv4 address, e.g. `10.1.2.2`. *note*::: A note about this reservation, intended for human consumption. """, hidden=hidden) group_arg.add_argument( '--remove-ip-range-reservation', type=arg_parsers.ArgDict(spec=IP_RESERVATION_KEY_SPEC), metavar='PROPERTY=VALUE', help=""" Remove a reservation of a range of IP addresses in the network. *start_address*::: The first address of the reservation block to remove. *end_address*::: The last address of the reservation block to remove. """, hidden=hidden) group_arg.add_argument( '--clear-ip-range-reservations', action='store_true', help="""Removes all IP range reservations in the network.""", hidden=hidden) def AddNfsSizeGibArg(parser): """Adds size GiB argument for NFS.""" parser.add_argument( '--size-gib', help='The requested size of the NFS share in GiB', type=int, required=True) def AddNfsStorageTypeArg(parser): """Adds storage type argument for NFS.""" parser.add_argument( '--storage-type', choices={ 'SSD': 'The storage type of the underlying volume will be SSD', 'HDD': 'The storage type of the underlying volume will be HDD' }, required=True, type=arg_utils.ChoiceToEnumName, help=('Specifies the storage type of the underlying volume which will be' ' created for the NFS share.')) def AddNfsAllowedClientArg(parser): parser.add_argument( '--allowed-client', type=arg_parsers.ArgDict(spec=NFS_ALLOWED_CLIENT_SPEC, required_keys=REQUIRED_NFS_ALLOWED_CLIENT_KEYS, ), required=True, action='append', metavar='PROPERTY=VALUE', help=NFS_ALLOWED_CLIENTS_HELP_TEXT, ) def AddNfsUpdateAllowedClientArgs(parser, hidden): """Adds NFS update allowed clients arguments group.""" group_arg = parser.add_mutually_exclusive_group(required=False, hidden=hidden) group_arg.add_argument( '--add-allowed-client', type=arg_parsers.ArgDict( spec=NFS_ALLOWED_CLIENT_SPEC, required_keys=REQUIRED_NFS_ALLOWED_CLIENT_KEYS, ), action='append', metavar='PROPERTY=VALUE', help=NFS_ALLOWED_CLIENTS_HELP_TEXT, ) group_arg.add_argument( '--remove-allowed-client', type=arg_parsers.ArgDict( spec=REMOVE_NFS_ALLOWED_CLIENT_SPEC, required_keys=REQUIRED_REMOVE_NFS_ALLOWED_CLIENT_KEYS, ), action='append', metavar='PROPERTY=VALUE', help=""" Removes an allowed client for the NFS share given its network name and cidr. This flag can be repeated to remove multiple allowed clients. *network*::: The name of the network of the allowed client to remove. *network-project-id*::: The project ID of the allowed client network. If not present, the project ID of the NFS share will be used. *cidr*::: The subnet of permitted IP addresses of the allowed client to remove. """) group_arg.add_argument( '--clear-allowed-clients', action='store_true', help="""Removes all IP range reservations in the network.""") def AddKMSCryptoKeyVersionToParser(parser, hidden): parser.add_argument( '--kms-crypto-key-version', type=str, help=""" Resource ID of a KMS CryptoKeyVersion used to encrypt the initial password. https://cloud.google.com/kms/docs/resource-hierarchy#key_versions """, hidden=hidden, )