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:
Dan Prince 2015-10-08 12:56:32 -04:00 committed by Lucas Alvares Gomes
parent 93f5a12a99
commit 735b58f2c3
3 changed files with 108 additions and 35 deletions

View File

@ -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

View File

@ -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)

View File

@ -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: