430 lines
13 KiB
Python
430 lines
13 KiB
Python
# -*- 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]
|