diff --git a/distributedcloud/dcmanager/tests/unit/manager/test_subcloud_manager.py b/distributedcloud/dcmanager/tests/unit/manager/test_subcloud_manager.py index 460add6fa..714b99dff 100644 --- a/distributedcloud/dcmanager/tests/unit/manager/test_subcloud_manager.py +++ b/distributedcloud/dcmanager/tests/unit/manager/test_subcloud_manager.py @@ -18,6 +18,7 @@ import base64 import collections import copy import datetime +import filecmp import json import os from os import path as os_path @@ -25,11 +26,14 @@ import sys import threading import time import uuid +import yaml from eventlet.green import subprocess import mock +import netaddr from oslo_concurrency import lockutils from oslo_utils import timeutils +from six.moves.urllib import request from tsconfig.tsconfig import SW_VERSION from dccommon import consts as dccommon_consts @@ -48,6 +52,7 @@ from dcmanager.manager import system_peer_manager from dcmanager.state import subcloud_state_manager from dcmanager.tests import base from dcmanager.tests.unit.common import fake_subcloud +from dcmanager.tests.unit.db import test_subcloud_alarms from dcmanager.tests.unit.manager import test_system_peer_manager from dcmanager.tests import utils @@ -63,6 +68,13 @@ FAKE_ADMIN_PROJECT_ID = 1 FAKE_SERVICE_PROJECT_ID = 2 +class FakeEndpoint(object): + def __init__(self, endpoint_name, region, service_id): + self.endpoint_name = endpoint_name + self.region = region + self.service_id = service_id + + class FakeUser(object): def __init__(self, name, id): self.name = name @@ -339,12 +351,13 @@ class BaseTestSubcloudManager(base.DCManagerTestCase): self._mock_dcmanager_api() self._mock_context() self._mock_subcloud_manager_create_addn_hosts_dc() - self._mock_subcloud_manager_write_subcloud_ansible_config() self._mock_log(subcloud_manager) + self._mock_subcloud_manager_keyring() self._mock_utils_create_subcloud_inventory() self._mock_utils_delete_subcloud_inventory() self._mock_utils_get_playbook_for_software_version() - self._mock_subcloud_manager_keyring() + self._mock_subcloud_manager_create_intermediate_ca_cert() + self._mock_subprocess_run() self._mock_os_mkdir() self._mock_os_listdir() self._mock_os_path_isdir() @@ -354,7 +367,12 @@ class BaseTestSubcloudManager(base.DCManagerTestCase): self.subcloud = self.create_subcloud_static(self.ctx) - self.mock_keyring.get_password.return_value = "testpassword" + self.system_peer_test = test_system_peer_manager.TestSystemPeerManager + self.system_peer = self.system_peer_test.create_system_peer_static( + self.ctx, peer_name='SystemPeer1' + ) + self.peer_group = self.create_subcloud_peer_group_static(self.ctx) + self.fake_install_values = \ copy.copy(fake_subcloud.FAKE_SUBCLOUD_INSTALL_VALUES) self.fake_payload = {"sysadmin_password": "testpass", @@ -454,6 +472,20 @@ class BaseTestSubcloudManager(base.DCManagerTestCase): self.mock_create_intermediate_ca_cert = mock_patch.start() self.addCleanup(mock_patch.stop) + def _mock_netaddr_ipaddress(self): + """Mock netaddr's IPAddress""" + + mock_patch = mock.patch.object(netaddr, 'IPAddress') + self.mock_netaddr_ipaddress = mock_patch.start() + self.addCleanup(mock_patch.stop) + + def _mock_subprocess_run(self): + """Mock subprocess's run""" + + mock_patch = mock.patch.object(subprocess, 'run') + self.mock_subprocess_run = mock_patch.start() + self.addCleanup(mock_patch.stop) + def _mock_context(self): """Mock the context""" @@ -513,11 +545,17 @@ class TestSubcloudManager(BaseTestSubcloudManager): self.values = utils.create_subcloud_dict(base.SUBCLOUD_SAMPLE_DATA_0) self.mock_openstack_driver().keystone_client = FakeKeystoneClient() + self.system_peer_test.create_peer_group_association_static( + self.ctx, + system_peer_id=self.system_peer.id, + peer_group_id=self.peer_group.id) + @mock.patch.object(kubeoperator, 'KubeOperator') - def test_generate_subcloud_ansible_config_initial_deployment(self, + @mock.patch.object(json, 'dumps') + def test_generate_subcloud_ansible_config_initial_deployment(self, mock_dumps, mock_kubeoperator): - self._mock_subcloud_manager_write_subcloud_ansible_config() initial_deployment = True + self._mock_builtins_open() self.sm.generate_subcloud_ansible_config(self.subcloud, self.values, initial_deployment) @@ -526,7 +564,6 @@ class TestSubcloudManager(BaseTestSubcloudManager): mock_kubeoperator.assert_called_once() def test_generate_subcloud_ansible_config(self): - self._mock_subcloud_manager_create_intermediate_ca_cert() self._mock_builtins_open() self.subcloud['region_name'] = self.values['region_name'] initial_deployment = False @@ -536,7 +573,6 @@ class TestSubcloudManager(BaseTestSubcloudManager): self.mock_keyring.get_password.assert_called() self.mock_create_subcloud_inventory.assert_called_once() self.mock_create_intermediate_ca_cert.assert_called_once() - self.mock_write_subcloud_ansible_config.assert_called_once() def test_generate_subcloud_ansible_config_failed(self): self.mock_create_subcloud_inventory.side_effect = base.FakeException('boom') @@ -550,12 +586,54 @@ class TestSubcloudManager(BaseTestSubcloudManager): {'name': fake_subcloud.FAKE_SUBCLOUD_DATA['name'], 'region_name': fake_subcloud.FAKE_SUBCLOUD_DATA['region_name']} ) - self.sm.get_subcloud_name_by_region_name(self.ctx, self.subcloud.region_name) ret = db_api.subcloud_get_by_region_name(self.ctx, self.subcloud.region_name) self.assertEqual(self.subcloud.name, ret.name) + def test_get_peer_system_list(self): + db_api.system_peer_update( + self.ctx, self.system_peer.id, availability_state= \ + consts.SYSTEM_PEER_AVAILABILITY_STATE_UNAVAILABLE + ) + self.sm._get_peer_system_list(self.peer_group) + self.mock_log.warning.assert_called_once_with( + "Peer system %s offline, skip checking" % self.system_peer.peer_name) + + def test_get_peer_system_list_availability_state(self): + db_api.system_peer_update( + self.ctx, self.system_peer.id, + availability_state=consts.SYSTEM_PEER_AVAILABILITY_STATE_AVAILABLE + ) + return_peer = self.sm._get_peer_system_list(self.peer_group) + self.assertEqual(len(return_peer), 1) + + def test_run_deploy_phases(self): + payload = {} + deploy_phases_to_run = {consts.DEPLOY_PHASE_CONFIG} + self.sm.run_deploy_phases( + self.ctx, self.subcloud.id, payload, deploy_phases_to_run, + ) + self.mock_log.exception.assert_called_once_with( + f'Failed to configure {self.subcloud.name}' + ) + + @mock.patch.object(subcloud_manager.SubcloudManager, + '_update_backup_status_by_ids') + def test_mark_invalid_subclouds_for_backup_validation_failed( + self, mock_update_backup_status_by_ids + ): + mock_update_backup_status_by_ids.side_effect = \ + exceptions.DCManagerException + self.assertRaises( + exceptions.DCManagerException, + self.sm._mark_invalid_subclouds_for_backup, + self.ctx, [self.subcloud] + ) + self.mock_log.exception.assert_called_once_with( + 'Subcloud backup validation failed' + ) + class TestSubcloudDeploy(BaseTestSubcloudManager): """Test class for testing subcloud deploy""" @@ -564,6 +642,7 @@ class TestSubcloudDeploy(BaseTestSubcloudManager): super().setUp() self._mock_builtins_open() + self._mock_subcloud_manager_write_subcloud_ansible_config() self._mock_subcloud_manager_run_subcloud_install() self._mock_ansible_run_playbook() self.mock_openstack_driver().keystone_client = FakeKeystoneClient() @@ -613,7 +692,6 @@ class TestSubcloudDeploy(BaseTestSubcloudManager): updated_subcloud.deploy_status) def test_subcloud_deploy_create(self): - self._mock_subcloud_manager_create_intermediate_ca_cert() values = utils.create_subcloud_dict(base.SUBCLOUD_SAMPLE_DATA_0) values['deploy_status'] = consts.DEPLOY_STATE_NONE @@ -648,7 +726,8 @@ class TestSubcloudDeploy(BaseTestSubcloudManager): values['deploy_status'] = consts.DEPLOY_STATE_NONE # dcmanager add_subcloud queries the data from the db - subcloud = self.create_subcloud_static(self.ctx, name=values['name'], + subcloud = self.create_subcloud_static(self.ctx, + name=values['name'], region_name=values['region_name']) values['id'] = subcloud.id @@ -667,7 +746,26 @@ class TestSubcloudDeploy(BaseTestSubcloudManager): updated_subcloud.deploy_status) def test_deploy_create_secondary(self): - self._mock_subcloud_manager_create_intermediate_ca_cert() + values = utils.create_subcloud_dict(base.SUBCLOUD_SAMPLE_DATA_0) + values['deploy_status'] = consts.DEPLOY_STATE_NONE + subcloud = self.create_subcloud_static( + self.ctx, name=values['name'], region_name=values['region_name'] + ) + values['id'] = subcloud.id + values['secondary'] = 'true' + values['ansible_ssh_pass'] = 'testpass' + values['sysadmin_password'] = 'testpass' + values['ansible_become_pass'] = 'testpass' + values['admin_password'] = 'testpass' + + subcloud_dict = self.sm.subcloud_deploy_create( + self.ctx, subcloud.id, payload=values) + + self.assertEqual( + consts.DEPLOY_STATE_SECONDARY, subcloud_dict['deploy-status'] + ) + + def test_deploy_create_secondary_without(self): values = utils.create_subcloud_dict(base.SUBCLOUD_SAMPLE_DATA_0) values['deploy_status'] = consts.DEPLOY_STATE_NONE subcloud = self.create_subcloud_static( @@ -682,9 +780,23 @@ class TestSubcloudDeploy(BaseTestSubcloudManager): self.assertEqual( consts.DEPLOY_STATE_SECONDARY, subcloud_dict['deploy-status'] ) - updated_subcloud = db_api.subcloud_get_by_name(self.ctx, values['name']) - self.assertEqual(consts.DEPLOY_STATE_SECONDARY, - updated_subcloud.deploy_status) + + def test_deploy_create_secondary_failed(self): + self.mock_openstack_driver.side_effect = Exception('boom') + values = utils.create_subcloud_dict(base.SUBCLOUD_SAMPLE_DATA_0) + values['deploy_status'] = consts.DEPLOY_STATE_NONE + subcloud = self.create_subcloud_static( + self.ctx, name=values['name'], region_name=values['region_name'] + ) + values['id'] = subcloud.id + values['secondary'] = 'true' + subcloud_dict = self.sm.subcloud_deploy_create( + self.ctx, subcloud.id, payload=values) + self.assertEqual( + consts.DEPLOY_STATE_SECONDARY_FAILED, subcloud_dict['deploy-status'] + ) + + @mock.patch.object(cutils, 'update_values_on_yaml_file') def test_subcloud_deploy_bootstrap(self, mock_update_yml): @@ -714,7 +826,6 @@ class TestSubcloudDeploy(BaseTestSubcloudManager): self.assertFalse(updated_subcloud.rehomed) def test_subcloud_deploy_bootstrap_run_playbook_failed(self): - self._mock_subcloud_manager_create_intermediate_ca_cert() self.mock_keyring.get_password.return_value = "testpass" self.mock_ansible_run_playbook.side_effect = PlaybookExecutionFailed() @@ -776,7 +887,6 @@ class TestSubcloudDeploy(BaseTestSubcloudManager): def test_configure_subcloud_failed(self): self.mock_ansible_run_playbook.side_effect = PlaybookExecutionFailed() self.subcloud['deploy_status'] = consts.DEPLOY_STATE_PRE_CONFIG - self.mock_keyring.get_password.return_value = "testpass" self.fake_payload.update({ "user_uploaded_artifacts": "fake_files", consts.BOOTSTRAP_ADDRESS: @@ -791,6 +901,19 @@ class TestSubcloudDeploy(BaseTestSubcloudManager): updated_subcloud.deploy_status) self.mock_create_subcloud_inventory.assert_called_once() + def test_configure_subcloud_pre_config_failed(self): + + ret = self.sm.subcloud_deploy_config(self.ctx, + self.subcloud.id, + payload=self.fake_payload) + updated_subcloud = db_api.subcloud_get_by_name(self.ctx, + self.subcloud.name) + self.assertEqual(consts.DEPLOY_STATE_PRE_CONFIG_FAILED, + updated_subcloud.deploy_status) + self.mock_log.exception.assert_called_once_with( + f'Failed to configure {self.subcloud.name}') + self.assertFalse(ret) + @mock.patch.object(subcloud_manager.SubcloudManager, '_prepare_for_deployment') @mock.patch.object(cutils, 'update_values_on_yaml_file') @@ -799,7 +922,6 @@ class TestSubcloudDeploy(BaseTestSubcloudManager): mock_prepare_for_deployment ): self.mock_get_playbook_for_software_version.return_value = FAKE_SW_VERSION - self.mock_keyring.get_password.return_value = "testpass" self.mock_ansible_run_playbook.return_value = False self.mock_run_subcloud_install.return_value = True @@ -876,7 +998,7 @@ class TestSubcloudAdd(BaseTestSubcloudManager): def setUp(self): super().setUp() self._mock_ansible_run_playbook() - self._mock_subcloud_manager_create_intermediate_ca_cert() + self._mock_subcloud_manager_write_subcloud_ansible_config() self.mock_openstack_driver().keystone_client = FakeKeystoneClient() self._mock_subcloud_manager_get_cached_regionone_data() self.mock_get_cached_regionone_data.return_value = \ @@ -1028,20 +1150,20 @@ class TestSubcloudDelete(BaseTestSubcloudManager): def setUp(self): super().setUp() + self._mock_os_remove() self.mock_openstack_driver().keystone_client = FakeKeystoneClient() self._mock_subcloud_manager_get_cached_regionone_data() self.mock_get_cached_regionone_data.return_value = \ FAKE_CACHED_REGIONONE_DATA - @mock.patch.object(subcloud_manager.SubcloudManager, - '_delete_subcloud_cert') - def test_delete_subcloud(self, - mock_delete_subcloud_cert): + @mock.patch.object(kubeoperator, 'KubeOperator') + def test_delete_subcloud(self, mock_kubeoperator): + self._mock_builtins_open() self.sm.delete_subcloud(self.ctx, subcloud_id=self.subcloud.id) self.mock_get_cached_regionone_data.assert_called_once() self.mock_sysinv_client().delete_route.assert_called() self.mock_create_addn_hosts.assert_called_once() - mock_delete_subcloud_cert.assert_called_once() + # mock_delete_subcloud_cert.assert_called_once() # Verify subcloud was deleted self.assertRaises(exceptions.SubcloudNameNotFound, @@ -1067,7 +1189,7 @@ class TestSubcloudDelete(BaseTestSubcloudManager): @mock.patch('shutil.rmtree') def test_cleanup_ansible_files(self, mock_rmtree): - + self._mock_os_path_exists() self.sm._cleanup_ansible_files('subcloud1') files = ('subcloud1.yml', @@ -1087,7 +1209,10 @@ class TestSubcloudDelete(BaseTestSubcloudManager): @mock.patch('shutil.rmtree') def test_cleanup_ansible_files_exception(self, mock_rmtree): + self._mock_os_path_exists() self.mock_os_remove.side_effect = FileNotFoundError() + self.mock_os_path_exists.return_value = True + self.sm._cleanup_ansible_files('subcloud1') self.mock_log.exception.assert_called_once_with( "Unable to cleanup subcloud ansible files for subcloud: subcloud1") @@ -1295,11 +1420,10 @@ class TestSubcloudUpdate(BaseTestSubcloudManager): @mock.patch.object(dcmanager_v1.DcmanagerClient, 'update_subcloud') def test_unmanage_system_peer_subcloud_failed(self, mock_update_subcloud, mock_peer_dc_client): - system_peer_test = test_system_peer_manager.TestSystemPeerManager - system_peer = system_peer_test.create_system_peer_static(self.ctx) mock_peer_dc_client.return_value = test_system_peer_manager.\ FakeDcmanagerClient() - ret = self.sm._unmanage_system_peer_subcloud([system_peer], self.subcloud) + ret = self.sm._unmanage_system_peer_subcloud( + [self.system_peer], self.subcloud) self.assertEqual(ret, False) @mock.patch.object(subcloud_manager.SubcloudManager, @@ -1405,6 +1529,71 @@ class TestSubcloudUpdate(BaseTestSubcloudManager): mock_update_endpoints.assert_called_once() self.assertFalse(mock_delete_route.called) + @mock.patch.object(subcloud_manager.SubcloudManager, + '_delete_subcloud_routes') + def test_configure_system_controller_network_failed( + self, mock_delete_route + ): + self.mock_sysinv_client.side_effect = Exception('boom') + self.subcloud['deploy_status'] = consts.DEPLOY_STATE_DONE + db_api.subcloud_update( + self.ctx, self.subcloud.id, + availability_status=dccommon_consts.AVAILABILITY_ONLINE) + + payload = {'name': "subcloud1", + 'description': "subcloud description", + 'location': "subcloud location", + 'management_subnet': "192.168.101.0/24", + 'management_start_ip': "192.168.101.3", + 'management_end_ip': "192.168.101.49", + 'management_gateway_ip': "192.168.101.1"} + + self.sm._configure_system_controller_network( + self.ctx, payload, self.subcloud) + + # Verify subcloud was updated with correct values + updated_subcloud = db_api.subcloud_get_by_name( + self.ctx, self.subcloud.name) + self.assertEqual(consts.DEPLOY_STATE_RECONFIGURING_NETWORK_FAILED, + updated_subcloud.deploy_status) + self.mock_openstack_driver.assert_called_once() + self.assertFalse(mock_delete_route.called) + self.mock_log.exception.assert_called_once_with( + f'Failed to create route to subcloud {self.subcloud.name}.') + + @mock.patch.object(subcloud_manager.SubcloudManager, + '_delete_subcloud_routes') + @mock.patch.object(subcloud_manager.SubcloudManager, + '_update_services_endpoint') + @mock.patch.object(subcloud_manager.SubcloudManager, + '_create_subcloud_route') + def test_configure_system_controller_network_failed_to_update_endpoints( + self, mock_create_route, + mock_update_endpoints, mock_delete_route): + mock_update_endpoints.side_effect = Exception('boom') + self.subcloud['deploy_status'] = consts.DEPLOY_STATE_DONE + db_api.subcloud_update( + self.ctx, self.subcloud.id, + availability_status=dccommon_consts.AVAILABILITY_ONLINE) + + payload = {'name': "subcloud1", + 'description': "subcloud description", + 'location': "subcloud location", + 'management_subnet': "192.168.101.0/24", + 'management_start_ip': "192.168.101.3", + 'management_end_ip': "192.168.101.49", + 'management_gateway_ip': "192.168.101.1"} + + self.sm._configure_system_controller_network( + self.ctx, payload, self.subcloud) + + self.mock_openstack_driver.assert_called_once() + mock_create_route.assert_called_once() + mock_update_endpoints.assert_called_once() + self.assertFalse(mock_delete_route.called) + self.mock_log.exception.assert_called_once_with( + f'Failed to update subcloud {self.subcloud.name} endpoints') + def test_update_subcloud_with_install_values(self): db_api.subcloud_update( self.ctx, @@ -2085,7 +2274,6 @@ class TestSubcloudUpdate(BaseTestSubcloudManager): @mock.patch.object(threading.Thread, 'start') def test_update_subcloud_with_network_reconfig_failed(self, mock_start): self._mock_builtins_open() - self._mock_subcloud_manager_create_intermediate_ca_cert() self.mock_os_listdir.return_value = ['testfile1', 'testfile2'] mock_start.side_effect = Exception('boom') @@ -2151,6 +2339,27 @@ class TestSubcloudUpdate(BaseTestSubcloudManager): .format(ANS_PATH)] ) + def test_update_subcloud_sync_endpoint_type_region_name_not_found(self): + # Test openstack app installed + openstack_installed = True + self.assertRaises( + exceptions.SubcloudRegionNameNotFound, + self.sm.update_subcloud_sync_endpoint_type, self.ctx, 'test_region', + dccommon_consts.ENDPOINT_TYPES_LIST_OS, openstack_installed + ) + + def test_update_subcloud_sync_endpoint_type_failed(self): + endpoint_type_list = None + # Test openstack app installed + openstack_installed = True + self.sm.update_subcloud_sync_endpoint_type(self.ctx, + self.subcloud.region_name, + endpoint_type_list, + openstack_installed) + self.mock_log.exception.assert_called_once_with( + 'Problem informing dcorch of subcloud sync endpoint type change,' + f' subcloud region: {base.SUBCLOUD_1["region_name"]}' + ) class TestSubcloudCompose(BaseTestSubcloudManager): """Test class for testing subcloud compose command""" @@ -2377,9 +2586,9 @@ class TestSubcloudRedeploy(BaseTestSubcloudManager): def test_handle_subcloud_operations_in_progress(self): # There are three types of transitory states state_map = { - 'deploy_status': subcloud_manager.TRANSITORY_STATES.copy(), - 'backup_status': subcloud_manager.TRANSITORY_BACKUP_STATES.copy(), - 'prestage_status': subcloud_manager.TRANSITORY_PRESTAGE_STATES.copy()} + 'deploy_status': subcloud_manager.TRANSITORY_STATES, + 'backup_status': subcloud_manager.TRANSITORY_BACKUP_STATES, + 'prestage_status': subcloud_manager.TRANSITORY_PRESTAGE_STATES} # Any state not defined in the transitory states should not be modified # NOTE: this should cover the test_handle_completed_subcloud_operations test @@ -2405,7 +2614,6 @@ class TestSubcloudRedeploy(BaseTestSubcloudManager): state_type, expected_state = expected_states[self.subcloud.name] self.assertEqual(expected_state, subcloud.get(state_type)) - class TestSubcloudBackup(BaseTestSubcloudManager): """Test class for testing Subcloud Backup""" @@ -2791,6 +2999,39 @@ class TestSubcloudBackup(BaseTestSubcloudManager): 'inventory_hostname=subcloud1'] ) + @mock.patch.object(subcloud_manager.SubcloudManager, + 'compose_backup_delete_command') + @mock.patch.object(subcloud_manager.SubcloudManager, + '_create_backup_overrides_file') + def test_delete_subcloud_backup_playbook_execution_failed( + self, mock_create_backup_overrides_file, + mock_compose_backup_delete_command + ): + self.mock_ansible_run_playbook.side_effect = PlaybookExecutionFailed() + db_api.subcloud_update( + self.ctx, + self.subcloud.id, + backup_status=consts.BACKUP_STATE_COMPLETE_CENTRAL) + + self.sm._delete_subcloud_backup( + self.ctx, payload=self.values, + release_version=FAKE_SW_VERSION, subcloud=self.subcloud + ) + Calls = [ + mock.call( + 'Failed to delete backup for subcloud subcloud1, check individual' + ' log at /var/log/dcmanager/ansible/subcloud1_playbook_output.log' + ' for detailed output.'), + mock.call( + 'FAILED failed playbook of (subcloud1).\ncheck individual' + ' log at /var/log/dcmanager/ansible/subcloud1_playbook_output.log' + ' for detailed output ')] + self.mock_log.error.assert_has_calls(Calls) + mock_create_backup_overrides_file.assert_called_once() + mock_compose_backup_delete_command.assert_called_once() + self.mock_ansible_run_playbook.assert_called_once() + self.mock_create_subcloud_inventory.assert_not_called() + class TestSubcloudPrestage(BaseTestSubcloudManager): """Test class for testing Subcloud Prestage""" @@ -3123,9 +3364,7 @@ class TestSubcloudBackupRestore(BaseTestSubcloudManager): updated_subcloud.deploy_status) @mock.patch.object(subcloud_install.SubcloudInstall, 'prep') - @mock.patch.object(subprocess, 'run') - def test_backup_restore_with_install_failed(self, mock_run, - mock_prep): + def test_backup_restore_with_install_failed(self, mock_prep): # FAILED installing playbook of (subcloud1). # Backup restore failed for all applied subclouds. self.mock_os_path_isdir.return_value = True @@ -3153,6 +3392,7 @@ class TestSubcloudBackupRestore(BaseTestSubcloudManager): def test_backup_restore_unmanage_online_complete_restore_val(self): self._mock_ansible_run_playbook() + self.mock_keyring.get_password.return_value = "testpassword" self.values['local_only'] = True self.values['registry_images'] = True self.values['restore_values'] = { @@ -3184,10 +3424,12 @@ class TestSubcloudBackupRestore(BaseTestSubcloudManager): self.mock_log.info.assert_has_calls(Calls) def test_backup_restore_unmanage_online_complete_backup_val(self): + self.backup_values = copy.copy(FAKE_BACKUP_CREATE_LOAD) self._mock_ansible_run_playbook() + self.mock_keyring.get_password.return_value = "testpassword" self.values['local_only'] = True self.values['registry_images'] = True - + self.values['backup_values'] = self.backup_values db_api.subcloud_update( self.ctx, self.subcloud.id, @@ -3214,6 +3456,7 @@ class TestSubcloudBackupRestore(BaseTestSubcloudManager): '_create_subcloud_inventory_file') def test_backup_restore_failed(self, mock_create_inventory_file): self._mock_ansible_run_playbook() + self.mock_keyring.get_password.return_value = "testpassword" mock_create_inventory_file.side_effect = Exception('boom') self.values['local_only'] = True self.values['registry_images'] = True @@ -3237,6 +3480,7 @@ class TestSubcloudBackupRestore(BaseTestSubcloudManager): def test_backup_restore_playbook_execution_failed(self): self._mock_ansible_run_playbook() + self.mock_keyring.get_password.return_value = "testpassword" self.mock_ansible_run_playbook.side_effect = PlaybookExecutionFailed() self.values['local_only'] = True self.values['registry_images'] = True @@ -3263,7 +3507,6 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): def setUp(self): super().setUp() self._mock_ansible_run_playbook() - self._mock_subcloud_manager_create_intermediate_ca_cert() self.mock_openstack_driver().keystone_client = FakeKeystoneClient() self.fake_bootstrap_values = \ @@ -3272,7 +3515,8 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): self.saved_payload = { "deploy_status": consts.DEPLOY_STATE_DONE, "rehome_data": '{"saved_payload": {"system_mode": "simplex",\ - "name": "testsub", "bootstrap-address": "128.224.119.56"}}', + "name": "testsub", "bootstrap-address": "128.224.119.56",\ + "admin_password": "TGk2OW51eA=="}}', } @mock.patch.object(subcloud_manager, 'db_api', side_effect=db_api) @@ -3288,7 +3532,7 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): "admin_password": self._create_password() }) payload = { - "sysadmin_password": "TGk2OW51eA==" + "sysadmin_password": self._create_password('Li69nux') } payload_result = { "name": self.subcloud.name, @@ -3298,7 +3542,8 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): "system_mode": "simplex", "name": "testsub", "bootstrap-address": "128.224.119.56", - "sysadmin_password": "Li69nux" + "sysadmin_password": "Li69nux", + "admin_password": "Li69nux" } }, } @@ -3317,12 +3562,11 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): '_run_parallel_group_operation') def test_batch_migrate_subcloud(self, mock_run_parallel_group_operation): # Prepare the test data - subcloud_pg = self.create_subcloud_peer_group_static(self.ctx) rehome_data = '{"saved_payload": {"system_mode": "simplex",\ "name": "test_sub_migrate", "bootstrap-address": "128.224.119.56"}}' payload = { "sysadmin_password": self._create_password(), - "peer_group": subcloud_pg.peer_group_name + "peer_group": self.peer_group.peer_group_name } subcloud = self.create_subcloud_static( self.ctx, @@ -3332,7 +3576,7 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): db_api.subcloud_update( self.ctx, subcloud.id, - peer_group_id=subcloud_pg.id, + peer_group_id=self.peer_group.id, rehome_data=rehome_data, management_state=dccommon_consts.MANAGEMENT_UNMANAGED) subcloud = self.create_subcloud_static( @@ -3343,7 +3587,7 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): db_api.subcloud_update( self.ctx, subcloud.id, - peer_group_id=subcloud_pg.id, + peer_group_id=self.peer_group.id, management_state=dccommon_consts.MANAGEMENT_UNMANAGED) subcloud = self.create_subcloud_static( self.ctx, @@ -3352,7 +3596,7 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): db_api.subcloud_update( self.ctx, subcloud.id, - peer_group_id=subcloud_pg.id, + peer_group_id=self.peer_group.id, rehome_data=rehome_data, management_state=dccommon_consts.MANAGEMENT_UNMANAGED) subcloud = self.create_subcloud_static( @@ -3362,7 +3606,7 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): db_api.subcloud_update( self.ctx, subcloud.id, - peer_group_id=subcloud_pg.id, + peer_group_id=self.peer_group.id, rehome_data="{}", management_state=dccommon_consts.MANAGEMENT_UNMANAGED) @@ -3383,10 +3627,8 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): def test_batch_migrate_subcloud_failed_password(self): # Prepare the test data - subcloud_pg = self.create_subcloud_peer_group_static(self.ctx) - payload = { - "peer_group": subcloud_pg.peer_group_name + "peer_group": self.peer_group.peer_group_name } self.sm.batch_migrate_subcloud(self.ctx, payload) self.mock_log.error.assert_called_once_with( @@ -3397,9 +3639,7 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): def test_migrate_manage_subcloud_called_unmanage_peer_subcloud( self, mock_unmanage_system_peer_subcloud ): - system_peer_test = test_system_peer_manager.TestSystemPeerManager - system_peer = system_peer_test.create_system_peer_static(self.ctx) - self.sm._migrate_manage_subcloud(self.ctx, mock.ANY, [system_peer], + self.sm._migrate_manage_subcloud(self.ctx, mock.ANY, [self.system_peer], self.subcloud) mock_unmanage_system_peer_subcloud.assert_called() @@ -3419,10 +3659,9 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): 'get_peer_dc_client') def test_unmanage_system_peer_subcloud_ret_false(self, mock_get_peer_dc_client): - system_peer_test = test_system_peer_manager.TestSystemPeerManager - system_peer = system_peer_test.create_system_peer_static(self.ctx) mock_get_peer_dc_client.return_value = None - ret = self.sm._unmanage_system_peer_subcloud([system_peer], self.subcloud) + ret = self.sm._unmanage_system_peer_subcloud( + [self.system_peer], self.subcloud) self.assertEqual(ret, False) @mock.patch.object(system_peer_manager.SystemPeerManager, @@ -3431,13 +3670,23 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): def test_unmanage_system_peer_subcloud_ret_true(self, mock_get_peer_dc_client, mock_update_subcloud): - system_peer_test = test_system_peer_manager.TestSystemPeerManager - system_peer = system_peer_test.create_system_peer_static(self.ctx) mock_get_peer_dc_client.return_value = mock.MagicMock() mock_update_subcloud.side_effect = exceptions.SubcloudNotUnmanaged() - ret = self.sm._unmanage_system_peer_subcloud([system_peer], self.subcloud) + ret = self.sm._unmanage_system_peer_subcloud( + [self.system_peer], self.subcloud) self.assertEqual(ret, True) + @mock.patch.object(system_peer_manager.SystemPeerManager, + 'get_peer_dc_client') + @mock.patch.object(dcmanager_v1.DcmanagerClient, 'update_subcloud') + def test_unmanage_system_peer_subcloud_update_subcloud(self, + mock_get_peer_dc_client, + mock_update_subcloud): + mock_get_peer_dc_client.return_value = mock.MagicMock() + ret = self.sm._unmanage_system_peer_subcloud( + [self.system_peer], self.subcloud) + self.assertEqual(ret, False) + @mock.patch.object(subcloud_manager.SubcloudManager, 'subcloud_deploy_create') @mock.patch.object(subcloud_manager.SubcloudManager, 'rehome_subcloud') @mock.patch.object(subcloud_manager.SubcloudManager, 'run_deploy_phases') @@ -3500,7 +3749,6 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): self._mock_builtins_open() mock_get_local_system.return_value = FakeSysinvClient.get_system(self) self.mock_openstack_driver.keystone_client = FakeKeystoneClient() - subcloud_pg = self.create_subcloud_peer_group_static(self.ctx) db_api.subcloud_peer_group_update( self.ctx, group_id=1, @@ -3518,11 +3766,11 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): self.ctx, self.subcloud.id, deploy_status=consts.DEPLOY_STATE_SECONDARY, - peer_group_id=subcloud_pg.id, + peer_group_id=self.peer_group.id, rehome_data=self.saved_payload['rehome_data'], management_state=dccommon_consts.MANAGEMENT_UNMANAGED) - self.sm.run_batch_migrate(self.ctx, subcloud_pg, "TGk2OW51eA==") + self.sm.run_batch_migrate(self.ctx, self.peer_group, "TGk2OW51eA==") Calls = [mock.call('No association found for peer group pgname'), mock.call('Batch migrate operation finished')] self.mock_log.info.assert_has_calls(Calls) @@ -3533,7 +3781,6 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): self, mock_get_local_system, mock_subcloud_peer_group_update ): self.mock_sysinv_client().return_value = FakeSysinvClient() - subcloud_pg = self.create_subcloud_peer_group_static(self.ctx) db_api.subcloud_peer_group_update( self.ctx, group_id=1, @@ -3550,13 +3797,13 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): db_api.subcloud_update( self.ctx, self.subcloud.id, - peer_group_id=subcloud_pg.id, + peer_group_id=self.peer_group.id, rehome_data=self.saved_payload['rehome_data'], management_state=dccommon_consts.MANAGEMENT_UNMANAGED) sysadmin_password = self._create_password() - self.sm.run_batch_migrate(self.ctx, subcloud_pg, sysadmin_password) + self.sm.run_batch_migrate(self.ctx, self.peer_group, sysadmin_password) Calls = [mock.call('Skipping subcloud subcloud1 from batch migration:' ' subcloud deploy_status is not in secondary,' ' rehome-failed or rehome-prep-failed'), @@ -3591,12 +3838,10 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): f'Failed to migrate subcloud: {self.subcloud.name}, must be in ' 'secondary or rehome failure state') - @mock.patch.object(subprocess, 'run') - def test_rehome_subcloud_failed(self, - mock_subprocess_run): + def test_rehome_subcloud_failed(self): self._mock_utils_get_playbook_for_software_version() self.mock_get_playbook_for_software_version.return_value = SW_VERSION - mock_subprocess_run.return_value.returncode = 0 + self.mock_subprocess_run.return_value.returncode = 0 self.mock_ansible_run_playbook.side_effect = PlaybookExecutionFailed() self.subcloud['deploy_status'] = consts.DEPLOY_STATE_NONE @@ -3605,3 +3850,339 @@ class TestSubcloudMigrate(BaseTestSubcloudManager): self.subcloud.name) self.assertEqual(consts.DEPLOY_STATE_REHOME_FAILED, updated_subcloud.deploy_status) + + +class TestSubcloudInstall(BaseTestSubcloudManager): + """Test class for testing Subcloud Install""" + + def setUp(self): + super().setUp() + self._mock_ansible_run_playbook() + self._mock_openstack_driver(subcloud_install) + self._mock_sysinv_client(subcloud_install) + self._mock_os_path_exists() + self._mock_os_remove() + self.fake_install_values = \ + copy.copy(fake_subcloud.FAKE_SUBCLOUD_INSTALL_VALUES) + + @mock.patch.object( + subcloud_manager.SubcloudManager, 'compose_install_command') + @mock.patch.object(subprocess, 'check_call') + @mock.patch.object(request, 'urlretrieve') + def test_subcloud_install(self, + mock_request_urlretrieve, + mock_subprocess_check_call, + mock_compose_install_command): + self._mock_builtins_open() + self._mock_ansible_run_playbook() + mock_request_urlretrieve.return_value = "fake_path", "empty" + self.mock_sysinv_client().get_oam_addresses.return_value = \ + FakeOamAddresses() + self.mock_subprocess_run.return_value.returncode = 0 + self.mock_ansible_run_playbook.return_value = False + self.subcloud.update( + {'name': fake_subcloud.FAKE_SUBCLOUD_DATA['name'], + 'deploy_status': consts.DEPLOY_STATE_PRE_INSTALL} + ) + self.fake_install_values['software_version'] = SW_VERSION + fake_log_file = ( + os.path.join(consts.DC_ANSIBLE_LOG_DIR, + fake_subcloud.FAKE_SUBCLOUD_DATA['name']) + + "_playbook_output.log" + ) + install_success = self.sm._run_subcloud_install( + self.ctx, + self.subcloud, + mock_compose_install_command, + fake_log_file, + self.fake_install_values + ) + updated_subcloud = db_api.subcloud_get_by_name(self.ctx, + self.subcloud.name) + self.assertEqual( + consts.DEPLOY_STATE_INSTALLING, + updated_subcloud.deploy_status + ) + self.mock_ansible_run_playbook.assert_called_once() + self.assertTrue(install_success) + + @mock.patch.object( + subcloud_manager.SubcloudManager, 'compose_install_command') + @mock.patch.object(subprocess, 'check_call') + @mock.patch.object(request, 'urlretrieve') + def test_subcloud_install_fail_prep( + self, mock_request_urlretrieve, mock_subprocess_check_call, + mock_compose_install_command + ): + self.mock_ansible_run_playbook.return_value = False + mock_request_urlretrieve.side_effect = base.FakeException('boom') + self.subcloud.update( + {'name': fake_subcloud.FAKE_SUBCLOUD_DATA['name'], + 'deploy_status': consts.DEPLOY_STATE_PRE_INSTALL} + ) + self.fake_install_values['software_version'] = SW_VERSION + fake_log_file = ( + os.path.join(consts.DC_ANSIBLE_LOG_DIR, + fake_subcloud.FAKE_SUBCLOUD_DATA['name']) + + "_playbook_output.log" + ) + install_success = self.sm._run_subcloud_install( + self.ctx, + self.subcloud, + mock_compose_install_command, + fake_log_file, + self.fake_install_values + ) + ret = db_api.subcloud_get_by_name(self.ctx, self.subcloud.name) + self.assertEqual( + consts.DEPLOY_STATE_PRE_INSTALL_FAILED, + ret.deploy_status + ) + self.mock_ansible_run_playbook.assert_not_called() + self.assertFalse(install_success) + + @mock.patch.object( + subcloud_manager.SubcloudManager, 'compose_install_command') + @mock.patch.object(subprocess, 'check_call') + @mock.patch.object(request, 'urlretrieve') + def test_subcloud_install_fail_install( + self, mock_request_urlretrieve, mock_subprocess_check_call, + mock_compose_install_command + ): + mock_request_urlretrieve.return_value = "fake_path", "empty" + self.mock_sysinv_client().get_oam_addresses.return_value = \ + FakeOamAddresses() + self.mock_subprocess_run.return_value.returncode = 0 + + self.subcloud.update( + {'name': fake_subcloud.FAKE_SUBCLOUD_DATA['name'], + 'deploy_status': consts.DEPLOY_STATE_PRE_INSTALL} + ) + self.fake_install_values['software_version'] = SW_VERSION + + fake_log_file = ( + os.path.join(consts.DC_ANSIBLE_LOG_DIR, + fake_subcloud.FAKE_SUBCLOUD_DATA['name']) + + "_playbook_output.log" + ) + install_success = self.sm._run_subcloud_install( + self.ctx, + self.subcloud, + mock_compose_install_command, + fake_log_file, + self.fake_install_values + ) + updated_subcloud = db_api.subcloud_get_by_name(self.ctx, self.subcloud.name) + self.assertEqual( + consts.DEPLOY_STATE_PRE_INSTALL_FAILED, + updated_subcloud.deploy_status + ) + self.assertFalse(install_success) + + @mock.patch.object( + subcloud_manager.SubcloudManager, 'compose_install_command') + @mock.patch.object(subprocess, 'check_call') + @mock.patch.object(request, 'urlretrieve') + def test_subcloud_install_with_aborted_install( + self, + mock_request_urlretrieve, mock_subprocess_check_call, + mock_compose_install_command + ): + self._mock_builtins_open() + mock_request_urlretrieve.return_value = "fake_path", "empty" + self.mock_sysinv_client().get_oam_addresses.return_value = \ + FakeOamAddresses() + self.mock_subprocess_run.return_value.returncode = 0 + self.mock_ansible_run_playbook.return_value = True + + self.subcloud.update( + {'name': fake_subcloud.FAKE_SUBCLOUD_DATA['name'], + 'deploy_status': consts.DEPLOY_STATE_PRE_INSTALL_FAILED} + ) + + self.fake_install_values['software_version'] = SW_VERSION + + fake_log_file = ( + os.path.join(consts.DC_ANSIBLE_LOG_DIR, + fake_subcloud.FAKE_SUBCLOUD_DATA['name']) + + "_playbook_output.log" + ) + install_success = self.sm._run_subcloud_install( + self.ctx, + self.subcloud, + mock_compose_install_command, + fake_log_file, + self.fake_install_values + ) + updated_subcloud = db_api.subcloud_get_by_name(self.ctx, self.subcloud.name) + self.assertEqual( + consts.DEPLOY_STATE_INSTALLING, updated_subcloud.deploy_status + ) + self.mock_ansible_run_playbook.assert_called_once() + self.assertFalse(install_success) + + +class TestNetworkReconfig(BaseTestSubcloudManager): + """Test class for testing Network Reconfig""" + + def setUp(self): + super().setUp() + self._mock_netaddr_ipaddress() + + self.payload = { + 'name': "subcloud1", 'description': "subcloud description", + 'location': "subcloud location", + 'management_subnet': "192.168.101.0/24", + 'management_start_address': "192.168.101.3", + 'management_end_ip': "192.168.101.49", + 'management_gateway_ip': "192.168.101.1" + } + self.subcloud['deploy_status'] = consts.DEPLOY_STATE_DONE + endpoint_1 = FakeEndpoint('endpoint1', 'regionOne', '1') + self.mock_openstack_driver().keystone_client.endpoints.list.return_value = \ + [endpoint_1] + self.mks_client = self.mock_openstack_driver() + db_api.subcloud_update( + self.ctx, self.subcloud.id, + availability_status=dccommon_consts.AVAILABILITY_ONLINE) + + def test_network_reconf_same_subnet_endpoint_type_platform(self): + self.mock_openstack_driver().\ + keystone_client.services.get.return_value.type = \ + dccommon_consts.ENDPOINT_TYPE_PLATFORM + + self.sm._update_services_endpoint( + self.ctx, self.payload, self.subcloud.region_name, self.mks_client + ) + self.mock_log.info.assert_called_once_with( + 'Update services endpoint to 192.168.101.3 in subcloud region ' + f'{base.SUBCLOUD_1["region_name"]}') + self.mock_dcmanager_api().subcloud_sysinv_endpoint_update.\ + assert_called_once_with(self.ctx, self.subcloud.region_name, + 'https://192.168.101.3:6386/v1') + + def test_network_reconf_same_subnet_endpoint_type_identity(self): + self.mock_openstack_driver().\ + keystone_client.services.get.return_value.type = \ + dccommon_consts.ENDPOINT_TYPE_IDENTITY + self.sm._update_services_endpoint( + self.ctx, self.payload, self.subcloud.region_name, self.mks_client + ) + self.mock_log.info.assert_called_once_with( + 'Update services endpoint to 192.168.101.3 in subcloud region ' + f'{base.SUBCLOUD_1["region_name"]}') + self.mock_dcmanager_api().subcloud_sysinv_endpoint_update.\ + assert_called_once_with(self.ctx, self.subcloud.region_name, + 'https://192.168.101.3:6386/v1') + + def test_network_reconf_same_subnet_endpoint_type_patching(self): + self.mock_openstack_driver().\ + keystone_client.services.get.return_value.type = \ + dccommon_consts.ENDPOINT_TYPE_PATCHING + self.sm._update_services_endpoint( + self.ctx, self.payload, self.subcloud.region_name, self.mks_client + ) + self.mock_log.info.assert_called_once_with( + 'Update services endpoint to 192.168.101.3 in subcloud region ' + f'{base.SUBCLOUD_1["region_name"]}') + self.mock_dcmanager_api().subcloud_sysinv_endpoint_update.\ + assert_called_once_with(self.ctx, self.subcloud.region_name, + 'https://192.168.101.3:6386/v1') + + def test_network_reconf_same_subnet_endpoint_type_fm(self): + self.mock_openstack_driver().\ + keystone_client.services.get.return_value.type = \ + dccommon_consts.ENDPOINT_TYPE_FM + self.sm._update_services_endpoint( + self.ctx, self.payload, self.subcloud.region_name, self.mks_client + ) + self.mock_log.info.assert_called_once_with( + 'Update services endpoint to 192.168.101.3 in subcloud region ' + f'{base.SUBCLOUD_1["region_name"]}') + self.mock_dcmanager_api().subcloud_sysinv_endpoint_update.\ + assert_called_once_with(self.ctx, self.subcloud.region_name, + 'https://192.168.101.3:6386/v1') + + def test_network_reconf_same_subnet_endpoint_type_nfv(self): + self.mock_openstack_driver().\ + keystone_client.services.get.return_value.type = \ + dccommon_consts.ENDPOINT_TYPE_NFV + self.sm._update_services_endpoint( + self.ctx, self.payload, self.subcloud.region_name, self.mks_client + ) + self.mock_log.info.assert_called_once_with( + 'Update services endpoint to 192.168.101.3 in subcloud region ' + f'{base.SUBCLOUD_1["region_name"]}') + self.mock_dcmanager_api().subcloud_sysinv_endpoint_update.\ + assert_called_once_with(self.ctx, self.subcloud.region_name, + 'https://192.168.101.3:6386/v1') + + def test_network_reconf_same_subnet_endpoint_type_software(self): + self.mock_openstack_driver().keystone_client.\ + services.get.return_value.type = dccommon_consts.ENDPOINT_TYPE_SOFTWARE + self.subcloud['deploy_status'] = consts.DEPLOY_STATE_DONE + self.sm._update_services_endpoint( + self.ctx, self.payload, self.subcloud.region_name, self.mks_client + ) + self.mock_log.info.assert_called_once_with( + 'Update services endpoint to 192.168.101.3 in subcloud region ' + f'{base.SUBCLOUD_1["region_name"]}' + ) + self.mock_dcmanager_api().subcloud_sysinv_endpoint_update.\ + assert_called_once_with(self.ctx, self.subcloud.region_name, + 'https://192.168.101.3:6386/v1') + + +class TestSubcloudRename(BaseTestSubcloudManager): + """Test class for testing Rename Subcloud""" + + def setUp(self): + super().setUp() + self._mock_builtins_open() + + @mock.patch.object(yaml, 'safe_load', return_value=True) + @mock.patch.object(filecmp, 'cmp', return_value=True) + @mock.patch.object(os, 'rename', return_value=True) + def test_rename_subcloud_ansible_files(self, mock_rename, mock_filecmp, + mock_load): + cur_file = 'subcloud1.yml' + self.mock_os_listdir.return_value = [cur_file] + data = {'key1': 'value1', 'key2': 'value2'} + mock_load.return_value = data + self.mock_builtins_open().return_value = \ + f'{ANS_PATH}/subcloud1_inventory.yml' + new_subcloud_name = 'testsubcloud' + alarms = test_subcloud_alarms.DBAPISubcloudAlarm + alarms.create_subcloud_alarms(self.ctx, self.subcloud.name) + rehome_data = '{"saved_payload": {"system_mode": "simplex",\ + "name": "test_sub_migrate", "bootstrap-address": "128.224.119.56"}}' + db_api.subcloud_update(self.ctx, self.subcloud.id, + rehome_data=rehome_data) + self.sm.rename_subcloud( + self.ctx, self.subcloud.id, self.subcloud.name, new_subcloud_name + ) + new_file = f'{ANS_PATH}/testsubcloud.yml' + self.assertEqual('/opt/dc-vault/ansible/testsubcloud.yml', new_file) + ret = db_api.subcloud_get_by_name(self.ctx, new_subcloud_name) + self.assertEqual(new_subcloud_name, ret.name) + + @mock.patch.object(filecmp, 'cmp', return_value=True) + def test_rename_subcloud_inventory_file_failed(self, mock_filecmp): + new_subcloud_name = 'testsubcloud' + self.mock_os_path_exists.return_value = False + self.mock_os_listdir.return_value = ['testfile1', 'testfile2'] + alarms = test_subcloud_alarms.DBAPISubcloudAlarm + alarms.create_subcloud_alarms(self.ctx, self.subcloud.name) + db_api.subcloud_update( + self.ctx, self.subcloud.id, self.subcloud.name + ) + self.sm.rename_subcloud( + self.ctx, self.subcloud.id, self.subcloud.name, new_subcloud_name + ) + ret = db_api.subcloud_get_by_name(self.ctx, new_subcloud_name) + self.mock_log.warn.assert_called_once_with( + 'Could not rename inventory file /opt/dc-vault/ansible/' + 'testsubcloud_inventory.yml because it does not exist.' + ) + self.assertEqual(new_subcloud_name, ret.name) + self.assertEqual(self.mock_os_listdir.call_count, 2)