Add post build cleanup of tmpfs chroots
The memory tied up in tmpfs filesystems needs to be released after building packages. This update also tries to simplify some of the more tortured logic, overly complex functions, code duplications and confusing or inconsistent namings. partial-bug: 2081843 Change-Id: I59c12602929a8da1c5076c27243d6e6dca951c61 Signed-off-by: Scott Little <scott.little@windriver.com>
This commit is contained in:
parent
bd9a4b6959
commit
5f6223bf08
@ -140,5 +140,13 @@ def clean_stamp():
|
|||||||
return jsonify(response)
|
return jsonify(response)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/pkgbuilder/freetmpfschroots', methods=['GET'])
|
||||||
|
def free_tmpfs_chroots():
|
||||||
|
log_request('freetmpfschroots', request.form)
|
||||||
|
if dbuider_initialized():
|
||||||
|
response = dbuilder.free_tmpfs_chroots(request.form)
|
||||||
|
return jsonify(response)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(host='0.0.0.0', port=80, debug=True)
|
app.run(host='0.0.0.0', port=80, debug=True)
|
||||||
|
@ -70,9 +70,107 @@ class Debbuilder(object):
|
|||||||
self.attrs['mode'] = mode
|
self.attrs['mode'] = mode
|
||||||
self.attrs['dist'] = dist
|
self.attrs['dist'] = dist
|
||||||
self.attrs['arch'] = arch
|
self.attrs['arch'] = arch
|
||||||
|
self.attrs['unique_id'] = None
|
||||||
self.set_extra_repos()
|
self.set_extra_repos()
|
||||||
self.set_environ_vars()
|
self.set_environ_vars()
|
||||||
os.system('/opt/setup.sh')
|
os.system('/opt/setup.sh')
|
||||||
|
self.schroot_config_dir = '/etc/schroot/chroot.d'
|
||||||
|
|
||||||
|
def get_parent_chroot_name(self, user):
|
||||||
|
return '-'.join([self.attrs['dist'], self.attrs['arch'], user])
|
||||||
|
|
||||||
|
def get_cloned_chroot_name(self, user, chroot_sequence):
|
||||||
|
return '-'.join([self.get_parent_chroot_name(user), str(chroot_sequence)])
|
||||||
|
|
||||||
|
def get_user_dir(self, user, project):
|
||||||
|
return os.path.join(STORE_ROOT, user, project)
|
||||||
|
|
||||||
|
def get_user_schroot_config_dir(self, user, project):
|
||||||
|
user_dir = self.get_user_dir(user, project)
|
||||||
|
return os.path.join(user_dir, 'chroots/chroot.d')
|
||||||
|
|
||||||
|
def get_user_chroots_dir(self, user, project):
|
||||||
|
user_dir = self.get_user_dir(user, project)
|
||||||
|
return os.path.join(user_dir, 'chroots')
|
||||||
|
|
||||||
|
def get_user_schroot_log_path(self, user, project):
|
||||||
|
user_dir = self.get_user_dir(user, project)
|
||||||
|
return os.path.join(user_dir, 'chroot.log')
|
||||||
|
|
||||||
|
def get_parent_chroot_dir(self, user, project):
|
||||||
|
user_chroots_dir = self.get_user_chroots_dir(user, project)
|
||||||
|
parent_chroot_name = self.get_parent_chroot_name(user)
|
||||||
|
return os.path.join(user_chroots_dir, parent_chroot_name)
|
||||||
|
|
||||||
|
def get_cloned_chroot_dir(self, user, project, chroot_sequence):
|
||||||
|
user_chroots_dir = self.get_user_chroots_dir(user, project)
|
||||||
|
cloned_chroot_name = self.get_cloned_chroot_name(user, chroot_sequence)
|
||||||
|
return os.path.join(user_chroots_dir, cloned_chroot_name)
|
||||||
|
|
||||||
|
def get_user_stamp_dir(self, user, project, build_type):
|
||||||
|
user_dir = self.get_user_dir(user, project)
|
||||||
|
return os.path.join(user_dir, build_type, 'stamp')
|
||||||
|
|
||||||
|
def compose_chroot_name(self, user, index=None):
|
||||||
|
chroot_name = '-'.join([self.attrs['dist'], self.attrs['arch'], user])
|
||||||
|
if index is not None:
|
||||||
|
chroot_name = '-'.join([chroot_name, str(index)])
|
||||||
|
return chroot_name
|
||||||
|
|
||||||
|
def decompose_chroot_name(self, chroot_name):
|
||||||
|
components = {}
|
||||||
|
parts = chroot_name.split('-')
|
||||||
|
if len(parts) < 3:
|
||||||
|
return components
|
||||||
|
components['dist'] = parts[0]
|
||||||
|
components['arch'] = parts[1]
|
||||||
|
components['user'] = parts[2]
|
||||||
|
if len(parts) >= 4:
|
||||||
|
components['index'] = parts[3]
|
||||||
|
return components
|
||||||
|
|
||||||
|
def index_from_chroot_name(self, chroot_name):
|
||||||
|
components = self.decompose_chroot_name(chroot_name)
|
||||||
|
if 'index' in components:
|
||||||
|
return int(components['index'])
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_schroot_conf_path(self, user, index=None):
|
||||||
|
parent_chroot_name = self.get_parent_chroot_name(user)
|
||||||
|
conf_file_path = schrootspool.get_schroot_conf_path(parent_chroot_name)
|
||||||
|
if conf_file_path is None:
|
||||||
|
return None
|
||||||
|
if index is not None:
|
||||||
|
conf_file_path = '-'.join([conf_file_path, str(index)])
|
||||||
|
return conf_file_path
|
||||||
|
|
||||||
|
def compose_schroot_name(self, user, index=None):
|
||||||
|
if self.attrs['unique_id'] is None:
|
||||||
|
self.logger.error("compose_schroot_name: attribute 'unique_id' has noty been set.")
|
||||||
|
return None
|
||||||
|
schroot_name = '-'.join([self.attrs['dist'], self.attrs['arch'], self.attrs['unique_id'], user])
|
||||||
|
if index is not None:
|
||||||
|
schroot_name = '-'.join([schroot_name, str(index)])
|
||||||
|
return schroot_name
|
||||||
|
|
||||||
|
def decompose_schroot_config_name(self, schroot_config_name):
|
||||||
|
components = {}
|
||||||
|
parts = schroot_config_name.split('-')
|
||||||
|
if len(parts) < 4:
|
||||||
|
return components
|
||||||
|
components['dist'] = parts[0]
|
||||||
|
components['arch'] = parts[1]
|
||||||
|
components['user'] = parts[2]
|
||||||
|
components['unique_id'] = parts[3]
|
||||||
|
if len(parts) >= 5:
|
||||||
|
components['index'] = parts[4]
|
||||||
|
return components
|
||||||
|
|
||||||
|
def index_from_schroot_config_name(self, schroot_config_name):
|
||||||
|
components = self.decompose_schroot_config_name(schroot_config_name)
|
||||||
|
if 'index' in components:
|
||||||
|
return int(components['index'])
|
||||||
|
return None
|
||||||
|
|
||||||
def get_state(self):
|
def get_state(self):
|
||||||
response = {}
|
response = {}
|
||||||
@ -160,6 +258,30 @@ class Debbuilder(object):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def is_parent_config(self, schroot_config_name):
|
||||||
|
index = self.index_from_schroot_config_name(schroot_config_name)
|
||||||
|
if index is None:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_parent_schroot_config(self):
|
||||||
|
schroot_conf_list = os.listdir(self.schroot_config_dir)
|
||||||
|
for schroot_conf_name in schroot_conf_list:
|
||||||
|
if self.is_parent_config(schroot_conf_name):
|
||||||
|
return schroot_conf_name
|
||||||
|
return None
|
||||||
|
|
||||||
|
def set_unique_id(self):
|
||||||
|
parent_schroot_config_name = self.get_parent_schroot_config()
|
||||||
|
self.logger.debug("parent_schroot_config_name: %s" % parent_schroot_config_name)
|
||||||
|
parent_schroot_components = self.decompose_schroot_config_name(parent_schroot_config_name)
|
||||||
|
if parent_schroot_components and 'unique_id' in parent_schroot_components:
|
||||||
|
self.attrs['unique_id'] = parent_schroot_components['unique_id']
|
||||||
|
self.logger.debug("unique_id: %s" % self.attrs['unique_id'])
|
||||||
|
else:
|
||||||
|
self.logger.error("failed to determine schroot unique_id from parent schroot name")
|
||||||
|
|
||||||
def add_chroot(self, request_form):
|
def add_chroot(self, request_form):
|
||||||
response = check_request(request_form, ['user', 'project'])
|
response = check_request(request_form, ['user', 'project'])
|
||||||
if response:
|
if response:
|
||||||
@ -167,29 +289,31 @@ class Debbuilder(object):
|
|||||||
user = request_form['user']
|
user = request_form['user']
|
||||||
project = request_form['project']
|
project = request_form['project']
|
||||||
|
|
||||||
chroot = '-'.join([self.attrs['dist'], self.attrs['arch'], user])
|
parent_chroot_name = self.get_parent_chroot_name(user)
|
||||||
if self.has_chroot(chroot):
|
if self.has_chroot(parent_chroot_name):
|
||||||
self.logger.warn("chroot %s already exists" % chroot)
|
self.logger.warn("chroot %s already exists" % parent_chroot_name)
|
||||||
|
self.set_unique_id()
|
||||||
response['status'] = 'exists'
|
response['status'] = 'exists'
|
||||||
response['msg'] = 'chroot exists'
|
response['msg'] = 'chroot exists'
|
||||||
return response
|
return response
|
||||||
|
|
||||||
user_dir = os.path.join(STORE_ROOT, user, project)
|
user_chroots_dir = self.get_user_chroots_dir(user, project)
|
||||||
user_chroots_dir = os.path.join(user_dir, 'chroots')
|
parent_chroot_dir = self.get_parent_chroot_dir(user, project)
|
||||||
|
user_schroot_log_path = self.get_user_schroot_log_path(user, project)
|
||||||
|
|
||||||
os.makedirs(user_chroots_dir, exist_ok=True)
|
os.makedirs(user_chroots_dir, exist_ok=True)
|
||||||
self.logger.debug("Directory of chroots: %s" % user_chroots_dir)
|
self.logger.debug("Directory of chroots: %s" % user_chroots_dir)
|
||||||
|
|
||||||
user_chroot = os.path.join(user_chroots_dir, chroot)
|
self.logger.debug("Found disused chroot %s, remove it" % parent_chroot_dir)
|
||||||
self.logger.debug("Found disused chroot %s, remove it" % user_chroot)
|
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(user_chroot)
|
shutil.rmtree(parent_chroot_dir)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.error(str(e))
|
||||||
# New chroot will be created below, we just reports this
|
# New chroot will be created below, we just reports this
|
||||||
self.logger.warning("Failed to remove %s" % user_chroot)
|
self.logger.warning("Failed to remove %s" % parent_chroot_dir)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.ctlog = open(os.path.join(user_dir, 'chroot.log'), 'w')
|
self.ctlog = open(user_schroot_log_path, 'w')
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
self.logger.error(str(e))
|
self.logger.error(str(e))
|
||||||
response['status'] = 'fail'
|
response['status'] = 'fail'
|
||||||
@ -199,7 +323,7 @@ class Debbuilder(object):
|
|||||||
chroot_cmd = ' '.join(['sbuild-createchroot', chroot_suffix,
|
chroot_cmd = ' '.join(['sbuild-createchroot', chroot_suffix,
|
||||||
'--include=apt-transport-https,ca-certificates,eatmydata',
|
'--include=apt-transport-https,ca-certificates,eatmydata',
|
||||||
'--command-prefix=eatmydata',
|
'--command-prefix=eatmydata',
|
||||||
self.attrs['dist'], user_chroot])
|
self.attrs['dist'], parent_chroot_dir])
|
||||||
if 'mirror' in request_form:
|
if 'mirror' in request_form:
|
||||||
chroot_cmd = ' '.join([chroot_cmd, request_form['mirror']])
|
chroot_cmd = ' '.join([chroot_cmd, request_form['mirror']])
|
||||||
self.logger.debug("Command to create chroot:%s" % chroot_cmd)
|
self.logger.debug("Command to create chroot:%s" % chroot_cmd)
|
||||||
@ -208,35 +332,149 @@ class Debbuilder(object):
|
|||||||
stderr=self.ctlog)
|
stderr=self.ctlog)
|
||||||
self.chroot_processes.setdefault(user, []).append(p)
|
self.chroot_processes.setdefault(user, []).append(p)
|
||||||
|
|
||||||
|
self.set_unique_id()
|
||||||
response['status'] = 'creating'
|
response['status'] = 'creating'
|
||||||
response['msg'] = 'Chroot creating, please check %s/chroot.log' % user_dir
|
response['msg'] = 'Chroot created, please check logs at: %s' % user_schroot_log_path
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def save_chroots_config(self, user, project):
|
def save_chroots_config(self, user, project):
|
||||||
self.logger.debug("Save the config file of chroot to persistent store")
|
self.logger.debug("Save the config file of chroot to persistent store")
|
||||||
user_conf_store_dir = os.path.join(STORE_ROOT, user, project, 'chroots/chroot.d')
|
user_schroot_config_dir = self.get_user_schroot_config_dir(user, project)
|
||||||
system_conf_dir = '/etc/schroot/chroot.d'
|
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(user_conf_store_dir)
|
shutil.rmtree(user_schroot_config_dir)
|
||||||
shutil.copytree(system_conf_dir, user_conf_store_dir)
|
shutil.copytree(self.schroot_config_dir, user_schroot_config_dir)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.error(str(e))
|
||||||
self.logger.error("Failed to save the config file of chroot")
|
self.logger.error("Failed to save the config file of chroot")
|
||||||
else:
|
else:
|
||||||
self.logger.info("Successfully saved the config file of chroot")
|
self.logger.info("Successfully saved the config file of chroot")
|
||||||
|
|
||||||
def is_parent_config(self, parent_chroot_name, target_config):
|
def delete_cloned_chroot(self, user, project, index):
|
||||||
# The name of config file for the parent schroot has two parts:
|
"""
|
||||||
# chroot_name + '-' + random number
|
Delete a clone chroot
|
||||||
# e.g. bullseye-amd64-user-yWJpyF
|
"""
|
||||||
# The name of config file for the cloned schroot has three parts:
|
rc = True
|
||||||
# chroot_name + '-' + random number + '-' + sequence
|
delete_chroot_dir = self.get_cloned_chroot_dir(user, project, index)
|
||||||
# e.g. bullseye-amd64-user-yWJpyF-1
|
|
||||||
conf_file_suffix = target_config.replace(parent_chroot_name + '-', '')
|
# Delete old chroot
|
||||||
if '-' not in conf_file_suffix:
|
if delete_chroot_dir is not None and os.path.exists(delete_chroot_dir):
|
||||||
return True
|
self.logger.debug('Delete chroot at path: %s', delete_chroot_dir)
|
||||||
|
try:
|
||||||
|
if utils.is_tmpfs(delete_chroot_dir):
|
||||||
|
utils.unmount_tmpfs(delete_chroot_dir)
|
||||||
|
shell_cmd = 'rm -rf --one-file-system %s' % delete_chroot_dir
|
||||||
|
self.logger.debug('shell_cmd=%s', shell_cmd)
|
||||||
|
subprocess.check_call(shell_cmd, shell=True)
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(str(e))
|
||||||
|
self.logger.error("Failed to delete unwanted chroot: %s", delete_chroot_dir)
|
||||||
|
rc = False
|
||||||
|
|
||||||
|
return rc
|
||||||
|
|
||||||
|
def delete_cloned_schroot_config(self, user, project, index):
|
||||||
|
"""
|
||||||
|
Delete a clone's schroot config
|
||||||
|
"""
|
||||||
|
rc = True
|
||||||
|
delete_conf_path = self.get_schroot_conf_path(user, index)
|
||||||
|
|
||||||
|
if delete_conf_path is not None and os.path.exists(delete_conf_path):
|
||||||
|
self.logger.debug('Delete schroot config at path: %s', delete_conf_path)
|
||||||
|
try:
|
||||||
|
shell_cmd = 'rm -f %s' % delete_conf_path
|
||||||
|
self.logger.debug('shell_cmd=%s', shell_cmd)
|
||||||
|
subprocess.check_call(shell_cmd, shell=True)
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(str(e))
|
||||||
|
self.logger.error("Failed to remove unwanted config file: %s", delete_conf_path)
|
||||||
|
rc = False
|
||||||
|
|
||||||
|
# self.chroots_pool.load()
|
||||||
|
return rc
|
||||||
|
|
||||||
|
def delete_clones_by_max_index(self, user, project, max_index):
|
||||||
|
"""
|
||||||
|
Delete a clone's chroot dir and schroot config file if it's index exceeds the maximum.
|
||||||
|
i.e. the number of parallel instances is being reduced
|
||||||
|
"""
|
||||||
|
rc = True
|
||||||
|
|
||||||
|
schroot_conf_list = os.listdir(self.schroot_config_dir)
|
||||||
|
for schroot_conf_name in schroot_conf_list:
|
||||||
|
index = self.index_from_schroot_config_name(schroot_conf_name)
|
||||||
|
if index is None or index <= max_index:
|
||||||
|
continue
|
||||||
|
if not self.delete_cloned_schroot_config(user, project, index):
|
||||||
|
rc = False
|
||||||
|
|
||||||
|
user_chroots_dir = self.get_user_chroots_dir(user, project)
|
||||||
|
chroot_list = os.listdir(user_chroots_dir)
|
||||||
|
for chroot_name in chroot_list:
|
||||||
|
if chroot_name == 'chroot.d':
|
||||||
|
continue
|
||||||
|
index = self.index_from_chroot_name(chroot_name)
|
||||||
|
if index is None or index <= max_index:
|
||||||
|
continue
|
||||||
|
if not self.delete_cloned_chroot(user, project, index):
|
||||||
|
rc = False
|
||||||
|
|
||||||
|
# self.chroots_pool.load()
|
||||||
|
return rc
|
||||||
|
|
||||||
|
def delete_all_clone_chroots(self, user, project):
|
||||||
|
rc = True
|
||||||
|
|
||||||
|
user_chroots_dir = self.get_user_chroots_dir(user, project)
|
||||||
|
chroot_list = os.listdir(user_chroots_dir)
|
||||||
|
for chroot_name in chroot_list:
|
||||||
|
if chroot_name == 'chroot.d':
|
||||||
|
continue
|
||||||
|
index = self.index_from_chroot_name(chroot_name)
|
||||||
|
if index is None:
|
||||||
|
continue
|
||||||
|
if not self.delete_cloned_chroot(user, project, index):
|
||||||
|
rc = False
|
||||||
|
|
||||||
|
return rc
|
||||||
|
|
||||||
|
def delete_tmpfs_clones(self, user, project):
|
||||||
|
rc = True
|
||||||
|
|
||||||
|
user_chroots_dir = self.get_user_chroots_dir(user, project)
|
||||||
|
chroot_list = os.listdir(user_chroots_dir)
|
||||||
|
for chroot_name in chroot_list:
|
||||||
|
if chroot_name == 'chroot.d':
|
||||||
|
continue
|
||||||
|
if not utils.is_tmpfs(os.path.join(user_chroots_dir, chroot_name)):
|
||||||
|
continue
|
||||||
|
index = self.index_from_chroot_name(chroot_name)
|
||||||
|
if index is None:
|
||||||
|
continue
|
||||||
|
if not self.delete_cloned_chroot(user, project, index):
|
||||||
|
rc = False
|
||||||
|
if not self.delete_cloned_schroot_config(user, project, index):
|
||||||
|
rc = False
|
||||||
|
|
||||||
|
return rc
|
||||||
|
|
||||||
|
def free_tmpfs_chroots(self, request_form):
|
||||||
|
response = check_request(request_form, ['user', 'project'])
|
||||||
|
if response:
|
||||||
|
return response
|
||||||
|
|
||||||
|
user = request_form['user']
|
||||||
|
project = request_form['project']
|
||||||
|
if not self.delete_tmpfs_clones(user, project):
|
||||||
|
msg = 'Failed to delete some tmpfs chroots.'
|
||||||
|
self.logger.error(msg)
|
||||||
|
response['status'] = 'fail'
|
||||||
|
response['msg'] = msg
|
||||||
else:
|
else:
|
||||||
return False
|
response['status'] = 'success'
|
||||||
|
response['msg'] = 'tmpfs chroots have been freed'
|
||||||
|
self.chroots_pool.load()
|
||||||
|
return response
|
||||||
|
|
||||||
def clone_chroot(self, request_form):
|
def clone_chroot(self, request_form):
|
||||||
"""
|
"""
|
||||||
@ -260,15 +498,32 @@ class Debbuilder(object):
|
|||||||
chroot_sequence = 1
|
chroot_sequence = 1
|
||||||
|
|
||||||
# Try to find the parent chroot
|
# Try to find the parent chroot
|
||||||
user_dir = os.path.join(STORE_ROOT, user, project)
|
|
||||||
# e.g bullseye-amd64-user
|
# e.g bullseye-amd64-user
|
||||||
parent_chroot_name = '-'.join([self.attrs['dist'], self.attrs['arch'], user])
|
parent_chroot_name = self.get_parent_chroot_name(user)
|
||||||
# e.g /localdisk/pkgbuilder/user/stx/chroots/bullseye-amd64-user
|
# e.g /localdisk/pkgbuilder/user/stx/chroots/bullseye-amd64-user
|
||||||
parent_chroot_path = os.path.join(user_dir, 'chroots', parent_chroot_name)
|
parent_chroot_dir = self.get_parent_chroot_dir(user, project)
|
||||||
if not os.path.exists(parent_chroot_path):
|
|
||||||
self.logger.error("Failed to find the parent chroot %s", parent_chroot_path)
|
if not os.path.exists(parent_chroot_dir):
|
||||||
|
self.logger.error("Failed to find the parent chroot %s", parent_chroot_dir)
|
||||||
response['status'] = 'fail'
|
response['status'] = 'fail'
|
||||||
response['msg'] = 'The parent chroot %s does not exist' % parent_chroot_path
|
response['msg'] = 'The parent chroot %s does not exist' % parent_chroot_dir
|
||||||
|
return response
|
||||||
|
|
||||||
|
parent_conf_path = self.get_schroot_conf_path(user)
|
||||||
|
if parent_conf_path is None or not os.path.exists(parent_conf_path):
|
||||||
|
self.logger.error("Failed to find the parent schroot config file for %s", parent_chroot_name)
|
||||||
|
response['status'] = 'fail'
|
||||||
|
response['msg'] = 'The parent schroot config file for %s does not exist' % parent_chroot_name
|
||||||
|
return response
|
||||||
|
|
||||||
|
if not self.delete_clones_by_max_index(user, project, required_instances):
|
||||||
|
response['status'] = 'fail'
|
||||||
|
response['msg'] = 'Failed to delete old schroot instances'
|
||||||
|
return response
|
||||||
|
|
||||||
|
if not self.delete_all_clone_chroots(user, project):
|
||||||
|
response['status'] = 'fail'
|
||||||
|
response['msg'] = 'Failed to delete old chroot instances'
|
||||||
return response
|
return response
|
||||||
|
|
||||||
# tmpfs calculations
|
# tmpfs calculations
|
||||||
@ -285,44 +540,38 @@ class Debbuilder(object):
|
|||||||
if mem_per_instance_gb >= min_tmpfs_size_gb:
|
if mem_per_instance_gb >= min_tmpfs_size_gb:
|
||||||
break
|
break
|
||||||
|
|
||||||
self.logger.debug("The parent chroot %s exists, start to clone chroot with it", parent_chroot_path)
|
self.logger.debug("The parent chroot %s exists, start to clone chroot from it", parent_chroot_dir)
|
||||||
self.logger.debug("creating %s instances, including %s instances using %s gb of tmpfs", required_instances, tmpfs_instances, mem_per_instance_gb)
|
self.logger.debug("creating %s instances, including %s instances using %s gb of tmpfs", required_instances, tmpfs_instances, mem_per_instance_gb)
|
||||||
for instance in range(required_instances):
|
for instance in range(required_instances):
|
||||||
cloned_chroot_name = parent_chroot_name + '-' + str(chroot_sequence)
|
cloned_chroot_name = self.get_cloned_chroot_name(user, chroot_sequence)
|
||||||
cloned_chroot_path = parent_chroot_path + '-' + str(chroot_sequence)
|
cloned_chroot_dir = self.get_cloned_chroot_dir(user, project, chroot_sequence)
|
||||||
|
clone_conf_path = self.get_schroot_conf_path(user, chroot_sequence)
|
||||||
|
|
||||||
|
if clone_conf_path is None:
|
||||||
|
err_msg = "Failed to determine the schroot config file for %s" % cloned_chroot_name
|
||||||
|
self.logger.error(err_msg)
|
||||||
|
response['status'] = 'fail'
|
||||||
|
response['msg'] = err_msg
|
||||||
|
return response
|
||||||
|
|
||||||
use_tmpfs = (instance >= (required_instances - tmpfs_instances))
|
use_tmpfs = (instance >= (required_instances - tmpfs_instances))
|
||||||
|
|
||||||
# Delete old chroot
|
|
||||||
if os.path.exists(cloned_chroot_path):
|
|
||||||
try:
|
|
||||||
if utils.is_tmpfs(cloned_chroot_path):
|
|
||||||
utils.unmount_tmpfs(cloned_chroot_path)
|
|
||||||
shell_cmd = 'rm -rf --one-file-system %s' % cloned_chroot_path
|
|
||||||
subprocess.check_call(shell_cmd, shell=True)
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(str(e))
|
|
||||||
response['status'] = 'fail'
|
|
||||||
if not response['msg']:
|
|
||||||
response['msg'] = 'Failed to delete old chroot instances:'
|
|
||||||
response['msg'].append(str(instance) + ' ')
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Create new chroot
|
# Create new chroot
|
||||||
self.logger.info("Cloning chroot %s from the parent %s", cloned_chroot_path, parent_chroot_path)
|
self.logger.info("Cloning chroot %s from the parent %s", cloned_chroot_dir, parent_chroot_dir)
|
||||||
try:
|
try:
|
||||||
if use_tmpfs:
|
if use_tmpfs:
|
||||||
os.makedirs(cloned_chroot_path)
|
os.makedirs(cloned_chroot_dir)
|
||||||
shell_cmd = 'mount -t tmpfs -o size=%sG tmpfs %s' % (mem_per_instance_gb, cloned_chroot_path)
|
shell_cmd = 'mount -t tmpfs -o size=%sG tmpfs %s' % (mem_per_instance_gb, cloned_chroot_dir)
|
||||||
subprocess.check_call(shell_cmd, shell=True)
|
subprocess.check_call(shell_cmd, shell=True)
|
||||||
shell_cmd = 'cp -ar %s/. %s/' % (parent_chroot_path, cloned_chroot_path)
|
shell_cmd = 'cp -ar %s/. %s/' % (parent_chroot_dir, cloned_chroot_dir)
|
||||||
subprocess.check_call(shell_cmd, shell=True)
|
subprocess.check_call(shell_cmd, shell=True)
|
||||||
else:
|
else:
|
||||||
self.logger.info("Cloning chroot %s from the parent %s", cloned_chroot_path, parent_chroot_path)
|
self.logger.info("Cloning chroot %s from the parent %s", cloned_chroot_dir, parent_chroot_dir)
|
||||||
shell_cmd = 'rm -rf %s.tmp' % cloned_chroot_path
|
shell_cmd = 'rm -rf %s.tmp' % cloned_chroot_dir
|
||||||
subprocess.check_call(shell_cmd, shell=True)
|
subprocess.check_call(shell_cmd, shell=True)
|
||||||
shell_cmd = 'cp -ar %s %s.tmp' % (parent_chroot_path, cloned_chroot_path)
|
shell_cmd = 'cp -ar %s %s.tmp' % (parent_chroot_dir, cloned_chroot_dir)
|
||||||
subprocess.check_call(shell_cmd, shell=True)
|
subprocess.check_call(shell_cmd, shell=True)
|
||||||
shell_cmd = 'mv %s.tmp %s' % (cloned_chroot_path, cloned_chroot_path)
|
shell_cmd = 'mv %s.tmp %s' % (cloned_chroot_dir, cloned_chroot_dir)
|
||||||
subprocess.check_call(shell_cmd, shell=True)
|
subprocess.check_call(shell_cmd, shell=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.error(str(e))
|
||||||
@ -332,41 +581,34 @@ class Debbuilder(object):
|
|||||||
response['msg'].append(str(instance) + ' ')
|
response['msg'].append(str(instance) + ' ')
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
self.logger.info("Successfully cloned chroot %s", cloned_chroot_path)
|
self.logger.info("Successfully cloned chroot %s", cloned_chroot_dir)
|
||||||
|
|
||||||
self.logger.info("Target cloned chroot %s is ready, updated config", cloned_chroot_path)
|
self.logger.info("Target cloned chroot %s is ready, updating config", cloned_chroot_dir)
|
||||||
# For the cloned chroot, the schroot config file also need to be created
|
|
||||||
# Try to find the config file of parent schroot and take it as template
|
# For the cloned chroot, the schroot config file also need to be created.
|
||||||
# e.g. it is /etc/chroots/chroot.d/bullseye-amd64-user-yWJpyF
|
# Start with the parent schroot as a template and modify it
|
||||||
schroot_conf_dir = os.listdir(os.path.join('/etc/schroot/chroot.d'))
|
if os.path.exists(clone_conf_path):
|
||||||
for conf in schroot_conf_dir:
|
self.logger.debug("Cloned chroot config %s already exists", clone_conf_path)
|
||||||
if self.is_parent_config(parent_chroot_name, conf):
|
chroot_sequence = chroot_sequence + 1
|
||||||
parent_conf_name = conf
|
continue
|
||||||
parent_conf_path = os.path.join('/etc/schroot/chroot.d', parent_conf_name)
|
try:
|
||||||
self.logger.info("Found the config of the parent chroot: %s", parent_conf_name)
|
self.logger.debug("Creating config file %s from %s", clone_conf_path, parent_conf_path)
|
||||||
new_conf_name = parent_conf_name + '-' + str(chroot_sequence)
|
shutil.copyfile(parent_conf_path, clone_conf_path)
|
||||||
new_conf_path = os.path.join('/etc/schroot/chroot.d', new_conf_name)
|
self.logger.debug("Successfully cloned chroot config, try to update %s", clone_conf_path)
|
||||||
if os.path.exists(new_conf_path):
|
shell_cmd = 'sed -i \'s/%s/%s/g\' %s' % (parent_chroot_name, cloned_chroot_name, clone_conf_path)
|
||||||
self.logger.debug("Cloned chroot config %s already exists", new_conf_path)
|
subprocess.check_call(shell_cmd, shell=True)
|
||||||
chroot_sequence = chroot_sequence + 1
|
except Exception as e:
|
||||||
continue
|
self.logger.error(str(e))
|
||||||
try:
|
self.logger.error("Failed to clone and update config file %s", clone_conf_path)
|
||||||
self.logger.debug("Creating config file %s from %s", new_conf_name, parent_conf_name)
|
break
|
||||||
shutil.copyfile(parent_conf_path, new_conf_path)
|
else:
|
||||||
self.logger.debug("Successfully cloned chroot config, try to update %s", new_conf_name)
|
self.logger.debug("Successfully cloned and updated chroot's config %s", clone_conf_path)
|
||||||
shell_cmd = 'sed -i \'s/%s/%s/g\' %s' % (parent_chroot_name, cloned_chroot_name, new_conf_path)
|
chroot_sequence = chroot_sequence + 1
|
||||||
subprocess.check_call(shell_cmd, shell=True)
|
break
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(str(e))
|
|
||||||
self.logger.error("Failed to clone and update config file %s", new_conf_path)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
self.logger.debug("Successfully cloned and updated chroot's config %s", new_conf_path)
|
|
||||||
chroot_sequence = chroot_sequence + 1
|
|
||||||
break
|
|
||||||
|
|
||||||
# Save the above chroot config files to the external persistent storage
|
# Save the above chroot config files to the external persistent storage
|
||||||
self.save_chroots_config(user, project)
|
self.save_chroots_config(user, project)
|
||||||
|
|
||||||
if chroot_sequence == required_instances + 1:
|
if chroot_sequence == required_instances + 1:
|
||||||
self.logger.info("All required %s chroots are created", str(required_instances))
|
self.logger.info("All required %s chroots are created", str(required_instances))
|
||||||
response['status'] = 'success'
|
response['status'] = 'success'
|
||||||
@ -376,6 +618,7 @@ class Debbuilder(object):
|
|||||||
required_instances, chroot_sequence - 1)
|
required_instances, chroot_sequence - 1)
|
||||||
response['status'] = 'fail'
|
response['status'] = 'fail'
|
||||||
response['msg'] = 'Available chroots=%d' % (chroot_sequence - 1)
|
response['msg'] = 'Available chroots=%d' % (chroot_sequence - 1)
|
||||||
|
|
||||||
# Reload all chroots into the chroots pool
|
# Reload all chroots into the chroots pool
|
||||||
self.chroots_pool.load()
|
self.chroots_pool.load()
|
||||||
return response
|
return response
|
||||||
@ -387,18 +630,16 @@ class Debbuilder(object):
|
|||||||
user = request_form['user']
|
user = request_form['user']
|
||||||
project = request_form['project']
|
project = request_form['project']
|
||||||
|
|
||||||
user_dir = os.path.join(STORE_ROOT, user, project)
|
user_schroot_config_dir = self.get_user_schroot_config_dir(user, project)
|
||||||
user_chroots = os.path.join(user_dir, 'chroots/chroot.d')
|
if not os.path.exists(user_schroot_config_dir):
|
||||||
if not os.path.exists(user_chroots):
|
self.logger.warn("Failed to find directory of chroots %s" % user_schroot_config_dir)
|
||||||
self.logger.warn("Failed to find directory of chroots %s" % user_chroots)
|
|
||||||
response['status'] = 'success'
|
response['status'] = 'success'
|
||||||
response['msg'] = ' '.join(['External chroot', user_chroots,
|
response['msg'] = ' '.join(['External chroot', user_schroot_config_dir,
|
||||||
'does not exist'])
|
'does not exist'])
|
||||||
else:
|
else:
|
||||||
target_dir = '/etc/schroot/chroot.d'
|
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(target_dir)
|
shutil.rmtree(self.schroot_config_dir)
|
||||||
shutil.copytree(user_chroots, target_dir)
|
shutil.copytree(user_schroot_config_dir, self.schroot_config_dir)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.error(str(e))
|
||||||
self.logger.error("Failed to load external config file of chroot")
|
self.logger.error("Failed to load external config file of chroot")
|
||||||
@ -418,21 +659,19 @@ class Debbuilder(object):
|
|||||||
user = request_form['user']
|
user = request_form['user']
|
||||||
project = request_form['project']
|
project = request_form['project']
|
||||||
|
|
||||||
user_dir = os.path.join(STORE_ROOT, user, project)
|
user_schroot_config_dir = self.get_user_schroot_config_dir(user, project)
|
||||||
user_chroots = os.path.join(user_dir, 'chroots/chroot.d')
|
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(user_chroots)
|
shutil.rmtree(user_schroot_config_dir)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.error(str(e))
|
||||||
# Just report this but not quit
|
# Just report this but not quit
|
||||||
self.logger.error("Failed to remove %s", user_chroots)
|
self.logger.error("Failed to remove %s", user_schroot_config_dir)
|
||||||
|
|
||||||
sys_schroots = '/etc/schroot/chroot.d'
|
|
||||||
try:
|
try:
|
||||||
shutil.copytree(sys_schroots, user_chroots)
|
shutil.copytree(self.schroot_config_dir, user_schroot_config_dir)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(str(e))
|
self.logger.error(str(e))
|
||||||
self.logger.error("Failed to save %s with %s", sys_schroots, user_chroots)
|
self.logger.error("Failed to save %s with %s", self.schroot_config_dir, user_schroot_config_dir)
|
||||||
response['status'] = 'fail'
|
response['status'] = 'fail'
|
||||||
response['msg'] = 'Failed to save the config files of chroots to persistent storage'
|
response['msg'] = 'Failed to save the config files of chroots to persistent storage'
|
||||||
else:
|
else:
|
||||||
@ -443,7 +682,7 @@ class Debbuilder(object):
|
|||||||
|
|
||||||
def refresh_chroots(self, request_form):
|
def refresh_chroots(self, request_form):
|
||||||
'''
|
'''
|
||||||
Refresh all chroots with the backup 'clean' chroot
|
Refresh all chroots with the 'clean' parent chroot
|
||||||
'''
|
'''
|
||||||
response = check_request(request_form, ['user', 'project'])
|
response = check_request(request_form, ['user', 'project'])
|
||||||
if response:
|
if response:
|
||||||
@ -463,54 +702,48 @@ class Debbuilder(object):
|
|||||||
subprocess.call('schroot --all --end-session', shell=True)
|
subprocess.call('schroot --all --end-session', shell=True)
|
||||||
|
|
||||||
dst_chroots = self.chroots_pool.get_idle()
|
dst_chroots = self.chroots_pool.get_idle()
|
||||||
backup_chroot = None
|
user_chroots_dir = self.get_user_chroots_dir(user, project)
|
||||||
user_dir = os.path.join(STORE_ROOT, user, project)
|
parent_chroot_name = self.get_parent_chroot_dir(user, project)
|
||||||
user_chroots_dir = os.path.join(user_dir, 'chroots')
|
if not os.path.exists(os.path.join(user_chroots_dir, parent_chroot_name)):
|
||||||
for chroot in dst_chroots:
|
self.logger.error("The parent chroot %s does not exist", parent_chroot_name)
|
||||||
|
response['status'] = 'fail'
|
||||||
|
response['msg'] = 'The parent chroot does not exist'
|
||||||
|
return response
|
||||||
|
for clone_chroot_name in dst_chroots:
|
||||||
# e.g. the chroot name is 'chroot:bullseye-amd64-<user>-1'
|
# e.g. the chroot name is 'chroot:bullseye-amd64-<user>-1'
|
||||||
self.logger.debug('The current chroot is %s', chroot)
|
self.logger.debug('The current chroot is %s', clone_chroot_name)
|
||||||
# chroot = chroot.split(':')[1]
|
if parent_chroot_name == clone_chroot_name:
|
||||||
self.logger.debug('The name of chroot: %s', chroot)
|
|
||||||
if not backup_chroot:
|
|
||||||
backup_chroot = chroot[0:chroot.rindex('-')]
|
|
||||||
self.logger.debug('The name of backup chroot: %s', backup_chroot)
|
|
||||||
if not os.path.exists(os.path.join(user_chroots_dir, backup_chroot)):
|
|
||||||
self.logger.error("The backup chroot %s does not exist", backup_chroot)
|
|
||||||
response['status'] = 'fail'
|
|
||||||
response['msg'] = 'The backup chroot does not exist'
|
|
||||||
return response
|
|
||||||
if backup_chroot == chroot:
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
backup_chroot_path = os.path.join(user_chroots_dir, backup_chroot)
|
parent_chroot_path = os.path.join(user_chroots_dir, parent_chroot_name)
|
||||||
self.logger.debug('The backup chroot path: %s', backup_chroot_path)
|
self.logger.debug('The parent chroot path: %s', parent_chroot_path)
|
||||||
chroot_path = os.path.join(user_chroots_dir, chroot)
|
clone_chroot_path = os.path.join(user_chroots_dir, clone_chroot_name)
|
||||||
self.logger.debug('The chroot path: %s', chroot_path)
|
self.logger.debug('The chroot path: %s', clone_chroot_path)
|
||||||
is_tmpfs = self.chroots_pool.is_tmpfs(chroot)
|
is_tmpfs = self.chroots_pool.is_tmpfs(clone_chroot_name)
|
||||||
self.logger.debug('is_tmpfs: %s', is_tmpfs)
|
self.logger.debug('is_tmpfs: %s', is_tmpfs)
|
||||||
try:
|
try:
|
||||||
if is_tmpfs:
|
if is_tmpfs:
|
||||||
self.logger.debug('clean directory: %s', chroot_path)
|
self.logger.debug('clean directory: %s', clone_chroot_path)
|
||||||
utils.clear_directory(chroot_path)
|
utils.clear_directory(clone_chroot_path)
|
||||||
shell_cmd = 'cp -ar %s/. %s/' % (backup_chroot_path, chroot_path)
|
shell_cmd = 'cp -ar %s/. %s/' % (parent_chroot_path, clone_chroot_path)
|
||||||
self.logger.debug('shell_cmd: %s', shell_cmd)
|
self.logger.debug('shell_cmd: %s', shell_cmd)
|
||||||
subprocess.check_call(shell_cmd, shell=True)
|
subprocess.check_call(shell_cmd, shell=True)
|
||||||
self.logger.debug('cmd exits: %s', shell_cmd)
|
self.logger.debug('cmd exits: %s', shell_cmd)
|
||||||
else:
|
else:
|
||||||
cp_cmd = 'cp -ra %s %s' % (backup_chroot_path, chroot_path + '.tmp')
|
cp_cmd = 'cp -ra %s %s' % (parent_chroot_path, clone_chroot_path + '.tmp')
|
||||||
subprocess.check_call(cp_cmd, shell=True)
|
subprocess.check_call(cp_cmd, shell=True)
|
||||||
rm_cmd = 'rm -rf --one-file-system ' + chroot_path
|
rm_cmd = 'rm -rf --one-file-system ' + clone_chroot_path
|
||||||
subprocess.check_call(rm_cmd, shell=True)
|
subprocess.check_call(rm_cmd, shell=True)
|
||||||
mv_cmd = 'mv -f %s %s' % (chroot_path + '.tmp', chroot_path)
|
mv_cmd = 'mv -f %s %s' % (clone_chroot_path + '.tmp', clone_chroot_path)
|
||||||
subprocess.check_call(mv_cmd, shell=True)
|
subprocess.check_call(mv_cmd, shell=True)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
self.logger.error(str(e))
|
self.logger.error(str(e))
|
||||||
self.logger.error('Failed to refresh the chroot %s', chroot)
|
self.logger.error('Failed to refresh the chroot %s', clone_chroot_name)
|
||||||
response['status'] = 'fail'
|
response['status'] = 'fail'
|
||||||
response['msg'] = 'Error during refreshing the chroots'
|
response['msg'] = 'Error during refreshing the chroots'
|
||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
self.logger.info('Successfully refreshed the chroot %s', chroot)
|
self.logger.info('Successfully refreshed the chroot %s', clone_chroot_name)
|
||||||
|
|
||||||
self.logger.info('Successfully refreshed all idle chroots')
|
self.logger.info('Successfully refreshed all idle chroots')
|
||||||
response['status'] = 'success'
|
response['status'] = 'success'
|
||||||
@ -552,11 +785,11 @@ class Debbuilder(object):
|
|||||||
size = request_form['size']
|
size = request_form['size']
|
||||||
allow_tmpfs = request_form['allow_tmpfs']
|
allow_tmpfs = request_form['allow_tmpfs']
|
||||||
|
|
||||||
chroot = '-'.join([self.attrs['dist'], self.attrs['arch'], user])
|
chroot_name = self.compose_chroot_name(user)
|
||||||
if not self.has_chroot(chroot):
|
if not self.has_chroot(chroot_name):
|
||||||
self.logger.critical("The basic chroot %s does not exist" % chroot)
|
self.logger.critical("The basic chroot %s does not exist" % chroot_name)
|
||||||
response['status'] = 'fail'
|
response['status'] = 'fail'
|
||||||
response['msg'] = ' '.join(['chroot', chroot, 'does not exist'])
|
response['msg'] = ' '.join(['chroot', chroot_name, 'does not exist'])
|
||||||
return response
|
return response
|
||||||
|
|
||||||
# for example: dsc = '/path/to/tsconfig_1.0-1.stx.3.dsc'
|
# for example: dsc = '/path/to/tsconfig_1.0-1.stx.3.dsc'
|
||||||
@ -617,7 +850,7 @@ class Debbuilder(object):
|
|||||||
user = request_form['user']
|
user = request_form['user']
|
||||||
project = request_form['project']
|
project = request_form['project']
|
||||||
build_type = request_form['type']
|
build_type = request_form['type']
|
||||||
stamp_dir = os.path.join(STORE_ROOT, user, project, build_type, 'stamp')
|
stamp_dir = self.get_user_stamp_dir(user, project, build_type)
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(stamp_dir)
|
shutil.rmtree(stamp_dir)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -691,9 +924,9 @@ class Debbuilder(object):
|
|||||||
user = request_form['user']
|
user = request_form['user']
|
||||||
|
|
||||||
# check whether the need schroot exists
|
# check whether the need schroot exists
|
||||||
chroot = '-'.join([self.attrs['dist'], self.attrs['arch'], user])
|
chroot_name = self.compose_chroot_name(user)
|
||||||
if not self.has_chroot(chroot):
|
if not self.has_chroot(chroot_name):
|
||||||
self.logger.critical("No required chroot %s" % chroot)
|
self.logger.critical("Can't find required chroot: %s" % chroot_name)
|
||||||
|
|
||||||
req['user'] = user
|
req['user'] = user
|
||||||
req['owner'] = 'all'
|
req['owner'] = 'all'
|
||||||
|
@ -76,25 +76,38 @@ def human_readable_to_bytes(human_size):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def get_schroot_conf_path(name):
|
||||||
|
# Get path to schroot config file
|
||||||
|
schroot_config_lines = subprocess.run(['grep', '-r', '-l', '^[[]' + name + '[]]$', SCHROOTS_CONFIG],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
universal_newlines=True).stdout.splitlines()
|
||||||
|
for line in schroot_config_lines:
|
||||||
|
return line.strip()
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class Schroot(object):
|
class Schroot(object):
|
||||||
def __init__(self, name, state='idle'):
|
def __init__(self, name, state='idle'):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.state = state
|
self.state = state
|
||||||
self.path = ""
|
|
||||||
self.size = 0
|
self.size = 0
|
||||||
self.tmpfs = False
|
self.tmpfs = False
|
||||||
|
|
||||||
# Get path to schroot
|
self.path = self.get_chroot_dir()
|
||||||
schroot_config_lines = subprocess.run(['schroot', '--config', '--chroot', name],
|
if self.path:
|
||||||
|
statvfs = os.statvfs(self.path)
|
||||||
|
self.size = statvfs.f_frsize * statvfs.f_bavail
|
||||||
|
self.tmpfs = utils.is_tmpfs(self.path)
|
||||||
|
|
||||||
|
def get_chroot_dir(self):
|
||||||
|
# Get path to chroot
|
||||||
|
schroot_config_lines = subprocess.run(['schroot', '--config', '--chroot', self.name],
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
universal_newlines=True).stdout.splitlines()
|
universal_newlines=True).stdout.splitlines()
|
||||||
for line in schroot_config_lines:
|
for line in schroot_config_lines:
|
||||||
if line.startswith('directory='):
|
if line.startswith('directory='):
|
||||||
self.path = line.split('=')[1].strip()
|
return line.split('=')[1].strip()
|
||||||
statvfs = os.statvfs(self.path)
|
return ''
|
||||||
self.size = statvfs.f_frsize * statvfs.f_bavail
|
|
||||||
self.tmpfs = utils.is_tmpfs(self.path)
|
|
||||||
break
|
|
||||||
|
|
||||||
def is_idle(self):
|
def is_idle(self):
|
||||||
if self.state == 'idle':
|
if self.state == 'idle':
|
||||||
@ -136,18 +149,36 @@ class SchrootsPool(object):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_schroot_list(self):
|
||||||
|
schroot_list = []
|
||||||
|
for line in subprocess.run(['schroot', '--list'], stdout=subprocess.PIPE,
|
||||||
|
universal_newlines=True).stdout.splitlines():
|
||||||
|
schroot_list.append(line.split(':')[1].strip())
|
||||||
|
return schroot_list
|
||||||
|
|
||||||
|
def get_schroot_clone_list(self):
|
||||||
|
schroot_clone_list = []
|
||||||
|
for schroot_name in self.get_schroot_list():
|
||||||
|
if len(schroot_name.split('-')) >= 4:
|
||||||
|
schroot_clone_list.append(schroot_name)
|
||||||
|
return schroot_clone_list
|
||||||
|
|
||||||
|
def get_schroot_parent(self):
|
||||||
|
for schroot_name in self.get_schroot_list():
|
||||||
|
if len(schroot_name.split('-')) < 4:
|
||||||
|
return schroot_name
|
||||||
|
self.logger.error('parent schroot not found')
|
||||||
|
raise ValueError('parent schroot not found')
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
self.schroots = []
|
self.schroots = []
|
||||||
schroots = subprocess.run(['schroot', '--list'], stdout=subprocess.PIPE,
|
schroots = self.get_schroot_clone_list()
|
||||||
universal_newlines=True).stdout.splitlines()
|
|
||||||
if len(schroots) < 1:
|
if len(schroots) < 1:
|
||||||
self.logger.error('There are no schroots found, exit')
|
self.logger.error('There are no schroots found, exit')
|
||||||
return False
|
return False
|
||||||
for sname in schroots:
|
for name in schroots:
|
||||||
# Filter 'chroot:bullseye-amd64-<user>' as the backup chroot
|
if not self.exists(name):
|
||||||
name = sname.split(':')[1]
|
self.schroots.append(Schroot(name, 'idle'))
|
||||||
if len(name.split('-')) >= 4 and not self.exists(sname):
|
|
||||||
self.schroots.append(Schroot(name.strip(), 'idle'))
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def acquire(self, needed_size=1, allow_tmpfs=True):
|
def acquire(self, needed_size=1, allow_tmpfs=True):
|
||||||
@ -170,6 +201,7 @@ class SchrootsPool(object):
|
|||||||
self.logger.debug('%s has been assigned', schroot.name)
|
self.logger.debug('%s has been assigned', schroot.name)
|
||||||
return schroot.name
|
return schroot.name
|
||||||
self.logger.debug("No idle schroot can be used")
|
self.logger.debug("No idle schroot can be used")
|
||||||
|
self.show()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def release(self, name):
|
def release(self, name):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user