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,47 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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 main command group for Google Cloud Functions."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import argparse
from googlecloudsdk.api_lib.functions import transforms
from googlecloudsdk.calliope import actions
from googlecloudsdk.calliope import base
from googlecloudsdk.core import properties
@base.DefaultUniverseOnly
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Functions(base.Group):
"""Manage Google Cloud Functions."""
category = base.COMPUTE_CATEGORY
@staticmethod
def Args(parser):
parser.display_info.AddTransforms(transforms.GetTransforms())
def Filter(self, context, args):
# TODO(b/190534642): Determine if command group works with project number
base.RequireProjectID(args)
del context, args
base.DisableUserProjectQuota()

View File

@@ -0,0 +1,69 @@
# -*- 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.
"""Add an IAM policy binding for a Google Cloud Function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions import util
from googlecloudsdk.command_lib.functions.v1.add_iam_policy_binding import command as command_v1
from googlecloudsdk.command_lib.functions.v2.add_iam_policy_binding import command as command_v2
from googlecloudsdk.command_lib.iam import iam_util
@base.ReleaseTracks(base.ReleaseTrack.GA)
class AddIamPolicyBinding(util.FunctionResourceCommand):
"""Adds an IAM policy binding for a Google Cloud Function."""
detailed_help = {
'DESCRIPTION': '{description}',
'EXAMPLES': """\
To add the iam policy binding for `FUNCTION-1` to role
`ROLE-1` for member `MEMBER-1` run:
$ {command} FUNCTION-1 --member=MEMBER-1 --role=ROLE-1
""",
}
@staticmethod
def Args(parser):
"""Registers flags for this command.
Args:
parser: The argparse parser.
"""
flags.AddFunctionResourceArg(parser, 'to add IAM policy binding for')
iam_util.AddArgsForAddIamPolicyBinding(parser)
flags.AddGen2Flag(parser, hidden=True)
def _RunV1(self, args):
return command_v1.Run(args)
def _RunV2(self, args):
return command_v2.Run(args, self.ReleaseTrack())
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class AddIamPolicyBindingBeta(AddIamPolicyBinding):
"""Adds an IAM policy binding for a Google Cloud Function."""
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class AddIamPolicyBindingAlpha(AddIamPolicyBindingBeta):
"""Adds an IAM policy binding for a Google Cloud Function."""

View File

@@ -0,0 +1,90 @@
# -*- 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.
"""Add an invoker binding to the IAM policy of a Google Cloud Function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.functions.v1 import util as api_util_v1
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import parser_extensions
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions import util
from googlecloudsdk.command_lib.functions.v2.add_invoker_policy_binding import command as command_v2
from googlecloudsdk.command_lib.iam import iam_util
_DETAILED_HELP = {
'DESCRIPTION': """\
Adds an invoker role IAM policy binding that allows the specified member
to invoke the specified function.
For Cloud Functions (1st gen), this adds the Cloud Functions Invoker
binding to the IAM policy of the specified function.
For Cloud Functions (2nd gen), this adds the Cloud Run Invoker binding to
the IAM policy of the specified function's underlying Cloud Run service.
""",
'EXAMPLES': """\
To add the invoker role policy binding for `FUNCTION-1` for member
`MEMBER-1` run:
$ {command} FUNCTION-1 --member=MEMBER-1
""",
}
@base.ReleaseTracks(base.ReleaseTrack.GA)
class AddInvokerPolicyBinding(util.FunctionResourceCommand):
"""Adds an invoker binding to the IAM policy of a Google Cloud Function.
This command applies to Cloud Functions 2nd gen only.
"""
detailed_help = _DETAILED_HELP
@staticmethod
def Args(parser):
"""Registers flags for this command."""
flags.AddFunctionResourceArg(parser, 'to add the invoker binding to')
flags.AddGen2Flag(parser, 'to add the invoker binding to', hidden=True)
iam_util.AddMemberFlag(parser, 'to add to the IAM policy', False)
def _RunV1(self, args: parser_extensions.Namespace):
return api_util_v1.AddFunctionIamPolicyBinding(
args.CONCEPTS.name.Parse().RelativeName(),
member=args.member,
role='roles/cloudfunctions.invoker',
)
def _RunV2(self, args):
return command_v2.Run(args, self.ReleaseTrack())
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class AddInvokerPolicyBindingBeta(AddInvokerPolicyBinding):
"""Adds an invoker binding to the IAM policy of a Google Cloud Function.
This command applies to Cloud Functions 2nd gen only.
"""
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class AddInvokerPolicyBindingAlpha(AddInvokerPolicyBindingBeta):
"""Add an invoker binding to the IAM policy of a Google Cloud Function.
This command applies to Cloud Functions 2nd Gen only.
"""

View File

@@ -0,0 +1,85 @@
# -*- 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.
"""Triggers execution of a Google Cloud Function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions import util
from googlecloudsdk.command_lib.functions.v1.call import command as command_v1
from googlecloudsdk.command_lib.functions.v2.call import command as command_v2
_DETAILED_HELP = {
'EXAMPLES': """
To call a function, giving it 'Hello World!' in the message field of its event
argument (depending on your environment you might need to escape
characters in `--data` flag value differently), run:
$ {command} helloWorld --data='{"message": "Hello World!"}'
Note that this method has a limited quota which cannot be increased. It is
intended for testing and debugging and should not be used in production.
Calls to HTTP-triggered functions are sent as HTTP POST requests. To use other
HTTP methods, use a dedicated HTTP request tool such as cURL or wget.
"""
}
@base.ReleaseTracks(base.ReleaseTrack.GA)
class Call(util.FunctionResourceCommand):
"""Triggers execution of a Google Cloud Function."""
detailed_help = _DETAILED_HELP
@staticmethod
def Args(parser):
"""Registers flags for this command."""
flags.AddFunctionResourceArg(parser, 'to execute')
data_flag_group = parser.add_mutually_exclusive_group()
flags.AddDataFlag(data_flag_group)
# Flags for GCFv2
flags.AddGen2Flag(parser, hidden=True)
flags.AddCloudEventsFlag(data_flag_group)
def _RunV1(self, args):
return command_v1.Run(args, self.ReleaseTrack())
def _RunV2(self, args):
return command_v2.Run(args, self.ReleaseTrack())
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class CallBeta(Call):
"""Triggers execution of a Google Cloud Function."""
@staticmethod
def Args(parser):
"""Register beta (and implicitly alpha) flags for this command."""
Call.Args(parser)
# Flags for beta (and implicitly alpha)
flags.AddGcloudHttpTimeoutFlag(parser)
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class CallAlpha(CallBeta):
"""Triggers execution of a Google Cloud Function."""

View File

@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""Deletes a Google Cloud Function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions import util
from googlecloudsdk.command_lib.functions.v1.delete import command as command_v1
from googlecloudsdk.command_lib.functions.v2.delete import command as command_v2
@base.ReleaseTracks(base.ReleaseTrack.GA)
class Delete(base.DeleteCommand, util.FunctionResourceCommand):
"""Delete a Google Cloud Function."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
flags.AddFunctionResourceArg(parser, 'to delete')
parser.display_info.AddCacheUpdater(None)
flags.AddGen2Flag(parser, hidden=True)
def _RunV1(self, args):
return command_v1.Run(args)
def _RunV2(self, args):
return command_v2.Run(args, self.ReleaseTrack())
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class DeleteBeta(Delete):
"""Delete a Google Cloud Function."""
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class DeleteAlpha(DeleteBeta):
"""Delete a Google Cloud Function."""

View File

@@ -0,0 +1,187 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""Creates or updates a Google Cloud Function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions import secrets_config
from googlecloudsdk.command_lib.functions import util
from googlecloudsdk.command_lib.functions.v1.deploy import command as command_v1
from googlecloudsdk.command_lib.functions.v1.deploy import labels_util
from googlecloudsdk.command_lib.functions.v2.deploy import command as command_v2
from googlecloudsdk.command_lib.functions.v2.deploy import env_vars_util
from googlecloudsdk.command_lib.util.args import labels_util as args_labels_util
from googlecloudsdk.core import log
_HOW_TO_DISABLE_CHANGE = (
'You can disable this behavior by explicitly specifying the --no-gen2 flag'
" or by setting the functions/gen2 config property to 'off'."
)
_LEARN_ABOUT_GEN_DIFFS = (
'To learn more about the differences between 1st gen and 2nd gen functions,'
' visit:'
'\nhttps://cloud.google.com/functions/docs/concepts/version-comparison'
)
_NEW_CHANGE_WARNING = (
'As of Cloud SDK 492.0.0 release, new functions will be deployed as 2nd gen'
' functions by default. This is equivalent to currently deploying new'
' with the --gen2 flag. Existing 1st gen functions will not be impacted'
' and will continue to deploy as 1st gen functions.\n'
f'{_HOW_TO_DISABLE_CHANGE}\n'
f'{_LEARN_ABOUT_GEN_DIFFS}'
)
def _CommonArgs(parser, track):
"""Register base flags for this command."""
# Add a positional "resource argument" for the name of the function
flags.AddFunctionResourceArg(parser, 'to deploy')
# Add `args.memory` as str. Converted at runtime to int for v1.
# Add `args.cpu` as flag that requires `args.memory`
flags.AddFunctionMemoryAndCpuFlags(parser)
# Add args for function properties
flags.AddAllowUnauthenticatedFlag(parser)
flags.AddFunctionRetryFlag(parser)
flags.AddFunctionTimeoutFlag(parser)
flags.AddMaxInstancesFlag(parser)
flags.AddMinInstancesFlag(parser)
flags.AddRuntimeFlag(parser)
flags.AddServiceAccountFlag(parser)
args_labels_util.AddUpdateLabelsFlags(
parser,
extra_update_message=labels_util.NO_LABELS_STARTING_WITH_DEPLOY_MESSAGE,
extra_remove_message=labels_util.NO_LABELS_STARTING_WITH_DEPLOY_MESSAGE,
)
# Add args for specifying the function source code
flags.AddSourceFlag(parser)
flags.AddStageBucketFlag(parser)
flags.AddEntryPointFlag(parser)
# Add args for specifying the function trigger
flags.AddTriggerFlagGroup(parser)
# Add args for specifying environment variables
env_vars_util.AddUpdateEnvVarsFlags(parser)
# Add flags for specifying build environment variables
env_vars_util.AddBuildEnvVarsFlags(parser)
# Add args for specifying ignore files to upload source
flags.AddIgnoreFileFlag(parser)
# Add args for base image automatic update policy
flags.AddRuntimeUpdatePolicy(parser, track)
# Add flags for CMEK
flags.AddKMSKeyFlags(parser)
flags.AddDockerRepositoryFlags(parser)
# Add flags for secrets
secrets_config.ConfigureFlags(parser)
# Add flags for network settings
flags.AddVPCConnectorMutexGroup(parser)
flags.AddEgressSettingsFlag(parser)
flags.AddIngressSettingsFlag(parser)
flags.AddSecurityLevelFlag(parser)
flags.AddBuildWorkerPoolMutexGroup(parser)
# Configure flags for Artifact Registry
flags.AddDockerRegistryFlags(parser)
# Add additional flags for GCFv2
flags.AddRunServiceAccountFlag(parser)
flags.AddTriggerLocationFlag(parser)
flags.AddTriggerServiceAccountFlag(parser)
flags.AddGen2Flag(parser)
flags.AddServeAllTrafficLatestRevisionFlag(parser)
flags.AddConcurrencyFlag(parser)
# Add flag for user-provided Cloud Build Service Account
flags.AddBuildServiceAccountFlag(parser)
# Add flag for Binary Authorization Policy (2nd Gen only)
flags.AddBinaryAuthorizationMutexGroup(parser)
@base.ReleaseTracks(base.ReleaseTrack.GA)
class Deploy(util.FunctionResourceCommand, base.Command):
"""Create or update a Google Cloud Function."""
@staticmethod
def Args(parser):
_CommonArgs(parser, base.ReleaseTrack.GA)
def _RunV1(self, args):
return command_v1.Run(args, track=self.ReleaseTrack())
def _RunV2(self, args):
if not self._v2_function and not flags.ShouldUseGen2():
# Gen2 function creation without an explicit generation specification.
log.status.Print(_NEW_CHANGE_WARNING)
return command_v2.Run(args, self.ReleaseTrack())
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class DeployBeta(Deploy):
"""Create or update a Google Cloud Function."""
@staticmethod
def Args(parser):
"""Register alpha (and implicitly beta) flags for this command."""
_CommonArgs(parser, base.ReleaseTrack.BETA)
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class DeployAlpha(DeployBeta):
"""Create or update a Google Cloud Function."""
@staticmethod
def Args(parser):
"""Register alpha (and implicitly beta) flags for this command."""
_CommonArgs(parser, base.ReleaseTrack.ALPHA)
# Flags specific to the Alpha track
flags.AddBuildpackStackFlag(parser)
# Flags specific to the Direct VPC
flags.AddAllDirectVpcFlags(parser)
DETAILED_HELP = {
'EXAMPLES': """\
To deploy a function that is triggered by write events on the document
``/messages/{pushId}'', run:
$ {command} my_function --runtime=python37 --trigger-event=providers/cloud.firestore/eventTypes/document.write --trigger-resource=projects/project_id/databases/(default)/documents/messages/{pushId}
See https://cloud.google.com/functions/docs/calling for more details
of using other types of resource as triggers.
"""
}
Deploy.detailed_help = DETAILED_HELP
DeployBeta.detailed_help = DETAILED_HELP
DeployAlpha.detailed_help = DETAILED_HELP

View File

@@ -0,0 +1,113 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""Displays details of a Google Cloud Function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import encoding
from googlecloudsdk.api_lib.functions.v1 import util as api_util_v1
from googlecloudsdk.api_lib.functions.v2 import client as client_v2
from googlecloudsdk.api_lib.functions.v2 import util as api_util_v2
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions import util
from googlecloudsdk.command_lib.functions.v1 import decorator
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
def _PrintV2StateMessages(state_messages):
log.critical('Function has the following conditions:')
for state_message_string in api_util_v2.GetStateMessagesStrings(
state_messages
):
log.status.Print(' ' + state_message_string)
log.status.Print('') # newline
def _ValidateArgs(args):
"""Validate arguments."""
if (
args.IsSpecified('v2')
and properties.VALUES.functions.gen2.IsExplicitlySet()
):
if args.v2 and not flags.ShouldUseGen2():
log.warning(
'Conflicting flags "--v2" and "--no-gen2" specified, Cloud Functions'
' v2 APIs will be used.'
)
if not args.v2 and flags.ShouldUseGen2():
log.warning(
'Conflicting flags "--no-v2" and "--gen2" specified, Cloud Functions'
' v2 APIs will be used.'
)
@base.ReleaseTracks(base.ReleaseTrack.GA)
class Describe(util.FunctionResourceCommand, base.DescribeCommand):
"""Display details of a Google Cloud Function."""
@staticmethod
def Args(parser):
"""Register flags for this command."""
flags.AddFunctionResourceArg(parser, 'to describe')
flags.AddGen2Flag(parser, hidden=True, allow_v2=True)
flags.AddV2Flag(parser)
def _RunV1(self, args):
client = api_util_v1.GetApiClientInstance()
function = client.projects_locations_functions.Get(
client.MESSAGES_MODULE.CloudfunctionsProjectsLocationsFunctionsGetRequest(
name=args.CONCEPTS.name.Parse().RelativeName()
)
)
if self.ReleaseTrack() == base.ReleaseTrack.ALPHA:
v2_function = self._v2_function or self._RunV2(args)
return decorator.decorate_v1_function_with_v2_api_info(
function, v2_function
)
# To facilitate testing, convert to dict for consistency with alpha track.
return encoding.MessageToDict(function)
def _RunV2(self, args):
client = client_v2.FunctionsClient(self.ReleaseTrack())
function = self._v2_function or client.GetFunction(
args.CONCEPTS.name.Parse().RelativeName(), raise_if_not_found=True
)
if function.stateMessages:
_PrintV2StateMessages(function.stateMessages)
return function
def Run(self, args):
_ValidateArgs(args)
if args.v2:
return self._RunV2(args)
return util.FunctionResourceCommand.Run(self, args)
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class DescribeBeta(Describe):
"""Display details of a Google Cloud Function."""
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class DescribeAlpha(DescribeBeta):
"""Display details of a Google Cloud Function."""

View File

@@ -0,0 +1,115 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 Google LLC. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Detach GCF 2nd gen function from GCF and make it a native Cloud Run function."""
from googlecloudsdk.api_lib.functions.v2 import client as client_v2
from googlecloudsdk.api_lib.functions.v2 import exceptions
from googlecloudsdk.api_lib.functions.v2 import util as api_util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions import run_util
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.GA)
class Detach(base.Command):
"""Detach a Cloud Functions v2 function from its existing environment and make it a native Cloud Run function."""
@staticmethod
def Args(parser):
flags.AddFunctionResourceArg(
parser,
help_text_override=(
'The name of the Cloud Functions v2 function to detach.'
),
)
def Run(self, args):
"""Detach a Cloud Functions v2 function from its existing environment.
Detach a Cloud Functions v2 function from its existing environment and
make it a native Cloud Run function.
Args:
args: The arguments of the command.
Raises:
FunctionsError: If the function does not exist or the Cloud Run service is
not found.
"""
client = client_v2.FunctionsClient(self.ReleaseTrack())
function_ref = args.CONCEPTS.name.Parse()
function_name = function_ref.RelativeName()
message = ( # gcloud-disable-gdu-domain
f'WARNING: This command detaches your function {function_name} from the'
' Cloud Functions API (cloudfunctions.googleapis.com). Detached'
' functions continue to serve traffic, and retain the'
' `cloudfunctions.net` URL. You can only manage your detached'
' functions using the Cloud Run Admin API or the `gcloud run'
' <command>`. '
)
if console_io.CanPrompt():
console_io.PromptContinue(message, default=True, cancel_on_no=True)
function = client.GetFunction(function_name)
if function is None:
raise exceptions.FunctionsError(
'Function [{}] does not exist.'.format(function_name)
)
operation = client.DetachFunction(function_name)
description = ( # gcloud-disable-gdu-domain
'Detaching function from Google Cloud Functions API'
' (cloudfunctions.googleapis.com)'
)
api_util.WaitForOperation(
client.client, client.messages, operation, description
)
# After detach, the function is a native Cloud Run service.
service = run_util.GetService(function)
if not service:
raise exceptions.FunctionsError(
'Failed to get the Cloud Run service for the function'
f' [{function_name}].'
)
self._PrintSuccessMessage(function_name, service.urls)
def _PrintSuccessMessage(self, function_name, urls):
log.status.Print()
log.status.Print(
f'Function {function_name} has been detached successfully! Your'
' function will continue to be available at the following endpoints:'
)
for url in urls:
log.status.Print(f'* {url}')
log.status.Print(
'Any existing event triggers associated with your function will'
' continue to work and can be managed through Eventarc API.\n'
'Reminder, your function can now be managed through the Cloud Run API. '
)
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class DetachBeta(Detach):
"""Detach a Cloud Functions v2 function from its existing environment and make it a native Cloud Run function."""
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class DetachAlpha(DetachBeta):
"""Detach a Cloud Functions v2 function from its existing environment and make it a native Cloud Run function."""

View File

@@ -0,0 +1,30 @@
# -*- 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.
"""List types of events that can be a trigger for a Google Cloud Function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import argparse
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.calliope import base
from googlecloudsdk.core import properties
class EventTypes(base.Group):
"""List types of events that can be a trigger for a Google Cloud Function."""

View File

@@ -0,0 +1,83 @@
# -*- 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.
"""List types of events that can be a trigger for a Google Cloud Function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions.v1.event_types.list import command as command_v1
from googlecloudsdk.command_lib.functions.v2.event_types.list import command as command_v2
_DISPLAY_INFO_V1_FORMAT = """
table(provider.label:label="EVENT_PROVIDER":sort=1,
label:label="EVENT_TYPE":sort=2,
event_is_optional.yesno('Yes'):label="EVENT_TYPE_DEFAULT",
resource_type.value.name:label="RESOURCE_TYPE",
resource_is_optional.yesno('Yes'):label="RESOURCE_OPTIONAL"
)
"""
_DISPLAY_INFO_V2_FORMAT = """
table(name:sort=1,
description
)
"""
_DETAILED_HELP = {
'DESCRIPTION': """
`{command}` displays types of events that can be a trigger for a Google Cloud
Function.
* For an event type, `EVENT_TYPE_DEFAULT` marks whether the given event type
is the default (in which case the `--trigger-event` flag may be omitted).
* For a resource, `RESOURCE_OPTIONAL` marks whether the resource has a
corresponding default value (in which case the `--trigger-resource` flag
may be omitted).
""",
}
@base.ReleaseTracks(base.ReleaseTrack.GA)
class List(base.Command):
"""List types of events that can be a trigger for a Google Cloud Function."""
detailed_help = _DETAILED_HELP
@staticmethod
def Args(parser):
flags.AddGen2Flag(parser, operates_on_existing_function=False)
def Run(self, args):
if flags.ShouldUseGen2():
if not args.IsSpecified('format'):
args.format = _DISPLAY_INFO_V2_FORMAT
return command_v2.Run(args, self.ReleaseTrack())
else:
if not args.IsSpecified('format'):
args.format = _DISPLAY_INFO_V1_FORMAT
return command_v1.Run(args)
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class ListBeta(List):
"""List types of events that can be a trigger for a Google Cloud Function."""
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class ListAlpha(ListBeta):
"""List types of events that can be a trigger for a Google Cloud Function."""

View File

@@ -0,0 +1,61 @@
# -*- 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.
"""Gets IAM policy for a Google Cloud Function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions import util
from googlecloudsdk.command_lib.functions.v1.get_iam_policy import command as command_v1
from googlecloudsdk.command_lib.functions.v2.get_iam_policy import command as command_v2
@base.ReleaseTracks(base.ReleaseTrack.GA)
class GetIamPolicy(util.FunctionResourceCommand, base.ListCommand):
"""Get IAM policy for a Google Cloud Function."""
detailed_help = {
'DESCRIPTION': '{description}',
'EXAMPLES': """\
To get the iam policy for `FUNCTION-1` run:
$ {command} FUNCTION-1
""",
}
@staticmethod
def Args(parser):
"""Registers flags for this command."""
flags.AddFunctionResourceArg(parser, 'to get IAM policy for')
flags.AddGen2Flag(parser, hidden=True)
def _RunV1(self, args):
return command_v1.Run(args)
def _RunV2(self, args):
return command_v2.Run(args, self.ReleaseTrack())
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class GetIamPolicyBeta(GetIamPolicy):
"""Gets IAM policy for a Google Cloud Function."""
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class GetIamPolicyAlpha(GetIamPolicyBeta):
"""Gets IAM policy for a Google Cloud Function."""

View File

@@ -0,0 +1,153 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""Lists Google Cloud Functions."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import itertools
from googlecloudsdk.api_lib.functions import transforms
from googlecloudsdk.api_lib.functions.v1 import util as api_util_v1
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import parser_extensions
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions.v1 import decorator as decorator_v1
from googlecloudsdk.command_lib.functions.v1.list import command as command_v1
from googlecloudsdk.command_lib.functions.v2.list import command as command_v2
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.GA)
class List(base.ListCommand):
"""List Google Cloud Functions."""
@staticmethod
def Args(parser):
parser.add_argument(
'--regions',
metavar='REGION',
help=(
'Regions containing functions to list. By default, functions '
'from the region configured in [functions/region] property are '
'listed.'
),
type=arg_parsers.ArgList(min_length=1),
default=['-'],
)
flags.AddV2Flag(parser)
parser.display_info.AddFormat("""
table(
name.basename():sort=1,
state():label=STATE,
trigger():label=TRIGGER,
name.scope("locations").segment(0):label=REGION,
generation():label=ENVIRONMENT
)""")
base.URI_FLAG.RemoveFromParser(parser)
def Run(self, args):
if args.v2:
return command_v2.Run(args, self.ReleaseTrack())
list_v2_generator = command_v2.Run(
args, self.ReleaseTrack(), 'environment="GEN_2"'
)
v1_regions = [r.locationId for r in api_util_v1.ListRegions()]
# Make a copy of the args for v1 that excludes v2-only regions.
# '-' is the default value, which corresponds to all regions.
list_v1_args = parser_extensions.Namespace(
limit=args.limit,
regions=[r for r in args.regions if r == '-' or r in v1_regions],
)
list_v1_generator = command_v1.Run(list_v1_args)
# respect the user overrides for all other cases.
return itertools.chain(list_v2_generator, list_v1_generator)
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class ListBeta(List):
"""List Google Cloud Functions."""
@staticmethod
def Args(parser):
parser.add_argument(
'--regions',
metavar='REGION',
help=(
'Regions containing functions to list. By default, functions '
'from the region configured in [functions/region] property are '
'listed.'
),
type=arg_parsers.ArgList(min_length=1),
default=['-'],
)
flags.AddV2Flag(parser)
parser.display_info.AddTransforms(transforms.GetTransformsBeta())
parser.display_info.AddFormat("""
table(
name.basename():sort=1,
state():label=STATE,
trigger():label=TRIGGER,
name.scope("locations").segment(0):label=REGION,
generation():label=ENVIRONMENT,
upgradestate():label=UPGRADE_STATE
)""")
base.URI_FLAG.RemoveFromParser(parser)
def Run(self, args):
if args.v2:
return command_v2.Run(args, self.ReleaseTrack())
list_gen2_generator_v2 = command_v2.Run(
args,
self.ReleaseTrack(),
'environment="GEN_2"',
)
v1_regions = [r.locationId for r in api_util_v1.ListRegions()]
# Make a copy of the args for v1 that excludes v2-only regions.
# '-' is the default value, which corresponds to all regions.
gen1_regions = [r for r in args.regions if r == '-' or r in v1_regions]
gen1_args = parser_extensions.Namespace(
limit=args.limit,
regions=gen1_regions,
)
list_gen1_generator_v1 = command_v1.Run(gen1_args)
list_gen1_generator_v2 = command_v2.Run(
gen1_args,
self.ReleaseTrack(),
'environment="GEN_1"',
)
return itertools.chain(
list_gen2_generator_v2,
decorator_v1.decorate_v1_generator_with_v2_api_info(
list_gen1_generator_v1, list_gen1_generator_v2
),
)
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class ListAlpha(ListBeta):
"""List Google Cloud Functions."""

View File

@@ -0,0 +1,33 @@
# -*- 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.
"""Manage local instances of Google Cloud Functions."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import argparse
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.calliope import base
from googlecloudsdk.core import properties
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class Local(base.Group):
"""Manage local instances of Google Cloud Functions."""
pass

View File

@@ -0,0 +1,58 @@
# -*- 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.
"""Call a locally deployed Google Cloud Function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.functions import call_util
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions.local import flags as local_flags
from googlecloudsdk.command_lib.functions.local import util
import six
_DETAILED_HELP = {
'DESCRIPTION': """
`{command}` Call a locally deployed Google Cloud Function.
""",
}
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class Call(base.Command):
"""Call a locally deployed Google Cloud Function."""
detailed_help = _DETAILED_HELP
@staticmethod
def Args(parser):
local_flags.AddDeploymentNameFlag(parser)
data_flag_group = parser.add_mutually_exclusive_group()
flags.AddDataFlag(data_flag_group)
flags.AddCloudEventsFlag(data_flag_group)
def Run(self, args):
util.ValidateDependencies()
name = args.NAME[0]
port = util.FindContainerPort(name)
localhost = 'http://localhost:' + six.text_type(port)
return call_util.MakePostRequest(localhost, args)

View File

@@ -0,0 +1,50 @@
# -*- 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.
"""Delete a locally deployed Google Cloud Function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.functions.local import flags as local_flags
from googlecloudsdk.command_lib.functions.local import util
from googlecloudsdk.core import log
_DETAILED_HELP = {
'DESCRIPTION': """
`{command}` Delete a locally deployed Google Cloud Function.
""",
}
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class Delete(base.Command):
"""Delete a locally deployed Google Cloud Function."""
detailed_help = _DETAILED_HELP
@staticmethod
def Args(parser):
local_flags.AddDeploymentNameFlag(parser)
def Run(self, args):
util.ValidateDependencies()
name = args.NAME[0]
if not util.ContainerExists(name):
raise util.ContainerNotFoundException(
'The container ' + name + ' does not exist.')
util.RemoveDockerContainer(name)
log.status.Print('The container ' + name + ' has been deleted.')

View File

@@ -0,0 +1,164 @@
# -*- 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.
"""Deploys a function locally."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import json
import textwrap
import typing
from googlecloudsdk.api_lib.functions.v2 import client as client_v2
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.calliope import parser_extensions
from googlecloudsdk.command_lib.functions import flags as flag_util
from googlecloudsdk.command_lib.functions import source_util
from googlecloudsdk.command_lib.functions.local import flags as local_flags
from googlecloudsdk.command_lib.functions.local import util
from googlecloudsdk.command_lib.functions.v2.deploy import env_vars_util
from googlecloudsdk.command_lib.util.args import map_util
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
from googlecloudsdk.core.util import files as file_utils
_LOCAL_DEPLOY_MESSAGE = textwrap.dedent("""\
Your function {name} is serving at localhost:{port}.
To call this locally deployed function using gcloud:
gcloud alpha functions local call {name} [--data=DATA] | [--cloud-event=CLOUD_EVENT]
To call local HTTP functions using curl:
curl -m 60 -X POST localhost:{port} -H "Content-Type: application/json" -d '{{}}'
To call local CloudEvent and Background functions using curl, please see:
https://cloud.google.com/functions/docs/running/calling
""")
_DETAILED_HELP = {
'DESCRIPTION': """
`{command}` Deploy a Google Cloud Function locally.
""",
}
_REGION = 'us-central1'
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class Deploy(base.Command):
"""Deploy a Google Cloud Function locally."""
detailed_help = _DETAILED_HELP
@staticmethod
def Args(parser):
local_flags.AddDeploymentNameFlag(parser)
local_flags.AddPortFlag(parser)
local_flags.AddBuilderFlag(parser)
flag_util.AddEntryPointFlag(parser)
flag_util.AddRuntimeFlag(parser)
flag_util.AddIgnoreFileFlag(parser)
# TODO(b/296916846): Add memory and CPU flags
flag_util.AddSourceFlag(parser)
env_vars_util.AddBuildEnvVarsFlags(parser)
env_vars_util.AddUpdateEnvVarsFlags(parser)
# Add NO-OP gen2 flag for user familiarity
flag_util.AddGen2Flag(parser, hidden=True)
def Run(self, args):
util.ValidateDependencies()
labels = self._CreateAndUpdateLabels(args)
client = client_v2.FunctionsClient(release_track=base.ReleaseTrack.ALPHA)
runtimes = sorted({r.name for r in client.ListRuntimes(_REGION).runtimes})
flags = labels.get('flags')
self._ValidateFlags(flags, runtimes)
name = args.NAME[0]
with file_utils.TemporaryDirectory() as tmp_dir:
path = source_util.CreateSourcesZipFile(
tmp_dir,
source_path=flags.get('source', '.'),
ignore_file=flags.get('ignore-file')
)
util.RunPack(name=name,
builder=flags.get('--builder'),
runtime=flags.get('--runtime'),
entry_point=flags.get('--entry-point'),
path=path,
build_env_vars=labels.get('build-env-vars'))
util.RunDockerContainer(name=name,
port=flags.get('--port', '8080'),
env_vars=labels.get('env-vars'),
labels=labels)
log.status.Print(_LOCAL_DEPLOY_MESSAGE.format(
name=name, port=flags.get('--port', '8080')))
def _CreateAndUpdateLabels(
self, args: parser_extensions.Namespace) -> typing.Dict[str, typing.Any]:
labels = {}
old_labels = util.GetDockerContainerLabels(args.NAME[0])
old_flags = json.loads(old_labels.get('flags', '{}'))
old_env_vars = json.loads(old_labels.get('env-vars', '{}'))
old_build_env_vars = json.loads(old_labels.get('build-env-vars', '{}'))
labels['flags'] = self._ApplyNewFlags(args, old_flags)
env_vars = map_util.GetMapFlagsFromArgs('env-vars', args)
labels['env-vars'] = map_util.ApplyMapFlags(old_env_vars, **env_vars)
build_env_vars = map_util.GetMapFlagsFromArgs('build-env-vars', args)
labels['build-env-vars'] = map_util.ApplyMapFlags(
old_build_env_vars, **build_env_vars)
return labels
def _ApplyNewFlags(self, args: parser_extensions.Namespace,
old_flags: typing.Dict[str, str]) -> typing.Dict[str, str]:
flags = {**old_flags, **args.GetSpecifiedArgs()}
flags = {k: v for (k, v) in flags.items()
if not('NAME' in k or 'env-vars' in k)}
return flags
def _ValidateFlags(self, flags: typing.Dict[str, str],
runtimes: typing.Set[str]) -> None:
if '--entry-point' not in flags:
raise exceptions.RequiredArgumentException(
'--entry-point', 'Flag `--entry-point` required.'
)
# Require runtime if builder not specified.
if '--builder' not in flags and '--runtime' not in flags:
flags['--runtime'] = self._PromptUserForRuntime(runtimes)
if flags.get('--runtime') not in runtimes:
log.out.Print('--runtime must be one of the following:')
flags['--runtime'] = self._PromptUserForRuntime(runtimes)
def _PromptUserForRuntime(self, runtimes: typing.Set[str]) -> str:
if not console_io.CanPrompt():
raise exceptions.RequiredArgumentException(
'--runtime', 'Flag `--runtime` required when builder not specified.'
)
idx = console_io.PromptChoice(
runtimes, message='Please select a runtime:\n'
)
return runtimes[idx]

View File

@@ -0,0 +1,28 @@
# -*- 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.
"""Display log entries produced by Google Cloud Functions."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
class Logs(base.Group):
"""Display log entries produced by Google Cloud Functions."""
pass

View File

@@ -0,0 +1,284 @@
# -*- coding: utf-8 -*- #
# Copyright 2015 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.
"""Displays log entries produced by Google Cloud Functions."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import datetime
from googlecloudsdk.api_lib.functions.v1 import util as util_v1
from googlecloudsdk.api_lib.functions.v2 import client as client_v2
from googlecloudsdk.api_lib.logging import common as logging_common
from googlecloudsdk.api_lib.logging import util as logging_util
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import parser_extensions
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions import util
from googlecloudsdk.core import log
from googlecloudsdk.core import properties
from googlecloudsdk.core import resources
import six
_DEFAULT_TABLE_FORMAT = 'table(level,name,execution_id,time_utc,log)'
def _GetFunctionRef(name):
# type: (str) -> resources.Resource | None
if not name:
return None
return resources.REGISTRY.Parse(
name,
params={
'projectsId': properties.VALUES.core.project.GetOrFail(),
'locationsId': properties.VALUES.functions.region.GetOrFail(),
},
collection='cloudfunctions.projects.locations.functions',
)
def _CreateGen1LogFilterBase(function_ref, region):
"""Generates Gen1-specific log filter base."""
log_filter = [
'resource.type="cloud_function"',
'resource.labels.region="{}"'.format(region),
'logName:"cloud-functions"',
]
if function_ref:
function_id = function_ref.functionsId
log_filter.append('resource.labels.function_name="{}"'.format(function_id))
return ' '.join(log_filter)
def _CreateGen2LogFilterBase(function_ref, region):
"""Generates Gen2-specific log filter base."""
log_filter = [
'resource.type="cloud_run_revision"',
'resource.labels.location="{}"'.format(region),
'logName:"run.googleapis.com"',
'labels."goog-managed-by"="cloudfunctions"',
]
if function_ref:
# To conform to Cloud Run resource formats, GCFv2 functions' service names
# are the function ID lower-cased with '_' replaced with '-'.
# Context: go/upper-case-function-ids
service_name = function_ref.functionsId.lower().replace('_', '-')
log_filter.append('resource.labels.service_name="{}"'.format(service_name))
return ' '.join(log_filter)
def _CreateLogFilter(args):
# type: (parser_extensions.Namespace) -> str
"""Creates the filter for retrieving function logs based on the given args.
Args:
args: The arguments that were provided to this command invocation.
Returns:
"""
function_ref = _GetFunctionRef(args.name)
region = properties.VALUES.functions.region.GetOrFail()
if flags.ShouldUseGen1():
log_filter = [_CreateGen1LogFilterBase(function_ref, region)]
elif flags.ShouldUseGen2():
log_filter = [_CreateGen2LogFilterBase(function_ref, region)]
else:
log_filter = [
'({}) OR ({})'.format(
_CreateGen1LogFilterBase(function_ref, region),
_CreateGen2LogFilterBase(function_ref, region),
)
]
# Append common filters
if args.execution_id:
log_filter.append('labels.execution_id="{}"'.format(args.execution_id))
if args.min_log_level:
log_filter.append('severity>={}'.format(args.min_log_level.upper()))
if args.end_time:
log_filter.append(
'timestamp<="{}"'.format(logging_util.FormatTimestamp(args.end_time))
)
log_filter.append(
'timestamp>="{}"'.format(
logging_util.FormatTimestamp(
args.start_time
or datetime.datetime.utcnow() - datetime.timedelta(days=7)
)
)
)
return ' '.join(log_filter)
def _YieldLogEntries(entries):
"""Processes the given entries to yield rows.
Args:
entries: the log entries to process.
Yields:
Rows with level, name, execution_id, time_utc, and log properties.
"""
for entry in entries:
message = entry.textPayload
if entry.jsonPayload:
props = [
prop.value
for prop in entry.jsonPayload.additionalProperties
if prop.key == 'message'
]
if len(props) == 1 and hasattr(props[0], 'string_value'):
message = props[0].string_value
row = {'log': message}
if entry.severity:
severity = six.text_type(entry.severity)
if severity in flags.SEVERITIES:
# Use short form (first letter) for expected severities.
row['level'] = severity[0]
else:
# Print full form of unexpected severities.
row['level'] = severity
if entry.resource and entry.resource.labels:
for label in entry.resource.labels.additionalProperties:
if label.key in ['function_name', 'service_name']:
row['name'] = label.value
if entry.labels:
for label in entry.labels.additionalProperties:
if label.key == 'execution_id':
row['execution_id'] = label.value
if entry.timestamp:
row['time_utc'] = util.FormatTimestamp(entry.timestamp)
yield row
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.GA)
class GetLogs(base.ListCommand):
"""Display log entries produced by Google Cloud Functions."""
@staticmethod
def Args(parser):
# type: (parser_extensions.ArgumentParser) -> None
"""Register flags for this command."""
flags.AddRegionFlag(
parser,
help_text='Only show logs generated by functions in the region.',
)
base.LIMIT_FLAG.RemoveFromParser(parser)
parser.add_argument(
'name',
nargs='?',
help=(
'Name of the function which logs are to be displayed. If no name '
'is specified, logs from all functions are displayed.'
),
)
parser.add_argument(
'--execution-id',
help='Execution ID for which logs are to be displayed.',
)
parser.add_argument(
'--start-time',
required=False,
type=arg_parsers.Datetime.Parse,
help=(
'Return only log entries in which timestamps are not earlier '
'than the specified time. If *--start-time* is not specified, a '
'default start time of 1 week ago is assumed. See $ gcloud '
'topic datetimes for information on time formats.'
),
)
parser.add_argument(
'--end-time',
required=False,
type=arg_parsers.Datetime.Parse,
help=(
'Return only log entries which timestamps are not later than '
'the specified time. If *--end-time* is specified but '
'*--start-time* is not, the command returns *--limit* latest '
'log entries which appeared before --end-time. See '
'*$ gcloud topic datetimes* for information on time formats.'
),
)
parser.add_argument(
'--limit',
required=False,
type=arg_parsers.BoundedInt(1, 1000),
default=20,
help=(
'Number of log entries to be fetched; must not be greater than '
'1000. Note that the most recent entries in the specified time '
'range are returned, rather than the earliest.'
),
)
flags.AddMinLogLevelFlag(parser)
parser.display_info.AddCacheUpdater(None)
flags.AddGen2Flag(parser)
@util_v1.CatchHTTPErrorRaiseHTTPException
def Run(self, args):
# type: (parser_extensions.Namespace) -> None
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
A generator of objects representing log entries.
"""
if not args.IsSpecified('format'):
args.format = _DEFAULT_TABLE_FORMAT
log_filter = _CreateLogFilter(args)
entries = list(
logging_common.FetchLogs(log_filter, order_by='DESC', limit=args.limit)
)
if args.name and not entries:
client = client_v2.FunctionsClient(self.ReleaseTrack())
function_ref = _GetFunctionRef(args.name)
if not client.GetFunction(function_ref.RelativeName()):
# The function doesn't exist in the given region.
log.warning(
'There is no function named `{}` in region `{}`. Perhaps you '
'meant to specify `--region` or update the `functions/region` '
'configuration property?'.format(
function_ref.functionsId, function_ref.locationsId
)
)
return _YieldLogEntries(entries)
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class GetLogsBeta(GetLogs):
"""Display log entries produced by Google Cloud Functions."""
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class GetLogsAlpha(GetLogsBeta):
"""Display log entries produced by Google Cloud Functions."""

View File

@@ -0,0 +1,28 @@
# -*- 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.
"""List regions available to Google Cloud Functions."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
class Regions(base.Group):
"""List regions available to Google Cloud Functions."""
pass

View File

@@ -0,0 +1,72 @@
# -*- 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.
"""List regions available to Google Cloud Functions."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.functions.v1 import util
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions.v1.regions.list import command as command_v1
from googlecloudsdk.command_lib.functions.v2.regions.list import command as command_v2
def _CommonArgs(parser):
parser.display_info.AddFormat('table(name)')
parser.display_info.AddUriFunc(flags.GetLocationsUri)
flags.AddGen2Flag(parser, operates_on_existing_function=False)
@base.ReleaseTracks(base.ReleaseTrack.GA)
class List(base.ListCommand):
"""List regions available to Google Cloud Functions."""
@staticmethod
def Args(parser):
"""Registers flags for this command."""
_CommonArgs(parser)
@util.CatchHTTPErrorRaiseHTTPException
def Run(self, args):
"""This is what gets called when the user runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
List of cloudfunctions_v1.Location or cloudfunctions_v2.Location:
List of GCF regions
Raises:
FunctionsError: If the user doesn't confirm on prompt.
"""
if flags.ShouldUseGen2():
return command_v2.Run(args, self.ReleaseTrack())
else:
return command_v1.Run(args)
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class ListBeta(List):
"""List regions available to Google Cloud Functions."""
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class ListAlpha(ListBeta):
"""List regions available to Google Cloud Functions."""

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.
"""Removes an IAM policy binding from a Google Cloud Function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions import util
from googlecloudsdk.command_lib.functions.v1.remove_iam_policy_binding import command as command_v1
from googlecloudsdk.command_lib.functions.v2.remove_iam_policy_binding import command as command_v2
from googlecloudsdk.command_lib.iam import iam_util
_DETAILED_HELP = {
'DESCRIPTION': '{description}',
'EXAMPLES': """\
To remove the iam policy binding for `FUNCTION-1` from role
`ROLE-1` for member `MEMBER-1` run:
$ {command} FUNCTION-1 --member=MEMBER-1 --role=ROLE-1
""",
}
@base.ReleaseTracks(base.ReleaseTrack.GA)
class RemoveIamPolicyBinding(util.FunctionResourceCommand):
"""Removes an IAM policy binding from a Google Cloud Function."""
detailed_help = _DETAILED_HELP
@staticmethod
def Args(parser):
"""Registers flags for this command."""
flags.AddFunctionResourceArg(parser, 'to remove IAM policy binding from')
iam_util.AddArgsForRemoveIamPolicyBinding(parser)
flags.AddGen2Flag(parser, hidden=True)
def _RunV1(self, args):
return command_v1.Run(args)
def _RunV2(self, args):
return command_v2.Run(args, self.ReleaseTrack())
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class RemoveIamPolicyBindingBeta(RemoveIamPolicyBinding):
"""Removes an IAM policy binding from a Google Cloud Function."""
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class RemoveIamPolicyBindingAlpha(RemoveIamPolicyBindingBeta):
"""Removes an IAM policy binding from a Google Cloud Function."""

View File

@@ -0,0 +1,91 @@
# -*- 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.
"""Removes an invoker binding from the IAM policy of a Google Cloud Function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.functions.v1 import util as api_util_v1
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import parser_extensions
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions import util
from googlecloudsdk.command_lib.functions.v2.remove_invoker_policy_binding import command as command_v2
from googlecloudsdk.command_lib.iam import iam_util
_DETAILED_HELP = {
'DESCRIPTION': """\
Removes the invoker role IAM policy binding that allows the specified
member to invoke the specified function.
For Cloud Functions (1st gen), this removes the Cloud Functions Invoker
binding from the IAM policy of the specified function.
For Cloud Functions (2nd gen), this removes the Cloud Run Invoker binding
from the IAM policy of the specified function's underlying Cloud Run
service.
""",
'EXAMPLES': """\
To remove the invoker role policy binding for `FUNCTION-1` for member
`MEMBER-1` run:
$ {command} FUNCTION-1 --member=MEMBER-1
""",
}
@base.ReleaseTracks(base.ReleaseTrack.GA)
class RemoveInvokerPolicyBinding(util.FunctionResourceCommand):
"""Removes an invoker binding from the IAM policy of a Google Cloud Function.
This command applies to Cloud Functions 2nd gen only.
"""
detailed_help = _DETAILED_HELP
@staticmethod
def Args(parser):
"""Registers flags for this command."""
flags.AddFunctionResourceArg(parser, 'to remove the invoker binding from')
flags.AddGen2Flag(parser, 'to remove the invoker binding from', hidden=True)
iam_util.AddMemberFlag(parser, 'to remove from the IAM policy', False)
def _RunV1(self, args: parser_extensions.Namespace):
return api_util_v1.RemoveFunctionIamPolicyBindingIfFound(
args.CONCEPTS.name.Parse().RelativeName(),
member=args.member,
role='roles/cloudfunctions.invoker',
)
def _RunV2(self, args: parser_extensions.Namespace):
return command_v2.Run(args, self.ReleaseTrack())
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class RemoveInvokerPolicyBindingBeta(RemoveInvokerPolicyBinding):
"""Removes an invoker binding from the IAM policy of a Google Cloud Function.
This command applies to Cloud Functions 2nd gen only.
"""
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class RemoveInvokerPolicyBindingAlpha(RemoveInvokerPolicyBindingBeta):
"""Removes an invoker binding from the IAM policy of a Google Cloud Function.
This command applies to Cloud Functions 2nd gen only.
"""

View File

@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*- #
# Copyright 2021 Google LLC. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""View runtimes available to Google Cloud Functions."""
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 Runtimes(base.Group):
"""List runtimes available to Google Cloud Functions."""
pass

View File

@@ -0,0 +1,65 @@
# -*- 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.
"""List runtimes available to Google Cloud Functions."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions.v2.runtimes.list import command as command_v2
@base.ReleaseTracks(base.ReleaseTrack.GA)
class List(base.ListCommand):
"""List runtimes available to Google Cloud Functions."""
detailed_help = {
'EXAMPLES':
"""\
To list the available runtimes, run:
$ {command}
""",
}
@staticmethod
def Args(parser):
"""Registers flags for this command."""
parser.display_info.AddFormat("""
table(
name,
stage,
environments()
)
""")
parser.display_info.AddUriFunc(flags.GetLocationsUri)
flags.AddRegionFlag(
parser, help_text='Only show runtimes within the region.')
def Run(self, args):
return command_v2.Run(args, self.ReleaseTrack())
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class ListBeta(List):
"""List runtimes available to Google Cloud Functions."""
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class ListAlpha(ListBeta):
"""List runtimes available to Google Cloud Functions."""

View File

@@ -0,0 +1,62 @@
# -*- 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.
"""Sets IAM policy for a Google Cloud Function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions import util
from googlecloudsdk.command_lib.functions.v1.set_iam_policy import command as command_v1
from googlecloudsdk.command_lib.functions.v2.set_iam_policy import command as command_v2
@base.ReleaseTracks(base.ReleaseTrack.GA)
class SetIamPolicy(util.FunctionResourceCommand):
"""Sets IAM policy for a Google Cloud Function."""
detailed_help = {
'DESCRIPTION': '{description}',
'EXAMPLES': """\
To set the iam policy for `FUNCTION-1` to the policy defined in `POLICY-FILE-1` run:
$ {command} FUNCTION-1 POLICY-FILE-1
""",
}
@staticmethod
def Args(parser):
"""Register flags for this command."""
flags.AddFunctionResourceArg(parser, 'to get IAM policy for')
flags.AddIAMPolicyFileArg(parser)
flags.AddGen2Flag(parser, hidden=True)
def _RunV1(self, args):
return command_v1.Run(args)
def _RunV2(self, args):
return command_v2.Run(args, self.ReleaseTrack())
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class SetIamPolicyBeta(SetIamPolicy):
"""Sets IAM policy for a Google Cloud Function."""
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class SetIamPolicyAlpha(SetIamPolicyBeta):
"""Sets IAM policy for a Google Cloud Function."""

View File

@@ -0,0 +1,393 @@
# -*- 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.
"""Upgrade a 1st gen Cloud Function to the Cloud Run function."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import collections
from googlecloudsdk.api_lib.functions import api_enablement
from googlecloudsdk.api_lib.functions.v2 import client as client_v2
from googlecloudsdk.api_lib.functions.v2 import exceptions
from googlecloudsdk.api_lib.functions.v2 import util as api_util
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions as calliope_exceptions
from googlecloudsdk.command_lib.eventarc import types as trigger_types
from googlecloudsdk.command_lib.functions import flags
from googlecloudsdk.command_lib.functions import run_util
from googlecloudsdk.command_lib.functions import service_account_util
from googlecloudsdk.command_lib.functions.v2 import deploy_util
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
import six
SUPPORTED_EVENT_TYPES = (
'google.pubsub.topic.publish',
'providers/cloud.pubsub/eventTypes/topic.publish',
)
UpgradeAction = collections.namedtuple(
'UpgradeAction',
[
'target_state',
'prompt_msg',
'op_description',
'success_msg',
],
)
_ABORT_GUIDANCE_MSG = (
'You can abort the upgrade process at any time by rerunning this command'
' with the --abort flag.'
)
_SETUP_CONFIG_ACTION = UpgradeAction(
target_state='SETUP_FUNCTION_UPGRADE_CONFIG_SUCCESSFUL',
prompt_msg=(
'This creates a Cloud Run function with the same name [{}], code, and'
' configuration as the 1st gen function. The 1st gen function will'
' continue to serve traffic until you redirect traffic to the Cloud Run'
' function in the next step.\n\nTo learn more about the differences'
' between 1st gen and Cloud Run functions, visit:'
' https://cloud.google.com/functions/docs/concepts/version-comparison'
),
op_description=(
'Setting up the upgrade for function. Please wait while we'
' duplicate the 1st gen function configuration and code to a Cloud Run'
' function.'
),
success_msg=(
'The Cloud Run function is now ready for testing:\n {}\nView the'
' function upgrade testing guide for steps on how to test the function'
' before redirecting traffic to it.\n\nOnce you are ready to redirect'
' traffic, rerun this command with the --redirect-traffic flag.'
)
+ '\n\n'
+ _ABORT_GUIDANCE_MSG,
)
_REDIRECT_TRAFFIC_ACTION = UpgradeAction(
target_state='REDIRECT_FUNCTION_UPGRADE_TRAFFIC_SUCCESSFUL',
prompt_msg=(
'This will redirect all traffic from the 1st gen function [{}] to its'
' Cloud Run function copy. Please ensure that you have tested the Cloud'
' Run function before proceeding.'
),
op_description='Redirecting traffic to the Cloud Run function.',
success_msg=(
'The Cloud Run function is now serving all traffic.'
' If you experience issues, rerun this command with the'
' --rollback-traffic flag. Otherwise, once you are ready to finalize'
' the upgrade, rerun this command with the --commit flag.'
)
+ '\n\n'
+ _ABORT_GUIDANCE_MSG,
)
_ROLLBACK_TRAFFIC_ACTION = UpgradeAction(
target_state='SETUP_FUNCTION_UPGRADE_CONFIG_SUCCESSFUL',
prompt_msg=(
'This will rollback all traffic from the Cloud Run function copy [{}]'
' to the original 1st gen function. The Cloud Run function is still'
' available for testing.'
),
op_description='Rolling back traffic to the 1st gen function.',
success_msg=(
'The 1st gen function is now serving all traffic. The Cloud Run'
' function is still available for testing.'
)
+ '\n\n'
+ _ABORT_GUIDANCE_MSG,
)
_ABORT_ACTION = UpgradeAction(
target_state='ELIGIBLE_FOR_2ND_GEN_UPGRADE',
prompt_msg=(
'This will abort the upgrade process and delete the Cloud Run function'
' copy of the 1st gen function [{}].'
),
op_description='Aborting the upgrade for function.',
success_msg=(
'Upgrade aborted and the Cloud Run function was successfully deleted.'
),
)
_COMMIT_ACTION = UpgradeAction(
target_state=None,
prompt_msg=(
'This will complete the upgrade process for function [{}] and delete'
' the 1st gen copy.\n\nThis action cannot be undone.'
),
op_description=(
'Completing the upgrade and deleting the 1st gen copy for function.'
),
success_msg=(
'Upgrade completed and the 1st gen copy was successfully'
' deleted.\n\nYour function will continue to be available at the'
' following endpoints:\n{}\nReminder, your function can now be managed'
' through the Cloud Run API. Any event triggers are now Eventarc'
' triggers and can be managed through Eventarc API.'
),
)
# Source: http://cs/f:UpgradeStateMachine.java
_VALID_TRANSITION_ACTIONS = {
'ELIGIBLE_FOR_2ND_GEN_UPGRADE': [_SETUP_CONFIG_ACTION],
'UPGRADE_OPERATION_IN_PROGRESS': [],
'SETUP_FUNCTION_UPGRADE_CONFIG_SUCCESSFUL': [
_REDIRECT_TRAFFIC_ACTION,
_ABORT_ACTION,
],
'SETUP_FUNCTION_UPGRADE_CONFIG_ERROR': [
_SETUP_CONFIG_ACTION,
_ABORT_ACTION,
],
'ABORT_FUNCTION_UPGRADE_ERROR': [_ABORT_ACTION],
'REDIRECT_FUNCTION_UPGRADE_TRAFFIC_SUCCESSFUL': [
_COMMIT_ACTION,
_ROLLBACK_TRAFFIC_ACTION,
_ABORT_ACTION,
],
'REDIRECT_FUNCTION_UPGRADE_TRAFFIC_ERROR': [
_REDIRECT_TRAFFIC_ACTION,
_ABORT_ACTION,
],
'ROLLBACK_FUNCTION_UPGRADE_TRAFFIC_ERROR': [
_ROLLBACK_TRAFFIC_ACTION,
_ABORT_ACTION,
],
'COMMIT_FUNCTION_UPGRADE_SUCCESSFUL': [],
'COMMIT_FUNCTION_UPGRADE_ERROR_ROLLBACK_SAFE': [
_COMMIT_ACTION,
_ROLLBACK_TRAFFIC_ACTION,
_ABORT_ACTION,
],
'COMMIT_FUNCTION_UPGRADE_ERROR': [_COMMIT_ACTION],
} # type: dict[str, list[UpgradeAction]]
def _ValidateStateTransition(upgrade_state, action):
# type: (_,UpgradeAction) -> None
"""Validates whether the action is a valid action for the given upgrade state."""
upgrade_state_str = six.text_type(upgrade_state)
if upgrade_state_str == 'UPGRADE_OPERATION_IN_PROGRESS':
raise exceptions.FunctionsError(
'An upgrade operation is already in progress for this function.'
' Please try again later.'
)
if upgrade_state_str == action.target_state:
raise exceptions.FunctionsError(
'This function is already in the desired upgrade state: {}'.format(
upgrade_state
)
)
if action not in _VALID_TRANSITION_ACTIONS[upgrade_state_str]:
raise exceptions.FunctionsError(
'This function is not eligible for this operation. Its current upgrade'
" state is '{}'.".format(upgrade_state)
)
# Source: http://cs/f:Gen1UpgradeEligibilityValidator.java
def _RaiseNotEligibleForUpgradeError(function):
"""Raises an error when the function is not eligible for upgrade."""
if six.text_type(function.environment) == 'GEN_2':
raise exceptions.FunctionsError(
f'Function [{function.name}] is not eligible for Upgrade. To migrate to'
' Cloud Run function, please detach the function using `gcloud'
' functions detach` instead.'
)
if ':' in api_util.GetProject():
raise exceptions.FunctionsError(
f'Function [{function.name}] is not eligible for Cloud Run function'
' upgrade. It is in domain-scoped project that Cloud Run does not'
' support.'
)
if six.text_type(function.state) != 'ACTIVE':
raise exceptions.FunctionsError(
f'Function [{function.name}] is not eligible for Cloud Run function'
f' upgrade. It is in state [{function.state}].'
)
if (
not function.url
and function.eventTrigger.eventType not in SUPPORTED_EVENT_TYPES
):
raise exceptions.FunctionsError(
f'Function [{function.name}] is not eligible for Cloud Run function'
' upgrade. Only HTTP functions and Pub/Sub triggered functions are'
' supported.'
)
raise exceptions.FunctionsError(
f'Function [{function.name}] is not eligible for Cloud Run function'
' upgrade.'
)
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.BETA)
class UpgradeBeta(base.Command):
"""Upgrade a 1st gen Cloud Function to the Cloud Run function."""
detailed_help = {
'DESCRIPTION': '{description}',
'EXAMPLES': """\
To start the upgrade process for a 1st gen function `foo` and create a Cloud Run function copy, run:
$ {command} foo --setup-config
Once you are ready to redirect traffic to the Cloud Run function copy, run:
$ {command} foo --redirect-traffic
If you find you need to do more local testing you can rollback traffic to the 1st gen copy:
$ {command} foo --rollback-traffic
Once you're ready to finish upgrading and delete the 1st gen copy, run:
$ {command} foo --commit
You can abort the upgrade process at any time by running:
$ {command} foo --abort
""",
}
@staticmethod
def Args(parser):
flags.AddFunctionResourceArg(parser, 'to upgrade')
flags.AddUpgradeFlags(parser)
def Run(self, args):
client = client_v2.FunctionsClient(self.ReleaseTrack())
function_ref = args.CONCEPTS.name.Parse()
function_name = function_ref.RelativeName()
function = client.GetFunction(function_name)
if not function:
raise exceptions.FunctionsError(
'Function [{}] does not exist.'.format(function_name)
)
if not function.upgradeInfo:
_RaiseNotEligibleForUpgradeError(function)
upgrade_state = function.upgradeInfo.upgradeState
if (
six.text_type(upgrade_state)
== 'INELIGIBLE_FOR_UPGRADE_UNTIL_REDEPLOYMENT'
):
raise exceptions.FunctionsError(
f'Function [{function.name}] is not eligible for Cloud Run function'
f' upgrade. The runtime [{function.buildConfig.runtime}] is not'
' supported. Please update to a supported runtime instead and try'
' again. Use `gcloud functions runtimes list` to get a list of'
' available runtimes.'
)
action = None
action_fn = None
if args.redirect_traffic:
action = _REDIRECT_TRAFFIC_ACTION
action_fn = client.RedirectFunctionUpgradeTraffic
elif args.rollback_traffic:
action = _ROLLBACK_TRAFFIC_ACTION
action_fn = client.RollbackFunctionUpgradeTraffic
elif args.commit:
action = _COMMIT_ACTION
action_fn = client.CommitFunctionUpgrade
elif args.abort:
action = _ABORT_ACTION
action_fn = client.AbortFunctionUpgrade
elif args.setup_config:
action = _SETUP_CONFIG_ACTION
action_fn = client.SetupFunctionUpgradeConfig
else:
raise calliope_exceptions.OneOfArgumentsRequiredException(
[
'--abort',
'--commit',
'--redirect-traffic',
'--rollback-traffic',
'--setup-config',
],
'One of the upgrade step must be specified.',
)
_ValidateStateTransition(upgrade_state, action)
message = action.prompt_msg.format(function_name)
if not console_io.PromptContinue(message, default=True):
return
if action == _SETUP_CONFIG_ACTION:
# Preliminary checks to ensure APIs and permissions are set up in case
# this is the user's first time deploying a Cloud Run function.
api_enablement.PromptToEnableApiIfDisabled('cloudbuild.googleapis.com')
api_enablement.PromptToEnableApiIfDisabled(
'artifactregistry.googleapis.com'
)
trigger = function.eventTrigger
if not trigger and args.trigger_service_account:
raise calliope_exceptions.InvalidArgumentException(
'--trigger-service-account',
'Trigger service account can only be specified for'
' event-triggered functions.',
)
if trigger and trigger_types.IsPubsubType(trigger.eventType):
deploy_util.ensure_pubsub_sa_has_token_creator_role()
if trigger and trigger_types.IsAuditLogType(trigger.eventType):
deploy_util.ensure_data_access_logs_are_enabled(trigger.eventFilters)
operation = action_fn(function_name, args.trigger_service_account)
else:
operation = action_fn(function_name)
description = action.op_description
api_util.WaitForOperation(
client.client, client.messages, operation, description
)
log.status.Print()
if action == _SETUP_CONFIG_ACTION:
function = client.GetFunction(function_name)
if function.eventTrigger:
# Checks trigger service account has route.invoker permission on the
# project. If not, prompts to add the run invoker role to the function.
service_account_util.ValidateAndBindTriggerServiceAccount(
function,
api_util.GetProject(),
args.trigger_service_account,
is_gen2=False,
)
log.status.Print(
action.success_msg.format(function.upgradeInfo.serviceConfig.uri)
)
elif action == _COMMIT_ACTION:
service = run_util.GetService(function)
urls_strings = ''.join(f'* {url}\n' for url in service.urls)
log.status.Print(action.success_msg.format(urls_strings))
else:
log.status.Print(action.success_msg)
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class UpgradeAlpha(UpgradeBeta):
"""Upgrade a 1st gen Cloud Function to the Cloud Run function."""