Files
nova/nova/tests/unit/virt/xenapi/test_vif.py
Huan Xie bebc0a4b2e XenAPI: Support neutron security group
This implementation is to give support on neutron security group with
XenServer as compute driver. When using neutron+openvswitch, the ovs
agent on compute node cannot run correctly due to lack of qbr linux
bridge on compute node. This change will add qbr linux bridge when
xenserver as hypervisor
Xenserver driver now doesn't have linux bridge, the connection is:
compute node: vm-vif -> br-int -> br-eth
network node: br-eth -> br-int -> br-ex
With this implemented, linux bridge(qbr) will be added in compute
node. Thus the security group rules can be applied on qbr bridge.
The connection will look like:
compute node: vm-vif -> qbr(linux bridge) -> br-int -> br-eth
network node: br-eth -> br-int -> br-ex

Closes-Bug: #1526138

Implements: blueprint support-neutron-security-group

DocImpact: /etc/modprobe.d/blacklist-bridge file in dom0 should be
    deleted since it prevent loading linux bridge module in dom0

Depends-On: I377f8ad51e1d2725c3e0153e64322055fcce7b54

Change-Id: Id9b39aa86558a9f7099caedabd2d517bf8ad3d68
2016-06-21 22:42:12 -07:00

302 lines
13 KiB
Python

# Copyright 2013 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 nova import exception
from nova.network import model
from nova import test
from nova.tests.unit.virt.xenapi import stubs
from nova.virt.xenapi import network_utils
from nova.virt.xenapi import vif
fake_vif = {
'created_at': None,
'updated_at': None,
'deleted_at': None,
'deleted': 0,
'id': '123456789123',
'address': '00:00:00:00:00:00',
'network_id': 123,
'instance_uuid': 'fake-uuid',
'uuid': 'fake-uuid-2',
}
def fake_call_xenapi(method, *args):
if method == "VM.get_VIFs":
return ["fake_vif_ref", "fake_vif_ref_A2"]
if method == "VIF.get_record":
if args[0] == "fake_vif_ref":
return {'uuid': fake_vif['uuid'],
'MAC': fake_vif['address'],
'network': 'fake_network',
'other_config': {'nicira-iface-id': fake_vif['id']}
}
else:
raise exception.Exception("Failed get vif record")
if method == "VIF.unplug":
return
if method == "VIF.destroy":
if args[0] == "fake_vif_ref":
return
else:
raise exception.Exception("unplug vif failed")
if method == "VIF.create":
if args[0] == "fake_vif_rec":
return "fake_vif_ref"
else:
raise exception.Exception("VIF existed")
return "Unexpected call_xenapi: %s.%s" % (method, args)
class XenVIFDriverTestBase(stubs.XenAPITestBaseNoDB):
def setUp(self):
super(XenVIFDriverTestBase, self).setUp()
self._session = mock.Mock()
self._session.call_xenapi.side_effect = fake_call_xenapi
def mock_patch_object(self, target, attribute, return_val=None,
side_effect=None):
"""Utilility function to mock object's attribute at runtime:
Some methods are dynamic, so standard mocking does not work
and we need to mock them at runtime.
e.g. self._session.VIF.get_record which is dynamically
created via the override function of __getattr__.
"""
patcher = mock.patch.object(target, attribute,
return_value=return_val,
side_effect=side_effect)
mock_one = patcher.start()
self.addCleanup(patcher.stop)
return mock_one
class XenVIFDriverTestCase(XenVIFDriverTestBase):
def setUp(self):
super(XenVIFDriverTestCase, self).setUp()
self.base_driver = vif.XenVIFDriver(self._session)
def test_get_vif_ref(self):
vm_ref = "fake_vm_ref"
vif_ref = 'fake_vif_ref'
ret_vif_ref = self.base_driver._get_vif_ref(fake_vif, vm_ref)
self.assertEqual(vif_ref, ret_vif_ref)
expected = [mock.call('VM.get_VIFs', vm_ref),
mock.call('VIF.get_record', vif_ref)]
self.assertEqual(expected, self._session.call_xenapi.call_args_list)
def test_get_vif_ref_none_and_exception(self):
vm_ref = "fake_vm_ref"
vif = {'address': "no_match_vif_address"}
ret_vif_ref = self.base_driver._get_vif_ref(vif, vm_ref)
self.assertIsNone(ret_vif_ref)
expected = [mock.call('VM.get_VIFs', vm_ref),
mock.call('VIF.get_record', 'fake_vif_ref'),
mock.call('VIF.get_record', 'fake_vif_ref_A2')]
self.assertEqual(expected, self._session.call_xenapi.call_args_list)
def test_create_vif(self):
vif_rec = "fake_vif_rec"
vm_ref = "fake_vm_ref"
ret_vif_ref = self.base_driver._create_vif(fake_vif, vif_rec, vm_ref)
self.assertEqual("fake_vif_ref", ret_vif_ref)
expected = [mock.call('VIF.create', vif_rec)]
self.assertEqual(expected, self._session.call_xenapi.call_args_list)
def test_create_vif_exception(self):
self.assertRaises(exception.NovaException,
self.base_driver._create_vif,
"fake_vif", "missing_vif_rec", "fake_vm_ref")
@mock.patch.object(vif.XenVIFDriver, '_get_vif_ref',
return_value='fake_vif_ref')
def test_unplug(self, mock_get_vif_ref):
instance = {'name': "fake_instance"}
vm_ref = "fake_vm_ref"
self.base_driver.unplug(instance, fake_vif, vm_ref)
expected = [mock.call('VIF.destroy', 'fake_vif_ref')]
self.assertEqual(expected, self._session.call_xenapi.call_args_list)
@mock.patch.object(vif.XenVIFDriver, '_get_vif_ref',
return_value='missing_vif_ref')
def test_unplug_exception(self, mock_get_vif_ref):
instance = "fake_instance"
vm_ref = "fake_vm_ref"
self.assertRaises(exception.NovaException,
self.base_driver.unplug,
instance, fake_vif, vm_ref)
class XenAPIBridgeDriverTestCase(XenVIFDriverTestBase, object):
def setUp(self):
super(XenAPIBridgeDriverTestCase, self).setUp()
self.bridge_driver = vif.XenAPIBridgeDriver(self._session)
@mock.patch.object(vif.XenAPIBridgeDriver, '_ensure_vlan_bridge',
return_value='fake_network_ref')
@mock.patch.object(vif.XenVIFDriver, '_create_vif',
return_value='fake_vif_ref')
def test_plug_create_vlan(self, mock_create_vif, mock_ensure_vlan_bridge):
instance = {'name': "fake_instance_name"}
network = model.Network()
network._set_meta({'should_create_vlan': True})
vif = model.VIF()
vif._set_meta({'rxtx_cap': 1})
vif['network'] = network
vif['address'] = "fake_address"
vm_ref = "fake_vm_ref"
device = 1
ret_vif_ref = self.bridge_driver.plug(instance, vif, vm_ref, device)
self.assertEqual('fake_vif_ref', ret_vif_ref)
class XenAPIOpenVswitchDriverTestCase(XenVIFDriverTestBase):
def setUp(self):
super(XenAPIOpenVswitchDriverTestCase, self).setUp()
self.ovs_driver = vif.XenAPIOpenVswitchDriver(self._session)
@mock.patch.object(vif.XenVIFDriver, '_create_vif',
return_value='fake_vif_ref')
@mock.patch.object(vif.XenAPIOpenVswitchDriver,
'create_vif_interim_network')
@mock.patch.object(vif.XenVIFDriver, '_get_vif_ref', return_value=None)
@mock.patch.object(vif.vm_utils, 'lookup', return_value='fake_vm_ref')
def test_plug(self, mock_lookup, mock_get_vif_ref,
mock_create_vif_interim_network,
mock_create_vif):
instance = {'name': "fake_instance_name"}
ret_vif_ref = self.ovs_driver.plug(
instance, fake_vif, vm_ref=None, device=1)
self.assertTrue(mock_lookup.called)
self.assertTrue(mock_get_vif_ref.called)
self.assertTrue(mock_create_vif_interim_network.called)
self.assertTrue(mock_create_vif.called)
self.assertEqual('fake_vif_ref', ret_vif_ref)
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_delete_linux_bridge')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_delete_linux_port')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_device_exists',
return_value=True)
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_ovs_del_br')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_ovs_del_port')
@mock.patch.object(network_utils, 'find_network_with_name_label',
return_value='fake_network')
@mock.patch.object(vif.XenVIFDriver, 'unplug')
def test_unplug(self, mock_super_unplug,
mock_find_network_with_name_label,
mock_ovs_del_port,
mock_ovs_del_br,
mock_device_exists,
mock_delete_linux_port,
mock_delete_linux_bridge):
instance = {'name': "fake_instance"}
vm_ref = "fake_vm_ref"
mock_network_get_VIFs = self.mock_patch_object(
self._session.network, 'get_VIFs', return_val=None)
mock_network_get_bridge = self.mock_patch_object(
self._session.network, 'get_bridge', return_val='fake_bridge')
mock_network_destroy = self.mock_patch_object(
self._session.network, 'destroy')
self.ovs_driver.unplug(instance, fake_vif, vm_ref)
self.assertTrue(mock_super_unplug.called)
self.assertTrue(mock_find_network_with_name_label.called)
self.assertTrue(mock_network_get_VIFs.called)
self.assertTrue(mock_network_get_bridge.called)
self.assertEqual(mock_ovs_del_port.call_count, 2)
self.assertTrue(mock_network_destroy.called)
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_ovs_del_br')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_ovs_del_port')
@mock.patch.object(network_utils, 'find_network_with_name_label',
return_value='fake_network')
@mock.patch.object(vif.XenVIFDriver, 'unplug')
def test_unplug_exception(self, mock_super_unplug,
mock_find_network_with_name_label,
mock_ovs_del_port,
mock_ovs_del_br):
instance = {'name': "fake_instance"}
vm_ref = "fake_vm_ref"
self.mock_patch_object(
self._session.network, 'get_VIFs', return_val=None)
self.mock_patch_object(
self._session.network, 'get_bridge', return_val='fake_bridge')
self.mock_patch_object(
self._session.network, 'destroy',
side_effect=test.TestingException)
self.assertRaises(exception.VirtualInterfaceUnplugException,
self.ovs_driver.unplug, instance, fake_vif,
vm_ref)
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_brctl_add_if')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_create_linux_bridge')
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_ovs_add_port')
def test_post_start_actions(self, mock_ovs_add_port,
mock_create_linux_bridge,
mock_brctl_add_if):
vif_ref = "fake_vif_ref"
instance = {'name': 'fake_instance_name'}
fake_vif_rec = {'uuid': fake_vif['uuid'],
'MAC': fake_vif['address'],
'network': 'fake_network',
'other_config': {
'nicira-iface-id': 'fake-nicira-iface-id'}
}
mock_VIF_get_record = self.mock_patch_object(
self._session.VIF, 'get_record', return_val=fake_vif_rec)
mock_network_get_bridge = self.mock_patch_object(
self._session.network, 'get_bridge',
return_val='fake_bridge_name')
mock_network_get_uuid = self.mock_patch_object(
self._session.network, 'get_uuid',
return_val='fake_network_uuid')
self.ovs_driver.post_start_actions(instance, vif_ref)
self.assertTrue(mock_VIF_get_record.called)
self.assertTrue(mock_network_get_bridge.called)
self.assertTrue(mock_network_get_uuid.called)
self.assertEqual(mock_ovs_add_port.call_count, 1)
self.assertTrue(mock_brctl_add_if.called)
@mock.patch.object(network_utils, 'find_network_with_name_label',
return_value="exist_network_ref")
def test_create_vif_interim_network_exist(self,
mock_find_network_with_name_label):
mock_network_create = self.mock_patch_object(
self._session.network, 'create', return_val='new_network_ref')
network_ref = self.ovs_driver.create_vif_interim_network(fake_vif)
self.assertFalse(mock_network_create.called)
self.assertEqual(network_ref, 'exist_network_ref')
@mock.patch.object(network_utils, 'find_network_with_name_label',
return_value=None)
def test_create_vif_interim_network_new(self,
mock_find_network_with_name_label):
mock_network_create = self.mock_patch_object(
self._session.network, 'create', return_val='new_network_ref')
network_ref = self.ovs_driver.create_vif_interim_network(fake_vif)
self.assertTrue(mock_network_create.called)
self.assertEqual(network_ref, 'new_network_ref')