Merge "XenAPI: OVS agent updates the wrong port with Neutron"
This commit is contained in:
commit
6a119fc720
@ -135,6 +135,11 @@ class VirtualInterfacePlugException(NovaException):
|
||||
msg_fmt = _("Virtual interface plugin failed")
|
||||
|
||||
|
||||
class VirtualInterfaceUnplugException(NovaException):
|
||||
msg_fmt = _("Virtual interface unplugin failed: "
|
||||
"%(reason)s")
|
||||
|
||||
|
||||
class GlanceConnectionFailed(NovaException):
|
||||
msg_fmt = _("Connection to glance host %(server)s failed: "
|
||||
"%(reason)s")
|
||||
|
@ -55,6 +55,11 @@ class ObjectsTestCase(stubs.XenAPITestBaseNoDB):
|
||||
vdi.get_X("ref")
|
||||
self.session.call_xenapi.assert_called_once_with("VDI.get_X", "ref")
|
||||
|
||||
def test_VIF(self):
|
||||
vdi = objects.VIF(self.session)
|
||||
vdi.get_X("ref")
|
||||
self.session.call_xenapi.assert_called_once_with("VIF.get_X", "ref")
|
||||
|
||||
def test_VBD(self):
|
||||
vbd = objects.VBD(self.session)
|
||||
vbd.get_X("ref")
|
||||
|
@ -100,6 +100,10 @@ class ApplySessionHelpersTestCase(stubs.XenAPITestBaseNoDB):
|
||||
self.session.VDI.get_X("ref")
|
||||
self.session.call_xenapi.assert_called_once_with("VDI.get_X", "ref")
|
||||
|
||||
def test_apply_session_helpers_add_VIF(self):
|
||||
self.session.VIF.get_X("ref")
|
||||
self.session.call_xenapi.assert_called_once_with("VIF.get_X", "ref")
|
||||
|
||||
def test_apply_session_helpers_add_VBD(self):
|
||||
self.session.VBD.get_X("ref")
|
||||
self.session.call_xenapi.assert_called_once_with("VBD.get_X", "ref")
|
||||
|
@ -17,6 +17,7 @@ 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
|
||||
@ -67,6 +68,22 @@ class XenVIFDriverTestBase(stubs.XenAPITestBaseNoDB):
|
||||
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):
|
||||
@ -149,41 +166,126 @@ class XenAPIBridgeDriverTestCase(XenVIFDriverTestBase, object):
|
||||
ret_vif_ref = self.bridge_driver.plug(instance, vif, vm_ref, device)
|
||||
self.assertEqual('fake_vif_ref', ret_vif_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.bridge_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)
|
||||
|
||||
|
||||
class XenAPIOpenVswitchDriverTestCase(XenVIFDriverTestBase):
|
||||
def setUp(self):
|
||||
super(XenAPIOpenVswitchDriverTestCase, self).setUp()
|
||||
self.ovs_driver = vif.XenAPIOpenVswitchDriver(self._session)
|
||||
|
||||
@mock.patch.object(network_utils, 'find_network_with_bridge',
|
||||
return_value='fake_network_ref')
|
||||
@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)
|
||||
def test_plug(self, mock_get_vif_ref, mock_create_vif,
|
||||
mock_find_network_with_bridge):
|
||||
@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"}
|
||||
vm_ref = "fake_vm_ref"
|
||||
device = 1
|
||||
ret_vif_ref = self.ovs_driver.plug(instance, fake_vif, vm_ref, device)
|
||||
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.XenVIFDriver, '_get_vif_ref',
|
||||
return_value='fake_vif_ref')
|
||||
def test_unplug(self, mock_get_vif_ref):
|
||||
@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):
|
||||
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)
|
||||
|
||||
expected = [mock.call('VIF.destroy', 'fake_vif_ref')]
|
||||
self.assertEqual(expected, self._session.call_xenapi.call_args_list)
|
||||
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, '_ovs_add_patch_port')
|
||||
@mock.patch.object(vif.XenAPIOpenVswitchDriver, '_ovs_map_external_ids')
|
||||
def test_post_start_actions(self, mock_ovs_map_external_ids,
|
||||
mock_ovs_add_patch_port):
|
||||
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_patch_port.call_count, 2)
|
||||
self.assertTrue(mock_ovs_map_external_ids.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')
|
||||
|
@ -100,6 +100,12 @@ class VDI(XenAPISessionObject):
|
||||
super(VDI, self).__init__(session, "VDI")
|
||||
|
||||
|
||||
class VIF(XenAPISessionObject):
|
||||
"""Virtual Network Interface."""
|
||||
def __init__(self, session):
|
||||
super(VIF, self).__init__(session, "VIF")
|
||||
|
||||
|
||||
class SR(XenAPISessionObject):
|
||||
"""Storage Repository."""
|
||||
def __init__(self, session):
|
||||
|
@ -53,6 +53,7 @@ def apply_session_helpers(session):
|
||||
session.VM = cli_objects.VM(session)
|
||||
session.SR = cli_objects.SR(session)
|
||||
session.VDI = cli_objects.VDI(session)
|
||||
session.VIF = cli_objects.VIF(session)
|
||||
session.VBD = cli_objects.VBD(session)
|
||||
session.PBD = cli_objects.PBD(session)
|
||||
session.PIF = cli_objects.PIF(session)
|
||||
@ -69,7 +70,7 @@ class XenAPISession(object):
|
||||
# changed in development environments.
|
||||
# MAJOR VERSION: Incompatible changes with the plugins
|
||||
# MINOR VERSION: Compatible changes, new plguins, etc
|
||||
PLUGIN_REQUIRED_VERSION = '1.4'
|
||||
PLUGIN_REQUIRED_VERSION = '1.5'
|
||||
|
||||
def __init__(self, url, user, pw):
|
||||
version_string = version.version_string_with_package()
|
||||
|
@ -760,7 +760,7 @@ class SessionBase(object):
|
||||
return base64.b64encode(zlib.compress("dom_id: %s" % dom_id))
|
||||
|
||||
def _plugin_nova_plugin_version_get_version(self, method, args):
|
||||
return pickle.dumps("1.4")
|
||||
return pickle.dumps("1.5")
|
||||
|
||||
def _plugin_xenhost_query_gc(self, method, args):
|
||||
return pickle.dumps("False")
|
||||
|
@ -23,6 +23,7 @@ import nova.conf
|
||||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova.i18n import _LW
|
||||
from nova.network import model as network_model
|
||||
from nova.virt.xenapi import network_utils
|
||||
from nova.virt.xenapi import vm_utils
|
||||
|
||||
@ -180,11 +181,18 @@ class XenAPIBridgeDriver(XenVIFDriver):
|
||||
def unplug(self, instance, vif, vm_ref):
|
||||
super(XenAPIBridgeDriver, self).unplug(instance, vif, vm_ref)
|
||||
|
||||
def post_start_actions(self, instance, vif_ref):
|
||||
"""no further actions needed for this driver type"""
|
||||
pass
|
||||
|
||||
|
||||
class XenAPIOpenVswitchDriver(XenVIFDriver):
|
||||
"""VIF driver for Open vSwitch with XenAPI."""
|
||||
|
||||
def plug(self, instance, vif, vm_ref=None, device=None):
|
||||
"""create an interim network for this vif; and build
|
||||
the vif_rec which will be used by xapi to create VM vif
|
||||
"""
|
||||
if not vm_ref:
|
||||
vm_ref = vm_utils.lookup(self._session, instance['name'])
|
||||
|
||||
@ -198,10 +206,10 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
||||
if not device:
|
||||
device = 0
|
||||
|
||||
# with OVS model, always plug into an OVS integration bridge
|
||||
# that is already created
|
||||
network_ref = network_utils.find_network_with_bridge(
|
||||
self._session, CONF.xenserver.ovs_integration_bridge)
|
||||
# Create an interim network for each VIF, so dom0 has a single
|
||||
# bridge for each device (the emulated and PV ethernet devices
|
||||
# will both be on this bridge.
|
||||
network_ref = self.create_vif_interim_network(vif)
|
||||
vif_rec = {}
|
||||
vif_rec['device'] = str(device)
|
||||
vif_rec['network'] = network_ref
|
||||
@ -216,4 +224,157 @@ class XenAPIOpenVswitchDriver(XenVIFDriver):
|
||||
return self._create_vif(vif, vif_rec, vm_ref)
|
||||
|
||||
def unplug(self, instance, vif, vm_ref):
|
||||
"""unplug vif:
|
||||
1. unplug and destroy vif.
|
||||
2. delete the patch port pair between the integration bridge and
|
||||
the interim network.
|
||||
3. destroy the interim network
|
||||
4. delete the OVS bridge service for the interim network
|
||||
"""
|
||||
super(XenAPIOpenVswitchDriver, self).unplug(instance, vif, vm_ref)
|
||||
|
||||
net_name = self.get_vif_interim_net_name(vif)
|
||||
network = network_utils.find_network_with_name_label(
|
||||
self._session, net_name)
|
||||
if network is None:
|
||||
return
|
||||
vifs = self._session.network.get_VIFs(network)
|
||||
if vifs:
|
||||
# only remove the interim network when it's empty.
|
||||
# for resize/migrate on local host, vifs on both of the
|
||||
# source and target VM will be connected to the same
|
||||
# interim network.
|
||||
return
|
||||
LOG.debug('destroying patch port pair for vif: vif_id=%(vif_id)s',
|
||||
{'vif_id': vif['id']})
|
||||
bridge_name = self._session.network.get_bridge(network)
|
||||
patch_port1, patch_port2 = self._get_patch_port_pair_names(vif['id'])
|
||||
try:
|
||||
# delete the patch port pair
|
||||
self._ovs_del_port(bridge_name, patch_port1)
|
||||
self._ovs_del_port(CONF.xenserver.ovs_integration_bridge,
|
||||
patch_port2)
|
||||
except Exception as e:
|
||||
LOG.warn(_LW("Failed to delete patch port pair for vif %(if)s,"
|
||||
" exception:%(exception)s"),
|
||||
{'if': vif, 'exception': e}, instance=instance)
|
||||
raise exception.VirtualInterfaceUnplugException(
|
||||
reason=_("Failed to delete patch port pair"))
|
||||
|
||||
LOG.debug('destroying network: network=%(network)s,'
|
||||
'bridge=%(br)s',
|
||||
{'network': network, 'br': bridge_name})
|
||||
try:
|
||||
self._session.network.destroy(network)
|
||||
# delete bridge if it still exists.
|
||||
# As there is patch port existing on this bridge when destroying
|
||||
# the VM vif (which happens when shutdown the VM), the bridge
|
||||
# won't be destroyed automatically by XAPI. So let's destroy it
|
||||
# at here.
|
||||
self._ovs_del_br(bridge_name)
|
||||
except Exception as e:
|
||||
LOG.warn(_LW("Failed to delete bridge for vif %(if)s, "
|
||||
"exception:%(exception)s"),
|
||||
{'if': vif, 'exception': e}, instance=instance)
|
||||
raise exception.VirtualInterfaceUnplugException(
|
||||
reason=_("Failed to delete bridge"))
|
||||
|
||||
def post_start_actions(self, instance, vif_ref):
|
||||
"""Do needed actions post vif start:
|
||||
plug the interim ovs bridge to the integration bridge;
|
||||
set external_ids to the int-br port which will service
|
||||
for this vif.
|
||||
"""
|
||||
vif_rec = self._session.VIF.get_record(vif_ref)
|
||||
network_ref = vif_rec['network']
|
||||
bridge_name = self._session.network.get_bridge(network_ref)
|
||||
network_uuid = self._session.network.get_uuid(network_ref)
|
||||
iface_id = vif_rec['other_config']['nicira-iface-id']
|
||||
patch_port1, patch_port2 = self._get_patch_port_pair_names(iface_id)
|
||||
LOG.debug('plug_ovs_bridge: port1=%(port1)s, port2=%(port2)s,'
|
||||
'network_uuid=%(uuid)s, bridge_name=%(bridge_name)s',
|
||||
{'port1': patch_port1, 'port2': patch_port2,
|
||||
'uuid': network_uuid, 'bridge_name': bridge_name})
|
||||
if bridge_name is None:
|
||||
raise exception.VirtualInterfacePlugException(
|
||||
_("Failed to find bridge for vif"))
|
||||
|
||||
self._ovs_add_patch_port(bridge_name, patch_port1, patch_port2)
|
||||
self._ovs_add_patch_port(CONF.xenserver.ovs_integration_bridge,
|
||||
patch_port2, patch_port1)
|
||||
self._ovs_map_external_ids(patch_port2, vif_rec)
|
||||
|
||||
def get_vif_interim_net_name(self, vif):
|
||||
return ("net-" + vif['id'])[:network_model.NIC_NAME_LEN]
|
||||
|
||||
def create_vif_interim_network(self, vif):
|
||||
net_name = self.get_vif_interim_net_name(vif)
|
||||
network_rec = {'name_label': net_name,
|
||||
'name_description': "interim network for vif",
|
||||
'other_config': {}}
|
||||
network_ref = network_utils.find_network_with_name_label(
|
||||
self._session, net_name)
|
||||
if network_ref:
|
||||
# already exist, just return
|
||||
# in some scenarios: e..g resize/migrate, it won't create new
|
||||
# interim network.
|
||||
return network_ref
|
||||
try:
|
||||
network_ref = self._session.network.create(network_rec)
|
||||
except Exception as e:
|
||||
LOG.warn(_LW("Failed to create interim network for vif %(if)s, "
|
||||
"exception:%(exception)s"),
|
||||
{'if': vif, 'exception': e})
|
||||
raise exception.VirtualInterfacePlugException(
|
||||
_("Failed to create the interim network for vif"))
|
||||
return network_ref
|
||||
|
||||
def _get_patch_port_pair_names(self, iface_id):
|
||||
return (("pp1-%s" % iface_id)[:network_model.NIC_NAME_LEN],
|
||||
("pp2-%s" % iface_id)[:network_model.NIC_NAME_LEN])
|
||||
|
||||
def _ovs_add_patch_port(self, bridge_name, port_name, peer_port_name):
|
||||
cmd = 'ovs_add_patch_port'
|
||||
args = {'bridge_name': bridge_name,
|
||||
'port_name': port_name,
|
||||
'peer_port_name': peer_port_name
|
||||
}
|
||||
self._exec_dom0_cmd(cmd, args)
|
||||
|
||||
def _ovs_del_port(self, bridge_name, port_name):
|
||||
cmd = 'ovs_del_port'
|
||||
args = {'bridge_name': bridge_name,
|
||||
'port_name': port_name
|
||||
}
|
||||
self._exec_dom0_cmd(cmd, args)
|
||||
|
||||
def _ovs_del_br(self, bridge_name):
|
||||
cmd = 'ovs_del_br'
|
||||
args = {'bridge_name': bridge_name}
|
||||
self._exec_dom0_cmd(cmd, args)
|
||||
|
||||
def _ovs_set_if_external_id(self, interface, extneral_id, value):
|
||||
cmd = 'ovs_set_if_external_id'
|
||||
args = {'interface': interface,
|
||||
'extneral_id': extneral_id,
|
||||
'value': value}
|
||||
self._exec_dom0_cmd(cmd, args)
|
||||
|
||||
def _ovs_map_external_ids(self, interface, vif_rec):
|
||||
'''set external ids on the integration bridge vif
|
||||
'''
|
||||
mac = vif_rec['MAC']
|
||||
iface_id = vif_rec['other_config']['nicira-iface-id']
|
||||
vif_uuid = vif_rec['uuid']
|
||||
status = 'active'
|
||||
|
||||
self._ovs_set_if_external_id(interface, 'attached-mac', mac)
|
||||
self._ovs_set_if_external_id(interface, 'iface-id', iface_id)
|
||||
self._ovs_set_if_external_id(interface, 'xs-vif-uuid', vif_uuid)
|
||||
self._ovs_set_if_external_id(interface, 'iface-status', status)
|
||||
|
||||
def _exec_dom0_cmd(self, cmd, cmd_args):
|
||||
args = {'cmd': cmd,
|
||||
'args': cmd_args
|
||||
}
|
||||
self._session.call_plugin_serialized('xenhost', 'network_config', args)
|
||||
|
@ -333,6 +333,18 @@ class VMOps(object):
|
||||
if bad_volumes_callback and bad_devices:
|
||||
bad_volumes_callback(bad_devices)
|
||||
|
||||
# Do some operations which have to be done after start:
|
||||
# e.g. The vif's interim bridge won't be created until VM starts.
|
||||
# So the operations on the interim bridge have be done after
|
||||
# start.
|
||||
self._post_start_actions(instance)
|
||||
|
||||
def _post_start_actions(self, instance):
|
||||
vm_ref = vm_utils.lookup(self._session, instance['name'])
|
||||
vif_refs = self._session.call_xenapi("VM.get_VIFs", vm_ref)
|
||||
for vif_ref in vif_refs:
|
||||
self.vif_driver.post_start_actions(instance, vif_ref)
|
||||
|
||||
def _get_vdis_for_instance(self, context, instance, name_label,
|
||||
image_meta, image_type, block_device_info):
|
||||
"""Create or connect to all virtual disks for this instance."""
|
||||
@ -1920,13 +1932,20 @@ class VMOps(object):
|
||||
"""Creates vifs for an instance."""
|
||||
|
||||
LOG.debug("Creating vifs", instance=instance)
|
||||
vif_refs = []
|
||||
|
||||
# this function raises if vm_ref is not a vm_opaque_ref
|
||||
self._session.call_xenapi("VM.get_domid", vm_ref)
|
||||
|
||||
for device, vif in enumerate(network_info):
|
||||
LOG.debug('Create VIF %s', vif, instance=instance)
|
||||
self.vif_driver.plug(instance, vif, vm_ref=vm_ref, device=device)
|
||||
vif_ref = self.vif_driver.plug(instance, vif,
|
||||
vm_ref=vm_ref, device=device)
|
||||
vif_refs.append(vif_ref)
|
||||
|
||||
LOG.debug('Created the vif_refs: %(vifs)s for VM name: %(name)s',
|
||||
{'vifs': vif_refs, 'name': instance['name']},
|
||||
instance=instance)
|
||||
|
||||
def plug_vifs(self, instance, network_info):
|
||||
"""Set up VIF networking on the host."""
|
||||
|
@ -30,7 +30,8 @@ import utils
|
||||
# 1.2 - Added support for pci passthrough devices
|
||||
# 1.3 - Add vhd2 functions for doing glance operations by url
|
||||
# 1.4 - Add support of Glance v2 api
|
||||
PLUGIN_VERSION = "1.4"
|
||||
# 1.5 - Added function for network configuration on ovs bridge
|
||||
PLUGIN_VERSION = "1.5"
|
||||
|
||||
|
||||
def get_version(session):
|
||||
|
@ -217,6 +217,65 @@ def iptables_config(session, args):
|
||||
raise pluginlib.PluginError(_("Invalid iptables command"))
|
||||
|
||||
|
||||
def _ovs_add_patch_port(args):
|
||||
bridge_name = pluginlib.exists(args, 'bridge_name')
|
||||
port_name = pluginlib.exists(args, 'port_name')
|
||||
peer_port_name = pluginlib.exists(args, 'peer_port_name')
|
||||
cmd_args = ['ovs-vsctl', '--', '--if-exists', 'del-port',
|
||||
port_name, '--', 'add-port', bridge_name, port_name,
|
||||
'--', 'set', 'interface', port_name,
|
||||
'type=patch', 'options:peer=%s' % peer_port_name]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
def _ovs_del_port(args):
|
||||
bridge_name = pluginlib.exists(args, 'bridge_name')
|
||||
port_name = pluginlib.exists(args, 'port_name')
|
||||
cmd_args = ['ovs-vsctl', '--', '--if-exists', 'del-port',
|
||||
bridge_name, port_name]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
def _ovs_del_br(args):
|
||||
bridge_name = pluginlib.exists(args, 'bridge_name')
|
||||
cmd_args = ['ovs-vsctl', '--', '--if-exists',
|
||||
'del-br', bridge_name]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
def _ovs_set_if_external_id(args):
|
||||
interface = pluginlib.exists(args, 'interface')
|
||||
extneral_id = pluginlib.exists(args, 'extneral_id')
|
||||
value = pluginlib.exists(args, 'value')
|
||||
cmd_args = ['ovs-vsctl', 'set', 'Interface', interface,
|
||||
'external-ids:%s=%s' % (extneral_id, value)]
|
||||
return _run_command(cmd_args)
|
||||
|
||||
|
||||
ALLOWED_NETWORK_CMDS = {
|
||||
# allowed cmds to config OVS bridge
|
||||
'ovs_add_patch_port': _ovs_add_patch_port,
|
||||
'ovs_del_port': _ovs_del_port,
|
||||
'ovs_del_br': _ovs_del_br,
|
||||
'ovs_set_if_external_id': _ovs_set_if_external_id
|
||||
}
|
||||
|
||||
|
||||
def network_config(session, args):
|
||||
"""network config functions"""
|
||||
cmd = pluginlib.exists(args, 'cmd')
|
||||
if not isinstance(cmd, basestring):
|
||||
msg = _("invalid command '%s'") % str(cmd)
|
||||
raise pluginlib.PluginError(msg)
|
||||
return
|
||||
if cmd not in ALLOWED_NETWORK_CMDS:
|
||||
msg = _("Dom0 execution of '%s' is not permitted") % cmd
|
||||
raise pluginlib.PluginError(msg)
|
||||
return
|
||||
cmd_args = pluginlib.exists(args, 'args')
|
||||
return ALLOWED_NETWORK_CMDS[cmd](cmd_args)
|
||||
|
||||
|
||||
def _power_action(action, arg_dict):
|
||||
# Host must be disabled first
|
||||
host_uuid = arg_dict['host_uuid']
|
||||
@ -453,10 +512,12 @@ def get_pci_type(session, pci_device):
|
||||
if __name__ == "__main__":
|
||||
# Support both serialized and non-serialized plugin approaches
|
||||
_, methodname = xmlrpclib.loads(sys.argv[1])
|
||||
if methodname in ['query_gc', 'get_pci_device_details', 'get_pci_type']:
|
||||
if methodname in ['query_gc', 'get_pci_device_details', 'get_pci_type',
|
||||
'network_config']:
|
||||
utils.register_plugin_calls(query_gc,
|
||||
get_pci_device_details,
|
||||
get_pci_type)
|
||||
get_pci_type,
|
||||
network_config)
|
||||
|
||||
XenAPIPlugin.dispatch(
|
||||
{"host_data": host_data,
|
||||
|
Loading…
Reference in New Issue
Block a user