Add an iboot reboot_delay setting
This patch adds a new reboot_delay setting to the iboot power driver. This setting is important when using IPA which can cause a power manager REBOOT which if there is no sleep can occur so quickly the machine doesn't properly power cycle. The patch also updates the ironic.conf.sample file. Closes-bug: #1504258 Change-Id: I70ec7151d0154bd6f6445bcc0e90de2dc5b380e5
This commit is contained in:
parent
93f5a12a99
commit
735b58f2c3
@ -166,7 +166,11 @@
|
||||
# The name of a logging configuration file. This file is
|
||||
# appended to any existing logging configuration files. For
|
||||
# details about logging configuration files, see the Python
|
||||
# logging module documentation. (string value)
|
||||
# logging module documentation. Note that when logging
|
||||
# configuration files are used then all logging configuration
|
||||
# is set in the configuration file and other logging
|
||||
# configuration options are ignored (for example, log_format).
|
||||
# (string value)
|
||||
# Deprecated group/name - [DEFAULT]/log_config
|
||||
#log_config_append=<None>
|
||||
|
||||
@ -174,38 +178,54 @@
|
||||
# which may use any of the available logging.LogRecord
|
||||
# attributes. This option is deprecated. Please use
|
||||
# logging_context_format_string and
|
||||
# logging_default_format_string instead. (string value)
|
||||
# logging_default_format_string instead. This option is
|
||||
# ignored if log_config_append is set. (string value)
|
||||
#log_format=<None>
|
||||
|
||||
# Format string for %%(asctime)s in log records. Default:
|
||||
# %(default)s . (string value)
|
||||
# %(default)s . This option is ignored if log_config_append is
|
||||
# set. (string value)
|
||||
#log_date_format=%Y-%m-%d %H:%M:%S
|
||||
|
||||
# (Optional) Name of log file to output to. If no default is
|
||||
# set, logging will go to stdout. (string value)
|
||||
# set, logging will go to stdout. This option is ignored if
|
||||
# log_config_append is set. (string value)
|
||||
# Deprecated group/name - [DEFAULT]/logfile
|
||||
#log_file=<None>
|
||||
|
||||
# (Optional) The base directory used for relative --log-file
|
||||
# paths. (string value)
|
||||
# paths. This option is ignored if log_config_append is set.
|
||||
# (string value)
|
||||
# Deprecated group/name - [DEFAULT]/logdir
|
||||
#log_dir=<None>
|
||||
|
||||
# (Optional) Uses logging handler designed to watch file
|
||||
# system. When log file is moved or removed this handler will
|
||||
# open a new log file with specified path instantaneously. It
|
||||
# makes sense only if log-file option is specified and Linux
|
||||
# platform is used. This option is ignored if
|
||||
# log_config_append is set. (boolean value)
|
||||
#watch_log_file=false
|
||||
|
||||
# Use syslog for logging. Existing syslog format is DEPRECATED
|
||||
# and will be changed later to honor RFC5424. (boolean value)
|
||||
# and will be changed later to honor RFC5424. This option is
|
||||
# ignored if log_config_append is set. (boolean value)
|
||||
#use_syslog=false
|
||||
|
||||
# (Optional) Enables or disables syslog rfc5424 format for
|
||||
# logging. If enabled, prefixes the MSG part of the syslog
|
||||
# message with APP-NAME (RFC5424). The format without the APP-
|
||||
# NAME is deprecated in Kilo, and will be removed in Mitaka,
|
||||
# along with this option. (boolean value)
|
||||
# along with this option. This option is ignored if
|
||||
# log_config_append is set. (boolean value)
|
||||
#use_syslog_rfc_format=true
|
||||
|
||||
# Syslog facility to receive log lines. (string value)
|
||||
# Syslog facility to receive log lines. This option is ignored
|
||||
# if log_config_append is set. (string value)
|
||||
#syslog_log_facility=LOG_USER
|
||||
|
||||
# Log output to standard error. (boolean value)
|
||||
# Log output to standard error. This option is ignored if
|
||||
# log_config_append is set. (boolean value)
|
||||
#use_stderr=true
|
||||
|
||||
# Format string to use for log messages with context. (string
|
||||
@ -224,7 +244,8 @@
|
||||
# (string value)
|
||||
#logging_exception_prefix=%(asctime)s.%(msecs)03d %(process)d ERROR %(name)s %(instance)s
|
||||
|
||||
# List of logger=LEVEL pairs. (list value)
|
||||
# List of logger=LEVEL pairs. This option is ignored if
|
||||
# log_config_append is set. (list value)
|
||||
#default_log_levels=amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN,taskflow=WARN
|
||||
|
||||
# Enables or disables publication of error events. (boolean
|
||||
@ -257,10 +278,15 @@
|
||||
#rpc_zmq_bind_address=*
|
||||
|
||||
# MatchMaker driver. (string value)
|
||||
#rpc_zmq_matchmaker=local
|
||||
#rpc_zmq_matchmaker=redis
|
||||
|
||||
# ZeroMQ receiver listening port. (integer value)
|
||||
#rpc_zmq_port=9501
|
||||
# Use REQ/REP pattern for all methods CALL/CAST/FANOUT.
|
||||
# (boolean value)
|
||||
#rpc_zmq_all_req_rep=true
|
||||
|
||||
# Type of concurrency used. Either "native" or "eventlet"
|
||||
# (string value)
|
||||
#rpc_zmq_concurrency=eventlet
|
||||
|
||||
# Number of ZeroMQ contexts, defaults to 1. (integer value)
|
||||
#rpc_zmq_contexts=1
|
||||
@ -281,11 +307,23 @@
|
||||
# by impl_zmq. (integer value)
|
||||
#rpc_cast_timeout=30
|
||||
|
||||
# Heartbeat frequency. (integer value)
|
||||
#matchmaker_heartbeat_freq=300
|
||||
# The default number of seconds that poll should wait. Poll
|
||||
# raises timeout exception when timeout expired. (integer
|
||||
# value)
|
||||
#rpc_poll_timeout=1
|
||||
|
||||
# Heartbeat time-to-live. (integer value)
|
||||
#matchmaker_heartbeat_ttl=600
|
||||
# Shows whether zmq-messaging uses broker or not. (boolean
|
||||
# value)
|
||||
#zmq_use_broker=true
|
||||
|
||||
# Host to locate redis. (string value)
|
||||
#host=127.0.0.1
|
||||
|
||||
# Use this port to connect to redis host. (integer value)
|
||||
#port=6379
|
||||
|
||||
# Password for Redis server (optional). (string value)
|
||||
#password=
|
||||
|
||||
# Size of executor thread pool. (integer value)
|
||||
# Deprecated group/name - [DEFAULT]/rpc_thread_pool_size
|
||||
@ -998,6 +1036,10 @@
|
||||
# operations (integer value)
|
||||
#retry_interval=1
|
||||
|
||||
# Time (in seconds) to sleep between when rebooting (powering
|
||||
# off and on again). (integer value)
|
||||
#reboot_delay=5
|
||||
|
||||
|
||||
[ilo]
|
||||
|
||||
@ -1376,18 +1418,7 @@
|
||||
#port=6379
|
||||
|
||||
# Password for Redis server (optional). (string value)
|
||||
#password=<None>
|
||||
|
||||
|
||||
[matchmaker_ring]
|
||||
|
||||
#
|
||||
# Options defined in oslo.messaging
|
||||
#
|
||||
|
||||
# Matchmaker ring file (JSON). (string value)
|
||||
# Deprecated group/name - [DEFAULT]/matchmaker_ringfile
|
||||
#ringfile=/etc/oslo/matchmaker_ring.json
|
||||
#password=
|
||||
|
||||
|
||||
[neutron]
|
||||
@ -1444,7 +1475,7 @@
|
||||
|
||||
# Max connection retries to check changes on OneView (integer
|
||||
# value)
|
||||
#max_polling_attempts=20
|
||||
#max_polling_attempts=12
|
||||
|
||||
|
||||
[oslo_concurrency]
|
||||
@ -1511,6 +1542,24 @@
|
||||
# Accept clients using either SSL or plain TCP (boolean value)
|
||||
#allow_insecure_clients=false
|
||||
|
||||
# Space separated list of acceptable SASL mechanisms (string
|
||||
# value)
|
||||
#sasl_mechanisms=
|
||||
|
||||
# Path to directory that contains the SASL configuration
|
||||
# (string value)
|
||||
#sasl_config_dir=
|
||||
|
||||
# Name of configuration file (without .conf suffix) (string
|
||||
# value)
|
||||
#sasl_config_name=
|
||||
|
||||
# User name for message broker authentication (string value)
|
||||
#username=
|
||||
|
||||
# Password for message broker authentication (string value)
|
||||
#password=
|
||||
|
||||
|
||||
[oslo_messaging_qpid]
|
||||
|
||||
@ -1782,7 +1831,7 @@
|
||||
#ipxe_boot_script=$pybasedir/drivers/modules/boot.ipxe
|
||||
|
||||
# The IP version that will be used for PXE booting. Can be
|
||||
# either 4 or 6. Defaults to 4. EXPERIMENTAL (integer value)
|
||||
# either 4 or 6. Defaults to 4. EXPERIMENTAL (string value)
|
||||
#ip_version=4
|
||||
|
||||
|
||||
|
@ -19,6 +19,8 @@
|
||||
Ironic iBoot PDU power manager.
|
||||
"""
|
||||
|
||||
import time
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_service import loopingcall
|
||||
@ -41,6 +43,11 @@ opts = [
|
||||
default=1,
|
||||
help=_('Time (in seconds) between retry attempts for iBoot '
|
||||
'operations')),
|
||||
cfg.IntOpt('reboot_delay',
|
||||
default=5,
|
||||
min=0,
|
||||
help=_('Time (in seconds) to sleep between when rebooting '
|
||||
'(powering off and on again).'))
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -139,6 +146,11 @@ def _switch(driver_info, enabled):
|
||||
return mutable['response']
|
||||
|
||||
|
||||
def _sleep_switch(seconds):
|
||||
"""Function broken out for testing purpose."""
|
||||
time.sleep(seconds)
|
||||
|
||||
|
||||
def _power_status(driver_info):
|
||||
conn = _get_connection(driver_info)
|
||||
relay_id = driver_info['relay_id']
|
||||
@ -258,6 +270,7 @@ class IBootPower(base.PowerInterface):
|
||||
"""
|
||||
driver_info = _parse_driver_info(task.node)
|
||||
_switch(driver_info, False)
|
||||
_sleep_switch(CONF.iboot.reboot_delay)
|
||||
_switch(driver_info, True)
|
||||
|
||||
state = _power_status(driver_info)
|
||||
|
@ -259,6 +259,7 @@ class IBootDriverTestCase(db_base.DbTestCase):
|
||||
super(IBootDriverTestCase, self).setUp()
|
||||
self.config(max_retry=0, group='iboot')
|
||||
self.config(retry_interval=0, group='iboot')
|
||||
self.config(reboot_delay=0, group='iboot')
|
||||
mgr_utils.mock_the_extension_manager(driver='fake_iboot')
|
||||
self.driver = driver_factory.get_driver('fake_iboot')
|
||||
self.node = obj_utils.create_test_node(
|
||||
@ -310,14 +311,19 @@ class IBootDriverTestCase(db_base.DbTestCase):
|
||||
task.driver.power.set_power_state,
|
||||
task, states.NOSTATE)
|
||||
|
||||
@mock.patch.object(iboot, '_sleep_switch', spec_set=types.FunctionType)
|
||||
@mock.patch.object(iboot, '_power_status', autospec=True)
|
||||
@mock.patch.object(iboot, '_switch', spec_set=types.FunctionType)
|
||||
def test_reboot_good(self, mock_switch, mock_power_status):
|
||||
manager = mock.MagicMock(spec_set=['switch'])
|
||||
def test_reboot_good(self, mock_switch, mock_power_status,
|
||||
mock_sleep_switch):
|
||||
self.config(reboot_delay=3, group='iboot')
|
||||
manager = mock.MagicMock(spec_set=['switch', 'sleep'])
|
||||
mock_power_status.return_value = states.POWER_ON
|
||||
|
||||
manager.attach_mock(mock_switch, 'switch')
|
||||
manager.attach_mock(mock_sleep_switch, 'sleep')
|
||||
expected = [mock.call.switch(self.info, False),
|
||||
mock.call.sleep(3),
|
||||
mock.call.switch(self.info, True)]
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
@ -325,14 +331,19 @@ class IBootDriverTestCase(db_base.DbTestCase):
|
||||
|
||||
self.assertEqual(manager.mock_calls, expected)
|
||||
|
||||
@mock.patch.object(iboot, '_sleep_switch', spec_set=types.FunctionType)
|
||||
@mock.patch.object(iboot, '_power_status', autospec=True)
|
||||
@mock.patch.object(iboot, '_switch', spec_set=types.FunctionType)
|
||||
def test_reboot_bad(self, mock_switch, mock_power_status):
|
||||
manager = mock.MagicMock(spec_set=['switch'])
|
||||
def test_reboot_bad(self, mock_switch, mock_power_status,
|
||||
mock_sleep_switch):
|
||||
self.config(reboot_delay=3, group='iboot')
|
||||
manager = mock.MagicMock(spec_set=['switch', 'sleep'])
|
||||
mock_power_status.return_value = states.POWER_OFF
|
||||
|
||||
manager.attach_mock(mock_switch, 'switch')
|
||||
manager.attach_mock(mock_sleep_switch, 'sleep')
|
||||
expected = [mock.call.switch(self.info, False),
|
||||
mock.call.sleep(3),
|
||||
mock.call.switch(self.info, True)]
|
||||
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
|
Loading…
x
Reference in New Issue
Block a user