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,26 @@
# -*- 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.
"""Command group for spanner databases."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
class Databases(base.Group):
"""Manage Cloud Spanner databases."""
pass

View File

@@ -0,0 +1,34 @@
release_tracks: [ALPHA, BETA, GA]
help_text:
brief: Add IAM policy binding to a Cloud Spanner database.
description: |
Add an IAM policy binding to a Cloud Spanner database. One binding consists of a member,
a role, and an optional condition.
examples: |
To add an IAM policy binding for the role of 'roles/editor' for the user 'test-user@gmail.com'
with database 'my-database' and instance 'my-instance', run:
$ {command} my-database --instance='my-instance' --member='user:test-user@gmail.com' --role='roles/editor'
To add an IAM policy binding which expires at the end of the year 2018 for the role of
'roles/spanner.databaseAdmin' and the user 'test-user@gmail.com' with database 'my-database' and instance 'my-instance', run:
$ {command} my-database --instance='my-instance' --member='user:test-user@gmail.com' --role='roles/spanner.databaseAdmin' --condition='expression=request.time < timestamp("2019-01-01T00:00:00Z"),title=expires_end_of_2018,description=Expires at midnight on 2018-12-31'
See https://cloud.google.com/iam/docs/managing-policies for details of
policy role and member types.
request:
collection: spanner.projects.instances.databases
arguments:
resource:
help_text: The Cloud Spanner database to which to add the IAM policy binding.
spec: !REF googlecloudsdk.command_lib.spanner.resources:database
iam:
enable_condition: true
policy_version: 3
get_iam_policy_version_path: getIamPolicyRequest.options.requestedPolicyVersion

View File

@@ -0,0 +1,108 @@
# -*- 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.
"""Command for spanner database change quorum."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import databases
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import resource_args
@base.DefaultUniverseOnly
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class ChangeQuorum(base.Command):
"""Change quorum of a Cloud Spanner database."""
detailed_help = {
'EXAMPLES': textwrap.dedent("""\
To trigger change quorum from single-region mode to dual-region mode, run:
$ {command} my-database-id --instance=my-instance-id --dual-region
To trigger change quorum from dual-region mode to single-region mode with serving location as `asia-south1`, run:
$ {command} my-database-id --instance=my-instance-id --single-region --serving-location=asia-south1
To trigger change quorum using etag specified, run:
$ {command} my-database-id --instance=my-instance-id --dual-region --etag=ETAG
"""),
}
@staticmethod
def Args(parser):
"""See base class."""
resource_args.AddDatabaseResourceArg(parser, 'to change quorum')
dual_region_or_single_region = parser.add_mutually_exclusive_group(
required=True
)
dual_region_flags = dual_region_or_single_region.add_argument_group(
'Command-line flag for dual-region quorum change:'
)
dual_region_flags.add_argument(
'--dual-region',
required=True,
action='store_true',
help='Switch to dual-region quorum type.',
)
single_region_flags = dual_region_or_single_region.add_argument_group(
'Command-line flags for single-region quorum change:'
)
single_region_flags.add_argument(
'--single-region',
required=True,
action='store_true',
help='Switch to single-region quorum type.',
)
single_region_flags.add_argument(
'--serving-location',
required=True,
help='The cloud Spanner location.',
)
parser.add_argument(
'--etag', help='Used for optimistic concurrency control.'
)
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:
Some value that we want to have printed later.
"""
msgs = apis.GetMessagesModule('spanner', 'v1')
if args.dual_region:
quorum_type = msgs.QuorumType(dualRegion=msgs.DualRegionQuorum())
else:
quorum_type = msgs.QuorumType(
singleRegion=msgs.SingleRegionQuorum(
servingLocation=args.serving_location
)
)
return databases.ChangeQuorum(
args.CONCEPTS.database.Parse(), quorum_type, args.etag
)

View File

@@ -0,0 +1,26 @@
# -*- 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.
"""Command group for managing Spanner database configurations."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class Config(base.Group):
"""Manage Spanner database configurations."""

View File

@@ -0,0 +1,38 @@
release_tracks: [ALPHA]
command_type: CONFIG_EXPORT
help_text:
brief: Export the configuration for a Spanner database.
description: |
*{command}* exports the configuration for a Spanner database.
Database configurations can be exported in
Kubernetes Resource Model (krm) or Terraform HCL formats. The
default format is `krm`.
Specifying `--all` allows you to export the configurations for all
databases within the project.
Specifying `--path` allows you to export the configuration(s) to
a local directory.
examples: |
To export the configuration for a database, run:
$ {command} my-database
To export the configuration for a database to a file, run:
$ {command} my-database --path=/path/to/dir/
To export the configuration for a database in Terraform
HCL format, run:
$ {command} my-database --resource-format=terraform
To export the configurations for all databases within a
project, run:
$ {command} --all
arguments:
resource:
help_text: Database to export the configuration for.
spec: !REF googlecloudsdk.command_lib.spanner.resources:database

View File

@@ -0,0 +1,109 @@
# -*- 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.
"""Command for spanner databases create."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import database_operations
from googlecloudsdk.api_lib.spanner import databases
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import flags
from googlecloudsdk.command_lib.spanner import resource_args
class Create(base.CreateCommand):
"""Create a Cloud Spanner database."""
detailed_help = {
'EXAMPLES':
textwrap.dedent("""\
To create an empty Cloud Spanner database, run:
$ {command} testdb --instance=my-instance-id
To create a Cloud Spanner database with populated schema, run:
$ {command} testdb --instance=my-instance-id
--ddl='CREATE TABLE mytable (a INT64, b INT64) PRIMARY KEY(a)'
To create a Cloud Spanner database with the PostgreSQL dialect, run:
$ {command} testdb --instance=my-instance-id
--database-dialect=POSTGRESQL
"""),
}
@staticmethod
def Args(parser):
"""See base class."""
resource_args.AddDatabaseResourceArg(parser, 'to create')
flags.Ddl(help_text='Semi-colon separated DDL (data definition language) '
'statements to run inside the '
'newly created database. If there is an error in any statement, '
'the database is not created. This option is not supported for '
'the PostgreSQL dialect. Full DDL specification is at '
'https://cloud.google.com/spanner/docs/data-definition-language'
).AddToParser(parser)
flags.DdlFile(
help_text='Path of a file that contains semi-colon separated DDL (data '
'definition language) statements to run inside the newly created '
'database. If there is an error in any statement, the database is not '
'created. This option is not supported for the PostgreSQL dialect. '
'Full DDL specification is at '
'https://cloud.google.com/spanner/docs/data-definition-language.'
' If --ddl_file is set, --ddl is ignored. One line comments starting '
'with -- are ignored.').AddToParser(parser)
flags.ProtoDescriptorsFile(
help_text='Path of a file that contains a protobuf-serialized '
'google.protobuf.FileDescriptorSet message. To generate it, install and'
' run `protoc` with --include_imports and --descriptor_set_out.'
).AddToParser(parser)
base.ASYNC_FLAG.AddToParser(parser)
parser.display_info.AddCacheUpdater(flags.DatabaseCompleter)
resource_args.AddKmsKeyResourceArg(parser,
'to create the Cloud Spanner database')
flags.DatabaseDialect(
help_text='The SQL dialect of the Cloud Spanner Database. '
'GOOGLE_STANDARD_SQL is the default.'
).AddToParser(parser)
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:
Some value that we want to have printed later.
"""
database_ref = args.CONCEPTS.database.Parse()
instance_ref = database_ref.Parent()
kms_key_name_or_names = resource_args.GetAndValidateKmsKeyName(args)
op = databases.Create(
instance_ref,
args.database,
flags.SplitDdlIntoStatements(args),
flags.GetProtoDescriptors(args),
kms_key_name_or_names,
args.database_dialect,
)
if args.async_:
return op
return database_operations.Await(op, 'Creating database')

View File

@@ -0,0 +1,26 @@
# -*- 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.
"""Command group for spanner databases ddl."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
class Ddl(base.Group):
"""Manage the DDL for Cloud Spanner databases."""
pass

View File

@@ -0,0 +1,68 @@
# -*- 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.
"""Command for spanner databases ddl describe."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import databases
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import flags
from googlecloudsdk.command_lib.spanner import resource_args
# TODO(b/305722139) Change @base.DefaultUniverseOnly to
# @base.UniverseCompatible once b/305722139 is fixed.
# See go/gcloud-cli-running-tpc-tests.
@base.DefaultUniverseOnly
class Describe(base.ListCommand):
"""Describe the DDL for a Cloud Spanner database."""
detailed_help = {
'EXAMPLES':
textwrap.dedent("""\
To describe the DDL for a given Cloud Spanner database, run:
$ {command} my-database-id --instance=my-instance-id
"""),
}
@staticmethod
def Args(parser):
"""See base class."""
resource_args.AddDatabaseResourceArg(parser, 'of which the ddl to describe')
parser.display_info.AddCacheUpdater(None)
parser.display_info.AddFormat('value(format("{0};\n"))')
flags.IncludeProtoDescriptors(
help_text=(
'Include debug string of proto bundle descriptors in the output.'
' The output is information only and not meant to be parsed.'
)
).AddToParser(parser)
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:
Some value that we want to have printed later.
"""
return databases.GetDdlWithDescriptors(args.CONCEPTS.database.Parse(), args)

View File

@@ -0,0 +1,82 @@
# -*- 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.
"""Command for spanner databases ddl update."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import database_operations
from googlecloudsdk.api_lib.spanner import databases
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import flags
from googlecloudsdk.command_lib.spanner import resource_args
from googlecloudsdk.core import log
class Update(base.UpdateCommand):
"""Update the DDL for a Cloud Spanner database."""
detailed_help = {
'EXAMPLES':
textwrap.dedent("""\
To add a column to a table in the given Cloud Spanner database, run:
$ {command} my-database-id --instance=my-instance-id
--ddl='ALTER TABLE test_table ADD COLUMN a INT64'
"""),
}
@staticmethod
def Args(parser):
"""See base class."""
resource_args.AddDatabaseResourceArg(parser, 'of which the ddl to update')
flags.Ddl(help_text='Semi-colon separated DDL '
'(data definition language) statements to '
'run inside the database. If a statement fails, all subsequent '
'statements in the batch are automatically cancelled.'
).AddToParser(parser)
flags.DdlFile(
help_text='Path of a file containing semi-colon separated DDL (data '
'definition language) statements to run inside the database. If a '
'statement fails, all subsequent statements in the batch are '
'automatically cancelled. If --ddl_file is set, --ddl is ignored. '
'One line comments starting with -- are ignored.').AddToParser(parser)
flags.ProtoDescriptorsFile(
help_text='Path of a file that contains a protobuf-serialized '
'google.protobuf.FileDescriptorSet message. To generate it, install and'
' run `protoc` with --include_imports and --descriptor_set_out.'
).AddToParser(parser)
base.ASYNC_FLAG.AddToParser(parser)
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:
Some value that we want to have printed later.
"""
op = databases.UpdateDdl(args.CONCEPTS.database.Parse(),
flags.SplitDdlIntoStatements(args),
flags.GetProtoDescriptors(args))
if args.async_:
return log.status.Print(
'Schema update in progress. Operation name={}'.format(op.name))
return database_operations.Await(op, 'Schema updating')

View File

@@ -0,0 +1,78 @@
# -*- 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.
"""Command for spanner databases delete."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import databases
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import resource_args
from googlecloudsdk.core.console import console_io
class Delete(base.DeleteCommand):
"""Delete a Cloud Spanner database.
Delete a Cloud Spanner database.
Note: Cloud Spanner might continue to accept requests for a few seconds
after the database has been deleted.
"""
detailed_help = {
'EXAMPLES':
textwrap.dedent("""\
To delete a Cloud Spanner database, run:
$ {command} my-database-id --instance=my-instance-id
"""),
}
@staticmethod
def Args(parser):
"""See base class."""
resource_args.AddDatabaseResourceArg(parser, 'to delete')
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:
Database delete response, which is empty.
Raises:
HttpException when the database is not found.
"""
database_ref = args.CONCEPTS.database.Parse()
console_io.PromptContinue(
'You are about to delete database: [{}]'.format(database_ref.Name()),
throw_if_unattended=True,
cancel_on_no=True)
# The delete API returns a 200 regardless of whether the database being
# deleted exists. In order to show users feedback for incorrectly
# entered database names, we have to make a request to check if the database
# exists. If the database exists, it's deleted, otherwise, we display the
# error from databases.Get.
database = databases.Get(database_ref)
if database:
return databases.Delete(database_ref)

View File

@@ -0,0 +1,55 @@
# -*- 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.
"""Command for spanner databases describe."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import databases
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import resource_args
class Describe(base.DescribeCommand):
"""Describe a Cloud Spanner database."""
detailed_help = {
'EXAMPLES':
textwrap.dedent("""\
To describe a Cloud Spanner database, run:
$ {command} my-database-id --instance=my-instance-id
"""),
}
@staticmethod
def Args(parser):
"""See base class."""
resource_args.AddDatabaseResourceArg(parser, 'to describe')
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:
Some value that we want to have printed later.
"""
return databases.Get(args.CONCEPTS.database.Parse())

View File

@@ -0,0 +1,256 @@
# -*- 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.
"""Command for spanner databases query."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.spanner import database_sessions
from googlecloudsdk.api_lib.util import apis
from googlecloudsdk.calliope import arg_parsers
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions as c_exceptions
from googlecloudsdk.command_lib.spanner import resource_args
from googlecloudsdk.command_lib.spanner import sql
from googlecloudsdk.command_lib.spanner.sql import QueryHasDml
from googlecloudsdk.command_lib.util.apis import arg_utils
from googlecloudsdk.core import log
from googlecloudsdk.core import resources
DETAILED_HELP = {
'EXAMPLES':
"""\
To execute a SQL SELECT statement against example-database under
example-instance, run:
$ {command} example-database --instance=example-instance --sql='SELECT * FROM MyTable WHERE MyKey = 1'
""",
}
def CreateSession(args, database_role=None):
"""Creates a session.
Args:
args: an argparse namespace. All the arguments that were provided to the
command invocation.
database_role: Cloud Spanner database role which owns this session.
Returns:
A session reference to be used to execute the sql.
"""
session_name = database_sessions.Create(args.CONCEPTS.database.Parse(),
database_role)
return resources.REGISTRY.ParseRelativeName(
relative_name=session_name.name,
collection='spanner.projects.instances.databases.sessions')
def AddBaseArgs(parser):
"""Parses provided arguments to add base arguments used for both Beta and GA.
Args:
parser: an argparse argument parser.
"""
resource_args.AddDatabaseResourceArg(parser,
'to execute the SQL query against')
parser.add_argument(
'--sql',
required=True,
help='The SQL query to issue to the database. Cloud Spanner SQL is '
'described at https://cloud.google.com/spanner/docs/query-syntax')
query_mode_choices = {
'NORMAL': (
'Returns only the query result, without any information about '
'the query plan.'
),
'PLAN': (
'Returns only the query plan, without any result rows or '
'execution statistics information.'
),
'PROFILE': (
'Returns the query plan, overall execution statistics, '
'operator-level execution statistics, along with the result rows.'
),
'WITH_STATS': (
'Returns the overall (but not operator-level) execution statistics '
'along with the results.'
),
'WITH_PLAN_AND_STATS': (
'Returns the query plan, overall (but not operator-level) execution '
'statistics, along with the results.'
),
}
parser.add_argument(
'--query-mode',
default='NORMAL',
type=lambda x: x.upper(),
choices=query_mode_choices,
help='Mode in which the query must be processed.')
parser.add_argument(
'--enable-partitioned-dml',
action='store_true',
help='Execute DML statement using Partitioned DML')
parser.add_argument(
'--timeout',
type=arg_parsers.Duration(),
default='10m',
help='Maximum time to wait for the SQL query to complete. See $ gcloud '
'topic datetimes for information on duration formats.')
msgs = apis.GetMessagesModule('spanner', 'v1')
GetRequestPriorityMapper(msgs).choice_arg.AddToParser(parser)
timestamp_bound_group = parser.add_argument_group(
mutex=True,
help='Read-only query timestamp bound. The default is --strong. See '
'https://cloud.google.com/spanner/docs/timestamp-bounds.')
timestamp_bound_group.add_argument(
'--strong',
action='store_true',
help='Perform a strong query.')
timestamp_bound_group.add_argument(
'--read-timestamp',
metavar='TIMESTAMP',
help='Perform a query at the given timestamp.')
parser.add_argument(
'--database-role',
help='Database role user assumes while accessing the database.')
def GetRequestPriorityMapper(messages):
return arg_utils.ChoiceEnumMapper(
'--priority',
messages.RequestOptions.PriorityValueValuesEnum,
custom_mappings={
'PRIORITY_LOW': 'low',
'PRIORITY_MEDIUM': 'medium',
'PRIORITY_HIGH': 'high',
'PRIORITY_UNSPECIFIED': 'unspecified',
},
help_str='The priority for the execute SQL request.',
)
@base.DefaultUniverseOnly
@base.UnicodeIsSupported
class Query(base.Command):
"""Executes a SQL query against a Cloud Spanner database."""
detailed_help = DETAILED_HELP
@staticmethod
def Args(parser):
"""See base class."""
AddBaseArgs(parser)
def Run(self, args):
"""Runs this command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Some value that we want to have printed later.
"""
msgs = apis.GetMessagesModule('spanner', 'v1')
request_options = msgs.RequestOptions(
priority=GetRequestPriorityMapper(msgs).GetEnumForChoice(args.priority)
)
read_only_options = self.ParseReadOnlyOptions(args)
session = CreateSession(args, args.database_role)
try:
return database_sessions.ExecuteSql(
args.sql,
args.query_mode,
session,
read_only_options,
request_options,
args.enable_partitioned_dml,
args.timeout)
finally:
database_sessions.Delete(session)
def ParseReadOnlyOptions(self, args):
"""Parses the options for a read-only request from command line arguments.
Args:
args: Command line arguments.
Returns:
A ReadOnly message if the query is read-only (not DML), otherwise None.
"""
if QueryHasDml(args.sql):
if args.IsSpecified('strong'):
raise c_exceptions.InvalidArgumentException(
'--strong',
'A timestamp bound cannot be specified for a DML statement.'
)
if args.IsSpecified('read_timestamp'):
raise c_exceptions.InvalidArgumentException(
'--read-timestamp',
'A timestamp bound cannot be specified for a DML statement.'
)
return None
else:
msgs = apis.GetMessagesModule('spanner', 'v1')
if args.IsSpecified('read_timestamp'):
return msgs.ReadOnly(readTimestamp=args.read_timestamp)
elif args.IsSpecified('strong'):
if not args.strong:
raise c_exceptions.InvalidArgumentException(
'--strong',
'`--strong` cannot be set to false. '
'Instead specify a different type of timestamp bound.'
)
else:
return msgs.ReadOnly(strong=True)
else:
# The default timestamp bound is strong.
return msgs.ReadOnly(strong=True)
def Display(self, args, result):
"""Displays the server response to a query.
This is called higher up the stack to over-write default display behavior.
What gets displayed depends on the mode in which the query was run.
'NORMAL': query result rows
'PLAN': query plan without execution statistics
'PROFILE': query result rows and the query plan with execution statistics
Args:
args: The arguments originally passed to the command.
result: The output of the command before display.
"""
display_plan = (
args.query_mode == 'PLAN'
or args.query_mode == 'PROFILE'
or args.query_mode == 'WITH_PLAN_AND_STATS'
)
display_results = args.query_mode != 'PLAN'
if sql.QueryHasAggregateStats(result):
sql.DisplayQueryAggregateStats(result.stats.queryStats, log.out)
if display_plan:
sql.DisplayQueryPlan(result, log.out)
if display_results:
sql.DisplayQueryResults(
result, log.status if args.query_mode == 'PROFILE' else log.out
)

View File

@@ -0,0 +1,58 @@
# -*- 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.
"""Command for spanner databases get-iam-policy."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import databases
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import resource_args
@base.ReleaseTracks(base.ReleaseTrack.GA, base.ReleaseTrack.BETA)
class GetIamPolicy(base.ListCommand):
"""Get the IAM policy for a Cloud Spanner database."""
detailed_help = {
'EXAMPLES':
textwrap.dedent("""\
To print the IAM policy for a given Cloud Spanner database, run:
$ {command} my-database-id
"""),
}
@staticmethod
def Args(parser):
"""See base class."""
resource_args.AddDatabaseResourceArg(parser,
'to get IAM policy binding for')
base.URI_FLAG.RemoveFromParser(parser)
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:
Some value that we want to have printed later.
"""
return databases.GetIamPolicy(args.CONCEPTS.database.Parse())

View File

@@ -0,0 +1,23 @@
- release_tracks: [ALPHA]
help_text:
brief: Get the IAM policy for a Cloud Spanner database.
description: |
*{command}* displays the IAM policy associated with a Cloud Spanner
database. If formatted as JSON, the output can be edited and used as
a policy file for *set-iam-policy*. The output includes an "etag"
field identifying the version emitted and allowing detection of
concurrent policy updates; see
$ {parent} set-iam-policy for additional details.
examples: |
To print the IAM policy for a given Cloud Spanner database, run:
$ {command} my-database
request:
collection: spanner.projects.instances.databases
arguments:
resource:
help_text: The Cloud Spanner database for which to display the IAM policy.
spec: !REF googlecloudsdk.command_lib.spanner.resources:database

View File

@@ -0,0 +1,91 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 Google LLC. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Import data from various source files to Cloud Spanner."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import flags
from googlecloudsdk.command_lib.spanner import migration_backend
from googlecloudsdk.command_lib.util.apis import arg_utils
from googlecloudsdk.core.credentials import store
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class Import(base.BinaryBackedCommand):
"""Import data from various source files to Cloud Spanner."""
detailed_help = {
'EXAMPLES':
textwrap.dedent(text="""\
To import data from a source file to Cloud Spanner:
$ {command} --instance=instanceA --database=databaseA
--table-name=tableA --source-uri=gs://bucket/data.csv --source-format=csv
--schema-uri=gs://bucket/schema.json
$ {command} --instance=instanceA --database=databaseA
--source-uri=gs://bucket/dump.sql --source-format=mysqldump
"""),
}
@staticmethod
def Args(parser):
"""Register the flags for this command."""
flags.Instance(False).AddToParser(parser)
flags.Database(False, True).AddToParser(parser)
flags.TableName(False).AddToParser(parser)
flags.SourceUri(True).AddToParser(parser)
flags.SourceFormat(True).AddToParser(parser)
flags.SchemaUri(False).AddToParser(parser)
flags.CsvLineDelimiter(False).AddToParser(parser)
flags.CsvFieldDelimiter(False).AddToParser(parser)
flags.DatabaseDialect('Dialect for the spanner database').AddToParser(
parser
)
def Run(self, args):
"""Run the import command."""
auth_token = store.GetFreshAccessTokenIfEnabled(min_expiry_duration='1h')
command_executor = migration_backend.SpannerMigrationWrapper()
env_vars = migration_backend.GetEnvArgsForCommand(
extra_vars={
'GCLOUD_HB_PLUGIN': 'true',
'GCLOUD_AUTH_PLUGIN': 'true',
'GCLOUD_AUTH_ACCESS_TOKEN': auth_token,
}
)
project = arg_utils.GetFromNamespace(args, '--project', use_defaults=True)
response = command_executor(
command='import',
instance=args.instance,
database=args.database,
table_name=args.table_name,
source_uri=args.source_uri,
source_format=args.source_format,
schema_uri=args.schema_uri,
csv_line_delimiter=args.csv_line_delimiter,
csv_field_delimiter=args.csv_field_delimiter,
project=project,
database_dialect=args.database_dialect,
env=env_vars,
)
self.exit_code = response.exit_code
return self._DefaultOperationResponseHandler(response)

View File

@@ -0,0 +1,58 @@
# -*- 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.
"""Command for spanner databases list."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import databases
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import resource_args
class List(base.ListCommand):
"""List the Cloud Spanner databases contained within the given instance."""
detailed_help = {
'EXAMPLES':
textwrap.dedent("""\
To list the Cloud Spanner databases in an instance, run:
$ {command} --instance=my-instance-id
"""),
}
@staticmethod
def Args(parser):
"""See base class."""
resource_args.AddInstanceResourceArg(
parser, 'in which to list databases', positional=False)
parser.display_info.AddFormat("""
table(
name.basename(),
state,
version_retention_period,
earliest_version_time,
encryptionConfig.kmsKeyName,
enable_drop_protection
)
""")
def Run(self, args):
"""This is what gets called when the user runs this command."""
return databases.List(args.CONCEPTS.instance.Parse())

View File

@@ -0,0 +1,33 @@
release_tracks: [ALPHA, BETA, GA]
help_text:
brief: Remove IAM policy binding of a Cloud Spanner database.
description: |
Remove an IAM policy binding of a Cloud Spanner database.
examples: |
To remove an IAM policy binding for the role of 'roles/editor' for the user 'test-user@gmail.com'
with database 'my-database' and instance 'my-instance', run:
$ {command} my-database --instance='my-instance' --member='user:test-user@gmail.com' --role='roles/editor'
To remove an IAM policy binding which expires at the end of the year 2018 for the role of
'roles/spanner.databaseAdmin' and the user 'test-user@gmail.com' with database 'my-database' and instance 'my-instance', run:
$ {command} my-database --instance='my-instance' --member='user:test-user@gmail.com' --role='roles/spanner.databaseAdmin' --condition='expression=request.time < timestamp("2019-01-01T00:00:00Z"),title=expires_end_of_2018,description=Expires at midnight on 2018-12-31'
See https://cloud.google.com/iam/docs/managing-policies for details of
policy role and member types.
request:
collection: spanner.projects.instances.databases
arguments:
resource:
help_text: The Cloud Spanner database to remove the IAM policy binding from.
spec: !REF googlecloudsdk.command_lib.spanner.resources:database
iam:
enable_condition: true
policy_version: 3
get_iam_policy_version_path: getIamPolicyRequest.options.requestedPolicyVersion

View File

@@ -0,0 +1,81 @@
# -*- coding: utf-8 -*- #
# Copyright 2020 Google LLC. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Command for spanner restore database."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import database_operations
from googlecloudsdk.api_lib.spanner import databases
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import resource_args
from googlecloudsdk.core import log
class Restore(base.RestoreCommand):
"""Restore a Cloud Spanner database."""
detailed_help = {
'DESCRIPTION':
textwrap.dedent("""
Restores from a backup to a new Cloud Spanner database."""),
'EXAMPLES':
textwrap.dedent("""
To restore a backup, run:
$ {command} --source-backup=BACKUP_ID --source-instance=SOURCE_INSTANCE --destination-database=DATABASE --destination-instance=INSTANCE_NAME
To restore a backup using relative names, run:
$ {command} --source-backup=projects/PROJECT_ID/instances/SOURCE_INSTANCE_ID/backups/BACKUP_ID --destination-database=projects/PROJECT_ID/instances/SOURCE_INSTANCE_ID/databases/DATABASE_ID
""")
}
@staticmethod
def Args(parser):
"""Register flags for this command."""
resource_args.AddRestoreResourceArgs(parser)
base.ASYNC_FLAG.AddToParser(parser)
encryption_group_parser = parser.add_argument_group()
resource_args.AddRestoreDbEncryptionTypeArg(encryption_group_parser)
resource_args.AddKmsKeyResourceArg(encryption_group_parser,
'to restore the Cloud Spanner database')
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:
A message indicating database is restoring or when async, the operation.
"""
backup_ref = args.CONCEPTS.source.Parse()
database_ref = args.CONCEPTS.destination.Parse()
encryption_type = resource_args.GetRestoreDbEncryptionType(args)
kms_key = resource_args.GetAndValidateKmsKeyName(args)
op = databases.Restore(database_ref, backup_ref, encryption_type, kms_key)
if args.async_:
return log.status.Print(
'Restore database in progress. Operation name={}'.format(op.name))
return database_operations.Await(
op,
'Restoring backup {0} to database {1}'.format(backup_ref.Name(),
database_ref.Name()))

View File

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

View File

@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*- #
# Copyright 2022 Google LLC. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Command for spanner database roles list."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import database_roles
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import resource_args
class List(base.ListCommand):
"""List the Cloud Spanner database roles defined in the given database."""
detailed_help = {
'EXAMPLES':
textwrap.dedent("""\
To list the Cloud Spanner database roles in a database, run:
$ {command} --instance=my-instance-id --database=my-database-id
"""),
}
@staticmethod
def Args(parser):
"""See base class."""
resource_args.AddDatabaseResourceArg(
parser, 'in which to list database roles', positional=False)
parser.display_info.AddFormat("""
table(
name.basename()
)
""")
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:
Some value that we want to have printed later.
"""
return database_roles.List(args.CONCEPTS.database.Parse())

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.
"""Command group for spanner databases sessions."""
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 Sessions(base.Group):
"""Manage the sessions for Cloud Spanner databases."""
pass

View File

@@ -0,0 +1,56 @@
# -*- 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.
"""Command for spanner database session delete."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import database_sessions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import resource_args
class Delete(base.DeleteCommand):
"""Delete a Cloud Spanner session."""
detailed_help = {
'EXAMPLES':
textwrap.dedent("""\
To delete a Cloud Spanner session, run:
$ {command} my-session-id --instance=my-instance-id
--database=my-database-id
"""),
}
@staticmethod
def Args(parser):
"""See base class."""
resource_args.AddSessionResourceArg(parser, 'to delete')
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:
Some value that we want to have printed later.
"""
return database_sessions.Delete(args.CONCEPTS.session.Parse())

View File

@@ -0,0 +1,65 @@
# -*- 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.
"""Command for spanner sessions list."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import database_sessions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import resource_args
class List(base.ListCommand):
"""List the Cloud Spanner sessions contained within the given database."""
detailed_help = {
'EXAMPLES':
textwrap.dedent("""\
To list the sessions for a given Cloud Spanner database, run:
$ {command} --instance=my-instance-id --database=my-database-id
"""),
}
@staticmethod
def Args(parser):
"""See base class."""
resource_args.AddDatabaseResourceArg(
parser, 'in which to list sessions', positional=False)
parser.add_argument(
'--server-filter',
required=False,
help=
'An expression for filtering the results of the request on the server. '
'Filter rules are case insensitive. The fields eligible for filtering '
'are: * labels.key where key is the name of a label.')
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:
Some value that we want to have printed later.
"""
return database_sessions.List(args.CONCEPTS.database.Parse(),
args.server_filter)

View File

@@ -0,0 +1,67 @@
# -*- 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.
"""Command for spanner databases set-iam-policy."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.iam import iam_util
from googlecloudsdk.command_lib.spanner import iam
from googlecloudsdk.command_lib.spanner import resource_args
class SetIamPolicy(base.Command):
"""Set the IAM policy for a Cloud Spanner database."""
detailed_help = {
'EXAMPLES':
textwrap.dedent("""\
The following command reads an IAM policy defined in a JSON file
`policy.json` and sets it for a spanner database with the ID
`my-database-id`:
$ {command} my-database-id --instance=my-instance-id policy.json
See https://cloud.google.com/iam/docs/managing-policies for details of the
policy file format and contents.
"""),
}
@staticmethod
def Args(parser):
"""See base class."""
resource_args.AddDatabaseResourceArg(parser,
'to set IAM policy binding for')
parser.add_argument(
'policy_file', help='Name of JSON or YAML file with the IAM policy.')
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:
Some value that we want to have printed later.
"""
database_ref = args.CONCEPTS.database.Parse()
result = iam.SetDatabaseIamPolicy(database_ref, args.policy_file)
iam_util.LogSetIamPolicy(database_ref.Name(), 'database')
return result

View File

@@ -0,0 +1,30 @@
# -*- 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.
"""Command group for spanner databases splits."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
@base.DefaultUniverseOnly
class Splits(base.Group):
"""Manage the split points for Spanner databases."""
pass

View File

@@ -0,0 +1,88 @@
# -*- 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.
"""Command for spanner databases add splits."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import database_splits
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import flags
from googlecloudsdk.command_lib.spanner import resource_args
@base.DefaultUniverseOnly
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class Add(base.UpdateCommand):
"""Add split points to a Spanner database."""
detailed_help = {
'EXAMPLES': textwrap.dedent("""\
To add split points to the given Spanner database, run:
$ {command} my-database-id --instance=my-instance-id
--splits-file=path/to/splits.txt --initiator=my-initiator-string
--split-expiration-date=2024-08-15T15:55:10Z
"""),
}
@staticmethod
def Args(parser):
"""See base class."""
resource_args.AddDatabaseResourceArg(parser, 'on which to add split points')
flags.SplitsFile(
help_text=(
'The path of a file containing split points to add to the database.'
' Separate split points in the file with a new line. The file'
' format is <ObjectType>[space]<ObjectName>[space]<Split Value>,'
' where the ObjectType is one of TABLE or INDEX and the Split Value'
' is the split point key. For index, the split point key is the'
' index key with or without a full table key prefix.'
)
).AddToParser(parser)
flags.SplitExpirationDate(
help_text=(
'The date when the split points become system managed and'
' becomes eligible for merging. The default is 10 days from the'
' date of creation. The maximum is 30 days from the date of'
' creation.'
)
).AddToParser(parser)
flags.Initiator(
help_text=(
'The tag to identify the initiator of the split points.'
)
).AddToParser(parser)
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:
Some value that we want to have printed later.
"""
return database_splits.AddSplitPoints(
args.CONCEPTS.database.Parse(),
flags.GetSplitPoints(args),
args.initiator,
)

View File

@@ -0,0 +1,72 @@
# -*- 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.
"""Command for spanner databases list user splits."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import database_splits
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import resource_args
@base.DefaultUniverseOnly
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
class List(base.ListCommand):
"""List split points that are added by a user to a Spanner database."""
detailed_help = {
'EXAMPLES': textwrap.dedent(text="""\
To list the user added split points of the given Spanner database,
run:
$ {command} my-database-id --instance=my-instance-id
"""),
}
@staticmethod
def Args(parser):
"""See base class."""
base.URI_FLAG.RemoveFromParser(parser)
parser.display_info.AddFormat(DEFAULT_SPLIT_POINTS_FORMAT)
resource_args.AddDatabaseResourceArg(
parser, 'on which to list split points')
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:
Some value that we want to have printed later.
"""
return database_splits.ListSplitPoints(args.CONCEPTS.database.Parse())
DEFAULT_SPLIT_POINTS_FORMAT = """\
table(
TABLE_NAME,
INDEX_NAME,
INITIATOR,
SPLIT_KEY,
EXPIRE_TIME
)"""

View File

@@ -0,0 +1,84 @@
# -*- 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.
"""Command for spanner databases update."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import textwrap
from googlecloudsdk.api_lib.spanner import database_operations
from googlecloudsdk.api_lib.spanner import databases
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.spanner import flags
from googlecloudsdk.command_lib.spanner import resource_args
@base.UniverseCompatible
class Update(base.UpdateCommand):
"""Update a Cloud Spanner database."""
detailed_help = {
'EXAMPLES': textwrap.dedent("""\
To enable database deletion protection on a Cloud Spanner database
'my-database', run:
$ {command} my-database --enable-drop-protection
To disable database deletion protection on a Cloud Spanner database
'my-database', run:
$ {command} my-database --no-enable-drop-protection
To update KMS key references for a Cloud Spanner database
'my-database', run:
$ {command} my-database --kms-keys="KEY1,KEY2"
"""),
}
@staticmethod
def Args(parser):
"""Args is called by calliope to gather arguments for this command.
Args:
parser: An argparse parser that you can use to add arguments that go on
the command line after this command. Positional arguments are allowed.
"""
resource_args.AddDatabaseResourceArg(parser, 'to update')
group_parser = parser.add_argument_group(mutex=True)
flags.EnableDropProtection().AddToParser(group_parser)
flags.EnableUpdateKmsKeys().AddToParser(group_parser)
base.ASYNC_FLAG.AddToParser(parser)
def Run(self, args):
"""This is what gets called when the user runs the `database update` command.
Args:
args: an argparse namespace. All the arguments that were provided to this
command invocation.
Returns:
Database update response.
"""
op = databases.Update(
args.CONCEPTS.database.Parse(),
args.enable_drop_protection,
args.kms_keys,
)
if args.async_:
return op
return database_operations.Await(op, 'Updating database.')