Merge "Add inactive param for import-load on conductor"
This commit is contained in:
commit
90a1dcb91f
|
@ -843,6 +843,7 @@ ACTION_UPDATE_JOURNAL = "update"
|
|||
MNT_DIR = '/tmp/mnt'
|
||||
|
||||
ACTIVE_LOAD_STATE = 'active'
|
||||
INACTIVE_LOAD_STATE = 'inactive'
|
||||
IMPORTING_LOAD_STATE = 'importing'
|
||||
IMPORTED_LOAD_STATE = 'imported'
|
||||
IMPORTED_METADATA_LOAD_STATE = 'imported-metadata'
|
||||
|
@ -860,6 +861,10 @@ LOAD_SIGNATURE = 'path_to_sig'
|
|||
IMPORT_LOAD_FILES = [LOAD_ISO, LOAD_SIGNATURE]
|
||||
LOAD_FILES_STAGING_DIR = '/scratch/tmp_load'
|
||||
STAGING_LOAD_FILES_REMOVAL_WAIT_TIME = 30
|
||||
CURRENT_METADATA_FILE_PATH = '/usr/rootdirs/opt/upgrades/metadata.xml'
|
||||
|
||||
ACTIVE_LOAD_IMPORT = 'active'
|
||||
INACTIVE_LOAD_IMPORT = 'inactive'
|
||||
|
||||
# Ceph
|
||||
CEPH_HEALTH_OK = 'HEALTH_OK'
|
||||
|
|
|
@ -1299,6 +1299,7 @@ def validate_load_for_delete(load):
|
|||
valid_delete_states = [
|
||||
constants.IMPORTED_LOAD_STATE,
|
||||
constants.IMPORTED_METADATA_LOAD_STATE,
|
||||
constants.INACTIVE_LOAD_STATE,
|
||||
constants.ERROR_LOAD_STATE,
|
||||
constants.DELETING_LOAD_STATE
|
||||
]
|
||||
|
|
|
@ -51,6 +51,7 @@ from contextlib import contextmanager
|
|||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
from distutils.util import strtobool
|
||||
from distutils.version import LooseVersion
|
||||
from copy import deepcopy
|
||||
|
||||
import tsconfig.tsconfig as tsc
|
||||
|
@ -11825,6 +11826,47 @@ class ConductorManager(service.PeriodicService):
|
|||
LOG.error("Host: %s not found in database" % ihost_id)
|
||||
return None
|
||||
|
||||
def _get_current_supported_upgrade_versions(self):
|
||||
supported_versions = []
|
||||
|
||||
try:
|
||||
metadata_file = open(constants.CURRENT_METADATA_FILE_PATH, 'r')
|
||||
root = ElementTree.fromstring(metadata_file.read())
|
||||
metadata_file.close()
|
||||
except Exception:
|
||||
raise exception.SysinvException(_(
|
||||
"Unable to read metadata file from current version"))
|
||||
|
||||
supported_upgrades_elm = root.find('supported_upgrades')
|
||||
|
||||
if not supported_upgrades_elm:
|
||||
raise exception.SysinvException(
|
||||
_("Invalid Metadata XML from current version"))
|
||||
|
||||
upgrade_paths = supported_upgrades_elm.findall('upgrade')
|
||||
|
||||
for upgrade_element in upgrade_paths:
|
||||
valid_from_version = upgrade_element.findtext('version')
|
||||
versions = valid_from_version.split(",")
|
||||
supported_versions.extend(versions)
|
||||
|
||||
return supported_versions
|
||||
|
||||
def _create_symlink_install_uuid(self, current_version):
|
||||
"""
|
||||
If the current version is Debian and the imported load
|
||||
is Centos, the install_uuid path is different. It's
|
||||
necessary to create a symlink for import.sh to find it.
|
||||
"""
|
||||
centos_feed_path = '/www/pages/feed/rel-%s' % current_version
|
||||
|
||||
os.makedirs(centos_feed_path, exist_ok=True)
|
||||
|
||||
src = '/var/www/pages/feed/rel-%s/install_uuid' % current_version
|
||||
dst = '%s/install_uuid' % centos_feed_path
|
||||
|
||||
os.symlink(src, dst)
|
||||
|
||||
def _import_load_error(self, new_load):
|
||||
"""
|
||||
Update the load state to 'error' in the database
|
||||
|
@ -11851,7 +11893,7 @@ class ConductorManager(service.PeriodicService):
|
|||
shutil.rmtree(mntdir)
|
||||
|
||||
def start_import_load(self, context, path_to_iso, path_to_sig,
|
||||
import_active=False):
|
||||
import_type=None):
|
||||
"""
|
||||
Mount the ISO and validate the load for import
|
||||
"""
|
||||
|
@ -11859,7 +11901,7 @@ class ConductorManager(service.PeriodicService):
|
|||
|
||||
active_load = cutils.get_active_load(loads)
|
||||
|
||||
if not import_active:
|
||||
if import_type != constants.ACTIVE_LOAD_IMPORT:
|
||||
cutils.validate_loads_for_import(loads)
|
||||
|
||||
current_version = active_load.software_version
|
||||
|
@ -11887,6 +11929,7 @@ class ConductorManager(service.PeriodicService):
|
|||
"Unable to mount iso"))
|
||||
|
||||
metadata_file_path = mntdir + '/upgrades/metadata.xml'
|
||||
|
||||
if not os.path.exists(metadata_file_path):
|
||||
self._unmount_iso(mounted_iso, mntdir)
|
||||
raise exception.SysinvException(_("Metadata file not found"))
|
||||
|
@ -11907,7 +11950,7 @@ class ConductorManager(service.PeriodicService):
|
|||
|
||||
new_version = root.findtext('version')
|
||||
|
||||
if import_active:
|
||||
if import_type == constants.ACTIVE_LOAD_IMPORT:
|
||||
if new_version != current_version:
|
||||
raise exception.SysinvException(
|
||||
_("Active version and import version must match (%s)")
|
||||
|
@ -11915,6 +11958,7 @@ class ConductorManager(service.PeriodicService):
|
|||
|
||||
# return the matching (active) load in the database
|
||||
loads = self.dbapi.load_get_list()
|
||||
|
||||
for load in loads:
|
||||
if load.software_version == new_version:
|
||||
break
|
||||
|
@ -11924,6 +11968,19 @@ class ConductorManager(service.PeriodicService):
|
|||
|
||||
return load
|
||||
|
||||
if import_type == constants.INACTIVE_LOAD_IMPORT:
|
||||
if LooseVersion(new_version) >= LooseVersion(current_version):
|
||||
raise exception.SysinvException(
|
||||
_("Inactive version must be less than the current version (%s)")
|
||||
% current_version)
|
||||
|
||||
supported_versions = self._get_current_supported_upgrade_versions()
|
||||
|
||||
if new_version not in supported_versions:
|
||||
raise exception.SysinvException(
|
||||
_("Inactive version must be upgradable to the current version (%s)")
|
||||
% current_version)
|
||||
|
||||
if new_version == current_version:
|
||||
raise exception.SysinvException(
|
||||
_("Active version and import version match (%s)")
|
||||
|
@ -11946,7 +12003,7 @@ class ConductorManager(service.PeriodicService):
|
|||
upgrade_path = upgrade_element
|
||||
break
|
||||
|
||||
if not path_found:
|
||||
if not path_found and import_type != constants.INACTIVE_LOAD_IMPORT:
|
||||
raise exception.SysinvException(
|
||||
_("No valid upgrade path found"))
|
||||
|
||||
|
@ -11958,9 +12015,12 @@ class ConductorManager(service.PeriodicService):
|
|||
patch['compatible_version'] = current_version
|
||||
|
||||
required_patches = []
|
||||
patch_elements = upgrade_path.findall('required_patch')
|
||||
for patch_element in patch_elements:
|
||||
required_patches.append(patch_element.text)
|
||||
|
||||
if upgrade_path:
|
||||
patch_elements = upgrade_path.findall('required_patch')
|
||||
for patch_element in patch_elements:
|
||||
required_patches.append(patch_element.text)
|
||||
|
||||
patch['required_patches'] = "\n".join(required_patches)
|
||||
|
||||
# create the new imported load in the database
|
||||
|
@ -11968,7 +12028,8 @@ class ConductorManager(service.PeriodicService):
|
|||
|
||||
return new_load
|
||||
|
||||
def import_load(self, context, path_to_iso, new_load):
|
||||
def import_load(self, context, path_to_iso, new_load,
|
||||
import_type=None):
|
||||
"""
|
||||
Run the import script and add the load to the database
|
||||
"""
|
||||
|
@ -11997,6 +12058,13 @@ class ConductorManager(service.PeriodicService):
|
|||
self._import_load_error(new_load)
|
||||
raise exception.SysinvException(_("Unable to mount iso"))
|
||||
|
||||
state = constants.IMPORTED_LOAD_STATE
|
||||
|
||||
if import_type == constants.INACTIVE_LOAD_IMPORT:
|
||||
active_load = cutils.get_active_load(loads)
|
||||
self._create_symlink_install_uuid(active_load.software_version)
|
||||
state = constants.INACTIVE_LOAD_STATE
|
||||
|
||||
# Run the upgrade script
|
||||
with open(os.devnull, "w") as fnull:
|
||||
try:
|
||||
|
@ -12014,8 +12082,7 @@ class ConductorManager(service.PeriodicService):
|
|||
|
||||
# Update the load status in the database
|
||||
try:
|
||||
self.dbapi.load_update(new_load['id'],
|
||||
{'state': constants.IMPORTED_LOAD_STATE})
|
||||
self.dbapi.load_update(new_load['id'], {'state': state})
|
||||
|
||||
except exception.SysinvException as e:
|
||||
LOG.exception(e)
|
||||
|
|
|
@ -1205,14 +1205,16 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy):
|
|||
ihost_uuid=ihost_uuid))
|
||||
|
||||
def start_import_load(self, context, path_to_iso, path_to_sig,
|
||||
import_active=False, timeout=180):
|
||||
import_type=None, timeout=180):
|
||||
"""Synchronously, mount the ISO and validate the load for import
|
||||
|
||||
:param context: request context.
|
||||
:param path_to_iso: the file path of the iso on this host
|
||||
:param path_to_sig: the file path of the iso's detached signature on
|
||||
this host
|
||||
:param import_active: boolean allow import of active load
|
||||
:param import_type: the type of the import, the possible values are
|
||||
constants.ACTIVE_LOAD_IMPORT for active load or
|
||||
constants.INACTIVE_LOAD_IMPORT for inactive load.
|
||||
:param timeout: rpc call timeout in seconds
|
||||
:returns: the newly create load object.
|
||||
"""
|
||||
|
@ -1220,21 +1222,24 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy):
|
|||
self.make_msg('start_import_load',
|
||||
path_to_iso=path_to_iso,
|
||||
path_to_sig=path_to_sig,
|
||||
import_active=import_active),
|
||||
import_type=import_type),
|
||||
timeout=timeout)
|
||||
|
||||
def import_load(self, context, path_to_iso, new_load):
|
||||
def import_load(self, context, path_to_iso, new_load,
|
||||
import_type=None):
|
||||
"""Asynchronously, import a load and add it to the database
|
||||
|
||||
:param context: request context.
|
||||
:param path_to_iso: the file path of the iso on this host
|
||||
:param new_load: the load object
|
||||
:param import_type: the type of the import (active or inactive)
|
||||
:returns: none.
|
||||
"""
|
||||
return self.cast(context,
|
||||
self.make_msg('import_load',
|
||||
path_to_iso=path_to_iso,
|
||||
new_load=new_load))
|
||||
new_load=new_load,
|
||||
import_type=import_type))
|
||||
|
||||
def delete_load(self, context, load_id):
|
||||
"""Asynchronously, cleanup a load from both controllers
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
It'S Ok
|
|
@ -0,0 +1 @@
|
|||
Simple Is Good
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<build>
|
||||
<version>0.1</version>
|
||||
<supported_upgrades>
|
||||
<upgrade>
|
||||
<version>0.0</version>
|
||||
<required_patch>PATCH_0001</required_patch>
|
||||
</upgrade>
|
||||
</supported_upgrades>
|
||||
</build>
|
|
@ -25,10 +25,13 @@
|
|||
import copy
|
||||
import mock
|
||||
import os.path
|
||||
import tempfile
|
||||
import uuid
|
||||
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from shutil import copy as shutil_copy
|
||||
from shutil import rmtree
|
||||
|
||||
from fm_api import constants as fm_constants
|
||||
from oslo_context import context
|
||||
|
@ -40,7 +43,9 @@ from sysinv.common import exception
|
|||
from sysinv.common import kubernetes
|
||||
from sysinv.common import utils as cutils
|
||||
from sysinv.conductor import manager
|
||||
from sysinv.db.sqlalchemy.api import Connection
|
||||
from sysinv.db import api as dbapi
|
||||
from sysinv.objects.load import Load
|
||||
|
||||
from sysinv.tests.db import base
|
||||
from sysinv.tests.db import utils
|
||||
|
@ -4229,8 +4234,318 @@ class ManagerTestCase(base.DbTestCase):
|
|||
self.assertEqual(endpoints, config_dict)
|
||||
|
||||
|
||||
class ManagerTestCaseInternal(base.BaseHostTestCase):
|
||||
@mock.patch('sysinv.conductor.manager.verify_files', lambda x, y: True)
|
||||
@mock.patch('sysinv.conductor.manager.cutils.ISO', mock.MagicMock())
|
||||
class ManagerStartLoadImportTest(base.BaseHostTestCase):
|
||||
def setUp(self):
|
||||
super(ManagerStartLoadImportTest, self).setUp()
|
||||
|
||||
# Set up objects for testing
|
||||
self.service = manager.ConductorManager('test-host', 'test-topic')
|
||||
self.service.dbapi = dbapi.get_instance()
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
self.tmp_dir = tempfile.mkdtemp(dir='/tmp')
|
||||
|
||||
patch_mkdtemp = mock.patch('tempfile.mkdtemp')
|
||||
mock_mkdtemp = patch_mkdtemp.start()
|
||||
mock_mkdtemp.return_value = self.tmp_dir
|
||||
self.addCleanup(patch_mkdtemp.stop)
|
||||
|
||||
self.upgrades_path = '%s/upgrades' % self.tmp_dir
|
||||
os.makedirs(self.upgrades_path, exist_ok=True)
|
||||
|
||||
self.metadata = os.path.join(
|
||||
os.path.dirname(__file__), "data", "metadata.xml"
|
||||
)
|
||||
shutil_copy(self.metadata, self.upgrades_path)
|
||||
|
||||
self.iso = os.path.join(
|
||||
os.path.dirname(__file__), "data", "bootimage.iso"
|
||||
)
|
||||
self.sig = os.path.join(
|
||||
os.path.dirname(__file__), "data", "bootimage.sig"
|
||||
)
|
||||
|
||||
def test_start_import_load(self):
|
||||
result = self.service.start_import_load(
|
||||
self.context,
|
||||
path_to_iso=self.iso,
|
||||
path_to_sig=self.sig,
|
||||
)
|
||||
|
||||
self.assertIsInstance(result, Load)
|
||||
self.assertEqual(result.state, constants.IMPORTING_LOAD_STATE)
|
||||
|
||||
@mock.patch('sysinv.conductor.manager.cutils.get_active_load')
|
||||
def test_start_import_load_same_version(self, mock_get_active_load):
|
||||
mock_get_active_load.return_value.software_version = '0.1'
|
||||
|
||||
self.assertRaises(
|
||||
exception.SysinvException,
|
||||
self.service.start_import_load,
|
||||
self.context,
|
||||
self.iso,
|
||||
self.sig,
|
||||
)
|
||||
|
||||
@mock.patch('sysinv.conductor.manager.cutils.get_active_load')
|
||||
def test_start_import_load_invalid_from_version(self, mock_get_active_load):
|
||||
mock_get_active_load.return_value.software_version = '0.2'
|
||||
|
||||
self.assertRaises(
|
||||
exception.SysinvException,
|
||||
self.service.start_import_load,
|
||||
self.context,
|
||||
self.iso,
|
||||
self.sig,
|
||||
)
|
||||
|
||||
@mock.patch.object(Connection, 'load_get_list')
|
||||
@mock.patch('sysinv.conductor.manager.cutils.get_active_load')
|
||||
def test_start_import_load_active(self, mock_get_active_load, mock_load_get_list):
|
||||
mock_get_active_load.return_value.software_version = '0.1'
|
||||
|
||||
load = utils.create_test_load(**{"software_version": "0.1"})
|
||||
mock_load_get_list.return_value = [load]
|
||||
|
||||
result = self.service.start_import_load(
|
||||
self.context,
|
||||
path_to_iso=self.iso,
|
||||
path_to_sig=self.sig,
|
||||
import_type=constants.ACTIVE_LOAD_IMPORT,
|
||||
)
|
||||
|
||||
self.assertIsInstance(result, Load)
|
||||
self.assertEqual(result.state, constants.ACTIVE_LOAD_STATE)
|
||||
|
||||
def test_start_import_load_active_invalid_version(self):
|
||||
self.assertRaises(
|
||||
exception.SysinvException,
|
||||
self.service.start_import_load,
|
||||
self.context,
|
||||
self.iso,
|
||||
self.sig,
|
||||
import_type=constants.ACTIVE_LOAD_IMPORT,
|
||||
)
|
||||
|
||||
@mock.patch.object(Connection, 'load_get_list')
|
||||
def test_start_import_load_active_load_not_found(self, mock_load_get_list):
|
||||
load = utils.create_test_load(**{"software_version": "0.1"})
|
||||
mock_load_get_list.side_effect = [[load], []]
|
||||
|
||||
self.assertRaises(
|
||||
exception.SysinvException,
|
||||
self.service.start_import_load,
|
||||
self.context,
|
||||
self.iso,
|
||||
self.sig,
|
||||
import_type=constants.ACTIVE_LOAD_IMPORT,
|
||||
)
|
||||
|
||||
@mock.patch('sysinv.conductor.manager.cutils.get_active_load')
|
||||
def test_start_import_load_inactive(self, mock_get_active_load):
|
||||
mock_get_active_load.return_value.software_version = '0.2'
|
||||
|
||||
metadata_orig = open(self.metadata, 'r').read()
|
||||
metadata_fake = b'''
|
||||
<build>\n<version>0.2</version>\n<supported_upgrades>
|
||||
\n<upgrade>\n<version>0.1</version>\n<required_patch>PATCH_0001
|
||||
</required_patch>\n</upgrade>\n</supported_upgrades>\n</build>
|
||||
'''
|
||||
|
||||
mock_files = [
|
||||
mock.mock_open(read_data=metadata_orig).return_value,
|
||||
mock.mock_open(read_data=metadata_fake).return_value,
|
||||
]
|
||||
mock_open = mock.mock_open()
|
||||
mock_open.side_effect = mock_files
|
||||
|
||||
with mock.patch('builtins.open', mock_open):
|
||||
result = self.service.start_import_load(
|
||||
self.context,
|
||||
path_to_iso=self.iso,
|
||||
path_to_sig=self.sig,
|
||||
import_type=constants.INACTIVE_LOAD_IMPORT,
|
||||
)
|
||||
|
||||
self.assertIsInstance(result, Load)
|
||||
self.assertEqual(result.state, constants.IMPORTING_LOAD_STATE)
|
||||
|
||||
@mock.patch('sysinv.conductor.manager.open')
|
||||
@mock.patch('sysinv.conductor.manager.cutils.get_active_load')
|
||||
def test_start_import_load_inactive_incompatible_version(self, mock_get_active_load, mock_open):
|
||||
mock_get_active_load.return_value.software_version = '0.3'
|
||||
|
||||
metadata_orig = open(self.metadata, 'r').read()
|
||||
metadata_fake = b'''
|
||||
<build>\n<version>0.3</version>\n<supported_upgrades>
|
||||
\n<upgrade>\n<version>0.2</version>\n<required_patch>PATCH_0001
|
||||
</required_patch>\n</upgrade>\n</supported_upgrades>\n</build>
|
||||
'''
|
||||
|
||||
mock_files = [
|
||||
mock.mock_open(read_data=metadata_orig).return_value,
|
||||
mock.mock_open(read_data=metadata_fake).return_value,
|
||||
]
|
||||
mock_open.side_effect = mock_files
|
||||
|
||||
self.assertRaises(
|
||||
exception.SysinvException,
|
||||
self.service.start_import_load,
|
||||
self.context,
|
||||
path_to_iso=self.iso,
|
||||
path_to_sig=self.sig,
|
||||
import_type=constants.INACTIVE_LOAD_IMPORT,
|
||||
)
|
||||
|
||||
def test_start_import_load_invalid_path(self):
|
||||
self.assertRaises(
|
||||
exception.SysinvException,
|
||||
self.service.start_import_load,
|
||||
self.context,
|
||||
'invalid/path/bootimage.iso',
|
||||
'invalid/path/bootimage.sig',
|
||||
)
|
||||
|
||||
def test_start_import_load_invalid_files(self):
|
||||
with mock.patch('sysinv.conductor.manager.verify_files', lambda x, y: False):
|
||||
self.assertRaises(
|
||||
exception.SysinvException,
|
||||
self.service.start_import_load,
|
||||
self.context,
|
||||
self.iso,
|
||||
self.sig,
|
||||
)
|
||||
|
||||
def test_start_import_load_without_metadata(self):
|
||||
rmtree(self.upgrades_path, ignore_errors=True)
|
||||
|
||||
self.assertRaises(
|
||||
exception.SysinvException,
|
||||
self.service.start_import_load,
|
||||
self.context,
|
||||
self.iso,
|
||||
self.sig,
|
||||
)
|
||||
|
||||
def test_start_import_load_invalid_metadata(self):
|
||||
iso = os.path.join(
|
||||
os.path.dirname(__file__), "data", "bootimage.iso"
|
||||
)
|
||||
shutil_copy(iso, self.upgrades_path)
|
||||
os.rename(
|
||||
'%s/bootimage.iso' % self.upgrades_path,
|
||||
'%s/metadata.xml' % self.upgrades_path,
|
||||
)
|
||||
|
||||
self.assertRaises(
|
||||
exception.SysinvException,
|
||||
self.service.start_import_load,
|
||||
self.context,
|
||||
self.iso,
|
||||
self.sig,
|
||||
)
|
||||
|
||||
|
||||
@mock.patch('sysinv.conductor.manager.subprocess', mock.MagicMock())
|
||||
@mock.patch('sysinv.conductor.manager.cutils.ISO', mock.MagicMock())
|
||||
class ManagerLoadImportTest(base.BaseHostTestCase):
|
||||
def setUp(self):
|
||||
super(ManagerLoadImportTest, self).setUp()
|
||||
|
||||
# Set up objects for testing
|
||||
self.service = manager.ConductorManager('test-host', 'test-topic')
|
||||
self.service.dbapi = dbapi.get_instance()
|
||||
self.context = context.get_admin_context()
|
||||
|
||||
self.iso = os.path.join(
|
||||
os.path.dirname(__file__), "data", "bootimage.iso"
|
||||
)
|
||||
|
||||
self.load = utils.create_test_load(
|
||||
**{"software_version": "0.1"}
|
||||
)
|
||||
|
||||
load_update = mock.patch.object(Connection, 'load_update')
|
||||
self.mock_load_update = load_update.start()
|
||||
self.mock_load_update.return_value = mock.MagicMock()
|
||||
self.addCleanup(load_update.stop)
|
||||
|
||||
def test_import_load(self):
|
||||
result = self.service.import_load(
|
||||
self.context,
|
||||
path_to_iso=self.iso,
|
||||
new_load=self.load,
|
||||
)
|
||||
|
||||
self.assertTrue(result)
|
||||
|
||||
self.mock_load_update.assert_called_once_with(
|
||||
mock.ANY,
|
||||
{'state': constants.IMPORTED_LOAD_STATE},
|
||||
)
|
||||
|
||||
@mock.patch('sysinv.conductor.manager.os.symlink', mock.Mock())
|
||||
@mock.patch('sysinv.conductor.manager.os.makedirs', mock.Mock())
|
||||
def test_import_load_inactive(self):
|
||||
result = self.service.import_load(
|
||||
self.context,
|
||||
path_to_iso=self.iso,
|
||||
new_load=self.load,
|
||||
import_type=constants.INACTIVE_LOAD_IMPORT,
|
||||
)
|
||||
|
||||
self.assertTrue(result)
|
||||
|
||||
self.mock_load_update.assert_called_once_with(
|
||||
mock.ANY,
|
||||
{'state': constants.INACTIVE_LOAD_STATE},
|
||||
)
|
||||
|
||||
def test_import_load_empty_new_load(self):
|
||||
self.assertRaises(
|
||||
exception.SysinvException,
|
||||
self.service.import_load,
|
||||
self.context,
|
||||
path_to_iso=self.iso,
|
||||
new_load=None,
|
||||
)
|
||||
|
||||
self.mock_load_update.assert_not_called()
|
||||
|
||||
def test_import_load_invalid_iso_path(self):
|
||||
self.assertRaises(
|
||||
exception.SysinvException,
|
||||
self.service.import_load,
|
||||
self.context,
|
||||
path_to_iso='invalid',
|
||||
new_load=self.load,
|
||||
)
|
||||
|
||||
self.mock_load_update.assert_called_once_with(
|
||||
mock.ANY,
|
||||
{'state': constants.ERROR_LOAD_STATE},
|
||||
)
|
||||
|
||||
def test_import_load_load_update_failed(self):
|
||||
self.mock_load_update.side_effect = exception.SysinvException()
|
||||
|
||||
self.assertRaises(
|
||||
exception.SysinvException,
|
||||
self.service.import_load,
|
||||
self.context,
|
||||
path_to_iso=self.iso,
|
||||
new_load=self.load,
|
||||
)
|
||||
|
||||
self.mock_load_update.assert_called_once_with(
|
||||
mock.ANY,
|
||||
{'state': constants.IMPORTED_LOAD_STATE},
|
||||
)
|
||||
|
||||
|
||||
class ManagerTestCaseInternal(base.BaseHostTestCase):
|
||||
def setUp(self):
|
||||
super(ManagerTestCaseInternal, self).setUp()
|
||||
|
||||
|
|
Loading…
Reference in New Issue