Create host state for determining initial inventory complete

Add host inv_state attribute to allow determination of when the
initial inventory collection has been completed.

Update references which were using disks/pvs as proxy for inventory
completion to reference the host inv_state attribute.

Description of issue (from Bug 1837097):
The system inventory agent needs to explicitly indicate that inventory
collection has finished for each host.  The current method for
determining whether a host has been inventoried successfully is to
wait for the disk/pv list to be non-empty.

That worked well until recently when the host file system feature
was merged.  The system inventory agent now collects/creates host file
systems after the disk list is populated so a provisioning system
waiting on the disk list will move ahead to unlock the node
prematurely before the host file systems have been created and reported
to system inventory.  This can lead to undefined behavior either on
the system being provisioned or the provisioning system that is
configuring the target system.

If we do not fix this properly with an explicit/deterministic flag then
we will trip over this issue each time someone adds a new inventory
collection step to the end of the system inventory agent's
initial process loop.

Change-Id: Ifdb8871a892414ee4c433cf7a6ec7e79390c6420
Closes-bug: 1837097
Signed-off-by: John Kung <john.kung@windriver.com>
This commit is contained in:
John Kung 2019-07-25 10:38:55 -04:00
parent d4549cf4b0
commit 168442b2e1
15 changed files with 227 additions and 59 deletions

View File

@ -56,7 +56,7 @@ DEFAULT_VIRTUAL_BACKUP_STOR_SIZE = \
DEFAULT_EXTENSION_STOR_SIZE = \
sysinv_constants.DEFAULT_EXTENSION_STOR_SIZE
SYSTEM_CONFIG_TIMEOUT = 300
SYSTEM_CONFIG_TIMEOUT = 420
SERVICE_ENABLE_TIMEOUT = 180
MINIMUM_ROOT_DISK_SIZE = 500
MAXIMUM_CGCS_LV_SIZE = 500

View File

@ -1,2 +1,2 @@
SRC_DIR="cgts-client"
TIS_PATCH_VER=68
TIS_PATCH_VER=69

View File

@ -35,7 +35,7 @@ def _print_ihost_show(ihost):
'location', 'uptime', 'reserved', 'created_at', 'updated_at',
'boot_device', 'rootfs_device', 'install_output', 'console',
'tboot', 'vim_progress_status', 'software_load', 'install_state',
'install_state_info']
'install_state_info', 'inv_state']
optional_fields = ['vsc_controllers', 'ttys_dcd']
if ihost.subfunctions != ihost.personality:
fields.append('subfunctions')

View File

@ -1,2 +1,2 @@
SRC_DIR="sysinv"
TIS_PATCH_VER=329
TIS_PATCH_VER=330

View File

@ -130,11 +130,34 @@ class AgentManager(service.PeriodicService):
RPC_API_VERSION = '1.0'
NUMA = 'numa'
CPU = 'cpu'
PORT = 'port'
PCI_DEVICE = 'pci_device'
MEMORY = 'memory'
DISK = 'disk'
PV = 'pv'
LVG = 'lvg'
HOST_FILESYSTEMS = 'host_filesystems'
# Note that this set must be extended when there are
# additional inventory required for the initial
# inventory complete (to be notified to conductor).
INVENTORY_REPORTS_REQUIRED = {
NUMA,
PORT,
PCI_DEVICE,
CPU,
MEMORY,
DISK,
PV,
LVG,
HOST_FILESYSTEMS}
def __init__(self, host, topic):
serializer = objects_base.SysinvObjectSerializer()
super(AgentManager, self).__init__(host, topic, serializer=serializer)
self._report_to_conductor = False
self._report_to_conductor_iplatform_avail_flag = False
self._ipci_operator = pci.PCIOperator()
self._inode_operator = node.NodeOperator()
@ -161,6 +184,8 @@ class AgentManager(service.PeriodicService):
self._tpmconfig_rpc_failure = False
self._tpmconfig_host_first_apply = False
self._first_grub_update = False
self._inventoried_initial = False
self._inventory_reported = set()
def start(self):
super(AgentManager, self).start()
@ -176,6 +201,22 @@ class AgentManager(service.PeriodicService):
if tsc.system_mode == constants.SYSTEM_MODE_SIMPLEX:
utils.touch(SYSINV_READY_FLAG)
def _report_to_conductor(self):
""" Initial inventory report to conductor required
returns: True if initial inventory report_to_conductor is required
"""
initial_reports_required = \
self.INVENTORY_REPORTS_REQUIRED - self._inventory_reported
initial_reports_required.discard(self.HOST_FILESYSTEMS)
if initial_reports_required:
LOG.info("_report_to_conductor initial_reports_required=%s" %
initial_reports_required)
return True
else:
return False
def _report_to_conductor_iplatform_avail(self):
# First report sent to conductor since boot
utils.touch(SYSINV_FIRST_REPORT_FLAG)
@ -679,18 +720,16 @@ class AgentManager(service.PeriodicService):
rpcapi.iport_update_by_ihost(context,
host_uuid,
port_list)
self._inventory_reported.add(self.PORT)
except RemoteError as e:
LOG.error("iport_update_by_ihost RemoteError exc_type=%s" %
e.exc_type)
self._report_to_conductor = False
except exception.SysinvException:
LOG.exception("Sysinv Agent exception updating port.")
pass
try:
rpcapi.pci_device_update_by_host(context,
host_uuid,
pci_device_list)
self._inventory_reported.add(self.PCI_DEVICE)
except exception.SysinvException:
LOG.exception("Sysinv Agent exception updating pci_device.")
pass
@ -743,7 +782,6 @@ class AgentManager(service.PeriodicService):
ipersonality = ihost.get('personality') or ""
if ihost and ipersonality:
self._report_to_conductor = True
self._ihost_uuid = ihost['uuid']
self._ihost_personality = ihost['personality']
self._mgmt_ip = ihost['mgmt_ip']
@ -773,7 +811,7 @@ class AgentManager(service.PeriodicService):
time.sleep(30)
slept += 30
if not self._report_to_conductor:
if not self._report_to_conductor():
# let the audit take care of it instead
LOG.info("Sysinv no matching ihost found... await Audit")
return
@ -807,18 +845,10 @@ class AgentManager(service.PeriodicService):
rpcapi.inumas_update_by_ihost(icontext,
ihost['uuid'],
inumas)
self._inventory_reported.add(self.NUMA)
except RemoteError as e:
LOG.error("inumas_update_by_ihost RemoteError exc_type=%s" %
e.exc_type)
if e.exc_type == 'TimeoutError':
self._report_to_conductor = False
except Exception as e:
LOG.exception("Sysinv Agent exception updating inuma e=%s." % e)
self._report_to_conductor = True
pass
except exception.SysinvException:
LOG.exception("Sysinv Agent uncaught exception updating inuma.")
pass
force_grub_update = self._force_grub_update()
try:
@ -827,18 +857,10 @@ class AgentManager(service.PeriodicService):
ihost['uuid'],
icpus,
force_grub_update)
self._inventory_reported.add(self.CPU)
except RemoteError as e:
LOG.error("icpus_update_by_ihost RemoteError exc_type=%s" %
e.exc_type)
if e.exc_type == 'TimeoutError':
self._report_to_conductor = False
except Exception as e:
LOG.exception("Sysinv Agent exception updating icpus e=%s." % e)
self._report_to_conductor = True
pass
except exception.SysinvException:
LOG.exception("Sysinv Agent uncaught exception updating icpus conductor.")
pass
imemory = self._inode_operator.inodes_get_imemory()
if imemory:
@ -847,6 +869,7 @@ class AgentManager(service.PeriodicService):
rpcapi.imemory_update_by_ihost(icontext,
ihost['uuid'],
imemory)
self._inventory_reported.add(self.MEMORY)
except RemoteError as e:
LOG.error("imemory_update_by_ihost RemoteError exc_type=%s" %
e.exc_type)
@ -862,6 +885,7 @@ class AgentManager(service.PeriodicService):
rpcapi.idisk_update_by_ihost(icontext,
ihost['uuid'],
idisk)
self._inventory_reported.add(self.DISK)
except RemoteError as e:
# TODO (oponcea): Valid for R4->R5, remove in R6.
# safe to ignore during upgrades
@ -882,6 +906,7 @@ class AgentManager(service.PeriodicService):
rpcapi.ipv_update_by_ihost(icontext,
ihost['uuid'],
ipv)
self._inventory_reported.add(self.PV)
except exception.SysinvException:
LOG.exception("Sysinv Agent exception updating ipv conductor.")
pass
@ -891,6 +916,7 @@ class AgentManager(service.PeriodicService):
rpcapi.ilvg_update_by_ihost(icontext,
ihost['uuid'],
ilvg)
self._inventory_reported.add(self.LVG)
except exception.SysinvException:
LOG.exception("Sysinv Agent exception updating ilvg conductor.")
pass
@ -959,6 +985,36 @@ class AgentManager(service.PeriodicService):
self._subfunctions_configured = True
return True
def notify_initial_inventory_completed(self, context):
"""Report the inventory completion event for this host to the
conductor when the conditions for inventory complete have
been met.
:param context: an admin context
"""
def _conditions_for_inventory_complete_met():
# NOTE: condition(s) for inventory complete must be
# reviewed for update when additional inventory is posted.
reports_required = \
self.INVENTORY_REPORTS_REQUIRED - self._inventory_reported
if not reports_required:
return True
else:
LOG.info("_conditions_for_inventory_complete_met requires %s" %
reports_required)
return False
if (_conditions_for_inventory_complete_met() and not
self._inventoried_initial):
LOG.info("Initial inventory completed host %s" %
self._ihost_uuid)
rpcapi = conductor_rpcapi.ConductorAPI(
topic=conductor_rpcapi.MANAGER_TOPIC)
rpcapi.initial_inventory_completed(context,
self._ihost_uuid)
self._inventoried_initial = True
def _report_config_applied(self, context):
"""Report the latest configuration applied for this host to the
conductor.
@ -1081,7 +1137,7 @@ class AgentManager(service.PeriodicService):
if os.path.isfile(tsc.INITIAL_CONFIG_COMPLETE_FLAG):
self._report_config_applied(icontext)
if self._report_to_conductor is False:
if self._report_to_conductor():
LOG.info("Sysinv Agent audit running inv_get_and_report.")
self.ihost_inv_get_and_report(icontext)
@ -1110,6 +1166,7 @@ class AgentManager(service.PeriodicService):
rpcapi.idisk_update_by_ihost(icontext,
self._ihost_uuid,
idisk)
self._inventory_reported.add(self.DISK)
except RemoteError as e:
# TODO (oponcea): Valid for R4->R5, remove in R6.
# safe to ignore during upgrades
@ -1168,6 +1225,7 @@ class AgentManager(service.PeriodicService):
rpcapi.imemory_update_by_ihost(icontext,
self._ihost_uuid,
imemory)
self._inventory_reported.add(self.MEMORY)
if self._agent_throttle > 5:
# throttle updates
self._agent_throttle = 0
@ -1207,6 +1265,7 @@ class AgentManager(service.PeriodicService):
rpcapi.idisk_update_by_ihost(icontext,
self._ihost_uuid,
idisk)
self._inventory_reported.add(self.DISK)
except RemoteError as e:
# TODO (oponcea): Valid for R4->R5, remove in R6.
# safe to ignore during upgrades
@ -1234,6 +1293,7 @@ class AgentManager(service.PeriodicService):
rpcapi.ipv_update_by_ihost(icontext,
self._ihost_uuid,
ipv)
self._inventory_reported.add(self.PV)
except exception.SysinvException:
LOG.exception("Sysinv Agent exception updating ipv"
"conductor.")
@ -1249,6 +1309,7 @@ class AgentManager(service.PeriodicService):
rpcapi.ilvg_update_by_ihost(icontext,
self._ihost_uuid,
ilvg)
self._inventory_reported.add(self.LVG)
except exception.SysinvException:
LOG.exception("Sysinv Agent exception updating ilvg"
"conductor.")
@ -1319,12 +1380,18 @@ class AgentManager(service.PeriodicService):
filesystems)
self._prev_fs = filesystems
self._inventory_reported.add(self.HOST_FILESYSTEMS)
except Exception as e:
LOG.exception(
"Sysinv Agent exception creating the host filesystems."
" %s" % e)
self._prev_fs = None
# Notify conductor of inventory completion after necessary
# inventory reports have been sent to conductor.
# This is as defined by _conditions_for_inventory_complete_met().
self.notify_initial_inventory_completed(icontext)
self._report_config_applied(icontext)
if os.path.isfile(tsc.PLATFORM_CONF_FILE):
@ -1931,3 +1998,4 @@ class AgentManager(service.PeriodicService):
self._ihost_uuid,
memory,
force_update=True)
self._inventory_reported.add(self.MEMORY)

View File

@ -399,6 +399,9 @@ class Host(base.APIBase):
ihost_action = wtypes.text
'Represent the current action task in progress'
inv_state = wtypes.text
'Represent the inventory state'
vim_progress_status = wtypes.text
'Represent the vim progress status'
@ -559,7 +562,8 @@ class Host(base.APIBase):
'tboot', 'vsc_controllers', 'ttys_dcd',
'software_load', 'target_load', 'peers', 'peer_id',
'install_state', 'install_state_info',
'iscsi_initiator_name']
'iscsi_initiator_name',
'inv_state']
fields = minimum_fields if not expand else None
uhost = Host.from_rpc_object(rpc_ihost, fields)
@ -2906,6 +2910,7 @@ class HostController(rest.RestController):
'invprovision', 'recordtype',
'ihost_action',
'action_state',
'inv_state',
'iconfig_applied',
'iconfig_target']
@ -4898,6 +4903,17 @@ class HostController(rest.RestController):
LOG.warn("Allowing force-unlock of host %s "
"undergoing reinstall." % hostupdate.displayid)
if not force_unlock:
# Ensure inventory has completed prior to allowing unlock
host = pecan.request.dbapi.ihost_get(
hostupdate.ihost_orig['uuid'])
if host.inv_state != constants.INV_STATE_INITIAL_INVENTORIED:
raise wsme.exc.ClientSideError(
_("Can not unlock host %s that has not yet been "
"inventoried. Please wait for host to complete "
"initial inventory prior to unlock."
% hostupdate.displayid))
personality = hostupdate.ihost_patch.get('personality')
if personality == constants.CONTROLLER:
self.check_unlock_controller(hostupdate, force_unlock)

View File

@ -192,6 +192,8 @@ HOST_ACTION_STATE = "action_state"
HAS_REINSTALLING = "reinstalling"
HAS_REINSTALLED = "reinstalled"
INV_STATE_INITIAL_INVENTORIED = "inventoried"
# Board Management Region Info
REGION_PRIMARY = "Internal"
REGION_SECONDARY = "External"

View File

@ -2024,15 +2024,11 @@ def is_default_huge_pages_required(host):
def is_inventory_config_complete(dbapi, forihostid):
"""Check if the initial inventory has completed
Due to lack of host state that signifies the completion of inventory, this
function retrieves the list of persistent volumes from the database. If
the count is not zero; ports, disks and PVs have been inventoried.
"""
try:
pvs = dbapi.ipv_get_by_ihost(forihostid)
return len(pvs) > 0
host = dbapi.ihost_get(forihostid)
return host.inv_state == constants.INV_STATE_INITIAL_INVENTORIED
except Exception:
return False

View File

@ -4366,6 +4366,16 @@ class ConductorManager(service.PeriodicService):
config_uuid = imsg_dict['config_applied']
self._update_host_config_applied(context, ihost, config_uuid)
def initial_inventory_completed(self, context, host_uuid):
host_uuid.strip()
try:
self.dbapi.ihost_update(
host_uuid,
{'inv_state': constants.INV_STATE_INITIAL_INVENTORIED})
except exception.ServerNotFound:
LOG.error("initial_inventory_completed invalid host_uuid %s" %
host_uuid)
def subfunctions_update_by_ihost(self, context,
ihost_uuid, subfunctions):
"""Update subfunctions for a host.

View File

@ -1029,6 +1029,18 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy):
ihost_uuid=ihost_uuid,
imsg_dict=imsg_dict))
def initial_inventory_completed(self, context, host_uuid):
"""Notify of initial inventory completion for a host.
:param context: an admin context
:param host_uuid: host unique id
"""
return self.call(context,
self.make_msg('initial_inventory_completed',
host_uuid=host_uuid,
))
def iinterface_get_providernets(self,
context,
pn_names=None):

View File

@ -0,0 +1,38 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (c) 2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from sqlalchemy import Column, MetaData, Table
from sqlalchemy import String, Integer
ENGINE = 'InnoDB'
CHARSET = 'utf8'
def upgrade(migrate_engine):
"""
This database upgrade creates a new host inv_state attribute for
storing the inventory state for a host.
"""
meta = MetaData()
meta.bind = migrate_engine
host = Table('i_host',
meta,
Column('id', Integer, primary_key=True, nullable=False),
mysql_engine=ENGINE, mysql_charset=CHARSET, autoload=True)
# Add the inventory state attribute
host.create_column(Column('inv_state', String(255)))
def downgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
# Downgrade is unsupported in this release.
raise NotImplementedError('SysInv database downgrade is unsupported.')

View File

@ -211,6 +211,7 @@ class ihost(Base):
action = Column(actionEnum, default="none")
ihost_action = Column(String(255))
action_state = Column(String(255))
inv_state = Column(String(255))
mtce_info = Column(String(255))
install_state = Column(String(255))
install_state_info = Column(String(255))

View File

@ -65,6 +65,7 @@ class Host(base.SysinvObject):
'availability': utils.str_or_none,
'ihost_action': utils.str_or_none,
'action_state': utils.str_or_none,
'inv_state': utils.str_or_none,
'mtce_info': utils.str_or_none,
'vim_progress_status': utils.str_or_none,
'action': utils.str_or_none,

View File

@ -13,6 +13,7 @@ Tests for the API /ihosts/ methods.
import mock
import webtest.app
from six.moves import http_client
from sysinv.common import constants
from sysinv.openstack.common import uuidutils
@ -622,12 +623,14 @@ class TestListHosts(TestHost):
class TestPatch(TestHost):
def _patch_host_action(self, hostname, action, user_agent):
def _patch_host_action(
self, hostname, action, user_agent, expect_errors=False):
return self.patch_json('/ihosts/%s' % hostname,
[{'path': '/action',
'value': action,
'op': 'replace'}],
headers={'User-Agent': user_agent})
headers={'User-Agent': user_agent},
expect_errors=expect_errors)
def test_update_optimizable(self):
# Create controller-0
@ -645,7 +648,7 @@ class TestPatch(TestHost):
'op': 'replace'}],
headers={'User-Agent': 'sysinv-test'})
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the host was updated with the specified location
result = self.get_json('/ihosts/%s' % ndict['hostname'])
@ -666,7 +669,7 @@ class TestPatch(TestHost):
constants.UNLOCK_ACTION,
'sysinv-test')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the unlock was sent to the VIM
self.mock_vim_api_host_action.assert_called_with(
@ -698,7 +701,7 @@ class TestPatch(TestHost):
constants.FORCE_UNLOCK_ACTION,
'sysinv-test')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the unlock was sent to the VIM
self.mock_vim_api_host_action.assert_called_with(
@ -715,6 +718,26 @@ class TestPatch(TestHost):
result = self.get_json('/ihosts/%s' % c0_host['hostname'])
self.assertEqual(constants.NONE_ACTION, result['action'])
def test_unlock_action_controller_inventory_not_complete(self):
self._configure_networks()
# Create controller-0 without inv_state initial inventory complete
c0_host = self._create_controller_0(
subfunctions=constants.CONTROLLER,
invprovision=constants.PROVISIONED,
administrative=constants.ADMIN_LOCKED,
operational=constants.OPERATIONAL_ENABLED,
availability=constants.AVAILABILITY_ONLINE,
inv_state=None)
# Unlock host
response = self._patch_host_action(c0_host['hostname'],
constants.UNLOCK_ACTION,
'sysinv-test',
expect_errors=True)
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(http_client.BAD_REQUEST, response.status_int)
self.assertTrue(response.json['error_message'])
def test_lock_action_controller(self):
self._configure_networks()
# Create controller-0
@ -739,7 +762,7 @@ class TestPatch(TestHost):
constants.LOCK_ACTION,
'sysinv-test')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the SM lock pre check was done
self.mock_sm_api_lock_pre_check.assert_called_with(c1_host['hostname'],
@ -782,7 +805,7 @@ class TestPatch(TestHost):
constants.FORCE_LOCK_ACTION,
'sysinv-test')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the SM lock pre check was not done
self.mock_sm_api_lock_pre_check.assert_not_called()
@ -832,7 +855,7 @@ class TestPatch(TestHost):
constants.UNLOCK_ACTION,
'sysinv-test')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the unlock was sent to the VIM
self.mock_vim_api_host_action.assert_called_with(
@ -880,7 +903,7 @@ class TestPatch(TestHost):
constants.LOCK_ACTION,
'sysinv-test')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the SM lock pre check was not done
self.mock_sm_api_lock_pre_check.assert_not_called()
@ -932,7 +955,7 @@ class TestPatch(TestHost):
constants.SWACT_ACTION,
'sysinv-test')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the SM swact pre check was done
self.mock_sm_api_swact_pre_check.assert_called_with(c1_host['hostname'],
@ -970,7 +993,7 @@ class TestPatch(TestHost):
constants.FORCE_SWACT_ACTION,
'sysinv-test')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the SM swact pre check was not done
self.mock_sm_api_swact_pre_check.assert_not_called()
@ -1007,7 +1030,7 @@ class TestPatch(TestHost):
constants.RESET_ACTION,
'sysinv-test')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the reset was not sent to the VIM
self.mock_vim_api_host_action.assert_not_called()
@ -1042,7 +1065,7 @@ class TestPatch(TestHost):
constants.REBOOT_ACTION,
'sysinv-test')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the reboot was not sent to the VIM
self.mock_vim_api_host_action.assert_not_called()
@ -1077,7 +1100,7 @@ class TestPatch(TestHost):
constants.REINSTALL_ACTION,
'sysinv-test')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the host config was removed
self.fake_conductor_api.remove_host_config.assert_called_with(
@ -1115,7 +1138,7 @@ class TestPatch(TestHost):
constants.POWERON_ACTION,
'sysinv-test')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the poweron was not sent to the VIM
self.mock_vim_api_host_action.assert_not_called()
@ -1150,7 +1173,7 @@ class TestPatch(TestHost):
constants.POWEROFF_ACTION,
'sysinv-test')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the poweroff was not sent to the VIM
self.mock_vim_api_host_action.assert_not_called()
@ -1186,7 +1209,7 @@ class TestPatch(TestHost):
constants.VIM_SERVICES_ENABLED,
'vim')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the services enabled was not sent to the VIM
self.mock_vim_api_host_action.assert_not_called()
@ -1229,7 +1252,7 @@ class TestPatch(TestHost):
constants.VIM_SERVICES_DISABLED,
'vim')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the services disabled was not sent to the VIM
self.mock_vim_api_host_action.assert_not_called()
@ -1273,7 +1296,7 @@ class TestPatch(TestHost):
constants.VIM_SERVICES_DISABLE_FAILED,
'vim')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the services disable failed was not sent to the VIM
self.mock_vim_api_host_action.assert_not_called()
@ -1316,7 +1339,7 @@ class TestPatch(TestHost):
constants.VIM_SERVICES_DISABLE_EXTEND,
'vim')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the services disable extend was not sent to the VIM
self.mock_vim_api_host_action.assert_not_called()
@ -1358,7 +1381,7 @@ class TestPatch(TestHost):
constants.VIM_SERVICES_DELETE_FAILED,
'vim')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the services disable failed was not sent to the VIM
self.mock_vim_api_host_action.assert_not_called()
@ -1437,7 +1460,7 @@ class TestPatch(TestHost):
constants.SUBFUNCTION_CONFIG_ACTION,
'sysinv-test')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.status_code, http_client.OK)
# Verify that the configure was not sent to the VIM
self.mock_vim_api_host_action.assert_not_called()

View File

@ -160,6 +160,7 @@ def get_test_ihost(**kw):
'install_state': kw.get('install_state', None),
'install_state_info': kw.get('install_state_info', None),
'iscsi_initiator_name': kw.get('iscsi_initiator_name', None),
'inv_state': kw.get('inv_state', 'inventoried'),
}
return inv