Merge "Wait for Neutron port updates when using SSHPower"
This commit is contained in:
commit
0bbb64d999
ironic
@ -14,6 +14,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import time
|
||||
|
||||
from neutronclient.common import exceptions as neutron_client_exc
|
||||
from neutronclient.v2_0 import client as clientv20
|
||||
from oslo.config import cfg
|
||||
@ -22,6 +24,7 @@ from ironic.api import acl
|
||||
from ironic.common import exception
|
||||
from ironic.common import keystone
|
||||
from ironic.common import tftp
|
||||
from ironic.drivers.modules import ssh
|
||||
from ironic.openstack.common import log as logging
|
||||
|
||||
|
||||
@ -159,3 +162,16 @@ def update_neutron(task, pxe_bootfile_name):
|
||||
"DHCP BOOT options for node %(node)s on the "
|
||||
"following ports: %(ports)s."),
|
||||
{'node': task.node.uuid, 'ports': failures})
|
||||
|
||||
_wait_for_neutron_update(task)
|
||||
|
||||
|
||||
def _wait_for_neutron_update(task):
|
||||
"""Wait for Neutron agents to process all requested changes if required."""
|
||||
# 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 sufficent DHCP config for netboot.
|
||||
if isinstance(task.driver.power, ssh.SSHPower):
|
||||
LOG.debug(_("Waiting 15 seconds for Neutron."))
|
||||
time.sleep(15)
|
||||
|
@ -196,28 +196,35 @@ class TestNeutron(base.TestCase):
|
||||
result = neutron.get_node_vif_ids(task)
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
@mock.patch('ironic.common.neutron._wait_for_neutron_update')
|
||||
@mock.patch('ironic.common.neutron.NeutronAPI.update_port_dhcp_opts')
|
||||
@mock.patch('ironic.common.neutron.get_node_vif_ids')
|
||||
def test_update_neutron(self, mock_gnvi, mock_updo):
|
||||
def test_update_neutron(self, mock_gnvi, mock_updo, mock_wait_neutron):
|
||||
opts = tftp.dhcp_options_for_instance(CONF.pxe.pxe_bootfile_name)
|
||||
mock_gnvi.return_value = {'port-uuid': 'vif-uuid'}
|
||||
with task_manager.acquire(self.context,
|
||||
self.node.uuid) as task:
|
||||
neutron.update_neutron(task, self.node)
|
||||
mock_updo.assertCalleOnceWith('vif-uuid', opts)
|
||||
mock_wait_neutron.assert_called_once_with(task)
|
||||
|
||||
@mock.patch('ironic.common.neutron._wait_for_neutron_update')
|
||||
@mock.patch('ironic.common.neutron.NeutronAPI.__init__')
|
||||
@mock.patch('ironic.common.neutron.get_node_vif_ids')
|
||||
def test_update_neutron_no_vif_data(self, mock_gnvi, mock_init):
|
||||
def test_update_neutron_no_vif_data(self, mock_gnvi, mock_init,
|
||||
mock_wait_neutron):
|
||||
mock_gnvi.return_value = {}
|
||||
with task_manager.acquire(self.context,
|
||||
self.node.uuid) as task:
|
||||
neutron.update_neutron(task, self.node)
|
||||
mock_init.assert_not_called()
|
||||
self.assertFalse(mock_init.called)
|
||||
self.assertFalse(mock_wait_neutron.called)
|
||||
|
||||
@mock.patch('ironic.common.neutron._wait_for_neutron_update')
|
||||
@mock.patch('ironic.common.neutron.NeutronAPI.update_port_dhcp_opts')
|
||||
@mock.patch('ironic.common.neutron.get_node_vif_ids')
|
||||
def test_update_neutron_some_failures(self, mock_gnvi, mock_updo):
|
||||
def test_update_neutron_some_failures(self, mock_gnvi, mock_updo,
|
||||
mock_wait_neutron):
|
||||
# confirm update is called twice, one fails, but no exception raised
|
||||
mock_gnvi.return_value = {'p1': 'v1', 'p2': 'v2'}
|
||||
exc = exception.FailedToUpdateDHCPOptOnPort('fake exception')
|
||||
@ -226,10 +233,13 @@ class TestNeutron(base.TestCase):
|
||||
self.node.uuid) as task:
|
||||
neutron.update_neutron(task, self.node)
|
||||
self.assertEqual(2, mock_updo.call_count)
|
||||
mock_wait_neutron.assert_called_once_with(task)
|
||||
|
||||
@mock.patch('ironic.common.neutron._wait_for_neutron_update')
|
||||
@mock.patch('ironic.common.neutron.NeutronAPI.update_port_dhcp_opts')
|
||||
@mock.patch('ironic.common.neutron.get_node_vif_ids')
|
||||
def test_update_neutron_fails(self, mock_gnvi, mock_updo):
|
||||
def test_update_neutron_fails(self, mock_gnvi, mock_updo,
|
||||
mock_wait_neutron):
|
||||
# confirm update is called twice, both fail, and exception is raised
|
||||
mock_gnvi.return_value = {'p1': 'v1', 'p2': 'v2'}
|
||||
exc = exception.FailedToUpdateDHCPOptOnPort('fake exception')
|
||||
@ -240,3 +250,23 @@ class TestNeutron(base.TestCase):
|
||||
neutron.update_neutron,
|
||||
task, self.node)
|
||||
self.assertEqual(2, mock_updo.call_count)
|
||||
self.assertFalse(mock_wait_neutron.called)
|
||||
|
||||
def test__wait_for_neutron_update(self):
|
||||
kw = {
|
||||
'id': 190238451205398,
|
||||
'uuid': utils.generate_uuid(),
|
||||
'driver': 'fake_ssh'
|
||||
}
|
||||
node = object_utils.create_test_node(self.context, **kw)
|
||||
mgr_utils.mock_the_extension_manager(driver="fake_ssh")
|
||||
with task_manager.acquire(self.context, node.uuid) as task:
|
||||
with mock.patch('time.sleep') as mock_sleep:
|
||||
neutron._wait_for_neutron_update(task)
|
||||
mock_sleep.assert_called_once_with(15)
|
||||
|
||||
def test__wait_for_neutron_update_no_sleep(self):
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
with mock.patch('time.sleep') as mock_sleep:
|
||||
neutron._wait_for_neutron_update(task)
|
||||
self.assertFalse(mock_sleep.called)
|
||||
|
Loading…
x
Reference in New Issue
Block a user