140 lines
4.7 KiB
Python
140 lines
4.7 KiB
Python
# -*- coding: utf-8 -*- #
|
|
# Copyright 2019 Google LLC. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
"""Bigtable backups API helper."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
from googlecloudsdk.api_lib.bigtable import util
|
|
from googlecloudsdk.calliope import arg_parsers
|
|
from googlecloudsdk.core import exceptions as core_exceptions
|
|
from googlecloudsdk.core.util import times
|
|
|
|
|
|
# General Utils
|
|
class NoFieldSpecified(core_exceptions.Error):
|
|
"""Error for calling update command with no args that represent fields."""
|
|
|
|
|
|
def ParseExpireTime(expiration_value):
|
|
"""Parse flag value into Datetime format for expireTime."""
|
|
# expiration_value could be in Datetime format or Duration format.
|
|
# backend timezone is UTC.
|
|
datetime = times.ParseDuration(expiration_value).GetRelativeDateTime(
|
|
times.Now(times.UTC)
|
|
)
|
|
parsed_datetime = times.FormatDateTime(
|
|
datetime, '%Y-%m-%dT%H:%M:%S.%6f%Ez', tzinfo=times.UTC
|
|
)
|
|
return parsed_datetime
|
|
|
|
|
|
def FormatDatetime(datetime_value: str) -> str:
|
|
"""Parse a string datetime value into a formatted string."""
|
|
parsed_time = arg_parsers.Datetime.ParseUtcTime(datetime_value)
|
|
return parsed_time.strftime('%Y-%m-%dT%H:%M:%SZ')
|
|
|
|
|
|
# TODO: b/353357876 - We can replace both of these flags since we can represent
|
|
# both formats using gcloud's arg_parser.
|
|
def GetExpireTime(args):
|
|
"""Parse flags for expire time."""
|
|
if args.expiration_date:
|
|
return args.expiration_date
|
|
elif args.retention_period:
|
|
return ParseExpireTime(args.retention_period)
|
|
|
|
|
|
def GetHotToStandardTime(args):
|
|
"""Parse flags for hot to standard time."""
|
|
if not args.hot_to_standard_time:
|
|
return args.hot_to_standard_time
|
|
|
|
return FormatDatetime(args.hot_to_standard_time)
|
|
|
|
|
|
# Create Command Utils
|
|
def ModifyCreateRequest(backup_ref, args, req):
|
|
"""Parse argument and construct create backup request."""
|
|
req.backup.sourceTable = f'projects/{backup_ref.projectsId}/instances/{backup_ref.instancesId}/tables/{args.table}'
|
|
|
|
req.backup.expireTime = GetExpireTime(args)
|
|
req.backup.hotToStandardTime = GetHotToStandardTime(args)
|
|
req.backupId = args.backup
|
|
req.parent = backup_ref.Parent().RelativeName()
|
|
return req
|
|
|
|
|
|
# Update Command Utils
|
|
def ResetDefaultMaskField(unused_instance_ref, unused_args, req):
|
|
req.updateMask = ''
|
|
return req
|
|
|
|
|
|
def AddFieldToUpdateMask(field, req):
|
|
update_mask = req.updateMask
|
|
if update_mask:
|
|
if update_mask.count(field) == 0:
|
|
req.updateMask = update_mask + ',' + field
|
|
else:
|
|
req.updateMask = field
|
|
return req
|
|
|
|
|
|
def AddBackupFieldsToUpdateMask(unused_backup_ref, args, req):
|
|
"""Add backup fields to updateMask in the patch request."""
|
|
expire_time = GetExpireTime(args)
|
|
if expire_time is not None:
|
|
req.backup.expireTime = expire_time
|
|
req = AddFieldToUpdateMask('expire_time', req)
|
|
|
|
hot_to_standard_time = GetHotToStandardTime(args)
|
|
if hot_to_standard_time is not None:
|
|
req = AddFieldToUpdateMask('hot_to_standard_time', req)
|
|
# We don't have to explicitly check if `hot_to_standard_time` is an empty
|
|
# string because even though it can also be None, we have already checked
|
|
# that it is not None.
|
|
#
|
|
# `hot_to_standard_time` is a string flag, so this means that we can
|
|
# simply check whether the flag is falsy to determine if it is an empty
|
|
# string.
|
|
#
|
|
# An empty string means that the user wants to clear the
|
|
# `hot_to_standard_time` field.
|
|
if not hot_to_standard_time:
|
|
req.backup.hotToStandardTime = None
|
|
else:
|
|
req.backup.hotToStandardTime = hot_to_standard_time
|
|
|
|
return req
|
|
|
|
|
|
def CopyBackup(source_backup_ref, destination_backup_ref, args):
|
|
"""Copy a backup."""
|
|
client = util.GetAdminClient()
|
|
msgs = util.GetAdminMessages()
|
|
copy_backup_request = msgs.CopyBackupRequest(
|
|
backupId=destination_backup_ref.Name(),
|
|
sourceBackup=source_backup_ref.RelativeName(),
|
|
)
|
|
copy_backup_request.expireTime = GetExpireTime(args)
|
|
|
|
req = msgs.BigtableadminProjectsInstancesClustersBackupsCopyRequest(
|
|
parent=destination_backup_ref.Parent().RelativeName(),
|
|
copyBackupRequest=copy_backup_request,
|
|
)
|
|
return client.projects_instances_clusters_backups.Copy(req)
|