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,57 @@
# -*- coding: utf-8 -*- #
# Copyright 2016 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.
"""Auth for Application Default Credentials."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA,
base.ReleaseTrack.ALPHA)
class ApplicationDefault(base.Group):
"""Manage your active Application Default Credentials.
Application Default Credentials (ADC) provide a method to get credentials used
in calling Google APIs. The {command} command group allows you to manage
active credentials on your machine that are used for local application
development.
These credentials are only used by Google client libraries in your own
application.
For more information about ADC and how it works, see [Authenticating as a
service account](https://cloud.google.com/docs/authentication/production).
## EXAMPLES
To use your own user credentials for your application to access an API, run:
$ {command} login
This will take you through a web flow to acquire new user credentials.
To create a service account and have your application use it for API access,
run:
$ gcloud iam service-accounts create my-account
$ gcloud iam service-accounts keys create key.json
--iam-account=my-account@my-project.iam.gserviceaccount.com
$ export GOOGLE_APPLICATION_CREDENTIALS=key.json
$ ./my_application.sh
"""

View File

@@ -0,0 +1,285 @@
# -*- coding: utf-8 -*- #
# Copyright 2016 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.
"""A command to install Application Default Credentials using a user account."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.auth import util as auth_util
from googlecloudsdk.calliope import actions
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions as c_exc
from googlecloudsdk.command_lib.auth import auth_util as command_auth_util
from googlecloudsdk.command_lib.auth import flags
from googlecloudsdk.command_lib.auth import workforce_login_config as workforce_login_config_util
from googlecloudsdk.core import config
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
from googlecloudsdk.core.console import console_io
from googlecloudsdk.core.credentials import creds as creds_module
from googlecloudsdk.core.credentials import gce as c_gce
from googlecloudsdk.core.credentials import store as c_store
from googlecloudsdk.core.util import files
@base.UniverseCompatible
class Login(base.Command):
r"""Acquire new user credentials to use for Application Default Credentials.
Obtains user access credentials via a web flow and puts them in the
well-known location for Application Default Credentials (ADC).
This command is useful when you are developing code that would normally
use a service account but need to run the code in a local development
environment where it's easier to provide user credentials. The credentials
will apply to all API calls that make use of the Application Default
Credentials client library. Do not set the `GOOGLE_APPLICATION_CREDENTIALS`
environment variable if you want to use the credentials generated by this
command in your local development. This command tries to find a quota
project from gcloud's context and write it to ADC so that Google client
libraries can use it for billing and quota. Alternatively, you can use
the `--client-id-file` flag. In this case, the project owning the client ID
will be used for billing and quota. You can create the client ID file
at https://console.cloud.google.com/apis/credentials.
This command has no effect on the user account(s) set up by the
`gcloud auth login` command.
Any credentials previously generated by
`gcloud auth application-default login` will be overwritten.
"""
detailed_help = {
'EXAMPLES':
"""\
If you want your local application to temporarily use your own user
credentials for API access, run:
$ {command}
If you'd like to login by passing in a file containing your own client
id, run:
$ {command} --client-id-file=clientid.json
"""
}
@staticmethod
def Args(parser):
"""Set args for gcloud auth application-default login."""
parser.add_argument(
'--client-id-file',
help='A file containing your own client id to use to login. If '
'--client-id-file is specified, the quota project will not be '
'written to ADC.')
parser.add_argument(
'--scopes',
type=arg_parsers.ArgList(min_length=1),
metavar='SCOPE',
help='The names of the scopes to authorize for. By default '
'{0} scopes are used. '
'The list of possible scopes can be found at: '
'[](https://developers.google.com/identity/protocols/googlescopes). '
'To add scopes for applications outside of Google Cloud Platform, '
'such as Google Drive, [create an OAuth Client ID]'
'(https://support.google.com/cloud/answer/6158849) and provide it by '
'using the --client-id-file flag. '
.format(', '.join(auth_util.DEFAULT_SCOPES)))
parser.add_argument(
'--login-config',
help='Path to the login configuration file (workforce pool, '
'generated by the Cloud Console or '
'`gcloud iam workforce-pools create-login-config`)',
action=actions.StoreProperty(properties.VALUES.auth.login_config_file))
parser.add_argument(
'account',
nargs='?',
help=(
'User account used for authorization. When the account specified'
' has valid credentials in the local credential store these'
' credentials will be re-used. Otherwise new ones will be fetched'
' and replace any stored credential.'
' This caching behavior is only available for user credentials.'
),
)
flags.AddQuotaProjectFlags(parser)
flags.AddRemoteLoginFlags(parser, for_adc=True)
parser.display_info.AddFormat('none')
def Run(self, args):
"""Run the authentication command."""
# TODO(b/203102970): Remove this condition check after the bug is resolved
if properties.VALUES.auth.access_token_file.Get():
raise c_store.FlowError(
'auth/access_token_file or --access-token-file was set which is not '
'compatible with this command. Please unset the property and rerun '
'this command.'
)
if c_gce.Metadata().connected:
message = textwrap.dedent("""
You are running on a Google Compute Engine virtual machine.
The service credentials associated with this virtual machine
will automatically be used by Application Default
Credentials, so it is not necessary to use this command.
If you decide to proceed anyway, your user credentials may be visible
to others with access to this virtual machine. Are you sure you want
to authenticate with your personal account?
""")
console_io.PromptContinue(
message=message, throw_if_unattended=True, cancel_on_no=True)
command_auth_util.PromptIfADCEnvVarIsSet()
if args.client_id_file and not args.launch_browser:
raise c_exc.InvalidArgumentException(
'--no-launch-browser',
'`--no-launch-browser` flow no longer works with the '
'`--client-id-file`. Please replace `--no-launch-browser` with '
'`--no-browser`.'
)
# Currently the original scopes are not stored in the ADC. If they were, a
# change in scopes could also be used to determine a cache hit.
if args.account and not args.scopes:
if ShouldUseCachedCredentials(args.account):
log.warning(
'\nValid credentials already exist for {}. To force refresh the'
' existing credentials, omit the "ACCOUNT" positional field.'
.format(args.account)
)
return
scopes = args.scopes or auth_util.DEFAULT_SCOPES
target_impersonation_principal, delegates, target_scopes = None, None, None
impersonation_service_accounts = (
properties.VALUES.auth.impersonate_service_account.Get()
)
if impersonation_service_accounts:
(target_impersonation_principal, delegates
) = c_store.ParseImpersonationAccounts(impersonation_service_accounts)
# Only set target_scopes if user explicitly asked for something, if not
# we will let auth and client library decide on the scopes.
target_scopes = args.scopes or None
# Source credential just needs the scope needed to call the IAM API for
# impersonation. Asking user to consent any other scope is unnecessary.
scopes = [auth_util.CLOUD_PLATFORM_SCOPE]
flow_params = dict(
no_launch_browser=not args.launch_browser,
no_browser=not args.browser,
remote_bootstrap=args.remote_bootstrap,
)
# 1. Try the 3PI web flow with --no-browser:
# This could be a 3PI flow initiated via --no-browser.
# If provider_name is present, then this is the 3PI flow.
# We can start the flow as is as the remote_bootstrap value will be used.
if args.remote_bootstrap and 'provider_name' in args.remote_bootstrap:
auth_util.DoInstalledAppBrowserFlowGoogleAuth(
config.CLOUDSDK_EXTERNAL_ACCOUNT_SCOPES,
auth_proxy_redirect_uri=(
'https://sdk.cloud.google/applicationdefaultauthcode.html'
),
**flow_params
)
return
# 2. Try the 3PI web flow with a login configuration file.
login_config_file = workforce_login_config_util.GetWorkforceLoginConfig()
if login_config_file:
if args.client_id_file:
raise c_exc.ConflictingArgumentsException(
'--client-id-file is not currently supported for third party login '
'flows. ')
if args.scopes:
raise c_exc.ConflictingArgumentsException(
'--scopes is not currently supported for third party login flows.')
creds = workforce_login_config_util.DoWorkforceHeadfulLogin(
login_config_file,
True,
**flow_params
)
else:
# 3. Try the 1P web flow.
properties.VALUES.auth.client_id.Set(
auth_util.DEFAULT_CREDENTIALS_DEFAULT_CLIENT_ID)
properties.VALUES.auth.client_secret.Set(
auth_util.DEFAULT_CREDENTIALS_DEFAULT_CLIENT_SECRET)
if auth_util.CLOUD_PLATFORM_SCOPE not in scopes:
raise c_exc.InvalidArgumentException(
'--scopes',
'{} scope is required but not requested. Please include it in the'
' --scopes flag.'.format(auth_util.CLOUD_PLATFORM_SCOPE),
)
creds = auth_util.DoInstalledAppBrowserFlowGoogleAuth(
scopes,
client_id_file=args.client_id_file,
auth_proxy_redirect_uri=(
'https://sdk.cloud.google.com/applicationdefaultauthcode.html'
),
**flow_params
)
if not creds:
return
if args.account and hasattr(creds, 'with_account'):
_ = command_auth_util.ExtractAndValidateAccount(args.account, creds)
creds = creds.with_account(args.account)
if not target_impersonation_principal:
if args.IsSpecified('client_id_file'):
command_auth_util.DumpADC(creds, quota_project_disabled=False)
elif args.disable_quota_project:
command_auth_util.DumpADC(creds, quota_project_disabled=True)
else:
command_auth_util.DumpADCOptionalQuotaProject(creds)
else:
# TODO(b/184049366): Supports quota project with impersonated creds.
command_auth_util.DumpImpersonatedServiceAccountToADC(
creds,
target_principal=target_impersonation_principal,
delegates=delegates,
scopes=target_scopes)
return creds
def ShouldUseCachedCredentials(account):
"""Skip login if the existing ADC was provisioned for the requested account."""
try:
file_path = config.ADCFilePath()
data = files.ReadFileContents(file_path)
except files.Error:
return False
try:
credential = creds_module.FromJsonGoogleAuth(data)
except creds_module.UnknownCredentialsType:
return False
except creds_module.InvalidCredentialsError:
return False
cred_type = creds_module.CredentialTypeGoogleAuth.FromCredentials(credential)
if cred_type == creds_module.CredentialTypeGoogleAuth.USER_ACCOUNT:
if credential.account != account:
return False
return True

View File

@@ -0,0 +1,235 @@
# -*- coding: utf-8 -*- #
# Copyright 2016 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.
"""A command that prints an access token for Application Default Credentials.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from google.auth import credentials
from google.auth import exceptions as google_auth_exceptions
from google.auth import impersonated_credentials
from google.oauth2 import credentials as google_auth_creds
from googlecloudsdk.api_lib.auth import util as auth_util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions as c_exc
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
from googlecloudsdk.core import requests
from googlecloudsdk.core.credentials import creds as c_creds
from googlecloudsdk.core.credentials import exceptions as creds_exceptions
from googlecloudsdk.core.credentials import google_auth_credentials as c_google_auth
from googlecloudsdk.core.credentials import store as c_store
import six
_DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds
@base.UniverseCompatible
class PrintAccessToken(base.Command):
r"""Print an access token for your current Application Default Credentials.
{command} generates and prints an access token for the current
Application Default Credential (ADC). The
[ADC](https://google.aip.dev/auth/4110) can be specified either by using
`gcloud auth application-default login`,
`gcloud auth login --cred-file=/path/to/cred/file --update-adc`, or by
setting the `GOOGLE_APPLICATION_CREDENTIALS` environment variable.
The access token generated by {command} is useful for manually testing
APIs via curl or similar tools.
In order to print details of the access token, such as the associated account
and the token's expiration time in seconds, run:
$ curl -H "Content-Type: application/x-www-form-urlencoded" \
-d "access_token=$(gcloud auth application-default print-access-token)" \
https://www.googleapis.com/oauth2/v1/tokeninfo
Note that token itself may not be enough to access some services.
If you use the token with curl or similar tools, you may see
permission errors similar to "Your application has authenticated using end
user credentials from the Google Cloud SDK or Google Cloud Shell".
If it happens, you may need to provide a quota project in the
"X-Goog-User-Project" header. For example,
$ curl -H "X-Goog-User-Project: your-project" \
-H \
"Authorization: Bearer $(gcloud auth application-default \
print-access-token)" foo.googleapis.com
The identity that granted the token must have the serviceusage.services.use
permission on the provided project. See
https://cloud.google.com/apis/docs/system-parameters for more
information.
"""
@staticmethod
def Args(parser):
parser.add_argument(
'--lifetime',
type=arg_parsers.Duration(upper_bound='43200s'),
help=(
'Access token lifetime. The default access token lifetime is 3600'
' seconds, but you can use this flag to reduce the lifetime or'
' extend it up to 43200 seconds (12 hours). The org policy'
' constraint'
' `constraints/iam.allowServiceAccountCredentialLifetimeExtension`'
' must be set if you want to extend the lifetime beyond 3600'
' seconds. Note that this flag is for service account impersonation'
' only, so it only works when either'
' `--impersonate-service-account` flag or'
' `auth/impersonate_service_account` property is set.'
),
)
parser.add_argument(
'--scopes',
type=arg_parsers.ArgList(min_length=1),
metavar='SCOPE',
help='The scopes to authorize for. This flag is supported for user '
'accounts and service accounts only. '
'The list of possible scopes can be found at: '
'[](https://developers.google.com/identity/protocols/googlescopes).\n\n'
'For end-user accounts, the provided '
'scopes must be from [{0}], or the scopes previously specified through '
'`gcloud auth application-default login --scopes`.'.format(', '.join(
map('`{}`'.format, auth_util.DEFAULT_SCOPES))))
parser.display_info.AddFormat('value(token)')
def Run(self, args):
"""Run the helper command."""
# Create the ADC cred.
try:
creds, _ = c_creds.GetGoogleAuthDefault().default(
scopes=args.scopes or [auth_util.CLOUD_PLATFORM_SCOPE])
except google_auth_exceptions.DefaultCredentialsError as e:
log.debug(e, exc_info=True)
raise c_exc.ToolException(six.text_type(e))
# Check if impersonation is used. There are two scenarios:
# (1) the ADC file is not an impersonated credential json file, and either
# --impersonate-service-account flag or auth/impersonate_service_account
# property is set. In this case, we will create a new impersonated cred,
# using the ADC cred as the source cred. The impersonated service account
# value will be parsed and used as target principal and delegates.
# (2) the ADC file is impersonated cred json file, then the ADC cred
# created above is an impersonated cred. If users provided impersonated
# service account via flag or property, we also need to parse the value to
# target principal and delegates, and override them in the cred.
is_adc_cred_impersonated = c_creds.IsImpersonatedAccountCredentials(creds)
impersonation_service_accounts = (
properties.VALUES.auth.impersonate_service_account.Get()
)
is_impersonation_used = is_adc_cred_impersonated or (
impersonation_service_accounts is not None
)
if args.lifetime and not is_impersonation_used:
raise c_exc.InvalidArgumentException(
'--lifetime',
(
'Lifetime flag is for service account impersonation only. It must'
' be used together with either --impersonate-service-account flag'
' or auth/impersonate_service_account property, or the'
' application default credential json file must have'
' `impersonated_service_account` type.'
),
)
if impersonation_service_accounts:
(target_principal, delegates) = c_store.ParseImpersonationAccounts(
impersonation_service_accounts
)
# Add scopes to the ADC cred. We don't do so for impersonated cred since
# for scenario (1): the ADC cred is the source cred, the scopes should be
# added to the impersonated cred not the source cred
# for scenario (2): the ADC cred is the impersonated cred, we already added
# the scope during the cred creation
if args.scopes and not is_impersonation_used:
cred_type = c_creds.CredentialTypeGoogleAuth.FromCredentials(creds)
if cred_type not in [
c_creds.CredentialTypeGoogleAuth.USER_ACCOUNT,
c_creds.CredentialTypeGoogleAuth.SERVICE_ACCOUNT
]:
# TODO(b/223649175): Add support for other credential types(e.g GCE).
log.warning(
'`--scopes` flag may not work as expected and will be ignored '
'for account type {}.'.format(cred_type.key)
)
scopes = args.scopes + [auth_util.OPENID, auth_util.USER_EMAIL_SCOPE]
# non user account credential types
# pylint:disable=protected-access
if isinstance(creds, credentials.Scoped):
creds = creds.with_scopes(scopes)
else:
creds._scopes = scopes
# Make adjustments to the ADC cred.
# - if it's user credentials, convert it so that it can handle reauth
# during refresh.
# - if it's impersonated cred, override the target principal and delegates
# if impersonated service account flag/property is provided, and set
# lifetime if lifetime flag is provided.
if isinstance(creds, google_auth_creds.Credentials):
creds = c_google_auth.Credentials.FromGoogleAuthUserCredentials(
creds)
if is_adc_cred_impersonated:
if impersonation_service_accounts:
creds._target_principal = target_principal # pylint: disable=protected-access
creds._delegates = delegates # pylint: disable=protected-access
if args.lifetime:
creds._lifetime = args.lifetime # pylint: disable=protected-access
# The token URI needs to be overridden in case
# context aware access is enabled.
# pylint: disable=protected-access
creds._token_uri = c_creds.GetDefaultTokenUri()
# pylint: enable=protected-access
# Refresh the ADC cred.
req = requests.GoogleAuthRequest()
try:
with c_store.HandleGoogleAuthCredentialsRefreshError(for_adc=True):
creds.refresh(req)
except creds_exceptions.TokenRefreshError as e:
if args.scopes:
raise c_exc.InvalidArgumentException(
'--scopes',
'Invalid scopes value. Please make sure the scopes are from [{0}], '
'or the scopes previously specified through '
'`gcloud auth application-default login --scopes`.'
.format(', '.join(map('`{}`'.format, auth_util.DEFAULT_SCOPES))))
else:
raise e
# If impersonation is not needed, or the ADC cred is already an impersonated
# cred, since we already did refresh above, we can return the cred.
# Otherwise, we need to create an impersonated cred using the ADC cred as
# the source cred and the provided target principal, delegates and lifetime.
# We then do a refresh and return the cred.
if not is_impersonation_used or is_adc_cred_impersonated:
return creds
impersonated_creds = impersonated_credentials.Credentials(
source_credentials=creds,
target_principal=target_principal,
delegates=delegates,
target_scopes=args.scopes or [auth_util.CLOUD_PLATFORM_SCOPE],
lifetime=args.lifetime or _DEFAULT_TOKEN_LIFETIME_SECS,
)
impersonated_creds.refresh(req)
return impersonated_creds

View File

@@ -0,0 +1,88 @@
# -*- coding: utf-8 -*- #
# Copyright 2016 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.
"""Revoke credentials being used by Application Default Credentials."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import os
from google.oauth2 import credentials as google_auth_creds
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions as c_exc
from googlecloudsdk.core import config
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
from googlecloudsdk.core.credentials import creds as c_creds
from googlecloudsdk.core.credentials import google_auth_credentials as c_google_auth
from googlecloudsdk.core.credentials import store as c_store
class Revoke(base.SilentCommand):
"""Revoke previously generated Application Default Credentials.
Revokes Application Default Credentials that have been previously generated by
`{parent_command} login` and deletes the local credential file.
This does not affect any credentials set up through other means,
such as credentials referenced by the Application Default Credentials
environment variable or service account credentials that are active on
a Google Compute Engine virtual machine.
"""
@staticmethod
def Args(parser):
pass
def Run(self, args):
"""Revoke Application Default Credentials."""
cred_file = config.ADCFilePath()
if not os.path.isfile(cred_file):
log.status.Print('Application Default Credentials have not been set up, '
'nothing to revoke.')
return
creds, _ = c_creds.GetGoogleAuthDefault().load_credentials_from_file(
cred_file)
if not (c_creds.IsUserAccountCredentials(creds) or
c_creds.IsExternalAccountCredentials(creds) or
c_creds.IsExternalAccountUserCredentials(creds) or
c_creds.IsImpersonatedAccountCredentials(creds)):
raise c_exc.BadFileException(
'The given credential file is a service account credential, and '
'cannot be revoked.')
if isinstance(creds, google_auth_creds.Credentials):
creds = c_google_auth.Credentials.FromGoogleAuthUserCredentials(
creds)
console_io.PromptContinue(
'You are about to revoke the credentials stored in: [{file}]'.format(
file=cred_file),
throw_if_unattended=True,
cancel_on_no=True)
try:
c_store.RevokeCredentials(creds)
os.remove(cred_file)
log.status.Print('Credentials revoked.')
except c_store.RevokeError:
os.remove(cred_file)
log.warning(
'The credentials stored in: [{file}] are not revocable from the '
'server but have been deleted from the file system.'.format(
file=cred_file))

View File

@@ -0,0 +1,58 @@
# -*- 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.
"""Update or add a quota project in application default credentials json."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.auth import auth_util
from googlecloudsdk.command_lib.resource_manager import completers
class SetQuotaProject(base.SilentCommand):
"""Update or add a quota project in application default credentials (ADC).
A quota project is a Google Cloud Project that will be used for billing
and quota limits.
Before running this command, an ADC must already be generated using
$ gcloud auth application-default login.
The quota project defined in the ADC will be used by the Google client
libraries.
The existing application default credentials must have the
`serviceusage.services.use` permission on the given project.
## EXAMPLES
To update the quota project in application default credentials to
`my-quota-project`, run:
$ {command} my-quota-project
"""
@staticmethod
def Args(parser):
base.Argument(
'quota_project_id',
metavar='QUOTA_PROJECT_ID',
completer=completers.ProjectCompleter,
help='Quota project ID to add to application default credentials. If '
'a quota project already exists, it will be updated.').AddToParser(
parser)
def Run(self, args):
return auth_util.AddQuotaProjectToADC(args.quota_project_id)