314951e1b4
This patch notifies nova whenever a floatingip or fixed_ip is updated. Implements blueprint: nova-event-callback DocImpact - This notifications are off by default. Change-Id: Ifbe9d856e80e512d5595fd72ea2d7c047ce0de9d
245 lines
11 KiB
Python
245 lines
11 KiB
Python
# Copyright 2014 OpenStack Foundation
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
|
|
import mock
|
|
from sqlalchemy.orm import attributes as sql_attr
|
|
|
|
from oslo.config import cfg
|
|
|
|
from neutron.common import constants
|
|
from neutron.db import models_v2
|
|
from neutron.notifiers import nova
|
|
from neutron.tests import base
|
|
|
|
|
|
class TestNovaNotify(base.BaseTestCase):
|
|
def setUp(self, plugin=None):
|
|
super(TestNovaNotify, self).setUp()
|
|
|
|
class FakePlugin(object):
|
|
def get_port(self, context, port_id):
|
|
return {'device_id': 'instance_uuid',
|
|
'device_owner': 'compute:None'}
|
|
|
|
self.nova_notifier = nova.Notifier()
|
|
self.nova_notifier._plugin_ref = FakePlugin()
|
|
|
|
def test_notify_port_status_all_values(self):
|
|
states = [constants.PORT_STATUS_ACTIVE, constants.PORT_STATUS_DOWN,
|
|
constants.PORT_STATUS_ERROR, constants.PORT_STATUS_BUILD,
|
|
sql_attr.NO_VALUE]
|
|
# test all combinations
|
|
for previous_port_status in states:
|
|
for current_port_status in states:
|
|
port = models_v2.Port(id='port-uuid', device_id='device-uuid',
|
|
device_owner="compute:",
|
|
status=current_port_status)
|
|
self._record_port_status_changed_helper(current_port_status,
|
|
previous_port_status,
|
|
port)
|
|
|
|
def test_port_without_device_owner_no_notify(self):
|
|
port = models_v2.Port(id='port-uuid', device_id='device-uuid',
|
|
status=constants.PORT_STATUS_ACTIVE)
|
|
self._record_port_status_changed_helper(constants.PORT_STATUS_ACTIVE,
|
|
sql_attr.NO_VALUE,
|
|
port)
|
|
|
|
def test_port_without_device_id_no_notify(self):
|
|
port = models_v2.Port(id='port-uuid', device_owner="network:dhcp",
|
|
status=constants.PORT_STATUS_ACTIVE)
|
|
self._record_port_status_changed_helper(constants.PORT_STATUS_ACTIVE,
|
|
sql_attr.NO_VALUE,
|
|
port)
|
|
|
|
def test_port_without_id_no_notify(self):
|
|
port = models_v2.Port(device_id='device-uuid',
|
|
device_owner="compute:",
|
|
status=constants.PORT_STATUS_ACTIVE)
|
|
self._record_port_status_changed_helper(constants.PORT_STATUS_ACTIVE,
|
|
sql_attr.NO_VALUE,
|
|
port)
|
|
|
|
def test_non_compute_instances_no_notify(self):
|
|
port = models_v2.Port(id='port-uuid', device_id='device-uuid',
|
|
device_owner="network:dhcp",
|
|
status=constants.PORT_STATUS_ACTIVE)
|
|
self._record_port_status_changed_helper(constants.PORT_STATUS_ACTIVE,
|
|
sql_attr.NO_VALUE,
|
|
port)
|
|
|
|
def _record_port_status_changed_helper(self, current_port_status,
|
|
previous_port_status, port):
|
|
|
|
if not (port.device_id and port.id and port.device_owner and
|
|
port.device_owner.startswith('compute:')):
|
|
return
|
|
|
|
if (previous_port_status == constants.PORT_STATUS_ACTIVE and
|
|
current_port_status == constants.PORT_STATUS_DOWN):
|
|
event_name = nova.VIF_UNPLUGGED
|
|
|
|
elif (previous_port_status in [sql_attr.NO_VALUE,
|
|
constants.PORT_STATUS_DOWN,
|
|
constants.PORT_STATUS_BUILD]
|
|
and current_port_status in [constants.PORT_STATUS_ACTIVE,
|
|
constants.PORT_STATUS_ERROR]):
|
|
event_name = nova.VIF_PLUGGED
|
|
|
|
else:
|
|
return
|
|
|
|
status = nova.NEUTRON_NOVA_EVENT_STATUS_MAP.get(current_port_status)
|
|
self.nova_notifier.record_port_status_changed(port,
|
|
current_port_status,
|
|
previous_port_status,
|
|
None)
|
|
|
|
event = {'server_uuid': 'device-uuid', 'status': status,
|
|
'name': event_name, 'tag': 'port-uuid'}
|
|
self.assertEqual(event, port._notify_event)
|
|
|
|
def test_update_fixed_ip_changed(self):
|
|
returned_obj = {'port':
|
|
{'device_owner': u'compute:dfd',
|
|
'id': u'bee50827-bcee-4cc8-91c1-a27b0ce54222',
|
|
'device_id': u'instance_uuid'}}
|
|
|
|
expected_event = {'server_uuid': 'instance_uuid',
|
|
'name': 'network-changed'}
|
|
event = self.nova_notifier.create_port_changed_event('update_port',
|
|
{}, returned_obj)
|
|
self.assertEqual(event, expected_event)
|
|
|
|
def test_create_floatingip_notify(self):
|
|
returned_obj = {'floatingip':
|
|
{'port_id': u'bee50827-bcee-4cc8-91c1-a27b0ce54222'}}
|
|
|
|
expected_event = {'server_uuid': 'instance_uuid',
|
|
'name': 'network-changed'}
|
|
event = self.nova_notifier.create_port_changed_event(
|
|
'create_floatingip', {}, returned_obj)
|
|
self.assertEqual(event, expected_event)
|
|
|
|
def test_create_floatingip_no_port_id_no_notify(self):
|
|
returned_obj = {'floatingip':
|
|
{'port_id': None}}
|
|
|
|
event = self.nova_notifier.create_port_changed_event(
|
|
'create_floatingip', {}, returned_obj)
|
|
self.assertFalse(event, None)
|
|
|
|
def test_delete_floatingip_notify(self):
|
|
returned_obj = {'floatingip':
|
|
{'port_id': u'bee50827-bcee-4cc8-91c1-a27b0ce54222'}}
|
|
|
|
expected_event = {'server_uuid': 'instance_uuid',
|
|
'name': 'network-changed'}
|
|
event = self.nova_notifier.create_port_changed_event(
|
|
'delete_floatingip', {}, returned_obj)
|
|
self.assertEqual(expected_event, event)
|
|
|
|
def test_delete_floatingip_no_port_id_no_notify(self):
|
|
returned_obj = {'floatingip':
|
|
{'port_id': None}}
|
|
|
|
event = self.nova_notifier.create_port_changed_event(
|
|
'delete_floatingip', {}, returned_obj)
|
|
self.assertEqual(event, None)
|
|
|
|
def test_associate_floatingip_notify(self):
|
|
returned_obj = {'floatingip':
|
|
{'port_id': u'5a39def4-3d3f-473d-9ff4-8e90064b9cc1'}}
|
|
original_obj = {'port_id': None}
|
|
|
|
expected_event = {'server_uuid': 'instance_uuid',
|
|
'name': 'network-changed'}
|
|
event = self.nova_notifier.create_port_changed_event(
|
|
'update_floatingip', original_obj, returned_obj)
|
|
self.assertEqual(expected_event, event)
|
|
|
|
def test_disassociate_floatingip_notify(self):
|
|
returned_obj = {'floatingip': {'port_id': None}}
|
|
original_obj = {'port_id': '5a39def4-3d3f-473d-9ff4-8e90064b9cc1'}
|
|
|
|
expected_event = {'server_uuid': 'instance_uuid',
|
|
'name': 'network-changed'}
|
|
|
|
event = self.nova_notifier.create_port_changed_event(
|
|
'update_floatingip', original_obj, returned_obj)
|
|
self.assertEqual(expected_event, event)
|
|
|
|
def test_no_notification_notify_nova_on_port_data_changes_false(self):
|
|
cfg.CONF.set_override('notify_nova_on_port_data_changes', False)
|
|
|
|
with mock.patch.object(self.nova_notifier,
|
|
'send_events') as send_events:
|
|
self.nova_notifier.send_network_change('update_floatingip',
|
|
{}, {})
|
|
self.assertFalse(send_events.called, False)
|
|
|
|
def test_nova_send_events_returns_bad_list(self):
|
|
with mock.patch.object(
|
|
self.nova_notifier.nclient.server_external_events,
|
|
'create') as nclient_create:
|
|
nclient_create.return_value = 'i am a string!'
|
|
self.nova_notifier.send_events()
|
|
|
|
def test_nova_send_events_raises(self):
|
|
with mock.patch.object(
|
|
self.nova_notifier.nclient.server_external_events,
|
|
'create') as nclient_create:
|
|
nclient_create.side_effect = Exception
|
|
self.nova_notifier.send_events()
|
|
|
|
def test_nova_send_events_returns_non_200(self):
|
|
with mock.patch.object(
|
|
self.nova_notifier.nclient.server_external_events,
|
|
'create') as nclient_create:
|
|
nclient_create.return_value = [{'code': 404,
|
|
'name': 'network-changed',
|
|
'server_uuid': 'uuid'}]
|
|
self.nova_notifier.pending_events.append(
|
|
{'name': 'network-changed', 'server_uuid': 'uuid'})
|
|
self.nova_notifier.send_events()
|
|
|
|
def test_nova_send_events_return_200(self):
|
|
with mock.patch.object(
|
|
self.nova_notifier.nclient.server_external_events,
|
|
'create') as nclient_create:
|
|
nclient_create.return_value = [{'code': 200,
|
|
'name': 'network-changed',
|
|
'server_uuid': 'uuid'}]
|
|
self.nova_notifier.pending_events.append(
|
|
{'name': 'network-changed', 'server_uuid': 'uuid'})
|
|
self.nova_notifier.send_events()
|
|
|
|
def test_nova_send_events_multiple(self):
|
|
with mock.patch.object(
|
|
self.nova_notifier.nclient.server_external_events,
|
|
'create') as nclient_create:
|
|
nclient_create.return_value = [{'code': 200,
|
|
'name': 'network-changed',
|
|
'server_uuid': 'uuid'},
|
|
{'code': 200,
|
|
'name': 'network-changed',
|
|
'server_uuid': 'uuid'}]
|
|
self.nova_notifier.pending_events.append(
|
|
{'name': 'network-changed', 'server_uuid': 'uuid'})
|
|
self.nova_notifier.pending_events.append(
|
|
{'name': 'network-changed', 'server_uuid': 'uuid'})
|
|
self.nova_notifier.send_events()
|