tools/stx/toCOPY/pkgbuilder/schrootspool.py
Haiqing Bai e5affdf346 Debian: pkgbuilder: Support parallel build with multiple chroots
Multiple chroots are created based on the client's request.
The maximum number of chroots are defined in the client's request.
If the chroots count the client required exceeds the maximum of
chroots, it must wait for some tasks to complete and at least
one chroot is released. The client decides how many parallel
build requests initiated.
'schrootspool' is used to manage all the created chroots and
is responsible for chroots applying and releasing.

The local repository 'deb-local-build' in '/etc/sbuild/sbuild.conf'
which is used to resolve dependency is removed for race condition:
Aptly does not support parallel accessing, when package A is built
done and the deb binaries are uploaded to 'deb-local-build', the
meta file of the repository like 'Release' will disappear for
a while until the new one is generated after Aptly publishing.
During the time, package B is fetching the repository to get the
depended packages, it fails to run 'apt-get' command on
'deb-local-build', to resolve this race condition, the config item
'deb http://stx-stx-repomgr:80/deb-local-build bullseye main' is
removed from '/etc/sbuild/sbuild.conf' and the snapshot mirror
'deb-local-build-<x>' is added to each sbuild command.

Story: 2008846
Task: 45665

Test Plan:
Pass: build-pkgs -c -a
pass: build-pkgs -c -l compiler,distro --parallel
pass: build-pkgs -c -a --parallel

Signed-off-by: Haiqing Bai <haiqing.bai@windriver.com>
Change-Id: I8deae43d7923beb6916e977313ad05bb57e10cca
2022-07-27 13:23:34 +08:00

122 lines
3.8 KiB
Python

# 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.
#
# Copyright (C) 2022 Wind River Systems,Inc
#
import logging
import subprocess
SCHROOTS_CONFIG = '/etc/schroot/chroot.d/'
class Schroot:
def __init__(self, name, state='idle'):
self.name = name
self.state = state
def is_idle(self):
if self.state == 'idle':
return True
return False
def set_busy(self):
self.state = 'work'
def get_name(self):
return self.name
class SchrootsPool:
"""
schrootsPool manages all the schroots in current container
The schroots listed by schroot -l will be registered
and assigned the build task
"""
def __init__(self, logger):
self.schroots = []
self.logger = logger
def exists(self, name):
for schroot in self.schroots:
if schroot.name == name:
return True
return False
def load(self):
schroots = subprocess.run(['schroot', '-l'], stdout=subprocess.PIPE,
universal_newlines=True).stdout.splitlines()
if len(schroots) < 1:
self.logger.error('There are no schroots found, exit')
return False
for sname in schroots:
# Filter 'chroot:bullseye-amd64-<user>' as the backup chroot
if len(sname.split('-')) >= 4 and not self.exists(sname):
self.schroots.append(Schroot(sname.strip(), 'idle'))
return True
def apply(self):
self.logger.debug("schroot pool status:")
self.show()
for schroot in self.schroots:
if schroot.is_idle():
schroot.set_busy()
self.logger.debug('%s has been assigned', schroot.name)
return schroot.name
self.logger.debug("No idle schroot can be used")
return None
def release(self, name):
for schroot in self.schroots:
if schroot.name == name.strip():
# Fixme, whether need to end session here
schroot.state = 'idle'
self.logger.debug('%s has been released', name)
def get_idle(self):
idle_schroots = []
for schroot in self.schroots:
schroot_name = schroot.get_name()
if not schroot.is_idle():
self.logger.error('schroot %s is busy and can not be refreshed', schroot_name)
continue
idle_schroots.append(schroot_name)
self.logger.debug('schroot %s is idle and can be refreshed', schroot_name)
return idle_schroots
def release_all(self):
for schroot in self.schroots:
# Fixme, whether need to end session here
schroot.state = 'idle'
self.logger.debug('All chroots has been released')
def show(self):
for schroot in self.schroots:
self.logger.info("schroot name:%s state:%s", schroot.name, schroot.state)
if __name__ == "__main__":
"""
For unit tests
"""
logger = logging.getLogger('schrootPool')
logger.setLevel(logging.DEBUG)
schroots_pool = SchrootsPool(logger)
schroots_pool.load()
s0 = schroots_pool.apply()
s1 = schroots_pool.apply()
s2 = schroots_pool.apply()
schroots_pool.show()
schroots_pool.release(s0)
schroots_pool.release(s1)
schroots_pool.show()