On 11:55 Mon 17 Jan     , Guido Trotter wrote:
> On Mon, Jan 17, 2011 at 10:47 AM, Apollon Oikonomopoulos
> <[email protected]> wrote:
> > This patch introduces network configuration for KVM in Ganeti.
> >
> > There are three problems with having KVM perform network configuration via 
> > ifup
> > scripts:
> >  a) Ganeti never gets to know the tap interface that is associated with an
> >     instance's NIC
> >  b) Migration of routed instances will cause network problems because the
> >     incoming KVM side configures the network as soon as it is spawned and 
> > not
> >     as soon as the migration finishes. This means that all routing
> >     configuration will be present in both, primary and secondary, nodes at 
> > the
> >     same time, possibly causing network disruption during the migration.
> >  c) We never get to know if the network configuration succeeded or not.
> >
> > This patch moves network configuration from KVM to Ganeti, using KVM's 
> > ability
> > to receive already open tap devices as file descriptors.
> >
> > _WriteNetScript is removed from hv_kvm.py, together with its unit tests.
> >
> > Minor modifications are made to _ExecKVMRuntime to handle tap device
> > initialization. NIC <-> tap associations are stored under a new directory,
> > _ROOT_DIR/nic in a file-per-nic fashion.
> >
> > The end-user semantics remain the same: The user can override the network
> > configuration by providing _KVM_NET_SCRIPT. If this is not present or
> > executable, the default constants.KVM_IFUP script is run.
> >
> > Signed-off-by: Apollon Oikonomopoulos <[email protected]>
> > ---
> >  lib/hypervisor/hv_kvm.py                  |  234 
> > +++++++++++++----------------
> >  test/ganeti.hypervisor.hv_kvm_unittest.py |   47 ------
> >  2 files changed, 107 insertions(+), 174 deletions(-)
> >
> > diff --git a/lib/hypervisor/hv_kvm.py b/lib/hypervisor/hv_kvm.py
> > index ee895f3..b2fafd2 100644
> > --- a/lib/hypervisor/hv_kvm.py
> > +++ b/lib/hypervisor/hv_kvm.py
> > @@ -33,6 +33,7 @@ import logging
> >  import pwd
> >  import struct
> >  import fcntl
> > +import glob
> 
> Not needed anymore.

Ooops, missed that...

> 
> >  from cStringIO import StringIO
> >
> >  from ganeti import utils
> 
> > +  @classmethod
> > +  def _InstanceAllNICFiles(cls, instance_name):
> > +    """Returns all existing NIC filenames
> > +
> > +    """
> > +    instance_nic_dir = cls._InstanceNICDir(instance_name)
> > +    files = [ utils.PathJoin(instance_nic_dir, name) for name in
> > +              utils.ListVisibleFiles(instance_nic_dir) ]
> > +    return sorted(files)
> > +
> 
> With the change below we could drop this function.
> 
> > +  @classmethod
> >   def _TryReadUidFile(cls, uid_file):
> >     """Try to read a uid file
> >
> > @@ -464,6 +392,9 @@ class KVMHypervisor(hv_base.BaseHypervisor):
> >     utils.RemoveFile(uid_file)
> >     if uid is not None:
> >       uidpool.ReleaseUid(uid)
> > +    for nicfile in cls._InstanceAllNICFiles(instance_name):
> > +      utils.RemoveFile(nicfile)
> > +    utils.RemoveDir(cls._InstanceNICDir(instance_name))
> 
> How about using shutil.rmtree ?

Hmmm, not a bad idea. I'll change this and remove _InstanceAllNICFiles.

> 
> > +  def _ConfigureNIC(instance, seq, nic, tap):
> > +    """Run the network configuration script for a specified NIC
> >
> >     @param instance: instance we're acting on
> >     @type instance: instance object
> > @@ -495,22 +424,39 @@ class KVMHypervisor(hv_base.BaseHypervisor):
> >     @type seq: int
> >     @param nic: nic we're acting on
> >     @type nic: nic object
> > -    @return: netscript file name
> > -    @rtype: string
> > +    @param tap: the host's tap interface this NIC corresponds to
> > +    @type tap: str
> >
> >     """
> > -    script = _WriteNetScript(instance, nic, seq)
> >
> > -    # As much as we'd like to put this in our _ROOT_DIR, that will happen 
> > to be
> > -    # mounted noexec sometimes, so we'll have to find another place.
> > -    (tmpfd, tmpfile_name) = tempfile.mkstemp()
> > -    tmpfile = os.fdopen(tmpfd, 'w')
> > -    try:
> > -      tmpfile.write(script)
> > -    finally:
> > -      tmpfile.close()
> > -    os.chmod(tmpfile_name, 0755)
> > -    return tmpfile_name
> > +    if instance.tags:
> > +      tags = " ".join(instance.tags)
> > +    else:
> > +      tags = ""
> > +
> > +    env = {
> > +      "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
> > +      "INSTANCE": instance.name,
> > +      "MAC": nic.mac,
> > +      "MODE": nic.nicparams[constants.NIC_MODE],
> > +      "INTERFACE": tap,
> > +      "INTERFACE_INDEX": str(seq),
> > +      "TAGS": tags,
> > +    }
> > +
> > +    if nic.ip:
> > +      env["IP"] = nic.ip
> > +
> > +    if nic.nicparams[constants.NIC_LINK]:
> > +      env["LINK"] = nic.nicparams[constants.NIC_LINK]
> > +
> > +    if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
> > +      env["BRIDGE"] = nic.nicparams[constants.NIC_LINK]
> > +
> > +    result = utils.RunCmd([constants.KVM_IFUP, tap], env=env)
> > +    if result.failed:
> > +      logging.warning("Failed to configure interface %s: %s (%s)" %
> > +                      (tap, result.fail_reason, result.output))
> >
> 
> Should it be a HypervisorError here? Does it make sense to go on if
> configuring the network fails, and just logging a warning?

I was thinking of that as well. Thing is, at the point this happens, the 
KVM instance has already started and should be cleaned up. What do you 
think?

Thanks,
Apollon

Reply via email to