619 lines
20 KiB
Python
619 lines
20 KiB
Python
# -*- 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.
|
|
"""Cloud Backup and DR Backups client."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
from googlecloudsdk.api_lib.backupdr import util
|
|
from googlecloudsdk.api_lib.backupdr.restore_util import ComputeUtil
|
|
from googlecloudsdk.api_lib.backupdr.restore_util import DiskUtil
|
|
from googlecloudsdk.calliope import exceptions
|
|
from googlecloudsdk.command_lib.backupdr import util as command_util
|
|
from googlecloudsdk.core import resources
|
|
from googlecloudsdk.generated_clients.apis.backupdr.v1 import backupdr_v1_messages
|
|
|
|
|
|
class ComputeRestoreConfig(util.RestrictedDict):
|
|
"""Restore configuration."""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
supported_flags = [
|
|
"Name",
|
|
"TargetZone",
|
|
"TargetProject",
|
|
"NetworkInterfaces",
|
|
"ServiceAccount",
|
|
"Scopes",
|
|
"NoScopes",
|
|
"CreateDisks",
|
|
"Description",
|
|
"Metadata",
|
|
"Labels",
|
|
"Tags",
|
|
"MachineType",
|
|
"Hostname",
|
|
"EnableUefiNetworking",
|
|
"ThreadsPerCore",
|
|
"VisibleCoreCount",
|
|
"Accelerator",
|
|
"MinCpuPlatform",
|
|
"MaintenancePolicy",
|
|
"Preemptible",
|
|
"RestartOnFailure",
|
|
"MinNodeCpus",
|
|
"ProvisioningModel",
|
|
"InstanceTerminationAction",
|
|
"LocalSsdRecoveryTimeout",
|
|
"NodeAffinityFile",
|
|
"ReservationAffinity",
|
|
"Reservation",
|
|
"EnableDisplayDevice",
|
|
"CanIpForward",
|
|
"PrivateIpv6GoogleAccessType",
|
|
"NetworkPerformanceConfigs",
|
|
"ConfidentialCompute",
|
|
"DeletionProtection",
|
|
"ResourceManagerTags",
|
|
"ResourcePolicies",
|
|
"KeyRevocationActionType",
|
|
"InstanceKmsKey",
|
|
"ClearOverridesFieldMask",
|
|
]
|
|
super(ComputeRestoreConfig, self).__init__(supported_flags, *args, **kwargs)
|
|
|
|
|
|
class DiskRestoreConfig(util.RestrictedDict):
|
|
"""Restore configuration."""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
supported_flags = [
|
|
"Name",
|
|
"TargetZone",
|
|
"TargetRegion",
|
|
"TargetProject",
|
|
"ReplicaZones",
|
|
"Description",
|
|
"Labels",
|
|
"Licenses",
|
|
"GuestOsFeatures",
|
|
"ConfidentialCompute",
|
|
"Type",
|
|
"AccessMode",
|
|
"ResourcePolicies",
|
|
"ProvisionedIops",
|
|
"KmsKey",
|
|
"Architecture",
|
|
"Size",
|
|
"ProvisionedThroughput",
|
|
"StoragePool",
|
|
"ClearOverridesFieldMask",
|
|
]
|
|
super(DiskRestoreConfig, self).__init__(supported_flags, *args, **kwargs)
|
|
|
|
|
|
class BackupsClient(util.BackupDrClientBase):
|
|
"""Cloud Backup and DR Backups client."""
|
|
|
|
def __init__(self):
|
|
super(BackupsClient, self).__init__()
|
|
self.service = (
|
|
self.client.projects_locations_backupVaults_dataSources_backups
|
|
)
|
|
|
|
def Delete(
|
|
self, resource: resources.Resource
|
|
) -> backupdr_v1_messages.Operation:
|
|
"""Deletes the given backup.
|
|
|
|
Args:
|
|
resource: The backup to be deleted.
|
|
|
|
Returns:
|
|
A long running operation
|
|
"""
|
|
request_id = command_util.GenerateRequestId()
|
|
request = self.messages.BackupdrProjectsLocationsBackupVaultsDataSourcesBackupsDeleteRequest(
|
|
name=resource.RelativeName(), requestId=request_id
|
|
)
|
|
|
|
return self.service.Delete(request)
|
|
|
|
def RestoreCompute(self, resource, restore_config: ComputeRestoreConfig):
|
|
"""Restores the given backup.
|
|
|
|
Args:
|
|
resource: The backup to be restored.
|
|
restore_config: Restore configuration.
|
|
|
|
Returns:
|
|
A long running operation
|
|
"""
|
|
restore_request = self.messages.RestoreBackupRequest()
|
|
restore_request.computeInstanceRestoreProperties = (
|
|
self.messages.ComputeInstanceRestoreProperties(
|
|
name=restore_config["Name"],
|
|
)
|
|
)
|
|
|
|
restore_request.computeInstanceTargetEnvironment = (
|
|
self.messages.ComputeInstanceTargetEnvironment(
|
|
zone=restore_config["TargetZone"],
|
|
project=restore_config["TargetProject"],
|
|
)
|
|
)
|
|
|
|
# Network Interface
|
|
if "NetworkInterfaces" in restore_config:
|
|
network_interfaces_message = ComputeUtil.ParserNetworkInterface(
|
|
self.messages, restore_config["NetworkInterfaces"]
|
|
)
|
|
if network_interfaces_message:
|
|
restore_request.computeInstanceRestoreProperties.networkInterfaces.extend(
|
|
network_interfaces_message
|
|
)
|
|
|
|
# Service Account & Scopes
|
|
service_accounts_message = ComputeUtil.ParserServiceAccount(
|
|
self.messages,
|
|
restore_config.get("ServiceAccount", None),
|
|
restore_config.get(
|
|
"Scopes", [] if restore_config.get("NoScopes", False) else None
|
|
),
|
|
)
|
|
if service_accounts_message:
|
|
restore_request.computeInstanceRestoreProperties.serviceAccounts = (
|
|
service_accounts_message
|
|
)
|
|
|
|
# Create Disks
|
|
if "CreateDisks" in restore_config:
|
|
disks_message = ComputeUtil.ParserDisks(
|
|
self.messages, restore_config["CreateDisks"]
|
|
)
|
|
if disks_message:
|
|
restore_request.computeInstanceRestoreProperties.disks.extend(
|
|
disks_message
|
|
)
|
|
|
|
# Description
|
|
if "Description" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.description = (
|
|
restore_config["Description"]
|
|
)
|
|
|
|
# Metadata
|
|
if "Metadata" in restore_config:
|
|
metadata_message = ComputeUtil.ParseMetadata(
|
|
self.messages, restore_config["Metadata"]
|
|
)
|
|
if metadata_message:
|
|
restore_request.computeInstanceRestoreProperties.metadata = (
|
|
metadata_message
|
|
)
|
|
|
|
# Labels
|
|
if "Labels" in restore_config:
|
|
labels_message = ComputeUtil.ParseLabels(
|
|
self.messages, restore_config["Labels"]
|
|
)
|
|
if labels_message:
|
|
restore_request.computeInstanceRestoreProperties.labels = labels_message
|
|
|
|
# Tags
|
|
if "Tags" in restore_config:
|
|
tags_message = self.messages.Tags(items=restore_config["Tags"])
|
|
if tags_message:
|
|
restore_request.computeInstanceRestoreProperties.tags = tags_message
|
|
|
|
# Machine Type
|
|
if "MachineType" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.machineType = (
|
|
restore_config["MachineType"]
|
|
)
|
|
|
|
# Hostname
|
|
if "Hostname" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.hostname = (
|
|
restore_config["Hostname"]
|
|
)
|
|
|
|
# AdvancedMachineFeatures
|
|
# EnableUefiNetworking, ThreadsPerCore, VisibleCoreCount
|
|
advanced_machine_features_message = (
|
|
ComputeUtil.ParseAdvancedMachineFeatures(
|
|
self.messages,
|
|
restore_config.get("EnableUefiNetworking", None),
|
|
restore_config.get("ThreadsPerCore", None),
|
|
restore_config.get("VisibleCoreCount", None),
|
|
)
|
|
)
|
|
if advanced_machine_features_message:
|
|
restore_request.computeInstanceRestoreProperties.advancedMachineFeatures = (
|
|
advanced_machine_features_message
|
|
)
|
|
|
|
# Accelerator
|
|
if "Accelerator" in restore_config:
|
|
accelerators_message = ComputeUtil.ParseAccelerator(
|
|
self.messages, restore_config["Accelerator"]
|
|
)
|
|
if accelerators_message:
|
|
restore_request.computeInstanceRestoreProperties.guestAccelerators = (
|
|
accelerators_message
|
|
)
|
|
|
|
# MinCpuPlatform
|
|
if "MinCpuPlatform" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.minCpuPlatform = (
|
|
restore_config["MinCpuPlatform"]
|
|
)
|
|
|
|
# Scheduling Flags
|
|
if any(
|
|
flag in restore_config
|
|
for flag in [
|
|
"MaintenancePolicy",
|
|
"Preemptible",
|
|
"RestartOnFailure",
|
|
"MinNodeCpus",
|
|
"ProvisioningModel",
|
|
"InstanceTerminationAction",
|
|
"LocalSsdRecoveryTimeout",
|
|
"NodeAffinityFile",
|
|
]
|
|
):
|
|
restore_request.computeInstanceRestoreProperties.scheduling = (
|
|
self.messages.Scheduling()
|
|
)
|
|
|
|
# MaintenancePolicy
|
|
if "MaintenancePolicy" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.scheduling.onHostMaintenance = self.messages.Scheduling.OnHostMaintenanceValueValuesEnum(
|
|
restore_config["MaintenancePolicy"]
|
|
)
|
|
|
|
# Preemptible
|
|
if "Preemptible" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.scheduling.preemptible = restore_config[
|
|
"Preemptible"
|
|
]
|
|
|
|
# RestartOnFailure
|
|
if "RestartOnFailure" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.scheduling.automaticRestart = restore_config[
|
|
"RestartOnFailure"
|
|
]
|
|
|
|
# MinNodeCpus
|
|
if "MinNodeCpus" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.scheduling.minNodeCpus = restore_config[
|
|
"MinNodeCpus"
|
|
]
|
|
|
|
# ProvisioningModel
|
|
if "ProvisioningModel" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.scheduling.provisioningModel = self.messages.Scheduling.ProvisioningModelValueValuesEnum(
|
|
restore_config["ProvisioningModel"]
|
|
)
|
|
|
|
# InstanceTerminationAction
|
|
if "InstanceTerminationAction" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.scheduling.instanceTerminationAction = self.messages.Scheduling.InstanceTerminationActionValueValuesEnum(
|
|
restore_config["InstanceTerminationAction"]
|
|
)
|
|
|
|
# LocalSsdRecoveryTimeout
|
|
if "LocalSsdRecoveryTimeout" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.scheduling.localSsdRecoveryTimeout = self.messages.SchedulingDuration(
|
|
seconds=restore_config["LocalSsdRecoveryTimeout"]
|
|
)
|
|
|
|
# NodeAffinityFile
|
|
if "NodeAffinityFile" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.scheduling.nodeAffinities = ComputeUtil.GetNodeAffinitiesFromFile(
|
|
self.messages, restore_config["NodeAffinityFile"]
|
|
)
|
|
|
|
# ReservationAffinity & Reservation
|
|
if "ReservationAffinity" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.reservationAffinity = (
|
|
ComputeUtil.ParseReservationAffinity(
|
|
self.messages,
|
|
restore_config["ReservationAffinity"],
|
|
restore_config.get("Reservation", None),
|
|
)
|
|
)
|
|
|
|
# EnableDisplayDevice
|
|
if "EnableDisplayDevice" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.displayDevice = (
|
|
self.messages.DisplayDevice(
|
|
enableDisplay=restore_config["EnableDisplayDevice"]
|
|
)
|
|
)
|
|
|
|
# CanIpForward
|
|
if "CanIpForward" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.canIpForward = (
|
|
restore_config["CanIpForward"]
|
|
)
|
|
|
|
# PrivateIpv6GoogleAccess
|
|
if "PrivateIpv6GoogleAccessType" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.privateIpv6GoogleAccess = self.messages.ComputeInstanceRestoreProperties.PrivateIpv6GoogleAccessValueValuesEnum(
|
|
restore_config["PrivateIpv6GoogleAccessType"]
|
|
)
|
|
|
|
# NetworkPerformanceConfigs
|
|
if "NetworkPerformanceConfigs" in restore_config:
|
|
network_performance_configs = self.messages.NetworkPerformanceConfig()
|
|
if (
|
|
"total-egress-bandwidth-tier"
|
|
in restore_config["NetworkPerformanceConfigs"]
|
|
):
|
|
network_performance_configs.totalEgressBandwidthTier = self.messages.NetworkPerformanceConfig.TotalEgressBandwidthTierValueValuesEnum(
|
|
restore_config["NetworkPerformanceConfigs"][
|
|
"total-egress-bandwidth-tier"
|
|
]
|
|
)
|
|
restore_request.computeInstanceRestoreProperties.networkPerformanceConfig = (
|
|
network_performance_configs
|
|
)
|
|
|
|
# ConfidentialCompute
|
|
if "ConfidentialCompute" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.confidentialInstanceConfig = self.messages.ConfidentialInstanceConfig(
|
|
enableConfidentialCompute=restore_config["ConfidentialCompute"]
|
|
)
|
|
|
|
# DeletionProtection
|
|
if "DeletionProtection" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.deletionProtection = (
|
|
restore_config["DeletionProtection"]
|
|
)
|
|
|
|
# ResourceManagerTags
|
|
if "ResourceManagerTags" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.params = self.messages.InstanceParams(
|
|
resourceManagerTags=self.messages.InstanceParams.ResourceManagerTagsValue(
|
|
additionalProperties=[
|
|
self.messages.InstanceParams.ResourceManagerTagsValue.AdditionalProperty(
|
|
key=key, value=value
|
|
)
|
|
for key, value in restore_config[
|
|
"ResourceManagerTags"
|
|
].items()
|
|
]
|
|
)
|
|
)
|
|
|
|
# ResourcePolicies
|
|
if "ResourcePolicies" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.resourcePolicies = (
|
|
restore_config["ResourcePolicies"]
|
|
)
|
|
|
|
# KeyRevocationActionType
|
|
if "KeyRevocationActionType" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.keyRevocationActionType = self.messages.ComputeInstanceRestoreProperties.KeyRevocationActionTypeValueValuesEnum(
|
|
restore_config["KeyRevocationActionType"]
|
|
)
|
|
|
|
# InstanceKmsKey
|
|
if "InstanceKmsKey" in restore_config:
|
|
restore_request.computeInstanceRestoreProperties.instanceEncryptionKey = (
|
|
self.messages.CustomerEncryptionKey(
|
|
kmsKeyName=restore_config["InstanceKmsKey"],
|
|
)
|
|
)
|
|
|
|
# ClearOverridesFieldMask
|
|
if "ClearOverridesFieldMask" in restore_config:
|
|
restore_request.clearOverridesFieldMask = restore_config[
|
|
"ClearOverridesFieldMask"
|
|
]
|
|
|
|
request = self.messages.BackupdrProjectsLocationsBackupVaultsDataSourcesBackupsRestoreRequest(
|
|
name=resource.RelativeName(), restoreBackupRequest=restore_request
|
|
)
|
|
return self.service.Restore(request)
|
|
|
|
def RestoreDisk(self, resource, restore_config: DiskRestoreConfig):
|
|
"""Restores the given backup.
|
|
|
|
Args:
|
|
resource: The backup to be restored.
|
|
restore_config: Restore configuration.
|
|
|
|
Returns:
|
|
A long running operation
|
|
"""
|
|
restore_request = self.messages.RestoreBackupRequest()
|
|
restore_request.diskRestoreProperties = self.messages.DiskRestoreProperties(
|
|
name=restore_config["Name"],
|
|
)
|
|
|
|
target_zone = restore_config.get("TargetZone", None)
|
|
target_region = restore_config.get("TargetRegion", None)
|
|
|
|
if target_zone is None and target_region is None:
|
|
raise exceptions.InvalidArgumentException(
|
|
"target_zone",
|
|
"Target zone or target region is required for disk restore",
|
|
)
|
|
|
|
if target_zone is not None and target_region is not None:
|
|
raise exceptions.InvalidArgumentException(
|
|
"target_zone",
|
|
"Both Target zone and target region cannot be specified for disk"
|
|
" restore",
|
|
)
|
|
if target_zone is not None:
|
|
restore_request.diskTargetEnvironment = (
|
|
self.messages.DiskTargetEnvironment(
|
|
zone=restore_config["TargetZone"],
|
|
project=restore_config["TargetProject"],
|
|
)
|
|
)
|
|
elif target_region is not None:
|
|
restore_request.regionDiskTargetEnvironment = (
|
|
self.messages.RegionDiskTargetEnvironment(
|
|
region=restore_config["TargetRegion"],
|
|
project=restore_config["TargetProject"],
|
|
replicaZones=restore_config["ReplicaZones"],
|
|
)
|
|
)
|
|
|
|
# Description
|
|
if "Description" in restore_config:
|
|
restore_request.diskRestoreProperties.description = restore_config[
|
|
"Description"
|
|
]
|
|
|
|
# Labels
|
|
if "Labels" in restore_config:
|
|
labels_message = DiskUtil.ParseLabels(
|
|
self.messages, restore_config["Labels"]
|
|
)
|
|
if labels_message:
|
|
restore_request.diskRestoreProperties.labels = labels_message
|
|
|
|
# Licenses
|
|
if "Licenses" in restore_config:
|
|
restore_request.diskRestoreProperties.licenses = restore_config[
|
|
"Licenses"
|
|
]
|
|
|
|
# ConfidentialCompute
|
|
if "ConfidentialCompute" in restore_config:
|
|
restore_request.diskRestoreProperties.enableConfidentialCompute = (
|
|
restore_config["ConfidentialCompute"]
|
|
)
|
|
|
|
# Type
|
|
if "Type" in restore_config:
|
|
restore_request.diskRestoreProperties.type = restore_config["Type"]
|
|
|
|
# Size
|
|
if "Size" in restore_config:
|
|
restore_request.diskRestoreProperties.sizeGb = restore_config["Size"]
|
|
|
|
# StoragePool
|
|
if "StoragePool" in restore_config:
|
|
restore_request.diskRestoreProperties.storagePool = restore_config[
|
|
"StoragePool"
|
|
]
|
|
|
|
# Architecture
|
|
if "Architecture" in restore_config:
|
|
restore_request.diskRestoreProperties.architecture = (
|
|
self.messages.DiskRestoreProperties.ArchitectureValueValuesEnum(
|
|
restore_config["Architecture"]
|
|
)
|
|
)
|
|
|
|
# AccessMode
|
|
if "AccessMode" in restore_config:
|
|
restore_request.diskRestoreProperties.accessMode = (
|
|
self.messages.DiskRestoreProperties.AccessModeValueValuesEnum(
|
|
restore_config["AccessMode"]
|
|
)
|
|
)
|
|
|
|
# ResourcePolicies
|
|
if "ResourcePolicies" in restore_config:
|
|
restore_request.diskRestoreProperties.resourcePolicy = restore_config[
|
|
"ResourcePolicies"
|
|
]
|
|
|
|
# ProvisionedIops
|
|
if "ProvisionedIops" in restore_config:
|
|
restore_request.diskRestoreProperties.provisionedIops = restore_config[
|
|
"ProvisionedIops"
|
|
]
|
|
|
|
# ProvisionedThroughput
|
|
if "ProvisionedThroughput" in restore_config:
|
|
restore_request.diskRestoreProperties.provisionedThroughput = (
|
|
restore_config["ProvisionedThroughput"]
|
|
)
|
|
|
|
# KmsKey
|
|
if "KmsKey" in restore_config:
|
|
restore_request.diskRestoreProperties.diskEncryptionKey = (
|
|
self.messages.CustomerEncryptionKey(
|
|
kmsKeyName=restore_config["KmsKey"],
|
|
)
|
|
)
|
|
|
|
# ClearOverridesFieldMask
|
|
if "ClearOverridesFieldMask" in restore_config:
|
|
restore_request.clearOverridesFieldMask = restore_config[
|
|
"ClearOverridesFieldMask"
|
|
]
|
|
|
|
# GuestOsFeatures
|
|
if "GuestOsFeatures" in restore_config:
|
|
guest_os_features = []
|
|
for feature in restore_config["GuestOsFeatures"]:
|
|
guest_os_features.append(
|
|
self.messages.GuestOsFeature(
|
|
type=self.messages.GuestOsFeature.TypeValueValuesEnum(feature)
|
|
)
|
|
)
|
|
restore_request.diskRestoreProperties.guestOsFeature = guest_os_features
|
|
|
|
request = self.messages.BackupdrProjectsLocationsBackupVaultsDataSourcesBackupsRestoreRequest(
|
|
name=resource.RelativeName(), restoreBackupRequest=restore_request
|
|
)
|
|
return self.service.Restore(request)
|
|
|
|
def ParseUpdate(self, enforced_retention, expire_time):
|
|
updated_backup = self.messages.Backup()
|
|
if enforced_retention is not None:
|
|
updated_backup.enforcedRetentionEndTime = enforced_retention
|
|
if expire_time is not None:
|
|
updated_backup.expireTime = expire_time
|
|
return updated_backup
|
|
|
|
def Update(self, resource, backup, update_mask):
|
|
request_id = command_util.GenerateRequestId()
|
|
request = self.messages.BackupdrProjectsLocationsBackupVaultsDataSourcesBackupsPatchRequest(
|
|
backup=backup,
|
|
name=resource.RelativeName(),
|
|
updateMask=update_mask,
|
|
requestId=request_id,
|
|
)
|
|
return self.service.Patch(request)
|
|
|
|
def FetchForResourceType(
|
|
self,
|
|
resource,
|
|
resource_type,
|
|
filter_expression=None,
|
|
page_size=None,
|
|
order_by=None,
|
|
):
|
|
request = self.messages.BackupdrProjectsLocationsBackupVaultsDataSourcesBackupsFetchForResourceTypeRequest(
|
|
parent=resource.RelativeName(),
|
|
resourceType=resource_type,
|
|
pageSize=page_size,
|
|
filter=filter_expression,
|
|
orderBy=order_by,
|
|
)
|
|
return self.service.FetchForResourceType(request)
|