Allow to set Neutron port setup delay from config
Unfortunately there still no mechanism to synchronize events with Neutron. Sometimes server can get to PXE faster than Neutron configures port for netboot. It may occur with VMs, and hardware servers with fast boot enabled. This patch introduce new config variable 'port_setup_delay' that allows to wait for Neutron operations. Change-Id: Iaeb78649a92b89e2c6eb0f545aed95a766d14430
This commit is contained in:
parent
3d80e41e8d
commit
5cf9f083fe
@ -506,6 +506,10 @@ function configure_ironic_conductor {
|
||||
iniset $IRONIC_CONF_FILE deploy http_root $IRONIC_HTTP_DIR
|
||||
iniset $IRONIC_CONF_FILE deploy http_url "http://$IRONIC_HTTP_SERVER:$IRONIC_HTTP_PORT"
|
||||
fi
|
||||
|
||||
if [[ "$IRONIC_IS_HARDWARE" == "False" ]]; then
|
||||
iniset $IRONIC_CONF_FILE neutron port_setup_delay 15
|
||||
fi
|
||||
}
|
||||
|
||||
# create_ironic_cache_dir() - Part of the init_ironic() process
|
||||
|
@ -1559,6 +1559,11 @@
|
||||
# value)
|
||||
#url_timeout = 30
|
||||
|
||||
# Delay value to wait for Neutron agents to setup sufficient
|
||||
# DHCP configuration for port. (integer value)
|
||||
# Minimum value: 0
|
||||
#port_setup_delay = 0
|
||||
|
||||
# Client retries in the case of a failed request. (integer
|
||||
# value)
|
||||
#retries = 3
|
||||
|
@ -40,6 +40,11 @@ neutron_opts = [
|
||||
cfg.IntOpt('url_timeout',
|
||||
default=30,
|
||||
help=_('Timeout value for connecting to neutron in seconds.')),
|
||||
cfg.IntOpt('port_setup_delay',
|
||||
default=0,
|
||||
min=0,
|
||||
help=_('Delay value to wait for Neutron agents to setup '
|
||||
'sufficient DHCP configuration for port.')),
|
||||
cfg.IntOpt('retries',
|
||||
default=3,
|
||||
help=_('Client retries in the case of a failed request.')),
|
||||
@ -193,13 +198,22 @@ class NeutronDHCPApi(base.BaseDHCP):
|
||||
{'node': task.node.uuid, 'ports': failures})
|
||||
|
||||
# TODO(adam_g): Hack to workaround bug 1334447 until we have a
|
||||
# mechanism for synchronizing events with Neutron. We need to sleep
|
||||
# only if we are booting VMs, which is implied by SSHPower, to ensure
|
||||
# they do not boot before Neutron agents have setup sufficient DHCP
|
||||
# config for netboot.
|
||||
if isinstance(task.driver.power, ssh.SSHPower):
|
||||
LOG.debug("Waiting 15 seconds for Neutron.")
|
||||
time.sleep(15)
|
||||
# mechanism for synchronizing events with Neutron. We need to sleep
|
||||
# only if server gets to PXE faster than Neutron agents have setup
|
||||
# sufficient DHCP config for netboot. It may occur when we are using
|
||||
# VMs or hardware server with fast boot enabled.
|
||||
port_delay = CONF.neutron.port_setup_delay
|
||||
# TODO(vsaienko) remove hardcoded value for SSHPower driver
|
||||
# after Newton release.
|
||||
if isinstance(task.driver.power, ssh.SSHPower) and port_delay == 0:
|
||||
LOG.warning(_LW("Setting the port delay to 15 for SSH power "
|
||||
"driver by default, this will be removed in "
|
||||
"Ocata release. Please set configuration "
|
||||
"parameter port_setup_delay to 15."))
|
||||
port_delay = 15
|
||||
if port_delay != 0:
|
||||
LOG.debug("Waiting %d seconds for Neutron.", port_delay)
|
||||
time.sleep(port_delay)
|
||||
|
||||
def _get_fixed_ip_address(self, port_uuid, client):
|
||||
"""Get a Neutron port's fixed ip address.
|
||||
|
@ -26,6 +26,7 @@ from ironic.common import exception
|
||||
from ironic.common import pxe_utils
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.dhcp import neutron
|
||||
from ironic.drivers.modules import ssh
|
||||
from ironic.tests.unit.conductor import mgr_utils
|
||||
from ironic.tests.unit.db import base as db_base
|
||||
from ironic.tests.unit.objects import utils as object_utils
|
||||
@ -250,6 +251,87 @@ class TestNeutron(db_base.DbTestCase):
|
||||
mock_gnvi.assert_called_once_with(task)
|
||||
self.assertEqual(2, mock_updo.call_count)
|
||||
|
||||
@mock.patch('time.sleep', autospec=True)
|
||||
@mock.patch.object(neutron.NeutronDHCPApi, 'update_port_dhcp_opts',
|
||||
autospec=True)
|
||||
@mock.patch('ironic.common.network.get_node_vif_ids', autospec=True)
|
||||
def test_update_dhcp_set_sleep_and_ssh(self, mock_gnvi, mock_updo,
|
||||
mock_ts):
|
||||
mock_gnvi.return_value = {'ports': {'port-uuid': 'vif-uuid'},
|
||||
'portgroups': {}}
|
||||
self.config(port_setup_delay=30, group='neutron')
|
||||
with task_manager.acquire(self.context,
|
||||
self.node.uuid) as task:
|
||||
task.driver.power = ssh.SSHPower()
|
||||
opts = pxe_utils.dhcp_options_for_instance(task)
|
||||
api = dhcp_factory.DHCPFactory()
|
||||
api.update_dhcp(task, opts)
|
||||
mock_ts.assert_called_with(30)
|
||||
mock_updo.assert_called_once_with(mock.ANY, 'vif-uuid', opts,
|
||||
token=self.context.auth_token)
|
||||
|
||||
@mock.patch.object(neutron, 'LOG', autospec=True)
|
||||
@mock.patch('time.sleep', autospec=True)
|
||||
@mock.patch.object(neutron.NeutronDHCPApi, 'update_port_dhcp_opts',
|
||||
autospec=True)
|
||||
@mock.patch('ironic.common.network.get_node_vif_ids', autospec=True)
|
||||
def test_update_dhcp_unset_sleep_and_ssh(self, mock_gnvi, mock_updo,
|
||||
mock_ts, mock_log):
|
||||
mock_gnvi.return_value = {'ports': {'port-uuid': 'vif-uuid'},
|
||||
'portgroups': {}}
|
||||
with task_manager.acquire(self.context,
|
||||
self.node.uuid) as task:
|
||||
opts = pxe_utils.dhcp_options_for_instance(task)
|
||||
task.driver.power = ssh.SSHPower()
|
||||
api = dhcp_factory.DHCPFactory()
|
||||
api.update_dhcp(task, opts)
|
||||
self.assertTrue(mock_log.warning.called)
|
||||
self.assertIn('Setting the port delay to 15 for SSH',
|
||||
mock_log.warning.call_args[0][0])
|
||||
mock_ts.assert_called_with(15)
|
||||
mock_updo.assert_called_once_with(mock.ANY, 'vif-uuid', opts,
|
||||
token=self.context.auth_token)
|
||||
|
||||
@mock.patch.object(neutron, 'LOG', autospec=True)
|
||||
@mock.patch('time.sleep', autospec=True)
|
||||
@mock.patch.object(neutron.NeutronDHCPApi, 'update_port_dhcp_opts',
|
||||
autospec=True)
|
||||
@mock.patch('ironic.common.network.get_node_vif_ids', autospec=True)
|
||||
def test_update_dhcp_set_sleep_and_fake(self, mock_gnvi, mock_updo,
|
||||
mock_ts, mock_log):
|
||||
mock_gnvi.return_value = {'ports': {'port-uuid': 'vif-uuid'},
|
||||
'portgroups': {}}
|
||||
self.config(port_setup_delay=30, group='neutron')
|
||||
with task_manager.acquire(self.context,
|
||||
self.node.uuid) as task:
|
||||
opts = pxe_utils.dhcp_options_for_instance(task)
|
||||
api = dhcp_factory.DHCPFactory()
|
||||
api.update_dhcp(task, opts)
|
||||
mock_log.debug.assert_called_once_with(
|
||||
"Waiting %d seconds for Neutron.", 30)
|
||||
mock_log.warning.assert_not_called()
|
||||
mock_ts.assert_called_with(30)
|
||||
mock_updo.assert_called_once_with(mock.ANY, 'vif-uuid', opts,
|
||||
token=self.context.auth_token)
|
||||
|
||||
@mock.patch.object(neutron, 'LOG', autospec=True)
|
||||
@mock.patch.object(neutron.NeutronDHCPApi, 'update_port_dhcp_opts',
|
||||
autospec=True)
|
||||
@mock.patch('ironic.common.network.get_node_vif_ids', autospec=True)
|
||||
def test_update_dhcp_unset_sleep_and_fake(self, mock_gnvi, mock_updo,
|
||||
mock_log):
|
||||
mock_gnvi.return_value = {'ports': {'port-uuid': 'vif-uuid'},
|
||||
'portgroups': {}}
|
||||
with task_manager.acquire(self.context,
|
||||
self.node.uuid) as task:
|
||||
opts = pxe_utils.dhcp_options_for_instance(task)
|
||||
api = dhcp_factory.DHCPFactory()
|
||||
api.update_dhcp(task, opts)
|
||||
mock_log.debug.assert_not_called()
|
||||
mock_log.warning.assert_not_called()
|
||||
mock_updo.assert_called_once_with(mock.ANY, 'vif-uuid', opts,
|
||||
token=self.context.auth_token)
|
||||
|
||||
def test__get_fixed_ip_address(self):
|
||||
port_id = 'fake-port-id'
|
||||
expected = "192.168.1.3"
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
other:
|
||||
- Add Neutron ``port_setup_delay`` configuration
|
||||
option. This delay allows Ironic to wait for
|
||||
Neutron port operations until we have a
|
||||
mechanism for synchronizing events with Neutron.
|
||||
Set to 0 by default.
|
Loading…
Reference in New Issue
Block a user