# -*- coding: utf-8 -*- # # Copyright 2023 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 and helpers for the config-manager command group.""" from __future__ import absolute_import from __future__ import division from __future__ import unicode_literals from googlecloudsdk.api_lib.functions.v1 import util as functions_api_util from googlecloudsdk.api_lib.infra_manager import configmanager_util from googlecloudsdk.calliope import arg_parsers from googlecloudsdk.calliope import base def AddLabelsFlag(parser, help_text): """Add --labels flag.""" parser.add_argument( '--labels', metavar='KEY=VALUE', type=arg_parsers.ArgDict(), help=help_text, ) def AddAnnotationsFlag(parser, help_text): """Add --annotations flag.""" parser.add_argument( '--annotations', metavar='KEY=VALUE', type=arg_parsers.ArgDict(), help=help_text, ) def AddAsyncFlag(parser): """Add --async flag.""" base.ASYNC_FLAG.AddToParser(parser) def AddTerraformBlueprintFlag(parser): """Add TerraformBlueprint related flags.""" input_values_help_text = """\ Input variable values for the Terraform blueprint. It only accepts (key, value) pairs where value is a scalar value. Examples: Pass input values on command line: $ {command} projects/p1/location/us-central1/deployments/my-deployment --gcs-source="gs://my-bucket" --input-values=projects=p1,region=r """ inputs_file_help_text = """\ A .tfvars file containing terraform variable values. --inputs-file flag is supported for python version 3.6 and above. Examples: Pass input values on the command line: $ {command} projects/p1/location/us-central1/deployments/my-deployment --gcs-source="gs://my-bucket" --inputs-file=path-to-tfvar-file.tfvar """ gcs_source_help_text = """\ URI of an object in Google Cloud Storage. e.g. `gs://{bucket}/{object}` Examples: Create a deployment from a storage my-bucket: $ {command} projects/p1/location/us-central1/deployments/my-deployment --gcs-source="gs://my-bucket" """ git_source_repo_help = """\ Repository URL. Example: 'https://github.com/examples/repository.git' Use in conjunction with `--git-source-directory` and `--git-source_ref` Examples: Create a deployment from the "https://github.com/examples/repository.git" repo, "staging/compute" folder, "mainline" branch: $ {command} projects/p1/location/us-central1/deployments/my-deployment --git-source-repo="https://github.com/examples/repository.git" --git-source-directory="staging/compute" --git-source-ref="mainline" """ git_source_directory_help = """\ Subdirectory inside the repository. Example: 'staging/my-package' Use in conjunction with `--git-source-repo` and `--git-source-ref` Examples: Create a deployment from the "https://github.com/examples/repository.git" repo, "staging/compute" folder, "mainline" branch: $ {command} projects/p1/location/us-central1/deployments/my-deployment --git-source-repo="https://github.com/examples/repository.git" --git-source-directory="staging/compute" --git-source-ref="mainline" """ git_source_ref_help = """\ Subdirectory inside the repository. Example: 'staging/my-package' Use in conjunction with `--git-source-repo` and `--git-source-directory` Examples: Create a deployment from the "https://github.com/examples/repository.git" repo, "staging/compute" folder, "mainline" branch: $ {command} projects/p1/location/us-central1/deployments/my-deployment --git-source-repo="https://github.com/examples/repository.git" --git-source-directory="staging/compute" --git-source-ref="mainline" """ local_source_help = """\ Local storage path where config files are stored. When using this option, Terraform config file references outside this storage path is not supported. e.g. `./path/to/blueprint` Examples: Create a deployment from a local storage path `./path/to/blueprint`: $ {command} projects/p1/location/us-central1/deployments/my-deployment --local-source="./path/to/blueprint" """ stage_bucket_help = """\ Use in conjunction with `--local-source` to specify a destination storage bucket for uploading local files. If unspecified, the bucket defaults to `gs://PROJECT_NAME_blueprints`. Uploaded content will appear in the `source` object under a name comprised of the timestamp and a UUID. The final output destination looks like this: `gs://_BUCKET_/source/1615850562.234312-044e784992744951b0cd71c0b011edce/` Examples: Create a deployment from a local storage path `./path/to/blueprint` and stage-bucket `gs://my-bucket`: $ {command} projects/p1/location/us-central1/deployments/my-deployment --local-source="./path/to/blueprint" --stage-bucket="gs://my-bucket" """ source_group = parser.add_group(mutex=False) input_values = source_group.add_mutually_exclusive_group() input_values.add_argument( '--input-values', metavar='KEY=VALUE', type=arg_parsers.ArgDict(), help=input_values_help_text, ) input_values.add_argument( '--inputs-file', help=inputs_file_help_text, ) source_details = source_group.add_mutually_exclusive_group() source_details.add_argument( '--gcs-source', help=gcs_source_help_text, ) git_source_group = source_details.add_group(mutex=False) git_source_group.add_argument( '--git-source-repo', help=git_source_repo_help, ) git_source_group.add_argument( '--git-source-directory', help=git_source_directory_help, ) git_source_group.add_argument( '--git-source-ref', help=git_source_ref_help, ) local_source_group = source_details.add_group(mutex=False) local_source_group.add_argument( '--local-source', help=local_source_help, ) local_source_group.add_argument( '--ignore-file', help=( 'Override the `.gcloudignore` file and use the specified file ' 'instead. See `gcloud topic gcloudignore` for more information.' ), ) # Note: we cannot specify a default here since the default value we would WANT # to use is dynamic; it includes the project ID. local_source_group.add_argument( '--stage-bucket', help=stage_bucket_help, hidden=True, # This will ensure that "--stage-bucket" takes on the form # "gs://my-bucket/". type=functions_api_util.ValidateAndStandarizeBucketUriOrRaise, ) def AddServiceAccountFlag(parser, hidden=False): """Add --service-account flag.""" parser.add_argument( '--service-account', hidden=hidden, help=( 'User-specified Service Account (SA) to be used as credential to' ' manage resources. Format:' ' `projects/{projectID}/serviceAccounts/{serviceAccount}`' ), ) def AddImportExistingResourcesFlag(parser, hidden=False): """Add --import-existing-resources flag.""" parser.add_argument( '--import-existing-resources', hidden=hidden, action='store_true', help=( 'By default, Infrastructure Manager will return a failure when' ' Terraform encounters a 409 code (resource conflict error) during' ' actuation. If this flag is set to true, Infrastructure Manager will' ' instead attempt to automatically import the resource into the' ' Terraform state (for supported resource types) and continue' ' actuation.' ), ) def AddWorkerPoolFlag(parser, hidden=False): """Add --worker-pool flag.""" parser.add_argument( '--worker-pool', hidden=hidden, help=( 'User-specified Worker Pool resource in which the Cloud Build job ' 'will execute. Format: ' 'projects/{project}/locations/{location}/workerPools/{workerPoolId}' ), ) def AddArtifactsGCSBucketFlag(parser, hidden=False): """Add --artifacts-gcs-bucket flag.""" parser.add_argument( '--artifacts-gcs-bucket', hidden=hidden, help=( 'user-defined location of Cloud Build logs, artifacts, and Terraform' ' state files in Google Cloud Storage. Format:' ' `gs://{bucket}/{folder}` A default bucket will be bootstrapped if' ' the field is not set or empty' ), ) def AddDraftFlag(parser, hidden=False): """Add --draft flag.""" parser.add_argument( '--draft', hidden=hidden, help=( 'If this flag is set to true, the exported deployment state file will' ' be the draft state' ), action='store_true', ) def AddLockFlag(parser, hidden=False): """Add --lock-id flag.""" parser.add_argument( '--lock-id', required=True, hidden=hidden, help='Lock ID of the lock file to verify person importing owns lock.', ) def AddDeploymentFlag(parser, hidden=False): """Add --deployment flag.""" parser.add_argument( '--deployment', hidden=hidden, help='Deployment reference for preview.', ) def AddPreviewModeFlag(parser, hidden=False): """Add --preview-mode flag.""" parser.add_argument( '--preview-mode', hidden=hidden, help='Preview mode to set it to either default or delete.', ) def AddFileFlag(parser, help_text, hidden=False): """Add --file flag.""" parser.add_argument( '--file', hidden=hidden, help=help_text, ) def AddTFVersionConstraintFlag(parser, hidden=False): """Add --tf-version-constraint flag.""" parser.add_argument( '--tf-version-constraint', hidden=hidden, help=( 'User-specified Terraform version constraint, for example "=1.3.10".' ), ) def AddQuotaValidationFlag(parser, hidden=False): """Add --quota-validation flag.""" parser.add_argument( '--quota-validation', hidden=hidden, help=( 'Input to control quota checks for resources in terraform' ' configuration files. There are limited resources on which quota' ' validation applies. Supported values are' ' QUOTA_VALIDATION_UNSPECIFIED, ENABLED, ENFORCED' ), type=QuotaValidationEnum, ) def QuotaValidationEnum(quota_validation): """Checks if a quota validation provided by user is valid and returns corresponding enum type. Args: quota_validation: value for quota validation. Returns: quota validation enum Raises: ArgumentTypeError: If the value provided by user is not valid. """ messages = configmanager_util.GetMessagesModule() quota_validation_enum_dict = { 'QUOTA_VALIDATION_UNSPECIFIED': ( messages.Deployment.QuotaValidationValueValuesEnum.QUOTA_VALIDATION_UNSPECIFIED ), 'ENABLED': messages.Deployment.QuotaValidationValueValuesEnum.ENABLED, 'ENFORCED': messages.Deployment.QuotaValidationValueValuesEnum.ENFORCED, } if quota_validation is None: return if quota_validation not in quota_validation_enum_dict: raise arg_parsers.ArgumentTypeError( "quota validation does not support: '{0}', supported values are: {1}" .format(quota_validation, list(quota_validation_enum_dict)) ) return quota_validation_enum_dict[quota_validation] # TODO: b/433318303 - Remove `hidden` annotation to make dark site # commands public. def AddProviderSourceFlag(parser, hidden=True): """Add --provider-source flag.""" parser.add_argument( '--provider-source', hidden=hidden, help=( 'Input to control from where to fetch providers. Supported values are' 'PROVIDER_SOURCE_UNSPECIFIED, SERVICE_MAINTAINED' ), type=ProviderSourceEnum, ) def ProviderSourceEnum(provider_source): """Checks if a provider config provided by user is valid and returns corresponding enum type. Args: provider_source: value for provider source. Returns: provider source enum Raises: ArgumentTypeError: If the value provided by user is not valid. """ messages = configmanager_util.GetMessagesModule() provider_source_enum_dict = { 'PROVIDER_SOURCE_UNSPECIFIED': ( messages.ProviderConfig.SourceTypeValueValuesEnum.PROVIDER_SOURCE_UNSPECIFIED ), 'SERVICE_MAINTAINED': ( messages.ProviderConfig.SourceTypeValueValuesEnum.SERVICE_MAINTAINED ), } if provider_source is None: return if provider_source not in provider_source_enum_dict: raise arg_parsers.ArgumentTypeError( "provider config does not support: '{0}', supported values are: {1}" .format(provider_source, list(provider_source_enum_dict)) ) return provider_source_enum_dict[provider_source]