feat: Add new gcloud commands, API clients, and third-party libraries across various services.

This commit is contained in:
2026-01-01 20:26:35 +01:00
parent 5e23cbece0
commit a19e592eb7
25221 changed files with 8324611 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 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.
"""The archives command group for the Apigee CLI."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.projects import util
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Archives(base.Group):
"""Manage Apigee archive deployments."""
detailed_help = {
"EXAMPLES": """
To deploy a local archive deployment remotely to the management plane
in the ``test'' environment, run:
$ {command} deploy --environment=test
To list all archive deployments in the ``dev'' environment, run:
$ {command} list --environment=dev
To describe the archive deployment with id ``abcdef01234'' in the
``demo'' environment of the ``my-org'' Apigee organization, run:
$ {command} describe abcdef01234 --environment=demo --organization=my-org
To update the labels of the archive deployment with id
``uvxwzy56789'' in the ``test'' environment, run:
$ {command} update uvxwzy56789 --environment=demo --update-labels=foo=1,bar=2
""",
}

View File

@@ -0,0 +1,70 @@
# -*- coding: utf-8 -*- # Lint as: python3
# Copyright 2021 Google Inc. 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 to delete an archive deployment in an Apigee organization."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib import apigee
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.apigee import defaults
from googlecloudsdk.command_lib.apigee import resource_args
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Delete(base.DeleteCommand):
"""Delete an Apigee archive deployment."""
detailed_help = {
"DESCRIPTION":
"""\
{description}
`{command}` deletes an Apigee archive deployment.""",
"EXAMPLES":
"""\
To delete an archive deployment with the ID ``abcdefghijkl123456'' in the
environment called ``my-env'' using the active Cloud Platform project, run:
$ {command} abcdefghijkl123456 --environment=my-env
To delete an archive deployment with the ID ``mnopqurstuvw654321'', in an
environment called ``my-env'', in an organization called ``my-org'', run:
$ {command} mnopqurstuvw654321 --environment=my-env --organization=my-org
"""
}
@staticmethod
def Args(parser):
resource_args.AddSingleResourceArgument(
parser,
"organization.environment.archive_deployment",
"Apigee archive deployment to delete.",
argument_name="archive_deployment",
positional=True,
required=True,
fallthroughs=[defaults.GCPProductOrganizationFallthrough()])
def Run(self, args):
"""Run the describe command."""
identifiers = args.CONCEPTS.archive_deployment.Parse().AsDict()
archive_id = identifiers["archiveDeploymentsId"]
msg = "Archive deployment [{}] will be deleted.".format(archive_id)
if console_io.PromptContinue(message=msg):
apigee.ArchivesClient.Delete(identifiers)
log.status.Print("Archive deployment [{}] deleted.".format(archive_id))

View File

@@ -0,0 +1,204 @@
# -*- coding: utf-8 -*- # Lint as: python3
# Copyright 2021 Google Inc. 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 to deploy an Apigee archive deployment to an environment."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib import apigee
from googlecloudsdk.api_lib.util import waiter
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.apigee import archives as cmd_lib
from googlecloudsdk.command_lib.apigee import defaults
from googlecloudsdk.command_lib.apigee import errors
from googlecloudsdk.command_lib.apigee import resource_args
from googlecloudsdk.command_lib.util.args import labels_util
from googlecloudsdk.core import log
from googlecloudsdk.core.util import files
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Deploy(base.DescribeCommand):
"""Deploy an Apigee archive deployment to an environment."""
detailed_help = {
"DESCRIPTION":
"""\
{description}
`{command}` installs an archive deployment in an Apigee environment.
By default, the archive deployment will be deployed on the remote management
plane for the specified Apigee organization. To deploy on a locally running
Apigee emulator, use the `--local` flag.
""",
"EXAMPLES":
"""\
To deploy the contents of the current working directory as an archive
deployment to an environment named ``my-test'', given that the Cloud Platform
project has been set in gcloud settings, run:
$ {command} --environment=my-test
To deploy an archive deployment from a local directory other than the current
working directory, to an environment named ``my-demo'' in an organization
belonging to a Cloud Platform project other than the one set in gcloud
settings, named ``my-org'', run:
$ {command} --organization=my-org --environment=my-demo --source=/apigee/dev
To deploy the contents of the current working directory as an archive
deployment, with the user-defined labels ``my-label1=foo'' and
``my-label2=bar'', to an environment named ``my-test'', given that the Cloud
Platform project has been set in gcloud settings, run:
$ {command} --environment=my-test --labels=my-label1=foo,my-label2=bar
"""
}
@staticmethod
def Args(parser):
fallthroughs = [defaults.GCPProductOrganizationFallthrough()]
resource_args.AddSingleResourceArgument(
parser,
resource_path="organization.environment",
help_text=("Apigee environment in which to deploy the archive "
"deployment."),
fallthroughs=fallthroughs,
positional=False,
required=True)
# Create a argument group to manage that only one of either --source or
# --bundle-file flags are provided on the command line.
source_input_group = parser.add_group(mutex=True, help="Source input.")
source_input_group.add_argument(
"--source",
required=False,
type=files.ExpandHomeDir,
help="The source directory of the archive to upload.")
source_input_group.add_argument(
"--bundle-file",
required=False,
type=files.ExpandHomeDir,
help="The zip file containing an archive to upload.")
parser.add_argument(
"--async",
action="store_true",
dest="async_",
help=("If set, returns immediately and outputs a description of the "
"long running operation that was launched. Else, `{command}` "
"will block until the archive deployment has been successfully "
"deployed to the specified environment.\n\n"
"To monitor the operation once it's been launched, run "
"`{grandparent_command} operations describe OPERATION_NAME`."))
# This adds the --labels flag.
labels_util.AddCreateLabelsFlags(parser)
def _GetUploadUrl(self, identifiers):
"""Gets the signed URL for uploading the archive deployment.
Args:
identifiers: A dict of resource identifers. Must contain "organizationsId"
and "environmentsId"
Returns:
A str of the upload URL.
Raises:
googlecloudsdk.command_lib.apigee.errors.RequestError if the "uploadUri"
field is not included in the GetUploadUrl response.
"""
get_upload_url_resp = apigee.ArchivesClient.GetUploadUrl(identifiers)
if "uploadUri" not in get_upload_url_resp:
raise errors.RequestError(
resource_type="getUploadUrl",
resource_identifier=identifiers,
body=get_upload_url_resp,
user_help="Please try again.")
return get_upload_url_resp["uploadUri"]
def _UploadArchive(self, upload_url, zip_file_path):
"""Issues an HTTP PUT call to the upload URL with the zip file payload.
Args:
upload_url: A str containing the full upload URL.
zip_file_path: A str of the local path to the zip file.
Raises:
googlecloudsdk.command_lib.apigee.errors.HttpRequestError if the response
status of the HTTP PUT call is not 200 (OK).
"""
upload_archive_resp = cmd_lib.UploadArchive(upload_url, zip_file_path)
if not upload_archive_resp.ok:
raise errors.HttpRequestError(upload_archive_resp.status_code,
upload_archive_resp.reason,
upload_archive_resp.content)
def _DeployArchive(self, identifiers, upload_url, labels):
"""Creates the archive deployment.
Args:
identifiers: A dict of resource identifers. Must contain "organizationsId"
and "environmentsId"
upload_url: A str containing the full upload URL.
labels: A dict of the key/value pairs to add as labels.
Returns:
A dict containing the operation metadata.
"""
post_data = {}
post_data["gcs_uri"] = upload_url
if labels:
post_data["labels"] = {}
for k, v in labels.items():
post_data["labels"][k] = v
api_response = apigee.ArchivesClient.CreateArchiveDeployment(
identifiers, post_data)
operation = apigee.OperationsClient.SplitName(api_response)
return operation
def Run(self, args):
"""Run the deploy command."""
identifiers = args.CONCEPTS.environment.Parse().AsDict()
labels_arg = labels_util.GetUpdateLabelsDictFromArgs(args)
local_dir_archive = None
try:
local_dir_archive = cmd_lib.LocalDirectoryArchive(args.source)
if args.bundle_file:
local_dir_archive.ValidateZipFilePath(args.bundle_file)
zip_file_path = args.bundle_file
else:
zip_file_path = local_dir_archive.Zip()
upload_url = self._GetUploadUrl(identifiers)
self._UploadArchive(upload_url, zip_file_path)
operation = self._DeployArchive(identifiers, upload_url, labels_arg)
if "organization" not in operation or "uuid" not in operation:
raise waiter.OperationError(
"Unknown operation response: {}".format(operation))
if "warnings" in operation["metadata"]:
for warning in operation["metadata"]["warnings"]:
log.warning(warning)
log.info("Started archives deploy operation %s", operation["name"])
if args.async_:
return operation
waiter.WaitFor(
apigee.LROPoller(operation["organization"]),
operation["uuid"],
message="Waiting for operation [{}] to complete".format(
operation["uuid"]),
wait_ceiling_ms=5000,
)
finally:
if local_dir_archive and hasattr(local_dir_archive, "Close"):
local_dir_archive.Close()

View File

@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*- # Lint as: python3
# Copyright 2021 Google Inc. 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 to describe an archive deployment in an Apigee organization."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib import apigee
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.apigee import archives as archive_helper
from googlecloudsdk.command_lib.apigee import defaults
from googlecloudsdk.command_lib.apigee import resource_args
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Describe(base.DescribeCommand):
"""Describe an Apigee archive deployment."""
detailed_help = {
"DESCRIPTION":
"""\
{description}
`{command}` shows metadata about an Apigee archive deployment.""",
"EXAMPLES":
"""\
To describe an archive deployment with the id ``abcdef1234'' in the Apigee
environment called ``my-env'' using the active Cloud Platform project, run:
$ {command} abcdef1234 --environment=my-env
To describe an archive deployment with the id ``1234abcdef'', in the Apigee
environment called ``my-env'', in an organization called ``my-org'', as a JSON
object, run:
$ {command} 1234abcdef --environment=my-env --organization=my-org --format=json
"""
}
@staticmethod
def Args(parser):
resource_args.AddSingleResourceArgument(
parser,
"organization.environment.archive_deployment",
help_text="Archive deployment to be described. To get a list of "
"available archive deployments, run `{parent_command} list`.",
argument_name="archive_deployment",
positional=True,
required=True,
fallthroughs=[defaults.GCPProductOrganizationFallthrough()])
def Run(self, args):
"""Run the describe command."""
identifiers = args.CONCEPTS.archive_deployment.Parse().AsDict()
org = identifiers["organizationsId"]
archive_name = (
"organizations/{}/environments/{}/archiveDeployments/{}".format(
org, identifiers["environmentsId"],
identifiers["archiveDeploymentsId"]))
archive_list_response = apigee.ArchivesClient.List(identifiers)
if not archive_list_response:
return apigee.ArchivesClient.Describe(identifiers)
extended_archives = archive_helper.ListArchives(org).ExtendedArchives(
archive_list_response)
for a in extended_archives:
if a["name"] == archive_name:
return a
return apigee.ArchivesClient.Describe(identifiers)

View File

@@ -0,0 +1,101 @@
# -*- coding: utf-8 -*- # Lint as: python3
# Copyright 2021 Google Inc. 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 to list all Apigee archive deployments in an environment."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib import apigee
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.apigee import archives as archive_helper
from googlecloudsdk.command_lib.apigee import defaults
from googlecloudsdk.command_lib.apigee import resource_args
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class List(base.ListCommand):
"""List Apigee archive deployments."""
detailed_help = {
"EXAMPLES":
"""\
To list all archive deployments, in an environment called ``my-env'', for the
active Cloud Platform project, run:
$ {command} --environment=my-env
To list all archive deployments, for an environment named ``my-env'', in an
organization called ``my-org'', run:
$ {command} --environment=my-env --organization=my-org
To list all archive deployments formatted as a JSON array, run:
$ {command} --environment=my-env --format=json
"""
}
@staticmethod
def Args(parser):
resource_args.AddSingleResourceArgument(
parser,
"organization.environment",
"Apigee environment whose archive deployments should be listed.",
positional=False,
required=True,
fallthroughs=[defaults.GCPProductOrganizationFallthrough()])
# The response is a JSON array of archive deployment descriptors, so the
# array needs to be flattened to display as a table.
parser.display_info.AddFlatten(["archiveDeployments[]"])
# Cloud SDK projections can be used to format each column of the display
# table:
# https://cloud.google.com/sdk/gcloud/reference/topic/projections
# The "ARCHIVE ID" column scopes the resource path in the "name" field of
# the API response to only show the id of the archive deployment.
archive_id_col = ("archiveDeployments.name.scope(archiveDeployments)"
":label='ARCHIVE ID'")
# The "ENVIORNMENT" column scopes the resource path in the "name" field of
# the API response to only show the Apigee environment id.
env_id_col = ("archiveDeployments.name.scope(environments).segment(0)"
":label=ENVIRONMENT")
# The "CREATED AT" column formats the posix epoch in the "createdAt" field
# of the API response into a human-readable date format.
created_col = ("archiveDeployments.createdAt.date("
"format='%Y-%m-%d %H:%M:%S %Z', unit=1000000, tz=LOCAL)"
":label='DEPLOYED AT'")
# The labels field is a list of key/value pairs so it is flattened to
# display in the table.
labels_col = "archiveDeployments.labels.flatten()"
# The status column uses operation metadata and timestamps to determine
# the current status of the archive deployment.
status_col = ("archiveDeployments.operationStatus:label='OPERATION STATUS'")
cols = ", ".join(
[archive_id_col, env_id_col, created_col, labels_col, status_col])
# Format the column definitions into a table.
table_fmt = "table({})".format(cols)
parser.display_info.AddFormat(table_fmt)
def Run(self, args):
"""Run the list command."""
identifiers = args.CONCEPTS.environment.Parse().AsDict()
org = identifiers["organizationsId"]
archive_response = apigee.ArchivesClient.List(identifiers)
extended_archives = archive_helper.ListArchives(org).ExtendedArchives(
archive_response)
return {"archiveDeployments": extended_archives}

View File

@@ -0,0 +1,95 @@
# -*- coding: utf-8 -*- # Lint as: python3
# Copyright 2021 Google Inc. 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 to update an archive deployment in an Apigee organization."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib import apigee
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.apigee import defaults
from googlecloudsdk.command_lib.apigee import resource_args
from googlecloudsdk.command_lib.util.args import labels_util
# DEVELOPER NOTE: This command inherits from the base.DescribeCommand (as
# opposed to the base.UpdateCommand) to get the print functionality of the
# return value (the base.UpdateCommand is silent) in order to print the updated
# archive deployment after the command is run.
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Update(base.DescribeCommand):
"""Update an existing Apigee archive deployment."""
detailed_help = {
"DESCRIPTION":
"""\
{description}
`{command}` updates an Apigee archive deployment.""",
"EXAMPLES":
"""\
To update the ``tag'' and ``rev'' labels of an archive deployment with the id
``abcdef01234'' in the Apigee environment called ``my-env'' using the active
Cloud Platform project, run:
$ {command} abcdef01234 --environment=my-env --update-labels=tag=my-tag,rev=1234
To remove the ``dev'' label on an archive deployment with the id
``uvwxyz56789'', in the Apigee environment called ``my-env'', in an
organization called ``my-org'', run:
$ {command} uvwxyz56789 --environment=my-env --organization=my-org --remove-labels=dev
To clear all labels on an archive deployment with the id ``mnop4321'', in
the Apigee environment called ``my-env'', in an organization called
``my-org'', and return the updated archive deployment as a JSON object, run:
$ {command} mnop4321 --environment=my-env --organization=my-org --clear-labels --format=json
"""
}
@staticmethod
def Args(parser):
resource_args.AddSingleResourceArgument(
parser,
"organization.environment.archive_deployment",
help_text="Archive deployment to update. To get a list of "
"existing archive deployments, run `{parent_command} list`.",
argument_name="archive_deployment",
positional=True,
required=True,
fallthroughs=[defaults.GCPProductOrganizationFallthrough()])
# This adds the --update-labels, --remove-labels and --clear-labels flags.
labels_util.AddUpdateLabelsFlags(parser)
def Run(self, args):
"""Run the update command."""
labels_util.GetAndValidateOpsFromArgs(args)
identifiers = args.CONCEPTS.archive_deployment.Parse().AsDict()
# First get the existing lables by calling describe on the current archive.
existing_archive = apigee.ArchivesClient.Describe(identifiers)
# Modify the label set based on provided flag values.
if "labels" in existing_archive and not args.clear_labels:
new_labels = existing_archive["labels"]
else:
new_labels = {}
if args.update_labels:
new_labels.update(args.update_labels)
if args.remove_labels:
for label in args.remove_labels:
if label in new_labels:
del new_labels[label]
labels_proto = {"labels": new_labels}
return apigee.ArchivesClient.Update(identifiers, labels_proto)