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,63 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""API client library for Application Templates."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.design_center import utils
from googlecloudsdk.calliope import base
class ApplicationTemplatesClient(object):
"""Client for Application Templates in the Design Center API."""
def __init__(self, release_track=base.ReleaseTrack.ALPHA):
self.client = utils.GetClientInstance(release_track)
self.messages = utils.GetMessagesModule(release_track)
self._service = self.client.projects_locations_spaces_applicationTemplates
def ImportIac(self, name, gcs_uri=None, iac_module=None,
allow_partial_import=False, validate_iac=False):
"""Calls the ImportApplicationTemplateIaC RPC.
Args:
name: str, The full resource name of the Application Template.
gcs_uri: str, The GCS URI of the IaC source.
iac_module: messages.IaCModule, The IaCModule object.
allow_partial_import: bool, Whether to allow partial imports.
validate_iac: bool, Whether to only validate the IaC.
Returns:
The response from the API call.
"""
if not name:
raise ValueError('Application template name cannot be empty or None.')
import_iac_request = self.messages.ImportApplicationTemplateIaCRequest(
allowPartialImport=allow_partial_import,
validateIac=validate_iac)
if gcs_uri:
import_iac_request.gcsUri = gcs_uri
elif iac_module:
import_iac_request.iacModule = iac_module
request = self.messages.DesigncenterProjectsLocationsSpacesApplicationTemplatesImportIaCRequest(
name=name,
importApplicationTemplateIaCRequest=import_iac_request)
return self._service.ImportIaC(request)

View File

@@ -0,0 +1,64 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""API client library for Applications."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.design_center import utils
from googlecloudsdk.calliope import base
class ApplicationsClient(object):
"""Client for Applications in the Design Center API."""
def __init__(self, release_track=base.ReleaseTrack.ALPHA):
self.client = utils.GetClientInstance(release_track)
self.messages = utils.GetMessagesModule(release_track)
self._service = self.client.projects_locations_spaces_applications
def ImportIac(self, name, gcs_uri=None, iac_module=None,
allow_partial_import=False, validate_iac=False):
"""Calls the ImportApplicationIaC RPC.
Args:
name: str, The full resource name of the Application.
gcs_uri: str, The GCS URI of the IaC source.
iac_module: messages.IaCModule, The IaCModule object.
allow_partial_import: bool, Whether to allow partial imports.
validate_iac: bool, Whether to only validate the IaC.
Returns:
The response from the API call.
"""
if not name:
raise ValueError('Application name cannot be empty or None.')
import_iac_request = self.messages.ImportApplicationIaCRequest(
allowPartialImport=allow_partial_import,
validateIac=validate_iac)
if gcs_uri:
import_iac_request.gcsUri = gcs_uri
elif iac_module:
import_iac_request.iacModule = iac_module
request = (
self.messages.DesigncenterProjectsLocationsSpacesApplicationsImportIaCRequest(
name=name,
importApplicationIaCRequest=import_iac_request))
return self._service.ImportIaC(request)

View File

@@ -0,0 +1,70 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Designcenter Locations API."""
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.design_center import utils as api_lib_utils
from googlecloudsdk.calliope import base
class LocationsClient(object):
"""Client for locations in Designcenter API."""
def __init__(self, release_track=base.ReleaseTrack.ALPHA):
self.client = api_lib_utils.GetClientInstance(release_track)
self.messages = api_lib_utils.GetMessagesModule(release_track)
self._lo_client = self.client.projects_locations
def List(self, parent, limit=None, page_size=100):
"""List all Designcenter locations in the Project.
Args:
parent: str, the project in which the locations being listed.
projects/{projectId}
limit: int or None, the total number of results to return.
Default value is None
page_size: int, the number of entries in each batch (affects requests
made, but not the yielded results). Default value is 100.
Returns:
A list of Designcenter locations that belong to the given parent.
"""
list_req = self.messages.DesigncenterProjectsLocationsListRequest(
name=parent)
return list_pager.YieldFromList(
self._lo_client,
list_req,
field='locations',
batch_size=page_size,
limit=limit,
batch_size_attribute='pageSize',
)
def Describe(self, location):
"""Describe a Designcenter location.
Args:
location: str, the name for the Designcenter Location being described.
Returns:
Described Designcenter location resource.
"""
describe_req = self.messages.DesigncenterProjectsLocationsGetRequest(
name=location)
return self._lo_client.Get(describe_req)

View File

@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""DesignCenter SharedTemplateRevisions API."""
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.design_center import utils as api_lib_utils
from googlecloudsdk.calliope import base
class SharedTemplateRevisionsClient(object):
"""Client for SharedTemplateRevisions in DesignCenter API."""
def __init__(self, release_track=base.ReleaseTrack.ALPHA):
self.client = api_lib_utils.GetClientInstance(release_track)
self.messages = api_lib_utils.GetMessagesModule(release_track)
self._str_client = (
self.client.projects_locations_spaces_sharedTemplates_revisions
)
def List(self, parent, limit=None, page_size=100):
"""List all DesignCenter SharedTemplateRevisions under a shared template.
Args:
parent: str, the full resource name of the parent shared template. e.g.,
projects/{p}/locations/{l}/spaces/{s}/sharedTemplates/{st}
limit: int or None, the total number of results to return. Default value
is None
page_size: int, the number of entries in each batch (affects requests
made, but not the yielded results). Default value is 100.
Returns:
A list of DesignCenter SharedTemplateRevisions that belong to the given
parent.
"""
list_req = (
self.messages.DesigncenterProjectsLocationsSpacesSharedTemplatesRevisionsListRequest(
parent=parent
)
)
return list_pager.YieldFromList(
self._str_client,
list_req,
field='sharedTemplateRevisions',
batch_size=page_size,
limit=limit,
batch_size_attribute='pageSize',
)
def Describe(self, name):
"""Describe a DesignCenter SharedTemplateRevision.
Args:
name: str, the full resource name of the SharedTemplateRevision.
e.g., projects/{p}/locations/{l}/spaces/{s}/sharedTemplates/{st}/
revisions/{str}
Returns:
Described DesignCenter SharedTemplateRevision resource.
"""
describe_req = self.messages.DesigncenterProjectsLocationsSpacesSharedTemplatesRevisionsGetRequest(
name=name)
return self._str_client.Get(describe_req)

View File

@@ -0,0 +1,74 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""DesignCenter SharedTemplates API."""
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.design_center import utils as api_lib_utils
from googlecloudsdk.calliope import base
class SharedTemplatesClient(object):
"""Client for SharedTemplates in DesignCenter API."""
def __init__(self, release_track=base.ReleaseTrack.ALPHA):
self.client = api_lib_utils.GetClientInstance(release_track)
self.messages = api_lib_utils.GetMessagesModule(release_track)
self._st_client = self.client.projects_locations_spaces_sharedTemplates
def List(self, parent, limit=None, page_size=100):
"""List all DesignCenter SharedTemplates under a space.
Args:
parent: str, the full resource name of the parent space. e.g.,
projects/{p}/locations/{l}/spaces/{s}
limit: int or None, the total number of results to return. Default value
is None
page_size: int, the number of entries in each batch (affects requests
made, but not the yielded results). Default value is 100.
Returns:
A list of DesignCenter SharedTemplates that belong to the given parent.
"""
list_req = (
self.messages.DesigncenterProjectsLocationsSpacesSharedTemplatesListRequest(
parent=parent
)
)
return list_pager.YieldFromList(
self._st_client,
list_req,
field='sharedTemplates',
batch_size=page_size,
limit=limit,
batch_size_attribute='pageSize',
)
def Describe(self, name):
"""Describe a DesignCenter SharedTemplate under a space.
Args:
name: str, the full resource name of the SharedTemplate.
e.g., projects/{p}/locations/{l}/spaces/{s}/sharedTemplates/{st}
Returns:
Described DesignCenter SharedTemplate resource.
"""
describe_req = self.messages.DesigncenterProjectsLocationsSpacesSharedTemplatesGetRequest(
name=name)
return self._st_client.Get(describe_req)

View File

@@ -0,0 +1,93 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""DesignCenter Spaces API."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.design_center import utils as api_lib_utils
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.iam import iam_util
class SpacesClient(object):
"""Client for Spaces in design center API."""
def __init__(self, release_track=base.ReleaseTrack.ALPHA):
self.client = api_lib_utils.GetClientInstance(release_track)
self.messages = api_lib_utils.GetMessagesModule(release_track)
self._spaces_client = self.client.projects_locations_spaces
def GetIamPolicy(self, space_id):
"""Fetch the IAM Policy attached to the sepcified space.
Args:
space_id: str, the space id.
Returns:
The spaces's IAM Policy.
"""
# version = iam_util.MAX_LIBRARY_IAM_SUPPORTED_VERSION
get_req = (
self.messages.DesigncenterProjectsLocationsSpacesGetIamPolicyRequest(
resource=space_id,
)
)
return self._spaces_client.GetIamPolicy(get_req)
def SetIamPolicy(self, space_id, policy_file):
"""Sets an space's IamPolicy to the one provided.
If 'policy_file' has no etag specified, this will BLINDLY OVERWRITE the IAM
policy!
Args:
space_id: str, the space id..
policy_file: a policy file.
Returns:
The IAM Policy.
"""
policy = iam_util.ParsePolicyFile(policy_file, self.messages.Policy)
return self._SetIamPolicyHelper(space_id, policy)
def _SetIamPolicyHelper(self, space_id, policy):
set_req = (
self.messages.DesigncenterProjectsLocationsSpacesSetIamPolicyRequest(
resource=space_id,
setIamPolicyRequest=self.messages.SetIamPolicyRequest(
policy=policy,),
))
return self._spaces_client.SetIamPolicy(set_req)
def TestIamPermissions(self, space_id, permissions):
"""Tests the IAM permissions for the specified space.
Args:
space_id: str, the space id.
permissions: list of str, the permissions to test.
Returns:
The TestIamPermissionsResponse.
"""
test_iam_perm_req = self.messages.TestIamPermissionsRequest(
permissions=permissions)
test_req = (
self.messages.DesigncenterProjectsLocationsSpacesTestIamPermissionsRequest(
resource=space_id,
testIamPermissionsRequest=test_iam_perm_req,
))
return self._spaces_client.TestIamPermissions(test_req)

View File

@@ -0,0 +1,195 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Util for Design Center Cloud SDK."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import encoding as apitools_encoding
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.api_lib.util import waiter
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.core import properties
from googlecloudsdk.core import resources
VERSION_MAP = {
base.ReleaseTrack.ALPHA: 'v1alpha',
base.ReleaseTrack.GA: 'v1',
}
OPERATIONS_COLLECTION = 'designcenter.projects.locations.operations'
# The messages module can also be accessed from client.MESSAGES_MODULE
def GetMessagesModule(release_track=base.ReleaseTrack.ALPHA):
api_version = VERSION_MAP.get(release_track)
return apis.GetMessagesModule('designcenter', api_version)
def GetClientInstance(release_track=base.ReleaseTrack.ALPHA):
api_version = VERSION_MAP.get(release_track)
return apis.GetClientInstance('designcenter', api_version)
def GetLocationRef(args):
"""Returns a location reference."""
location_ref = args.CONCEPTS.location.Parse()
if not location_ref.Name():
raise exceptions.InvalidArgumentException(
'location', 'location id must be non-empty.'
)
return location_ref
def GetProjectRef():
"""Returns a project reference."""
return resources.REGISTRY.Parse(
properties.VALUES.core.project.GetOrFail(),
collection='designcenter.projects',
)
def GetSpaceRef(args):
"""Returns a space reference."""
space_ref = args.CONCEPTS.space.Parse()
if not space_ref.Name():
raise exceptions.InvalidArgumentException(
'space', 'space id must be non-empty.'
)
return space_ref
def MakeGetUriFunc(collection, release_track=base.ReleaseTrack.ALPHA):
"""Returns a function which turns a resource into a uri."""
def _GetUri(resource):
api_version = VERSION_MAP.get(release_track)
result = resources.Registry().ParseRelativeName(
resource.name, collection=collection, api_version=api_version
)
return result.SelfLink()
return _GetUri
class EmbeddedResultOperationPoller(waiter.CloudOperationPoller):
"""Poller for operations with result embedded in operation.response."""
def __init__(self, operation_service):
super(EmbeddedResultOperationPoller, self).__init__(None, operation_service)
def GetRequestType(self, request_name):
"""Overrides."""
return self.operation_service.GetRequestType(request_name)
def GetResult(self, operation):
"""Overrides."""
if operation.response:
return apitools_encoding.MessageToPyValue(operation.response)
return None
def WaitForOperation(
client,
operation,
message: str,
max_wait_sec: int,
release_track=base.ReleaseTrack.ALPHA,
):
"""Waits for the given operation to complete."""
operation_ref = resources.REGISTRY.ParseRelativeName(
operation.name,
collection=OPERATIONS_COLLECTION,
api_version=VERSION_MAP.get(release_track),
)
return waiter.WaitFor(
poller=waiter.CloudOperationPoller(
client.projects_locations_operations,
client.projects_locations_operations,
),
operation_ref=operation_ref,
message=message,
max_wait_ms=max_wait_sec * 1000,
)
def GetGoogleCatalogProjectId() -> str:
"""Returns the project ID for Google Catalog based on API endpoint."""
endpoint_override = (
properties.VALUES.api_endpoint_overrides.designcenter.Get()
)
# universe_domain will always be non empty with default value 'googleapis.com'
universe_domain = properties.VALUES.core.universe_domain.Get()
if (
endpoint_override
and f'autopush-designcenter.sandbox.{universe_domain}'
in endpoint_override
):
return 'gcpdesigncenter-autopush'
if (
endpoint_override
and f'staging-designcenter.sandbox.{universe_domain}'
in endpoint_override
):
return 'gcpdesigncenter-staging'
return 'gcpdesigncenter'
def WaitForOperationWithEmbeddedResult(
client,
operation,
message: str,
max_wait_sec: int,
release_track=base.ReleaseTrack.ALPHA,
):
"""Waits for an operation to complete, where the result is embedded in the operation response."""
operation_ref = resources.REGISTRY.ParseRelativeName(
operation.name,
collection=OPERATIONS_COLLECTION,
api_version=VERSION_MAP.get(release_track),
)
poller = EmbeddedResultOperationPoller(
client.projects_locations_operations
)
return waiter.WaitFor(
poller=poller,
operation_ref=operation_ref,
message=message,
max_wait_ms=max_wait_sec * 1000,
)
def ParseIaCModuleData(client, iac_module_data):
"""Parses dict data into an IaCModule message."""
if not isinstance(iac_module_data, dict) or 'files' not in iac_module_data:
raise ValueError('Invalid IaC module format. Expected a dictionary with a "files" key.')
iac_files = []
for file_data in iac_module_data['files']:
if not isinstance(file_data, dict) or 'name' not in file_data:
raise ValueError('Each file in IaC module must have a "name".')
iac_file = client.messages.IaCFile(
name=file_data['name'],
content=file_data.get('content') or ''
)
iac_files.append(iac_file)
return client.messages.IaCModule(files=iac_files)