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,32 @@
# -*- 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.
"""Transfer Appliance Order commands."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class Orders(base.Group):
"""Manage Transfer Appliance Orders.
Transfer Appliances are high-capacity storage devices that enable
the transfer and secure shipment of data to a Google upload facility, where
data is uploaded to Cloud Storage.
"""

View File

@@ -0,0 +1,175 @@
# -*- 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.
"""Command to create transfer appliance orders."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import uuid
from googlecloudsdk.api_lib.transfer.appliances import operations_util
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.api_lib.util import exceptions as gcloud_exception
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.transfer.appliances import flags
from googlecloudsdk.command_lib.transfer.appliances import mapping_util
from googlecloudsdk.command_lib.transfer.appliances import regions
from googlecloudsdk.command_lib.transfer.appliances import resource_args
DETAILED_HELP = {
'DESCRIPTION':
"""
*{command}* facilitates the creation of Transfer Appliance orders.
When an order is created, an appliance record is created as well.
""",
'EXAMPLES':
"""
To order a rackable appliance with 40 TB of storage, named
`my-appliance`, a Cloud Storage destination of `my-bucket` and the
minimum amount of contact information.
$ {command} my-appliance \
--model=TA40_RACKABLE \
--shipping-contact="name=Jane Doe,emails=[jane@example.com],phone=12345678910" \
--offline-import=gs://my-bucket \
--order-contact="name=John Doe,phone=123456578910,emails=[john@example.com]" --country=US \
--address="lines=['1600 Amphitheatre Parkway'],locality=Mountain View,administrative-area=CA,postal-code=94043"
To clone an appliance order with the ID `my-appliance` and location
`us-central1`, only changing the name and Cloud Storage destination:
$ {command} \
my-other-appliance --country=US --clone=my-appliance \
--clone-region=us-central1 --offline-import=my-other-bucket
To use a flags file to create an appliance rather than provide a
long list of flags:
$ {command} my-appliance \
--flags-file=FLAGS_FILE
Example file with all possible flags set:
--address:
lines:
- 1600 Amphitheatre Parkway
locality: Mountain View
administrative-area: California
postal-code: 94043
--cmek: projects/p/locations/global/keyRings/kr/cryptoKeys/ck
--country: US
--delivery-notes: None
--display-name: test
--internet-enabled:
--model: TA40_RACKABLE
--offline-export:
source: gs://my-bucket/path
manifest: gs://my-other-bucket/manifest
--offline-import: gs://my-bucket/path
--online-import: gs://my-bucket/path
--order-contact:
business: Google
name: Jane Doe
phone: 1234567890
emails:
- janedoe@example.com
--shipping-contact:
business: Google
name: John Doe
phone: 1234567890
emails:
- johndoe@example.com
""",
}
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class Create(base.Command):
"""Create an order for a transfer appliance."""
detailed_help = DETAILED_HELP
@staticmethod
def Args(parser):
parser.add_argument(
'name',
help='Immutable ID that will uniquely identify the appliance.')
parser.add_argument(
'--submit',
action='store_true',
help=(
'When specified the order will be submitted immediately. By '
'default, orders are created in a draft state. Use '
'`{parent_command} update --submit` to submit the order later.'
)
)
resource_args.add_clone_resource_arg(parser)
flags.add_appliance_settings(parser)
flags.add_delivery_information(parser)
@gcloud_exception.CatchHTTPErrorRaiseHTTPException(
'Status code: {status_code}. {status_message}.'
)
def Run(self, args):
client = apis.GetClientInstance('transferappliance', 'v1alpha1')
messages = apis.GetMessagesModule('transferappliance', 'v1alpha1')
appliance = messages.Appliance()
order = messages.Order()
results = []
region = regions.COUNTRY_TO_LOCATION_MAP[args.country]
parent = resource_args.get_parent_string(region)
if args.IsSpecified('clone'):
# Clone-specific logic.
clone_ref = args.CONCEPTS.clone.Parse()
order = client.projects_locations_orders.Get(
request=messages.TransferapplianceProjectsLocationsOrdersGetRequest(
name=clone_ref.RelativeName()))
if order.appliances:
# We only use the first appliance in a clone operation, as the
# workflow expects a 1:1 relationship of orders to appliances.
appliance = client.projects_locations_appliances.Get(
messages.TransferapplianceProjectsLocationsAppliancesGetRequest(
name=order.appliances[0]))
# Map args to the appliance resource and make the API call, append result.
mapping_util.apply_args_to_appliance(appliance, args)
operation = client.projects_locations_appliances.Create(
messages.TransferapplianceProjectsLocationsAppliancesCreateRequest(
appliance=appliance,
applianceId=args.name,
parent=parent,
requestId=uuid.uuid4().hex))
results.append(operations_util.wait_then_yield_appliance(
operation, 'create'))
# Map args to the order resource, make the API call, append result.
appliance_name = resource_args.get_appliance_name(region, args.name)
mapping_util.apply_args_to_order(order, args, appliance_name)
order.skipDraft = args.submit
operation = client.projects_locations_orders.Create(
messages.TransferapplianceProjectsLocationsOrdersCreateRequest(
order=order,
orderId=args.name,
parent=parent,
requestId=uuid.uuid4().hex))
results.append(operations_util.wait_then_yield_order(
operation, 'create'))
return results

View File

@@ -0,0 +1,84 @@
# -*- 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.
"""Command to delete Transfer Appliance Orders."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import uuid
from googlecloudsdk.api_lib.transfer.appliances import operations_util
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.api_lib.util import exceptions as gcloud_exception
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.transfer.appliances import resource_args
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class Delete(base.DeleteCommand):
"""Delete transfer appliance orders."""
detailed_help = {
'DESCRIPTION':
"""\
Delete transfer appliance orders.
""",
'EXAMPLES':
"""\
To delete an order, run:
$ {command} ORDER
To delete an order but keep the associated appliance records:
$ {command} ORDER --keep-appliances
""",
}
@staticmethod
def Args(parser):
resource_args.add_order_resource_arg(
parser, verb=resource_args.ResourceVerb.DELETE)
parser.add_argument(
'--keep-appliances',
action='store_true',
help=(
'Keep appliances associated with the order rather than deleting'
' them.'
))
@gcloud_exception.CatchHTTPErrorRaiseHTTPException(
'Status code: {status_code}. {status_message}.'
)
def Run(self, args):
client = apis.GetClientInstance('transferappliance', 'v1alpha1')
messages = apis.GetMessagesModule('transferappliance', 'v1alpha1')
order_ref = args.CONCEPTS.order.Parse()
# Get the order first to get to the appliance names to delete.
if not args.keep_appliances:
request = messages.TransferapplianceProjectsLocationsOrdersGetRequest(
name=order_ref.RelativeName())
order = client.projects_locations_orders.Get(request=request)
for appliance_name in order.appliances:
operation = client.projects_locations_appliances.Delete(
messages.TransferapplianceProjectsLocationsAppliancesDeleteRequest(
name=appliance_name, requestId=uuid.uuid4().hex))
operations_util.wait_then_yield_nothing(operation, 'delete appliance')
operation = client.projects_locations_orders.Delete(
messages.TransferapplianceProjectsLocationsOrdersDeleteRequest(
name=order_ref.RelativeName(), requestId=uuid.uuid4().hex))
return operations_util.wait_then_yield_nothing(operation, 'delete order')

View File

@@ -0,0 +1,55 @@
# -*- 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.
"""Command to describe Transfer Appliance Orders."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.transfer.appliances import resource_args
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class Describe(base.DescribeCommand):
"""Get information about Transfer Appliance orders."""
detailed_help = {
'DESCRIPTION':
"""\
Get information about transfer appliance orders.
""",
'EXAMPLES':
"""\
To describe an order by name, including its prefix, run:
$ {command} ORDER --region=REGION
""",
}
@staticmethod
def Args(parser):
resource_args.add_order_resource_arg(
parser, resource_args.ResourceVerb.DESCRIBE)
def Run(self, args):
client = apis.GetClientInstance('transferappliance', 'v1alpha1')
messages = apis.GetMessagesModule('transferappliance', 'v1alpha1')
order_ref = args.CONCEPTS.order.Parse()
request = messages.TransferapplianceProjectsLocationsOrdersGetRequest(
name=order_ref.RelativeName())
return client.projects_locations_orders.Get(request=request)

View File

@@ -0,0 +1,72 @@
# -*- 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.
"""Command to list Transfer Appliances."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import list_pager
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.transfer.appliances import resource_args
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class List(base.ListCommand):
"""List Transfer Appliance orders."""
detailed_help = {
'DESCRIPTION':
"""\
List Transfer Appliances in a given project to show their state and
corresponding orders.
""",
'EXAMPLES':
"""\
To list all appliances in your current project, run:
$ {command}
To list all information about all jobs formatted as JSON, run:
$ {command} --format=json
""",
}
@staticmethod
def Args(parser):
resource_args.add_list_resource_args(parser, listing_orders=True)
parser.display_info.AddFormat(
"""
yaml(name,appliances,state,submit_time.date(),update_time.date())
""")
def Run(self, args):
"""Command execution logic."""
client = apis.GetClientInstance('transferappliance', 'v1alpha1')
messages = apis.GetMessagesModule('transferappliance', 'v1alpha1')
return list_pager.YieldFromList(
client.projects_locations_orders,
messages.TransferapplianceProjectsLocationsOrdersListRequest(
filter=resource_args.parse_list_resource_args_as_filter_string(
args, listing_orders=True),
orderBy='name asc',
parent=resource_args.get_parent_string(args.region)),
batch_size_attribute='pageSize',
field='orders')

View File

@@ -0,0 +1,124 @@
# -*- 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.
"""Command to update transfer appliance orders."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import uuid
from googlecloudsdk.api_lib.transfer.appliances import operations_util
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.api_lib.util import exceptions as gcloud_exception
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.transfer.appliances import flags
from googlecloudsdk.command_lib.transfer.appliances import mapping_util
from googlecloudsdk.command_lib.transfer.appliances import resource_args
from googlecloudsdk.core import log
DETAILED_HELP = {
'DESCRIPTION':
"""
*{command}* facilitates the update of Transfer Appliance Orders.
""",
'EXAMPLES':
"""
To update the shipping contact of an appliance called `my-appliance`:
$ {command} my-appliance --shipping-contact="name=Jane Doe,emails=[jane@example.com],phone=12345678910"
""",
}
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class Update(base.Command):
"""Update an order for a transfer appliance."""
detailed_help = DETAILED_HELP
@staticmethod
def Args(parser):
resource_args.add_order_resource_arg(
parser, resource_args.ResourceVerb.UPDATE)
parser.add_argument(
'--submit',
action='store_true',
help='Submits an order that is in draft.')
flags.add_appliance_settings(parser, for_create_command=False)
flags.add_delivery_information(parser, for_create_command=False)
@gcloud_exception.CatchHTTPErrorRaiseHTTPException(
'Status code: {status_code}. {status_message}.'
)
def Run(self, args):
client = apis.GetClientInstance('transferappliance', 'v1alpha1')
messages = apis.GetMessagesModule('transferappliance', 'v1alpha1')
name = args.CONCEPTS.order.Parse().RelativeName()
results = []
# Get the order first to get to the appliance ID.
order = client.projects_locations_orders.Get(
messages.TransferapplianceProjectsLocationsOrdersGetRequest(name=name))
if order.appliances:
# We only use the first appliance in update operations, as the workflow
# expects a 1:1 relationship of orders to appliances.
appliance_name = order.appliances[0]
if len(order.appliances) > 1:
log.warning(
'Only 1 appliance per order is supported. {} will be updated and'
' all others will be ignored.'.format(appliance_name))
appliance = messages.Appliance()
update_mask = mapping_util.apply_args_to_appliance(appliance, args)
if update_mask:
operation = client.projects_locations_appliances.Patch(
messages.TransferapplianceProjectsLocationsAppliancesPatchRequest(
name=appliance_name,
appliance=appliance,
requestId=uuid.uuid4().hex,
updateMask=update_mask,
)
)
results.append(operations_util.wait_then_yield_appliance(
operation, 'update'))
# Map args to the order resource, make the API call if needed.
update_mask = mapping_util.apply_args_to_order(order, args)
if update_mask:
operation = client.projects_locations_orders.Patch(
messages.TransferapplianceProjectsLocationsOrdersPatchRequest(
name=name,
order=order,
requestId=uuid.uuid4().hex,
updateMask=update_mask,
)
)
results.append(operations_util.wait_then_yield_order(operation, 'update'))
if args.submit:
operation = client.projects_locations_orders.Submit(
messages.TransferapplianceProjectsLocationsOrdersSubmitRequest(
name=name))
if update_mask:
# We don't want to dump out the order twice, so when an order update
# already occurred we just wait for the submit operation to complete.
operations_util.wait_then_yield_nothing(operation, 'submit')
else:
# Since there's no update operation on the order we can yield an order
# and add it to the result output.
results.append(operations_util.wait_then_yield_order(
operation, 'submit'))
if not results:
log.warning('No updates were performed.')
return results