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,34 @@
# -*- 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.
"""The main command group for Backup and DR."""
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.ReleaseTracks(
base.ReleaseTrack.GA, base.ReleaseTrack.BETA, base.ReleaseTrack.ALPHA
)
class Backupdr(base.Group):
"""Manage Backup and DR resources."""
# See third_party/py/googlecloudsdk/calliope/base.py for a list of categories.
category = base.STORAGE_CATEGORY
def Filter(self, context, args):
# restricts users to pass in project id only, need to check whether
# its okay to pass in project number
base.RequireProjectID(args)
del context, args

View File

@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Command group for Backup and DR Backup Plan Association."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class BackupPlanAssociations(base.Group):
"""Manage Backup and DR backup plan associations."""

View File

@@ -0,0 +1,112 @@
# -*- 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.
"""Creates Backup and DR Backup Plan Association."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.backup_plan_associations import BackupPlanAssociationsClient
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import log
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class Create(base.CreateCommand):
"""Create a new backup plan association."""
detailed_help = {
'BRIEF': 'Creates a new backup plan association',
'DESCRIPTION': (
'Create a new backup plan association in the project. It can only be'
' created in locations where Backup and DR is available.'
),
'EXAMPLES': """\
To create a new backup plan association `sample-bpa` in project `sample-project` and location `us-central1` for resource `sample-resource-uri` with backup plan `sample-backup-plan`, run:
$ {command} sample-bpa --project=sample-project --location=us-central1 --backup-plan=sample-backup-plan --resource=sample-resource-uri
""",
}
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
base.ASYNC_FLAG.AddToParser(parser)
base.ASYNC_FLAG.SetDefault(parser, True)
flags.AddCreateBackupPlanAssociationFlags(parser)
def Run(self, args):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = BackupPlanAssociationsClient()
is_async = args.async_
backup_plan_association = args.CONCEPTS.backup_plan_association.Parse()
backup_plan = args.CONCEPTS.backup_plan.Parse()
resource = args.resource
resource_type = args.resource_type
try:
operation = client.Create(
backup_plan_association, backup_plan, resource, resource_type
)
if resource_type.endswith('Disk'):
log.warning(
'In the event of a source region outage, backups in multi-region'
' vault remain accessible, but the restore will fail if your disk'
' is protected with a regional CMEK.'
)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
if is_async:
log.CreatedResource(
backup_plan_association.RelativeName(),
kind='backup plan association',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
)
return operation
resource = client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'Creating backup plan association [{}]. (This operation could'
' take up to 2 minutes.)'.format(
backup_plan_association.RelativeName()
)
),
)
log.CreatedResource(
backup_plan_association.RelativeName(), kind='backup plan association'
)
return resource

View File

@@ -0,0 +1,112 @@
# -*- 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.
"""Delete a specified Backup and DR Backup Plan Association."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.backup_plan_associations import BackupPlanAssociationsClient
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class Delete(base.DeleteCommand):
"""Delete the specified backup plan association."""
detailed_help = {
'BRIEF': 'Delete a specific backup plan association',
'DESCRIPTION': '{description}',
'EXAMPLES': """\
To delete a backup plan association `sample-bpa` in project `sample-project` and location `us-central1` , run:
$ {command} sample-bpa --project=sample-project --location=us-central1
""",
}
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
base.ASYNC_FLAG.AddToParser(parser)
base.ASYNC_FLAG.SetDefault(parser, True)
flags.AddBackupPlanAssociationResourceArg(
parser,
'Name of the backup plan association to delete.',
)
def Run(self, args):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = BackupPlanAssociationsClient()
is_async = args.async_
backup_plan_association = args.CONCEPTS.backup_plan_association.Parse()
console_io.PromptContinue(
message=(
'The backup plan association will be deleted. You cannot undo this'
' action.'
),
default=True,
cancel_on_no=True,
)
try:
operation = client.Delete(backup_plan_association)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
if is_async:
log.DeletedResource(
backup_plan_association.RelativeName(),
kind='backup plan association',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
)
return operation
response = client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'Deleting backup plan association [{}]. (This operation could'
' take up to 2 minutes.)'.format(
backup_plan_association.RelativeName()
)
),
has_result=False,
)
log.DeletedResource(
backup_plan_association.RelativeName(), kind='backup plan association'
)
return response

View File

@@ -0,0 +1,22 @@
- release_tracks: [ALPHA, GA]
help_text:
brief: Show details of the backup plan association.
description: Show all configuration data associated with the specified backup plan association.
examples: |
To view details for backup plan association ``BACKUP_PLAN_ASSOCIATION'', run:
$ {command} BACKUP_PLAN_ASSOCIATION
request:
collection: backupdr.projects.locations.backupPlanAssociations
response:
id_field: name
arguments:
resource:
help_text: Name of the backup plan association to describe.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:backupPlanAssociations
output:
format: json

View File

@@ -0,0 +1,122 @@
# -*- 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.
"""Command to fetch backup plan associations for a resource type."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.backupdr import backup_plan_associations
from googlecloudsdk.api_lib.util import common_args
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import log
BackupPlanAssociationsClient = (
backup_plan_associations.BackupPlanAssociationsClient
)
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class FetchForResourceType(base.ListCommand):
"""Fetch Backup Plan Associations for a given resource type and location."""
detailed_help = {
'BRIEF': (
'List backup plan associations in a specified location'
' and resource type in a project.'
),
'DESCRIPTION': (
'{description} List backup plan associations in a specified location'
' and resource type in a project.'
),
'EXAMPLES': """\
To list backup plan associations for Cloud SQL with location `us-central1`, run:
$ {command} sqladmin.googleapis.com/Instance --location="us-central1"
""",
}
DEFAULT_LIST_FORMAT = """
table(
name.basename():label=NAME,
resource:label=RESOURCE,
resourceType:label=RESOURCE_TYPE,
backupPlan:label=BACKUP_PLAN,
state:label=STATE
)
"""
@staticmethod
def Args(parser):
parser.add_argument(
'--location',
required=True,
help='Location for which backup plan associations should be fetched.',
)
parser.add_argument(
'resource_type',
help=(
'Resource type for which backup plan associations should be'
' fetched.'
),
)
flags.AddOutputFormat(parser, FetchForResourceType.DEFAULT_LIST_FORMAT)
def _Validate_and_Parse_SortBy(self, args):
order_by = common_args.ParseSortByArg(args.sort_by)
# Only sort by name is supported by CLH right now.
if order_by is None:
return None
order_by_fields = order_by.split(' ')
if (
order_by_fields
and isinstance(order_by_fields[0], str)
and order_by_fields[0]
not in ('name', 'Name')
):
raise exceptions.InvalidArgumentException(
'sort_by',
'Invalid sort_by argument. Only sort_by'
' name/Name is'
' supported.',
)
order_by_fields[0] = 'name'
order_by = ' '.join(order_by_fields)
return order_by
def Run(self, args):
"""Run the command."""
location = args.location
resource_type = args.resource_type
try:
client = BackupPlanAssociationsClient()
result = client.FetchForResourceType(
location,
resource_type,
filter_expression=args.filter,
page_size=args.page_size,
order_by=self._Validate_and_Parse_SortBy(args),
)
if result and result.backupPlanAssociations:
return result.backupPlanAssociations # Return the list directly
else:
return [] # Return an empty list
except Exception as e: # pylint: disable=broad-except
log.error(f'Error fetching backup plan associations : {e}')
raise e # Raise the exception

View File

@@ -0,0 +1,33 @@
- release_tracks: [ALPHA, GA]
help_text:
brief: List Backup and DR backup plan associations
description: List backup plan associations in the project for a specified location.
examples: |
To list backup plan associations for all locations, run:
$ {command}
To list backup plan associations in a location ``my-location'', run:
$ {command} --location=my-location
request:
collection: backupdr.projects.locations.backupPlanAssociations
response:
id_field: name
arguments:
resource:
help_text: Location for which backup plan associations should be listed.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:locationDefaultGlobal
output:
format: |
table(
name.basename():label=NAME:sort=2,
resource,
resourceType,
backupPlan,
state:label=STATUS
)

View File

@@ -0,0 +1,124 @@
# -*- 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.
"""Create an on-demand backup."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.backup_plan_associations import BackupPlanAssociationsClient
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions as calliope_exceptions
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import log
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class TriggerBackup(base.Command):
"""Create an on-demand backup for a resource."""
detailed_help = {
'BRIEF': 'Create an on-demand backup.',
'DESCRIPTION': (
'{description} Trigger an on demand backup for the given backup rule.'
),
'EXAMPLES': """\
To trigger an on demand backup for a backup plan association `sample-bpa` in project `sample-project` and location `us-central1` with backup rule `sample-backup-rule`, run:
$ {command} sample-bpa --project=sample-project --location=us-central1 --backup-rule-id=sample-backup-rule
""",
}
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
base.ASYNC_FLAG.AddToParser(parser)
base.ASYNC_FLAG.SetDefault(parser, True)
flags.AddTriggerBackupFlags(parser)
def Run(self, args):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = BackupPlanAssociationsClient()
is_async = args.async_
backup_plan_association = args.CONCEPTS.backup_plan_association.Parse()
backup_rule = args.backup_rule_id
custom_retention_days = args.custom_retention_days
labels = args.labels
if backup_rule and custom_retention_days:
raise calliope_exceptions.MutualExclusionError(
'argument --custom-retention-days: At most one of --backup-rule-id |'
' --custom-retention-days may be specified.'
)
try:
operation = client.TriggerBackup(
backup_plan_association, backup_rule, custom_retention_days, labels
)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
if is_async:
# pylint: disable=protected-access
# none of the log.CreatedResource, log.DeletedResource etc. matched
log._PrintResourceChange(
'on demand backup',
backup_plan_association.RelativeName(),
kind='backup plan association',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
failed=None,
)
return operation
client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'On demand backup in progress [{}]. (This operation usually takes'
' less than 15 minutes but could take up to 8 hours.)'.format(
backup_plan_association.RelativeName()
)
),
)
# pylint: disable=protected-access
# none of the log.CreatedResource, log.DeletedResource etc. matched
log._PrintResourceChange(
'on demand backup',
backup_plan_association.RelativeName(),
kind='backup plan association',
is_async=False,
details=None,
failed=None,
operation_past_tense='on demand backup done for',
)
return

View File

@@ -0,0 +1,123 @@
# -*- 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.
"""Updates Backup and DR Backup Plan Association."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.backup_plan_associations import BackupPlanAssociationsClient
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import log
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class Update(base.UpdateCommand):
"""Update a specific backup plan within a backup plan association."""
detailed_help = {
'BRIEF': (
'Update a specific backup plan within a backup plan association.'
),
'DESCRIPTION': (
'{description}'
),
'EXAMPLES': """\
To update backup plan association `sample-bpa` in project `sample-project` and location `us-central1` with backup plan `sample-backup-plan` in the same project and location, run:
$ {command} sample-bpa --project=sample-project --location=us-central1 --backup-plan=sample-backup-plan
To update backup plan association `sample-bpa-uri` with backup plan `sample-backup-plan-uri` (using full URIs), run:
$ {command} sample-bpa-uri --backup-plan=sample-backup-plan-uri
To update backup plan association `sample-bpa` in location `us-central1` with backup plan `sample-backup-plan-uri`, run:
$ {command} sample-bpa --location=us-central1 --backup-plan=sample-backup-plan-uri
To update backup plan association `sample-bpa` in project `workload-project` and location `us-central1` with backup plan `sample-backup-plan` in project `sample-project`, run:
$ {command} sample-bpa --workload-project=workload-project --location=us-central1 --backup-plan=sample-backup-plan --project=sample-project
""",
}
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
base.ASYNC_FLAG.AddToParser(parser)
base.ASYNC_FLAG.SetDefault(parser, True)
flags.AddUpdateBackupPlanAssociationFlags(parser)
def GetUpdateMask(self, args):
return 'backup_plan' if args.IsSpecified('backup_plan') else ''
def Run(self, args):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = BackupPlanAssociationsClient()
is_async = args.async_
backup_plan_association = args.CONCEPTS.backup_plan_association.Parse()
backup_plan = args.CONCEPTS.backup_plan.Parse()
try:
parsed_bpa = client.ParseUpdate(backup_plan)
update_mask = self.GetUpdateMask(args)
operation = client.Update(
backup_plan_association,
parsed_bpa,
update_mask=update_mask,
)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT) from e
if is_async:
log.UpdatedResource(
backup_plan_association.RelativeName(),
kind='backup plan association',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
)
return operation
resource = client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'Updating backup plan association [{}]. (This operation could'
' take up to 2 minutes.)'.format(
backup_plan_association.RelativeName()
)
),
)
log.UpdatedResource(
backup_plan_association.RelativeName(), kind='backup plan association'
)
return resource

View File

@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Command group for Backup and DR Backup Plan Revisions."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class BackupPlanRevisions(base.Group):
"""View Backup and DR backup plan revisions."""

View File

@@ -0,0 +1,22 @@
- release_tracks: [ALPHA, GA]
help_text:
brief: Show details of the backup plan revision.
description: Show all data associated with the specified backup plan revision.
examples: |
To view details for backup plan revision 'BACKUP_PLAN_REVISION', run:
$ {command} BACKUP_PLAN_REVISION
request:
collection: backupdr.projects.locations.backupPlans.revisions
response:
id_field: name
arguments:
resource:
help_text: Name of the backup plan revision to describe.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:backupPlanRevisions
output:
format: json

View File

@@ -0,0 +1,30 @@
- release_tracks: [ALPHA, GA]
help_text:
brief: List backup plan revisions.
description: List backup plan revisions in the project.
examples: |
To list backup plan revisions for all backup plans and locations, run:
$ {command}
To list all backup plan revisions for a backup plan ``my-backup-plan'', run:
$ {command} --backup-plan=my-backup-plan
To list all backup plan revisions for a backup plan ``my-backup-plan'' in location ``my-location'', run:
$ {command} --backup-plan=my-backup-plan --location=my-location
request:
collection: backupdr.projects.locations.backupPlans.revisions
response:
id_field: name
arguments:
resource:
help_text: Backup plan to list backup plan revisions from.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:backupPlanDefault
is_positional: false
output:
format: json

View File

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

View File

@@ -0,0 +1,198 @@
# -*- 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.
"""Creates a new Backup Plan."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import backup_plans
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import log
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class Create(base.CreateCommand):
"""Creates a new Backup Plan."""
detailed_help = {
'BRIEF': 'Creates a new backup plan',
'DESCRIPTION': """\
Create a new backup plan in the project. It can only be created in
locations where Backup and DR is available.
""",
'EXAMPLES': """\
To create a new backup plan ``sample-backup-plan''
in project ``sample-project'',
at location ``us-central1'',
with resource-type ``compute.<UNIVERSE_DOMAIN>.com/Instance'' and
backup-vault ``backup-vault''
with 2 backup-rules:
run:
$ {command} sample-backup-plan --project=sample-project --location=us-central1
--resource-type 'compute.<UNIVERSE_DOMAIN>.com/Instance'
--backup-vault <BACKUP-VAULT>
--backup-rule <BACKUP-RULE>
--backup-rule <BACKUP-RULE>
Backup Rule Examples:
1. Hourly backup rule with hourly backup frequency of 6 hours and store it for 30 days, and expect the backups to run only between 10:00 to 20:00 UTC
<BACKUP-RULE>: rule-id=sample-hourly-rule,retention-days=30,recurrence=HOURLY,hourly-frequency=6,time-zone=UTC,backup-window-start=10,backup-window-end=20
Properties:
-- rule-id = "sample-hourly-rule"
-- retention-days = 30
-- recurrence = HOURLY
-- hourly-frequency = 6
-- time-zone = UTC
-- backup-window-start = 10
-- backup-window-end = 20
2. Daily backup rule with daily backup frequency of 6 hours and store it for 7 days
<BACKUP-RULE>: rule-id=sample-daily-rule,retention-days=7,recurrence=DAILY,backup-window-start=1,backup-window-end=14
Properties:
-- rule-id = "sample-daily-rule"
-- retention-days = 7
-- recurrence = DAILY
-- backup-window-start = 1
-- backup-window-end = 14
3. Weekly backup rule with weekly backup frequency on every MONDAY & FRIDAY and store it for 21 days
<BACKUP-RULE>: rule-id=sample-weekly-rule,retention-days=21,recurrence=WEEKLY,days-of-week="MONDAY FRIDAY",backup-window-start=10,backup-window-end=20
Properties:
-- rule-id = "sample-weekly-rule"
-- retention-days: 21
-- recurrence = WEEKLY
-- days-of-week = "MONDAY FRIDAY"
-- backup-window-start = 10
-- backup-window-end = 20
""",
}
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
base.ASYNC_FLAG.AddToParser(parser)
base.ASYNC_FLAG.SetDefault(parser, True)
flags.AddBackupPlanResourceArgWithBackupVault(
parser,
"""Name of the backup plan to be created.
Once the backup plan is created, this name can't be changed.
The name must be unique for a project and location.
""",
)
flags.AddResourceType(
parser,
"""Type of resource to which the backup plan should be applied.
E.g., `compute.<UNIVERSE_DOMAIN>.com/Instance` """,
)
flags.AddBackupRule(parser)
flags.AddMaxCustomOnDemandRetentionDays(parser)
description_help = """\
Provide a description of the backup plan, such as specific use cases and
relevant details, in 2048 characters or less.
E.g., This is a backup plan that performs a daily backup at 6 p.m. and
retains data for 3 months.
"""
flags.AddDescription(parser, description_help)
labels_help = """\
If you have assigned labels to your resources for grouping, you can
provide the label using this flag.A label is a key-value pair.
Keys must start with a lowercase character and contain only hyphens (-),
underscores (_), lowercase characters, and numbers. Values must contain
only hyphens (-), underscores (_), lowercase characters, and numbers.
"""
flags.AddLabels(parser, labels_help)
flags.AddLogRetentionDays(parser)
def Run(self, args):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = backup_plans.BackupPlansClient()
is_async = args.async_
backup_plan = args.CONCEPTS.backup_plan.Parse()
backup_vault = args.CONCEPTS.backup_vault.Parse()
resource_type = args.resource_type
backup_rules = args.backup_rule
log_retention_days = args.log_retention_days
description = args.description
labels = args.labels
max_custom_on_demand_retention_days = (
args.max_custom_on_demand_retention_days
)
try:
operation = client.Create(
backup_plan,
backup_vault.RelativeName(),
resource_type,
backup_rules,
log_retention_days,
description,
labels,
max_custom_on_demand_retention_days
)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
if is_async:
log.CreatedResource(
backup_plan.RelativeName(),
kind='backup plan',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
)
return operation
resource = client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'Creating backup plan [{}]. (This operation could'
' take up to 2 minutes.)'.format(backup_plan.RelativeName())
),
)
log.CreatedResource(backup_plan.RelativeName(), kind='backup plan')
return resource

View File

@@ -0,0 +1,105 @@
# -*- 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.
"""Deletes a Backup Plan."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.backup_plans import BackupPlansClient
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
@base.DefaultUniverseOnly
class Delete(base.DeleteCommand):
"""Deletes a Backup Plan."""
detailed_help = {
'BRIEF': 'Deletes a specific backup plan',
'DESCRIPTION': '{description}',
'EXAMPLES': """\
To delete a backup plan `sample-backup-plan` in project `sample-project` and location `us-central1` , run:
$ {command} sample-backup-plan --project=sample-project --location=us-central1
""",
}
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
base.ASYNC_FLAG.AddToParser(parser)
base.ASYNC_FLAG.SetDefault(parser, True)
flags.AddBackupPlanResourceArg(
parser,
'Name of the backup plan to delete'
)
def Run(self, args):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = BackupPlansClient()
is_async = args.async_
backup_plan = args.CONCEPTS.backup_plan.Parse()
console_io.PromptContinue(
message=(
'The backup plan will be deleted. You cannot undo this action.'
),
default=True,
cancel_on_no=True,
)
try:
operation = client.Delete(backup_plan)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT) from e
if is_async:
log.DeletedResource(
backup_plan.RelativeName(),
kind='backup plan',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
)
return operation
# For sync operation
return client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'Deleting backup plan [{}]. '
'(This operation could take up to 2 minutes.)'
.format(backup_plan.RelativeName())
),
has_result=False,
)

View File

@@ -0,0 +1,22 @@
- release_tracks: [ALPHA, GA]
help_text:
brief: Show details of the backup plan.
description: Show all data associated with the specified backup plan.
examples: |
To view details for backup plan 'BACKUP_PLAN', run:
$ {command} BACKUP_PLAN
request:
collection: backupdr.projects.locations.backupPlans
response:
id_field: name
arguments:
resource:
help_text: Name of the backup plan to describe.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:backupPlans
output:
format: json

View File

@@ -0,0 +1,27 @@
- release_tracks: [ALPHA, GA]
help_text:
brief: List backup plans in the project
description: List backup plans in the project.
examples: |
To list backup plans for all locations, run:
$ {command}
To list backup plans in a location "my-location", run:
$ {command} --location=my-location
request:
collection: backupdr.projects.locations.backupPlans
response:
id_field: name
arguments:
resource:
help_text: Location for which backup plans should be listed.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:locationDefaultGlobal
output:
format: json
# TODO: b/336698260 Update the format to table format

View File

@@ -0,0 +1,311 @@
# -*- 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.
"""Updates a new Backup Plan."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import argparse
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import backup_plans
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import exceptions as core_exceptions
from googlecloudsdk.core import log
from googlecloudsdk.core import yaml
@base.UniverseCompatible
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class Update(base.UpdateCommand):
"""Update a specific backup plan."""
detailed_help = {
'BRIEF': 'Update a specific backup plan',
'DESCRIPTION': """\
Update a specific backup plan in the project. It can only be updated in regions supported by the Backup and DR Service.
""",
'EXAMPLES': """\
To update 2 backup rules and description of an existing backup plan ``sample-backup-plan''
in project ``sample-project'',
at location ``us-central1'':
run:
$ {command} sample-backup-plan --project=sample-project --location=us-central1
--backup-rule <BACKUP-RULE>
--backup-rule <BACKUP-RULE>
--description "This is a sample backup plan"
To add backup rules to an existing backup plan ``sample-backup-plan''
in project ``sample-project'',
at location ``us-central1'':
run:
$ {command} sample-backup-plan --project=sample-project --location=us-central1
--add-backup-rule <BACKUP-RULE>
--add-backup-rule <BACKUP-RULE>
To remove a backup rule with id ``sample-daily-rule'' from an existing backup plan ``sample-backup-plan''
in project ``sample-project'',
at location ``us-central1'':
run:
$ {command} sample-backup-plan --project=sample-project --location=us-central1
--remove-backup-rule sample-daily-rule
To override backup rules in an existing backup plan ``sample-backup-plan''
in project ``sample-project'',
at location ``us-central1'', pass a file path containing backup rules in YAML or JSON format:
This flag is mutually exclusive with --add-backup-rule, --remove-backup-rule and --backup-rule flags.
run:
$ {command} sample-backup-plan --project=sample-project --location=us-central1
--backup-rules-fom-file <FILE_PATH>
Backup Rule Examples:
1. Hourly backup rule with hourly backup frequency of 6 hours and store it for 30 days, and expect the backups to run only between 10:00 to 20:00 UTC
<BACKUP-RULE>: rule-id=sample-hourly-rule,retention-days=30,recurrence=HOURLY,hourly-frequency=6,time-zone=UTC,backup-window-start=10,backup-window-end=20
Properties:
-- rule-id = "sample-hourly-rule"
-- retention-days = 30
-- recurrence = HOURLY
-- hourly-frequency = 6
-- time-zone = UTC
-- backup-window-start = 10
-- backup-window-end = 20
2. Daily backup rule with daily backup frequency of 6 hours and store it for 7 days
<BACKUP-RULE>: rule-id=sample-daily-rule,retention-days=7,recurrence=DAILY,backup-window-start=1,backup-window-end=14
Properties:
-- rule-id = "sample-daily-rule"
-- retention-days = 7
-- recurrence = DAILY
-- backup-window-start = 1
-- backup-window-end = 14
3. Weekly backup rule with weekly backup frequency on every MONDAY & FRIDAY and store it for 21 days
<BACKUP-RULE>: rule-id=sample-weekly-rule,retention-days=21,recurrence=WEEKLY,days-of-week="MONDAY FRIDAY",backup-window-start=10,backup-window-end=20
Properties:
-- rule-id = "sample-weekly-rule"
-- retention-days: 21
-- recurrence = WEEKLY
-- days-of-week = "MONDAY FRIDAY"
-- backup-window-start = 10
-- backup-window-end = 20
YAML and JSON file examples:
YAML file example:
```
backup-rules:
- rule-id: weekly-rule
retention-days: 7
recurrence: WEEKLY
backup-window-start: 0
backup-window-end: 23
days-of-week: [MONDAY, TUESDAY]
time-zone: UTC
- rule-id: daily-rule
retention-days: 1
recurrence: DAILY
backup-window-start: 1
backup-window-end: 24
time-zone: UTC
```
JSON file example:
```
{
"backup-rules": [
{
"rule-id": "weekly-rule",
"retention-days": 7,
"recurrence": "WEEKLY",
"backup-window-start": 0,
"backup-window-end": 23,
"days-of-week": ["MONDAY", "TUESDAY"],
"time-zone": "UTC"
},
{
"rule-id": "daily-rule",
"retention-days": 1,
"recurrence": "DAILY",
"backup-window-start": 1,
"backup-window-end": 24,
"time-zone": "UTC"
}
]
}
```
""",
}
@staticmethod
def Args(parser: argparse.ArgumentParser):
"""Specifies additional command flags.
Args:
parser: Parser object for command line inputs.
"""
base.ASYNC_FLAG.AddToParser(parser)
base.ASYNC_FLAG.SetDefault(parser, True)
flags.AddBackupPlanResourceArg(
parser,
"""Name of the backup plan to be updated.
The name must be unique for a project and location.
""",
)
flags.AddUpdateBackupRule(parser)
flags.AddAddBackupRule(parser)
flags.AddRemoveBackupRule(parser)
flags.AddBackupRulesFromFile(parser)
description_help = """\
Provide a description of the backup plan, such as specific use cases and
relevant details, in 2048 characters or less.
E.g., This is a backup plan that performs a daily backup at 6 p.m. and
retains data for 3 months.
"""
flags.AddDescription(parser, description_help)
flags.AddLogRetentionDays(parser)
flags.AddMaxCustomOnDemandRetentionDays(parser)
class YamlOrJsonLoadError(core_exceptions.Error):
"""Error parsing YAML or JSON file content."""
def _GetBackupRulesFromFile(self, backup_rules_file_content):
"""Parses the backup rules from the file content."""
try:
backup_rules = yaml.load(backup_rules_file_content)
return backup_rules.get('backup-rules')
except Exception as exc: # pylint: disable=broad-except
raise self.YamlOrJsonLoadError(
'Could not parse content in the backup rules file: {0}'.format(exc)
) from exc
def Run(self, args) -> any:
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = backup_plans.BackupPlansClient()
backup_plan = args.CONCEPTS.backup_plan.Parse()
backup_rules_file_content = args.backup_rules_from_file
update_backup_rules = args.backup_rule
add_backup_rules = args.add_backup_rule
remove_backup_rules = args.remove_backup_rule
if backup_rules_file_content and (
update_backup_rules or add_backup_rules or remove_backup_rules
):
raise core_exceptions.Error(
'--backup-rules-from-file flag cannot be used with'
' --backup-rule, --add-backup-rule or --remove-backup-rule flags.'
)
log_retention_days = args.log_retention_days
description = args.description
max_custom_on_demand_retention_days = (
args.max_custom_on_demand_retention_days
)
try:
current_backup_plan = client.Describe(backup_plan)
new_backup_rules_from_file = None
if backup_rules_file_content:
new_backup_rules_from_file = self._GetBackupRulesFromFile(
backup_rules_file_content
)
updated_backup_plan = client.ParseUpdate(
description,
new_backup_rules_from_file,
update_backup_rules,
add_backup_rules,
remove_backup_rules,
current_backup_plan,
log_retention_days,
max_custom_on_demand_retention_days,
)
update_mask = []
if (
description is not None
and description != current_backup_plan.description
):
update_mask.append('description')
if (
log_retention_days is not None
and log_retention_days != current_backup_plan.logRetentionDays
):
update_mask.append('logRetentionDays')
if (
max_custom_on_demand_retention_days is not None
and max_custom_on_demand_retention_days
!= current_backup_plan.maxCustomOnDemandRetentionDays
):
update_mask.append('maxCustomOnDemandRetentionDays')
if any([
update_backup_rules,
add_backup_rules,
remove_backup_rules,
new_backup_rules_from_file,
]):
update_mask.append('backupRules')
operation = client.Update(
backup_plan, updated_backup_plan, ','.join(update_mask)
)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
if args.async_:
log.UpdatedResource(
backup_plan.RelativeName(),
kind='backup plan',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
)
return operation
resource = client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
f'Updating backup plan [{backup_plan.RelativeName()}]. (This'
' operation could take up to 2 minutes.)'
),
)
log.UpdatedResource(backup_plan.RelativeName(), kind='backup plan')
return resource

View File

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

View File

@@ -0,0 +1,210 @@
# -*- 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.
"""Creates a Backup and DR Backup Vault."""
import argparse
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.backup_vaults import BackupVaultsClient
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.command_lib.backupdr import util as command_util
from googlecloudsdk.command_lib.util.args import labels_util
from googlecloudsdk.core import log
def _add_common_args(parser: argparse.ArgumentParser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
flags.AddBackupVaultResourceArg(
parser,
'Name of the backup vault to create. A vault name cannot be changed'
' after creation. It must be between 3-63 characters long and must be'
' unique within the project and location.',
)
flags.AddNoAsyncFlag(parser)
flags.AddEnforcedRetention(parser, True)
flags.AddDescription(parser)
flags.AddEffectiveTime(parser)
flags.AddLabels(parser)
flags.AddBackupVaultAccessRestrictionEnumFlag(parser, 'create')
flags.AddBackupRetentionInheritance(parser)
flags.AddKmsKey(parser)
def _run(
args: argparse.Namespace,
):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = BackupVaultsClient()
backup_vault = args.CONCEPTS.backup_vault.Parse()
backup_min_enforced_retention = command_util.ConvertIntToStr(
args.backup_min_enforced_retention
)
description = args.description
effective_time = command_util.VerifyDateInFuture(
args.effective_time, 'effective-time'
)
labels = labels_util.ParseCreateArgs(
args, client.messages.BackupVault.LabelsValue
)
no_async = args.no_async
access_restriction = args.access_restriction
backup_retention_inheritance = args.backup_retention_inheritance
encryption_config = (
client.messages.EncryptionConfig(kmsKeyName=args.kms_key)
)
try:
operation = client.Create(
backup_vault,
backup_min_enforced_retention,
description,
labels,
effective_time,
access_restriction,
backup_retention_inheritance=backup_retention_inheritance,
encryption_config=encryption_config,
)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
if no_async:
resource = client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'Creating backup vault [{}]. (This operation could'
' take up to 2 minutes.)'.format(backup_vault.RelativeName())
),
)
log.CreatedResource(backup_vault.RelativeName(), kind='backup vault')
return resource
log.CreatedResource(
backup_vault.RelativeName(),
kind='backup vault',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
)
return operation
@base.ReleaseTracks(base.ReleaseTrack.GA)
@base.DefaultUniverseOnly
class Create(base.CreateCommand):
"""Create a Backup and DR backup vault."""
detailed_help = {
'BRIEF': 'Creates a Backup and DR backup vault.',
'DESCRIPTION': '{description}',
'API REFERENCE': (
'This command uses the backupdr/v1 API. The full documentation for'
' this API can be found at:'
' https://cloud.google.com/backup-disaster-recovery'
),
'EXAMPLES': """\
To create a new backup vault ``BACKUP_VAULT'' in location ``MY_LOCATION'' with
minimum enforced-retention for backups of 1 month and 1 day, run:
$ {command} BACKUP_VAULT --location=MY_LOCATION \
--backup-min-enforced-retention="p1m1d"
To create a new backup vault ``BACKUP_VAULT'' in location ``MY_LOCATION'' with
minimum enforced-retention for backups of 1 day and description ``DESCRIPTION'',
run:
$ {command} BACKUP_VAULT --location=MY_LOCATION \
--backup-min-enforced-retention="1d" --description=DESCRIPTION
To create a new backup vault ``BACKUP_VAULT'' in location ``MY_LOCATION'' with
minimum enforced-retention for backups of 1 day and label key1 with value value1,
run:
$ {command} BACKUP_VAULT --location=MY_LOCATION \
--backup-min-enforced-retention="1d" --labels=key1=value1
To create a new backup vault ``BACKUP_VAULT'' in location ``MY_LOCATION'' with
minimum enforced-retention for backups of 1 day and effective-time "2024-03-22",
run:
$ {command} BACKUP_VAULT --location=MY_LOCATION \
--backup-min-enforced-retention="1d" --effective-time="2024-03-22"
""",
}
@staticmethod
def Args(parser: argparse.ArgumentParser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
_add_common_args(parser)
def Run(self, args: argparse.Namespace):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
return _run(
args
)
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class CreateAlpha(Create):
"""Create a Backup and DR backup vault."""
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
_add_common_args(parser)
def Run(self, args: argparse.Namespace):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
return _run(
args
)

View File

@@ -0,0 +1,141 @@
# -*- 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.
"""Deletes a Backup and DR Backup Vault."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.backup_vaults import BackupVaultsClient
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
@base.DefaultUniverseOnly
class Delete(base.DeleteCommand):
"""Delete the specified Backup Vault."""
detailed_help = {
'BRIEF': 'Deletes a specific backup vault',
'DESCRIPTION': '{description}',
'API REFERENCE': (
'This command uses the backupdr/v1 API. The full documentation for'
' this API can be found at:'
' https://cloud.google.com/backup-disaster-recovery'
),
'EXAMPLES': """\
To delete a backup vault ``BACKUP_VAULT'' in location ``MY_LOCATION'', run:
$ {command} BACKUP_VAULT --location=MY_LOCATION
To override restrictions against the deletion of a backup vault ``BACKUP_VAULT''
containing inactive datasources in location ``MY_LOCATION'', run:
$ {command} BACKUP_VAULT --location=MY_LOCATION --ignore-inactive-datasources
To override restrictions against the deletion of a backup vault ``BACKUP_VAULT''
containing backup plan references in location ``MY_LOCATION'', run:
$ {command} BACKUP_VAULT --location=MY_LOCATION --ignore-backup-plan-references
""",
}
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
flags.AddBackupVaultResourceArg(
parser,
'Name of the backup vault to delete. Before you delete, take a look at'
' the prerequisites'
' [here](https://cloud.google.com/backup-disaster-recovery/docs/configuration/decommission).',
)
flags.AddNoAsyncFlag(parser)
flags.AddIgnoreInactiveDatasourcesFlag(parser)
flags.AddIgnoreBackupPlanReferencesFlag(parser)
flags.AddAllowMissing(parser, 'backup vault')
def Run(self, args):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = BackupVaultsClient()
backup_vault = args.CONCEPTS.backup_vault.Parse()
no_async = args.no_async
console_io.PromptContinue(
message=(
'The backup vault will be deleted. You cannot undo this action.'
),
default=True,
cancel_on_no=True,
)
try:
operation = client.Delete(
backup_vault,
ignore_inactive_datasources=args.ignore_inactive_datasources,
ignore_backup_plan_references=args.ignore_backup_plan_references,
allow_missing=args.allow_missing,
)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
operation_ref = client.GetOperationRef(operation)
if args.allow_missing and operation_ref == 'None':
log.DeletedResource(
operation.name,
kind='backup vault',
is_async=False,
details=(
'= requested backup vault [{}] was not found.'.format(
backup_vault.RelativeName()
)
),
)
return operation
if no_async:
return client.WaitForOperation(
operation_ref=operation_ref,
message=(
'Deleting backup vault [{}]. (This operation could'
' take up to 2 minutes.)'.format(backup_vault.RelativeName())
),
has_result=False,
)
log.DeletedResource(
backup_vault.RelativeName(),
kind='backup vault',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
)
return operation

View File

@@ -0,0 +1,89 @@
# -*- 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.
"""Show the metadata for a Backup and DR backup vault."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.backupdr.backup_vaults import BackupVaultsClient
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.command_lib.backupdr import util as command_util
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class Describe(base.DescribeCommand):
"""Show the metadata for a Backup and DR backup vault."""
detailed_help = {
'BRIEF': 'Show the metadata for a Backup and DR backup vault.',
'DESCRIPTION': '{description}',
'API REFERENCE': (
'This command uses the backupdr/v1 API. The full documentation for'
' this API can be found at:'
' https://cloud.google.com/backup-disaster-recovery'
),
'EXAMPLES': """\
To view details associated with backup vault 'BACKUP_VAULT', run:
$ {command} BACKUP_VAULT
""",
}
DEFAULT_DESCRIBE_FORMAT = """
json(
name.basename(),
description,
createTime,
updateTime,
accessRestriction,
deletable,
state,
totalStoredBytes,
etag,
serviceAccount,
uid,
backupCount,
labels,
backupMinimumEnforcedRetentionDuration,
effectiveTime,
backupRetentionInheritance,
encryptionConfig
)
"""
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
flags.AddBackupVaultResourceArg(
parser,
'Name of the backup vault to retreive metadata of.',
)
flags.AddOutputFormat(parser, Describe.DEFAULT_DESCRIBE_FORMAT)
def Run(self, args):
client = BackupVaultsClient()
backup_vault = args.CONCEPTS.backup_vault.Parse()
bv_details = client.Describe(backup_vault)
bv_details.backupMinimumEnforcedRetentionDuration = (
command_util.TransformEnforcedRetention(bv_details)
)
return bv_details

View File

@@ -0,0 +1,79 @@
# -*- 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.
"""List Backup and DR backup vaults."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.backupdr.backup_vaults import BackupVaultsClient
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class List(base.ListCommand):
"""List Backup and DR backup vaults."""
detailed_help = {
'BRIEF': 'List Backup and DR backup vaults.',
'DESCRIPTION': '{description}',
'API REFERENCE': (
'This command uses the backupdr/v1 API. The full documentation for'
' this API can be found at:'
' https://cloud.google.com/backup-disaster-recovery'
),
'EXAMPLES': """\
To list backup vaults in all location, run:
$ {command}
To list backup vaults in a location ''my-location'', run:
$ {command} --location=my-location
""",
}
DEFAULT_LIST_FORMAT = """
table(
name.basename(),
createTime:label=CREATED,
state:label=STATUS,
name.scope("locations").segment(0):label=LOCATION,
totalStoredBytes:label=STORED_BYTES,
backupMinimumEnforcedRetentionDuration():label=BACKUP_MINIMUM_ENFORCED_RETENTION_DURATION
)
"""
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
flags.AddOutputFormat(parser, List.DEFAULT_LIST_FORMAT)
flags.AddLocationResourceArg(
parser,
'Location for which backup vaults should be listed.',
default='-',
)
parser.display_info.AddCacheUpdater(None)
def Run(self, args):
parent_ref = args.CONCEPTS.location.Parse()
client = BackupVaultsClient()
return client.List(parent_ref)

View File

@@ -0,0 +1,307 @@
# -*- 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.
"""Updates a Backup and DR Backup Vault."""
import argparse
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.backup_vaults import BackupVaultsClient
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions as calliope_exceptions
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.command_lib.backupdr import util as command_util
from googlecloudsdk.core import log
def _add_common_args(parser: argparse.ArgumentParser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
flags.AddBackupVaultResourceArg(
parser,
'Name of the existing backup vault to update.',
)
flags.AddNoAsyncFlag(parser)
flags.AddEnforcedRetention(parser, False)
flags.AddDescription(parser)
flags.AddEffectiveTime(parser)
flags.AddUnlockBackupMinEnforcedRetention(parser)
flags.AddForceUpdateFlag(parser)
flags.AddForceUpdateAccessRestriction(parser)
flags.AddBackupVaultAccessRestrictionEnumFlag(parser, 'update')
def _add_common_update_mask(args: argparse.Namespace) -> str:
"""Creates the update mask for the update command.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
A string containing the update mask.
"""
updated_fields = []
if args.IsSpecified('description'):
updated_fields.append('description')
if args.IsSpecified('backup_min_enforced_retention'):
updated_fields.append('backupMinimumEnforcedRetentionDuration')
if args.IsSpecified(
'unlock_backup_min_enforced_retention'
) or args.IsSpecified('effective_time'):
updated_fields.append('effectiveTime')
if args.IsSpecified('access_restriction'):
updated_fields.append('accessRestriction')
return ','.join(updated_fields)
def _parse_update_bv(args: argparse.Namespace):
"""Parses the update backup vault arguments.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
A tuple containing the backup min enforced retention, description and
effective time.
Raises:
calliope_exceptions.ConflictingArgumentsException: If both
--unlock-backup-min-enforced-retention and --effective-time are specified.
"""
backup_min_enforced_retention = command_util.ConvertIntToStr(
args.backup_min_enforced_retention
)
description = args.description
if args.unlock_backup_min_enforced_retention and args.effective_time:
raise calliope_exceptions.ConflictingArgumentsException(
'Only one of --unlock-backup-min-enforced-retention or '
'--effective-time can be specified.'
)
if args.unlock_backup_min_enforced_retention:
effective_time = command_util.ResetEnforcedRetention()
else:
effective_time = command_util.VerifyDateInFuture(
args.effective_time, 'effective-time'
)
if args.access_restriction:
access_restriction = args.access_restriction
else:
access_restriction = None
return (
backup_min_enforced_retention,
description,
effective_time,
access_restriction,
)
def _run(
self,
args: argparse.Namespace,
):
"""Constructs and sends request.
Args:
self: The object that is calling this method.
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
Raises:
exceptions.HttpException: if the http request fails.
"""
client = BackupVaultsClient()
backup_vault = args.CONCEPTS.backup_vault.Parse()
no_async = args.no_async
force_update_access_restriction = args.force_update_access_restriction
try:
parsed_bv = self.ParseUpdateBv(args, client)
update_mask = self.GetUpdateMask(args)
operation = client.Update(
backup_vault,
parsed_bv,
force_update=args.force_update,
update_mask=update_mask,
force_update_access_restriction=force_update_access_restriction,
)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
if no_async:
resource = client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'Updating backup vault [{}]. (This operation could'
' take up to 1 minute.)'.format(backup_vault.RelativeName())
),
has_result=False,
)
log.UpdatedResource(backup_vault.RelativeName(), kind='backup vault')
return resource
log.UpdatedResource(
backup_vault.RelativeName(),
kind='backup vault',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
)
return operation
@base.ReleaseTracks(base.ReleaseTrack.GA)
@base.DefaultUniverseOnly
class Update(base.UpdateCommand):
"""Update a Backup and DR backup vault."""
detailed_help = {
'BRIEF': 'Updates a Backup and DR backup vault.',
'DESCRIPTION': '{description}',
'API REFERENCE': (
'This command uses the backupdr/v1 API. The full documentation for'
' this API can be found at:'
' https://cloud.google.com/backup-disaster-recovery'
),
'EXAMPLES': """\
To update a backup vault BACKUP_VAULT in location MY_LOCATION with one update
field, run:
$ {command} BACKUP_VAULT --location=MY_LOCATION --effective-time="2024-03-22"
To update a backup vault BACKUP_VAULT in location MY_LOCATION with multiple
update fields, run:
$ {command} BACKUP_VAULT --location=MY_LOCATION \
--backup-min-enforced-retention="400000s" --description="Updated backup vault"
""",
}
@staticmethod
def Args(parser: argparse.ArgumentParser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
_add_common_args(parser)
def GetUpdateMask(self, args: argparse.Namespace) -> str:
"""Returns the update mask for the update command.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
A string containing the update mask.
"""
return _add_common_update_mask(args)
def ParseUpdateBv(self, args: argparse.Namespace, client: BackupVaultsClient):
"""Parses the update backup vault arguments.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
client: BackupVaultsClient, The client to use to parse the backup vault.
Returns:
A parsed backup vault object.
"""
(
backup_min_enforced_retention,
description,
effective_time,
access_restriction,
) = _parse_update_bv(args)
return client.ParseUpdate(
description=description,
backup_min_enforced_retention=backup_min_enforced_retention,
effective_time=effective_time,
access_restriction=access_restriction,
)
def Run(self, args):
return _run(self, args)
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class UpdateAlpha(Update):
"""Update a Backup and DR backup vault."""
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
_add_common_args(parser)
def ParseUpdateBv(self, args: argparse.Namespace, client: BackupVaultsClient):
"""Parses the update backup vault arguments.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
client: BackupVaultsClient, The client to use to parse the backup vault.
Returns:
A parsed backup vault object.
"""
(
backup_min_enforced_retention,
description,
effective_time,
access_restriction,
) = _parse_update_bv(args)
return client.ParseUpdate(
description=description,
backup_min_enforced_retention=backup_min_enforced_retention,
effective_time=effective_time,
access_restriction=access_restriction,
)
def GetUpdateMask(self, args: argparse.Namespace) -> str:
"""Returns the update mask for the update command.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
A string containing the update mask.
"""
mask = _add_common_update_mask(args)
return mask
def Run(self, args):
return _run(self, args)

View File

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

View File

@@ -0,0 +1,105 @@
# -*- 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.
"""Deletes a Backup and DR Backup."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.backups import BackupsClient
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class Delete(base.DeleteCommand):
"""Delete the specified Backup."""
detailed_help = {
'BRIEF': 'Deletes a specific backup',
'DESCRIPTION': '{description}',
'EXAMPLES': """\
To delete a backup `sample-backup` in backup vault `sample-vault`, data source `sample-ds`, project `sample-project` and location `us-central1` , run:
$ {command} sample-backup --backup-vault=sample-vault --data-source=sample-ds --project=sample-project --location=us-central1
""",
}
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
base.ASYNC_FLAG.AddToParser(parser)
base.ASYNC_FLAG.SetDefault(parser, True)
flags.AddBackupResourceArg(
parser,
'Name of the backup to delete.',
)
def Run(self, args):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = BackupsClient()
is_async = args.async_
backup = args.CONCEPTS.backup.Parse()
console_io.PromptContinue(
message='The backup will be deleted. You cannot undo this action.',
default=True,
cancel_on_no=True,
)
try:
operation = client.Delete(backup)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
if is_async:
log.DeletedResource(
backup.RelativeName(),
kind='backup',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
)
return operation
response = client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'Deleting backup [{}]. (This operation usually takes 5 mins but'
' could take up to 60 mins.)'.format(backup.RelativeName())
),
has_result=False,
)
log.DeletedResource(backup.RelativeName(), kind='backup')
return response

View File

@@ -0,0 +1,23 @@
- release_tracks: [ALPHA, GA]
help_text:
brief: Show details of the backup.
description: Show all data associated with the specified backup.
examples: |
To view details for backup 'BACKUP', run:
$ {command} BACKUP
request:
collection: backupdr.projects.locations.backupVaults.dataSources.backups
response:
id_field: name
arguments:
resource:
help_text: Name of the backup to describe.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:backup
is_positional: true
output:
format: json

View File

@@ -0,0 +1,126 @@
# -*- 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.
"""Command to fetch backups for a resource type."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.api_lib.backupdr import backups
from googlecloudsdk.api_lib.util import common_args
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.command_lib.util.concepts import concept_parsers
from googlecloudsdk.core import log
BackupsClient = (
backups.BackupsClient
)
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class FetchForResourceType(base.ListCommand):
"""Fetch Backups for a given resource type and location."""
detailed_help = {
'BRIEF': (
'List backups in a specified location'
' and resource type in a project.'
),
'DESCRIPTION': (
'{description} List backups for the specified resource type for a '
'data source.'
),
'EXAMPLES': """\
To list backups for Cloud SQL instance resources for data source `my-data-source` with location `us-central1` under backup vault, `my-vault`.
$ {command} sqladmin.googleapis.com/Instance --data-source=my-data-source --backup-vault=my-vault --location=us-central1
""",
}
DEFAULT_LIST_FORMAT = """
table(
name.basename():label=NAME,
description:label=DESCRIPTION,
createTime:label=CREATE_TIME,
enforcedRetentionEndTime:label=ENFORCED_RETENTION_END_TIME,
state:label=STATE,
backupType:label=BACKUP_TYPE,
expireTime:label=EXPIRE_TIME,
resourceSizeBytes:label=RESOURCE_SIZE_BYTES
)
"""
@staticmethod
def Args(parser):
parser.add_argument(
'resource_type',
help=(
'Resource type for which backup plan associations should be'
' fetched.'
),
)
concept_parsers.ConceptParser.ForResource(
'--data-source',
flags.GetDataSourceResourceSpec(),
'Data source for which backups should be fetched.',
required=True).AddToParser(parser)
flags.AddOutputFormat(parser, FetchForResourceType.DEFAULT_LIST_FORMAT)
def _Validate_and_Parse_SortBy(self, args):
order_by = common_args.ParseSortByArg(args.sort_by)
# Only sort by name is supported by CLH right now.
if order_by is None:
return None
order_by_fields = order_by.split(' ')
if (
order_by_fields
and isinstance(order_by_fields[0], str)
and order_by_fields[0]
not in ('name', 'Name')
):
raise exceptions.InvalidArgumentException(
'sort_by',
'Invalid sort_by argument. Only sort_by'
' name/Name is'
' supported.',
)
order_by_fields[0] = 'name'
order_by = ' '.join(order_by_fields)
return order_by
def Run(self, args):
"""Run the command."""
resource_type = args.resource_type
data_source_ref = args.CONCEPTS.data_source.Parse()
try:
client = BackupsClient()
result = client.FetchForResourceType(
data_source_ref,
resource_type,
filter_expression=args.filter,
page_size=args.page_size,
order_by=self._Validate_and_Parse_SortBy(args),
)
if result and result.backups:
return result.backups # Return the list directly
else:
return [] # Return an empty list
except Exception as e: # pylint: disable=broad-except
log.error(f'Error fetching backups : {e}')
raise e # Raise the exception

View File

@@ -0,0 +1,29 @@
- release_tracks: [ALPHA, GA]
help_text:
brief: List Backups
description: Displays all backups in a project.
examples: |
To list backups for all data sources, backup vaults and locations, run:
$ {command}
To list all backups for a data source ``my-data-source'' and a backup vault ``my-vault'' in a location ``my-location'', run:
$ {command} --data-source=my-data-source --backup-vault=my-vault --location=my-location
request:
collection: backupdr.projects.locations.backupVaults.dataSources.backups
modify_request_hooks:
- googlecloudsdk.command_lib.backupdr.declarative:SetBasicViewByDefaultRequestHook
response:
id_field: name
arguments:
resource:
help_text: Data source to list backups from.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:dataSourceDefault
is_positional: false
output:
format: |
json

View File

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

View File

@@ -0,0 +1,257 @@
# -*- 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.
"""Restores a Compute Instance Backup."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.backups import BackupsClient
from googlecloudsdk.api_lib.backupdr.backups import ComputeRestoreConfig
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.command_lib.backupdr.restore import compute_flags
from googlecloudsdk.core import log
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class Compute(base.Command):
"""Restores a Compute Engine VM Backup."""
detailed_help = {
'BRIEF': 'Restores the specified backup',
'DESCRIPTION': '{description}',
'EXAMPLES': """\
To restore a backup `sample-backup` in project `sample-project` and location `us-central1`,
with `sample-data-store` and `sample-backup-vault`, and additional target properties, run:
$ {command} sample-backup --project=sample-project --location=us-central1 --backup-vault=sample-backup-vault --data-source=sample-data-source --<target-properties>
""",
}
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
base.ASYNC_FLAG.AddToParser(parser)
base.ASYNC_FLAG.SetDefault(parser, True)
flags.AddBackupResourceArg(
parser, 'The backup of a resource to be restored.'
)
compute_flags.AddNameArg(parser)
compute_flags.AddTargetZoneArg(parser)
compute_flags.AddTargetProjectArg(parser)
compute_flags.AddNetworkInterfaceArg(parser, False)
compute_flags.AddServiceAccountArg(parser, False)
compute_flags.AddScopesArg(parser, False)
compute_flags.AddCreateDiskArg(parser, False)
compute_flags.AddDescriptionArg(parser, False)
compute_flags.AddMetadataArg(parser, False)
compute_flags.AddLabelsArg(parser, False)
compute_flags.AddTagsArg(parser, False)
compute_flags.AddMachineTypeArg(parser, False)
compute_flags.AddHostnameArg(parser, False)
compute_flags.AddEnableUefiNetworkingArg(parser, False)
compute_flags.AddThreadsPerCoreArg(parser, False)
compute_flags.AddVisibleCoreCountArg(parser, False)
compute_flags.AddAcceleratorArg(parser, False)
compute_flags.AddMinCpuPlatform(parser, False)
# Scheduling Flags
compute_flags.AddMaintenancePolicyArg(parser, False)
compute_flags.AddPreemptibleArg(parser, False)
compute_flags.AddRestartOnFailureArg(parser, False)
compute_flags.AddMinNodeCpuArg(parser, False)
compute_flags.AddProvisioningModelArg(parser, False)
compute_flags.AddInstanceTerminationActionArg(parser, False)
compute_flags.AddLocalSsdRecoveryTimeoutArg(parser, False)
compute_flags.AddNodeAffinityFileArg(parser, False)
compute_flags.AddReservationArgs(parser, False)
compute_flags.AddEnableDisplayDeviceArg(parser, False)
compute_flags.AddCanIpForwardArg(parser, False)
compute_flags.AddPrivateIpv6GoogleAccessArg(parser, False)
compute_flags.AddNetworkPerformanceConfigsArg(parser, False)
compute_flags.AddConfidentialComputeArg(parser, False)
compute_flags.AddDeletionProtectionArg(parser, False)
compute_flags.AddResourceManagerTagsArg(parser, False)
compute_flags.AddResourcePoliciesArg(parser, False)
compute_flags.AddKeyRevocationActionTypeArg(parser, False)
compute_flags.AddInstanceKmsKeyArg(parser, False)
compute_flags.AddClearEncryptionKeyArg(parser)
def _ParseResourcePolicies(self, resource_policies, project, zone):
"""Parses the resource policies flag."""
resource_policy_uris = []
for policy in resource_policies:
if not policy.startswith('projects/'):
region = zone.rsplit('-', 1)[0]
policy = (
'projects/{}/regions/{}/resourcePolicies/{}'.format(
project, region, policy
)
)
resource_policy_uris.append(policy)
return resource_policy_uris
def Run(self, args):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = BackupsClient()
is_async = args.async_
backup = args.CONCEPTS.backup.Parse()
restore_config = ComputeRestoreConfig()
restore_config['Name'] = args.name
restore_config['TargetZone'] = args.target_zone
restore_config['TargetProject'] = args.target_project
if args.network_interface:
restore_config['NetworkInterfaces'] = args.network_interface
if args.service_account:
restore_config['ServiceAccount'] = args.service_account
if args.scopes:
restore_config['Scopes'] = args.scopes
restore_config['NoScopes'] = args.no_scopes if args.no_scopes else False
if args.create_disk:
restore_config['CreateDisks'] = args.create_disk
if args.description:
restore_config['Description'] = args.description
if args.metadata:
restore_config['Metadata'] = args.metadata
if args.labels:
restore_config['Labels'] = args.labels
if args.tags:
restore_config['Tags'] = args.tags
if args.machine_type:
if not args.machine_type.startswith('projects/'):
args.machine_type = 'projects/{}/zones/{}/machineTypes/{}'.format(
args.target_project, args.target_zone, args.machine_type
)
restore_config['MachineType'] = args.machine_type
if args.hostname:
restore_config['Hostname'] = args.hostname
if args.enable_uefi_networking is not None:
restore_config['EnableUefiNetworking'] = args.enable_uefi_networking
if args.threads_per_core:
restore_config['ThreadsPerCore'] = args.threads_per_core
if args.visible_core_count:
restore_config['VisibleCoreCount'] = args.visible_core_count
if args.accelerator:
if not args.accelerator['type'].startswith('projects/'):
args.accelerator['type'] = (
'projects/{}/zones/{}/acceleratorTypes/{}'.format(
args.target_project, args.target_zone, args.accelerator['type']
)
)
restore_config['Accelerator'] = args.accelerator
if args.min_cpu_platform:
restore_config['MinCpuPlatform'] = args.min_cpu_platform
if args.maintenance_policy:
restore_config['MaintenancePolicy'] = args.maintenance_policy
if args.preemptible is not None:
restore_config['Preemptible'] = args.preemptible
if args.restart_on_failure is not None:
restore_config['RestartOnFailure'] = args.restart_on_failure
if args.min_node_cpu:
restore_config['MinNodeCpus'] = args.min_node_cpu
if args.provisioning_model:
restore_config['ProvisioningModel'] = args.provisioning_model
if args.instance_termination_action:
restore_config['InstanceTerminationAction'] = (
args.instance_termination_action
)
if args.local_ssd_recovery_timeout:
restore_config['LocalSsdRecoveryTimeout'] = (
args.local_ssd_recovery_timeout
)
if args.node_affinity_file:
restore_config['NodeAffinityFile'] = args.node_affinity_file
if args.reservation_affinity:
restore_config['ReservationAffinity'] = args.reservation_affinity
if args.reservation:
restore_config['Reservation'] = args.reservation
if args.enable_display_device is not None:
restore_config['EnableDisplayDevice'] = args.enable_display_device
if args.can_ip_forward is not None:
restore_config['CanIpForward'] = args.can_ip_forward
if args.private_ipv6_google_access_type:
restore_config['PrivateIpv6GoogleAccessType'] = (
args.private_ipv6_google_access_type
)
if args.network_performance_configs:
restore_config['NetworkPerformanceConfigs'] = (
args.network_performance_configs
)
if args.confidential_compute:
restore_config['ConfidentialCompute'] = args.confidential_compute
if args.deletion_protection is not None:
restore_config['DeletionProtection'] = args.deletion_protection
if args.resource_manager_tags:
restore_config['ResourceManagerTags'] = args.resource_manager_tags
if args.resource_policies:
restore_config['ResourcePolicies'] = self._ParseResourcePolicies(
args.resource_policies, args.target_project, args.target_zone
)
if args.key_revocation_action_type:
restore_config['KeyRevocationActionType'] = (
args.key_revocation_action_type
)
if args.instance_kms_key:
restore_config['InstanceKmsKey'] = args.instance_kms_key
if args.clear_encryption_key:
restore_config['ClearOverridesFieldMask'] = (
'compute_instance_restore_properties.disks.*.disk_encryption_key'
)
try:
operation = client.RestoreCompute(backup, restore_config)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT) from e
if is_async:
log.RestoredResource(
backup.Name(),
kind='backup',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
)
return operation
# For sync operation
return client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'Restoring backup'
' [{}].'
' (This operation could take up to 15 minutes.)'.format(
backup.Name()
)
),
has_result=False,
)

View File

@@ -0,0 +1,179 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 Google LLC. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Restores a Compute Disk Backup."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.backups import BackupsClient
from googlecloudsdk.api_lib.backupdr.backups import DiskRestoreConfig
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.command_lib.backupdr.restore import disk_flags
from googlecloudsdk.core import log
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class Disk(base.Command):
"""Restores a Compute Disk Backup."""
detailed_help = {
'BRIEF': 'Restores the specified backup',
'DESCRIPTION': '{description}',
'EXAMPLES': """\
To restore a backup `sample-backup` in project `sample-project` and location `us-central1`,
with `sample-data-store` and `sample-backup-vault`, and additional target properties, run:
$ {command} sample-backup --project=sample-project --location=us-central1 --backup-vault=sample-backup-vault --data-source=sample-data-source --<target-properties>
""",
}
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
base.ASYNC_FLAG.AddToParser(parser)
base.ASYNC_FLAG.SetDefault(parser, True)
flags.AddBackupResourceArg(
parser, 'The backup of a resource to be restored.'
)
disk_flags.AddNameArg(parser)
disk_flags.AddTargetZoneArg(parser, False)
disk_flags.AddTargetRegionArg(parser, False)
disk_flags.AddTargetProjectArg(parser)
disk_flags.AddReplicaZonesArg(parser, False)
disk_flags.AddGuestOsFeaturesArgs(parser, False)
disk_flags.AddDescriptionArg(parser, False)
disk_flags.AddLicensesArg(parser, False)
disk_flags.AddLabelsArg(parser, False)
disk_flags.AddTypeArg(parser, False)
disk_flags.AddAccessModeArg(parser, False)
disk_flags.AddProvisionedIopsArg(parser, False)
disk_flags.AddProvisionedThroughputArg(parser, False)
disk_flags.AddArchitectureArg(parser, False)
disk_flags.AddStoragePoolArg(parser, False)
disk_flags.AddSizeArg(parser, False)
disk_flags.AddConfidentialComputeArg(parser, False)
disk_flags.AddResourcePoliciesArg(parser, False)
disk_flags.AddKmsKeyArg(parser, False)
disk_flags.AddClearEncryptionKeyArg(parser)
def _ParseResourcePolicies(self, resource_policies, project, zone):
"""Parses the resource policies flag."""
resource_policy_uris = []
for policy in resource_policies:
if not policy.startswith('projects/'):
region = zone.rsplit('-', 1)[0]
policy = 'projects/{}/regions/{}/resourcePolicies/{}'.format(
project, region, policy
)
resource_policy_uris.append(policy)
return resource_policy_uris
def Run(self, args):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = BackupsClient()
is_async = args.async_
backup = args.CONCEPTS.backup.Parse()
restore_config = DiskRestoreConfig()
restore_config['Name'] = args.name
restore_config['TargetProject'] = args.target_project
if args.target_zone:
restore_config['TargetZone'] = args.target_zone
if args.target_region:
restore_config['TargetRegion'] = args.target_region
if args.replica_zones:
restore_config['ReplicaZones'] = args.replica_zones
if args.guest_os_features:
restore_config['GuestOsFeatures'] = args.guest_os_features
if args.licenses:
restore_config['Licenses'] = args.licenses
if args.description:
restore_config['Description'] = args.description
if args.type:
restore_config['Type'] = args.type
if args.access_mode:
restore_config['AccessMode'] = args.access_mode
if args.provisioned_iops:
restore_config['ProvisionedIops'] = args.provisioned_iops
if args.provisioned_throughput:
restore_config['ProvisionedThroughput'] = args.provisioned_throughput
if args.architecture:
restore_config['Architecture'] = args.architecture
if args.storage_pool:
restore_config['StoragePool'] = args.storage_pool
if args.size:
restore_config['Size'] = args.size
if args.kms_key:
restore_config['KmsKey'] = args.kms_key
if args.labels:
restore_config['Labels'] = args.labels
restore_config['ConfidentialCompute'] = args.confidential_compute
if args.resource_policies:
restore_config['ResourcePolicies'] = self._ParseResourcePolicies(
args.resource_policies, args.target_project, args.target_zone
)
if (
hasattr(args, 'clear_encryption_key')
and args.clear_encryption_key
):
restore_config['ClearOverridesFieldMask'] = (
'disk_restore_properties.disk_encryption_key'
)
try:
operation = client.RestoreDisk(backup, restore_config)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT) from e
if is_async:
log.RestoredResource(
backup.Name(),
kind='backup',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
)
return operation
# For sync operation
return client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'Restoring backup'
' [{}].'
' (This operation could take upto 15 minutes.)'.format(
backup.Name()
)
),
has_result=False,
)

View File

@@ -0,0 +1,161 @@
# -*- 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.
"""Updates a Backup and DR Backup."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
import argparse
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.backups import BackupsClient
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.command_lib.backupdr import util as command_util
from googlecloudsdk.core import log
def _add_common_args(parser: argparse.ArgumentParser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
base.ASYNC_FLAG.AddToParser(parser)
base.ASYNC_FLAG.SetDefault(parser, True)
flags.AddBackupResourceArg(
parser,
'Name of the backup to update.',
)
flags.AddUpdateBackupFlags(parser)
def _add_common_update_mask(args) -> str:
updated_fields = []
if args.IsSpecified('enforced_retention_end_time'):
updated_fields.append('enforcedRetentionEndTime')
if args.IsSpecified('expire_time'):
updated_fields.append('expireTime')
return ','.join(updated_fields)
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.GA)
class Update(base.UpdateCommand):
"""Update the specified Backup."""
detailed_help = {
'BRIEF': 'Updates a specific backup',
'DESCRIPTION': '{description}',
'EXAMPLES': """\
To update the enforced retention of a backup sample-backup in backup vault sample-vault, data source
sample-ds, project sample-project and location us-central1, run:
$ {command} sample-backup --backup-vault=sample-vault --data-source=sample-ds --project=sample-project --location=us-central1 --enforced-retention-end-time="2025-02-14T01:10:20Z"
""",
}
@staticmethod
def Args(parser: argparse.ArgumentParser):
_add_common_args(parser)
def ParseUpdate(self, args, client):
updated_enforced_retention = command_util.VerifyDateInFuture(
args.enforced_retention_end_time, 'enforced-retention-end-time'
)
expire_time = command_util.VerifyDateInFuture(
args.expire_time, 'expire-time'
)
parsed_backup = client.ParseUpdate(updated_enforced_retention, expire_time)
return parsed_backup
def GetUpdateMask(self, args):
return _add_common_update_mask(args)
def Run(self, args):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = BackupsClient()
is_async = args.async_
backup = args.CONCEPTS.backup.Parse()
try:
parsed_backup = self.ParseUpdate(args, client)
update_mask = self.GetUpdateMask(args)
operation = client.Update(
backup,
parsed_backup,
update_mask=update_mask,
)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
if is_async:
log.UpdatedResource(
backup.RelativeName(),
kind='backup',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
)
return operation
response = client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'Updating backup [{}]. (This operation usually takes less than 1'
' minute.)'.format(backup.RelativeName())
),
has_result=False,
)
log.UpdatedResource(backup.RelativeName(), kind='backup')
return response
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class UpdateAlpha(Update):
"""Update the specified Backup."""
@staticmethod
def Args(parser: argparse.ArgumentParser):
_add_common_args(parser)
def ParseUpdate(self, args, client):
updated_enforced_retention = command_util.VerifyDateInFuture(
args.enforced_retention_end_time, 'enforced-retention-end-time'
)
expire_time = command_util.VerifyDateInFuture(
args.expire_time, 'expire-time'
)
parsed_backup = client.ParseUpdate(updated_enforced_retention, expire_time)
return parsed_backup
def GetUpdateMask(self, args):
return _add_common_update_mask(args)

View File

@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Command group for Backup and DR data source references."""
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.util.concepts import concept_parsers
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class DataSourceReferences(base.Group):
"""Command group for Backup and DR Data Source References."""
group = True
commands = ['describe', 'fetch-for-resource-type']

View File

@@ -0,0 +1,23 @@
- release_tracks: [ALPHA, GA]
help_text:
brief: Show details of the data source reference.
description: Show all configuration data source associated with the specified data source reference.
examples: |
To view details for data source 'DATA_SOURCE_REFERENCE', run:
$ {command} DATA_SOURCE_REFERENCE
request:
collection: backupdr.projects.locations.dataSourceReferences
response:
id_field: name
arguments:
resource:
help_text: Name of the data source reference to describe.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:dataSourceReference
is_positional: true
output:
format: json

View File

@@ -0,0 +1,141 @@
# -*- 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.
"""Command to fetch data source references for a resource type."""
from googlecloudsdk.api_lib.backupdr import data_source_references
from googlecloudsdk.api_lib.util import common_args
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import log
DataSourceReferencesClient = data_source_references.DataSourceReferencesClient
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class FetchForResourceType(base.ListCommand):
"""Fetch Data Source References for a given resource type and location."""
detailed_help = {
'BRIEF': (
'List data source references in a specified location and resource'
' type in a project.'
),
'DESCRIPTION': (
'{description} Show all configuration data associated with the'
' specified data source reference.'
),
'EXAMPLES': """\
To list data source references for Cloud SQL with location `us-central1` in project `test-project`, run:
$ {command} sqladmin.googleapis.com/Instance --location="us-central1" --project="test-project"
""",
}
DEFAULT_LIST_FORMAT = """
table(
name.basename():label=NAME,
dataSourceGcpResourceInfo.type:label=RESOURCE_TYPE,
dataSourceGcpResourceInfo.gcpResourcename:label=RESOURCE_NAME,
dataSource:label=DATA_SOURCE,
dataSourceBackupConfigState:label=BACKUP_CONFIG_STATE,
dataSourceGcpResourceInfo.location:label=LOCATION
)
"""
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
parser.add_argument(
'--location',
required=True,
help='Location for which data source references should be fetched.',
)
parser.add_argument(
'resource_type',
help=(
'Resource type for which data source references should be fetched.'
),
)
flags.AddOutputFormat(parser, FetchForResourceType.DEFAULT_LIST_FORMAT)
def _Validate_and_Parse_SortBy(self, args):
"""Validates and parses the sort_by argument.
Args:
args: The arguments that were provided to the command.
Returns:
The parsed order_by string, or None if no sort_by argument was provided.
Raises:
exceptions.InvalidArgumentException: If the sort_by argument is invalid.
"""
order_by = common_args.ParseSortByArg(args.sort_by)
# Only sort by name is supported by CLH right now.
if order_by is None:
return None
order_by_fields = order_by.split(' ')
if (
order_by_fields
and isinstance(order_by_fields[0], str)
and order_by_fields[0]
not in ('name', 'Name')
):
raise exceptions.InvalidArgumentException(
'sort_by',
'Invalid sort_by argument. Only sort_by name/Name is supported.',
)
order_by_fields[0] = 'name'
order_by = ' '.join(order_by_fields)
return order_by
def Run(self, args):
"""Run the command.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the Args method.
Returns:
List of data source references.
Raises:
exceptions.Error: If the API call fails.
"""
location = args.location
resource_type = args.resource_type
try:
client = DataSourceReferencesClient()
result = client.FetchForResourceType(
location,
resource_type,
filter_expression=args.filter,
page_size=args.page_size,
order_by=self._Validate_and_Parse_SortBy(args),
)
if result and result.dataSourceReferences:
data_source_refs = result.dataSourceReferences
return data_source_refs
return [] # Return an empty list
except Exception as e: # pylint: disable=broad-except
log.error(f'Error fetching data source references: {e}')
raise # Raise the exception

View File

@@ -0,0 +1,34 @@
- release_tracks: [ALPHA, GA]
help_text:
brief: List Backup and DR data source references.
description: List Backup and DR data source references.
examples: |
To list data source references in all locations, run:
$ {command}
To list data source references in a location 'my-location', run:
$ {command} --location=my-location
request:
collection: backupdr.projects.locations.dataSourceReferences
response:
id_field: name
arguments:
resource:
help_text: Location for which data source references should be listed.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:locationDefaultGlobal
is_positional: false
output:
format: |
table(
name.basename():label=NAME,
dataSourceGcpResourceInfo.type:label=RESOURCE_TYPE,
dataSourceGcpResourceInfo.gcpResourcename:label=RESOURCE_NAME,
dataSource:label=DATA_SOURCE,
dataSourceBackupConfigState:label=BACKUP_CONFIG_STATE,
dataSourceGcpResourceInfo.location:label=LOCATION
)

View File

@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*- #
# Copyright 2024 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Command group for Backup and DR data source."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class DataSources(base.Group):
"""View Backup and DR data sources."""

View File

@@ -0,0 +1,23 @@
- release_tracks: [ALPHA, GA]
help_text:
brief: Show details of the data source.
description: Show all configuration data associated with the specified data source.
examples: |
To view details for data source 'DATA_SOURCE', run:
$ {command} DATA_SOURCE
request:
collection: backupdr.projects.locations.backupVaults.dataSources
response:
id_field: name
arguments:
resource:
help_text: Name of the data source to describe.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:dataSource
is_positional: true
output:
format: json

View File

@@ -0,0 +1,26 @@
- release_tracks: [ALPHA, GA]
help_text:
brief: List Data Sources
description: Displays all data sources in a project.
examples: |
To list data sources for all backup vaults and locations, run:
$ {command}
To list all data sources for a backup vault ``my-vault'' in a location ``my-location'', run:
$ {command} --backup-vault=my-vault --location=my-location
request:
collection: backupdr.projects.locations.backupVaults.dataSources
response:
id_field: name
arguments:
resource:
help_text: Backup vault to list data sources from.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:backupVaultDefault
is_positional: false
output:
format: json

View File

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

View File

@@ -0,0 +1,25 @@
- release_tracks: [ALPHA, BETA, GA]
help_text:
brief: List available Backup and DR locations.
description: List all locations where Backup and DR Service is available.
examples: |
To list all locations, run:
$ {command}
request:
collection: backupdr.projects.locations
response:
id_field: name
arguments:
resource:
help_text: The parent project of Backup and DR Locations to list.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:project
output:
format: |
table(
name
)

View File

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

View File

@@ -0,0 +1,113 @@
# -*- 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.
"""Creates a new Backup and DR Management Server."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.management_servers import ManagementServersClient
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import log
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
@base.DefaultUniverseOnly
class Create(base.CreateCommand):
"""Create a new management server in the project."""
detailed_help = {
'BRIEF': 'Creates a new management server',
'DESCRIPTION': (
'{description} A management server is required to access the'
' management console. It can only be created in locations where'
' Backup and DR is available. Resources in other locations can be'
' backed up.'
),
'EXAMPLES': """\
To create a new management server `sample-ms` in project `sample-project` and location `us-central1`, run:
$ {command} sample-ms --project=sample-project --location=us-central1
""",
}
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
base.ASYNC_FLAG.AddToParser(parser)
base.ASYNC_FLAG.SetDefault(parser, True)
flags.AddManagementServerResourceArg(
parser,
'Name of the management server to be created. Once the management'
" server is deployed, this name can't be changed. The name must be"
' unique for a project and location.',
)
flags.AddNetwork(parser)
def Run(self, args):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = ManagementServersClient()
is_async = args.async_
management_server = args.CONCEPTS.management_server.Parse()
network = args.network
try:
operation = client.Create(management_server, network)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
if is_async:
log.CreatedResource(
operation.name,
kind='management server',
is_async=True,
details=(
'Run the [gcloud backup-dr operations describe] command '
'to check the status of this operation.'
),
)
return operation
resource = client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'Creating management server [{}]. (This operation could'
' take up to 1 hour.)'.format(management_server.RelativeName())
),
)
log.CreatedResource(
management_server.RelativeName(), kind='management server'
)
return resource

View File

@@ -0,0 +1,112 @@
# -*- 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.
"""Deletes a Backup and DR Management Server."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.management_servers import ManagementServersClient
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import log
from googlecloudsdk.core.console import console_io
@base.ReleaseTracks(
base.ReleaseTrack.ALPHA, base.ReleaseTrack.BETA, base.ReleaseTrack.GA
)
@base.DefaultUniverseOnly
class DeleteAlpha(base.DeleteCommand):
"""Delete the specified Management Server."""
detailed_help = {
'BRIEF': 'Deletes a specific management server',
'DESCRIPTION': '{description}',
'EXAMPLES': """\
To delete a management server `sample-ms` in project `sample-project` and location `us-central1` , run:
$ {command} sample-ms --project=sample-project --location=us-central1
""",
}
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
base.ASYNC_FLAG.AddToParser(parser)
base.ASYNC_FLAG.SetDefault(parser, True)
flags.AddManagementServerResourceArg(
parser,
'Name of the management server to delete. Before you delete, take a'
' look at the prerequisites'
' [here](https://cloud.google.com/backup-disaster-recovery/docs/configuration/decommission).',
)
def Run(self, args):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = ManagementServersClient()
is_async = args.async_
management_server = args.CONCEPTS.management_server.Parse()
console_io.PromptContinue(
message=(
'The management server will be deleted. You cannot undo this'
' action.'
),
default=True,
cancel_on_no=True,
)
try:
operation = client.Delete(management_server)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
if is_async:
log.DeletedResource(
operation.name,
kind='management server',
is_async=True,
details=(
'Run the [gcloud backup-dr operations describe] command '
'to check the status of this operation.'
),
)
return operation
return client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'Deleting management server [{}]. (This operation could'
' take up to 1 hour.)'.format(management_server.RelativeName())
),
has_result=False,
)

View File

@@ -0,0 +1,19 @@
- release_tracks: [ALPHA, BETA, GA]
help_text:
brief: Show details of the management server.
description: Show all configuration data associated with the specified management server.
examples: |
To view details for management server 'MANAGEMENT_SERVER', run:
$ {command} MANAGEMENT_SERVER
request:
collection: backupdr.projects.locations.managementServers
response:
id_field: name
arguments:
resource:
help_text: Name of the management server to describe.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:managementServer

View File

@@ -0,0 +1,23 @@
- release_tracks: [ALPHA, BETA, GA]
help_text:
brief: List management servers in the project
description: List management servers in the project. Currently, a project can have only one management server.
examples: |
To list management servers for all locations, run:
$ {command}
To list management servers in a location ``my-location'', run:
$ {command} --location=my-location
request:
collection: backupdr.projects.locations.managementServers
response:
id_field: name
arguments:
resource:
help_text: Location for which management servers should be listed.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:locationDefaultGlobal

View File

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

View File

@@ -0,0 +1,18 @@
- help_text:
brief: |
Describe an operation.
description: |
Describe a Backup and DR operation.
examples: |
To view details for operation 'OPERATION', run:
$ {command} OPERATION
request:
collection: backupdr.projects.locations.operations
arguments:
resource:
spec: !REF googlecloudsdk.command_lib.backupdr.resources:operation
help_text: |
Backup and DR operation to describe.

View File

@@ -0,0 +1,33 @@
- release_tracks: [ALPHA, BETA, GA]
help_text:
brief: List all operations.
description: List all Backup and DR operations.
examples: |
To list all operations in a location ``my-location'', run:
$ {command} --location=my-location
To list all operations in all locations, run:
$ {command} --location=-
request:
collection: backupdr.projects.locations.operations
arguments:
resource:
help_text: Location for which operations should be listed.
spec: !REF googlecloudsdk.command_lib.backupdr.resources:location
response:
id_field: name
output:
format: |
table(
name.scope("operations"):label=ID,
name.scope("locations").segment(0):label=LOCATION,
metadata.target:label=TARGET,
metadata.verb:label=TYPE,
done:label=DONE
)

View File

@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*- #
# Copyright 2025 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Command group for Backup and DR Resource Backup Config."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import base
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class ResourceBackupConfig(base.Group):
"""Show protection summary for resources in a particular location and project."""

View File

@@ -0,0 +1,154 @@
# -*- 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.
"""List protection summary."""
from googlecloudsdk.api_lib.backupdr import rbc_filter_rewrite
from googlecloudsdk.api_lib.backupdr import resource_backup_config
from googlecloudsdk.api_lib.util import common_args
from googlecloudsdk.calliope import base
from googlecloudsdk.calliope import exceptions
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import log
from googlecloudsdk.core.resource import resource_projection_spec
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA)
class List(base.ListCommand):
"""Show backup configuration metadata associated with specified resources in a particular location for the project."""
detailed_help = {
'BRIEF': (
'list backup configurations for a specified project and location.'
),
'DESCRIPTION': (
'{description}'
),
'FLAGS/ARGUMENTS': """\
`--project`: Project for which backup configurations should be listed.
`--location`: Location for which backup configurations should be listed.
`--filter`: The filter expression to filter results.
`--sort-by`: The field to sort results by.
""",
'SUBARGUMENTS': """\
`target_resource_display_name`: Name of the resource for which protection summary is to be listed.
`target_resource_type`: Type of resource for which protection summary is to be displayed.\n
Allowed values:
* CLOUD_SQL_INSTANCE
* COMPUTE_ENGINE_VM
`backup_configured`: Displays if the specified resource has backups configured.
`vaulted`: Displays if configured backups are protected using a backup vault.
`backup_configs_details.backup_config_source_display_name`: Name of the backup schedule applied to the resource.
`backup_configs_details.type`: Backup schedule type applied to the resource.\n
Allowed values:
* CLOUD_SQL_INSTANCE_BACKUP_CONFIG
* COMPUTE_ENGINE_RESOURCE_POLICY
* BACKUPDR_BACKUP_PLAN
* BACKUPDR_TEMPLATE
""",
'EXAMPLES': """\
* To list protection summary for a resource named `resource-1`:
$ {command} --project=sample-project --location=us-central1 --filter="target_resource_display_name=resource-1"
* To list protection summary for a resource named `resource-1` that has backup configured:
$ {command} --project=sample-project --location=us-central1 --filter="target_resource_display_name=resource-1 AND backup_configured=true"
You can sort the results using the `--sort-by` flag. The only supported field for sorting is `target_resource_display_name`.
Example of sorting:
$ {command} --project=sample-project --location=us-central1 --sort-by="target_resource_display_name"
""",
}
@staticmethod
def Args(parser):
flags.AddLocationResourceArg(
parser,
'Location for which the resource backup config should be listed.',
)
def _Validate_and_Parse_SortBy(self, args):
order_by = common_args.ParseSortByArg(args.sort_by)
# Only sort by target_resource_display_name is supported by CLH right now.
if order_by is None:
return None
order_by_fields = order_by.split(' ')
if (
order_by_fields
and isinstance(order_by_fields[0], str)
and order_by_fields[0]
not in ('target_resource_display_name', 'targetResourceDisplayName')
):
raise exceptions.InvalidArgumentException(
'sort_by',
'Invalid sort_by argument. Only sort_by'
' target_resource_display_name/targetResourceDisplayName is'
' supported.',
)
order_by_fields[0] = 'target_resource_display_name'
order_by = ' '.join(order_by_fields)
return order_by
def Run(self, args):
"""Constructs and sends request."""
# Location is required.
if args.location is None:
raise exceptions.RequiredArgumentException(
'location',
'Location for which the resource backup config should be listed.',
)
client = resource_backup_config.ResourceBackupConfigClient()
parent_ref = args.CONCEPTS.location.Parse()
# Client and server side filtering.
display_info = args.GetDisplayInfo()
defaults = resource_projection_spec.ProjectionSpec(
symbols=display_info.transforms, aliases=display_info.aliases
)
_, server_filter = rbc_filter_rewrite.ListFilterRewrite().Rewrite(
args.filter, defaults=defaults)
log.info('original_filter=%r, server_filter=%r',
args.filter, server_filter)
# No client side filtering.
args.filter = None
if args.page_size is not None:
# Server side limit.
args.page_size = min(500, args.page_size)
if not args.format:
args.format = 'json'
order_by = self._Validate_and_Parse_SortBy(args)
return client.List(
parent=parent_ref.RelativeName(),
filters=server_filter,
page_size=args.page_size,
limit=args.limit,
order_by=order_by,
)

View File

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

View File

@@ -0,0 +1,129 @@
# -*- 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.
"""Initialize a Backup and DR Service Config."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from apitools.base.py import exceptions as apitools_exceptions
from googlecloudsdk.api_lib.backupdr import util
from googlecloudsdk.api_lib.backupdr.service_config import ServiceConfigClient
from googlecloudsdk.api_lib.util import exceptions
from googlecloudsdk.calliope import base
from googlecloudsdk.command_lib.backupdr import flags
from googlecloudsdk.core import log
@base.DefaultUniverseOnly
@base.ReleaseTracks(base.ReleaseTrack.ALPHA, base.ReleaseTrack.GA)
class Init(base.Command):
"""Initialize a Backup and DR Service configuration."""
detailed_help = {
'BRIEF': 'Initializes a Backup and DR Service configuration.',
'DESCRIPTION': '{description}',
'API REFERENCE': (
'This command uses the backupdr/v1 API. The full documentation for'
' this API can be found at:'
' https://cloud.google.com/backup-disaster-recovery'
),
'EXAMPLES': """\
To initialize a new service configuration in location ``MY_LOCATION''
and project ``MY_PROJECT'' for resource type ``MY_RESOURCE_TYPE'', run:
$ {command} --project=MY_PROJECT \
--location=MY_LOCATION \
--resource-type=MY_RESOURCE_TYPE
""",
}
@staticmethod
def Args(parser):
"""Specifies additional command flags.
Args:
parser: argparse.Parser: Parser object for command line inputs.
"""
flags.AddNoAsyncFlag(parser)
flags.AddLocationResourceArg(
parser,
"""The location for which the service configuration should be created.""",
)
flags.AddResourceType(
parser,
"""The resource type to which the default service configuration
will be applied. Examples include, "compute.<UNIVERSE_DOMAIN>.com/Instance"
""",
)
def Run(self, args):
"""Constructs and sends request.
Args:
args: argparse.Namespace, An object that contains the values for the
arguments specified in the .Args() method.
Returns:
ProcessHttpResponse of the request made.
"""
client = ServiceConfigClient()
location = args.CONCEPTS.location.Parse().RelativeName()
resource_type = args.resource_type
no_async = args.no_async
try:
operation = client.Init(
location,
resource_type,
)
except apitools_exceptions.HttpError as e:
raise exceptions.HttpException(e, util.HTTP_ERROR_FORMAT)
if no_async:
resource = client.WaitForOperation(
operation_ref=client.GetOperationRef(operation),
message=(
'Initializing service configuration for resource type [{}] in'
' location [{}]. (This operation could take up to 2 minutes.)'
.format(resource_type, location)
),
has_result=False,
)
# pylint: disable=protected-access
# none of the log.CreatedResource, log.DeletedResource etc. matched
log._PrintResourceChange(
'Initialization of service configuration',
location,
kind='location',
is_async=False,
details=None,
failed=None,
operation_past_tense='Service configuration initialized for',
)
return resource
# pylint: disable=protected-access
# none of the log.CreatedResource, log.DeletedResource etc. matched
log._PrintResourceChange(
'Initialization of service configuration',
location,
kind='location',
is_async=True,
details=util.ASYNC_OPERATION_MESSAGE.format(operation.name),
failed=None,
)
return operation