apt:
packages:
- lxc
+ - lxd
# perform the build and fail immediately on error
install:
@staticmethod
def build_cmd_path(in_container, cmd):
if in_container:
- return os.path.join('/', consts.LIBCG_MOUNT_POINT,
- 'src/tools/.libs/{}'.format(cmd))
+ return os.path.join(consts.LIBCG_MOUNT_POINT,
+ 'src/tools/{}'.format(cmd))
else:
return cmd
else:
# Use the default container settings
self.container = Container(name=consts.DEFAULT_CONTAINER_NAME,
- stop_timeout=args.timeout, arch=None, cfg_path=args.config,
+ stop_timeout=args.timeout, arch=None,
distro=args.distro, release=args.release)
self.ftest_dir = os.path.dirname(os.path.abspath(__file__))
LOG_DEBUG = 8
DEFAULT_LOG_LEVEL = 5
-LIBCG_MOUNT_POINT = 'libcg'
+ftest_dir = os.path.dirname(os.path.abspath(__file__))
+tests_dir = os.path.dirname(ftest_dir)
+LIBCG_MOUNT_POINT = os.path.dirname(tests_dir)
-DEFAULT_CONTAINER_NAME = 'test_libcg'
-DEFAULT_CONTAINER_DISTRO = 'oracle'
-DEFAULT_CONTAINER_RELEASE = '7'
+DEFAULT_CONTAINER_NAME = 'TestLibcg'
+DEFAULT_CONTAINER_DISTRO = 'ubuntu'
+DEFAULT_CONTAINER_RELEASE = '18.04'
DEFAULT_CONTAINER_ARCH = 'amd64'
DEFAULT_CONTAINER_STOP_TIMEOUT = 5
DEFAULT_CONTAINER_CFG_PATH=os.path.join(
else:
self.arch = consts.DEFAULT_CONTAINER_ARCH
- if cfg_path:
- self.cfg_path = cfg_path
- else:
- self.cfg_path = consts.DEFAULT_CONTAINER_CFG_PATH
-
if distro:
self.distro = distro
else:
ftest_dir = os.path.dirname(os.path.abspath(__file__))
tests_dir = os.path.dirname(ftest_dir)
- libcg_dir = os.path.dirname(tests_dir)
-
- self.tmp_cfg_path = os.path.join(ftest_dir, consts.TEMP_CONTAINER_CFG_FILE)
- try:
- Run.run(['rm', '-f', self.tmp_cfg_path])
- except:
- pass
+ # save off the path to the libcgroup source code
+ self.libcg_dir = os.path.dirname(tests_dir)
- Run.run(['cp', self.cfg_path, self.tmp_cfg_path])
-
- conf_line = 'lxc.arch = {}'.format(self.arch)
- Run.run(['echo', conf_line, '>>', self.tmp_cfg_path], shell_bool=True)
-
- conf_line = 'lxc.mount.entry = {} {} none bind,ro 0 0'.format(
- libcg_dir, consts.LIBCG_MOUNT_POINT)
- Run.run(['echo', conf_line, '>>', self.tmp_cfg_path], shell_bool=True)
-
- if not self.privileged:
- conf_line = 'lxc.idmap = u 0 100000 65536'
- Run.run(['echo', conf_line, '>>', self.tmp_cfg_path], shell_bool=True)
- conf_line = 'lxc.idmap = g 0 100000 65536'
- Run.run(['echo', conf_line, '>>', self.tmp_cfg_path], shell_bool=True)
def __str__(self):
out_str = "{}".format(self.name)
out_str += "\n\tdistro = {}".format(self.distro)
out_str += "\n\trelease = {}".format(self.release)
out_str += "\n\tarch = {}".format(self.arch)
- out_str += "\n\tcfg_path = {}".format(self.cfg_path)
out_str += "\n\tstop_timeout = {}".format(self.stop_timeout)
return out_str
- def create(self):
- cmd = list()
-
- if self.privileged:
- cmd.append('sudo')
-
- cmd.append('lxc-create')
- cmd.append('-t')
- cmd.append( 'download')
+ # configure the container to meet our needs
+ def config(self):
+ ftest_dir = os.path.dirname(os.path.abspath(__file__))
+ tests_dir = os.path.dirname(ftest_dir)
+ libcg_dir = os.path.dirname(tests_dir)
- cmd.append('-n')
- cmd.append(self.name)
+ # map our UID and GID to the same UID/GID in the container
+ cmd = 'printf "uid {} 1000\ngid {} 1000" | sudo lxc config set {} raw.idmap -'.format(
+ os.getuid(), os.getgid(), self.name)
+ Run.run(cmd, shell_bool=True)
+ # add the libcgroup root directory (where we did the build) into
+ # the container
+ cmd2 = list()
if self.privileged:
- cmd.append('sudo')
- cmd.append('-f')
- cmd.append(self.tmp_cfg_path)
-
- cmd.append('--')
-
- cmd.append('-d')
- cmd.append(self.distro)
-
- cmd.append('-r')
- cmd.append(self.release)
-
- cmd.append('-a')
- cmd.append(self.arch)
-
- return Run.run(cmd)
+ cmd2.append('sudo')
+ cmd2.append('lxc')
+ cmd2.append('config')
+ cmd2.append('device')
+ cmd2.append('add')
+ cmd2.append(self.name)
+ cmd2.append('libcgsrc') # arbitrary name of device
+ cmd2.append('disk')
+ # to appease gcov, mount the libcgroup source at the same path as we
+ # built it. This can be worked around someday by using
+ # GCOV_PREFIX_STRIP, but that was more difficult to setup than just
+ # doing this initially
+ cmd2.append('source={}'.format(self.libcg_dir))
+ cmd2.append('path={}'.format(self.libcg_dir))
+
+ return Run.run(cmd2)
- def destroy(self):
+ def create(self):
cmd = list()
if self.privileged:
cmd.append('sudo')
- cmd.append('lxc-destroy')
+ cmd.append('lxc')
+ cmd.append('init')
+
+ cmd.append('{}:{}'.format(self.distro, self.release))
- cmd.append('-n')
cmd.append(self.name)
return Run.run(cmd)
- def info(self, cfgname):
+ def delete(self):
cmd = list()
if self.privileged:
cmd.append('sudo')
- cmd.append('lxc-info')
-
- cmd.append('--config={}'.format(cfgname))
+ cmd.append('lxc')
+ cmd.append('delete')
- cmd.append('-n')
cmd.append(self.name)
return Run.run(cmd)
- def rootfs(self):
- # try to read lxc.rootfs.path first
- ret = self.info('lxc.rootfs.path')
- if len(ret.strip()) > 0:
- return ret.decode()
-
- # older versions of lxc used lxc.rootfs. Try that.
- ret = self.info('lxc.rootfs')
- if len(ret.strip()) == 0:
- # we failed to get the rootfs
- raise ContainerError('Failed to get the rootfs')
- return ret.decode()
-
def run(self, cntnr_cmd):
cmd = list()
if self.privileged:
cmd.append('sudo')
- cmd.append('lxc-attach')
+ cmd.append('lxc')
+ cmd.append('exec')
- cmd.append('-n')
cmd.append(self.name)
cmd.append('--')
- # concatenate the lxc-attach command with the command to be run
+ # concatenate the lxc exec command with the command to be run
# inside the container
if isinstance(cntnr_cmd, str):
cmd.append(cntnr_cmd)
if self.privileged:
cmd.append('sudo')
- cmd.append('lxc-start')
- cmd.append('-d')
+ cmd.append('lxc')
+ cmd.append('start')
- cmd.append('-n')
cmd.append(self.name)
return Run.run(cmd)
- def stop(self, kill=True):
+ def stop(self, force=True):
cmd = list()
if self.privileged:
cmd.append('sudo')
- cmd.append('lxc-stop')
+ cmd.append('lxc')
+ cmd.append('stop')
- cmd.append('-n')
cmd.append(self.name)
- if kill:
- cmd.append('-k')
+ if force:
+ cmd.append('-f')
else:
- cmd.append('-t')
+ cmd.append('--timeout')
cmd.append(str(self.stop_timeout))
return Run.run(cmd)
- def version(self):
- cmd = ['lxc-create', '--version']
- return Run.run(cmd)
-
class ContainerError(Exception):
def __init__(self, message, ret):
super(RunError, self).__init__(message)
parser.add_argument('-n', '--name',
help='name of the container',
required=False, type=str, default=None)
- parser.add_argument('-f', '--config',
- help='initial configuration file',
- required=False, type=str, default=None)
parser.add_argument('-d', '--distro',
help='linux distribution to use as a template',
required=False, type=str, default=None)
parser.add_argument('-s', '--suite',
help='Test suite to run, e.g. cpuset', required=False,
default=consts.TESTS_RUN_ALL_SUITES, type=str)
- parser.add_argument('-u', '--unpriv',
- help='Run the tests in an unprivileged container',
- required=False, action="store_true")
parser.add_argument('-v', '--verbose',
help='Print all information about this test run',
default=True, required=False, action="store_false")
log.log_level = config.args.loglevel
if config.args.logfile:
log.log_file = config.args.logfile
- if config.args.unpriv:
- raise ValueError('Unprivileged containers are not currently supported')
- config.container.privileged = False
return config
+# this function maps the container UID to the host UID. By doing
+# this, we can write to a bind-mounted device - and thus generate
+# code coverage data in the LXD container
+def update_host_subuid():
+ subuid_line1 = 'lxd:{}:1'.format(os.getuid())
+ subuid_line2 = 'root:{}:1'.format(os.getuid())
+ found_line1 = False
+ found_line2 = False
+
+ with open('/etc/subuid') as ufile:
+ for line in ufile.readlines():
+ if line.strip() == subuid_line1:
+ found_line1 = True
+ elif line.strip() == subuid_line2:
+ found_line2 = True
+
+ if not found_line1:
+ Run.run('sudo sh -c "echo {} >> /etc/subuid"'.format(
+ subuid_line1), shell_bool=True)
+ if not found_line2:
+ Run.run('sudo sh -c "echo {} >> /etc/subuid"'.format(
+ subuid_line2), shell_bool=True)
+
+# this function maps the container GID to the host GID. By doing
+# this, we can write to a bind-mounted device - and thus generate
+# code coverage data in the LXD container
+def update_host_subgid():
+ subgid_line1 = 'lxd:{}:1'.format(os.getgid())
+ subgid_line2 = 'root:{}:1'.format(os.getgid())
+ found_line1 = False
+ found_line2 = False
+
+ with open('/etc/subgid') as ufile:
+ for line in ufile.readlines():
+ if line.strip() == subgid_line1:
+ found_line1 = True
+ elif line.strip() == subgid_line2:
+ found_line2 = True
+
+ if not found_line1:
+ Run.run('sudo sh -c "echo {} >> /etc/subgid"'.format(
+ subgid_line1), shell_bool=True)
+ if not found_line2:
+ Run.run('sudo sh -c "echo {} >> /etc/subgid"'.format(
+ subgid_line2), shell_bool=True)
+
def setup(config, do_teardown=True, record_time=False):
global setup_time
start_time = time.time()
# log but ignore all exceptions
Log.log_debug(e)
- config.container.create()
-
- # make the /libcg directory in the container's rootfs
- rootfs = config.container.rootfs()
- container_rootfs_path = rootfs.split('=')[1].strip()
- Run.run(['sudo', 'mkdir', os.path.join(container_rootfs_path,
- consts.LIBCG_MOUNT_POINT)])
+ # this command initializes the lxd storage, networking, etc.
+ Run.run(['sudo', 'lxd', 'init', '--auto'])
+ update_host_subuid()
+ update_host_subgid()
+ config.container.create()
+ config.container.config()
config.container.start()
# add the libcgroup library to the container's ld
echo_cmd = ['bash', '-c', 'echo {} >> /etc/ld.so.conf.d/libcgroup.conf'.format(
- os.path.join('/', consts.LIBCG_MOUNT_POINT, 'src/.libs'))]
+ os.path.join(consts.LIBCG_MOUNT_POINT, 'src/.libs'))]
config.container.run(echo_cmd)
config.container.run('ldconfig')
if record_time:
# log but ignore all exceptions
Log.log_debug(e)
try:
- config.container.destroy()
+ config.container.delete()
except Exception as e:
# log but ignore all exceptions
Log.log_debug(e)
else:
Log.log_debug(
"run:\n\tcommand = {}\n\tret = {}\n\tstdout = {}\n\tstderr = {}".format(
- ''.join(command), ret, out, err))
+ ' '.join(command), ret, out, err))
if ret != 0:
raise RunError("Command '{}' failed".format(''.join(command)),