Merge "Notify nova with network-vif-plugged in case of live migration"

This commit is contained in:
Jenkins 2016-07-25 21:54:55 +00:00 committed by Gerrit Code Review
commit 3fb38b41f7
4 changed files with 67 additions and 13 deletions

View File

@ -172,26 +172,31 @@ class Notifier(object):
else:
return self._get_network_changed_event(port['device_id'])
def _can_notify(self, port):
if not port.id:
LOG.warning(_LW("Port ID not set! Nova will not be notified of "
"port status change."))
return False
# If there is no device_id set there is nothing we can do here.
if not port.device_id:
LOG.debug("device_id is not set on port %s yet.", port.id)
return False
# We only want to notify about nova ports.
if not self._is_compute_port(port):
return False
return True
def record_port_status_changed(self, port, current_port_status,
previous_port_status, initiator):
"""Determine if nova needs to be notified due to port status change.
"""
# clear out previous _notify_event
port._notify_event = None
# If there is no device_id set there is nothing we can do here.
if not port.device_id:
LOG.debug("device_id is not set on port yet.")
if not self._can_notify(port):
return
if not port.id:
LOG.warning(_LW("Port ID not set! Nova will not be notified of "
"port status change."))
return
# We only want to notify about nova ports.
if not self._is_compute_port(port):
return
# We notify nova when a vif is unplugged which only occurs when
# the status goes from ACTIVE to DOWN.
if (previous_port_status == constants.PORT_STATUS_ACTIVE and
@ -228,6 +233,24 @@ class Notifier(object):
self.batch_notifier.queue_event(event)
port._notify_event = None
def notify_port_active_direct(self, port):
"""Notify nova about active port
Used when port was wired on the host other than port's current host
according to port binding. This happens during live migration.
In this case ml2 plugin skips port status update but we still we need
to notify nova.
"""
if not self._can_notify(port):
return
port._notify_event = (
{'server_uuid': port.device_id,
'name': VIF_PLUGGED,
'status': 'completed',
'tag': port.id})
self.send_port_status(None, None, port)
def send_events(self, batched_events):
LOG.debug("Sending events: %s", batched_events)
try:

View File

@ -14,6 +14,7 @@
# under the License.
from neutron_lib import constants as n_const
from neutron_lib import exceptions
from oslo_log import log
import oslo_messaging
from sqlalchemy.orm import exc
@ -209,6 +210,17 @@ class RpcCallbacks(type_tunnel.TunnelRpcCallbackMixin):
LOG.debug("Device %(device)s not bound to the"
" agent host %(host)s",
{'device': device, 'host': host})
# this might mean that a VM is in the process of live migration
# and vif was plugged on the destination compute node;
# need to notify nova explicitly
try:
port = plugin._get_port(rpc_context, port_id)
except exceptions.PortNotFound:
LOG.debug("Port %s not found, will not notify nova.", port_id)
else:
if port.device_owner.startswith(
n_const.DEVICE_OWNER_COMPUTE_PREFIX):
plugin.nova_notifier.notify_port_active_direct(port)
return
if port and port['device_owner'] == n_const.DEVICE_OWNER_DVR_INTERFACE:
# NOTE(kevinbenton): we have to special case DVR ports because of

View File

@ -340,3 +340,19 @@ class TestNovaNotify(base.BaseTestCase):
region_name=cfg.CONF.nova.region_name,
endpoint_type='internal',
extensions=mock.ANY)
def test_notify_port_active_direct(self):
device_id = '32102d7b-1cf4-404d-b50a-97aae1f55f87'
port_id = 'bee50827-bcee-4cc8-91c1-a27b0ce54222'
port = models_v2.Port(id=port_id, device_id=device_id,
device_owner=DEVICE_OWNER_COMPUTE)
expected_event = {'server_uuid': device_id,
'name': nova.VIF_PLUGGED,
'status': 'completed',
'tag': port_id}
self.nova_notifier.notify_port_active_direct(port)
self.assertEqual(
1, len(self.nova_notifier.batch_notifier.pending_events))
self.assertEqual(expected_event,
self.nova_notifier.batch_notifier.pending_events[0])

View File

@ -222,6 +222,9 @@ class RpcCallbacksTestCase(base.BaseTestCase):
def test_update_device_up_with_device_not_bound_to_host(self):
self.assertIsNone(self._test_update_device_not_bound_to_host(
self.callbacks.update_device_up))
port = self.plugin._get_port.return_value
(self.plugin.nova_notifier.notify_port_active_direct.
assert_called_once_with(port))
def test_update_device_down_with_device_not_bound_to_host(self):
self.assertEqual(