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,67 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 Google LLC. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""The command group for the Services V1 CLI."""
from googlecloudsdk.calliope import base
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class ServicesAlpha(base.Group):
"""List, enable and disable APIs and services.
The gcloud services command group lets you manage your project's access to
services provided by Google and third parties.
"""
category = base.API_PLATFORM_AND_ECOSYSTEMS_CATEGORY
def Filter(self, context, args):
del context, args
# Don't ever take this off. Use gcloud quota so that you can enable APIs
# on your own project before you have API access on that project.
base.DisableUserProjectQuota()
@base.ReleaseTracks(base.ReleaseTrack.BETA, base.ReleaseTrack.GA)
class Services(base.Group):
"""List, enable and disable APIs and services.
The gcloud services command group lets you manage your project's access to
services provided by Google and third parties.
## EXAMPLES
To see how to enable a service, run:
$ {command} enable --help
To see how to list services, run:
$ {command} list --help
To see how to disable a service, run:
$ {command} disable --help
"""
category = base.API_PLATFORM_AND_ECOSYSTEMS_CATEGORY
def Filter(self, context, args):
del context, args
# Don't ever take this off. Use gcloud quota so that you can enable APIs
# on your own project before you have API access on that project.
base.DisableUserProjectQuota()

View File

@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""Package for the api_keys CLI subcommands."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA,
base.ReleaseTrack.GA)
class ApiKeys(base.Group):
"""Manage API keys."""

View File

@@ -0,0 +1,166 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""services api-keys create command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import apikeys
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
OP_BASE_CMD = 'gcloud services operations '
OP_WAIT_CMD = OP_BASE_CMD + 'wait {0}'
_DETAILED_HELP = {'EXAMPLES': """
To create a key with display name and allowed IPs specified:
$ {command} --display-name="test name" --allowed-ips=2620:15c:2c4:203:2776:1f90:6b3b:217,104.133.8.78
To create a key with annotations:
$ {command} --annotations=foo=bar,abc=def
To create a key with user-specified key ID:
$ {command} --key-id="my-key-id"
To create a key with allowed referrers restriction:
$ {command} --allowed-referrers="https://www.example.com/*,http://sub.example.com/*"
To create a key with allowed IOS app bundle IDs:
$ {command} --allowed-bundle-ids=my.app
To create a key with allowed Android application:
$ {command} --allowed-application=sha1_fingerprint=foo1,package_name=bar.foo --allowed-application=sha1_fingerprint=foo2,package_name=foo.bar
To create a key with allowed API targets (service name only):
$ {command} --api-target=service=bar.service.com --api-target=service=foo.service.com
To create a key with service account:
$ {command} --service-account=my-service-account
To create a key with allowed API targets (service and methods are
specified):
$ {command} --flags-file=my-flags.yaml
The content of 'my-flags.yaml' is as follows:
```
- --api-target:
service: "foo.service.com"
- --api-target:
service: "bar.service.com"
methods:
- "foomethod"
- "barmethod"
```
"""}
@base.UniverseCompatible
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Create(base.CreateCommand):
"""Create an API key."""
@staticmethod
def Args(parser):
common_flags.display_name_flag(parser=parser, suffix='to create')
common_flags.add_key_create_args(parser)
common_flags.key_id_flag(parser=parser, suffix='to create')
common_flags.service_account_flag(parser)
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
None
"""
project_id = properties.VALUES.core.project.GetOrFail()
client = apikeys.GetClientInstance()
messages = client.MESSAGES_MODULE
key_proto = messages.V2Key(restrictions=messages.V2Restrictions())
if args.IsSpecified('display_name'):
key_proto.displayName = args.display_name
if args.IsSpecified('allowed_referrers'):
key_proto.restrictions.browserKeyRestrictions = (
messages.V2BrowserKeyRestrictions(
allowedReferrers=args.allowed_referrers
)
)
elif args.IsSpecified('allowed_ips'):
key_proto.restrictions.serverKeyRestrictions = (
messages.V2ServerKeyRestrictions(allowedIps=args.allowed_ips)
)
elif args.IsSpecified('allowed_bundle_ids'):
key_proto.restrictions.iosKeyRestrictions = messages.V2IosKeyRestrictions(
allowedBundleIds=args.allowed_bundle_ids
)
elif args.IsSpecified('allowed_application'):
key_proto.restrictions.androidKeyRestrictions = (
messages.V2AndroidKeyRestrictions(
allowedApplications=apikeys.GetAllowedAndroidApplications(
args, messages
)
)
)
if args.IsSpecified('api_target'):
key_proto.restrictions.apiTargets = apikeys.GetApiTargets(args, messages)
if args.IsSpecified('annotations'):
key_proto.annotations = apikeys.GetAnnotations(args, messages)
if args.IsSpecified('service_account'):
key_proto.serviceAccountEmail = args.service_account
if args.IsSpecified('key_id'):
request = messages.ApikeysProjectsLocationsKeysCreateRequest(
parent=apikeys.GetParentResourceName(project_id),
v2Key=key_proto,
keyId=args.key_id,
)
else:
request = messages.ApikeysProjectsLocationsKeysCreateRequest(
parent=apikeys.GetParentResourceName(project_id), v2Key=key_proto
)
op = client.projects_locations_keys.Create(request)
if not op.done:
if args.async_:
cmd = OP_WAIT_CMD.format(op.name)
log.status.Print(
'Asynchronous operation is in progress... '
'Use the following command to wait for its '
'completion:\n {0}'.format(cmd)
)
return op
op = services_util.WaitOperation(op.name, apikeys.GetOperation)
services_util.PrintOperationWithResponse(op)
return op
detailed_help = _DETAILED_HELP

View File

@@ -0,0 +1,82 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""services api-keys delete command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import apikeys
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import log
OP_BASE_CMD = 'gcloud services operations '
OP_WAIT_CMD = OP_BASE_CMD + 'wait {0}'
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Delete(base.DeleteCommand):
"""Delete an API key.
Delete an API key.
## EXAMPLES
Delete an API Key :
$ {command} projects/myproject/locations/global/keys/1234
$ {command} 1234
"""
@staticmethod
def Args(parser):
common_flags.key_flag(parser=parser, suffix='to delete')
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The response from the Delete API call.
"""
client = apikeys.GetClientInstance()
messages = client.MESSAGES_MODULE
key_ref = args.CONCEPTS.key.Parse()
request = messages.ApikeysProjectsLocationsKeysDeleteRequest(
name=key_ref.RelativeName())
op = client.projects_locations_keys.Delete(request)
if not op.done:
if args.async_:
cmd = OP_WAIT_CMD.format(op.name)
log.status.Print('Asynchronous operation is in progress... '
'Use the following command to wait for its '
'completion:\n {0}'.format(cmd))
return op
op = services_util.WaitOperation(op.name, apikeys.GetOperation)
services_util.PrintOperationWithResponse(op)
return op

View File

@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""services api-keys describe command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import apikeys
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
DETAILED_HELP = {
'DESCRIPTION':
"""Describe an API key's metadata.""",
'EXAMPLES':
"""\
To describe an API key using Key:
$ {command} 1234
OR
$ {command} projects/myproject/locations/global/keys/1234
To describe an API key with key and project:
$ {command} 1234 --project=myproject
To describe an API key with key, project, and location:
$ {command} 1234 --project=myproject --location=global
""",
}
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA,
base.ReleaseTrack.GA)
class DescribeGa(base.DescribeCommand):
"""Describe an API key's metadata."""
detailed_help = DETAILED_HELP
@staticmethod
def Args(parser):
common_flags.key_flag(parser=parser, suffix='to describe', api_version='v2')
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The metadata of API key.
"""
client = apikeys.GetClientInstance(self.ReleaseTrack())
messages = client.MESSAGES_MODULE
key_ref = args.CONCEPTS.key.Parse()
request = messages.ApikeysProjectsLocationsKeysGetRequest(
name=key_ref.RelativeName())
return client.projects_locations_keys.Get(request)

View File

@@ -0,0 +1,68 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""services api-keys get-key-string command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import apikeys
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class GetKeyString(base.DescribeCommand):
"""Get the key string of an API key.
Get the key string of an API key
## EXAMPLES
To get the key string of API key `1234`, run:
$ {command} 1234
To get the key string of API key `1234` in project
`myproject` using the fully qualified API key name, run:
$ {command} projects/myproject/locations/global/keys/1234
"""
@staticmethod
def Args(parser):
common_flags.key_flag(parser=parser, suffix='to retrieve key string')
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Key string.
"""
client = apikeys.GetClientInstance()
messages = client.MESSAGES_MODULE
key_ref = args.CONCEPTS.key.Parse()
request = messages.ApikeysProjectsLocationsKeysGetKeyStringRequest(
name=key_ref.RelativeName())
return client.projects_locations_keys.GetKeyString(request)

View File

@@ -0,0 +1,83 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""services api-keys list command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import apikeys
from googlecloudsdk.calliope import base
from googlecloudsdk.core import properties
from googlecloudsdk.core import resources
def _GetUriFunction(api_version):
"""Returns a Uri function for list."""
collection = 'apikeys.projects.locations.keys'
def UriFunc(resource):
return resources.REGISTRY.ParseRelativeName(
resource.name, collection=collection,
api_version=api_version).SelfLink()
return UriFunc
def _ListArgs(parser):
parser.add_argument(
'--show-deleted',
action='store_true',
help=('Show soft-deleted keys by specifying this flag.'))
@base.ReleaseTracks(base.ReleaseTrack.ALPHA,
base.ReleaseTrack.BETA, base.ReleaseTrack.GA)
class List(base.ListCommand):
"""Lists API keys.
Lists the API keys of a given project.
## EXAMPLES
List keys of a given project:
$ {command}
List keys of a given project, including keys that were soft-deleted in the
past 30 days.:
$ {command} --show-deleted --project=my_project
"""
@staticmethod
def Args(parser):
_ListArgs(parser)
parser.display_info.AddUriFunc(_GetUriFunction(api_version='v2'))
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The list of api keys.
"""
project_id = properties.VALUES.core.project.GetOrFail()
return apikeys.ListKeys(project_id, args.show_deleted, args.page_size,
args.limit)

View File

@@ -0,0 +1,59 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""services api-keys lookup command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import apikeys
from googlecloudsdk.calliope import base
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Lookup(base.Command):
"""Look up resource name of a key string.
Look up resource name of a key string.
## EXAMPLES
Look up resource name of a key string named my-key-string:
$ {command} my-key-string
"""
@staticmethod
def Args(parser):
parser.add_argument('key_string', help='Key string of the key')
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Resource name and its parent name.
"""
client = apikeys.GetClientInstance()
messages = client.MESSAGES_MODULE
request = messages.ApikeysKeysLookupKeyRequest(keyString=args.key_string)
return client.keys.LookupKey(request)

View File

@@ -0,0 +1,102 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""services api-keys undelete command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import apikeys
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import log
OP_BASE_CMD = 'gcloud services operations '
OP_WAIT_CMD = OP_BASE_CMD + 'wait {0}'
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Undelete(base.RestoreCommand):
"""Undelete an API key.
API Keys that are deleted will be retained in the system for 30 days. If a
key is still within this retention window, it can be undeleted with this
command.
## EXAMPLES
UnDelete an API Key (Key or key-string should be specified):
To undelete with key `1234`, run:
$ {command} 1234
To undelete with `1234` in project `myproject` using the fully qualified API
key name, run:
$ {command} projects/myproject/locations/global/keys/1234
To undelete using a Key-string, run:
$ {command} --key-string='my-key-string'
"""
@staticmethod
def Args(parser):
common_flags.add_key_undelete_args(parser)
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
None
"""
client = apikeys.GetClientInstance()
messages = client.MESSAGES_MODULE
if args.IsSpecified('key'):
key_ref = args.CONCEPTS.key.Parse()
key_name = key_ref.RelativeName()
if args.IsSpecified('key_string'):
lookup_request = messages.ApikeysKeysLookupKeyRequest(
keyString=args.key_string
)
response = client.keys.LookupKey(lookup_request)
key_name = response.name
request = messages.ApikeysProjectsLocationsKeysUndeleteRequest(
name=key_name
)
op = client.projects_locations_keys.Undelete(request)
if not op.done:
if args.async_:
cmd = OP_WAIT_CMD.format(op.name)
log.status.Print('Asynchronous operation is in progress... '
'Use the following command to wait for its '
'completion:\n {0}'.format(cmd))
return op
op = services_util.WaitOperation(op.name, apikeys.GetOperation)
services_util.PrintOperationWithResponse(op)
return op

View File

@@ -0,0 +1,157 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""services api-keys update command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import apikeys
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import log
OP_BASE_CMD = 'gcloud services operations '
OP_WAIT_CMD = OP_BASE_CMD + 'wait {0}'
DETAILED_HELP = {
'EXAMPLES':
"""
To remove all restrictions of the key:
$ {command} projects/myproject/keys/my-key-id --clear-restrictions
To update display name and set allowed ips as server key restrictions:
$ {command} projects/myproject/keys/my-key-id --display-name="test name" --allowed-ips=2620:15c:2c4:203:2776:1f90:6b3b:217,104.133.8.78
To update annotations:
$ {command} projects/myproject/keys/my-key-id --annotations=foo=bar,abc=def
To update key's allowed referrers restriction:
$ {command} projects/myproject/keys/my-key-id --allowed-referrers="https://www.example.com/*,http://sub.example.com/*"
To update key's allowed ios app bundle ids:
$ {command} projects/myproject/keys/my-key-id --allowed-bundle-ids=my.app
To update key's allowed android application:
$ {command} projects/myproject/keys/my-key-id --allowed-application=sha1_fingerprint=foo1,package_name=bar1 --allowed-application=sha1_fingerprint=foo2,package_name=bar2
To update keys' allowed api target with multiple services:
$ {command} projects/myproject/keys/my-key-id --api-target=service=bar.service.com --api-target=service=foo.service.com
To update keys' allowed api target with service and method:
$ {command} projects/myproject/keys/my-key-id --flags-file=my-flags.yaml
The content of 'my-flags.yaml' is as following:
```
- --api-target:
service: "foo.service.com"
- --api-target:
service: "bar.service.com"
methods:
- "foomethod"
- "barmethod"
```
"""
}
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Update(base.UpdateCommand):
"""Update an API key's metadata."""
@staticmethod
def Args(parser):
common_flags.key_flag(parser=parser, suffix='to update')
common_flags.display_name_flag(parser=parser, suffix='to update')
common_flags.add_key_update_args(parser)
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
None
"""
client = apikeys.GetClientInstance()
messages = client.MESSAGES_MODULE
key_ref = args.CONCEPTS.key.Parse()
update_mask = []
key_proto = messages.V2Key(
name=key_ref.RelativeName(), restrictions=messages.V2Restrictions())
if args.IsSpecified('annotations'):
update_mask.append('annotations')
key_proto.annotations = apikeys.GetAnnotations(args, messages)
if args.IsSpecified('display_name'):
update_mask.append('display_name')
key_proto.displayName = args.display_name
if args.IsSpecified('clear_annotations'):
update_mask.append('annotations')
if args.IsSpecified('clear_restrictions'):
update_mask.append('restrictions')
else:
if args.IsSpecified('allowed_referrers'):
update_mask.append('restrictions.browser_key_restrictions')
key_proto.restrictions.browserKeyRestrictions = messages.V2BrowserKeyRestrictions(
allowedReferrers=args.allowed_referrers)
elif args.IsSpecified('allowed_ips'):
update_mask.append('restrictions.server_key_restrictions')
key_proto.restrictions.serverKeyRestrictions = messages.V2ServerKeyRestrictions(
allowedIps=args.allowed_ips)
elif args.IsSpecified('allowed_bundle_ids'):
update_mask.append('restrictions.ios_key_restrictions')
key_proto.restrictions.iosKeyRestrictions = messages.V2IosKeyRestrictions(
allowedBundleIds=args.allowed_bundle_ids)
elif args.IsSpecified('allowed_application'):
update_mask.append('restrictions.android_key_restrictions')
key_proto.restrictions.androidKeyRestrictions = messages.V2AndroidKeyRestrictions(
allowedApplications=apikeys.GetAllowedAndroidApplications(
args, messages))
if args.IsSpecified('api_target'):
update_mask.append('restrictions.api_targets')
key_proto.restrictions.apiTargets = apikeys.GetApiTargets(
args, messages)
request = messages.ApikeysProjectsLocationsKeysPatchRequest(
name=key_ref.RelativeName(),
updateMask=','.join(update_mask),
v2Key=key_proto)
op = client.projects_locations_keys.Patch(request)
if not op.done:
if args.async_:
cmd = OP_WAIT_CMD.format(op.name)
log.status.Print('Asynchronous operation is in progress... '
'Use the following command to wait for its '
'completion:\n {0}'.format(cmd))
return op
op = services_util.WaitOperation(op.name, apikeys.GetOperation)
services_util.PrintOperationWithResponse(op)
return op
detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,278 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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.
"""services disable command."""
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import arg_parsers
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
from googlecloudsdk.core.console import console_io
OP_BASE_CMD = 'gcloud beta services operations '
OP_WAIT_CMD = OP_BASE_CMD + 'wait {0}'
# TODO(b/321801975) make command public after preview.
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class DisableAlpha(base.SilentCommand):
"""Disable a service for consumption for a project, folder or organization.
This command disables one or more previously-enabled services for
consumption.
To see a list of the enabled services for a project, run:
$ {parent_command} list
More information on listing services can be found at:
https://cloud.google.com/service-usage/docs/list-services and on
disabling a service at:
https://cloud.google.com/service-usage/docs/enable-disable
## EXAMPLES
To disable a service called `my-consumed-service` for the current
project, run:
$ {command} my-consumed-service
To disable a service called `my-consumed-service` for the project
`my-project`, run:
$ {command} my-consumed-service --project=my-project
To disable a service called `my-consumed-service` for the folder
`my-folder`, run:
$ {command} my-consumed-service --folder=my-folder
To disable a service called `my-consumed-service` for the organization
`my-organization`, run:
$ {command} my-consumed-service --organization=my-organization
To run the same command asynchronously (non-blocking), run:
$ {command} my-consumed-service --async
"""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
common_flags.consumer_service_flag(suffix='to disable').AddToParser(parser)
common_flags.add_resource_args(parser)
base.ASYNC_FLAG.AddToParser(parser)
common_flags.validate_only_args(parser, suffix='disable')
common_flags.bypass_api_usage_check_flag(parser)
common_flags.add_dependency_check_args(parser)
parser.add_argument(
'--force',
action='store_true',
help=(
'If specified, the disable call will proceed even if there are'
' enabled services which depend on the service to be disabled, or'
' the service to be disabled was used in the last 30 days, or the'
' service to be disabled was enabled in the last 3 days. Forcing'
' the call means that the services which depend on the service to'
' be disabled will also be disabled. (Note): If '
' --bypass-api-usage-check, --bypass-dependency-service-check, or'
' --disable-dependency-services flags are used, they will take'
' precedence over --force.'
),
)
def Run(self, args):
"""Run 'services disable'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
Nothing.
"""
project = (
args.project
if args.IsSpecified('project')
else properties.VALUES.core.project.Get(required=True)
)
folder = args.folder if args.IsSpecified('folder') else None
organization = (
args.organization if args.IsSpecified('organization') else None
)
bypass_api_usage_check = args.force
# Default behaviour without any flags.
# The operation will be blocked if there are
# any enabled dependent services.
skip_dependency_check = False
disable_dependency_services = False
# All dependent services will be disabled.
if args.IsSpecified('force') or args.IsSpecified(
'disable_dependency_services'
):
disable_dependency_services = True
# API usage check of the service to be disabled will be bypassed.
if args.IsSpecified('bypass_api_usage_check'):
bypass_api_usage_check = True
# All dependent services will remain enabled.
if args.IsSpecified('bypass_dependency_service_check'):
skip_dependency_check = True
service_names = []
for service_name in args.service:
service_name = arg_parsers.GetServiceNameFromArg(service_name)
protected_msg = serviceusage.GetProtectedServiceWarning(service_name)
if protected_msg:
if args.IsSpecified('quiet'):
raise console_io.RequiredPromptError()
do_disable = console_io.PromptContinue(
protected_msg, default=False, throw_if_unattended=True
)
if not do_disable:
continue
service_names.append(service_name)
if not service_names:
return None
op = serviceusage.RemoveEnableRule(
project,
service_names,
force=bypass_api_usage_check,
folder=folder,
organization=organization,
validate_only=args.validate_only,
skip_dependency_check=skip_dependency_check,
disable_dependency_services=disable_dependency_services,
)
if op is None:
return None
if args.async_:
cmd = OP_WAIT_CMD.format(op.name)
log.status.Print(
'Asynchronous operation is in progress... Use the following'
f' command to wait for its completion:\n {cmd}'
)
op = services_util.WaitOperation(op.name, serviceusage.GetOperationV2Beta)
if args.validate_only:
services_util.PrintOperation(op)
else:
services_util.PrintOperationWithResponseForUpdateConsumerPolicy(op)
@base.ReleaseTracks(base.ReleaseTrack.GA)
class Disable(base.SilentCommand):
"""Disable a service for consumption for a project.
This command disables one or more previously-enabled services for
consumption.
To see a list of the enabled services for a project, run:
$ {parent_command} list
More information on listing services can be found at:
https://cloud.google.com/service-usage/docs/list-services and on
disabling a service at:
https://cloud.google.com/service-usage/docs/enable-disable
## EXAMPLES
To disable a service called `my-consumed-service` for the active
project, run:
$ {command} my-consumed-service
To run the same command asynchronously (non-blocking), run:
$ {command} my-consumed-service --async
"""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
common_flags.consumer_service_flag(suffix='to disable').AddToParser(parser)
base.ASYNC_FLAG.AddToParser(parser)
parser.add_argument(
'--force',
action='store_true',
help=(
'If specified, the disable call will proceed even if there are'
' enabled services which depend on the service to be disabled or'
' disable the service used in last 30 days or was enabled in'
' recent 3 days. Forcing the call means that the services which'
' depend on the service to be disabled will also be disabled.'
),
)
def Run(self, args):
"""Run 'services disable'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
Nothing.
"""
project = properties.VALUES.core.project.Get(required=True)
for service_name in args.service:
service_name = arg_parsers.GetServiceNameFromArg(service_name)
protected_msg = serviceusage.GetProtectedServiceWarning(service_name)
if protected_msg:
if args.IsSpecified('quiet'):
raise console_io.RequiredPromptError()
do_disable = console_io.PromptContinue(
protected_msg, default=False, throw_if_unattended=True
)
if not do_disable:
continue
op = serviceusage.DisableApiCall(project, service_name, args.force)
if op.done:
continue
if args.async_:
cmd = OP_WAIT_CMD.format(op.name)
log.status.Print(
'Asynchronous operation is in progress... '
'Use the following command to wait for its '
f'completion:\n {cmd}'
)
continue
op = services_util.WaitOperation(op.name, serviceusage.GetOperation)
services_util.PrintOperation(op)

View File

@@ -0,0 +1,233 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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.
"""services enable command."""
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
_OP_BASE_CMD = 'gcloud beta services operations '
_OP_WAIT_CMD = _OP_BASE_CMD + 'wait {0}'
_DETAILED_HELP_ALPHA = {
'DESCRIPTION': """\
This command enables a service for consumption for a project, folder or organization.
To see a list of available services for a project, run:
$ {parent_command} list --available
More information on listing services can be found at:
https://cloud.google.com/service-usage/docs/list-services and on
disabling a service at:
https://cloud.google.com/service-usage/docs/enable-disable
""",
'EXAMPLES': """\
To enable a service called `my-consumed-service` on the current
project, run:
$ {command} my-consumed-service
To enable a service called `my-consumed-service` on the project
`my-project`, run:
$ {command} my-consumed-service --project=my-project
To enable a service called `my-consumed-service` on the folder
`my-folder, run:
$ {command} my-consumed-service --folder=my-folder
To enable a service called `my-consumed-service` on the organization
`my-organization`, run:
$ {command} my-consumed-service --organization=my-organization
To run the same command asynchronously (non-blocking), run:
$ {command} my-consumed-service --async
To enable services called `service1`, `service2`, and `service3` on the
current project, run:
$ {command} service1 service2 service3
""",
}
_DETAILED_HELP = {
'DESCRIPTION': """\
This command enables a service for consumption for a project.
To see a list of available services for a project, run:
$ {parent_command} list --available
More information on listing services can be found at:
https://cloud.google.com/service-usage/docs/list-services and on
disabling a service at:
https://cloud.google.com/service-usage/docs/enable-disable
""",
'EXAMPLES': """\
To enable a service called `my-consumed-service` on the current
project, run:
$ {command} my-consumed-service
To run the same command asynchronously (non-blocking), run:
$ {command} my-consumed-service --async
To enable services called `service1`, `service2`, and `service3` on the
current project, run:
$ {command} service1 service2 service3
""",
}
# TODO(b/321801975) make command public after preview.
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class EnableAlpha(base.SilentCommand):
"""Enables a service for consumption for a project, folder or organization."""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
common_flags.available_service_flag(suffix='to enable').AddToParser(parser)
common_flags.add_resource_args(parser)
base.ASYNC_FLAG.AddToParser(parser)
common_flags.validate_only_args(parser, suffix='enable')
common_flags.skip_dependency_flag(parser)
def Run(self, args):
"""Run 'services enable'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
Nothing.
"""
project = (
args.project
if args.IsSpecified('project')
else properties.VALUES.core.project.Get(required=True)
)
folder = args.folder if args.IsSpecified('folder') else None
organization = (
args.organization if args.IsSpecified('organization') else None
)
update_consumer_policy_op, services_enabled = serviceusage.AddEnableRule(
args.service,
project,
folder=folder,
organization=organization,
validate_only=args.validate_only,
skip_dependency=args.skip_dependency,
)
if update_consumer_policy_op is None:
return None
if args.async_:
cmd = _OP_WAIT_CMD.format(update_consumer_policy_op.name)
log.status.Print(
'Asynchronous operation is in progress... '
'Use the following command to wait for its '
f'completion:\n {cmd}'
)
if not folder and not organization:
serviceusage.GenerateServiceIdentityForEnabledService(
project, services_enabled
)
return
update_consumer_policy_op = services_util.WaitOperation(
update_consumer_policy_op.name, serviceusage.GetOperationV2Beta
)
if args.validate_only:
services_util.PrintOperation(update_consumer_policy_op)
else:
services_util.PrintOperationWithResponse(update_consumer_policy_op)
if (
not update_consumer_policy_op.error
and not folder
and not organization
):
serviceusage.GenerateServiceIdentityForEnabledService(
project, services_enabled
)
EnableAlpha.detailed_help = _DETAILED_HELP_ALPHA
@base.ReleaseTracks(base.ReleaseTrack.GA)
class Enable(base.SilentCommand):
"""Enables a service for consumption for a project."""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go
on the command line after this command. Positional arguments are
allowed.
"""
common_flags.available_service_flag(suffix='to enable').AddToParser(parser)
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""Run 'services enable'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
Nothing.
"""
project = properties.VALUES.core.project.Get(required=True)
if len(args.service) == 1:
op = serviceusage.EnableApiCall(project, args.service[0])
else:
op = serviceusage.BatchEnableApiCall(project, args.service)
if op.done:
return
if args.async_:
cmd = _OP_WAIT_CMD.format(op.name)
log.status.Print(
'Asynchronous operation is in progress... '
'Use the following command to wait for its '
f'completion:\n {cmd}'
)
return
op = services_util.WaitOperation(op.name, serviceusage.GetOperation)
services_util.PrintOperation(op)
Enable.detailed_help = _DETAILED_HELP

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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.
"""Package for the groups CLI subcommands."""
from googlecloudsdk.calliope import base
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Groups(base.Group):
"""View service group information."""

View File

@@ -0,0 +1,93 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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.
"""services groups list ancestor groups command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import properties
_PROJECT_RESOURCE_TEMPLATE = 'projects/%s'
_FOLDER_RESOURCE_TEMPLATE = 'folders/%s'
_ORGANIZATION_RESOURCE_TEMPLATE = 'organizations/%s'
_SERVICE_RESOURCE_TEMPLATE = 'services/%s'
_GROUP_RESOURCE_TEMPLATE = 'groups/%s'
# TODO(b/321801975) make command public after suv2alpha launch.
@base.UniverseCompatible
@base.Hidden
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class ListAncestorGroups(base.ListCommand):
"""List ancestor groups of a specific service.
List ancestor groups of a specific service.
## EXAMPLES
List ancestor groups of service my-service:
$ {command} my-service
List ancestor groups of service my-service for a specific project '12345678':
$ {command} my-service --project=12345678
"""
@staticmethod
def Args(parser):
parser.add_argument('service', help='Name of the service.')
common_flags.add_resource_args(parser)
base.PAGE_SIZE_FLAG.SetDefault(parser, 50)
# Remove unneeded list-related flags from parser
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat("""
table(
groupName:label=''
)
""")
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Resource name and its parent name.
"""
if args.IsSpecified('folder'):
resource_name = _FOLDER_RESOURCE_TEMPLATE % args.folder
elif args.IsSpecified('organization'):
resource_name = _ORGANIZATION_RESOURCE_TEMPLATE % args.organization
elif args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE_TEMPLATE % args.project
else:
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE_TEMPLATE % project
response = serviceusage.ListAncestorGroups(
resource_name,
_SERVICE_RESOURCE_TEMPLATE % args.service,
)
return response

View File

@@ -0,0 +1,94 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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.
"""services groups list descendant services command."""
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import properties
_PROJECT_RESOURCE = 'projects/%s'
_FOLDER_RESOURCE = 'folders/%s'
_ORGANIZATION_RESOURCE = 'organizations/%s'
_SERVICE_RESOURCE = 'services/%s'
_GROUP_RESOURCE = 'groups/%s'
# TODO(b/402831836): Do not make the command public.
@base.UniverseCompatible
@base.Hidden
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class ListDescendantServices(base.ListCommand):
"""List descendant services of a specific service and group.
List descendant services of a specific service and group.
## EXAMPLES
List descendant services of service my-service and group my-group:
$ {command} my-service my-group
List descendant services of service my-service and group my-group
for a specific project '12345678':
$ {command} my-service my-group --project=12345678
"""
@staticmethod
def Args(parser):
parser.add_argument('service', help='Name of the service.')
parser.add_argument(
'group', help='Service group name, for example "dependencies".'
)
common_flags.add_resource_args(parser)
base.PAGE_SIZE_FLAG.SetDefault(parser, 50)
# Remove unneeded list-related flags from parser
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat("""
table(
serviceName:label=''
)
""")
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Resource name and its parent name.
"""
if args.IsSpecified('folder'):
resource_name = _FOLDER_RESOURCE % args.folder
elif args.IsSpecified('organization'):
resource_name = _ORGANIZATION_RESOURCE % args.organization
elif args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE % args.project
else:
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE % project
response = serviceusage.ListDescendantServices(
resource_name,
'{}/{}'.format(
_SERVICE_RESOURCE % args.service, _GROUP_RESOURCE % args.group
),
)
return response

View File

@@ -0,0 +1,108 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""services groups list expanded members command."""
import collections
from googlecloudsdk.api_lib.services import exceptions
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.command_lib.services import util
from googlecloudsdk.core import properties
_PROJECT_RESOURCE = 'projects/%s'
_FOLDER_RESOURCE = 'folders/%s'
_ORGANIZATION_RESOURCE = 'organizations/%s'
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class ListExpandedMembers(base.ListCommand):
"""List expanded members of a specific service and group.
List expanded members of a specific service and group.
## EXAMPLES
List expanded members of service my-service and group my-group:
$ {command} my-service my-group
List expanded members of service my-service and group my-group
for a specific project '12345678':
$ {command} my-service my-group --project=12345678
"""
@staticmethod
def Args(parser):
parser.add_argument('service', help='Name of the service.')
parser.add_argument(
'group', help='Service group name, for example "dependencies".'
)
common_flags.add_resource_args(parser)
base.PAGE_SIZE_FLAG.SetDefault(parser, 50)
# Remove unneeded list-related flags from parser
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat("""
table(
Name:label=''
)
""")
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Resource name and its parent name.
"""
if args.IsSpecified('folder'):
resource_name = _FOLDER_RESOURCE % args.folder
elif args.IsSpecified('organization'):
resource_name = _ORGANIZATION_RESOURCE % args.organization
elif args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE % args.project
else:
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE % project
if not util.IsValidGroupName(args.service, args.group):
raise exceptions.InvalidGroupNameError(
util.GetGroupName(args.service, args.group)
)
response = serviceusage.ListExpandedMembers(
resource_name,
util.GetGroupName(args.service, args.group),
page_size=args.page_size,
)
service_names = []
results = collections.namedtuple('Service', ['name'])
for service in response:
service_names.append(results(name=service))
if not service_names:
raise exceptions.EmptyMembersError(
util.GetGroupName(args.service, args.group)
)
return service_names

View File

@@ -0,0 +1,115 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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.
"""services groups list members command."""
import collections
from googlecloudsdk.api_lib.services import exceptions
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.command_lib.services import util
from googlecloudsdk.core import properties
_PROJECT_RESOURCE = 'projects/{}'
_FOLDER_RESOURCE = 'folders/{}'
_ORGANIZATION_RESOURCE = 'organizations/{}'
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class ListGroupMembers(base.ListCommand):
"""List members of a specific service and group.
List members of a specific service and group.
## EXAMPLES
List members of service my-service and group my-group:
$ {command} my-service my-group
List members of service my-service and group my-group
for a specific project '12345678':
$ {command} my-service my-group --project=12345678
"""
@staticmethod
def Args(parser):
parser.add_argument('service', help='Name of the service.')
parser.add_argument(
'group', help='Service group name, for example "dependencies".'
)
common_flags.add_resource_args(parser)
base.PAGE_SIZE_FLAG.SetDefault(parser, 50)
# Remove unneeded list-related flags from parser
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat("""
table(
name,
reason
)
""")
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Resource name and its parent name.
"""
if args.IsSpecified('folder'):
resource_name = _FOLDER_RESOURCE.format(args.folder)
elif args.IsSpecified('organization'):
resource_name = _ORGANIZATION_RESOURCE.format(args.organization)
elif args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE.format(args.project)
else:
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE.format(project)
if not util.IsValidGroupName(args.service, args.group):
raise exceptions.InvalidGroupNameError(
util.GetGroupName(args.service, args.group)
)
member_states = serviceusage.ListGroupMembers(
resource_name,
util.GetGroupName(args.service, args.group),
args.page_size,
)
members = []
results = collections.namedtuple('Member', ['name', 'reason'])
for member_state in member_states:
member = member_state.member
if member.groupName:
members.append(results(member.groupName, member.reason))
else:
members.append(results(member.serviceName, member.reason))
if not members:
raise exceptions.EmptyMembersError(
util.GetGroupName(args.service, args.group)
)
return members

View File

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""Package for the endpoints/quota CLI subcommands."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Identity(base.Group):
"""Manage service identity."""

View File

@@ -0,0 +1,119 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""create command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.util.args import common_args
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
class Create(base.CreateCommand):
"""Create a service identity for a consumer.
This command creates a service identity for a consumer. The supported
consumers are projects, folders, and organizations.
## EXAMPLES
To create a service identity for a project, run:
$ {command} --service=example.googleapis.com --project=helloworld
Using a project number:
$ {command} --service=example.googleapis.com --project=1234567890
To create a service identity for a folder, run:
$ {command} --service=example.googleapis.com --folder=1234567890
To create a service identity for an organization, run:
$ {command} --service=example.googleapis.com --organization=1234567890
"""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
parser.add_argument(
'--service',
required=True,
help='The service to create a service identity for.')
container = parser.add_group(
mutex=True,
help=(
'Container resource where the service identity will be used.'
),
)
common_args.ProjectArgument(
help_text_to_prepend='Project where the service identity will be used.'
).AddToParser(container)
base.Argument(
'--folder',
default=None,
type=int,
help='Folder where the service identity will be used.',
).AddToParser(container)
base.Argument(
'--organization',
default=None,
type=int,
help='Organization where the service identity will be used.',
).AddToParser(container)
def Run(self, args):
"""Run 'services identity create'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
response with service identity email and uniqueId.
"""
if args.folder:
container = args.folder
container_type = serviceusage.ContainerType.FOLDER_SERVICE_RESOURCE
elif args.organization:
container = args.organization
container_type = serviceusage.ContainerType.ORG_SERVICE_RESOURCE
else:
if args.project:
container = args.project
else:
container = properties.VALUES.core.project.Get(required=True)
container_type = serviceusage.ContainerType.PROJECT_SERVICE_RESOURCE
response = serviceusage.GenerateServiceIdentity(
container, args.service, container_type
)
if 'email' not in response:
# Print generic message when email not provided in response.
# Error in GenerateServiceIdentity indicated by thrown exception.
log.status.Print('Service identity created')
else:
log.status.Print('Service identity created: {0}'.format(
response['email']))
return response

View File

@@ -0,0 +1,221 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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.
"""services list command."""
import sys
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
# TODO(b/321801975) make command public after preview.
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class ListAlpha(base.ListCommand):
"""List services for a project, folder or organization.
This command lists the services that are enabled or available to be enabled
by a project, folder or organization. Service enablement and availability can
be inherited from
resource ancestors. A resource's enabled services include services that are
enabled on the resource itself and enabled on all resource ancestors.
services by using exactly one of the `--enabled` or `--available` flags.
`--enabled` is the default.
## EXAMPLES
To list the services the current project has enabled for consumption, run:
$ {command} --enabled
To list the services the current project can enable for
consumption, run:
$ {command} --available
"""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
mode_group = parser.add_mutually_exclusive_group(required=False)
mode_group.add_argument(
'--enabled',
action='store_true',
help=(
'(DEFAULT) Return the services which the project, folder or'
' organization has enabled.'
),
)
mode_group.add_argument(
'--available',
action='store_true',
help=(
'Return the services available to the '
'project, folder or organization to enable.'
),
)
common_flags.add_resource_args(parser)
base.PAGE_SIZE_FLAG.SetDefault(parser, 1000)
# Remove unneeded list-related flags from parser
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat("""
table(
name:label=NAME:sort=1,
title
)
""")
def Run(self, args):
"""Run 'services list'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
The list of services for this project.
"""
# Default mode is --enabled, so if no flags were specified,
# turn on the args.enabled flag.
if not (args.enabled or args.available):
args.enabled = True
if args.IsSpecified('project'):
project = args.project
else:
project = services_util.GetValidatedProject(args.project)
if args.IsSpecified('folder'):
folder = args.folder
else:
folder = None
if args.IsSpecified('organization'):
organization = args.organization
else:
organization = None
if args.IsSpecified('limit'):
limit = args.limit
else:
limit = sys.maxsize
return serviceusage.ListServicesV2Beta(
project,
args.enabled,
args.page_size,
limit,
folder=folder,
organization=organization,
)
@base.ReleaseTracks(base.ReleaseTrack.GA)
class List(base.ListCommand):
"""List services for a project.
This command lists the services that are enabled or available to be enabled
by a project. You can choose the mode in which the command will list
services by using exactly one of the `--enabled` or `--available` flags.
`--enabled` is the default.
## EXAMPLES
To list the services for the current project has enabled for consumption,
run:
$ {command} --enabled
To list the services for the current project can enable for consumption, run:
$ {command} --available
To list the services for project `my-project` has enabled for consumption,
run:
$ {command} --enabled --project=my-project
To list the services the project `my-project` can enable for consumption, run:
$ {command} --available --project=my-project
"""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go
on the command line after this command. Positional arguments are
allowed.
"""
mode_group = parser.add_mutually_exclusive_group(required=False)
mode_group.add_argument(
'--enabled',
action='store_true',
help=('(DEFAULT) Return the services which the '
'project has enabled.'))
mode_group.add_argument(
'--available',
action='store_true',
help=('Return the services available to the '
'project to enable. This list will '
'include any services that the project '
'has already enabled.'))
base.PAGE_SIZE_FLAG.SetDefault(parser, 200)
# Remove unneeded list-related flags from parser
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat("""
table(
config.name:label=NAME:sort=1,
config.title
)
""")
def Run(self, args):
"""Run 'services list'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
The list of services for this project.
"""
# Default mode is --enabled, so if no flags were specified,
# turn on the args.enabled flag.
if not (args.enabled or args.available):
args.enabled = True
project = services_util.GetValidatedProject(args.project)
return serviceusage.ListServices(
project, args.enabled, args.page_size, args.limit
)

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Package for the policies CLI subcommands."""
from googlecloudsdk.calliope import base
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class MCP(base.Group):
"""List, enable and disable MCP endpoints."""

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Package for the MCP policies CLI subcommands."""
from googlecloudsdk.calliope import base
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class ContentSecurity(base.Group):
"""Get/add/remove MCP content security."""

View File

@@ -0,0 +1,77 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""services mcp content-security add command."""
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import properties
_PROJECT_RESOURCE = 'projects/%s'
_CONTENT_SECURITY_POLICY_DEFAULT = '/contentSecurityPolicies/%s'
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Add(base.Command):
"""Add MCP content security provider of a project.
Add MCP content security provider of a project.
## EXAMPLES
Add MCP content security provider of a project:
$ {command} my-mcp-content-security-provider
Add MCP content security provider of a project `my-project`:
$ {command} my-mcp-content-security-provider --project=my-project
"""
@staticmethod
def Args(parser):
common_flags.mcp_content_security_provider_flag(
suffix='to add'
).AddToParser(parser)
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The content security providers for a project.
"""
if args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE % args.project
else:
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE % project
op = serviceusage.AddContentSecurityProvider(
args.mcp_content_security_provider,
resource_name + _CONTENT_SECURITY_POLICY_DEFAULT % 'default',
)
if op is None:
return None
op = services_util.WaitOperation(op.name, serviceusage.GetOperationV2Beta)
services_util.PrintOperation(op)

View File

@@ -0,0 +1,84 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""services mcp content-security get command."""
import collections
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.core import properties
_PROJECT_RESOURCE = 'projects/%s'
_CONTENT_SECURITY_POLICY_DEFAULT = '/contentSecurityPolicies/default'
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Get(base.Command):
"""Get MCP content security providers for a project.
Get MCP content security providers for a project.
## EXAMPLES
Get MCP content security providers for a project:
$ {command}
Get MCP content security providers for a project `my-project`:
$ {command} --project=my-project
"""
@staticmethod
def Args(parser):
parser.display_info.AddFormat("""
table(
contentSecurityProvider
)
""")
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The content security providers for a project.
"""
if args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE % args.project
else:
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE % project
mcp_content_security = serviceusage.GetContentSecurityPolicy(
resource_name + _CONTENT_SECURITY_POLICY_DEFAULT,
).mcpContentSecurity
content_security_providers = []
results = collections.namedtuple(
'ContentSecurityProvider', ['contentSecurityProvider']
)
for (
content_security_provider
) in mcp_content_security.contentSecurityProviders:
content_security_providers.append(results(content_security_provider.name))
return content_security_providers

View File

@@ -0,0 +1,77 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""services mcp content-security remove command."""
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import properties
_PROJECT_RESOURCE = 'projects/%s'
_CONTENT_SECURITY_POLICY_DEFAULT = '/contentSecurityPolicies/%s'
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Remove(base.Command):
"""Remove MCP content security provider of a project.
Remove MCP content security provider of a project.
## EXAMPLES
Remove MCP content security provider of a project:
$ {command} my-mcp-content-security-provider
Remove MCP content security provider of a project `my-project`:
$ {command} my-mcp-content-security-provider --project=my-project
"""
@staticmethod
def Args(parser):
common_flags.mcp_content_security_provider_flag(
suffix='to remove'
).AddToParser(parser)
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The content security providers for a project.
"""
if args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE % args.project
else:
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE % project
op = serviceusage.RemoveContentSecurityProvider(
args.mcp_content_security_provider,
resource_name + _CONTENT_SECURITY_POLICY_DEFAULT % 'default',
)
if op is None:
return None
op = services_util.WaitOperation(op.name, serviceusage.GetOperationV2Beta)
services_util.PrintOperation(op)

View File

@@ -0,0 +1,134 @@
# -*- 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.
"""services mcp disable command."""
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
_OP_BASE_CMD = 'gcloud beta services operations '
_OP_WAIT_CMD = _OP_BASE_CMD + 'wait {0}'
_SERVICE = 'services/%s'
_PROJECT_RESOURCE = 'projects/{}'
_FOLDER_RESOURCE = 'folders/{}'
_ORGANIZATION_RESOURCE = 'organizations/{}'
_CONSUMER_POLICY_DEFAULT = '/consumerPolicies/{}'
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Disable(base.SilentCommand):
"""Disable a service for MCP on a project, folder or organization.
Disable a service for MCP on a project, folder or organization
## EXAMPLES
To disable a service for MCP called `my-service` on the current project, run:
$ {command} my-service
To disable a service for MCP called `my-service` on the project
`my-project`, run:
$ {command} my-service --project=my-project
To disable a service for MCP called `my-service` on the folder
`my-folder, run:
$ {command} my-service --folder=my-folder
To disable a service for MCP called `my-service` on the organization
`my-organization`, run:
$ {command} my-service --organization=my-organization
To run the same command asynchronously (non-blocking), run:
$ {command} my-service --async
"""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
common_flags.service_flag(suffix='to disable MCP').AddToParser(parser)
common_flags.add_resource_args(parser)
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""Run 'services mcp disable'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
Updated MCP Policy.
"""
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE.format(project)
if args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE.format(args.project)
project = args.project
if args.IsSpecified('folder'):
resource_name = _FOLDER_RESOURCE.format(args.folder)
folder = args.folder
else:
folder = None
if args.IsSpecified('organization'):
resource_name = _ORGANIZATION_RESOURCE.format(args.organization)
organization = args.organization
else:
organization = None
op = serviceusage.RemoveMcpEnableRule(
project,
args.service,
folder=folder,
organization=organization,
)
if op is None:
return None
if args.async_:
cmd = _OP_WAIT_CMD.format(op.name)
log.status.Print(
'Asynchronous operation is in progress... '
'Use the following command to wait for its '
f'completion:\n {cmd}'
)
return
op = services_util.WaitOperation(op.name, serviceusage.GetOperationV2Beta)
if op.error:
services_util.PrintOperation(op)
else:
log.status.Print(
f'The MCP endpoint for service {args.service} has been disabled for'
f' the resource {resource_name}.'
)

View File

@@ -0,0 +1,180 @@
# -*- 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.
"""services mcp enable command."""
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
from googlecloudsdk.core.console import console_io
_OP_BASE_CMD = 'gcloud beta services operations '
_OP_WAIT_CMD = _OP_BASE_CMD + 'wait {0}'
_SERVICE = 'services/%s'
_PROJECT_RESOURCE = 'projects/{}'
_FOLDER_RESOURCE = 'folders/{}'
_ORGANIZATION_RESOURCE = 'organizations/{}'
_CONSUMER_POLICY_DEFAULT = '/consumerPolicies/{}'
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Enable(base.SilentCommand):
"""Enable a service for MCP on a project, folder or organization.
Enable a service for MCP on a project, folder or organization
## EXAMPLES
To enable a service for MCP called `my-service` on the current project, run:
$ {command} my-service
To enable a service for MCP called `my-service` on the project
`my-project`, run:
$ {command} my-service --project=my-project
To enable a service for MCP called `my-service` on the folder
`my-folder, run:
$ {command} my-service --folder=my-folder
To enable a service for MCP called `my-service` on the organization
`my-organization`, run:
$ {command} my-service --organization=my-organization
To run the same command asynchronously (non-blocking), run:
$ {command} my-service --async
"""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
common_flags.service_flag(suffix='to enable MCP').AddToParser(parser)
common_flags.add_resource_args(parser)
common_flags.skip_mcp_endpoint_check_flag(parser)
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""Run 'services mcp enable'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
Updated MCP Policy.
"""
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE.format(project)
if args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE.format(args.project)
project = args.project
if args.IsSpecified('folder'):
resource_name = _FOLDER_RESOURCE.format(args.folder)
folder = args.folder
else:
folder = None
if args.IsSpecified('organization'):
resource_name = _ORGANIZATION_RESOURCE.format(args.organization)
organization = args.organization
else:
organization = None
# check if sevice has Mcp Config
service_metadata = serviceusage.GetServiceV2Beta(
f'{resource_name}/services/{args.service}'
)
if not args.skip_mcp_endpoint_check and (
not service_metadata.service.mcpServer
or not service_metadata.service.mcpServer.urls
):
log.error(
f'The service {args.service} does not have MCP endpoint.'
)
return
if not service_metadata.state.enableRules:
enable_msg = serviceusage.GetMcpEnabledError(resource_name)
do_enable = console_io.PromptContinue(
enable_msg,
default=False,
throw_if_unattended=True,
)
if do_enable:
enable_service_op, _ = serviceusage.AddEnableRule(
[args.service],
project,
folder=folder,
organization=organization,
)
# The operation should not be None when enable rules are empty,
# but in case it is, we check it here to avoid error.
if enable_service_op:
enable_service_op = services_util.WaitOperation(
enable_service_op.name, serviceusage.GetOperationV2Beta
)
if enable_service_op.error:
log.error(
f'Failed to enable the service {args.service} for the resource'
f' {resource_name}: {enable_service_op.error}'
)
return
else:
return
op = serviceusage.AddMcpEnableRule(
args.service,
project,
folder=folder,
organization=organization,
)
if op is None:
return None
if args.async_:
cmd = _OP_WAIT_CMD.format(op.name)
log.status.Print(
'Asynchronous operation is in progress... '
'Use the following command to wait for its '
f'completion:\n {cmd}'
)
return
op = services_util.WaitOperation(op.name, serviceusage.GetOperationV2Beta)
if op.error:
services_util.PrintOperation(op)
else:
log.status.Print(
f'The MCP endpoint for service {args.service} has been enabled for'
f' the resource {resource_name}.'
)

View File

@@ -0,0 +1,127 @@
# -*- 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.
"""services mcp list command."""
import sys
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class List(base.ListCommand):
"""List MCP services for a project, folder or organization.
This command lists the MCP services that are enabled or available (with MCP
endpoints) to be MCP enabled
by a project, folder or organization.
## EXAMPLES
To list the services the current project has enabled for MCP, run:
$ {command} --enabled
To list the services the current project can enable for MCP, run:
$ {command} --available
"""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
mode_group = parser.add_mutually_exclusive_group(required=False)
mode_group.add_argument(
'--enabled',
action='store_true',
help=(
'(DEFAULT) Return the MCP services which the project, folder or'
' organization has enabled.'
),
)
mode_group.add_argument(
'--available',
action='store_true',
help=(
'Return the services available to the '
'project, folder or organization to enable for MCP.'
),
)
common_flags.add_resource_args(parser)
base.PAGE_SIZE_FLAG.SetDefault(parser, 1000)
# Remove unneeded list-related flags from parser
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat("""
table(
name:label=NAME:sort=1,
mcp_endpoint:label=MCP_ENDPOINT
)
""")
def Run(self, args):
"""Run 'services mcp list'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
The list of MCP services for the given project, folder or organization.
"""
# Default mode is --enabled, so if no flags were specified,
# turn on the args.enabled flag.
if not (args.enabled or args.available):
args.enabled = True
if args.IsSpecified('project'):
project = args.project
else:
project = services_util.GetValidatedProject(args.project)
if args.IsSpecified('folder'):
folder = args.folder
else:
folder = None
if args.IsSpecified('organization'):
organization = args.organization
else:
organization = None
if args.IsSpecified('limit'):
limit = args.limit
else:
limit = sys.maxsize
return serviceusage.ListMcpServicesV2Beta(
project,
args.enabled,
args.page_size,
limit=limit,
folder=folder,
organization=organization,
)

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""Package for the MCP policies CLI subcommands."""
from googlecloudsdk.calliope import base
# TODO(b/321801975) make command public after suv2 launch.
@base.UniverseCompatible
@base.Hidden
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Policies(base.Group):
"""Get/update MCP policies and get the effective MCP policy."""

View File

@@ -0,0 +1,179 @@
# -*- 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.
"""services mcp policies get command."""
import json
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
from googlecloudsdk.core import yaml
from googlecloudsdk.core.util import files
_PROJECT_RESOURCE = 'projects/{}'
_FOLDER_RESOURCE = 'folders/{}'
_ORGANIZATION_RESOURCE = 'organizations/{}'
_MCP_POLICY_DEFAULT = '/mcpPolicies/{}'
_INVALID_TIMESTAMP = (
# Invalid timestamp as the consumer policy is not created previously.
'1970-01-01T00:00:00Z'
)
# TODO(b/321801975) make command public after suv2 launch.
@base.UniverseCompatible
@base.Hidden
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Get(base.Command):
"""Get MCP policy for a project, folder or organization.
Get MCP policy for a project, folder or
organization.
## EXAMPLES
Get MCP policy for default policy on current project:
$ {command}
OR
$ {command} --policy-name=default
Get MCP policy for default policy on current project and save the
content in an output file:
$ {command} --output-file=/path/to/the/file.yaml
OR
$ {command} --output-file=/path/to/the/file.json
"""
@staticmethod
def Args(parser):
parser.add_argument(
'--policy-name',
help='Name of the MCP policy. Currently only "default" is supported.',
default='default',
)
common_flags.add_resource_args(parser)
parser.add_argument(
'--output-file',
help=(
'Path to the file to write policy contents to. Supported format:'
'.yaml or .json.'
),
)
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Resource name and its parent name.
"""
if args.IsSpecified('folder'):
resource_name = _FOLDER_RESOURCE.format(args.folder)
elif args.IsSpecified('organization'):
resource_name = _ORGANIZATION_RESOURCE.format(args.organization)
elif args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE.format(args.project)
else:
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE.format(project)
policy = serviceusage.GetMcpPolicy(
resource_name + _MCP_POLICY_DEFAULT.format(args.policy_name),
)
if args.IsSpecified('output_file'):
if not (
args.output_file.endswith('.json')
or args.output_file.endswith('.yaml')
):
log.error(
'Invalid output-file format. Please provide path to a yaml or json'
' file.'
)
else:
if args.output_file.endswith('.json'):
data = json.dumps(_ConvertToDict(policy), sort_keys=False)
else:
data = yaml.dump(_ConvertToDict(policy), round_trip=True)
files.WriteFileContents(args.output_file, data)
log.status.Print(
'Policy written to the output file %s ' % args.output_file
)
elif args.IsSpecified('format'):
return policy
else:
result = _ConvertToDict(policy)
for k, v in result.items():
if k not in ['mcpEnableRules'] and v:
log.status.Print(k + ': ' + v)
elif k == 'mcpEnableRules':
log.status.Print(k + ':')
for enable_rule in v:
_PrintRules(enable_rule)
return
def _ConvertToDict(policy):
"""ConvertToDict command.
Args:
policy: mcpPolicy to be convert to orderedDict.
Returns:
orderedDict.
"""
output = {
'name': policy.name,
'mcpEnableRules': [],
'updateTime': policy.updateTime,
'createTime': policy.createTime,
'etag': policy.etag,
}
for enable_rule in policy.mcpEnableRules:
if enable_rule.mcpServices:
output['mcpEnableRules'].append(
{'mcpservices': list(enable_rule.mcpServices)}
)
if not policy.mcpEnableRules:
del output['mcpEnableRules']
if policy.updateTime == _INVALID_TIMESTAMP:
del output['updateTime']
if policy.createTime == _INVALID_TIMESTAMP:
del output['createTime']
return output
def _PrintRules(rule):
keys = ['mcpServices']
for key in keys:
if key in rule.keys():
log.status.Print(' ' + key + ':')
for mcpservices in rule[key]:
for services in mcpservices:
log.status.Print(' - ' + services)

View File

@@ -0,0 +1,117 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
# TODO: b/300099033 - Capitalize and turn into a sentence.
"""services MCP policies get-effective-policy command."""
import collections
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
_PROJECT_RESOURCE = 'projects/{}'
_FOLDER_RESOURCE = 'folders/{}'
_ORGANIZATION_RESOURCE = 'organizations/{}'
# TODO: b/321801975 - Make command public after suv2 launch.
@base.UniverseCompatible
@base.Hidden
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class GetEffectivePolicy(base.Command):
"""Get effective MCP policy for a project, folder or organization.
Get effective MCP policy for a project, folder or organization.
## EXAMPLES
Get effective MCP policy for the current project:
$ {command}
Get effective MCP policy for project `my-project`:
$ {command} --project=my-project
"""
@staticmethod
def Args(parser):
parser.add_argument(
'--view',
help=(
'The view of the effective MCP policy. BASIC includes basic'
' metadata about the effective MCP policy. FULL includes every'
' information related to effective MCP policy.'
),
choices=['BASIC', 'FULL'],
default='BASIC',
)
common_flags.add_resource_args(parser)
parser.display_info.AddFormat("""
table(
EnabledMcpService:label=EnabledMcpService:sort=1,
EnabledMcpPolicies:label=EnabledMcpPolicies
)
""")
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Effective Policy.
"""
if args.IsSpecified('folder'):
resource_name = _FOLDER_RESOURCE.format(args.folder)
elif args.IsSpecified('organization'):
resource_name = _ORGANIZATION_RESOURCE.format(args.organization)
elif args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE.format(args.project)
else:
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE.format(project)
response = serviceusage.GetEffectiveMcpPolicy(
resource_name + '/effectiveMcpPolicy', args.view
)
if args.IsSpecified('format'):
return response
else:
log.status.Print('McpEnableRules:')
for enable_rule in response.mcpEnableRules:
log.status.Print(' McpServices:')
for mcp_service in enable_rule.mcpServices:
log.status.Print(' - %s' % mcp_service.service)
if args.view == 'FULL':
log.status.Print('\nMetadata of effective policy:')
result = []
resources = collections.namedtuple(
'serviceMcpSources', ['EnabledMcpService', 'EnabledMcpPolicies']
)
for metadata in response.mcpEnableRuleMetadata:
for values in metadata.serviceMcpSources.additionalProperties:
result.append(resources(values.key, values.value.policies))
return result

View File

@@ -0,0 +1,92 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""services mcp policies test-enabled command."""
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import properties
_PROJECT_RESOURCE = 'projects/%s'
_FOLDER_RESOURCE = 'folders/%s'
_ORGANIZATION_RESOURCE = 'organizations/%s'
_SERVICE = 'services/%s'
# TODO(b/321801975) make command public after suv2 launch.
@base.UniverseCompatible
@base.Hidden
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class TestEnabled(base.Command):
"""Test a service against the result of merging MCP policies in the resource hierarchy.
Test a service against the result of merging MCP policies in the resource
hierarchy.
## EXAMPLES
Test for service my-service for current project:
$ {command} my-service
Test for service my-service for project `my-project`:
$ {command} my-service --project=my-project
"""
@staticmethod
def Args(parser):
common_flags.add_resource_args(parser)
parser.add_argument(
'service', help='Name of the service. example: foobar.googleapis.com'
)
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The enablement of the given service.
"""
resource = 'project'
if args.IsSpecified('folder'):
resource_name = _FOLDER_RESOURCE % args.folder
resource = 'folder'
elif args.IsSpecified('organization'):
resource_name = _ORGANIZATION_RESOURCE % args.organization
resource = 'organization'
elif args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE % args.project
else:
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE % project
response = serviceusage.TestMcpEnabled(
resource_name, _SERVICE % args.service
)
# If mcpEnableRules is empty that means service is not enabled.
if response.mcpEnableRules:
return (
f'MCP is ENABLED for Service {args.service} for the'
f' {resource} {resource_name}.'
)
else:
return (
f'MCP is NOT ENABLED for Service {args.service} for the'
f' {resource} {resource_name}.'
)

View File

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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.
"""Package for the services/operations CLI subcommands."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
class Operations(base.Group):
"""Manage Operation for various services."""

View File

@@ -0,0 +1,87 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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.
"""services operations describe command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import apikeys
from googlecloudsdk.api_lib.services import scm
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import actions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
MAX_RESPONSE_BYTES = 1000
# Define GetOperation function mapping. Default is serviceusage.GetOperation.
_GET_OP_FUNC_MAP = {
'akmf': apikeys.GetOperation,
'acf': scm.GetOperation,
}
class Describe(base.DescribeCommand):
"""Describes an operation resource for a given operation name.
This command will return information about an operation given the name
of that operation.
## EXAMPLES
To describe an operation resource named
`operations/abc`, run:
$ {command} operations/abc
"""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go
on the command line after this command. Positional arguments are
allowed.
"""
common_flags.operation_flag(suffix='to describe').AddToParser(parser)
parser.display_info.AddFormat(
':(metadata.startTime.date(format="%Y-%m-%d %H:%M:%S %Z", tz=LOCAL)) '
'[transforms] default')
action = actions.DeprecationAction('full', warn='This flag is deprecated.')
parser.add_argument(
'--full',
action=action,
default=False,
help=('This flag is deprecated.'))
def Run(self, args):
"""Run 'services operations describe'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
The response from the operations.Get API call.
"""
namespace = common_flags.get_operation_namespace(args.operation)
get_op_func = _GET_OP_FUNC_MAP.get(namespace, serviceusage.GetOperation)
op = get_op_func(args.operation)
services_util.PrintOperationWithResponse(op)

View File

@@ -0,0 +1,72 @@
# -*- coding: utf-8 -*- #
# Copyright 2017 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.
"""service operations wait command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import apikeys
from googlecloudsdk.api_lib.services import scm
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
_GET_OP_FUNC_MAP = {
'akmf': apikeys.GetOperation,
'acf': scm.GetOperation,
}
class WaitAlpha(base.Command):
"""Waits for an operation to complete for a given operation name.
This command will block until an operation has been marked as complete.
## EXAMPLES
To wait on an operation named `operations/abc`
to complete, run:
$ {command} operations/abc
"""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go
on the command line after this command. Positional arguments are
allowed.
"""
common_flags.operation_flag(suffix='on which to wait').AddToParser(parser)
def Run(self, args):
"""Run 'services operations wait'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
If successful, the response from the operations.Get API call.
"""
namespace = common_flags.get_operation_namespace(args.operation)
get_op_func = _GET_OP_FUNC_MAP.get(namespace, serviceusage.GetOperation)
op = services_util.WaitOperation(args.operation, get_op_func)
services_util.PrintOperationWithResponse(op)

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 Google LLC. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""The command group for services peered DNS domains."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
class PeeredDnsDomains(base.Group):
"""Peered DNS domains for various private service connections."""

View File

@@ -0,0 +1,121 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""services peered-dns-domains create command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudresourcemanager import projects_api
from googlecloudsdk.api_lib.services import peering
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.projects import util as projects_util
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
_OP_BASE_CMD = 'gcloud services vpc-peerings operations '
_OP_WAIT_CMD = _OP_BASE_CMD + 'wait {0}'
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA,
base.ReleaseTrack.BETA,
base.ReleaseTrack.GA,
)
class Create(base.SilentCommand):
"""Create a peered DNS domain for a private service connection."""
detailed_help = {
'DESCRIPTION':
"""\
This command creates a peered DNS domain for a private service
connection which sends requests for records in a given namespace
originating in the service producer VPC network to the consumer
VPC network to be resolved.
""",
'EXAMPLES':
"""\
To create a peered DNS domain called `example-com` which forwards DNS
requests for the domain suffix `example.com.` for a private service
connection between service `peering-service` and the consumer network
`my-network` in the current project, run:
$ {command} example-com --network=my-network \\
--service=peering-service --dns-suffix=example.com.
To run the same command asynchronously (non-blocking), run:
$ {command} example-com --network=my-network \\
--service=peering-service --dns-suffix=example.com. \\
--async
""",
}
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
parser.add_argument(
'name', help='The name of the peered DNS domain to create.')
parser.add_argument(
'--network',
metavar='NETWORK',
required=True,
help='The network in the consumer project peered with the service.')
parser.add_argument(
'--service',
metavar='SERVICE',
default='servicenetworking.googleapis.com',
help='The name of the service to create a peered DNS domain for.')
parser.add_argument(
'--dns-suffix',
metavar='DNS_SUFFIX',
required=True,
help='The DNS domain name suffix of the peered DNS domain.')
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""Run 'services peered-dns-domains create'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
"""
project = properties.VALUES.core.project.Get(required=True)
project_number = _GetProjectNumber(project)
op = peering.CreatePeeredDnsDomain(
project_number,
args.service,
args.network,
args.name,
args.dns_suffix,
)
if args.async_:
cmd = _OP_WAIT_CMD.format(op.name)
log.status.Print('Asynchronous operation is in progress... '
'Use the following command to wait for its '
'completion:\n {0}'.format(cmd))
return
op = services_util.WaitOperation(op.name, peering.GetOperation)
services_util.PrintOperation(op)
def _GetProjectNumber(project_id):
return projects_api.Get(projects_util.ParseProject(project_id)).projectNumber

View File

@@ -0,0 +1,111 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""services peered-dns-domains delete command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudresourcemanager import projects_api
from googlecloudsdk.api_lib.services import peering
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.projects import util as projects_util
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
_OP_BASE_CMD = 'gcloud services vpc-peerings operations '
_OP_WAIT_CMD = _OP_BASE_CMD + 'wait {0}'
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA,
base.ReleaseTrack.BETA,
base.ReleaseTrack.GA,
)
class Delete(base.SilentCommand):
"""Delete a peered DNS domain for a private service connection."""
detailed_help = {
'DESCRIPTION':
"""\
This command deletes a peered DNS domain from a private service
connection.
""",
'EXAMPLES':
"""\
To delete a peered DNS domain called `example-com` from a private
service connection between service `peering-service` and the consumer
network `my-network` in the current project, run:
$ {command} example-com --network=my-network \\
--service=peering-service
To run the same command asynchronously (non-blocking), run:
$ {command} example-com --network=my-network \\
--service=peering-service --async
""",
}
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
parser.add_argument(
'name', help='The name of the peered DNS domain to delete.')
parser.add_argument(
'--network',
metavar='NETWORK',
required=True,
help='The network in the consumer project peered with the service.')
parser.add_argument(
'--service',
metavar='SERVICE',
default='servicenetworking.googleapis.com',
help='The name of the service to delete a peered DNS domain for.')
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""Run 'services peered-dns-domains delete'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
"""
project = properties.VALUES.core.project.Get(required=True)
project_number = _GetProjectNumber(project)
op = peering.DeletePeeredDnsDomain(
project_number,
args.service,
args.network,
args.name,
)
if args.async_:
cmd = _OP_WAIT_CMD.format(op.name)
log.status.Print('Asynchronous operation is in progress... '
'Use the following command to wait for its '
'completion:\n {0}'.format(cmd))
return
op = services_util.WaitOperation(op.name, peering.GetOperation)
services_util.PrintOperation(op)
def _GetProjectNumber(project_id):
return projects_api.Get(projects_util.ParseProject(project_id)).projectNumber

View File

@@ -0,0 +1,98 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""services peered-dns-domains delete command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudresourcemanager import projects_api
from googlecloudsdk.api_lib.services import peering
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.projects import util as projects_util
from googlecloudsdk.core import properties
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA,
base.ReleaseTrack.BETA,
base.ReleaseTrack.GA,
)
class List(base.DescribeCommand):
"""List the peered DNS domains for a private service connection."""
detailed_help = {
'DESCRIPTION':
"""\
This command lists the peered DNS domains for a private service
connection.
""",
'EXAMPLES':
"""\
To list the peered DNS domains for a private service connection
between service ``peering-service'' and the consumer network
``my-network'' in the current project, run:
$ {command} --network=my-network --service=peering-service
""",
}
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
parser.add_argument(
'--network',
metavar='NETWORK',
required=True,
help='Network in the consumer project peered with the service.')
parser.add_argument(
'--service',
metavar='SERVICE',
default='servicenetworking.googleapis.com',
help='Name of the service to list the peered DNS domains for.')
parser.display_info.AddFormat("""
table(
name:sort=1,
dnsSuffix
)
""")
def Run(self, args):
"""Run 'services peered-dns-domains list'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
The list of peered DNS domains.
"""
project = properties.VALUES.core.project.Get(required=True)
project_number = _GetProjectNumber(project)
domains = peering.ListPeeredDnsDomains(
project_number,
args.service,
args.network,
)
return domains
def _GetProjectNumber(project_id):
return projects_api.Get(projects_util.ParseProject(project_id)).projectNumber

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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.
"""Package for the policies CLI subcommands."""
from googlecloudsdk.calliope import base
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Policies(base.Group):
"""Get/update consumer policies and get the effective policy."""

View File

@@ -0,0 +1,177 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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.
"""services policies get command."""
import json
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
from googlecloudsdk.core import yaml
from googlecloudsdk.core.util import files
_PROJECT_RESOURCE = 'projects/{}'
_FOLDER_RESOURCE = 'folders/{}'
_ORGANIZATION_RESOURCE = 'organizations/{}'
_CONSUMER_POLICY_DEFAULT = '/consumerPolicies/{}'
_INVALID_TIMESTAMP = (
# Invalid timestamp as the consumer policy is not created previously.
'1970-01-01T00:00:00Z'
)
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Get(base.Command):
"""Get consumer policy for a project, folder or organization.
Get consumer policy for a project, folder or
organization.
## EXAMPLES
Get consumer policy for default policy on current project:
$ {command}
OR
$ {command} --policy-name=default
Get consumer policy for default policy on current project and save the
content in an output file:
$ {command} --output-file=/path/to/the/file.yaml
OR
$ {command} --output-file=/path/to/the/file.json
"""
@staticmethod
def Args(parser):
parser.add_argument(
'--policy-name',
help=(
'Name of the consumer policy. Currently only "default" is'
' supported.'
),
default='default',
)
common_flags.add_resource_args(parser)
parser.add_argument(
'--output-file',
help=(
'Path to the file to write policy contents to. Supported format:'
'.yaml or .json.'
),
)
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Resource name and its parent name.
"""
if args.IsSpecified('folder'):
resource_name = _FOLDER_RESOURCE.format(args.folder)
elif args.IsSpecified('organization'):
resource_name = _ORGANIZATION_RESOURCE.format(args.organization)
elif args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE.format(args.project)
else:
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE.format(project)
policy = serviceusage.GetConsumerPolicyV2Beta(
resource_name + _CONSUMER_POLICY_DEFAULT.format(args.policy_name),
)
if args.IsSpecified('output_file'):
if not (
args.output_file.endswith('.json')
or args.output_file.endswith('.yaml')
):
log.error(
'Invalid output-file format. Please provide path to a yaml or json'
' file.'
)
else:
if args.output_file.endswith('.json'):
data = json.dumps(_ConvertToDict(policy), sort_keys=False)
else:
data = yaml.dump(_ConvertToDict(policy), round_trip=True)
files.WriteFileContents(args.output_file, data)
log.status.Print(
'Policy written to the output file %s ' % args.output_file
)
elif args.IsSpecified('format'):
return policy
else:
result = _ConvertToDict(policy)
for k, v in result.items():
if k != 'enableRules' and v:
log.status.Print(k + ': ' + v)
elif k == 'enableRules':
log.status.Print(k + ':')
for enable_rule in v:
_PrintRules(enable_rule)
return
def _ConvertToDict(policy):
"""ConvertToDict command.
Args:
policy: consumerPolicy to be convert to orderedDict.
Returns:
orderedDict.
"""
output = {
'name': policy.name,
'enableRules': [],
'updateTime': policy.updateTime,
'createTime': policy.createTime,
'etag': policy.etag,
}
for enable_rule in policy.enableRules:
if enable_rule.services:
output['enableRules'].append({'services': list(enable_rule.services)})
if not policy.enableRules:
del output['enableRules']
if policy.updateTime == _INVALID_TIMESTAMP:
del output['updateTime']
if policy.createTime == _INVALID_TIMESTAMP:
del output['createTime']
return output
def _PrintRules(rule):
keys = ['services']
for key in keys:
if key in rule.keys():
log.status.Print(' ' + key + ':')
for value in rule[key]:
log.status.Print(' - ' + value)

View File

@@ -0,0 +1,115 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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.
# TODO: b/300099033 - Capitalize and turn into a sentence.
"""services policies get-effective-policy command."""
import collections
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
_PROJECT_RESOURCE = 'projects/{}'
_FOLDER_RESOURCE = 'folders/{}'
_ORGANIZATION_RESOURCE = 'organizations/{}'
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class GetEffectivePolicy(base.Command):
"""Get effective policy for a project, folder or organization.
Get effective policy for a project, folder or organization.
## EXAMPLES
Get effective policy for the current project:
$ {command}
Get effective policy for project `my-project`:
$ {command} --project=my-project
"""
@staticmethod
def Args(parser):
parser.add_argument(
'--view',
help=(
'The view of the effective policy. BASIC includes basic metadata'
' about the effective policy. FULL includes every information'
' related to effective policy.'
),
default='BASIC',
choices=['BASIC', 'FULL'],
)
common_flags.add_resource_args(parser)
parser.display_info.AddFormat("""
table(
EnabledService:label=EnabledService:sort=1,
EnabledPolicies:label=EnabledPolicies
)
""")
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Effective Policy.
"""
if args.IsSpecified('folder'):
resource_name = _FOLDER_RESOURCE.format(args.folder)
elif args.IsSpecified('organization'):
resource_name = _ORGANIZATION_RESOURCE.format(args.organization)
elif args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE.format(args.project)
else:
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE.format(project)
response = serviceusage.GetEffectivePolicyV2Beta(
resource_name + '/effectivePolicy', args.view
)
if args.IsSpecified('format'):
return response
else:
log.status.Print('EnabledRules:')
for enable_rule in response.enableRules:
log.status.Print(' Services:')
for service in enable_rule.services:
log.status.Print(' - %s' % service)
if args.view == 'FULL':
log.status.Print('\nMetadata of effective policy:')
result = []
resources = collections.namedtuple(
'serviceSources', ['EnabledService', 'EnabledPolicies']
)
for metadata in response.enableRuleMetadata:
for values in metadata.serviceSources.additionalProperties:
result.append(resources(values.key, values.value.policies))
return result

View File

@@ -0,0 +1,79 @@
# -*- coding: utf-8 -*- #
# Copyright 2023 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.
"""services policies test-enabled command."""
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import properties
_PROJECT_RESOURCE = 'projects/%s'
_FOLDER_RESOURCE = 'folders/%s'
_ORGANIZATION_RESOURCE = 'organizations/%s'
_SERVICE = 'services/%s'
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class TestEnabled(base.Command):
"""Test a value against the result of merging consumer policies in the resource hierarchy.
Test a value against the result of merging consumer policies in the resource
hierarchy.
## EXAMPLES
Test for service my-service for current project:
$ {command} my-service
Test for service my-service for project `my-project`:
$ {command} my-service --project=my-project
"""
@staticmethod
def Args(parser):
common_flags.add_resource_args(parser)
parser.add_argument('service', help='Name of the service.')
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
The enablement of the given service.
"""
if args.IsSpecified('folder'):
resource_name = _FOLDER_RESOURCE % args.folder
elif args.IsSpecified('organization'):
resource_name = _ORGANIZATION_RESOURCE % args.organization
elif args.IsSpecified('project'):
resource_name = _PROJECT_RESOURCE % args.project
else:
project = properties.VALUES.core.project.Get(required=True)
resource_name = _PROJECT_RESOURCE % project
response = serviceusage.TestEnabled(resource_name, _SERVICE % args.service)
# If enableRules is empty that means service is not enabled.
if response.enableRules:
return f'Service {args.service} is ENABLED for resource {resource_name}.'
else:
return (
f'Service {args.service} is NOT ENABLED for resource {resource_name}.'
)

View File

@@ -0,0 +1,108 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 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.
"""services policies update command."""
from googlecloudsdk.api_lib.services import exceptions
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.services import common_flags
from googlecloudsdk.core import log
from googlecloudsdk.core import yaml
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA)
class Update(base.Command):
"""Update consumer policy for a project, folder or organization.
Update consumer policy for a project, folder or organization.
## EXAMPLES
Update consumer policy
$ {command} --consumer-policy-file=/path/to/the/file.yaml
Validate the update action on the policy:
$ {command} --consumer-policy-file=/path/to/the/file.yaml --validate-only
Update consumer policy and bypass dependency check:
$ {command} --consumer-policy-file=/path/to/the/file.yaml
--bypass-dependency-check
Update consumer policy and bypass api usage check:
$ {command} --consumer-policy-file=/path/to/the/file.yaml
--bypass-api-usage-check
"""
@staticmethod
def Args(parser):
common_flags.consumer_policy_file_flag().AddToParser(parser)
common_flags.validate_only_args(parser, suffix='to update')
common_flags.bypass_api_usage_check().AddToParser(parser)
common_flags.bypass_dependency_check().AddToParser(parser)
def Run(self, args):
"""Run command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Response from longrunning.operations from UpdateConsumerPolicy API call.
"""
if not args.consumer_policy_file.endswith('.yaml'):
raise exceptions.ConfigError(
'Invalid consumer_policy_file format. Please provide path to a yaml'
' file.'
)
policy = yaml.load_path(args.consumer_policy_file)
if not isinstance(policy, dict):
raise exceptions.ConfigError(
'Invalid consumer-policy-file. Please provide a valid policy.'
)
if 'name' not in policy:
raise exceptions.ConfigError(
'Invalid Consumer Policy. Please provide a name.'
)
op = serviceusage.UpdateConsumerPolicy(
policy,
validate_only=args.validate_only,
bypass_dependency_check=args.bypass_dependency_check,
force=args.bypass_api_usage_check,
)
# If there is no change in the consumer policy after applying the changes,
# the operation name is empty.
# temporary fix till the backend returns name for no-op operations.
if op.done and not op.name:
log.warning('No change required for the current consumer policy.')
return None
op = services_util.WaitOperation(op.name, serviceusage.GetOperationV2Beta)
if args.validate_only:
services_util.PrintOperation(op)
else:
services_util.PrintOperationWithResponseForUpdateConsumerPolicy(op)

View File

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""Package for the endpoints/quota CLI subcommands."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class Quota(base.Group):
"""Manage service consumer quota."""

View File

@@ -0,0 +1,117 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""create command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
class Create(base.SilentCommand):
"""Create a quota override for a consumer.
This command creates a quota override for a consumer. The supported
consumers are projects, folders, and organizations.
## EXAMPLES
To create a quota override for a project with project number, run:
$ {command} --service=example.googleapis.com --consumer=projects/12321
--metric=example.googleapis.com/default_requests
--unit=1/min/{project} --value=360
To create a quota override for a project with project ID, run:
$ {command} --service=example.googleapis.com --consumer=projects/hello
--metric=example.googleapis.com/default_requests
--unit=1/min/{project} --value=360
To create a quota override for an organization, run:
$ {command} --service=example.googleapis.com --consumer=organizations/555
--metric=example.googleapis.com/default_requests
--unit=1/min/{project} --value=360
To force the creation of a quota override with dimensions, run:
$ {command} --service=example.googleapis.com --consumer=projects/12321
--metric=example.googleapis.com/default_requests
--unit=1/min/{project} --dimensions=regions=us-central1
--dimensions=zones=us-central1-c --value=360 --force
"""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
parser.add_argument(
'--service',
required=True,
help='The service to create a quota override for.')
parser.add_argument(
'--consumer',
required=True,
help='The consumer to create a quota override for.')
parser.add_argument(
'--metric',
required=True,
help='The metric to create a quota override for.')
parser.add_argument(
'--unit',
required=True,
help='The unit of a metric to create a quota override for.')
parser.add_argument(
'--dimensions',
type=arg_parsers.ArgDict(),
metavar='KEY=VALUE',
action=arg_parsers.UpdateAction,
help='The dimensions of the override, e.g. for specific locations.')
parser.add_argument(
'--value', type=int, required=True, help='The value of the override.')
parser.add_argument(
'--force',
action='store_true',
default=False,
help='Force override creation even if the change results in a '
'substantial decrease in available quota.')
def Run(self, args):
"""Run 'endpoints quota create'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
Nothing.
"""
op = serviceusage.UpdateQuotaOverrideCall(args.consumer, args.service,
args.metric, args.unit,
args.dimensions, args.value,
args.force)
if op.done:
return
op = services_util.WaitOperation(op.name, serviceusage.GetOperation)
services_util.PrintOperation(op)

View File

@@ -0,0 +1,111 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""delete command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
class Delete(base.SilentCommand):
"""Delete a quota override for a consumer.
This command deletes a quota override for a consumer. The supported consumers
are projects, folders, and organizations. The override ID can be found from
list command output.
## EXAMPLES
To delete a quota override for a project with project number, run:
$ {command} --service=example.googleapis.com --consumer=projects/12321
--metric=example.googleapis.com/default_requests
--unit=1/min/{project}
To delete a quota override for a project with project ID, run:
$ {command} --service=example.googleapis.com --consumer=projects/hello
--metric=example.googleapis.com/default_requests
--unit=1/min/{project}
To delete a quota override for an organization, run:
$ {command} --service=example.googleapis.com --consumer=organizations/555
--metric=example.googleapis.com/default_requests
--unit=1/min/{project}
To force the deletion of a quota override, run:
$ {command} --service=example.googleapis.com --consumer=projects/12321
--metric=example.googleapis.com/default_requests
--unit=1/min/{project} --force
"""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
parser.add_argument(
'--service',
required=True,
help='The service to delete a quota override for.')
parser.add_argument(
'--consumer',
required=True,
help='The consumer to delete a quota override for.')
parser.add_argument(
'--metric',
required=True,
help='The metric to delete a quota override for.')
parser.add_argument(
'--unit',
required=True,
help='The unit of a metric to delete a quota override for.')
parser.add_argument(
'--override-id',
required=True,
help='The override ID of the override previous created.')
parser.add_argument(
'--force',
action='store_true',
default=False,
help='Force override deletion even if the change results in a '
'substantial decrease in available quota.')
def Run(self, args):
"""Run 'endpoints quota delete'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
Nothing.
"""
op = serviceusage.DeleteQuotaOverrideCall(args.consumer, args.service,
args.metric, args.unit,
args.override_id, args.force)
if op.done:
return
op = services_util.WaitOperation(op.name, serviceusage.GetOperation)
services_util.PrintOperation(op)

View File

@@ -0,0 +1,101 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""services list command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import base
class List(base.ListCommand):
"""List service quota metrics for a consumer.
This command lists the service quota metrics for a consumer. The supported
consumers can be projects, folders, or organizations.
## EXAMPLES
To list the quota metrics for service 'example.googleapis.com' and consumer
'projects/12321', run:
$ {command} --service=example.googleapis.com --consumer=projects/12321
To list the quota metrics for service 'example.googleapis.com' and consumer
'projects/hello-world', run:
$ {command} --service=example.googleapis.com --consumer=projects/helloworld
To list the quota metrics for service 'example.googleapis.com' and consumer
'folders/12345', run:
$ {command} --service=example.googleapis.com --consumer=folders/12345
To list the quota metrics for service 'example.googleapis.com' and consumer
'organizations/54321', run:
$ {command} --service=example.googleapis.com --consumer=organizations/54321
"""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
parser.add_argument(
'--service',
required=True,
metavar='SERVICE',
help='The service to list metrics for.')
parser.add_argument(
'--consumer',
required=True,
metavar='CONSUMER',
help='The consumer to list metrics for.')
def Run(self, args):
"""Run command.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
The list of quota metrics for the service and consumer.
"""
metrics = serviceusage.ListQuotaMetrics(args.consumer, args.service,
args.page_size, args.limit)
return [self.delete_resource_name(m) for m in metrics]
@staticmethod
def delete_resource_name(metric):
"""Delete the name fields from metric message.
Args:
metric: The quota metric message.
Returns:
The updated metric message.
"""
metric.reset('name')
for l in metric.consumerQuotaLimits:
l.reset('name')
return metric

View File

@@ -0,0 +1,119 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""update command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.api_lib.services import serviceusage
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
class Update(base.SilentCommand):
"""Update a quota override for a consumer.
This command updates a quota override for a consumer. The supported consumers
are projects, folders, and organizations. The override ID can be
found from list command output.
## EXAMPLES
To update a quota override for project with project number, run:
$ {command} --service=example.googleapis.com --consumer=projects/12321
--metric=example.googleapis.com/default_requests
--unit=1/min/{project} --value=360
To update a quota override for project with project ID, run:
$ {command} --service=example.googleapis.com --consumer=projects/hello
--metric=example.googleapis.com/default_requests
--unit=1/min/{project} --value=360
To update a quota override for an organization, run:
$ {command} --service=example.googleapis.com --consumer=organizations/555
--metric=example.googleapis.com/default_requests
--unit=1/min/{project} --value=360
To force the update of a quota override, run:
$ {command} --service=example.googleapis.com --consumer=projects/12321
--metric=example.googleapis.com/default_requests
--unit=1/min/{project}
--dimensions=regions=us-central1
--dimensions=zones=us-central1-c --value=360 --force
"""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
parser.add_argument(
'--service',
required=True,
help='The service to update a quota override for.')
parser.add_argument(
'--consumer',
required=True,
help='The consumer to update override for.')
parser.add_argument(
'--metric',
required=True,
help='The metric to update a quota override for.')
parser.add_argument(
'--unit',
required=True,
help='The unit of a metric to update a quota override for.')
parser.add_argument(
'--dimensions',
type=arg_parsers.ArgDict(),
metavar='KEY=VALUE',
action=arg_parsers.UpdateAction,
help='The dimensions of the override, e.g. for specific locations.')
parser.add_argument(
'--value', type=int, required=True, help='The value of the override.')
parser.add_argument(
'--force',
action='store_true',
default=False,
help='Force override update even if the change results in a '
'substantial decrease in available quota.')
def Run(self, args):
"""Run 'endpoints quota update'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
Nothing.
"""
op = serviceusage.UpdateQuotaOverrideCall(args.consumer, args.service,
args.metric, args.unit,
args.dimensions, args.value,
args.force)
if op.done:
return
op = services_util.WaitOperation(op.name, serviceusage.GetOperation)
services_util.PrintOperation(op)

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*- #
# Copyright 2018 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.
"""Package for the services/operations CLI subcommands."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
class VpcPeerings(base.Group):
"""VPC Peerings to various services."""

View File

@@ -0,0 +1,110 @@
# -*- coding: utf-8 -*- #
# Copyright 2018 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.
"""services vpc-peerings connect command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudresourcemanager import projects_api
from googlecloudsdk.api_lib.services import peering
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.projects import util as projects_util
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
OP_BASE_CMD = 'gcloud services vpc-peerings operations '
OP_WAIT_CMD = OP_BASE_CMD + 'wait {0}'
class Connect(base.SilentCommand):
"""Connect to a service via VPC peering for a project network."""
detailed_help = {
'DESCRIPTION':
"""\
This command connects a private service connection to a service via a
VPC network.
""",
'EXAMPLES':
"""\
To connect a network called `my-network` on the current project to a
service called `your-service` with IP CIDR ranges
`google-range-1,google-range-2` for the service to use, run:
$ {command} --network=my-network --service=your-service \\
--ranges=google-range-1,google-range-2
To run the same command asynchronously (non-blocking), run:
$ {command} --network=my-network --service=your-service \\
--ranges=google-range-1,google-range-2 --async
""",
}
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go
on the command line after this command. Positional arguments are
allowed.
"""
parser.add_argument(
'--network',
metavar='NETWORK',
required=True,
help='The network in the current project to be peered with the service')
parser.add_argument(
'--service',
metavar='SERVICE',
default='servicenetworking.googleapis.com',
help='The service to connect to')
parser.add_argument(
'--ranges',
metavar='RANGES',
required=True,
help='The names of IP CIDR ranges for service to use.')
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""Run 'services vpc-peerings connect'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
Nothing.
"""
project = properties.VALUES.core.project.Get(required=True)
project_number = _GetProjectNumber(project)
ranges = args.ranges.split(',')
op = peering.CreateConnection(project_number, args.service, args.network,
ranges)
if args.async_:
cmd = OP_WAIT_CMD.format(op.name)
log.status.Print('Asynchronous operation is in progress... '
'Use the following command to wait for its '
'completion:\n {0}'.format(cmd))
return
op = services_util.WaitOperation(op.name, peering.GetOperation)
services_util.PrintOperation(op)
def _GetProjectNumber(project_id):
return projects_api.Get(projects_util.ParseProject(project_id)).projectNumber

View File

@@ -0,0 +1,106 @@
# -*- 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.
"""services vpc-peerings delete command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudresourcemanager import projects_api
from googlecloudsdk.api_lib.services import peering
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.projects import util as projects_util
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
OP_BASE_CMD = 'gcloud services vpc-peerings operations '
OP_WAIT_CMD = OP_BASE_CMD + 'wait {0}'
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA,
base.ReleaseTrack.BETA,
base.ReleaseTrack.GA,
)
class Delete(base.SilentCommand):
"""Delete a private service connection to a service for a project network."""
detailed_help = {
'DESCRIPTION':
"""\
This command deletes a private service connection to a service via a
VPC network.
""",
'EXAMPLES':
"""\
To delete an existing connection for a network called `my-network` on
the current project to a service called `your-service` run:
$ {command} --network=my-network --service=your-service
To run the same command asynchronously (non-blocking), run:
$ {command} --network=my-network --service=your-service --async
""",
}
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
parser.add_argument(
'--network',
metavar='NETWORK',
required=True,
help='The network in the current project which is peered with the service'
)
parser.add_argument(
'--service',
metavar='SERVICE',
default='servicenetworking.googleapis.com',
help='The service to connect to')
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""Run 'services vpc-peerings delete'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
Nothing.
"""
project = properties.VALUES.core.project.Get(required=True)
project_number = _GetProjectNumber(project)
op = peering.DeleteConnection(project_number, args.service, args.network)
if args.async_:
cmd = OP_WAIT_CMD.format(op.name)
log.status.Print('Asynchronous operation is in progress... '
'Use the following command to wait for its '
'completion:\n {0}'.format(cmd))
return
op = services_util.WaitOperation(op.name, peering.GetOperation)
services_util.PrintOperation(op)
def _GetProjectNumber(project_id):
return projects_api.Get(projects_util.ParseProject(project_id)).projectNumber

View File

@@ -0,0 +1,109 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""services vpc-peerings disable-vpc-service-controls command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudresourcemanager import projects_api
from googlecloudsdk.api_lib.services import peering
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.projects import util as projects_util
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
OP_BASE_CMD = 'gcloud services vpc-peerings operations '
OP_WAIT_CMD = OP_BASE_CMD + 'wait {0}'
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA,
base.ReleaseTrack.BETA,
base.ReleaseTrack.GA,
)
class DisableVpcServiceControls(base.SilentCommand):
"""Disable VPC Service Controls for the peering connection."""
detailed_help = {
'DESCRIPTION':
"""\
This command disables VPC Service Controls for the peering connection.
The local default route (destination 0.0.0.0/0, next hop default
internet gateway) is recreated in the service producer VPC network.
After the route is recreated, the service producer VPC network cannot
import a custom default route from the peering connection to the
customer VPC network.
""",
'EXAMPLES':
"""\
To disable VPC Service Controls for a connection peering a network
called `my-network` on the current project to a service called
`your-service`, run:
$ {command} --network=my-network --service=your-service
To run the same command asynchronously (non-blocking), run:
$ {command} --network=my-network --service=your-service --async
""",
}
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that can be used to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
parser.add_argument(
'--network',
metavar='NETWORK',
required=True,
help='The network in the current project that is peered with the service.'
)
parser.add_argument(
'--service',
metavar='SERVICE',
default='servicenetworking.googleapis.com',
help='The service to enable VPC service controls for.')
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""Run 'services vpc-peerings enable-vpc-service-controls'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
"""
project = properties.VALUES.core.project.Get(required=True)
project_number = _GetProjectNumber(project)
op = peering.DisableVpcServiceControls(project_number, args.service,
args.network)
if args.async_:
cmd = OP_WAIT_CMD.format(op.name)
log.status.Print('Asynchronous operation is in progress... '
'Use the following command to wait for its '
'completion:\n {0}'.format(cmd))
return
op = services_util.WaitOperation(op.name, peering.GetOperation)
services_util.PrintOperation(op)
def _GetProjectNumber(project_id):
return projects_api.Get(projects_util.ParseProject(project_id)).projectNumber

View File

@@ -0,0 +1,131 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 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.
"""services vpc-peerings enable-vpc-service-controls command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudresourcemanager import projects_api
from googlecloudsdk.api_lib.services import peering
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.projects import util as projects_util
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
OP_BASE_CMD = 'gcloud services vpc-peerings operations '
OP_WAIT_CMD = OP_BASE_CMD + 'wait {0}'
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA,
base.ReleaseTrack.BETA,
base.ReleaseTrack.GA,
)
class EnableVpcServiceControls(base.SilentCommand):
"""Enable VPC Service Controls for the peering connection."""
detailed_help = {
'DESCRIPTION':
"""\
This command configures IPv4 routes and DNS zones applicable to a
service producer VPC network (for example, servicenetworking). The
route and DNS configuration match those recommended for using the
restricted.googleapis.com VIP:
When enabled, Google Cloud makes the following route configuration
changes in the service producer VPC network: Google Cloud removes the
IPv4 default route (destination 0.0.0.0/0, next hop default internet
gateway). Google Cloud then creates an IPv4 route for destination
199.36.153.4/30 using the default internet gateway next hop.
When enabled, Google Cloud also creates Cloud DNS managed private
zones and authorizes those zones for the service producer VPC network.
The zones include googleapis.com, pkg.dev, gcr.io, and other necessary
domains or host names for Google APIs and services that are compatible
with VPC Service Controls. Record data in the zones resolves all host
names to 199.36.153.4, 199.36.153.5, 199.36.153.6, and 199.36.153.7.
When disabled, Google Cloud makes the following route configuration
changes in the service producer VPC network: Google Cloud restores a
default route (destination 0.0.0.0/0, next hop default internet
gateway). Google Cloud also deletes the Cloud DNS managed private
zones that provided the host name overrides.
While enabled, the service producer VPC network can still import
static and dynamic routes from the peered customer network if you
enable custom route export. These custom routes can include a default
route. For this reason, this command is not to be used solely as a
means for preventing access to the internet.
""",
'EXAMPLES':
"""\
To enable VPC Service Controls for a connection peering a network
called `my-network` on the current project to a service called
`your-service`, run:
$ {command} --network=my-network --service=your-service
To run the same command asynchronously (non-blocking), run:
$ {command} --network=my-network --service=your-service --async
""",
}
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that can be used to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
parser.add_argument(
'--network',
metavar='NETWORK',
required=True,
help='The network in the current project that is peered with the service.'
)
parser.add_argument(
'--service',
metavar='SERVICE',
default='servicenetworking.googleapis.com',
help='The service to enable VPC service controls for.')
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""Run 'services vpc-peerings enable-vpc-service-controls'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
"""
project = properties.VALUES.core.project.Get(required=True)
project_number = _GetProjectNumber(project)
op = peering.EnableVpcServiceControls(project_number, args.service,
args.network)
if args.async_:
cmd = OP_WAIT_CMD.format(op.name)
log.status.Print('Asynchronous operation is in progress... '
'Use the following command to wait for its '
'completion:\n {0}'.format(cmd))
return
op = services_util.WaitOperation(op.name, peering.GetOperation)
services_util.PrintOperation(op)
def _GetProjectNumber(project_id):
return projects_api.Get(projects_util.ParseProject(project_id)).projectNumber

View File

@@ -0,0 +1,114 @@
# -*- 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.
"""services vpc-peerings get-vpc-service-controls command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import peering
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.projects import util as projects_util
from googlecloudsdk.core import properties
@base.DefaultUniverseOnly
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class GetVpcServiceControls(base.DescribeCommand):
"""Get VPC state of Service Controls for the peering connection."""
detailed_help = {
'DESCRIPTION': """\
This command provides the state of the VPC Service Controls for a
connection. The state can be enabled or disabled.
When enabled, Google Cloud makes the following route configuration
changes in the service producer VPC network: Google Cloud removes the
IPv4 default route (destination 0.0.0.0/0, next hop default internet
gateway), Google Cloud then creates an IPv4 route for destination
199.36.153.4/30 using the default internet gateway next hop.
When enabled, Google Cloud also creates Cloud DNS managed private
zones and authorizes those zones for the service producer VPC network.
The zones include googleapis.com, gcr.io, pkg.dev,
notebooks.cloud.google.com, kernels.googleusercontent.com,
backupdr.cloud.google.com, and backupdr.googleusercontent.com
as necessary domains or host names for Google APIs and services that are
compatible with VPC Service Controls. Record data in the zones resolves
all host names to 199.36.153.4, 199.36.153.5, 199.36.153.6, and
199.36.153.7.
When disabled, Google Cloud makes the following route configuration
changes in the service producer VPC network: Google Cloud restores a
default route (destination 0.0.0.0/0, next hop default internet
gateway), Google Cloud also deletes the Cloud DNS managed private
zones that provided the host name overrides.
While enabled, the service producer VPC network can still import
static and dynamic routes from the peered customer network if you
enable custom route export. These custom routes can include a default
route. For this reason, this command is not to be used solely as a
means for preventing access to the internet.
""",
'EXAMPLES': """\
To get the status of the VPC Service Controls for a connection peering
a network called `my-network` on the current project to a service called
`your-service`, run:
$ {command} --network=my-network --service=your-service
""",
}
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that can be used to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
parser.add_argument(
'--network',
metavar='NETWORK',
required=True,
help=(
'The network in the current project that is peered with the'
' service.'
),
)
parser.add_argument(
'--service',
metavar='SERVICE',
default='servicenetworking.googleapis.com',
help='The service to get VPC service controls for.',
)
def Run(self, args):
"""Run 'services vpc-peerings get-vpc-service-controls'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
The state of the Vpc Service Controls, that is enabled or disabled.
"""
project = properties.VALUES.core.project.Get(required=True)
project_number = projects_util.GetProjectNumber(project)
return peering.GetVpcServiceControls(
project_number, args.service, args.network
)

View File

@@ -0,0 +1,89 @@
# -*- coding: utf-8 -*- #
# Copyright 2018 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.
"""services vpc-peerings list command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import peering
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.projects import util as projects_util
from googlecloudsdk.core import properties
_DETAILED_HELP = {
'DESCRIPTION':
"""\
This command lists connections of a network to a service via VPC peering
for a project.
""",
'EXAMPLES':
"""\
To list connections of a network called `my-network` to a service called
`your-service`, run:
$ {command} --network=my-network --service=your-service
To list connections of a network against all services, run:
$ {command} --network=my-network
""",
}
# TODO(b/125365973): add e2e test for list command.
class List(base.DescribeCommand):
"""List connections to a service via VPC peering for a project network."""
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go
on the command line after this command. Positional arguments are
allowed.
"""
parser.add_argument(
'--network',
metavar='NETWORK',
required=True,
help='The network in the current project to list connections with the service'
)
parser.add_argument(
'--service',
metavar='SERVICE',
default='',
help='The service to list connections')
def Run(self, args):
"""Run 'services vpc-peerings list'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
The list of connections.
"""
project = properties.VALUES.core.project.Get(required=True)
project_number = projects_util.GetProjectNumber(project)
service = args.service if args.IsSpecified('service') else '-'
conns = peering.ListConnections(project_number, service, args.network)
return iter(conns)
List.detailed_help = _DETAILED_HELP

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*- #
# Copyright 2018 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.
"""Package for the services/operations CLI subcommands."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
class Operations(base.Group):
"""Manage VPC Peering operations."""

View File

@@ -0,0 +1,66 @@
# -*- coding: utf-8 -*- #
# Copyright 2018 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.
"""services operations describe command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import peering
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.calliope import base
_NAME_HELP = """The name of operation to describe"""
class Describe(base.DescribeCommand):
# pylint: disable=line-too-long
"""Describes an operation resource for a given operation name.
This command will return information about an operation given the name
of that operation.
## EXAMPLES
To describe an operation resource named
`operations/abc`, run:
$ {command} --name=operations/abc
"""
# pylint: enable=line-too-long
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go
on the command line after this command. Positional arguments are
allowed.
"""
parser.add_argument(
'--name', metavar='OPERATION_NAME', required=True, help=_NAME_HELP)
def Run(self, args):
"""Run 'services operations describe'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
Nothing.
"""
op = peering.GetOperation(args.name)
services_util.PrintOperation(op)

View File

@@ -0,0 +1,64 @@
# -*- coding: utf-8 -*- #
# Copyright 2018 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.
"""service-management operations wait command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.services import peering
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.calliope import base
_NAME_HELP = 'The name of operation to wait'
class Wait(base.Command):
"""Waits for an operation to complete for a given operation name.
This command will block until an operation has been marked as complete.
## EXAMPLES
To wait on an operation named `operations/abc`
to complete, run:
$ {command} --name=operations/abc
"""
# pylint: enable=line-too-long
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go
on the command line after this command. Positional arguments are
allowed.
"""
parser.add_argument(
'--name', metavar='OPERATION_NAME', required=True, help=_NAME_HELP)
def Run(self, args):
"""Run 'services operations wait'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
Returns:
Nothing.
"""
op = services_util.WaitOperation(args.name, peering.GetOperation)
services_util.PrintOperation(op)

View File

@@ -0,0 +1,113 @@
# -*- coding: utf-8 -*- #
# Copyright 2019 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.
"""services vpc-peerings update command."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.cloudresourcemanager import projects_api
from googlecloudsdk.api_lib.services import peering
from googlecloudsdk.api_lib.services import services_util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.projects import util as projects_util
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
OP_BASE_CMD = 'gcloud services vpc-peerings operations '
OP_WAIT_CMD = OP_BASE_CMD + 'wait {0}'
class Update(base.SilentCommand):
"""Update a private service connection to a service for a project network."""
detailed_help = {
'DESCRIPTION':
"""\
This command updates a private service connection to a service via a
VPC network.
""",
'EXAMPLES':
"""\
To update connection for a network called `my-network` on the current
project to a service called `your-service` with IP CIDR ranges
`google-range-1,google-range-2` for the service to use, run:
$ {command} --network=my-network --service=your-service \\
--ranges=google-range-1,google-range-2
To run the same command asynchronously (non-blocking), run:
$ {command} --network=my-network --service=your-service \\
--ranges=google-range-1,google-range-2 --async
""",
}
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
parser.add_argument(
'--network',
metavar='NETWORK',
required=True,
help='The network in the current project to be peered with the service')
parser.add_argument(
'--service',
metavar='SERVICE',
default='servicenetworking.googleapis.com',
help='The service to connect to')
parser.add_argument(
'--ranges',
metavar='RANGES',
help='The names of IP CIDR ranges for service to use.')
parser.add_argument(
'--force',
action='store_true',
help='If specified, the update call will proceed even if the update '
'can be destructive.')
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""Run 'services vpc-peerings connect'.
Args:
args: argparse.Namespace, The arguments that this command was invoked
with.
"""
project = properties.VALUES.core.project.Get(required=True)
project_number = _GetProjectNumber(project)
if args.ranges:
ranges = args.ranges.split(',')
op = peering.UpdateConnection(project_number, args.service, args.network,
ranges, args.force)
if args.async_:
cmd = OP_WAIT_CMD.format(op.name)
log.status.Print('Asynchronous operation is in progress... '
'Use the following command to wait for its '
'completion:\n {0}'.format(cmd))
return
op = services_util.WaitOperation(op.name, peering.GetOperation)
services_util.PrintOperation(op)
def _GetProjectNumber(project_id):
return projects_api.Get(projects_util.ParseProject(project_id)).projectNumber