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,14 @@
# -*- 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.

View File

@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.

View File

@@ -0,0 +1,78 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""Connect Gateway API client.
This does not provide client methods for GatewayService, which expects raw HTTP
requests as provided by e.g. kubectl.
"""
from typing import Union
from googlecloudsdk.api_lib.container.fleet.connectgateway import util
from googlecloudsdk.calliope import base
class GatewayClient:
"""Client for the Connect Gateway API with related helper methods.
If not provided, the default client is for the GA (v1) track. This client
is a thin wrapper around the base client, and does not handle any exceptions.
Fields:
release_track: The release track of the command [ALPHA, BETA, GA].
client: The raw GKE Hub API client for the specified release track.
messages: The matching messages module for the client.
"""
def __init__(self, release_track: base.ReleaseTrack = util.DEFAULT_TRACK):
self.release_track = (
release_track if release_track is not None else util.DEFAULT_TRACK
)
self.client = util.GetClientInstance(release_track)
self.messages = util.GetMessagesModule(release_track)
def GenerateCredentials(
self,
name: str,
force_use_agent: bool = False,
version: Union[str, None] = None,
kubernetes_namespace: Union[str, None] = None,
operating_system: util.TYPES.OperatingSystem = None,
) -> util.TYPES.GenerateCredentialsResponse:
"""Retrieve connection information for accessing a membership through Connect Gateway.
Args:
name: The full membership name, in the form
`projects/*/locations/*/memberships/*`.
force_use_agent: Whether to force the use of Connect Agent-based
transport.
version: The Connect Gateway version to be used in the resulting
configuration.
kubernetes_namespace: The namespace to use in the kubeconfig context.
operating_system: The operating system for which the kubeconfig should be
generated. The default value of `None` works for supported operating
systems other than Windows.
Returns:
The GenerateCredentialsResponse message.
"""
req = self.messages.ConnectgatewayProjectsLocationsMembershipsGenerateCredentialsRequest(
name=name,
forceUseAgent=force_use_agent,
version=version,
kubernetesNamespace=kubernetes_namespace,
operatingSystem=operating_system,
)
return self.client.projects_locations_memberships.GenerateCredentials(req)

View File

@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""Connect Gateway API utils."""
from typing import Union
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.calliope import base
from googlecloudsdk.generated_clients.apis.connectgateway.v1 import connectgateway_v1_messages as messages_v1
from googlecloudsdk.generated_clients.apis.connectgateway.v1alpha1 import connectgateway_v1alpha1_messages as messages_v1alpha1
from googlecloudsdk.generated_clients.apis.connectgateway.v1beta1 import connectgateway_v1beta1_messages as messages_v1beta1
class TYPES:
# pylint: disable=invalid-name: Follows the naming convention of the generated client.
GenerateCredentialsResponse = Union[
messages_v1alpha1.GenerateCredentialsResponse,
messages_v1beta1.GenerateCredentialsResponse,
messages_v1.GenerateCredentialsResponse,
]
# pylint: disable=invalid-name: Follows the naming convention of the generated client.
OperatingSystem = Union[
messages_v1alpha1.ConnectgatewayProjectsLocationsMembershipsGenerateCredentialsRequest.OperatingSystemValueValuesEnum,
messages_v1beta1.ConnectgatewayProjectsLocationsMembershipsGenerateCredentialsRequest.OperatingSystemValueValuesEnum,
messages_v1.ConnectgatewayProjectsLocationsMembershipsGenerateCredentialsRequest.OperatingSystemValueValuesEnum,
]
API_NAME = 'connectgateway'
DEFAULT_TRACK = base.ReleaseTrack.GA
VERSION_MAP = {
base.ReleaseTrack.ALPHA: 'v1alpha1',
base.ReleaseTrack.BETA: 'v1beta1',
base.ReleaseTrack.GA: 'v1',
}
# The messages module can also be accessed from client.MESSAGES_MODULE
def GetMessagesModule(release_track=DEFAULT_TRACK):
api_version = VERSION_MAP.get(release_track, VERSION_MAP[DEFAULT_TRACK])
return apis.GetMessagesModule(API_NAME, api_version)
def GetClientInstance(release_track=DEFAULT_TRACK):
api_version = VERSION_MAP.get(release_track, VERSION_MAP[DEFAULT_TRACK])
return apis.GetClientInstance(API_NAME, api_version)
def WindowsOperatingSystem(release_track=DEFAULT_TRACK):
"""Returns the Windows enum value for the OperatingSystem enum.
Args:
release_track: The gcloud release track to use.
"""
return GetMessagesModule(
release_track
).ConnectgatewayProjectsLocationsMembershipsGenerateCredentialsRequest.OperatingSystemValueValuesEnum.OPERATING_SYSTEM_WINDOWS

View File

@@ -0,0 +1,147 @@
# -*- 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.
"""Util package for memberships debug API."""
import re
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib import network_services
from googlecloudsdk.api_lib.container import kubeconfig as kconfig
from googlecloudsdk.api_lib.container import util as container_util
from googlecloudsdk.api_lib.container.fleet import util as fleet_util
from googlecloudsdk.command_lib.container.fleet import api_util as hubapi_util
from googlecloudsdk.command_lib.container.fleet.features import base
from googlecloudsdk.core import exceptions
from googlecloudsdk.core import properties
location = None
CONNECT_GATEWAY_KUBECONTEXT_FORMAT = 'connectgateway_{project}_{location}_{membership}'
def ContextGenerator(args):
"""Generate k8s context from membership, location and project."""
membership_resource_name = base.ParseMembership(
args, prompt=True, autoselect=True, search=True
)
membership_id = fleet_util.MembershipShortname(membership_resource_name)
project_id = args.project
global location
location = args.location
if project_id is None:
# read the default projectId from local configuration file
project_id = properties.VALUES.core.project.Get()
if location is None:
location = fleet_util.MembershipLocation(membership_resource_name)
# fetch clusterName from fleet API
try:
membership_resource = hubapi_util.GetMembership(membership_resource_name)
except apitools_exceptions.HttpNotFoundError:
raise exceptions.Error(
'Failed finding membership. Please verify the membership, and location'
' passed is valid. membership={}, location={}, project={}'.format(
membership_id, location, project_id
)
)
if membership_resource is None:
print('Membership resource is none')
return
if not membership_resource.endpoint.gkeCluster:
raise exceptions.Error(
'The cluster to the input membership does not belong to gke.'
' Please verify the membership and location'
' passed is valid. membership={}, location={}, project={}.'.format(
membership_id, location, project_id
)
)
cluster_resourcelink = membership_resource.endpoint.gkeCluster.resourceLink
# override the project_id for cross-project membership use case
matcher = re.match(
r'.*/projects/(.*)/.*/(.*)/clusters/(.*)', cluster_resourcelink
)
if matcher is None:
raise exceptions.Error(
'Failed to parse gke cluster resource link. resourceLink = {}'
.format(cluster_resourcelink)
)
cluster_project_id = matcher.group(1)
cluster_location = matcher.group(2)
cluster_name = matcher.group(3)
print('Found cluster=' + cluster_name)
cluster_context = container_util.ClusterConfig.KubeContext(
cluster_name, cluster_location, cluster_project_id
)
kubeconfig = (
kconfig.Kubeconfig.Default()
) # istioctl uses the default kubeconfig location so it's safe.
if cluster_context not in kubeconfig.contexts:
print('GKE cluster context not found in kubeconfig')
cluster_context = CONNECT_GATEWAY_KUBECONTEXT_FORMAT.format(
project=project_id, location=location, membership=membership_id
)
if cluster_context not in kubeconfig.contexts:
# TODO(b/376311669): add a link to the doc about how to generate kube
# context.
raise exceptions.Error(
'Failed to find kube context of your cluster in your local'
' kubeconfig file. Please make sure the kube context is generated.'
' kube_context={}'.format(cluster_context)
)
print('Using kube context=' + cluster_context)
return cluster_context
def ListMeshes():
client = network_services.GetClientInstance()
return client.projects_locations_meshes.List(
client.MESSAGES_MODULE.NetworkservicesProjectsLocationsMeshesListRequest(
parent='projects/{}/locations/global'.format(
properties.VALUES.core.project.Get()
)
)
)
# Return meshName, projectNumber
def MeshInfoGenerator(args):
"""Generate meshName from membership, location and project."""
target_mesh_name = ''
target_project_number = ''
meshes = ListMeshes()
for mesh_info in meshes.meshes:
if mesh_info.description is None:
continue
matcher = re.match(
r'.*projects/(.*)/locations/(.*)/memberships/(.*): ',
mesh_info.description,
)
if matcher is None:
continue
if matcher.group(2) != location or matcher.group(3) != args.membership:
continue
else:
matcher_new = re.match(r'.+/meshes/(.*)', mesh_info.name)
if matcher_new is None: continue
target_mesh_name = matcher_new.group(1)
target_project_number = matcher.group(1)
break
# it's possible the targetMeshName does not exist.
# Return '' as meshName if meshName not exists.
return target_mesh_name, target_project_number

View File

@@ -0,0 +1,92 @@
# -*- coding: utf-8 -*- #
# Copyright 2022 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.
"""GKEHUB API client utils."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import encoding
from googlecloudsdk.api_lib.util import apis as core_apis
from googlecloudsdk.api_lib.util import waiter
from googlecloudsdk.calliope import base
GKEHUB_API_NAME = 'gkehub'
GKEHUB_ALPHA_API_VERSION = 'v1alpha'
GKEHUB_BETA_API_VERSION = 'v1beta'
GKEHUB_GA_API_VERSION = 'v1'
def GetApiVersionForTrack(release_track=None):
if not release_track:
return core_apis.ResolveVersion(GKEHUB_API_NAME)
elif release_track == base.ReleaseTrack.ALPHA:
return GKEHUB_ALPHA_API_VERSION
elif release_track == base.ReleaseTrack.BETA:
return GKEHUB_BETA_API_VERSION
elif release_track == base.ReleaseTrack.GA:
return GKEHUB_GA_API_VERSION
return core_apis.ResolveVersion(GKEHUB_API_NAME)
def GetApiClientForApiVersion(api_version=None):
if not api_version:
api_version = core_apis.ResolveVersion(GKEHUB_API_NAME)
return core_apis.GetClientInstance(GKEHUB_API_NAME, api_version)
def GetApiClientForTrack(release_track=base.ReleaseTrack.GA):
return GetApiClientForApiVersion(
GetApiVersionForTrack(release_track=release_track)
)
class HubFeatureOperationPoller(waiter.CloudOperationPoller):
"""Poller for GKE Hub Feature API.
This is necessary because the CloudOperationPoller library doesn't support
setting the `returnPartialSuccess` field in the Get request.
"""
def __init__(self, result_service, operation_service):
"""Sets up poller for cloud operations.
Args:
result_service: apitools.base.py.base_api.BaseApiService, api service for
retrieving created result of initiated operation.
operation_service: apitools.base.py.base_api.BaseApiService, api service
for retrieving information about ongoing operation.
Note that result_service and operation_service Get request must have
single attribute called 'name'.
"""
self.result_service = result_service
self.operation_service = operation_service
def GetResult(self, operation):
"""Overrides.
Args:
operation: api_name_messages.Operation.
Returns:
result of result_service.Get request.
"""
request_type = self.result_service.GetRequestType('Get')
response_dict = encoding.MessageToPyValue(operation.response)
return self.result_service.Get(
request_type(name=response_dict['name'], returnPartialSuccess=True),
)

View File

@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.

View File

@@ -0,0 +1,159 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""Utilities for Package Rollouts FleetPackages API."""
from apitools.base.py import list_pager
from googlecloudsdk.api_lib.container.fleet.packages import util
from googlecloudsdk.api_lib.util import waiter
FLEET_PACKAGE_COLLECTION = 'configdelivery.projects.locations.fleetPackages'
def _ParentPath(project, location):
return f'projects/{project}/locations/{location}'
def _FullyQualifiedPath(project, location, name):
return f'projects/{project}/locations/{location}/fleetPackages/{name}'
class FleetPackagesClient(object):
"""Client for FleetPackages in Config Delivery Package Rollouts API."""
def __init__(self, api_version, client=None, messages=None):
self._api_version = api_version or util.DEFAULT_API_VERSION
self.client = client or util.GetClientInstance(self._api_version)
self.messages = messages or util.GetMessagesModule(self.client)
self._service = self.client.projects_locations_fleetPackages
self.fleet_package_waiter = waiter.CloudOperationPollerNoResources(
operation_service=self.client.projects_locations_operations,
get_name_func=lambda x: x.name,
)
def List(self, project, location, limit=None, page_size=100):
"""List FleetPackages from Package Rollouts API.
Args:
project: GCP project id.
location: Valid GCP location (e.g. us-central1).
limit: int or None, the total number of results to return.
page_size: int, the number of entries in each batch (affects requests
made, but not the yielded results).
Returns:
Generator of matching devices.
"""
list_request = (
self.messages.ConfigdeliveryProjectsLocationsFleetPackagesListRequest(
parent=_ParentPath(project, location)
)
)
return list_pager.YieldFromList(
self._service,
list_request,
field='fleetPackages',
batch_size=page_size,
limit=limit,
batch_size_attribute='pageSize',
)
def Create(self, fleet_package, fleet_package_id, parent):
"""Create FleetPackage for Package Rollouts API.
Args:
fleet_package: A parsed FleetPackage resource
fleet_package_id: Name of FleetPackage
parent: Parent GCP location
Returns:
Created FleetPackage resource.
"""
create_request = (
self.messages.ConfigdeliveryProjectsLocationsFleetPackagesCreateRequest(
fleetPackage=fleet_package,
fleetPackageId=fleet_package_id,
parent=parent,
)
)
return waiter.WaitFor(
self.fleet_package_waiter,
self._service.Create(create_request),
f'Creating FleetPackage {fleet_package_id}',
)
def Delete(self, project, location, name, force=False):
"""Delete a FleetPackage resource.
Args:
project: GCP project id.
location: Valid GCP location (e.g., us-central1).
name: Name of the FleetPackage.
force: Whether to delete release of FleetPackage's ResourceBundle.
Returns:
Empty Response Message.
"""
fully_qualified_path = _FullyQualifiedPath(project, location, name)
delete_req = (
self.messages.ConfigdeliveryProjectsLocationsFleetPackagesDeleteRequest(
name=fully_qualified_path, force=force
)
)
return waiter.WaitFor(
self.fleet_package_waiter,
self._service.Delete(delete_req),
f'Deleting FleetPackage {fully_qualified_path}',
)
def Describe(self, project, location, name):
"""Describe a FleetPackage resource.
Args:
project: GCP project id.
location: Valid GCP location (e.g., us-central1).
name: Name of the FleetPackage.
Returns:
Empty Response Message.
"""
fully_qualified_path = _FullyQualifiedPath(project, location, name)
describe_req = (
self.messages.ConfigdeliveryProjectsLocationsFleetPackagesGetRequest(
name=fully_qualified_path
)
)
return self._service.Get(describe_req)
def Update(self, fleet_package, name, update_mask=None):
"""Create FleetPackage for Package Rollouts API.
Args:
fleet_package: A parsed FleetPackage resource
name: Fully qualified name of the FleetPackage.
update_mask: Field mask for the update.
Returns:
Updated FleetPackage resource.
"""
update_request = (
self.messages.ConfigdeliveryProjectsLocationsFleetPackagesPatchRequest(
fleetPackage=fleet_package, name=name, updateMask=update_mask
)
)
return waiter.WaitFor(
self.fleet_package_waiter,
self._service.Patch(update_request),
f'Updating FleetPackage {name}',
)

View File

@@ -0,0 +1,275 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""Utilities for Package Rollouts Releases API."""
from apitools.base.py import exceptions as apitools_exceptions
from apitools.base.py import list_pager
from googlecloudsdk.api_lib.container.fleet.packages import util
from googlecloudsdk.api_lib.container.fleet.packages import variants as variants_apis
from googlecloudsdk.api_lib.util import waiter
_LIST_REQUEST_BATCH_SIZE_ATTRIBUTE = 'pageSize'
_VARIANT_STORAGE_STRATEGY_LABEL_KEY = 'configdelivery-variant-storage-strategy'
_VARIANT_STORAGE_STRATEGY_LABEL_VALUE_NESTED = 'nested'
_SKIP_CREATING_VARIANT_RESOURCES_LABEL_KEY = 'configdelivery-skip-creating-variant-resources'
_SKIP_CREATING_VARIANT_RESOURCES_LABEL_VALUE = 'true'
RELEASE_COLLECTION = 'configdelivery.projects.locations.resourceBundles.releases'
def _ParentPath(project, location, parent_bundle):
return (
f'projects/{project}/locations/{location}/resourceBundles/{parent_bundle}'
)
def _FullyQualifiedPath(project, location, resource_bundle, release):
name = release.replace('.', '-')
return f'projects/{project}/locations/{location}/resourceBundles/{resource_bundle}/releases/{name}'
class ReleasesClient(object):
"""Client for Releases in Config Delivery Package Rollouts API."""
def __init__(self, api_version, client=None, messages=None):
self._api_version = api_version or util.DEFAULT_API_VERSION
self.client = client or util.GetClientInstance(self._api_version)
self.messages = messages or util.GetMessagesModule(self.client)
self._service = self.client.projects_locations_resourceBundles_releases
self.release_waiter = waiter.CloudOperationPollerNoResources(
operation_service=self.client.projects_locations_operations,
get_name_func=lambda x: x.name,
)
def GetLifecycleEnum(self, lifecycle_str):
"""Converts input-format lifecycle to internal enum."""
if lifecycle_str and lifecycle_str.upper() == 'DRAFT':
return self.messages.Release.LifecycleValueValuesEnum.DRAFT
else:
return self.messages.Release.LifecycleValueValuesEnum.PUBLISHED
def List(self, project, location, parent_bundle, limit=None, page_size=100):
"""List Releases of a ResourceBundle.
Args:
project: GCP project id.
location: Valid GCP location (e.g. us-central1).
parent_bundle: Name of parent ResourceBundle.
limit: int or None, the total number of results to return.
page_size: int, the number of entries in each batch (affects requests
made, but not the yielded results).
Returns:
Generator of matching devices.
"""
list_request = self.messages.ConfigdeliveryProjectsLocationsResourceBundlesReleasesListRequest(
parent=_ParentPath(project, location, parent_bundle)
)
return list_pager.YieldFromList(
self._service,
list_request,
field='releases',
batch_size=page_size,
limit=limit,
batch_size_attribute=_LIST_REQUEST_BATCH_SIZE_ATTRIBUTE,
)
def Create(
self,
resource_bundle,
version,
project,
location,
lifecycle=None,
variants=None,
skip_creating_variant_resources=False,
):
"""Create Release for a ResourceBundle.
Args:
resource_bundle: Name of parent ResourceBundle.
version: Version of the Release.
project: GCP Project ID.
location: Valid GCP location (e.g., uc-central1)
lifecycle: Lifecycle of the Release.
variants: Variants of the Release.
skip_creating_variant_resources: Whether to use the crane upload strategy
to upload variant images.
Returns:
Created Release resource.
"""
fully_qualified_path = _FullyQualifiedPath(
project, location, resource_bundle, version
)
# Create Draft Release, create nested Variant resources, then updates
# release to have those variants. Publishes release at update step, if
# necessary.
if not variants and lifecycle is None:
raise ValueError(
'No variants found in source directory. Please check the source'
' directory and variants pattern, or create the release with'
' --lifecycle=DRAFT.'
)
labels = self.messages.Release.LabelsValue(
additionalProperties=[
self.messages.Release.LabelsValue.AdditionalProperty(
key=_VARIANT_STORAGE_STRATEGY_LABEL_KEY,
value=_VARIANT_STORAGE_STRATEGY_LABEL_VALUE_NESTED,
)
]
)
if skip_creating_variant_resources:
labels.additionalProperties.append(
self.messages.Release.LabelsValue.AdditionalProperty(
key=_SKIP_CREATING_VARIANT_RESOURCES_LABEL_KEY,
value=_SKIP_CREATING_VARIANT_RESOURCES_LABEL_VALUE,
)
)
release = self.messages.Release(
name=fully_qualified_path,
labels=labels,
lifecycle=self.GetLifecycleEnum('DRAFT'),
version=version,
)
create_request = self.messages.ConfigdeliveryProjectsLocationsResourceBundlesReleasesCreateRequest(
parent=_ParentPath(project, location, resource_bundle),
release=release,
releaseId=version.replace('.', '-'),
)
_ = waiter.WaitFor(
self.release_waiter,
self._service.Create(create_request),
f'Creating Release {fully_qualified_path}',
)
for variant, variant_resources in variants.items():
variants_client = variants_apis.VariantsClient(self._api_version)
try:
variants_client.Create(
resource_bundle=resource_bundle,
release=version.replace('.', '-'),
name=variant,
project=project,
location=location,
variant_resources=variant_resources,
)
except apitools_exceptions.HttpConflictError as e:
# If the variant already exists, we can safely skip.
if 'already_exists' in str(e).lower():
pass
else:
# Re-raise the exception if conflict is not due to "already exists".
raise
return self.Update(
release=version,
project=project,
location=location,
resource_bundle=resource_bundle,
labels=labels,
lifecycle=lifecycle,
)
def Delete(self, project, location, resource_bundle, release, force=False):
"""Delete a Release resource.
Args:
project: GCP project ID.
location: GCP location of Release.
resource_bundle: Name of ResourceBundle.
release: Name of Release.
force: Whether to force deletion of any child variants.
Returns:
Empty Response Message.
"""
fully_qualified_path = _FullyQualifiedPath(
project,
location,
resource_bundle,
release,
)
delete_req = self.messages.ConfigdeliveryProjectsLocationsResourceBundlesReleasesDeleteRequest(
name=fully_qualified_path,
force=force,
)
return waiter.WaitFor(
self.release_waiter,
self._service.Delete(delete_req),
f'Deleting Release {fully_qualified_path}',
)
def Describe(self, project, location, resource_bundle, release):
"""Describe a Release resource.
Args:
project: GCP project ID.
location: GCP location of Release.
resource_bundle: Name of ResourceBundle.
release: Name of Release.
Returns:
Requested Release resource.
"""
fully_qualified_path = _FullyQualifiedPath(
project, location, resource_bundle, release
)
describe_req = self.messages.ConfigdeliveryProjectsLocationsResourceBundlesReleasesGetRequest(
name=fully_qualified_path
)
return self._service.Get(describe_req)
def Update(
self,
release,
project,
location,
resource_bundle,
labels=None,
lifecycle=None,
update_mask=None,
):
"""Update Release for a ResourceBundle.
Args:
release: Name of Release (e.g., v1).
project: GCP project ID.
location: GCP location of Release.
resource_bundle: Name of parent ResourceBundle.
labels: Labels of the Release.
lifecycle: Lifecycle of the Release.
update_mask: Fields to be updated.
Returns:
Updated Release resource.
"""
fully_qualified_path = _FullyQualifiedPath(
project, location, resource_bundle, release
)
release = self.messages.Release(
name=fully_qualified_path,
labels=labels,
lifecycle=self.GetLifecycleEnum(lifecycle),
version=release,
)
update_request = self.messages.ConfigdeliveryProjectsLocationsResourceBundlesReleasesPatchRequest(
name=fully_qualified_path, release=release, updateMask=update_mask
)
return waiter.WaitFor(
self.release_waiter,
self._service.Patch(update_request),
f'Updating Release {fully_qualified_path}',
)

View File

@@ -0,0 +1,178 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""Utilities for Package Rollouts ResourceBundle API."""
from apitools.base.py import list_pager
from googlecloudsdk.api_lib.container.fleet.packages import util
from googlecloudsdk.api_lib.util import waiter
_LIST_REQUEST_BATCH_SIZE_ATTRIBUTE = 'pageSize'
RESOURCE_BUNDLE_COLLECTION = 'configdelivery.projects.locations.resourceBundles'
def _ParentPath(project, location):
return f'projects/{project}/locations/{location}'
def _FullyQualifiedPath(project, location, name):
return f'projects/{project}/locations/{location}/resourceBundles/{name}'
class ResourceBundlesClient(object):
"""Client for ResourceBundles in Config Delivery Package Rollouts API."""
def __init__(self, api_version, client=None, messages=None):
self._api_version = api_version or util.DEFAULT_API_VERSION
self.client = client or util.GetClientInstance(self._api_version)
self.messages = messages or util.GetMessagesModule(self.client)
self._service = self.client.projects_locations_resourceBundles
self.resource_bundle_waiter = waiter.CloudOperationPollerNoResources(
operation_service=self.client.projects_locations_operations,
get_name_func=lambda x: x.name,
)
def List(self, project, location, limit=None, page_size=100):
"""List ResourceBundles from Package Rollouts API.
Args:
project: GCP project id.
location: Valid GCP location (e.g. us-central1).
limit: int or None, the total number of results to return.
page_size: int, the number of entries in each batch (affects requests
made, but not the yielded results).
Returns:
Generator of matching devices.
"""
list_request = (
self.messages.ConfigdeliveryProjectsLocationsResourceBundlesListRequest(
parent=_ParentPath(project, location),
)
)
return list_pager.YieldFromList(
self._service,
list_request,
field='resourceBundles',
batch_size=page_size,
limit=limit,
batch_size_attribute=_LIST_REQUEST_BATCH_SIZE_ATTRIBUTE,
)
def Create(self, project, location, name, description=None):
"""Create ResourceBundle for Package Rollouts API.
Args:
project: GCP project id.
location: Valid GCP location (e.g. us-central1).
name: Name of the ResourceBundle.
description: Description of the ResourceBundle.
Returns:
Created ResourceBundle resource.
"""
fully_qualified_path = _FullyQualifiedPath(project, location, name)
resource_bundle = self.messages.ResourceBundle(
name=fully_qualified_path, description=description, labels=None
)
create_request = self.messages.ConfigdeliveryProjectsLocationsResourceBundlesCreateRequest(
resourceBundle=resource_bundle,
parent=_ParentPath(project, location),
resourceBundleId=name,
)
result = waiter.WaitFor(
self.resource_bundle_waiter,
self._service.Create(create_request),
f'Creating ResourceBundle {name}',
)
return result
def Delete(self, project, location, name, force=False):
"""Delete a ResourceBundle resource.
Args:
project: GCP project id.
location: Valid GCP location (e.g., us-central1).
name: Name of the ResourceBundle.
force: Nested resource deletion flag.
Returns:
Empty Response Message.
"""
fully_qualified_path = _FullyQualifiedPath(project, location, name)
delete_req = self.messages.ConfigdeliveryProjectsLocationsResourceBundlesDeleteRequest(
name=fully_qualified_path, force=force
)
return waiter.WaitFor(
self.resource_bundle_waiter,
self._service.Delete(delete_req),
f'Deleting ResourceBundle {name}',
)
def Describe(self, project, location, name):
"""Describe a ResourceBundle resource.
Args:
project: GCP project id.
location: Valid GCP location (e.g., us-central1).
name: Name of the ResourceBundle.
Returns:
Requested ResourceBundle resource.
"""
fully_qualified_path = _FullyQualifiedPath(project, location, name)
describe_req = (
self.messages.ConfigdeliveryProjectsLocationsResourceBundlesGetRequest(
name=fully_qualified_path
)
)
return self._service.Get(describe_req)
def Update(
self,
project,
location,
name,
description=None,
labels=None,
update_mask=None,
):
"""Update ResourceBundle for Package Rollouts API.
Args:
project: GCP project id.
location: Valid GCP location (e.g. us-central1).
name: Name of the ResourceBundle.
description: Description of the ResourceBundle.
labels: Kubernetes labels to apply to your ResourceBundle.
update_mask: Fields to be updated.
Returns:
Updated ResourceBundle resource.
"""
fully_qualified_path = _FullyQualifiedPath(project, location, name)
resource_bundle = self.messages.ResourceBundle(
name=fully_qualified_path, description=description, labels=labels
)
update_request = self.messages.ConfigdeliveryProjectsLocationsResourceBundlesPatchRequest(
resourceBundle=resource_bundle,
name=fully_qualified_path,
updateMask=update_mask,
)
return waiter.WaitFor(
self.resource_bundle_waiter,
self._service.Patch(update_request),
f'Updating ResourceBundle {name}',
)

View File

@@ -0,0 +1,163 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""Utilities for Package Rollouts Rollouts API."""
from apitools.base.py import list_pager
from googlecloudsdk.api_lib.container.fleet.packages import util
from googlecloudsdk.api_lib.util import waiter
ROLLOUT_COLLECTION = 'configdelivery.projects.locations.fleetPackages.rollouts'
class RolloutsClient(object):
"""Client for Rollouts in Config Delivery Package Rollouts API."""
def __init__(self, api_version, client=None, messages=None):
self._api_version = api_version or util.DEFAULT_API_VERSION
self.client = client or util.GetClientInstance(self._api_version)
self.messages = messages or util.GetMessagesModule(self.client)
self._service = self.client.projects_locations_fleetPackages_rollouts
self.rollout_waiter = waiter.CloudOperationPollerNoResources(
operation_service=self.client.projects_locations_operations,
get_name_func=lambda x: x.name,
)
def List(self, project, location, fleet_package, limit=None, page_size=100):
"""List Rollouts of a Fleet Package.
Args:
project: GCP project id.
location: Valid GCP location (e.g. us-central1).
fleet_package: Name of parent Fleet Package.
limit: int or None, the total number of results to return.
page_size: int, the number of entries in each batch (affects requests
made, but not the yielded results).
Returns:
Generator of matching devices.
"""
list_request = self.messages.ConfigdeliveryProjectsLocationsFleetPackagesRolloutsListRequest(
parent=f'projects/{project}/locations/{location}/fleetPackages/{fleet_package}',
orderBy='create_time desc',
)
return list_pager.YieldFromList(
self._service,
list_request,
field='rollouts',
batch_size=page_size,
limit=limit,
batch_size_attribute='pageSize',
)
def Describe(self, project, location, fleet_package, rollout):
"""Describe a Rollout resource.
Args:
project: GCP project ID.
location: GCP location of Fleet Package.
fleet_package: Name of parent Fleet Package.
rollout: Name of Rollout.
Returns:
Requested Rollout resource.
"""
fully_qualified_path = f'projects/{project}/locations/{location}/fleetPackages/{fleet_package}/rollouts/{rollout}'
describe_req = self.messages.ConfigdeliveryProjectsLocationsFleetPackagesRolloutsGetRequest(
name=fully_qualified_path
)
return self._service.Get(describe_req)
def Abort(self, project, location, fleet_package, rollout, reason=None):
"""Abort an in-progress Rollout.
Args:
project: GCP project ID.
location: GCP location of Fleet Package.
fleet_package: Name of parent Fleet Package.
rollout: Name of Rollout.
reason: Reason for aborting the Rollout.
Returns:
None.
Raises:
apitools.base.py.HttpError: If the request returns an HTTP error.
"""
fully_qualified_path = f'projects/{project}/locations/{location}/fleetPackages/{fleet_package}/rollouts/{rollout}'
abort_req = self.messages.ConfigdeliveryProjectsLocationsFleetPackagesRolloutsAbortRequest(
name=fully_qualified_path,
abortRolloutRequest=self.messages.AbortRolloutRequest(reason=reason),
)
waiter.WaitFor(
self.rollout_waiter,
self._service.Abort(abort_req),
f'Aborting Rollout {rollout}',
)
def Resume(self, project, location, fleet_package, rollout, reason=None):
"""Resume a suspended Rollout.
Args:
project: GCP project ID.
location: GCP location of Fleet Package.
fleet_package: Name of parent Fleet Package.
rollout: Name of Rollout.
reason: Reason for resuming the Rollout.
Returns:
None.
Raises:
apitools.base.py.HttpError: If the request returns an HTTP error.
"""
fully_qualified_path = f'projects/{project}/locations/{location}/fleetPackages/{fleet_package}/rollouts/{rollout}'
resume_req = self.messages.ConfigdeliveryProjectsLocationsFleetPackagesRolloutsResumeRequest(
name=fully_qualified_path,
resumeRolloutRequest=self.messages.ResumeRolloutRequest(reason=reason),
)
waiter.WaitFor(
self.rollout_waiter,
self._service.Resume(resume_req),
f'Resuming Rollout {rollout}',
)
def Suspend(self, project, location, fleet_package, rollout, reason=None):
"""Suspend an in-progress Rollout.
Args:
project: GCP project ID.
location: GCP location of Fleet Package.
fleet_package: Name of parent Fleet Package.
rollout: Name of Rollout.
reason: Reason for suspending the Rollout.
Returns:
None.
Raises:
apitools.base.py.HttpError: If the request returns an HTTP error.
"""
fully_qualified_path = f'projects/{project}/locations/{location}/fleetPackages/{fleet_package}/rollouts/{rollout}'
suspend_req = self.messages.ConfigdeliveryProjectsLocationsFleetPackagesRolloutsSuspendRequest(
name=fully_qualified_path,
suspendRolloutRequest=self.messages.SuspendRolloutRequest(
reason=reason
),
)
waiter.WaitFor(
self.rollout_waiter,
self._service.Suspend(suspend_req),
f'Suspending Rollout {rollout}',
)

View File

@@ -0,0 +1,29 @@
# -*- 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.
"""ConfigDelivery API utils."""
from googlecloudsdk.api_lib.util import apis
API_NAME = 'configdelivery'
DEFAULT_API_VERSION = 'v1alpha'
def GetClientInstance(api_version=DEFAULT_API_VERSION):
return apis.GetClientInstance('configdelivery', api_version)
def GetMessagesModule(client):
return client.MESSAGES_MODULE

View File

@@ -0,0 +1,94 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""Utilities for Package Rollouts Variants API."""
from googlecloudsdk.api_lib.container.fleet.packages import util
from googlecloudsdk.api_lib.util import waiter
_LIST_REQUEST_BATCH_SIZE_ATTRIBUTE = 'pageSize'
VARIANT_COLLECTION = 'configdelivery.projects.locations.resourceBundles.releases.variants'
def _ParentPath(project, location, parent_bundle, parent_release):
return f'projects/{project}/locations/{location}/resourceBundles/{parent_bundle}/releases/{parent_release}'
def _FullyQualifiedPath(project, location, resource_bundle, release, variant):
name = release.replace('.', '-')
return f'projects/{project}/locations/{location}/resourceBundles/{resource_bundle}/releases/{name}/variants/{variant}'
def GetFullyQualifiedPath(project, location, resource_bundle, release, variant):
return _FullyQualifiedPath(
project, location, resource_bundle, release, variant
)
class VariantsClient(object):
"""Client for Variants in Config Delivery Package Rollouts API."""
def __init__(self, api_version, client=None, messages=None):
self._api_version = api_version or util.DEFAULT_API_VERSION
self.client = client or util.GetClientInstance(self._api_version)
self.messages = messages or util.GetMessagesModule(self.client)
self._service = (
self.client.projects_locations_resourceBundles_releases_variants
)
self.variant_waiter = waiter.CloudOperationPollerNoResources(
operation_service=self.client.projects_locations_operations,
get_name_func=lambda x: x.name,
)
def Create(
self,
resource_bundle,
release,
name,
project,
location,
variant_resources=None,
):
"""Create Variant for a Release.
Args:
resource_bundle: Name of parent ResourceBundle.
release: Name of parent Release.
name: Name of the Variant.
project: GCP Project ID.
location: Valid GCP location (e.g., uc-central1)
variant_resources: Resources of the Variant.
Returns:
Created Variant resource.
"""
fully_qualified_path = _FullyQualifiedPath(
project, location, resource_bundle, release, name
)
variant = self.messages.Variant(
name=fully_qualified_path,
labels=None,
resources=variant_resources,
)
create_request = self.messages.ConfigdeliveryProjectsLocationsResourceBundlesReleasesVariantsCreateRequest(
parent=_ParentPath(project, location, resource_bundle, release),
variant=variant,
variantId=name,
)
return waiter.WaitFor(
self.variant_waiter,
self._service.Create(create_request),
f'Creating Variant {fully_qualified_path}',
)

View File

@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*- #
# Copyright 2022 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.

View File

@@ -0,0 +1,38 @@
# -*- 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.
"""GKE Hub Policy Controller library to manipulate API proto messages."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from typing import Any, Dict
def additional_properties_to_dict(spec):
"""Extracts the additional properties of a message.Message as a dictionary."""
if spec is None:
return {}
return {prop.key: prop.value for prop in spec.additionalProperties}
def set_additional_properties(message, additional_properties: Dict[Any, Any]):
"""Sets additional properties on a message."""
ls = [
message.AdditionalProperty(key=key, value=value)
for key, value in additional_properties.items()
]
message.additionalProperties = ls
return message

View File

@@ -0,0 +1,191 @@
# -*- coding: utf-8 -*- #
# Copyright 2022 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.
"""Anthos Policy Controller status API utilities."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.container.fleet import api_util as fleet_api_util
from googlecloudsdk.command_lib.container.fleet.policycontroller import constants
from googlecloudsdk.core import exceptions
import six
def _GetApiVersionFromReleaseTrack(release_track):
if release_track == base.ReleaseTrack.ALPHA:
return 'v1alpha'
raise ValueError('Invalid release track: ' + release_track)
def GetMessagesModule(release_track):
"""Returns the Policy Controller status API messages module."""
return apis.GetMessagesModule(
'anthospolicycontrollerstatus_pa',
_GetApiVersionFromReleaseTrack(release_track))
def GetClientInstance(release_track):
"""Returns the Policy Controller status API client instance."""
return apis.GetClientInstance(
'anthospolicycontrollerstatus_pa',
_GetApiVersionFromReleaseTrack(release_track))
def GetMembershipConstraint(client, messages, constraint_name, project_id,
membership, release_track):
"""Returns a formatted membership constraint."""
try:
membership_obj = fleet_api_util.GetMembership(membership,
release_track)
except apitools_exceptions.HttpNotFoundError:
raise exceptions.Error(
'Membership [{}] was not found in the Fleet.'
.format(membership))
try:
request = messages.AnthospolicycontrollerstatusPaProjectsMembershipConstraintsGetRequest(
name='projects/{}/membershipConstraints/{}/{}'.format(
project_id, constraint_name, membership_obj.uniqueId))
response = client.projects_membershipConstraints.Get(request)
except apitools_exceptions.HttpNotFoundError:
raise exceptions.Error(
'Constraint [{}] was not found in Fleet membership [{}].'
.format(constraint_name, membership))
return {
'name':
response.constraintRef.name,
'template':
response.constraintRef.constraintTemplateName,
'enforcementAction':
constants.get_enforcement_action_label(
six.text_type(response.spec.enforcementAction)),
'membership': membership,
'violationCount':
response.status.numViolations or 0,
'violations': [],
'match':
response.spec.kubernetesMatch or {},
'parameters':
response.spec.parameters or {}
}
def GetFleetConstraint(client, messages, constraint_name, project_id):
"""Returns a formatted Fleet constraint."""
try:
request = messages.AnthospolicycontrollerstatusPaProjectsFleetConstraintsGetRequest(
name='projects/{}/fleetConstraints/{}'.format(
project_id, constraint_name))
response = client.projects_fleetConstraints.Get(request)
except apitools_exceptions.HttpNotFoundError:
raise exceptions.Error(
'Constraint [{}] was not found in the fleet.'
.format(constraint_name))
constraint = {
'name': response.ref.name,
'template': response.ref.constraintTemplateName,
'violations': [],
'violationCount': response.numViolations or 0,
'memberships': [],
'membershipCount': response.numMemberships or 0
}
membership_constraints_request = messages.AnthospolicycontrollerstatusPaProjectsMembershipConstraintsListRequest(
parent='projects/{}'.format(project_id))
membership_constraints_response = client.projects_membershipConstraints.List(
membership_constraints_request)
for membership_constraint in membership_constraints_response.membershipConstraints:
if constraint_name == '{}/{}'.format(
membership_constraint.constraintRef.constraintTemplateName,
membership_constraint.constraintRef.name):
constraint['memberships'].append(
membership_constraint.membershipRef.name)
return constraint
def ListFleetConstraints(client, msg, project_id):
client_fn = client.projects_fleetConstraints
req = msg.AnthospolicycontrollerstatusPaProjectsFleetConstraintsListRequest()
return _Autopage(client_fn, req, project_id,
lambda response: response.fleetConstraints)
def ListMembershipConstraints(client, msg, project_id):
client_fn = client.projects_membershipConstraints
req = msg.AnthospolicycontrollerstatusPaProjectsMembershipConstraintsListRequest() # pylint: disable=line-too-long
return _Autopage(client_fn, req, project_id,
lambda response: response.membershipConstraints)
def ListFleetConstraintTemplates(client, msg, project_id):
client_fn = client.projects_fleetConstraintTemplates
req = msg.AnthospolicycontrollerstatusPaProjectsFleetConstraintTemplatesListRequest() # pylint: disable=line-too-long
return _Autopage(client_fn, req, project_id,
lambda response: response.fleetConstraintTemplates)
def ListMembershipConstraintTemplates(client, msg, project_id):
client_fn = client.projects_membershipConstraintTemplates
req = msg.AnthospolicycontrollerstatusPaProjectsMembershipConstraintTemplatesListRequest() # pylint: disable=line-too-long
return _Autopage(client_fn, req, project_id,
lambda response: response.membershipConstraintTemplates)
def ListViolations(client, msg, project_id):
client_fn = client.projects_membershipConstraintAuditViolations
req = msg.AnthospolicycontrollerstatusPaProjectsMembershipConstraintAuditViolationsListRequest() # pylint: disable=line-too-long
return _Autopage(
client_fn, req, project_id,
lambda response: response.membershipConstraintAuditViolations)
def ListMemberships(client, msg, project_id):
client_fn = client.projects_memberships
req = msg.AnthospolicycontrollerstatusPaProjectsMembershipsListRequest()
return _Autopage(client_fn, req, project_id,
lambda response: response.memberships)
def _Autopage(client_fn, request, project_id, resource_collector):
"""Auto-page through the responses if the next page token is not empty and returns a list of all resources.
Args:
client_fn: Function specific to the endpoint
request: Request object specific to the endpoint
project_id: Project id that will be used in populating the request object
resource_collector: Function to be used for retrieving the relevant field
from the response
Returns:
List of all resources specific to the endpoint
"""
resources = []
next_page_token = ''
while True:
request.parent = 'projects/' + project_id
request.pageToken = next_page_token
response = client_fn.List(request)
resources += resource_collector(response)
if not response.nextPageToken:
break
next_page_token = response.nextPageToken
return resources

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.
"""Fleet resource transforms.
A resource transform function converts a JSON-serializable resource to a string
value. This module contains built-in transform functions that may be used in
resource projection and filter expressions.
NOTICE: Unlike transforms of top-level command groups like 'container', the
transform functions in this module are not publicly documented under
'gcloud topic projections'.
"""
def construct_origin_transform(client, fleet_default_exists):
"""Returns projection for MembershipFeatureSpec's origin.type value.
Args:
client: Fleet API client.
fleet_default_exists (bool): Whether the fleetDefaultMemberConfig exists on
the Feature in question.
Returns:
A projection transform function that accepts the origin.type value and
returns a string representation of whether the Membership's spec is synced
to the Feature's Fleet-default Membership configuration.
"""
def transform_feature_membership_spec_origin(r):
"""Returns formatted origin.
Args:
r: The JSON-serializable origin.type value string.
"""
if not fleet_default_exists:
return 'FLEET_DEFAULT_NOT_CONFIGURED'
if not r:
return 'UNKNOWN'
if r == str(client.messages.Origin.TypeValueValuesEnum.FLEET):
return 'YES'
if (r == str(client.messages.Origin.TypeValueValuesEnum.USER) or
r == str(client.messages.Origin.TypeValueValuesEnum.FLEET_OUT_OF_SYNC)):
return 'NO'
# Showing unknown underlying value fails fast.
return r
return transform_feature_membership_spec_origin
def get_transforms(client, fleet_default_exists):
"""Returns the Fleet-specific resource transform symbol table.
Format strings, either set by the user or the default set in the command, may
call the transform functions in the table by the associated table keys. Format
strings call the functions on resource fields returned by commands to change
the displayed value of that field.
Args:
client: Fleet API client.
fleet_default_exists (bool): Whether the fleetDefaultMemberConfig exists on
the Feature in question.
Returns:
A dictionary of transform names to functions.
"""
return {
'synced_to_fleet_default':
construct_origin_transform(client, fleet_default_exists),
}

View File

@@ -0,0 +1,223 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 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.
"""Fleet API type helpers.
Because the Fleet API is split into multiple API tracks, this file provides
helpers to make it easier to work with the different tracks. TypeAlias is not
used because it is only supported in Python 3.10+. These type aliases are
intended to be used in type hints when the specific track is not known.
"""
from typing import Generator, Union
from googlecloudsdk.generated_clients.apis.gkehub.v1 import gkehub_v1_client as ga_client
from googlecloudsdk.generated_clients.apis.gkehub.v1 import gkehub_v1_messages as ga_messages
from googlecloudsdk.generated_clients.apis.gkehub.v1alpha import gkehub_v1alpha_client as alpha_client
from googlecloudsdk.generated_clients.apis.gkehub.v1alpha import gkehub_v1alpha_messages as alpha_messages
from googlecloudsdk.generated_clients.apis.gkehub.v1beta import gkehub_v1beta_client as beta_client
from googlecloudsdk.generated_clients.apis.gkehub.v1beta import gkehub_v1beta_messages as beta_messages
from googlecloudsdk.generated_clients.apis.gkehub.v2 import gkehub_v2_client as v2_ga_client
from googlecloudsdk.generated_clients.apis.gkehub.v2alpha import gkehub_v2alpha_client as v2_alpha_client
from googlecloudsdk.generated_clients.apis.gkehub.v2beta import gkehub_v2beta_client as v2_beta_client
BinaryAuthorizationConfig = Union[
alpha_messages.BinaryAuthorizationConfig,
beta_messages.BinaryAuthorizationConfig,
ga_messages.BinaryAuthorizationConfig,
]
BinaryAuthorizationConfigEvaluationModeValueValuesEnum = Union[
alpha_messages.BinaryAuthorizationConfig.EvaluationModeValueValuesEnum,
beta_messages.BinaryAuthorizationConfig.EvaluationModeValueValuesEnum,
ga_messages.BinaryAuthorizationConfig.EvaluationModeValueValuesEnum,
]
CompliancePostureConfig = Union[
alpha_messages.CompliancePostureConfig,
beta_messages.CompliancePostureConfig,
ga_messages.CompliancePostureConfig,
]
DefaultClusterConfig = Union[
alpha_messages.DefaultClusterConfig,
beta_messages.DefaultClusterConfig,
ga_messages.DefaultClusterConfig,
]
Fleet = Union[alpha_messages.Fleet, beta_messages.Fleet, ga_messages.Fleet]
GkehubProjectsLocationsFleetsCreateRequest = Union[
alpha_messages.GkehubProjectsLocationsFleetsCreateRequest,
beta_messages.GkehubProjectsLocationsFleetsCreateRequest,
ga_messages.GkehubProjectsLocationsFleetsCreateRequest,
]
GkehubProjectsLocationsFleetsDeleteRequest = Union[
alpha_messages.GkehubProjectsLocationsFleetsDeleteRequest,
beta_messages.GkehubProjectsLocationsFleetsDeleteRequest,
ga_messages.GkehubProjectsLocationsFleetsDeleteRequest,
]
GkehubProjectsLocationsFleetsPatchRequest = Union[
alpha_messages.GkehubProjectsLocationsFleetsPatchRequest,
beta_messages.GkehubProjectsLocationsFleetsPatchRequest,
ga_messages.GkehubProjectsLocationsFleetsPatchRequest,
]
GkehubProjectsLocationsOperationsListRequest = Union[
alpha_messages.GkehubProjectsLocationsOperationsListRequest,
beta_messages.GkehubProjectsLocationsOperationsListRequest,
ga_messages.GkehubProjectsLocationsOperationsListRequest,
]
GkehubProjectsLocationsOperationsGetRequest = Union[
alpha_messages.GkehubProjectsLocationsOperationsGetRequest,
beta_messages.GkehubProjectsLocationsOperationsGetRequest,
ga_messages.GkehubProjectsLocationsOperationsGetRequest,
]
GkehubProjectsLocationsRolloutsCreateRequest = Union[
alpha_messages.GkehubProjectsLocationsRolloutsCreateRequest,
# Rollouts are not yet available in beta or GA.
# beta_messages.GkehubProjectsLocationsRolloutsCreateRequest,
# ga_messages.GkehubProjectsLocationsRolloutsCreateRequest,
]
GkehubProjectsLocationsRolloutsDeleteRequest = Union[
alpha_messages.GkehubProjectsLocationsRolloutsDeleteRequest,
# Rollouts are not yet available in beta or GA.
# beta_messages.GkehubProjectsLocationsRolloutsDeleteRequest,
# ga_messages.GkehubProjectsLocationsRolloutsDeleteRequest,
]
GkehubProjectsLocationsRolloutsGetRequest = Union[
alpha_messages.GkehubProjectsLocationsRolloutsGetRequest,
# Rollouts are not yet available in beta or GA.
# beta_messages.GkehubProjectsLocationsRolloutsGetRequest,
# ga_messages.GkehubProjectsLocationsRolloutsGetRequest,
]
GkehubProjectsLocationsRolloutsListRequest = Union[
alpha_messages.GkehubProjectsLocationsRolloutsListRequest,
# Rollouts are not yet available in beta or GA.
# beta_messages.GkehubProjectsLocationsRolloutsListRequest,
# ga_messages.GkehubProjectsLocationsRolloutsListRequest,
]
GkehubProjectsLocationsRolloutsPauseRequest = Union[
alpha_messages.GkehubProjectsLocationsRolloutsPauseRequest,
# Rollouts are not yet available in beta or GA.
# beta_messages.GkehubProjectsLocationsRolloutsPauseRequest,
# ga_messages.GkehubProjectsLocationsRolloutsPauseRequest,
]
GkehubProjectsLocationsRolloutsResumeRequest = Union[
alpha_messages.GkehubProjectsLocationsRolloutsResumeRequest,
# Rollouts are not yet available in beta or GA.
# beta_messages.GkehubProjectsLocationsRolloutsResumeRequest,
# ga_messages.GkehubProjectsLocationsRolloutsResumeRequest,
]
GkehubProjectsLocationsRolloutSequencesCreateRequest = Union[
alpha_messages.GkehubProjectsLocationsRolloutSequencesCreateRequest,
# RolloutSequences are not yet available in beta or GA.
# beta_messages.GkehubProjectsLocationsRolloutSequencesCreateRequest,
# ga_messages.GkehubProjectsLocationsRolloutSequencesCreateRequest,
]
GkehubProjectsLocationsRolloutSequencesGetRequest = Union[
alpha_messages.GkehubProjectsLocationsRolloutSequencesGetRequest,
# RolloutSequences are not yet available in beta or GA.
# beta_messages.GkehubProjectsLocationsRolloutSequencesGetRequest,
# ga_messages.GkehubProjectsLocationsRolloutSequencesGetRequest,
]
GkehubProjectsLocationsRolloutSequencesListRequest = Union[
alpha_messages.GkehubProjectsLocationsRolloutSequencesListRequest,
# RolloutSequences are not yet available in beta or GA.
# beta_messages.GkehubProjectsLocationsRolloutSequencesListRequest,
# ga_messages.GkehubProjectsLocationsRolloutSequencesListRequest,
]
GkehubProjectsLocationsRolloutSequencesDeleteRequest = Union[
alpha_messages.GkehubProjectsLocationsRolloutSequencesDeleteRequest,
# RolloutSequences are not yet available in beta or GA.
# beta_messages.GkehubProjectsLocationsRolloutSequencesDeleteRequest,
# ga_messages.GkehubProjectsLocationsRolloutSequencesDeleteRequest,
]
GkehubProjectsLocationsRolloutSequencesPatchRequest = Union[
alpha_messages.GkehubProjectsLocationsRolloutSequencesPatchRequest,
# RolloutSequences are not yet available in beta or GA.
# beta_messages.GkehubProjectsLocationsRolloutSequencesPatchRequest,
# ga_messages.GkehubProjectsLocationsRolloutSequencesPatchRequest,
]
Operation = Union[
alpha_messages.Operation, beta_messages.Operation, ga_messages.Operation
]
PolicyBinding = Union[
alpha_messages.PolicyBinding,
beta_messages.PolicyBinding,
ga_messages.PolicyBinding,
]
Rollout = Union[
alpha_messages.Rollout,
# Rollouts are not yet available in beta or GA.
# beta_messages.Rollout,
# ga_messages.Rollout,
]
RolloutSequence = Union[
alpha_messages.RolloutSequence,
# RolloutSequences are not yet available in beta or GA.
# beta_messages.RolloutSequence,
# ga_messages.RolloutSequence,
]
RolloutGenerator = Generator[Rollout, None, None]
RolloutSequenceGenerator = Generator[RolloutSequence, None, None]
SecurityPostureConfig = Union[
alpha_messages.SecurityPostureConfig,
beta_messages.SecurityPostureConfig,
ga_messages.SecurityPostureConfig,
]
SecurityPostureConfigModeValueValuesEnum = Union[
alpha_messages.SecurityPostureConfig.ModeValueValuesEnum,
beta_messages.SecurityPostureConfig.ModeValueValuesEnum,
ga_messages.SecurityPostureConfig.ModeValueValuesEnum,
]
SecurityPostureConfigVulnerabilityModeValueValuesEnum = Union[
alpha_messages.SecurityPostureConfig.VulnerabilityModeValueValuesEnum,
beta_messages.SecurityPostureConfig.VulnerabilityModeValueValuesEnum,
ga_messages.SecurityPostureConfig.VulnerabilityModeValueValuesEnum,
]
TrackClient = Union[
alpha_client.GkehubV1alpha, beta_client.GkehubV1beta, ga_client.GkehubV1
]
V2TrackClient = Union[
v2_alpha_client.GkehubV2alpha,
v2_beta_client.GkehubV2beta,
v2_ga_client.GkehubV2,
]

View File

@@ -0,0 +1,497 @@
# -*- 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.
"""Fleet API utils."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import re
from googlecloudsdk.api_lib.container.fleet import types
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import parser_extensions
from googlecloudsdk.core import exceptions
from googlecloudsdk.core import resources
from googlecloudsdk.generated_clients.apis.gkehub.v1alpha import gkehub_v1alpha_messages as alpha_messages
VERSION_MAP = {
base.ReleaseTrack.ALPHA: 'v1alpha',
base.ReleaseTrack.BETA: 'v1beta',
base.ReleaseTrack.GA: 'v1',
}
V2_VERSION_MAP = {
base.ReleaseTrack.ALPHA: 'v2alpha',
base.ReleaseTrack.BETA: 'v2beta',
base.ReleaseTrack.GA: 'v2',
}
def GetMessagesModule(release_track=base.ReleaseTrack.GA):
return apis.GetMessagesModule('gkehub', VERSION_MAP[release_track])
def GetV2MessagesModule(release_track=base.ReleaseTrack.ALPHA):
return apis.GetMessagesModule('gkehub', V2_VERSION_MAP[release_track])
def FleetMessageModule(release_track: base.ReleaseTrack):
"""Dynamically load Fleet message module based on command track.
Explicitly import message to enable type hint in Cider-V since
`apis.GetMessagesModule()` cannot derive type to the specific Python module.
Args:
release_track: Determines the generated API message module to be returned.
Returns:
An API message module that corresponds to the release track.
"""
if release_track == base.ReleaseTrack.ALPHA:
return alpha_messages
raise NotImplementedError(
'Fleet command has not been promoted to {} track.'.format(
release_track.name
)
)
def GetClientInstance(
release_track=base.ReleaseTrack.GA,
) -> types.TrackClient:
return apis.GetClientInstance('gkehub', VERSION_MAP[release_track])
def GetV2ClientInstance(
release_track=base.ReleaseTrack.ALPHA,
) -> types.V2TrackClient:
return apis.GetClientInstance('gkehub', V2_VERSION_MAP[release_track])
def GetClientClass(release_track=base.ReleaseTrack.GA):
return apis.GetClientClass('gkehub', VERSION_MAP[release_track])
def LocationResourceName(project, location='global'):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Create(
'gkehub.projects.locations',
projectsId=project,
locationsId=location,
).RelativeName()
def MembershipLocation(full_name):
matches = re.search('projects/.*/locations/(.*)/memberships/(.*)', full_name)
if matches:
return matches.group(1)
raise exceptions.Error(
'Invalid membership resource name: {}'.format(full_name)
)
def MembershipResourceName(project, membership, location='global'):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Create(
'gkehub.projects.locations.memberships',
projectsId=project,
locationsId=location,
membershipsId=membership,
).RelativeName()
def MembershipFeatureResourceName(
project,
membership,
feature,
location='global',
release_track=base.ReleaseTrack.ALPHA,
):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': location,
'membershipsId': membership,
'featuresId': feature,
},
collection='gkehub.projects.locations.memberships.features',
# Defaults to v1 without specifying api version.
api_version=V2_VERSION_MAP[release_track],
).RelativeName()
def MembershipPartialName(full_name):
matches = re.search('projects/.*/locations/(.*)/memberships/(.*)', full_name)
if matches:
return matches.group(1) + '/' + matches.group(2)
raise exceptions.Error(
'Invalid membership resource name: {}'.format(full_name)
)
def MembershipShortname(full_name):
return resources.REGISTRY.ParseRelativeName(
full_name, collection='gkehub.projects.locations.memberships'
).Name()
def FeatureResourceName(project, feature, location='global'):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Create(
'gkehub.projects.locations.features',
projectsId=project,
locationsId=location,
featuresId=feature,
).RelativeName()
def OperationResourceName(project, operation, location='global'):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Create(
'gkehub.projects.locations.operations',
projectsId=project,
locationsId=location,
operationsId=operation,
).RelativeName()
def FleetRef(
project,
fleet='default',
location='global',
release_track=base.ReleaseTrack.ALPHA,
) -> resources.Resource:
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': location,
'fleetsId': fleet,
},
collection='gkehub.projects.locations.fleets',
api_version=VERSION_MAP[release_track],
)
def FleetResourceName(
project,
fleet='default',
location='global',
release_track=base.ReleaseTrack.ALPHA,
) -> str:
# See command_lib/container/fleet/resources.yaml
return FleetRef(project, fleet, location, release_track).RelativeName()
def FleetParentName(
project, location='global', release_track=base.ReleaseTrack.ALPHA
):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': location,
},
collection='gkehub.projects.locations',
api_version=VERSION_MAP[release_track],
).RelativeName()
def FleetOrgParentName(organization, location='global'):
return 'organizations/{0}/locations/{1}'.format(organization, location)
def ScopeParentName(project, release_track=base.ReleaseTrack.ALPHA):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': 'global',
},
collection='gkehub.projects.locations',
api_version=VERSION_MAP[release_track],
).RelativeName()
def NamespaceParentName(project, release_track=base.ReleaseTrack.ALPHA):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': 'global',
},
collection='gkehub.projects.locations',
api_version=VERSION_MAP[release_track],
).RelativeName()
def NamespaceResourceName(project, name, release_track=base.ReleaseTrack.ALPHA):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': 'global',
'namespacesId': name,
},
collection='gkehub.projects.locations.namespaces',
api_version=VERSION_MAP[release_track],
).RelativeName()
def ScopeNamespaceParentName(
project, scope, release_track=base.ReleaseTrack.ALPHA
):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': 'global',
'scopesId': scope,
},
collection='gkehub.projects.locations.scopes',
api_version=VERSION_MAP[release_track],
).RelativeName()
def ScopeNamespaceResourceName(
project, scope, name, release_track=base.ReleaseTrack.ALPHA
):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': 'global',
'scopesId': scope,
'namespacesId': name,
},
collection='gkehub.projects.locations.scopes.namespaces',
api_version=VERSION_MAP[release_track],
).RelativeName()
def RBACRoleBindingParentName(
project, namespace, release_track=base.ReleaseTrack.ALPHA
):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': 'global',
'namespacesId': namespace,
},
collection='gkehub.projects.locations.namespaces',
api_version=VERSION_MAP[release_track],
).RelativeName()
def ScopeRBACRoleBindingParentName(
project, scope, release_track=base.ReleaseTrack.ALPHA
):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': 'global',
'scopesId': scope,
},
collection='gkehub.projects.locations.scopes',
api_version=VERSION_MAP[release_track],
).RelativeName()
def RBACRoleBindingResourceName(
project, namespace, name, release_track=base.ReleaseTrack.ALPHA
):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': 'global',
'namespacesId': namespace,
'rbacrolebindingsId': name,
},
collection='gkehub.projects.locations.namespaces.rbacrolebindings',
api_version=VERSION_MAP[release_track],
).RelativeName()
def ScopeRBACRoleBindingResourceName(
project, scope, name, release_track=base.ReleaseTrack.ALPHA
):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': 'global',
'scopesId': scope,
'rbacrolebindingsId': name,
},
collection='gkehub.projects.locations.scopes.rbacrolebindings',
api_version=VERSION_MAP[release_track],
).RelativeName()
def MembershipRBACRoleBindingResourceName(
project, location, membership, name, release_track=base.ReleaseTrack.ALPHA
):
"""Parses a Membership RBAC Role Binding resource.
Args:
project: the full project ID or number for the resource.
location: the location of the resource.
membership: the parent membership of the resource.
name: the resource name for the role binding.
release_track: the API version for the resource parsing.
Returns:
A Membership RBAC Role Binding resource.
"""
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': location,
'membershipsId': membership,
'rbacrolebindingsId': name,
},
collection='gkehub.projects.locations.memberships.rbacrolebindings',
api_version=VERSION_MAP[release_track],
).RelativeName()
def MembershipBindingResourceName(
project,
name,
membership,
location='global',
release_track=base.ReleaseTrack.GA,
):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': location,
'membershipsId': membership,
'bindingsId': name,
},
collection='gkehub.projects.locations.memberships.bindings',
api_version=VERSION_MAP[release_track],
).RelativeName()
def MembershipBindingParentName(
project, membership, location='global', release_track=base.ReleaseTrack.GA
):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Parse(
line=None,
params={
'projectsId': project,
'locationsId': location,
'membershipsId': membership,
},
collection='gkehub.projects.locations.memberships',
api_version=VERSION_MAP[release_track],
).RelativeName()
def ScopeResourceName(project, scope, location='global'):
# See command_lib/container/fleet/resources.yaml
return resources.REGISTRY.Create(
'gkehub.projects.locations.scopes',
projectsId=project,
locationsId=location,
scopesId=scope,
).RelativeName()
def OperationRef(operation: alpha_messages.Operation) -> resources.Resource:
"""Parses a gkehub Operation reference from an operation."""
return resources.REGISTRY.ParseRelativeName(
operation.name, collection='gkehub.projects.locations.operations'
)
def RolloutRef(args: parser_extensions.Namespace) -> resources.Resource:
if getattr(args.CONCEPTS, 'rollout', None):
return args.CONCEPTS.rollout.Parse()
def RolloutName(args: parser_extensions.Namespace) -> str:
rollout_ref = RolloutRef(args)
if rollout_ref:
return rollout_ref.RelativeName()
return None
def RolloutParentName(args: parser_extensions.Namespace):
rollout_ref = RolloutRef(args)
if rollout_ref:
return rollout_ref.Parent().RelativeName()
return None
def RolloutId(args: parser_extensions.Namespace) -> str:
rollout_ref = RolloutRef(args)
if rollout_ref:
return rollout_ref.Name()
return None
def RolloutSequenceRef(
args: parser_extensions.Namespace,
) -> resources.Resource:
if getattr(args.CONCEPTS, 'rolloutsequence', None):
return args.CONCEPTS.rolloutsequence.Parse()
return None
def RolloutSequenceName(args: parser_extensions.Namespace) -> str:
rollout_sequence_ref = RolloutSequenceRef(args)
if rollout_sequence_ref:
return rollout_sequence_ref.RelativeName()
return None
def RolloutSequenceParentName(args: parser_extensions.Namespace):
rollout_sequence_ref = RolloutSequenceRef(args)
if rollout_sequence_ref:
return rollout_sequence_ref.Parent().RelativeName()
return None
def RolloutSequenceId(args: parser_extensions.Namespace) -> str:
rollout_sequence_ref = RolloutSequenceRef(args)
if rollout_sequence_ref:
return rollout_sequence_ref.Name()
return None