Source code for taf.testlib.lxc

# Copyright (c) 2011 - 2017, Intel Corporation.
#
# 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.

"""``lxc.py``

`LXC-specific functionality`

"""

import os
import errno
import shutil
import stat

from subprocess import Popen, PIPE

# WORKAROUND BEGIN
import platform
# WORKAROUND END

from . import loggers

mod_logger = loggers.module_logger(name=__name__)


[docs]def mkdir_p(path): """Create dir and pass exception if one already exists. """ try: os.makedirs(path) except OSError as exc: if exc.errno == errno.EEXIST: pass else: raise
[docs]class Lxc(object): """Base class to work with Linux containers. """ class_logger = loggers.ClassLogger()
[docs] def __init__(self, lxc_ip=None, lxc_iface=None, vlab_ip=None, switch_bin_path=None, switch_id=None, switch_port=8081): """Init method for container. Args: lxc_ip(str): IP of the container lxc_iface(str): Network interface for container vlab_ip(str): real ip of the local vlab switch_bin_path(str): path to switchpp binary switch_id(str): simswitch id switch_port(int): switchpp xmlrpc port Returns: None """ self.topbuilddir = os.path.realpath(os.curdir) self.lxc_id = int(switch_port) - 8080 self.lxc_env = os.path.join(os.path.realpath(os.curdir), "cfg%s" % (self.lxc_id, )) self.lxc_ip = lxc_ip self.lxc_iface = lxc_iface self.build_name = "%s%s" % (os.path.basename(self.topbuilddir), self.lxc_id) self.vlab_ip = vlab_ip self.switch_bin_path = switch_bin_path self.switch_id = switch_id or (int(switch_port) - 8080)
[docs] def start(self, stdout=None, stderr=None): """Starts container. Args: stdout(str): Output file stderr(str): Error file Returns: None """ mkdir_p(os.path.join(os.sep, "var", "run", "quagga")) mkdir_p(os.path.join(os.sep, "var", "run", "ovs")) mkdir_p(os.path.join(self.lxc_env, "rootfs", "root")) mkdir_p(os.path.join(self.lxc_env, "rootfs", "etc", "quagga")) mkdir_p(os.path.join(self.lxc_env, "rootfs", "etc", "network")) mkdir_p(os.path.join(self.lxc_env, "rootfs", "var", "run", "quagga")) mkdir_p(os.path.join(self.lxc_env, "rootfs", "var", "log", "quagga")) mkdir_p(os.path.join(self.lxc_env, "rootfs", "var", "run", "ovs")) shutil.copy(os.path.join(os.sep, "usr", "local", "etc", "zebra.conf.sample"), os.path.join(self.lxc_env, "rootfs", "etc", "quagga", "zebra.conf")) shutil.copy(os.path.join(os.sep, "usr", "local", "etc", "ospfd.conf.sample"), os.path.join(self.lxc_env, "rootfs", "etc", "quagga", "ospfd.conf")) with open(os.path.join(self.lxc_env, "rootfs", "etc", "network", "interfaces"), 'w+') as fo: fo.write('auto eth0\n') fo.write('iface eth0 inet dhcp\n') ld_lib_path = os.path.normpath(os.path.join(os.path.dirname(self.switch_bin_path), "../lib")) if not (os.path.exists(ld_lib_path) and os.path.isdir(ld_lib_path)): self.class_logger.log(loggers.levels['WARNING'], "LD_LIBRARY_PATH=%s not found and will not be exported." % ld_lib_path) ld_lib_path = None else: self.class_logger.log(loggers.levels['INFO'], "Found LD_LIBRARY_PATH=%s" % ld_lib_path) with open(os.path.join(self.lxc_env, "rootfs", "root", "init"), 'w+') as fo: fo.write('#!/bin/bash\n') if ld_lib_path is not None: fo.write('export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%s\n' % ld_lib_path) fo.write('export OVS_RUNDIR=/var/run/ovs\n') fo.write('PATH=%s:%s\n' % (self.topbuilddir, os.getenv('PATH'))) fo.write('chmod a+rw /var/run/quagga\n') fo.write('zebra -u root -g root -f /etc/quagga/zebra.conf -i /var/run/quagga/zebra.pid -d\n') fo.write('ospfd -u root -g root -f /etc/quagga/ospfd.conf -i /var/run/quagga/ospfd.pid -d\n') fo.write('sysctl -w net.ipv4.ip_forward=1\n') fo.write('/usr/sbin/sshd\n') fo.write('cd %s\n' % (os.path.dirname(self.switch_bin_path), )) fo.write('%s -v %s -i %s -e %s -d\n' % (self.switch_bin_path, self.vlab_ip, self.switch_id, self.switch_id + 4700)) os.chmod(os.path.join(self.lxc_env, "rootfs", "root", "init"), stat.S_IXGRP | stat.S_IXUSR | stat.S_IXOTH) # TODO: Write files in one command instead of multiple f.write's with open(os.path.join(self.lxc_env, "conf"), 'w+') as fo: fo.write('lxc.utsname = %s\n' % (self.build_name, )) # WORKAROUND BEGIN: Ubuntu 12.04 bug #993706 # https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/993706 if platform.platform().find("precise") > 0: fo.write('lxc.aa_profile = unconfined\n') # WORKAROUND END fo.write('lxc.network.type = veth\n') fo.write('lxc.network.flags = up\n') fo.write('lxc.network.link = %s\n' % (self.lxc_iface, )) fo.write('lxc.network.name = eth0\n') fo.write('lxc.network.ipv4 = %s\n' % (self.lxc_ip, )) fo.write('lxc.mount.entry = %s /root none bind 0 0\n' % (os.path.join(self.lxc_env, "rootfs", "root"), )) fo.write('lxc.mount.entry = %s /etc/quagga none bind 0 0\n' % (os.path.join(self.lxc_env, "rootfs", "etc", "quagga"), )) fo.write('lxc.mount.entry = %s /etc/network/interfaces none bind 0 0\n' % (os.path.join(self.lxc_env, "rootfs", "etc", "network", "interfaces"), )) fo.write('lxc.mount.entry = %s /var/run/quagga none bind 0 0\n' % (os.path.join(self.lxc_env, "rootfs", "var", "run", "quagga"), )) fo.write('lxc.mount.entry = %s /var/log/quagga none bind 0 0\n' % (os.path.join(self.lxc_env, "rootfs", "var", "log", "quagga"), )) fo.write('lxc.mount.entry = %s /var/run/ovs none bind 0 0\n' % (os.path.join(self.lxc_env, "rootfs", "var", "run", "ovs"), )) process = Popen(['/usr/bin/lxc-execute', '-n', '%s' % (self.build_name, ), '-f', '%s' % (os.path.join(self.lxc_env, "conf"), ), '/root/init', '&'], stdout=stdout, stderr=stderr, close_fds=True) process = Popen(['lxc-wait', '-n', '%s' % (self.build_name, ), '-s', 'RUNNING'], stdout=stdout, stderr=stderr, close_fds=True) process.wait()
[docs] def stop(self): """Stops container. Returns: None """ process = Popen(['lxc-stop', '-n', '%s' % (self.build_name, )], stdout=PIPE, close_fds=True) process.wait() process = Popen(['lxc-wait', '-n', '%s' % (self.build_name, ), '-s', 'STOPPED'], stdout=PIPE, close_fds=True) process.wait() # try to remove LXC containers files in case lxc-wait did not do this for some reason try: shutil.rmtree(self.lxc_env) except Exception: pass # try to restore tty settings try: Popen(["stty", "sane"]) except Exception: pass