Merge "Add support for AIO-SX to DX migration on subcloud"
This commit is contained in:
commit
245440d262
|
@ -108,10 +108,6 @@ def do_modify(cc, args):
|
||||||
if isystem.system_type != constants.TS_AIO:
|
if isystem.system_type != constants.TS_AIO:
|
||||||
raise exc.CommandError("system_mode can only be modified on an "
|
raise exc.CommandError("system_mode can only be modified on an "
|
||||||
"AIO system")
|
"AIO system")
|
||||||
if isystem.system_mode == constants.SYSTEM_MODE_SIMPLEX:
|
|
||||||
raise exc.CommandError("system_mode can not be modified if it is "
|
|
||||||
"currently set to '%s'" %
|
|
||||||
constants.SYSTEM_MODE_SIMPLEX)
|
|
||||||
mode = args.system_mode
|
mode = args.system_mode
|
||||||
if isystem.system_mode == mode:
|
if isystem.system_mode == mode:
|
||||||
raise exc.CommandError("system_mode value already set to '%s'" %
|
raise exc.CommandError("system_mode value already set to '%s'" %
|
||||||
|
|
|
@ -3446,6 +3446,29 @@ class HostController(rest.RestController):
|
||||||
# Check for new hardware since upgrade-start
|
# Check for new hardware since upgrade-start
|
||||||
self._semantic_check_upgrade_refresh(upgrade, ihost, force_unlock)
|
self._semantic_check_upgrade_refresh(upgrade, ihost, force_unlock)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _semantic_check_duplex_oam_config(ihost):
|
||||||
|
system = pecan.request.dbapi.isystem_get_one()
|
||||||
|
if system.capabilities.get('simplex_to_duplex_migration'):
|
||||||
|
network = pecan.request.dbapi.network_get_by_type(constants.NETWORK_TYPE_OAM)
|
||||||
|
address_names = {'oam_c0_ip': '%s-%s' % (constants.CONTROLLER_0_HOSTNAME,
|
||||||
|
constants.NETWORK_TYPE_OAM),
|
||||||
|
'oam_c1_ip': '%s-%s' % (constants.CONTROLLER_1_HOSTNAME,
|
||||||
|
constants.NETWORK_TYPE_OAM)}
|
||||||
|
addresses = {a['name']: a for a in
|
||||||
|
pecan.request.dbapi.addresses_get_by_pool_uuid(network.pool_uuid)}
|
||||||
|
|
||||||
|
# check if controller-0-oam and controller-1-oam entries exist
|
||||||
|
for key, name in address_names.items():
|
||||||
|
if addresses.get(name) is None:
|
||||||
|
msg = _("Can not unlock controller on a duplex without "
|
||||||
|
"configuring %s." % key)
|
||||||
|
raise wsme.exc.ClientSideError(msg)
|
||||||
|
if addresses[name].address is None:
|
||||||
|
msg = _("Can not unlock controller on a duplex without "
|
||||||
|
"configuring a unit IP for %s." % key)
|
||||||
|
raise wsme.exc.ClientSideError(msg)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _semantic_check_oam_interface(ihost):
|
def _semantic_check_oam_interface(ihost):
|
||||||
"""
|
"""
|
||||||
|
@ -5532,6 +5555,8 @@ class HostController(rest.RestController):
|
||||||
# If HTTPS is enabled then we may be in TPM configuration mode
|
# If HTTPS is enabled then we may be in TPM configuration mode
|
||||||
if utils.get_https_enabled():
|
if utils.get_https_enabled():
|
||||||
self._semantic_check_tpm_config(hostupdate.ihost_orig)
|
self._semantic_check_tpm_config(hostupdate.ihost_orig)
|
||||||
|
if utils.get_system_mode() == constants.SYSTEM_MODE_DUPLEX:
|
||||||
|
self._semantic_check_duplex_oam_config(hostupdate.ihost_orig)
|
||||||
|
|
||||||
def check_unlock_worker(self, hostupdate, force_unlock=False):
|
def check_unlock_worker(self, hostupdate, force_unlock=False):
|
||||||
"""Check semantics on host-unlock of a worker."""
|
"""Check semantics on host-unlock of a worker."""
|
||||||
|
|
|
@ -466,6 +466,12 @@ class OAMNetworkController(rest.RestController):
|
||||||
|
|
||||||
rpc_extoam.save() # pylint: disable=no-value-for-parameter
|
rpc_extoam.save() # pylint: disable=no-value-for-parameter
|
||||||
|
|
||||||
|
# Update OAM networking configuration with the new unit IPs of each
|
||||||
|
# controller when transitioning to a duplex system
|
||||||
|
system = pecan.request.dbapi.isystem_get_one()
|
||||||
|
if system.capabilities.get('simplex_to_duplex_migration'):
|
||||||
|
rpc_extoam.migrate_to_duplex()
|
||||||
|
|
||||||
pecan.request.rpcapi.update_oam_config(pecan.request.context)
|
pecan.request.rpcapi.update_oam_config(pecan.request.context)
|
||||||
|
|
||||||
return OAMNetwork.convert_with_links(rpc_extoam)
|
return OAMNetwork.convert_with_links(rpc_extoam)
|
||||||
|
|
|
@ -275,6 +275,26 @@ class SystemController(rest.RestController):
|
||||||
raise wsme.exc.ClientSideError(
|
raise wsme.exc.ClientSideError(
|
||||||
_("Host {} must be locked.".format(h['hostname'])))
|
_("Host {} must be locked.".format(h['hostname'])))
|
||||||
|
|
||||||
|
def _check_mgmt(self, system_mode):
|
||||||
|
iinterfaces = pecan.request.dbapi.iinterface_get_all()
|
||||||
|
mgmt_if = None
|
||||||
|
for iif in iinterfaces:
|
||||||
|
if (iif.networktypelist and
|
||||||
|
constants.NETWORK_TYPE_MGMT in iif.networktypelist):
|
||||||
|
mgmt_if = iif
|
||||||
|
break
|
||||||
|
if mgmt_if is None:
|
||||||
|
msg = _("Cannot modify system mode to %s "
|
||||||
|
"without configuring the management "
|
||||||
|
"interface." % system_mode)
|
||||||
|
raise wsme.exc.ClientSideError(msg)
|
||||||
|
if mgmt_if.ifname == constants.LOOPBACK_IFNAME:
|
||||||
|
msg = _("Cannot modify system mode to %s "
|
||||||
|
"when the management interface is "
|
||||||
|
"configured on loopback. "
|
||||||
|
% system_mode)
|
||||||
|
raise wsme.exc.ClientSideError(msg)
|
||||||
|
|
||||||
def _get_isystem_collection(self, marker, limit, sort_key, sort_dir,
|
def _get_isystem_collection(self, marker, limit, sort_key, sort_dir,
|
||||||
expand=False, resource_url=None):
|
expand=False, resource_url=None):
|
||||||
limit = api_utils.validate_limit(limit)
|
limit = api_utils.validate_limit(limit)
|
||||||
|
@ -360,6 +380,7 @@ class SystemController(rest.RestController):
|
||||||
change_sdn = False
|
change_sdn = False
|
||||||
change_dc_role = False
|
change_dc_role = False
|
||||||
vswitch_type = None
|
vswitch_type = None
|
||||||
|
new_system_mode = None
|
||||||
|
|
||||||
# prevent description field from being updated
|
# prevent description field from being updated
|
||||||
for p in jsonpatch.JsonPatch(patch):
|
for p in jsonpatch.JsonPatch(patch):
|
||||||
|
@ -390,14 +411,12 @@ class SystemController(rest.RestController):
|
||||||
# be bound to the conditions below.
|
# be bound to the conditions below.
|
||||||
if cutils.is_initial_config_complete():
|
if cutils.is_initial_config_complete():
|
||||||
if rpc_isystem.system_mode == \
|
if rpc_isystem.system_mode == \
|
||||||
constants.SYSTEM_MODE_SIMPLEX:
|
constants.SYSTEM_MODE_DUPLEX:
|
||||||
msg = _("Cannot modify system mode when it is "
|
msg = _("Cannot modify system mode when it is "
|
||||||
"already set to %s." % rpc_isystem.system_mode)
|
"set to %s." % rpc_isystem.system_mode)
|
||||||
raise wsme.exc.ClientSideError(msg)
|
|
||||||
elif new_system_mode == constants.SYSTEM_MODE_SIMPLEX:
|
|
||||||
msg = _("Cannot modify system mode to simplex when "
|
|
||||||
"it is set to %s " % rpc_isystem.system_mode)
|
|
||||||
raise wsme.exc.ClientSideError(msg)
|
raise wsme.exc.ClientSideError(msg)
|
||||||
|
elif new_system_mode != constants.SYSTEM_MODE_SIMPLEX:
|
||||||
|
self._check_mgmt(new_system_mode)
|
||||||
else:
|
else:
|
||||||
system_mode_options.append(constants.SYSTEM_MODE_SIMPLEX)
|
system_mode_options.append(constants.SYSTEM_MODE_SIMPLEX)
|
||||||
|
|
||||||
|
@ -447,6 +466,14 @@ class SystemController(rest.RestController):
|
||||||
except api_utils.JSONPATCH_EXCEPTIONS as e:
|
except api_utils.JSONPATCH_EXCEPTIONS as e:
|
||||||
raise exception.PatchError(patch=patch, reason=e)
|
raise exception.PatchError(patch=patch, reason=e)
|
||||||
|
|
||||||
|
if 'system_mode' in updates:
|
||||||
|
# Update capabilities if system mode is changed from simplex to
|
||||||
|
# duplex after the initial config is complete
|
||||||
|
if (cutils.is_initial_config_complete() and
|
||||||
|
rpc_isystem.system_mode == constants.SYSTEM_MODE_SIMPLEX and
|
||||||
|
new_system_mode == constants.SYSTEM_MODE_DUPLEX):
|
||||||
|
patched_system['capabilities']['simplex_to_duplex_migration'] = True
|
||||||
|
|
||||||
if 'sdn_enabled' in updates:
|
if 'sdn_enabled' in updates:
|
||||||
if sdn_enabled != rpc_isystem['capabilities']['sdn_enabled']:
|
if sdn_enabled != rpc_isystem['capabilities']['sdn_enabled']:
|
||||||
self._check_hosts()
|
self._check_hosts()
|
||||||
|
|
|
@ -285,6 +285,8 @@ class ConductorManager(service.PeriodicService):
|
||||||
|
|
||||||
self._handle_restore_in_progress()
|
self._handle_restore_in_progress()
|
||||||
|
|
||||||
|
self._reset_simplex_to_duplex_flag(system)
|
||||||
|
|
||||||
LOG.info("sysinv-conductor start committed system=%s" %
|
LOG.info("sysinv-conductor start committed system=%s" %
|
||||||
system.as_dict())
|
system.as_dict())
|
||||||
|
|
||||||
|
@ -390,6 +392,21 @@ class ConductorManager(service.PeriodicService):
|
||||||
self._create_default_service_parameter()
|
self._create_default_service_parameter()
|
||||||
return system
|
return system
|
||||||
|
|
||||||
|
def _reset_simplex_to_duplex_flag(self, system):
|
||||||
|
|
||||||
|
# Skip if the flag is not set or if the system mode is not set to duplex
|
||||||
|
if (not system.capabilities.get('simplex_to_duplex_migration') or
|
||||||
|
system.system_mode != constants.SYSTEM_MODE_DUPLEX):
|
||||||
|
return
|
||||||
|
|
||||||
|
host = self.dbapi.ihost_get(self.host_uuid)
|
||||||
|
if host.administrative != constants.ADMIN_UNLOCKED:
|
||||||
|
return
|
||||||
|
|
||||||
|
system_dict = system.as_dict()
|
||||||
|
del system_dict['capabilities']['simplex_to_duplex_migration']
|
||||||
|
self.dbapi.isystem_update(system.uuid, system_dict)
|
||||||
|
|
||||||
def _upgrade_init_actions(self):
|
def _upgrade_init_actions(self):
|
||||||
""" Perform any upgrade related startup actions"""
|
""" Perform any upgrade related startup actions"""
|
||||||
try:
|
try:
|
||||||
|
@ -6357,6 +6374,18 @@ class ConductorManager(service.PeriodicService):
|
||||||
def update_system_mode_config(self, context):
|
def update_system_mode_config(self, context):
|
||||||
"""Update the system mode configuration"""
|
"""Update the system mode configuration"""
|
||||||
personalities = [constants.CONTROLLER]
|
personalities = [constants.CONTROLLER]
|
||||||
|
|
||||||
|
# Update manifest files if system mode is updated for simplex to
|
||||||
|
# duplex migration
|
||||||
|
system = self.dbapi.isystem_get_one()
|
||||||
|
if system.capabilities.get('simplex_to_duplex_migration'):
|
||||||
|
config_uuid = self._config_update_hosts(context, personalities)
|
||||||
|
|
||||||
|
# NOTE: no specific classes need to be specified since the default
|
||||||
|
# platform::config will be applied to configure the system mode
|
||||||
|
config_dict = {"personalities": personalities}
|
||||||
|
self._config_apply_runtime_manifest(context, config_uuid, config_dict)
|
||||||
|
|
||||||
self._config_update_hosts(context, personalities, reboot=True)
|
self._config_update_hosts(context, personalities, reboot=True)
|
||||||
|
|
||||||
def configure_system_timezone(self, context):
|
def configure_system_timezone(self, context):
|
||||||
|
|
|
@ -15,7 +15,6 @@ from sysinv.db import api as db_api
|
||||||
from sysinv.objects import base
|
from sysinv.objects import base
|
||||||
from sysinv.objects import utils
|
from sysinv.objects import utils
|
||||||
|
|
||||||
|
|
||||||
ADDRESS_FORMAT_ARGS = (constants.CONTROLLER_HOSTNAME,
|
ADDRESS_FORMAT_ARGS = (constants.CONTROLLER_HOSTNAME,
|
||||||
constants.NETWORK_TYPE_OAM)
|
constants.NETWORK_TYPE_OAM)
|
||||||
|
|
||||||
|
@ -124,6 +123,71 @@ class OAMNetwork(base.SysinvObject):
|
||||||
|
|
||||||
self.obj_reset_changes()
|
self.obj_reset_changes()
|
||||||
|
|
||||||
|
@base.remotable
|
||||||
|
def migrate_to_duplex(self, context):
|
||||||
|
"""Add controller unit IPs for OAM configuration when transitioning to
|
||||||
|
a duplex system.
|
||||||
|
|
||||||
|
:param context: Security context
|
||||||
|
"""
|
||||||
|
network = self.dbapi._network_get(self.uuid) # pylint: disable=no-member
|
||||||
|
address_pool = network.address_pool
|
||||||
|
addresses = OAMNetwork._get_pool_addresses(address_pool)
|
||||||
|
|
||||||
|
subnet = netaddr.IPNetwork(self['oam_subnet'])
|
||||||
|
|
||||||
|
# Add address entry
|
||||||
|
values = {
|
||||||
|
'address_pool_id': address_pool.id,
|
||||||
|
'family': subnet.version,
|
||||||
|
'prefix': subnet.prefixlen,
|
||||||
|
'enable_dad': False
|
||||||
|
}
|
||||||
|
address_pool_values = {}
|
||||||
|
|
||||||
|
if self['oam_c0_ip']:
|
||||||
|
if self.address_names['oam_c0_ip'] in addresses:
|
||||||
|
self.dbapi.address_update(addresses.get(self.address_names['oam_c0_ip']).uuid,
|
||||||
|
{'address': self['oam_c0_ip']})
|
||||||
|
else:
|
||||||
|
# Only update the floating address entry if the controller-0
|
||||||
|
# unit IP is being added for the first time
|
||||||
|
for name, address in addresses.items():
|
||||||
|
if (address.interface_id and
|
||||||
|
name == self.address_names['oam_floating_ip']):
|
||||||
|
|
||||||
|
# Clear the interface id for the floating oam address
|
||||||
|
self.dbapi.address_update(address.uuid, {'interface_id': None})
|
||||||
|
|
||||||
|
# Address values specific to controller-0
|
||||||
|
c0_values = {
|
||||||
|
'name': self.address_names['oam_c0_ip'],
|
||||||
|
'address': self['oam_c0_ip'],
|
||||||
|
'interface_id': address.interface_id
|
||||||
|
}
|
||||||
|
c0_values.update(values)
|
||||||
|
c0_address = self.dbapi.address_create(c0_values)
|
||||||
|
address_pool_values.update({'controller0_address_id': c0_address.id})
|
||||||
|
break
|
||||||
|
|
||||||
|
if self['oam_c1_ip']:
|
||||||
|
if self.address_names['oam_c1_ip'] in addresses:
|
||||||
|
self.dbapi.address_update(addresses.get(self.address_names['oam_c1_ip']).uuid,
|
||||||
|
{'address': self['oam_c1_ip']})
|
||||||
|
else:
|
||||||
|
# Address values specific to controller-1
|
||||||
|
c1_values = {
|
||||||
|
'name': self.address_names['oam_c1_ip'],
|
||||||
|
'address': self['oam_c1_ip'],
|
||||||
|
}
|
||||||
|
c1_values.update(values)
|
||||||
|
c1_address = self.dbapi.address_create(c1_values)
|
||||||
|
address_pool_values.update({'controller1_address_id': c1_address.id})
|
||||||
|
|
||||||
|
# Update address pool if new address entries for controllers were added
|
||||||
|
if address_pool_values:
|
||||||
|
self.dbapi.address_pool_update(address_pool.uuid, address_pool_values)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_pool_addresses(pool):
|
def _get_pool_addresses(pool):
|
||||||
"""Return a dictionary of addresses for the supplied pool keyed by name
|
"""Return a dictionary of addresses for the supplied pool keyed by name
|
||||||
|
|
|
@ -362,6 +362,31 @@ class TestPatchMixin(OAMNetworkTestCase):
|
||||||
self._test_patch_fail(patch_obj, http_client.BAD_REQUEST,
|
self._test_patch_fail(patch_obj, http_client.BAD_REQUEST,
|
||||||
error_message)
|
error_message)
|
||||||
|
|
||||||
|
def test_patch_oam_simplex_to_duplex(self):
|
||||||
|
system_dict = self.system.as_dict()
|
||||||
|
system_dict['capabilities'].update({'simplex_to_duplex_migration': True})
|
||||||
|
self.dbapi.isystem_update(self.system.uuid, system_dict)
|
||||||
|
|
||||||
|
oam_floating_ip = self.oam_subnet[2] + 100
|
||||||
|
oam_c0_ip = self.oam_subnet[3] + 100
|
||||||
|
oam_c1_ip = self.oam_subnet[4] + 100
|
||||||
|
patch_obj = {
|
||||||
|
'oam_floating_ip': str(oam_floating_ip),
|
||||||
|
'oam_c0_ip': str(oam_c0_ip),
|
||||||
|
'oam_c1_ip': str(oam_c1_ip),
|
||||||
|
}
|
||||||
|
addresses = {a['name']: a for a in
|
||||||
|
self.dbapi.addresses_get_all()}
|
||||||
|
|
||||||
|
self.assertIn('%s-%s' % (constants.CONTROLLER_0_HOSTNAME,
|
||||||
|
constants.NETWORK_TYPE_OAM),
|
||||||
|
addresses.keys())
|
||||||
|
self.assertIn('%s-%s' % (constants.CONTROLLER_1_HOSTNAME,
|
||||||
|
constants.NETWORK_TYPE_OAM),
|
||||||
|
addresses.keys())
|
||||||
|
|
||||||
|
self._test_patch_success(patch_obj)
|
||||||
|
|
||||||
|
|
||||||
class IPv4TestDelete(TestDeleteMixin,
|
class IPv4TestDelete(TestDeleteMixin,
|
||||||
OAMNetworkTestCase):
|
OAMNetworkTestCase):
|
||||||
|
|
|
@ -7,7 +7,10 @@
|
||||||
"""
|
"""
|
||||||
Tests for the API /isystems/ methods.
|
Tests for the API /isystems/ methods.
|
||||||
"""
|
"""
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from sysinv.common import constants
|
||||||
|
from sysinv.db import api as db_api
|
||||||
from sysinv.tests.api import base
|
from sysinv.tests.api import base
|
||||||
from sysinv.tests.db import utils as dbutils
|
from sysinv.tests.db import utils as dbutils
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
|
@ -78,3 +81,102 @@ class TestSystemUpdate(TestSystem):
|
||||||
update = {"longitude": None}
|
update = {"longitude": None}
|
||||||
self._patch_and_check(self._get_path(self.system.uuid),
|
self._patch_and_check(self._get_path(self.system.uuid),
|
||||||
update)
|
update)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSystemUpdateModeFromSimplex(TestSystem):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestSystemUpdateModeFromSimplex, self).setUp()
|
||||||
|
self.dbapi = db_api.get_instance()
|
||||||
|
self.system = dbutils.create_test_isystem(system_type=constants.TIS_AIO_BUILD,
|
||||||
|
system_mode=constants.SYSTEM_MODE_SIMPLEX)
|
||||||
|
|
||||||
|
def _create_mgmt_interface_network(self, interface='mgmt'):
|
||||||
|
self.controller = dbutils.create_test_ihost(
|
||||||
|
id='1',
|
||||||
|
uuid=None,
|
||||||
|
forisystemid=self.system.id,
|
||||||
|
hostname='controller-0',
|
||||||
|
personality=constants.CONTROLLER,
|
||||||
|
subfunctions=constants.CONTROLLER,
|
||||||
|
invprovision=constants.PROVISIONED,
|
||||||
|
)
|
||||||
|
self.address_pool_mgmt = dbutils.create_test_address_pool(
|
||||||
|
id=1,
|
||||||
|
network='192.168.204.0',
|
||||||
|
name='management',
|
||||||
|
ranges=[['192.168.204.2', '192.168.204.254']],
|
||||||
|
prefix=24)
|
||||||
|
self.mgmt_network = dbutils.create_test_network(
|
||||||
|
id=1,
|
||||||
|
name='mgmt',
|
||||||
|
type=constants.NETWORK_TYPE_MGMT,
|
||||||
|
link_capacity=1000,
|
||||||
|
vlan_id=2,
|
||||||
|
address_pool_id=self.address_pool_mgmt.id)
|
||||||
|
|
||||||
|
self.mgmt_interface = dbutils.create_test_interface(ifname=interface,
|
||||||
|
id=1,
|
||||||
|
ifclass=constants.INTERFACE_CLASS_PLATFORM,
|
||||||
|
forihostid=self.controller.id,
|
||||||
|
ihost_uuid=self.controller.uuid,
|
||||||
|
networktypelist=[constants.NETWORK_TYPE_MGMT])
|
||||||
|
|
||||||
|
dbutils.create_test_interface_network(
|
||||||
|
interface_id=self.mgmt_interface.id,
|
||||||
|
network_id=self.mgmt_network.id)
|
||||||
|
|
||||||
|
@mock.patch('sysinv.common.utils.is_initial_config_complete', return_value=True)
|
||||||
|
def test_update_system_mode_simplex_to_duplex_with_mgmt_if(self, mock_exists):
|
||||||
|
self._create_mgmt_interface_network()
|
||||||
|
update = {"system_mode": constants.SYSTEM_MODE_DUPLEX}
|
||||||
|
self._patch_and_check(self._get_path(self.system.uuid),
|
||||||
|
update)
|
||||||
|
system = self.dbapi.isystem_get_one()
|
||||||
|
system_dict = system.as_dict()
|
||||||
|
self.assertIn('simplex_to_duplex_migration', system_dict['capabilities'])
|
||||||
|
|
||||||
|
@mock.patch('sysinv.common.utils.is_initial_config_complete', return_value=True)
|
||||||
|
def test_update_system_mode_simplex_to_duplex_mgmt_on_lo(self, mock_exists):
|
||||||
|
self._create_mgmt_interface_network(interface=constants.LOOPBACK_IFNAME)
|
||||||
|
update = {"system_mode": constants.SYSTEM_MODE_DUPLEX}
|
||||||
|
self._patch_and_check(self._get_path(self.system.uuid),
|
||||||
|
update, expect_errors=True)
|
||||||
|
|
||||||
|
@mock.patch('sysinv.common.utils.is_initial_config_complete', return_value=True)
|
||||||
|
def test_update_system_mode_simplex_to_duplex_no_mgmt_if(self, mock_exists):
|
||||||
|
update = {"system_mode": constants.SYSTEM_MODE_DUPLEX}
|
||||||
|
self._patch_and_check(self._get_path(self.system.uuid),
|
||||||
|
update, expect_errors=True)
|
||||||
|
|
||||||
|
@mock.patch('sysinv.common.utils.is_initial_config_complete', return_value=True)
|
||||||
|
def test_update_system_mode_simplex_to_simplex(self, mock_exists):
|
||||||
|
update = {"system_mode": constants.SYSTEM_MODE_SIMPLEX}
|
||||||
|
self._patch_and_check(self._get_path(self.system.uuid),
|
||||||
|
update)
|
||||||
|
system = self.dbapi.isystem_get_one()
|
||||||
|
system_dict = system.as_dict()
|
||||||
|
self.assertNotIn('simplex_to_duplex_migration', system_dict['capabilities'])
|
||||||
|
|
||||||
|
@mock.patch('sysinv.common.utils.is_initial_config_complete', return_value=False)
|
||||||
|
def test_update_system_mode_before_initial_config_complete(self, mock_exists):
|
||||||
|
update = {"system_mode": constants.SYSTEM_MODE_DUPLEX}
|
||||||
|
self._patch_and_check(self._get_path(self.system.uuid),
|
||||||
|
update)
|
||||||
|
system = self.dbapi.isystem_get_one()
|
||||||
|
system_dict = system.as_dict()
|
||||||
|
self.assertNotIn('simplex_to_duplex_migration', system_dict['capabilities'])
|
||||||
|
|
||||||
|
|
||||||
|
class TestSystemUpdateModeFromDuplex(TestSystem):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestSystemUpdateModeFromDuplex, self).setUp()
|
||||||
|
self.system = dbutils.create_test_isystem(system_type=constants.TIS_AIO_BUILD,
|
||||||
|
system_mode=constants.SYSTEM_MODE_DUPLEX)
|
||||||
|
|
||||||
|
@mock.patch('sysinv.common.utils.is_initial_config_complete', return_value=True)
|
||||||
|
def test_update_system_mode_duplex_to_simplex(self, mock_exists):
|
||||||
|
update = {"system_mode": constants.SYSTEM_MODE_SIMPLEX}
|
||||||
|
self._patch_and_check(self._get_path(self.system.uuid),
|
||||||
|
update, expect_errors=True)
|
||||||
|
|
Loading…
Reference in New Issue