1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
|
# SPDX-License-Identifier: LGPL-2.1-only
#
# Container class for the libcgroup functional tests
#
# Copyright (c) 2019-2021 Oracle and/or its affiliates.
# Author: Tom Hromatka <tom.hromatka@oracle.com>
#
from run import Run, RunError
from queue import Queue
import threading as tp
from log import Log
import consts
import time
import os
class Container(object):
def __init__(self, name, stop_timeout=None, arch=None, cfg_path=None,
distro=None, release=None):
self.name = name
self.privileged = True
if stop_timeout:
self.stop_timeout = stop_timeout
else:
self.stop_timeout = consts.DEFAULT_CONTAINER_STOP_TIMEOUT
if arch:
self.arch = arch
else:
self.arch = consts.DEFAULT_CONTAINER_ARCH
if distro:
self.distro = distro
else:
self.distro = consts.DEFAULT_CONTAINER_DISTRO
if release:
self.release = release
else:
self.release = consts.DEFAULT_CONTAINER_RELEASE
ftest_dir = os.path.dirname(os.path.abspath(__file__))
tests_dir = os.path.dirname(ftest_dir)
# save off the path to the libcgroup source code
self.libcg_dir = os.path.dirname(tests_dir)
def __str__(self):
out_str = 'Container {}'.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\tstop_timeout = {}\n'.format(self.stop_timeout)
return out_str
# configure the container to meet our needs
def config(self):
# 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:
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 _init_container(self, q):
cmd = list()
if self.privileged:
cmd.append('sudo')
cmd.append('lxc')
cmd.append('init')
cmd.append('{}:{}'.format(self.distro, self.release))
cmd.append(self.name)
try:
Run.run(cmd)
q.put(True)
except Exception: # noqa: E722
q.put(False)
except BaseException: # noqa: E722
q.put(False)
def create(self):
# Github Actions sometimes has timeout issues with the LXC sockets.
# Try this command multiple times in an attempt to work around this
# limitation
queue = Queue()
sleep_time = 5
ret = False
for i in range(5):
thread = tp.Thread(target=self._init_container, args=(queue, ))
thread.start()
time_cnt = 0
while thread.is_alive():
time.sleep(sleep_time)
time_cnt += sleep_time
Log.log_debug('Waiting... {}'.format(time_cnt))
ret = queue.get()
if ret:
break
else:
try:
self.delete()
except RunError:
pass
thread.join()
if not ret:
raise ContainerError('Failed to create the container')
def delete(self):
cmd = list()
if self.privileged:
cmd.append('sudo')
cmd.append('lxc')
cmd.append('delete')
cmd.append(self.name)
return Run.run(cmd)
def run(self, cntnr_cmd, shell_bool=False):
cmd = list()
if self.privileged:
cmd.append('sudo')
cmd.append('lxc')
cmd.append('exec')
cmd.append(self.name)
cmd.append('--')
# concatenate the lxc exec command with the command to be run
# inside the container
if isinstance(cntnr_cmd, str):
cmd.append(cntnr_cmd)
elif isinstance(cntnr_cmd, list):
cmd = cmd + cntnr_cmd
else:
raise ContainerError('Unsupported command type')
return Run.run(cmd, shell_bool=shell_bool)
def start(self):
cmd = list()
if self.privileged:
cmd.append('sudo')
cmd.append('lxc')
cmd.append('start')
cmd.append(self.name)
return Run.run(cmd)
def stop(self, force=True):
cmd = list()
if self.privileged:
cmd.append('sudo')
cmd.append('lxc')
cmd.append('stop')
cmd.append(self.name)
if force:
cmd.append('-f')
else:
cmd.append('--timeout')
cmd.append(str(self.stop_timeout))
return Run.run(cmd)
class ContainerError(Exception):
def __init__(self, message):
super(ContainerError, self).__init__(message)
def __str__(self):
out_str = 'ContainerError:\n\tmessage = {}'.format(self.message)
return out_str
# vim: set et ts=4 sw=4:
|