From 06e5909d05321a257afe6fa3b9b440e29cea88e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jason=20K=C3=B6lker?= Date: Thu, 22 Dec 2011 14:26:51 -0600 Subject: [PATCH] Refactor Xen Vif drivers. Fixes LP907850 * Allows Vif subclasses to have an __init__ for setting up state * Allows Vif subclasses to pass arbitrary kwargs to plug/unplug should they require more than what the interface specifies Change-Id: I816aa1537d21005d4332af3477d9fd12f177f326 --- nova/virt/vif.py | 8 +++-- nova/virt/xenapi/vif.py | 73 +++++++++++++++++++++++---------------- nova/virt/xenapi/vmops.py | 11 +++--- 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/nova/virt/vif.py b/nova/virt/vif.py index b7868995706e..07139b200563 100644 --- a/nova/virt/vif.py +++ b/nova/virt/vif.py @@ -20,11 +20,15 @@ class VIFDriver(object): """Abstract class that defines generic interfaces for all VIF drivers.""" + def __init__(self, **kwargs): + # NOTE(jkoelker) __init__ is here so subclasses *could* take + # advantage of any kwargs should they need to + pass - def plug(self, instance, network, mapping): + def plug(self, instance, network, mapping, **kwargs): """Plug VIF into network.""" raise NotImplementedError() - def unplug(self, instance, network, mapping): + def unplug(self, instance, network, mapping, **kwargs): """Unplug VIF from network.""" raise NotImplementedError() diff --git a/nova/virt/xenapi/vif.py b/nova/virt/xenapi/vif.py index e3d7b9a7da33..b53b456f112d 100644 --- a/nova/virt/xenapi/vif.py +++ b/nova/virt/xenapi/vif.py @@ -23,6 +23,7 @@ from nova import flags from nova import log as logging from nova.virt.vif import VIFDriver from nova.virt.xenapi.network_utils import NetworkHelper +from nova.virt.xenapi.vm_utils import VMHelper FLAGS = flags.FLAGS flags.DEFINE_string('xenapi_ovs_integration_bridge', 'xapi1', @@ -31,33 +32,42 @@ flags.DEFINE_string('xenapi_ovs_integration_bridge', 'xapi1', LOG = logging.getLogger("nova.virt.xenapi.vif") -class XenAPIBridgeDriver(VIFDriver): +class XenVIFDriver(VIFDriver): + def __init__(self, xenapi_session): + self._session = xenapi_session + + +class XenAPIBridgeDriver(XenVIFDriver): """VIF Driver for XenAPI that uses XenAPI to create Networks.""" - def plug(self, xenapi_session, vm_ref, instance, device, network, - network_mapping): - if network_mapping.get('should_create_vlan'): - network_ref = self.ensure_vlan_bridge(xenapi_session, network) + def plug(self, instance, network, mapping, vm_ref=None, device=None): + if not vm_ref: + vm_ref = VMHelper.lookup(self._session, instance.name) + if not device: + device = 0 + + if mapping.get('should_create_vlan'): + network_ref = self._ensure_vlan_bridge(network) else: network_ref = NetworkHelper.find_network_with_bridge( - xenapi_session, network['bridge']) + self._session, network['bridge']) vif_rec = {} vif_rec['device'] = str(device) vif_rec['network'] = network_ref vif_rec['VM'] = vm_ref - vif_rec['MAC'] = network_mapping['mac'] + vif_rec['MAC'] = mapping['mac'] vif_rec['MTU'] = '1500' vif_rec['other_config'] = {} - if "rxtx_cap" in network_mapping: + if "rxtx_cap" in mapping: vif_rec['qos_algorithm_type'] = "ratelimit" vif_rec['qos_algorithm_params'] = \ - {"kbps": str(network_mapping['rxtx_cap'] * 1024)} + {"kbps": str(mapping['rxtx_cap'] * 1024)} else: vif_rec['qos_algorithm_type'] = "" vif_rec['qos_algorithm_params'] = {} return vif_rec - def ensure_vlan_bridge(self, xenapi_session, network): + def _ensure_vlan_bridge(self, network): """Ensure that a VLAN bridge exists""" vlan_num = network['vlan'] @@ -66,7 +76,7 @@ class XenAPIBridgeDriver(VIFDriver): # Check whether bridge already exists # Retrieve network whose name_label is "bridge" network_ref = NetworkHelper.find_network_with_name_label( - xenapi_session, bridge) + self._session, bridge) if network_ref is None: # If bridge does not exists # 1 - create network @@ -74,34 +84,34 @@ class XenAPIBridgeDriver(VIFDriver): network_rec = {'name_label': bridge, 'name_description': description, 'other_config': {}} - network_ref = xenapi_session.call_xenapi('network.create', - network_rec) + network_ref = self._session.call_xenapi('network.create', + network_rec) # 2 - find PIF for VLAN NOTE(salvatore-orlando): using double # quotes inside single quotes as xapi filter only support # tokens in double quotes expr = 'field "device" = "%s" and \ field "VLAN" = "-1"' % bridge_interface - pifs = xenapi_session.call_xenapi('PIF.get_all_records_where', - expr) + pifs = self._session.call_xenapi('PIF.get_all_records_where', + expr) pif_ref = None # Multiple PIF are ok: we are dealing with a pool if len(pifs) == 0: raise Exception(_('Found no PIF for device %s') % \ bridge_interface) for pif_ref in pifs.keys(): - xenapi_session.call_xenapi('VLAN.create', - pif_ref, - str(vlan_num), - network_ref) + self._session.call_xenapi('VLAN.create', + pif_ref, + str(vlan_num), + network_ref) else: # Check VLAN tag is appropriate - network_rec = xenapi_session.call_xenapi('network.get_record', - network_ref) + network_rec = self._session.call_xenapi('network.get_record', + network_ref) # Retrieve PIFs from network for pif_ref in network_rec['PIFs']: # Retrieve VLAN from PIF - pif_rec = xenapi_session.call_xenapi('PIF.get_record', - pif_ref) + pif_rec = self._session.call_xenapi('PIF.get_record', + pif_ref) pif_vlan = int(pif_rec['VLAN']) # Raise an exception if VLAN != vlan_num if pif_vlan != vlan_num: @@ -116,27 +126,32 @@ class XenAPIBridgeDriver(VIFDriver): pass -class XenAPIOpenVswitchDriver(VIFDriver): +class XenAPIOpenVswitchDriver(XenVIFDriver): """VIF driver for Open vSwitch with XenAPI.""" - def plug(self, xenapi_session, vm_ref, instance, device, network, - network_mapping): + def plug(self, instance, network, mapping, vm_ref=None, device=None): + if not vm_ref: + vm_ref = VMHelper.lookup(self._session, instance.name) + + if not device: + device = 0 + # with OVS model, always plug into an OVS integration bridge # that is already created - network_ref = NetworkHelper.find_network_with_bridge(xenapi_session, + network_ref = NetworkHelper.find_network_with_bridge(self._session, FLAGS.xenapi_ovs_integration_bridge) vif_rec = {} vif_rec['device'] = str(device) vif_rec['network'] = network_ref vif_rec['VM'] = vm_ref - vif_rec['MAC'] = network_mapping['mac'] + vif_rec['MAC'] = mapping['mac'] vif_rec['MTU'] = '1500' vif_rec['qos_algorithm_type'] = "" vif_rec['qos_algorithm_params'] = {} # OVS on the hypervisor monitors this key and uses it to # set the iface-id attribute vif_rec['other_config'] = \ - {"nicira-iface-id": network_mapping['vif_uuid']} + {"nicira-iface-id": mapping['vif_uuid']} return vif_rec def unplug(self, instance, network, mapping): diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 6525b64dec0b..5b12b5fe34fc 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -94,7 +94,8 @@ class VMOps(object): self._session = session self.poll_rescue_last_ran = None VMHelper.XenAPI = self.XenAPI - self.vif_driver = utils.import_object(FLAGS.xenapi_vif_driver) + vif_impl = utils.import_class(FLAGS.xenapi_vif_driver) + self.vif_driver = vif_impl(xenapi_session=self._session) self._product_version = product_version def list_instances(self): @@ -1429,8 +1430,8 @@ class VMOps(object): self._session.call_xenapi("VM.get_record", vm_ref) for device, (network, info) in enumerate(network_info): - vif_rec = self.vif_driver.plug(self._session, - vm_ref, instance, device, network, info) + vif_rec = self.vif_driver.plug(instance, network, info, + vm_ref=vm_ref, device=device) network_ref = vif_rec['network'] LOG.debug(_('Creating VIF for VM %(vm_ref)s,' \ ' network %(network_ref)s.') % locals()) @@ -1440,8 +1441,8 @@ class VMOps(object): def plug_vifs(self, instance, network_info): """Set up VIF networking on the host.""" - for (network, mapping) in network_info: - self.vif_driver.plug(self._session, instance, network, mapping) + for device, (network, mapping) in enumerate(network_info): + self.vif_driver.plug(instance, network, mapping, device=device) def unplug_vifs(self, instance, network_info): if network_info: