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.

>  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 ?

> +  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?

LGTM for the rest

Thanks,

Guido

Reply via email to