From 979282fba8b9dc20bc6345a3b3c017d6339662fa Mon Sep 17 00:00:00 2001 From: danwent Date: Wed, 20 Jul 2011 00:41:26 -0700 Subject: first cut of xenserver vif-plugging, some minor tweaks to libvirt plugging --- nova/virt/libvirt/connection.py | 8 +++----- nova/virt/libvirt/vif.py | 5 +++-- nova/virt/xenapi/vm_utils.py | 22 ---------------------- nova/virt/xenapi/vmops.py | 34 ++++++++++++++++++++++++---------- nova/virt/xenapi_conn.py | 3 +++ 5 files changed, 33 insertions(+), 39 deletions(-) (limited to 'nova') diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 936e1b171..1fa6e5c2f 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -261,11 +261,9 @@ class LibvirtConnection(driver.ComputeDriver): def setup_vif_network(self, ctxt, instance_id): """Set up VIF networking on the host.""" - # FIXME: this is dying because DB has no networks for instances - #networks = db.network_get_all_by_instance(ctxt, instance_id) - #for network in networks: - # self.vif_driver.plug(network) - pass + networks = db.network_get_all_by_instance(ctxt, instance_id) + for network in networks: + self.vif_driver.plug(network) def destroy(self, instance, network_info, cleanup=True): instance_name = instance['name'] diff --git a/nova/virt/libvirt/vif.py b/nova/virt/libvirt/vif.py index 4f7bb0b4d..2188251f0 100644 --- a/nova/virt/libvirt/vif.py +++ b/nova/virt/libvirt/vif.py @@ -28,6 +28,8 @@ FLAGS = flags.FLAGS flags.DEFINE_bool('allow_project_net_traffic', True, 'Whether to allow in project network traffic') +flags.DEFINE_string('libvirt_ovs_integration_bridge', 'br-int', + 'Name of Integration Bridge used by Open vSwitch') class LibvirtVIF(object): @@ -110,7 +112,7 @@ class LibvirtOpenVswitchDriver(VIFDriver): utils.execute('sudo', 'ip', 'tuntap', 'add', dev, 'mode', 'tap') utils.execute('sudo', 'ip', 'link', 'set', dev, 'up') utils.execute('sudo', 'ovs-vsctl', '--', '--may-exist', 'add-port', - FLAGS.flat_network_bridge, dev, + FLAGS.libvirt_ovs_integration_bridge, dev, '--', 'set', 'Interface', dev, "external-ids:iface-id=%s" % vif_id, '--', 'set', 'Interface', dev, "external-ids:iface-status=active", '--', 'set', 'Interface', dev, "external-ids:attached-mac=%s" % \ @@ -120,7 +122,6 @@ class LibvirtOpenVswitchDriver(VIFDriver): 'script': '', 'name': dev, 'mac_address': mapping['mac']} - print "using result = %s" % str(result) return result def plug(self, network): diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 71107aff4..e63582b54 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -282,27 +282,6 @@ class VMHelper(HelperBase): LOG.exception(exc) raise StorageError(_('Unable to destroy VDI %s') % vdi_ref) - @classmethod - def create_vif(cls, session, vm_ref, network_ref, mac_address, - dev, rxtx_cap=0): - """Create a VIF record. Returns a Deferred that gives the new - VIF reference.""" - vif_rec = {} - vif_rec['device'] = str(dev) - vif_rec['network'] = network_ref - vif_rec['VM'] = vm_ref - vif_rec['MAC'] = mac_address - vif_rec['MTU'] = '1500' - vif_rec['other_config'] = {} - vif_rec['qos_algorithm_type'] = "ratelimit" if rxtx_cap else '' - vif_rec['qos_algorithm_params'] = \ - {"kbps": str(rxtx_cap * 1024)} if rxtx_cap else {} - LOG.debug(_('Creating VIF for VM %(vm_ref)s,' - ' network %(network_ref)s.') % locals()) - vif_ref = session.call_xenapi('VIF.create', vif_rec) - LOG.debug(_('Created VIF %(vif_ref)s for VM %(vm_ref)s,' - ' network %(network_ref)s.') % locals()) - return vif_ref @classmethod def create_vdi(cls, session, sr_ref, name_label, virtual_size, read_only): @@ -1116,7 +1095,6 @@ def _stream_disk(dev, image_type, virtual_size, image_file): for chunk in image_file: f.write(chunk) - def _write_partition(virtual_size, dev): dest = '/dev/%s' % dev primary_first = MBR_SIZE_SECTORS diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index c332c27b0..26f90fedd 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -52,6 +52,9 @@ FLAGS = flags.FLAGS flags.DEFINE_integer('windows_version_timeout', 300, 'number of seconds to wait for windows agent to be ' 'fully operational') +flags.DEFINE_string('xenapi_vif_driver', + 'nova.virt.xenapi.vif.XenAPIBridgeDriver', + 'The XenAPI VIF driver using XenServer Network APIs.') def cmp_version(a, b): @@ -78,6 +81,7 @@ 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) def list_instances(self): """List VM instances.""" @@ -255,7 +259,7 @@ class VMOps(object): VMHelper.preconfigure_instance(self._session, instance, first_vdi_ref, network_info) - self.create_vifs(vm_ref, network_info) + self.create_vifs(vm_ref, instance, network_info) self.inject_network_info(instance, network_info, vm_ref) return vm_ref @@ -873,6 +877,11 @@ class VMOps(object): self._destroy_kernel_ramdisk(instance, vm_ref) self._destroy_vm(instance, vm_ref) + networks = db.network_get_all_by_instance(ctxt, instance['id']) + for network in networks: + self.vif_driver.unplug(network) + + def _wait_with_callback(self, instance_id, task, callback): ret = None try: @@ -1068,7 +1077,7 @@ class VMOps(object): # catch KeyError for domid if instance isn't running pass - def create_vifs(self, vm_ref, network_info): + def create_vifs(self, vm_ref, instance, network_info): """Creates vifs for an instance.""" logging.debug(_("creating vif(s) for vm: |%s|"), vm_ref) @@ -1077,14 +1086,19 @@ class VMOps(object): self._session.get_xenapi().VM.get_record(vm_ref) for device, (network, info) in enumerate(network_info): - mac_address = info['mac'] - bridge = network['bridge'] - rxtx_cap = info.pop('rxtx_cap') - network_ref = \ - NetworkHelper.find_network_with_bridge(self._session, - bridge) - VMHelper.create_vif(self._session, vm_ref, network_ref, - mac_address, device, rxtx_cap) + vif_rec = self.vif_driver.get_vif_rec(self._session, + vm_ref, instance, device, network, info) + LOG.debug(_('Creating VIF for VM %(vm_ref)s,' \ + ' network %(network_ref)s.') % locals()) + vif_ref = session.call_xenapi('VIF.create', vif_rec) + LOG.debug(_('Created VIF %(vif_ref)s for VM %(vm_ref)s,' + ' network %(network_ref)s.') % locals()) + + def setup_vif_network(self, ctxt, instance_id): + """Set up VIF networking on the host.""" + networks = db.network_get_all_by_instance(ctxt, instance_id) + for network in networks: + self.vif_driver.plug(network) def reset_network(self, instance, vm_ref=None): """Creates uuid arg to pass to make_agent_call and calls it.""" diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 032ab7345..ae39ecab4 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -269,6 +269,9 @@ class XenAPIConnection(driver.ComputeDriver): """inject network info for specified instance""" self._vmops.inject_network_info(instance, network_info) + def setup_vif_network(self, ctxt, instance_id): + self._vmops.setup_vif_network(ctxt, instance_id) + def get_info(self, instance_id): """Return data about VM instance""" return self._vmops.get_info(instance_id) -- cgit From 43de3c5f6b5d65d981fbebf169c05d06faa6a09e Mon Sep 17 00:00:00 2001 From: danwent Date: Wed, 20 Jul 2011 01:03:02 -0700 Subject: remove xenapi_net.py from network directory, as this functionality is now moved to virt layer --- nova/network/xenapi_net.py | 87 ---------------------------------------------- 1 file changed, 87 deletions(-) delete mode 100644 nova/network/xenapi_net.py (limited to 'nova') diff --git a/nova/network/xenapi_net.py b/nova/network/xenapi_net.py deleted file mode 100644 index e86f4017d..000000000 --- a/nova/network/xenapi_net.py +++ /dev/null @@ -1,87 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (c) 2011 Citrix Systems, Inc. -# Copyright 2011 OpenStack LLC. -# -# 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. - -"""Implements vlans, bridges, and iptables rules using linux utilities.""" - -import os - -from nova import db -from nova import exception -from nova import flags -from nova import log as logging -from nova import utils -from nova.virt import xenapi_conn -from nova.virt.xenapi import network_utils - - -LOG = logging.getLogger("nova.xenapi_net") - - -FLAGS = flags.FLAGS - - -def ensure_vlan_bridge(vlan_num, bridge, bridge_interface, net_attrs=None): - """Create a vlan and bridge unless they already exist.""" - # Open xenapi session - LOG.debug('ENTERING ensure_vlan_bridge in xenapi net') - url = FLAGS.xenapi_connection_url - username = FLAGS.xenapi_connection_username - password = FLAGS.xenapi_connection_password - session = xenapi_conn.XenAPISession(url, username, password) - # Check whether bridge already exists - # Retrieve network whose name_label is "bridge" - network_ref = network_utils.NetworkHelper.find_network_with_name_label( - session, - bridge) - if network_ref is None: - # If bridge does not exists - # 1 - create network - description = 'network for nova bridge %s' % bridge - network_rec = {'name_label': bridge, - 'name_description': description, - 'other_config': {}} - network_ref = 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 = 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) - # 3 - create vlan for network - for pif_ref in pifs.keys(): - session.call_xenapi('VLAN.create', - pif_ref, - str(vlan_num), - network_ref) - else: - # Check VLAN tag is appropriate - network_rec = 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 = 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: - raise Exception(_("PIF %(pif_rec['uuid'])s for network " - "%(bridge)s has VLAN id %(pif_vlan)d. " - "Expected %(vlan_num)d") % locals()) -- cgit From 2b8cc5f98435423eb2b8bc42bcb7e9c38e453c34 Mon Sep 17 00:00:00 2001 From: danwent Date: Wed, 20 Jul 2011 13:03:27 -0700 Subject: update for ryu's naming changes, fix some bugs. tested with OVSDriver only so far --- nova/virt/xenapi/vmops.py | 32 +++++++++++++++++++------------- nova/virt/xenapi_conn.py | 6 +++--- 2 files changed, 22 insertions(+), 16 deletions(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 26f90fedd..f88715c50 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -81,8 +81,9 @@ class VMOps(object): self._session = session self.poll_rescue_last_ran = None VMHelper.XenAPI = self.XenAPI + print "loading vif_driver = %s" % FLAGS.xenapi_vif_driver self.vif_driver = utils.import_object(FLAGS.xenapi_vif_driver) - + print "driver class = %s" % str(self.vif_driver) def list_instances(self): """List VM instances.""" # TODO(justinsb): Should we just always use the details method? @@ -473,7 +474,7 @@ class VMOps(object): self._session, instance, template_vdi_uuids, image_id) finally: if template_vm_ref: - self._destroy(instance, template_vm_ref, + self._destroy(instance, template_vm_ref, None, shutdown=False, destroy_kernel_ramdisk=False) logging.debug(_("Finished snapshot and upload for VM %s"), instance) @@ -843,7 +844,7 @@ class VMOps(object): self._session.call_xenapi("Async.VM.destroy", rescue_vm_ref) - def destroy(self, instance): + def destroy(self, instance, network_info): """Destroy VM instance. This is the method exposed by xenapi_conn.destroy(). The rest of the @@ -853,9 +854,9 @@ class VMOps(object): instance_id = instance.id LOG.info(_("Destroying VM for Instance %(instance_id)s") % locals()) vm_ref = VMHelper.lookup(self._session, instance.name) - return self._destroy(instance, vm_ref, shutdown=True) + return self._destroy(instance, vm_ref, network_info, shutdown=True) - def _destroy(self, instance, vm_ref, shutdown=True, + def _destroy(self, instance, vm_ref, network_info, shutdown=True, destroy_kernel_ramdisk=True): """Destroys VM instance by performing: @@ -877,9 +878,14 @@ class VMOps(object): self._destroy_kernel_ramdisk(instance, vm_ref) self._destroy_vm(instance, vm_ref) - networks = db.network_get_all_by_instance(ctxt, instance['id']) - for network in networks: - self.vif_driver.unplug(network) + if network_info: + try: + for (network, mapping) in network_info: + self.vif_driver.unplug(instance, network, mapping) + except: + LOG.warning("Failed while unplugging vif of instance '%s'" % \ + instance['name']) + raise def _wait_with_callback(self, instance_id, task, callback): @@ -1088,17 +1094,17 @@ class VMOps(object): for device, (network, info) in enumerate(network_info): vif_rec = self.vif_driver.get_vif_rec(self._session, vm_ref, instance, device, network, info) + network_ref = vif_rec['network'] LOG.debug(_('Creating VIF for VM %(vm_ref)s,' \ ' network %(network_ref)s.') % locals()) - vif_ref = session.call_xenapi('VIF.create', vif_rec) + vif_ref = self._session.call_xenapi('VIF.create', vif_rec) LOG.debug(_('Created VIF %(vif_ref)s for VM %(vm_ref)s,' ' network %(network_ref)s.') % locals()) - def setup_vif_network(self, ctxt, instance_id): + def plug_vifs(instance, network_info): """Set up VIF networking on the host.""" - networks = db.network_get_all_by_instance(ctxt, instance_id) - for network in networks: - self.vif_driver.plug(network) + for (network, mapping) in network_info: + self.vif_driver.plug(self._session, instance, network, mapping) def reset_network(self, instance, vm_ref=None): """Creates uuid arg to pass to make_agent_call and calls it.""" diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 10a532ea0..102278e1c 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -226,7 +226,7 @@ class XenAPIConnection(driver.ComputeDriver): def destroy(self, instance, network_info): """Destroy VM instance""" - self._vmops.destroy(instance) + self._vmops.destroy(instance, network_info) def pause(self, instance, callback): """Pause VM instance""" @@ -269,8 +269,8 @@ class XenAPIConnection(driver.ComputeDriver): """inject network info for specified instance""" self._vmops.inject_network_info(instance, network_info) - def setup_vif_network(self, ctxt, instance_id): - self._vmops.setup_vif_network(ctxt, instance_id) + def plug_vifs(self, instance_ref, network_info): + self._vmops.plug_vifs(instance_ref, network_info) def get_info(self, instance_id): """Return data about VM instance""" -- cgit From 407e30e4843d27943e38374d61525805236319d2 Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Wed, 20 Jul 2011 13:10:25 -0700 Subject: remove debug prints --- nova/virt/xenapi/vmops.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'nova') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index f88715c50..bdf471d16 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -81,9 +81,8 @@ class VMOps(object): self._session = session self.poll_rescue_last_ran = None VMHelper.XenAPI = self.XenAPI - print "loading vif_driver = %s" % FLAGS.xenapi_vif_driver self.vif_driver = utils.import_object(FLAGS.xenapi_vif_driver) - print "driver class = %s" % str(self.vif_driver) + def list_instances(self): """List VM instances.""" # TODO(justinsb): Should we just always use the details method? -- cgit