[Kimchi-devel] [PATCH] issue #548: Hotplug network interfaces

Crístian Viana cristiandeives at gmail.com
Tue Apr 14 21:09:56 UTC 2015


What exactly are the drivers that support it? I was able to hot plug
interfaces using virtio, rtl8139 and e1000, at least.

On Mon, Apr 13, 2015 at 11:12 AM Aline Manera <alinefm at linux.vnet.ibm.com>
wrote:

>
>
> On 08/04/2015 09:34, Crístian Deives wrote:
> > Currently, network interfaces can only be added to shutoff VMs. However,
> > the use might want to attach an interface to a running VM as well.
> >
> > Allow network interfaces to be attached also while the VM is running.
> > The related test cases have been updated to perform the same operations
> > on both a shutoff and a running VM.
> >
> > Fix issue #548 (Kimchi does not support NIC hot plug) - backend only.
> >
> > Signed-off-by: Crístian Deives <cristiandeives at gmail.com>
> > ---
> >   src/kimchi/i18n.py           |  1 -
> >   src/kimchi/model/vmifaces.py | 45 ++++++++++++++---------
> >   tests/test_model.py          | 86
> ++++++++++++++++++++++----------------------
> >   3 files changed, 73 insertions(+), 59 deletions(-)
> >
> > diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
> > index 46990a5..d4c1cc6 100644
> > --- a/src/kimchi/i18n.py
> > +++ b/src/kimchi/i18n.py
> > @@ -118,7 +118,6 @@ messages = {
> >
> >       "KCHVMIF0001E": _("Interface %(iface)s does not exist in virtual
> machine %(name)s"),
> >       "KCHVMIF0002E": _("Network %(network)s specified for virtual
> machine %(name)s does not exist"),
> > -    "KCHVMIF0003E": _("Do not support guest interface hot plug
> attachment"),
> >       "KCHVMIF0004E": _("Supported virtual machine interfaces type is
> only network"),
> >       "KCHVMIF0005E": _("Network name for virtual machine interface must
> be a string"),
> >       "KCHVMIF0006E": _("Invalid network model card specified for
> virtual machine interface"),
> > diff --git a/src/kimchi/model/vmifaces.py b/src/kimchi/model/vmifaces.py
> > index 0c10fa9..a64315d 100644
> > --- a/src/kimchi/model/vmifaces.py
> > +++ b/src/kimchi/model/vmifaces.py
> > @@ -22,7 +22,7 @@ import random
> >   import libvirt
> >   from lxml import etree, objectify
> >
> > -from kimchi.exception import InvalidOperation, InvalidParameter,
> NotFoundError
> > +from kimchi.exception import InvalidParameter, NotFoundError
> >   from kimchi.model.config import CapabilitiesModel
> >   from kimchi.model.vms import DOM_STATE_MAP, VMModel
> >   from kimchi.xmlutils.interface import get_iface_xml
> > @@ -48,10 +48,6 @@ class VMIfacesModel(object):
> >               raise InvalidParameter("KCHVMIF0002E",
> >                                      {'name': vm, 'network':
> params["network"]})
> >
> > -        dom = VMModel.get_vm(vm, self.conn)
> > -        if DOM_STATE_MAP[dom.info()[0]] != "shutoff":
> > -            raise InvalidOperation("KCHVMIF0003E")
> > -
> >           macs = (iface.mac.get('address')
> >                   for iface in self.get_vmifaces(vm, self.conn))
> >
> > @@ -60,10 +56,19 @@ class VMIfacesModel(object):
> >               if params['mac'] not in macs:
> >                   break
> >
> > +        dom = VMModel.get_vm(vm, self.conn)
> > +
>
> We need to restrict the hot plug operation to the drivers that supports it.
>
> >           os_data = VMModel.vm_get_os_metadata(dom,
> self.caps.metadata_support)
> >           os_distro, os_version = os_data
> >           xml = get_iface_xml(params, conn.getInfo()[0], os_distro,
> os_version)
> > -        dom.attachDeviceFlags(xml, libvirt.VIR_DOMAIN_AFFECT_CURRENT)
> > +
> > +        flags = 0
> > +        if dom.isPersistent():
> > +            flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG
> > +        if DOM_STATE_MAP[dom.info()[0]] != "shutoff":
> > +            flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE
> > +
> > +        dom.attachDeviceFlags(xml, flags)
> >
> >           return params['mac']
> >
> > @@ -118,14 +123,16 @@ class VMIfaceModel(object):
> >           dom = VMModel.get_vm(vm, self.conn)
> >           iface = self._get_vmiface(vm, mac)
> >
> > -        if DOM_STATE_MAP[dom.info()[0]] != "shutoff":
> > -            raise InvalidOperation("KCHVMIF0003E")
> > -
> >           if iface is None:
> >               raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface':
> mac})
> >
> > -        dom.detachDeviceFlags(etree.tostring(iface),
> > -                              libvirt.VIR_DOMAIN_AFFECT_CURRENT)
> > +        flags = 0
> > +        if dom.isPersistent():
> > +            flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG
> > +        if DOM_STATE_MAP[dom.info()[0]] != "shutoff":
> > +            flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE
> > +
> > +        dom.detachDeviceFlags(etree.tostring(iface), flags)
> >
> >       def update(self, vm, mac, params):
> >           dom = VMModel.get_vm(vm, self.conn)
> > @@ -134,16 +141,22 @@ class VMIfaceModel(object):
> >           if iface is None:
> >               raise NotFoundError("KCHVMIF0001E", {'name': vm, 'iface':
> mac})
> >
> > -        # FIXME we will support to change the live VM configuration
> later.
> > +        flags = 0
> > +        if dom.isPersistent():
> > +            flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG
> > +        if DOM_STATE_MAP[dom.info()[0]] != "shutoff":
> > +            flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE
> > +
> >           if iface.attrib['type'] == 'network' and 'network' in params:
> >               iface.source.attrib['network'] = params['network']
> >               xml = etree.tostring(iface)
> > -            dom.updateDeviceFlags(xml,
> flags=libvirt.VIR_DOMAIN_AFFECT_CONFIG)
> >
> > -        # change on the persisted VM configuration only.
> > -        if 'model' in params and dom.isPersistent():
> > +            dom.updateDeviceFlags(xml, flags=flags)
> > +
> > +        if 'model' in params:
> >               iface.model.attrib["type"] = params['model']
> >               xml = etree.tostring(iface)
> > -            dom.updateDeviceFlags(xml,
> flags=libvirt.VIR_DOMAIN_AFFECT_CONFIG)
> > +
> > +            dom.updateDeviceFlags(xml, flags=flags)
> >
> >           return mac
> > diff --git a/tests/test_model.py b/tests/test_model.py
> > index 63bd721..39e4fe6 100644
> > --- a/tests/test_model.py
> > +++ b/tests/test_model.py
> > @@ -297,9 +297,6 @@ class ModelTests(unittest.TestCase):
> >               params = {'name': 'test', 'disks': [], 'cdrom': UBUNTU_ISO}
> >               inst.templates_create(params)
> >               rollback.prependDefer(inst.template_delete, 'test')
> > -            params = {'name': 'kimchi-ifaces', 'template':
> '/templates/test'}
> > -            inst.vms_create(params)
> > -            rollback.prependDefer(inst.vm_delete, 'kimchi-ifaces')
> >
> >               # Create a network
> >               net_name = 'test-network'
> > @@ -311,45 +308,50 @@ class ModelTests(unittest.TestCase):
> >               inst.network_activate(net_name)
> >               rollback.prependDefer(inst.network_deactivate, net_name)
> >
> > -            ifaces = inst.vmifaces_get_list('kimchi-ifaces')
> > -            self.assertEquals(1, len(ifaces))
> > -
> > -            iface = inst.vmiface_lookup('kimchi-ifaces', ifaces[0])
> > -            self.assertEquals(17, len(iface['mac']))
> > -            self.assertEquals("default", iface['network'])
> > -            self.assertIn("model", iface)
> > -
> > -            # attach network interface to vm
> > -            iface_args = {"type": "network",
> > -                          "network": "test-network",
> > -                          "model": "virtio"}
> > -            mac = inst.vmifaces_create('kimchi-ifaces', iface_args)
> > -            # detach network interface from vm
> > -            rollback.prependDefer(inst.vmiface_delete, 'kimchi-ifaces',
> mac)
> > -            self.assertEquals(17, len(mac))
> > -
> > -            iface = inst.vmiface_lookup('kimchi-ifaces', mac)
> > -            self.assertEquals("network", iface["type"])
> > -            self.assertEquals("test-network", iface['network'])
> > -            self.assertEquals("virtio", iface["model"])
> > -
> > -            # attach network interface to vm without providing model
> > -            iface_args = {"type": "network",
> > -                          "network": "test-network"}
> > -            mac = inst.vmifaces_create('kimchi-ifaces', iface_args)
> > -            rollback.prependDefer(inst.vmiface_delete, 'kimchi-ifaces',
> mac)
> > -
> > -            iface = inst.vmiface_lookup('kimchi-ifaces', mac)
> > -            self.assertEquals("network", iface["type"])
> > -            self.assertEquals("test-network", iface['network'])
> > -
> > -            # update vm interface
> > -            iface_args = {"network": "default",
> > -                          "model": "e1000"}
> > -            inst.vmiface_update('kimchi-ifaces', mac, iface_args)
> > -            iface = inst.vmiface_lookup('kimchi-ifaces', mac)
> > -            self.assertEquals("default", iface['network'])
> > -            self.assertEquals("e1000", iface["model"])
> > +            for vm_name in ['kimchi-ifaces', 'kimchi-ifaces-running']:
> > +                params = {'name': vm_name, 'template':
> '/templates/test'}
> > +                inst.vms_create(params)
> > +                rollback.prependDefer(inst.vm_delete, vm_name)
> > +
> > +                ifaces = inst.vmifaces_get_list(vm_name)
> > +                self.assertEquals(1, len(ifaces))
> > +
> > +                iface = inst.vmiface_lookup(vm_name, ifaces[0])
> > +                self.assertEquals(17, len(iface['mac']))
> > +                self.assertEquals("default", iface['network'])
> > +                self.assertIn("model", iface)
> > +
> > +                # attach network interface to vm
> > +                iface_args = {"type": "network",
> > +                              "network": "test-network",
> > +                              "model": "virtio"}
> > +                mac = inst.vmifaces_create(vm_name, iface_args)
> > +                # detach network interface from vm
> > +                rollback.prependDefer(inst.vmiface_delete, vm_name, mac)
> > +                self.assertEquals(17, len(mac))
> > +
> > +                iface = inst.vmiface_lookup(vm_name, mac)
> > +                self.assertEquals("network", iface["type"])
> > +                self.assertEquals("test-network", iface['network'])
> > +                self.assertEquals("virtio", iface["model"])
> > +
> > +                # attach network interface to vm without providing model
> > +                iface_args = {"type": "network",
> > +                              "network": "test-network"}
> > +                mac = inst.vmifaces_create(vm_name, iface_args)
> > +                rollback.prependDefer(inst.vmiface_delete, vm_name, mac)
> > +
> > +                iface = inst.vmiface_lookup(vm_name, mac)
> > +                self.assertEquals("network", iface["type"])
> > +                self.assertEquals("test-network", iface['network'])
> > +
> > +                # update vm interface
> > +                iface_args = {"network": "default",
> > +                              "model": "e1000"}
> > +                inst.vmiface_update(vm_name, mac, iface_args)
> > +                iface = inst.vmiface_lookup(vm_name, mac)
> > +                self.assertEquals("default", iface['network'])
> > +                self.assertEquals("e1000", iface["model"])
> >
> >       @unittest.skipUnless(utils.running_as_root(), 'Must be run as
> root')
> >       def test_vm_disk(self):
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ovirt.org/pipermail/kimchi-devel/attachments/20150414/94970c12/attachment.html>


More information about the Kimchi-devel mailing list