Add release parameter to subcloud-backup restore
Add optional --release parameter to subcloud-backup restore so that the user can specify which loaded image to use during the installation process triggered by --with-install. This parameter can only be used if --with-install is also specified. Test plan: PASS: Verify that the subcloud is restored with installation of current active release when specified. PASS: Verify that the subcloud is restored with installation of previous inactive release when specified. PASS: Verify that the subcloud is restored with installation of current active release if the "--release" parameter is omitted. Story: 2010611 Task: 47709 Signed-off-by: Victor Romano <victor.gluzromano@windriver.com> Change-Id: I619a1bf50c221fe6fc8cdfa87724d18393aef9cb
This commit is contained in:
parent
73c64fc242
commit
9824f80d95
|
@ -1031,6 +1031,7 @@ serviceUnavailable (503)
|
||||||
.. rest_parameters:: parameters.yaml
|
.. rest_parameters:: parameters.yaml
|
||||||
|
|
||||||
- with_install: with_install
|
- with_install: with_install
|
||||||
|
- release: release
|
||||||
- local_only: backup_local_only
|
- local_only: backup_local_only
|
||||||
- registry_images: backup_registry_images
|
- registry_images: backup_registry_images
|
||||||
- sysadmin_password: sysadmin_password
|
- sysadmin_password: sysadmin_password
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
"subcloud": 1,
|
"subcloud": 1,
|
||||||
"local_only": "false",
|
"local_only": "false",
|
||||||
"registry_images": "false",
|
"registry_images": "false",
|
||||||
"with_install": "false",
|
"with_install": "true",
|
||||||
|
"release": "21.12",
|
||||||
"sysadmin_password": "XXXXXXX",
|
"sysadmin_password": "XXXXXXX",
|
||||||
"restore_values": {
|
"restore_values": {
|
||||||
"backup_filename": "filename"
|
"backup_filename": "filename"
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2022 Wind River Systems, Inc.
|
# Copyright (c) 2022-2023 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
import json
|
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_messaging import RemoteError
|
from oslo_messaging import RemoteError
|
||||||
import pecan
|
import pecan
|
||||||
import yaml
|
|
||||||
|
|
||||||
from pecan import expose
|
from pecan import expose
|
||||||
from pecan import request as pecan_request
|
from pecan import request as pecan_request
|
||||||
from pecan import response
|
from pecan import response
|
||||||
|
import tsconfig.tsconfig as tsc
|
||||||
|
import yaml
|
||||||
|
|
||||||
from dcmanager.api.controllers import restcomm
|
from dcmanager.api.controllers import restcomm
|
||||||
from dcmanager.api.policies import subcloud_backup as subcloud_backup_policy
|
from dcmanager.api.policies import subcloud_backup as subcloud_backup_policy
|
||||||
|
@ -28,6 +28,7 @@ from dcmanager.common import utils
|
||||||
from dcmanager.db import api as db_api
|
from dcmanager.db import api as db_api
|
||||||
from dcmanager.rpc import client as rpc_client
|
from dcmanager.rpc import client as rpc_client
|
||||||
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -71,6 +72,7 @@ class SubcloudBackupController(object):
|
||||||
elif verb == 'restore':
|
elif verb == 'restore':
|
||||||
expected_params = {
|
expected_params = {
|
||||||
"with_install": "text",
|
"with_install": "text",
|
||||||
|
"release": "text",
|
||||||
"local_only": "text",
|
"local_only": "text",
|
||||||
"registry_images": "text",
|
"registry_images": "text",
|
||||||
"sysadmin_password": "text",
|
"sysadmin_password": "text",
|
||||||
|
@ -339,6 +341,10 @@ class SubcloudBackupController(object):
|
||||||
pecan.abort(400, _('Option registry_images cannot be used '
|
pecan.abort(400, _('Option registry_images cannot be used '
|
||||||
'without local_only option.'))
|
'without local_only option.'))
|
||||||
|
|
||||||
|
if not payload['with_install'] and payload.get('release'):
|
||||||
|
pecan.abort(400, _('Option release cannot be used '
|
||||||
|
'without with_install option.'))
|
||||||
|
|
||||||
request_entity = self._read_entity_from_request_params(context, payload)
|
request_entity = self._read_entity_from_request_params(context, payload)
|
||||||
if len(request_entity.subclouds) == 0:
|
if len(request_entity.subclouds) == 0:
|
||||||
msg = "No subclouds exist under %s %s" % (request_entity.type,
|
msg = "No subclouds exist under %s %s" % (request_entity.type,
|
||||||
|
@ -359,8 +365,9 @@ class SubcloudBackupController(object):
|
||||||
'install data.'))
|
'install data.'))
|
||||||
|
|
||||||
if payload.get('with_install'):
|
if payload.get('with_install'):
|
||||||
# Confirm the active system controller load is still in dc-vault
|
# Confirm the requested or active load is still in dc-vault
|
||||||
matching_iso, err_msg = utils.get_matching_iso()
|
payload['software_version'] = payload.get('release', tsc.SW_VERSION)
|
||||||
|
matching_iso, err_msg = utils.get_matching_iso(payload['software_version'])
|
||||||
if err_msg:
|
if err_msg:
|
||||||
LOG.exception(err_msg)
|
LOG.exception(err_msg)
|
||||||
pecan.abort(400, _(err_msg))
|
pecan.abort(400, _(err_msg))
|
||||||
|
|
|
@ -742,10 +742,14 @@ def _is_valid_for_backup_delete(subcloud):
|
||||||
|
|
||||||
def _is_valid_for_backup_restore(subcloud):
|
def _is_valid_for_backup_restore(subcloud):
|
||||||
|
|
||||||
|
msg = None
|
||||||
if subcloud.management_state != dccommon_consts.MANAGEMENT_UNMANAGED \
|
if subcloud.management_state != dccommon_consts.MANAGEMENT_UNMANAGED \
|
||||||
or subcloud.deploy_status in consts.INVALID_DEPLOY_STATES_FOR_RESTORE:
|
or subcloud.deploy_status in consts.INVALID_DEPLOY_STATES_FOR_RESTORE:
|
||||||
msg = ('Subcloud %s must be unmanaged and in a valid deploy state '
|
msg = ('Subcloud %s must be unmanaged and in a valid deploy state '
|
||||||
'for the subcloud-backup restore operation.' % subcloud.name)
|
'for the subcloud-backup restore operation.' % subcloud.name)
|
||||||
|
elif not subcloud.data_install:
|
||||||
|
msg = ('Data installation on %s is missing.' % subcloud.name)
|
||||||
|
if msg:
|
||||||
raise exceptions.ValidateFail(msg)
|
raise exceptions.ValidateFail(msg)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -745,8 +745,9 @@ class SubcloudManager(manager.Manager):
|
||||||
def _subcloud_operation_notice(
|
def _subcloud_operation_notice(
|
||||||
self, operation, restore_subclouds, failed_subclouds,
|
self, operation, restore_subclouds, failed_subclouds,
|
||||||
invalid_subclouds):
|
invalid_subclouds):
|
||||||
all_failed = not set(restore_subclouds) - set(failed_subclouds)
|
all_failed = ((not set(restore_subclouds) - set(failed_subclouds))
|
||||||
if restore_subclouds and all_failed:
|
and not invalid_subclouds)
|
||||||
|
if all_failed:
|
||||||
LOG.error("Backup %s failed for all applied subclouds" % operation)
|
LOG.error("Backup %s failed for all applied subclouds" % operation)
|
||||||
raise exceptions.SubcloudBackupOperationFailed(operation=operation)
|
raise exceptions.SubcloudBackupOperationFailed(operation=operation)
|
||||||
|
|
||||||
|
@ -972,12 +973,13 @@ class SubcloudManager(manager.Manager):
|
||||||
return subcloud, False
|
return subcloud, False
|
||||||
|
|
||||||
if payload.get('with_install'):
|
if payload.get('with_install'):
|
||||||
|
software_version = payload.get('software_version')
|
||||||
install_command = self.compose_install_command(
|
install_command = self.compose_install_command(
|
||||||
subcloud.name, subcloud_inventory_file, subcloud.software_version)
|
subcloud.name, subcloud_inventory_file, software_version)
|
||||||
# Update data_install with missing data
|
# Update data_install with missing data
|
||||||
matching_iso, _ = utils.get_vault_load_files(subcloud.software_version)
|
matching_iso, _ = utils.get_vault_load_files(software_version)
|
||||||
|
data_install['software_version'] = software_version
|
||||||
data_install['image'] = matching_iso
|
data_install['image'] = matching_iso
|
||||||
data_install['software_version'] = subcloud.software_version
|
|
||||||
data_install['ansible_ssh_pass'] = payload['sysadmin_password']
|
data_install['ansible_ssh_pass'] = payload['sysadmin_password']
|
||||||
data_install['ansible_become_pass'] = payload['sysadmin_password']
|
data_install['ansible_become_pass'] = payload['sysadmin_password']
|
||||||
install_success = self._run_subcloud_install(
|
install_success = self._run_subcloud_install(
|
||||||
|
@ -1371,7 +1373,8 @@ class SubcloudManager(manager.Manager):
|
||||||
db_api.subcloud_update(
|
db_api.subcloud_update(
|
||||||
context, subcloud.id,
|
context, subcloud.id,
|
||||||
deploy_status=consts.DEPLOY_STATE_INSTALLING,
|
deploy_status=consts.DEPLOY_STATE_INSTALLING,
|
||||||
error_description=consts.ERROR_DESC_EMPTY)
|
error_description=consts.ERROR_DESC_EMPTY,
|
||||||
|
software_version=str(payload['software_version']))
|
||||||
try:
|
try:
|
||||||
install.install(consts.DC_ANSIBLE_LOG_DIR, install_command)
|
install.install(consts.DC_ANSIBLE_LOG_DIR, install_command)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2022 Wind River Systems, Inc.
|
# Copyright (c) 2022-2023 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
|
@ -1216,3 +1216,101 @@ class TestSubcloudRestore(testroot.DCManagerApiTest):
|
||||||
six.assertRaisesRegex(self, webtest.app.AppError, "400 *",
|
six.assertRaisesRegex(self, webtest.app.AppError, "400 *",
|
||||||
self.app.patch_json, FAKE_URL_RESTORE,
|
self.app.patch_json, FAKE_URL_RESTORE,
|
||||||
headers=FAKE_HEADERS, params=data)
|
headers=FAKE_HEADERS, params=data)
|
||||||
|
|
||||||
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
|
@mock.patch('os.path.isdir')
|
||||||
|
@mock.patch('os.listdir')
|
||||||
|
def test_backup_restore_subcloud_with_install_no_release(self,
|
||||||
|
mock_listdir,
|
||||||
|
mock_isdir,
|
||||||
|
mock_rpc_client):
|
||||||
|
|
||||||
|
subcloud = fake_subcloud.create_fake_subcloud(self.ctx)
|
||||||
|
data_install = str(fake_subcloud.FAKE_SUBCLOUD_INSTALL_VALUES).replace('\'', '"')
|
||||||
|
db_api.subcloud_update(self.ctx,
|
||||||
|
subcloud.id,
|
||||||
|
availability_status=dccommon_consts.AVAILABILITY_ONLINE,
|
||||||
|
management_state=dccommon_consts.MANAGEMENT_UNMANAGED,
|
||||||
|
data_install=data_install)
|
||||||
|
|
||||||
|
fake_password = (base64.b64encode('testpass'.encode("utf-8"))).decode('ascii')
|
||||||
|
data = {'sysadmin_password': fake_password,
|
||||||
|
'subcloud': '1',
|
||||||
|
'with_install': 'True'
|
||||||
|
}
|
||||||
|
|
||||||
|
mock_isdir.return_value = True
|
||||||
|
mock_listdir.return_value = ['test.iso', 'test.sig']
|
||||||
|
mock_rpc_client().restore_subcloud_backups.return_value = True
|
||||||
|
response = self.app.patch_json(FAKE_URL_RESTORE,
|
||||||
|
headers=FAKE_HEADERS,
|
||||||
|
params=data)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_int, 200)
|
||||||
|
|
||||||
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
|
@mock.patch('os.path.isdir')
|
||||||
|
@mock.patch('os.listdir')
|
||||||
|
def test_backup_restore_subcloud_with_install_with_release(self,
|
||||||
|
mock_listdir,
|
||||||
|
mock_isdir,
|
||||||
|
mock_rpc_client):
|
||||||
|
|
||||||
|
subcloud = fake_subcloud.create_fake_subcloud(self.ctx)
|
||||||
|
data_install = str(fake_subcloud.FAKE_SUBCLOUD_INSTALL_VALUES).replace('\'', '"')
|
||||||
|
db_api.subcloud_update(self.ctx,
|
||||||
|
subcloud.id,
|
||||||
|
availability_status=dccommon_consts.AVAILABILITY_ONLINE,
|
||||||
|
management_state=dccommon_consts.MANAGEMENT_UNMANAGED,
|
||||||
|
data_install=data_install)
|
||||||
|
|
||||||
|
fake_password = (base64.b64encode('testpass'.encode("utf-8"))).decode('ascii')
|
||||||
|
data = {'sysadmin_password': fake_password,
|
||||||
|
'subcloud': '1',
|
||||||
|
'with_install': 'True',
|
||||||
|
'release': '22.12'
|
||||||
|
}
|
||||||
|
|
||||||
|
mock_isdir.return_value = True
|
||||||
|
mock_listdir.return_value = ['test.iso', 'test.sig']
|
||||||
|
mock_rpc_client().restore_subcloud_backups.return_value = True
|
||||||
|
|
||||||
|
response = self.app.patch_json(FAKE_URL_RESTORE,
|
||||||
|
headers=FAKE_HEADERS,
|
||||||
|
params=data)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_int, 200)
|
||||||
|
|
||||||
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
|
def test_backup_restore_subcloud_no_install_with_release(self, mock_rpc_client):
|
||||||
|
|
||||||
|
fake_password = (base64.b64encode('testpass'.encode("utf-8"))).decode('ascii')
|
||||||
|
data = {'sysadmin_password': fake_password,
|
||||||
|
'subcloud': '1',
|
||||||
|
'release': '22.12'
|
||||||
|
}
|
||||||
|
|
||||||
|
mock_rpc_client().restore_subcloud_backups.return_value = True
|
||||||
|
|
||||||
|
six.assertRaisesRegex(self, webtest.app.AppError, "400 *",
|
||||||
|
self.app.patch_json, FAKE_URL_RESTORE,
|
||||||
|
headers=FAKE_HEADERS, params=data)
|
||||||
|
|
||||||
|
@mock.patch.object(rpc_client, 'ManagerClient')
|
||||||
|
@mock.patch('dcmanager.common.utils.get_matching_iso')
|
||||||
|
def test_backup_restore_subcloud_invalid_release(self,
|
||||||
|
mock_rpc_client,
|
||||||
|
mock_matching_iso):
|
||||||
|
|
||||||
|
fake_password = (base64.b64encode('testpass'.encode("utf-8"))).decode('ascii')
|
||||||
|
data = {'sysadmin_password': fake_password,
|
||||||
|
'subcloud': '1',
|
||||||
|
'release': '00.00'
|
||||||
|
}
|
||||||
|
|
||||||
|
mock_rpc_client().restore_subcloud_backups.return_value = True
|
||||||
|
mock_matching_iso.return_value = [None, True]
|
||||||
|
|
||||||
|
six.assertRaisesRegex(self, webtest.app.AppError, "400 *",
|
||||||
|
self.app.patch_json, FAKE_URL_RESTORE,
|
||||||
|
headers=FAKE_HEADERS, params=data)
|
||||||
|
|
|
@ -318,6 +318,17 @@ FAKE_BACKUP_CREATE_LOAD_1 = {
|
||||||
"registry_images": False,
|
"registry_images": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FAKE_BACKUP_RESTORE_LOAD = {
|
||||||
|
"sysadmin_password": "testpasswd",
|
||||||
|
"subcloud": 1
|
||||||
|
}
|
||||||
|
|
||||||
|
FAKE_BACKUP_RESTORE_LOAD_WITH_INSTALL = {
|
||||||
|
"sysadmin_password": "testpasswd",
|
||||||
|
"subcloud": 1,
|
||||||
|
"install_values": fake_subcloud.FAKE_SUBCLOUD_INSTALL_VALUES
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Subcloud(object):
|
class Subcloud(object):
|
||||||
def __init__(self, data, is_online):
|
def __init__(self, data, is_online):
|
||||||
|
@ -2187,3 +2198,184 @@ class TestSubcloudManager(base.DCManagerTestCase):
|
||||||
mock_keystone_client, mock_sysinv_client)
|
mock_keystone_client, mock_sysinv_client)
|
||||||
expiry2 = cached_regionone_data['expiry']
|
expiry2 = cached_regionone_data['expiry']
|
||||||
self.assertEqual(expiry1, expiry2)
|
self.assertEqual(expiry1, expiry2)
|
||||||
|
|
||||||
|
@mock.patch.object(subcloud_manager.SubcloudManager,
|
||||||
|
'_run_subcloud_backup_restore_playbook')
|
||||||
|
@mock.patch.object(subcloud_manager.SubcloudManager,
|
||||||
|
'_create_overrides_for_backup_or_restore')
|
||||||
|
@mock.patch.object(subcloud_manager.SubcloudManager,
|
||||||
|
'_create_subcloud_inventory_file')
|
||||||
|
def test_backup_restore_unmanaged_online(self,
|
||||||
|
mock_create_inventory_file,
|
||||||
|
mock_create_overrides,
|
||||||
|
mock_run_playbook
|
||||||
|
):
|
||||||
|
mock_create_inventory_file.return_value = 'inventory_file.yml'
|
||||||
|
mock_create_overrides.return_value = 'overrides_file.yml'
|
||||||
|
|
||||||
|
values = copy.copy(FAKE_BACKUP_RESTORE_LOAD)
|
||||||
|
subcloud = self.create_subcloud_static(
|
||||||
|
self.ctx,
|
||||||
|
name='subcloud1',
|
||||||
|
deploy_status=consts.DEPLOY_STATE_DONE)
|
||||||
|
|
||||||
|
data_install = str(fake_subcloud.FAKE_SUBCLOUD_INSTALL_VALUES).replace('\'', '"')
|
||||||
|
|
||||||
|
db_api.subcloud_update(self.ctx,
|
||||||
|
subcloud.id,
|
||||||
|
availability_status=dccommon_consts.AVAILABILITY_ONLINE,
|
||||||
|
management_state=dccommon_consts.MANAGEMENT_UNMANAGED,
|
||||||
|
data_install=data_install)
|
||||||
|
|
||||||
|
sm = subcloud_manager.SubcloudManager()
|
||||||
|
sm.restore_subcloud_backups(self.ctx, payload=values)
|
||||||
|
|
||||||
|
mock_create_inventory_file.assert_called_once()
|
||||||
|
mock_create_overrides.assert_called_once()
|
||||||
|
mock_run_playbook.assert_called_once()
|
||||||
|
|
||||||
|
# Verify that subcloud has the correct deploy status
|
||||||
|
updated_subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud.name)
|
||||||
|
self.assertEqual(consts.DEPLOY_STATE_PRE_RESTORE,
|
||||||
|
updated_subcloud.deploy_status)
|
||||||
|
|
||||||
|
@mock.patch.object(subcloud_manager.SubcloudManager,
|
||||||
|
'_run_subcloud_backup_restore_playbook')
|
||||||
|
@mock.patch.object(subcloud_manager.SubcloudManager,
|
||||||
|
'_create_overrides_for_backup_or_restore')
|
||||||
|
@mock.patch.object(subcloud_manager.SubcloudManager,
|
||||||
|
'_create_subcloud_inventory_file')
|
||||||
|
def test_backup_restore_managed_online(self,
|
||||||
|
mock_create_inventory_file,
|
||||||
|
mock_create_overrides,
|
||||||
|
mock_run_playbook
|
||||||
|
):
|
||||||
|
|
||||||
|
values = copy.copy(FAKE_BACKUP_RESTORE_LOAD)
|
||||||
|
subcloud = self.create_subcloud_static(
|
||||||
|
self.ctx,
|
||||||
|
name='subcloud1',
|
||||||
|
deploy_status=consts.DEPLOY_STATE_NONE)
|
||||||
|
|
||||||
|
data_install = str(fake_subcloud.FAKE_SUBCLOUD_INSTALL_VALUES).replace('\'', '"')
|
||||||
|
|
||||||
|
db_api.subcloud_update(self.ctx,
|
||||||
|
subcloud.id,
|
||||||
|
availability_status=dccommon_consts.AVAILABILITY_ONLINE,
|
||||||
|
management_state=dccommon_consts.MANAGEMENT_MANAGED,
|
||||||
|
data_install=data_install)
|
||||||
|
|
||||||
|
sm = subcloud_manager.SubcloudManager()
|
||||||
|
return_log = sm.restore_subcloud_backups(self.ctx, payload=values)
|
||||||
|
|
||||||
|
expected_log = 'skipped for local backup restore operation'
|
||||||
|
|
||||||
|
self.assertIn(expected_log, return_log)
|
||||||
|
|
||||||
|
@mock.patch.object(subcloud_manager.SubcloudManager,
|
||||||
|
'_run_subcloud_backup_restore_playbook')
|
||||||
|
@mock.patch.object(subcloud_manager.SubcloudManager,
|
||||||
|
'_create_overrides_for_backup_or_restore')
|
||||||
|
@mock.patch.object(subcloud_manager.SubcloudManager,
|
||||||
|
'_create_subcloud_inventory_file')
|
||||||
|
def test_backup_restore_unmanaged_offline(self,
|
||||||
|
mock_create_inventory_file,
|
||||||
|
mock_create_overrides,
|
||||||
|
mock_run_playbook
|
||||||
|
):
|
||||||
|
|
||||||
|
values = copy.copy(FAKE_BACKUP_RESTORE_LOAD)
|
||||||
|
subcloud = self.create_subcloud_static(
|
||||||
|
self.ctx,
|
||||||
|
name='subcloud1',
|
||||||
|
deploy_status=consts.DEPLOY_STATE_NONE)
|
||||||
|
|
||||||
|
data_install = str(fake_subcloud.FAKE_SUBCLOUD_INSTALL_VALUES).replace('\'', '"')
|
||||||
|
|
||||||
|
db_api.subcloud_update(self.ctx,
|
||||||
|
subcloud.id,
|
||||||
|
availability_status=dccommon_consts.AVAILABILITY_OFFLINE,
|
||||||
|
management_state=dccommon_consts.MANAGEMENT_UNMANAGED,
|
||||||
|
data_install=data_install)
|
||||||
|
|
||||||
|
sm = subcloud_manager.SubcloudManager()
|
||||||
|
sm.restore_subcloud_backups(self.ctx, payload=values)
|
||||||
|
|
||||||
|
mock_create_inventory_file.assert_called_once()
|
||||||
|
mock_create_overrides.assert_called_once()
|
||||||
|
mock_run_playbook.assert_called_once()
|
||||||
|
|
||||||
|
# Verify that subcloud has the correct deploy status
|
||||||
|
updated_subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud.name)
|
||||||
|
self.assertEqual(consts.DEPLOY_STATE_PRE_RESTORE,
|
||||||
|
updated_subcloud.deploy_status)
|
||||||
|
|
||||||
|
def test_backup_restore_managed_offline(self):
|
||||||
|
|
||||||
|
values = copy.copy(FAKE_BACKUP_RESTORE_LOAD)
|
||||||
|
subcloud = self.create_subcloud_static(
|
||||||
|
self.ctx,
|
||||||
|
name='subcloud1',
|
||||||
|
deploy_status=consts.DEPLOY_STATE_NONE)
|
||||||
|
|
||||||
|
db_api.subcloud_update(self.ctx,
|
||||||
|
subcloud.id,
|
||||||
|
availability_status=dccommon_consts.AVAILABILITY_OFFLINE,
|
||||||
|
management_state=dccommon_consts.MANAGEMENT_MANAGED)
|
||||||
|
|
||||||
|
sm = subcloud_manager.SubcloudManager()
|
||||||
|
return_log = sm.restore_subcloud_backups(self.ctx, payload=values)
|
||||||
|
|
||||||
|
expected_log = 'skipped for local backup restore operation'
|
||||||
|
|
||||||
|
self.assertIn(expected_log, return_log)
|
||||||
|
|
||||||
|
@mock.patch.object(subcloud_manager.SubcloudManager,
|
||||||
|
'_run_subcloud_backup_restore_playbook')
|
||||||
|
@mock.patch.object(subcloud_manager.SubcloudManager, '_run_subcloud_install')
|
||||||
|
@mock.patch.object(subcloud_manager.SubcloudManager,
|
||||||
|
'_create_overrides_for_backup_or_restore')
|
||||||
|
@mock.patch.object(subcloud_manager.SubcloudManager,
|
||||||
|
'_create_subcloud_inventory_file')
|
||||||
|
@mock.patch('os.path.isdir')
|
||||||
|
@mock.patch('os.listdir')
|
||||||
|
def test_backup_restore_with_install(self,
|
||||||
|
mock_listdir,
|
||||||
|
mock_isdir,
|
||||||
|
mock_create_inventory_file,
|
||||||
|
mock_create_overrides,
|
||||||
|
mock_subcloud_install,
|
||||||
|
mock_run_restore_playbook
|
||||||
|
):
|
||||||
|
mock_isdir.return_value = True
|
||||||
|
mock_listdir.return_value = ['test.iso', 'test.sig']
|
||||||
|
mock_create_inventory_file.return_value = 'inventory_file.yml'
|
||||||
|
mock_create_overrides.return_value = 'overrides_file.yml'
|
||||||
|
mock_subcloud_install.return_value = True
|
||||||
|
mock_run_restore_playbook.return_value = True
|
||||||
|
|
||||||
|
data_install = str(fake_subcloud.FAKE_SUBCLOUD_INSTALL_VALUES).replace('\'', '"')
|
||||||
|
|
||||||
|
values = copy.copy(FAKE_BACKUP_RESTORE_LOAD_WITH_INSTALL)
|
||||||
|
values['with_install'] = True
|
||||||
|
subcloud = self.create_subcloud_static(
|
||||||
|
self.ctx,
|
||||||
|
name='subcloud1',
|
||||||
|
data_install=data_install,
|
||||||
|
deploy_status=consts.DEPLOY_STATE_DONE)
|
||||||
|
|
||||||
|
db_api.subcloud_update(self.ctx,
|
||||||
|
subcloud.id,
|
||||||
|
availability_status=dccommon_consts.AVAILABILITY_ONLINE,
|
||||||
|
management_state=dccommon_consts.MANAGEMENT_UNMANAGED)
|
||||||
|
|
||||||
|
sm = subcloud_manager.SubcloudManager()
|
||||||
|
sm.restore_subcloud_backups(self.ctx, payload=values)
|
||||||
|
|
||||||
|
mock_create_inventory_file.assert_called_once()
|
||||||
|
mock_create_overrides.assert_called_once()
|
||||||
|
|
||||||
|
# Verify that subcloud has the correct deploy status
|
||||||
|
updated_subcloud = db_api.subcloud_get_by_name(self.ctx, subcloud.name)
|
||||||
|
self.assertEqual(consts.DEPLOY_STATE_PRE_RESTORE,
|
||||||
|
updated_subcloud.deploy_status)
|
||||||
|
|
Loading…
Reference in New Issue