Move MidonetInterfaceDriver and use mm-ctl
* Change the plug method in MidonetInterfaceDriver to use mm-ctl * Move MidonetInterfaceDriver to interface.py * adapt interface driver midonet unit tests to mm-ctl Change-Id: Ib6cfbc212b793fa939cad17017c0b2b8b0a5b7fb Closes-Bug: #1245797
This commit is contained in:
parent
da139f6156
commit
e19a2ae0b3
@ -18,6 +18,7 @@ kill_dnsmasq_usr: KillFilter, root, /usr/sbin/dnsmasq, -9, -HUP
|
||||
|
||||
ovs-vsctl: CommandFilter, ovs-vsctl, root
|
||||
ivs-ctl: CommandFilter, ivs-ctl, root
|
||||
mm-ctl: CommandFilter, mm-ctl, root
|
||||
dhcp_release: CommandFilter, dhcp_release, root
|
||||
|
||||
# metadata proxy
|
||||
|
@ -15,6 +15,7 @@ haproxy: CommandFilter, haproxy, root
|
||||
kill_haproxy_usr: KillFilter, root, /usr/sbin/haproxy, -9, -HUP
|
||||
|
||||
ovs-vsctl: CommandFilter, ovs-vsctl, root
|
||||
mm-ctl: CommandFilter, mm-ctl, root
|
||||
|
||||
# ip_lib
|
||||
ip: IpFilter, ip, root
|
||||
|
@ -219,6 +219,50 @@ class OVSInterfaceDriver(LinuxInterfaceDriver):
|
||||
device_name)
|
||||
|
||||
|
||||
class MidonetInterfaceDriver(LinuxInterfaceDriver):
|
||||
|
||||
def plug(self, network_id, port_id, device_name, mac_address,
|
||||
bridge=None, namespace=None, prefix=None):
|
||||
"""This method is called by the Dhcp agent or by the L3 agent
|
||||
when a new network is created
|
||||
"""
|
||||
if not ip_lib.device_exists(device_name,
|
||||
self.root_helper,
|
||||
namespace=namespace):
|
||||
ip = ip_lib.IPWrapper(self.root_helper)
|
||||
tap_name = device_name.replace(prefix or 'tap', 'tap')
|
||||
|
||||
# Create ns_dev in a namespace if one is configured.
|
||||
root_dev, ns_dev = ip.add_veth(tap_name, device_name,
|
||||
namespace2=namespace)
|
||||
|
||||
ns_dev.link.set_address(mac_address)
|
||||
|
||||
# Add an interface created by ovs to the namespace.
|
||||
namespace_obj = ip.ensure_namespace(namespace)
|
||||
namespace_obj.add_device_to_namespace(ns_dev)
|
||||
|
||||
ns_dev.link.set_up()
|
||||
root_dev.link.set_up()
|
||||
|
||||
cmd = ['mm-ctl', '--bind-port', port_id, device_name]
|
||||
utils.execute(cmd, self.root_helper)
|
||||
|
||||
else:
|
||||
LOG.warn(_("Device %s already exists"), device_name)
|
||||
|
||||
def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
|
||||
# the port will be deleted by the dhcp agent that will call the plugin
|
||||
device = ip_lib.IPDevice(device_name,
|
||||
self.root_helper,
|
||||
namespace)
|
||||
device.link.delete()
|
||||
LOG.debug(_("Unplugged interface '%s'"), device_name)
|
||||
|
||||
ip_lib.IPWrapper(
|
||||
self.root_helper, namespace).garbage_collect_namespace()
|
||||
|
||||
|
||||
class IVSInterfaceDriver(LinuxInterfaceDriver):
|
||||
"""Driver for creating an internal interface on an IVS bridge."""
|
||||
|
||||
|
@ -19,13 +19,7 @@
|
||||
# @author: Tomoe Sugihara, Midokura Japan KK
|
||||
# @author: Ryu Ishimoto, Midokura Japan KK
|
||||
|
||||
from midonetclient import api
|
||||
from oslo.config import cfg
|
||||
from webob import exc as w_exc
|
||||
|
||||
from neutron.agent.linux import dhcp
|
||||
from neutron.agent.linux import interface
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.midonet.common import config # noqa
|
||||
|
||||
@ -59,83 +53,3 @@ class DhcpNoOpDriver(dhcp.DhcpLocalProcess):
|
||||
|
||||
def spawn_process(self):
|
||||
pass
|
||||
|
||||
|
||||
class MidonetInterfaceDriver(interface.LinuxInterfaceDriver):
|
||||
def __init__(self, conf):
|
||||
super(MidonetInterfaceDriver, self).__init__(conf)
|
||||
# Read config values
|
||||
midonet_conf = conf.MIDONET
|
||||
midonet_uri = midonet_conf.midonet_uri
|
||||
admin_user = midonet_conf.username
|
||||
admin_pass = midonet_conf.password
|
||||
admin_project_id = midonet_conf.project_id
|
||||
|
||||
self.mido_api = api.MidonetApi(midonet_uri, admin_user,
|
||||
admin_pass,
|
||||
project_id=admin_project_id)
|
||||
|
||||
def _get_host_uuid(self):
|
||||
"""Get MidoNet host id from host_uuid.properties file."""
|
||||
f = open(cfg.CONF.MIDONET.midonet_host_uuid_path)
|
||||
lines = f.readlines()
|
||||
host_uuid = filter(lambda x: x.startswith('host_uuid='),
|
||||
lines)[0].strip()[len('host_uuid='):]
|
||||
return host_uuid
|
||||
|
||||
def plug(self, network_id, port_id, device_name, mac_address,
|
||||
bridge=None, namespace=None, prefix=None):
|
||||
"""This method is called by the Dhcp agent or by the L3 agent
|
||||
when a new network is created
|
||||
"""
|
||||
if not ip_lib.device_exists(device_name,
|
||||
self.root_helper,
|
||||
namespace=namespace):
|
||||
ip = ip_lib.IPWrapper(self.root_helper)
|
||||
tap_name = device_name.replace(prefix or 'tap', 'tap')
|
||||
|
||||
# Create ns_dev in a namespace if one is configured.
|
||||
root_dev, ns_dev = ip.add_veth(tap_name,
|
||||
device_name,
|
||||
namespace2=namespace)
|
||||
|
||||
ns_dev.link.set_address(mac_address)
|
||||
|
||||
# Add an interface created by ovs to the namespace.
|
||||
namespace_obj = ip.ensure_namespace(namespace)
|
||||
namespace_obj.add_device_to_namespace(ns_dev)
|
||||
|
||||
ns_dev.link.set_up()
|
||||
root_dev.link.set_up()
|
||||
|
||||
vport_id = port_id
|
||||
host_dev_name = device_name
|
||||
|
||||
# create if-vport mapping.
|
||||
host_uuid = self._get_host_uuid()
|
||||
try:
|
||||
host = self.mido_api.get_host(host_uuid)
|
||||
except w_exc.HTTPError as e:
|
||||
LOG.error(_('Failed to create a if-vport mapping on host=%s'),
|
||||
host_uuid)
|
||||
raise e
|
||||
try:
|
||||
self.mido_api.add_host_interface_port(
|
||||
host, vport_id, host_dev_name)
|
||||
except w_exc.HTTPError:
|
||||
LOG.warn(_(
|
||||
'Faild binding vport=%(vport)s to device=%(device)s'),
|
||||
{"vport": vport_id, "device": host_dev_name})
|
||||
else:
|
||||
LOG.warn(_("Device %s already exists"), device_name)
|
||||
|
||||
def unplug(self, device_name, bridge=None, namespace=None, prefix=None):
|
||||
# the port will be deleted by the dhcp agent that will call the plugin
|
||||
device = ip_lib.IPDevice(device_name,
|
||||
self.root_helper,
|
||||
namespace)
|
||||
device.link.delete()
|
||||
LOG.debug(_("Unplugged interface '%s'"), device_name)
|
||||
|
||||
ip_lib.IPWrapper(
|
||||
self.root_helper, namespace).garbage_collect_namespace()
|
||||
|
@ -19,93 +19,16 @@
|
||||
# @author: Rossella Sblendido, Midokura Japan KK
|
||||
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
import sys
|
||||
sys.modules["midonetclient"] = mock.Mock()
|
||||
|
||||
from neutron.agent.common import config
|
||||
from neutron.agent.linux import dhcp
|
||||
from neutron.agent.linux import interface
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.common import config as base_config
|
||||
from neutron.openstack.common import uuidutils
|
||||
import neutron.plugins.midonet.agent.midonet_driver as driver
|
||||
from neutron.tests import base
|
||||
|
||||
|
||||
class MidoInterfaceDriverTestCase(base.BaseTestCase):
|
||||
def setUp(self):
|
||||
self.conf = config.setup_conf()
|
||||
self.conf.register_opts(interface.OPTS)
|
||||
config.register_root_helper(self.conf)
|
||||
self.ip_dev_p = mock.patch.object(ip_lib, 'IPDevice')
|
||||
self.ip_dev = self.ip_dev_p.start()
|
||||
self.ip_p = mock.patch.object(ip_lib, 'IPWrapper')
|
||||
self.ip = self.ip_p.start()
|
||||
self.device_exists_p = mock.patch.object(ip_lib, 'device_exists')
|
||||
self.device_exists = self.device_exists_p.start()
|
||||
self.device_exists.return_value = False
|
||||
self.addCleanup(mock.patch.stopall)
|
||||
midonet_opts = [
|
||||
cfg.StrOpt('midonet_uri',
|
||||
default='http://localhost:8080/midonet-api',
|
||||
help=_('MidoNet API server URI.')),
|
||||
cfg.StrOpt('username', default='admin',
|
||||
help=_('MidoNet admin username.')),
|
||||
cfg.StrOpt('password', default='passw0rd',
|
||||
secret=True,
|
||||
help=_('MidoNet admin password.')),
|
||||
cfg.StrOpt('project_id',
|
||||
default='77777777-7777-7777-7777-777777777777',
|
||||
help=_('ID of the project that MidoNet admin user'
|
||||
'belongs to.'))
|
||||
]
|
||||
self.conf.register_opts(midonet_opts, "MIDONET")
|
||||
self.driver = driver.MidonetInterfaceDriver(self.conf)
|
||||
self.root_dev = mock.Mock()
|
||||
self.ns_dev = mock.Mock()
|
||||
self.ip().add_veth = mock.Mock(return_value=(
|
||||
self.root_dev, self.ns_dev))
|
||||
self.driver._get_host_uuid = mock.Mock(
|
||||
return_value=uuidutils.generate_uuid())
|
||||
self.network_id = uuidutils.generate_uuid()
|
||||
self.port_id = uuidutils.generate_uuid()
|
||||
self.device_name = "tap0"
|
||||
self.mac_address = "aa:bb:cc:dd:ee:ff"
|
||||
self.bridge = "br-test"
|
||||
self.namespace = "ns-test"
|
||||
super(MidoInterfaceDriverTestCase, self).setUp()
|
||||
|
||||
def test_plug(self):
|
||||
self.driver.plug(
|
||||
self.network_id, self.port_id,
|
||||
self.device_name, self.mac_address,
|
||||
self.bridge, self.namespace)
|
||||
|
||||
expected = [mock.call(), mock.call('sudo'),
|
||||
mock.call().add_veth(self.device_name,
|
||||
self.device_name,
|
||||
namespace2=self.namespace),
|
||||
mock.call().ensure_namespace(self.namespace),
|
||||
mock.call().ensure_namespace().add_device_to_namespace(
|
||||
mock.ANY)]
|
||||
self.ns_dev.assert_has_calls(
|
||||
[mock.call.link.set_address(self.mac_address)])
|
||||
|
||||
self.root_dev.assert_has_calls([mock.call.link.set_up()])
|
||||
self.ns_dev.assert_has_calls([mock.call.link.set_up()])
|
||||
self.ip.assert_has_calls(expected, True)
|
||||
|
||||
def test_unplug(self):
|
||||
self.driver.unplug(self.device_name, self.bridge, self.namespace)
|
||||
|
||||
self.ip_dev.assert_has_calls([
|
||||
mock.call(self.device_name, self.driver.root_helper,
|
||||
self.namespace),
|
||||
mock.call().link.delete()])
|
||||
self.ip.assert_has_calls(mock.call().garbage_collect_namespace())
|
||||
|
||||
|
||||
class FakeNetwork:
|
||||
id = 'aaaabbbb-cccc-dddd-eeee-ffff00001111'
|
||||
namespace = 'qdhcp-ns'
|
||||
|
@ -23,6 +23,7 @@ from neutron.agent.linux import interface
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.agent.linux import utils
|
||||
from neutron.extensions.flavor import (FLAVOR_NETWORK)
|
||||
from neutron.openstack.common import uuidutils
|
||||
from neutron.tests import base
|
||||
|
||||
|
||||
@ -468,3 +469,59 @@ class TestIVSInterfaceDriver(TestBase):
|
||||
execute.assert_called_once_with(ivsctl_cmd, 'sudo')
|
||||
self.ip_dev.assert_has_calls([mock.call('ns-0', 'sudo', None),
|
||||
mock.call().link.delete()])
|
||||
|
||||
|
||||
class TestMidonetInterfaceDriver(TestBase):
|
||||
def setUp(self):
|
||||
self.conf = config.setup_conf()
|
||||
self.conf.register_opts(interface.OPTS)
|
||||
config.register_root_helper(self.conf)
|
||||
self.device_exists_p = mock.patch.object(ip_lib, 'device_exists')
|
||||
self.device_exists = self.device_exists_p.start()
|
||||
self.addCleanup(mock.patch.stopall)
|
||||
self.driver = interface.MidonetInterfaceDriver(self.conf)
|
||||
self.network_id = uuidutils.generate_uuid()
|
||||
self.port_id = uuidutils.generate_uuid()
|
||||
self.device_name = "tap0"
|
||||
self.mac_address = "aa:bb:cc:dd:ee:ff"
|
||||
self.bridge = "br-test"
|
||||
self.namespace = "ns-test"
|
||||
super(TestMidonetInterfaceDriver, self).setUp()
|
||||
|
||||
def test_plug(self):
|
||||
cmd = ['mm-ctl', '--bind-port', self.port_id, 'tap0']
|
||||
self.device_exists.return_value = False
|
||||
|
||||
root_dev = mock.Mock()
|
||||
ns_dev = mock.Mock()
|
||||
self.ip().add_veth = mock.Mock(return_value=(root_dev, ns_dev))
|
||||
with mock.patch.object(utils, 'execute') as execute:
|
||||
self.driver.plug(
|
||||
self.network_id, self.port_id,
|
||||
self.device_name, self.mac_address,
|
||||
self.bridge, self.namespace)
|
||||
execute.assert_called_once_with(cmd, 'sudo')
|
||||
|
||||
expected = [mock.call(), mock.call('sudo'),
|
||||
mock.call().add_veth(self.device_name,
|
||||
self.device_name,
|
||||
namespace2=self.namespace),
|
||||
mock.call().ensure_namespace(self.namespace),
|
||||
mock.call().ensure_namespace().add_device_to_namespace(
|
||||
mock.ANY)]
|
||||
|
||||
ns_dev.assert_has_calls(
|
||||
[mock.call.link.set_address(self.mac_address)])
|
||||
|
||||
root_dev.assert_has_calls([mock.call.link.set_up()])
|
||||
ns_dev.assert_has_calls([mock.call.link.set_up()])
|
||||
self.ip.assert_has_calls(expected, True)
|
||||
|
||||
def test_unplug(self):
|
||||
self.driver.unplug(self.device_name, self.bridge, self.namespace)
|
||||
|
||||
self.ip_dev.assert_has_calls([
|
||||
mock.call(self.device_name, self.driver.root_helper,
|
||||
self.namespace),
|
||||
mock.call().link.delete()])
|
||||
self.ip.assert_has_calls(mock.call().garbage_collect_namespace())
|
||||
|
Loading…
Reference in New Issue
Block a user