Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion e2e/e2e_tests/backup/test_backup_restore.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,8 @@ def _restore_backup(self, backup_id: str, lvol_name: str, pool_name: str = None)
sleep_n_sec(60)
pool = pool_name or self.pool_name
out, err = self._sbcli(
f"-d backup restore {backup_id} --lvol {lvol_name} --pool {pool}")
f"-d backup restore {backup_id} --lvol {lvol_name} --pool {pool} "
f"--cluster-id {self.cluster_id}")
assert not (err and "error" in err.lower()), \
f"backup restore failed: {err}"
if out and "Error:" in out:
Expand Down
3 changes: 2 additions & 1 deletion simplyblock_cli/cli-reference.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2400,9 +2400,10 @@ commands:
dest: node
type: str
- name: "--cluster-id"
help: "The cluster id."
help: "The target cluster id."
dest: cluster_id
type: str
required: true
- name: export
help: "Export backup metadata to a JSON file for cross-cluster restore."
arguments:
Expand Down
2 changes: 1 addition & 1 deletion simplyblock_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -985,7 +985,7 @@ def init_backup__restore(self, subparser):
subcommand.add_argument('--lvol', help='The new logical volume name.', type=str, dest='lvol_name', required=True)
subcommand.add_argument('--pool', help='The target pool name or id.', type=str, dest='pool', required=True)
subcommand.add_argument('--node', help='The target storage node id.', type=str, dest='node')
subcommand.add_argument('--cluster-id', help='The cluster id.', type=str, dest='cluster_id')
subcommand.add_argument('--cluster-id', help='The target cluster id.', type=str, dest='cluster_id', required=True)

def init_backup__export(self, subparser):
subcommand = self.add_sub_command(subparser, 'export', 'Export backup metadata to a JSON file for cross-cluster restore.')
Expand Down
2 changes: 1 addition & 1 deletion simplyblock_cli/clibase.py
Original file line number Diff line number Diff line change
Expand Up @@ -928,7 +928,7 @@ def backup__delete(self, sub_command, args):
def backup__restore(self, sub_command, args):
result, error = backup_controller.restore_backup(
args.backup_id, args.lvol_name, args.pool,
cluster_id=getattr(args, 'cluster_id', None),
cluster_id=args.cluster_id,
target_node_id=getattr(args, 'node', None))
if error:
print(f"Error: {error}")
Expand Down
8 changes: 4 additions & 4 deletions simplyblock_core/controllers/backup_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import re
import time
import uuid
from typing import Optional

import boto3
from botocore.exceptions import BotoCoreError, ClientError
Expand Down Expand Up @@ -388,8 +389,8 @@ def backup_snapshot(snapshot_id, cluster_id=None):
return final_backup_id, None


def restore_backup(backup_id, lvol_name, pool_id_or_name, cluster_id,
target_node_id=None):
def restore_backup(backup_id: str, lvol_name: str, pool_id_or_name: str, cluster_id: str,
target_node_id: Optional[str] = None):
"""Restore a backup chain into a new fully-accessible lvol.

Creates the volume (with subsystem, listeners, namespace) via
Expand Down Expand Up @@ -419,8 +420,7 @@ def restore_backup(backup_id, lvol_name, pool_id_or_name, cluster_id,
# If the backup came from an external cluster, the S3 bdev must be
# switched to that cluster's bucket before restoring.
backup_src = backup.source_cluster_id or backup.cluster_id
cl = db_controller.get_cluster_by_id(cluster_id)
active_src = cl.backup_source or cluster_id
active_src = cluster.backup_source or cluster.uuid
if backup_src != active_src:
return None, (
f"Backup source is {backup_src[:8]} but active S3 source "
Expand Down
14 changes: 9 additions & 5 deletions tests/integration/test_backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,12 +588,14 @@ class TestRestoreBackup(unittest.TestCase):
@patch("simplyblock_core.controllers.backup_controller.tasks_controller")
@patch("simplyblock_core.controllers.backup_controller.db_controller")
def test_success(self, mock_db, mock_tasks):
backup = _backup(s3_id=5)
cluster_uuid = "00000000-0000-0000-0000-000000000001"
backup = _backup(s3_id=5, cluster_id=cluster_uuid)
mock_db.get_backup_by_id.return_value = backup
mock_db.get_backup_chain.return_value = [backup]
mock_tasks.add_backup_restore_task.return_value = True

mock_cluster = MagicMock()
mock_cluster.uuid = cluster_uuid
mock_cluster.backup_source = ""
mock_db.get_cluster_by_id.return_value = mock_cluster

Expand All @@ -610,7 +612,7 @@ def test_success(self, mock_db, mock_tasks):
mock_add_ha.return_value = ("lvol-new", None)

from simplyblock_core.controllers.backup_controller import restore_backup
result, error = restore_backup("backup-1", "restored_lvol", "pool-1", "cluster-1")
result, error = restore_backup("backup-1", "restored_lvol", "pool-1", cluster_uuid)

self.assertEqual(result, "lvol-new")
self.assertIsNone(error)
Expand All @@ -630,19 +632,21 @@ def test_backup_not_found(self, mock_db):

@patch("simplyblock_core.controllers.backup_controller.db_controller")
def test_add_lvol_ha_fails(self, mock_db):
mock_db.get_backup_by_id.return_value = _backup()
mock_db.get_backup_chain.return_value = [_backup()]
cluster_uuid = "00000000-0000-0000-0000-000000000001"
mock_db.get_backup_by_id.return_value = _backup(cluster_id=cluster_uuid)
mock_db.get_backup_chain.return_value = [_backup(cluster_id=cluster_uuid)]
mock_db.get_storage_node_by_id.return_value = _node()

mock_cluster = MagicMock()
mock_cluster.uuid = cluster_uuid
mock_cluster.backup_source = ""
mock_db.get_cluster_by_id.return_value = mock_cluster

with patch("simplyblock_core.controllers.lvol_controller.add_lvol_ha") as mock_add_ha:
mock_add_ha.return_value = (None, "Pool not found")

from simplyblock_core.controllers.backup_controller import restore_backup
result, error = restore_backup("backup-1", "lvol", "bad-pool", "cluster-1")
result, error = restore_backup("backup-1", "lvol", "bad-pool", cluster_uuid)

self.assertIsNone(result)
self.assertIn("Failed to create restore volume", error)
Expand Down
Loading