Merge "Create host state for determining initial inventory complete"
This commit is contained in:
commit
1dc0d8623c
|
@ -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
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
SRC_DIR="cgts-client"
|
||||
TIS_PATCH_VER=68
|
||||
TIS_PATCH_VER=69
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
SRC_DIR="sysinv"
|
||||
TIS_PATCH_VER=329
|
||||
TIS_PATCH_VER=330
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
@ -2915,6 +2919,7 @@ class HostController(rest.RestController):
|
|||
'invprovision', 'recordtype',
|
||||
'ihost_action',
|
||||
'action_state',
|
||||
'inv_state',
|
||||
'iconfig_applied',
|
||||
'iconfig_target']
|
||||
|
||||
|
@ -4951,6 +4956,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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -4372,6 +4372,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.
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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.')
|
|
@ -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))
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue