generate-all-test-cases: add --build-rpms option

Add `--build-rpms` option which will make the script build osbuild-composer
RPMs on the remote runner from the sources which were copied over. These
RPMs are then installed on the system, before any image test cases are
generated.

Signed-off-by: Tomas Hozza <thozza@redhat.com>
This commit is contained in:
Tomas Hozza 2021-12-06 13:12:27 +01:00 committed by Ondřej Budai
parent 0379cb5796
commit 523bcdd98e
2 changed files with 48 additions and 14 deletions

View file

@ -104,6 +104,7 @@ In simplified example, the script does the following:
2. Waits for the Runner to be ready for use by running a specific command n it. 2. Waits for the Runner to be ready for use by running a specific command n it.
3. Installs RPMs necessary for the test case generation on the Runner. 3. Installs RPMs necessary for the test case generation on the Runner.
- In case you need to install packages from a specific external repository, you can specify each such repository using `--repofrompath` option. For example if you want to use the latest `osbuild` upstream build, use `--repofrompath 'osbuild,https://download.copr.fedorainfracloud.org/results/@osbuild/osbuild/fedora-$releasever-$basearch/'`. - In case you need to install packages from a specific external repository, you can specify each such repository using `--repofrompath` option. For example if you want to use the latest `osbuild` upstream build, use `--repofrompath 'osbuild,https://download.copr.fedorainfracloud.org/results/@osbuild/osbuild/fedora-$releasever-$basearch/'`.
- In case you need to install osbuild-composer RPMs, which were built from the sources copied over to the runner, use the `--build-rpms` option. The script will build osbuild-composer RPMs on the remote runner and install them.
4. Copies the 'sources' using rsync to the Runner. 4. Copies the 'sources' using rsync to the Runner.
5. Executes the 'tools/test-case-generators/generate-test-cases' on the runner for each requested distro and image type. 5. Executes the 'tools/test-case-generators/generate-test-cases' on the runner for each requested distro and image type.
6. After each image test case is generated successfully, the result is copied using rsync from the Runner to 'output' directory. 6. After each image test case is generated successfully, the result is copied using rsync from the Runner to 'output' directory.

View file

@ -25,6 +25,10 @@
- In case you need to install packages from a specific external repository, - In case you need to install packages from a specific external repository,
you can specify each such repository using --repofrompath option. you can specify each such repository using --repofrompath option.
e.g. --repofrompath 'osbuild,https://download.copr.fedorainfracloud.org/results/@osbuild/osbuild/fedora-$releasever-$basearch/' e.g. --repofrompath 'osbuild,https://download.copr.fedorainfracloud.org/results/@osbuild/osbuild/fedora-$releasever-$basearch/'
- In case you need to install osbuild-composer RPMs, which were built
from the sources copied over to the runner, use the `--build-rpms`
option. The script will build osbuild-composer RPMs on the remote
runner and install them.
4. Copies the 'sources' using rsync to the Runner. 4. Copies the 'sources' using rsync to the Runner.
5. Executes the 'tools/test-case-generators/generate-test-cases' on the 5. Executes the 'tools/test-case-generators/generate-test-cases' on the
runner for each requested distro and image type. runner for each requested distro and image type.
@ -730,7 +734,7 @@ class BaseTestCaseMatrixGenerator(contextlib.AbstractContextManager):
"python3-pyyaml", # needed by image-info "python3-pyyaml", # needed by image-info
] ]
def __init__(self, arch_gen_matrix, sources, output, ssh_id_file, repos=[], keep_workdir=False, log_level=logging.INFO): def __init__(self, arch_gen_matrix, sources, output, ssh_id_file, repos=[], build_rpms=False, keep_workdir=False, log_level=logging.INFO):
""" """
'arch_get_matrix' is a dict of requested distro-image_type matrix per architecture: 'arch_get_matrix' is a dict of requested distro-image_type matrix per architecture:
{ {
@ -767,6 +771,7 @@ class BaseTestCaseMatrixGenerator(contextlib.AbstractContextManager):
self.output = output self.output = output
self.ssh_id_file = ssh_id_file self.ssh_id_file = ssh_id_file
self.repos = repos self.repos = repos
self.build_rpms = build_rpms
self.keep_workdir = keep_workdir self.keep_workdir = keep_workdir
self.log_level = log_level self.log_level = log_level
@ -849,15 +854,20 @@ class BaseTestCaseMatrixGenerator(contextlib.AbstractContextManager):
# install necessary packages # install necessary packages
runner.dnf_install(self.install_rpms_list) runner.dnf_install(self.install_rpms_list)
# Log installed versions of important RPMs
rpm_versions, _, _ = runner.run_command("rpm -q osbuild osbuild-composer")
log.info("Installed packages: %s", " ".join(rpm_versions.split("\n")))
# copy sources from the host to the runner # copy sources from the host to the runner
log.info("Copying sources to the runner") log.info("Copying sources to the runner")
runner_sources_dir = f"{runner_workdir}/sources" runner_sources_dir = f"{runner_workdir}/sources"
runner.copytree_to_runner(self.sources, runner_sources_dir) runner.copytree_to_runner(self.sources, runner_sources_dir)
if self.build_rpms:
# build composer RPMs from the copied over sources and install them
self._build_install_rpms_from_source(runner, runner_sources_dir)
# Log installed versions of important RPMs
rpm_versions, _, _ = runner.run_command("rpm -q osbuild osbuild-composer")
log.info("Installed packages: %s", " ".join(rpm_versions.split("\n")))
# create output directory for the results on the runner # create output directory for the results on the runner
runner_output_dir = f"{runner_workdir}/output" runner_output_dir = f"{runner_workdir}/output"
runner.run_command_check_call(f"mkdir {runner_output_dir}") runner.run_command_check_call(f"mkdir {runner_output_dir}")
@ -911,6 +921,21 @@ class BaseTestCaseMatrixGenerator(contextlib.AbstractContextManager):
log.info("'%s' finished its work", current_process_name) log.info("'%s' finished its work", current_process_name)
log.info("Results: %s", results) log.info("Results: %s", results)
@staticmethod
def _build_install_rpms_from_source(runner: BaseRunner, sources_path: os.PathLike):
"""
Builds the (presumably osbuild-composer's) RPMs from sources on the runner
and installs them on the runner.
"""
log.info("Building RPMs from source and installing them")
enter_src_dir = f"cd {sources_path};"
runner.dnf_install(["'@RPM Development Tools'"])
runner.run_command_check_call(f"{enter_src_dir} sudo dnf -y builddep *.spec")
runner.run_command_check_call(f"{enter_src_dir} make rpm")
# do not install debuginfo and debugsource RPMs
runner.run_command_check_call(f"{enter_src_dir} sudo dnf install -y $(ls rpmbuild/RPMS/*/*.rpm | grep -Ev 'debugsource|debuginfo')")
def _cleanup(self): def _cleanup(self):
""" """
Terminates all running Runner processes. Terminates all running Runner processes.
@ -940,7 +965,7 @@ class BaseTestCaseMatrixGenerator(contextlib.AbstractContextManager):
raise NotImplementedError() raise NotImplementedError()
@staticmethod @staticmethod
def main(arch_gen_matrix_dict, sources, output, ssh_id_file, repos, keep_workdir, parser_args): def main(arch_gen_matrix_dict, sources, output, ssh_id_file, repos, build_rpms, keep_workdir, parser_args):
raise NotImplementedError() raise NotImplementedError()
@ -964,7 +989,7 @@ class QEMUTestCaseMatrixGenerator(BaseTestCaseMatrixGenerator):
"s390x": S390xQEMURunner "s390x": S390xQEMURunner
} }
def __init__(self, images, arch_gen_matrix, sources, output, ssh_id_file, repos=[], ci_userdata=None, keep_workdir=False, log_level=logging.INFO): def __init__(self, images, arch_gen_matrix, sources, output, ssh_id_file, repos=[], build_rpms=False, ci_userdata=None, keep_workdir=False, log_level=logging.INFO):
""" """
'images' is a dict of qcow2 image paths for each supported architecture, 'images' is a dict of qcow2 image paths for each supported architecture,
that should be used for VMs: that should be used for VMs:
@ -1000,7 +1025,7 @@ class QEMUTestCaseMatrixGenerator(BaseTestCaseMatrixGenerator):
for generating CDROM ISO image, that is attached to each VM as a cloud-init data source. for generating CDROM ISO image, that is attached to each VM as a cloud-init data source.
If the value is not provided, then the default internal cloud-init user-data are used. If the value is not provided, then the default internal cloud-init user-data are used.
""" """
super().__init__(arch_gen_matrix, sources, output, ssh_id_file, repos, keep_workdir, log_level) super().__init__(arch_gen_matrix, sources, output, ssh_id_file, repos, build_rpms, keep_workdir, log_level)
self.images = images self.images = images
self.ci_userdata = ci_userdata self.ci_userdata = ci_userdata
@ -1079,7 +1104,7 @@ class QEMUTestCaseMatrixGenerator(BaseTestCaseMatrixGenerator):
parser_qemu.set_defaults(func=QEMUTestCaseMatrixGenerator.main) parser_qemu.set_defaults(func=QEMUTestCaseMatrixGenerator.main)
@staticmethod @staticmethod
def main(arch_gen_matrix_dict, sources, output, ssh_id_file, repos, keep_workdir, parser_args): def main(arch_gen_matrix_dict, sources, output, ssh_id_file, repos, build_rpms, keep_workdir, parser_args):
""" """
The main function of the 'qemu' command The main function of the 'qemu' command
""" """
@ -1093,7 +1118,8 @@ class QEMUTestCaseMatrixGenerator(BaseTestCaseMatrixGenerator):
with QEMUTestCaseMatrixGenerator( with QEMUTestCaseMatrixGenerator(
vm_images, arch_gen_matrix_dict, sources, output, vm_images, arch_gen_matrix_dict, sources, output,
ssh_id_file, repos, ci_userdata, keep_workdir, log.level) as generator: ssh_id_file, repos, build_rpms, ci_userdata, keep_workdir,
log.level) as generator:
generator.generate() generator.generate()
@ -1111,7 +1137,7 @@ class RemoteTestCaseMatrixGenerator(BaseTestCaseMatrixGenerator):
"s390x": RemoteRunner "s390x": RemoteRunner
} }
def __init__(self, hosts, username, arch_gen_matrix, sources, output, ssh_id_file, repos, keep_workdir, log_level=logging.INFO): def __init__(self, hosts, username, arch_gen_matrix, sources, output, ssh_id_file, repos, build_rpms, keep_workdir, log_level=logging.INFO):
""" """
'hosts' is a dict of a remote system hostnames or IP addresses for each supported architecture, 'hosts' is a dict of a remote system hostnames or IP addresses for each supported architecture,
that should be used to generate image test cases: that should be used to generate image test cases:
@ -1146,7 +1172,7 @@ class RemoteTestCaseMatrixGenerator(BaseTestCaseMatrixGenerator):
'output' is a directory path, where the generated test case manifests should be stored. 'output' is a directory path, where the generated test case manifests should be stored.
'ssh_id_file' is path to the SSH ID file to use as the authorized key for the QEMU VMs. 'ssh_id_file' is path to the SSH ID file to use as the authorized key for the QEMU VMs.
""" """
super().__init__(arch_gen_matrix, sources, output, ssh_id_file, repos, keep_workdir, log_level) super().__init__(arch_gen_matrix, sources, output, ssh_id_file, repos, build_rpms, keep_workdir, log_level)
self.hosts = hosts self.hosts = hosts
self.username = username self.username = username
@ -1211,7 +1237,7 @@ class RemoteTestCaseMatrixGenerator(BaseTestCaseMatrixGenerator):
parser_remote.set_defaults(func=RemoteTestCaseMatrixGenerator.main) parser_remote.set_defaults(func=RemoteTestCaseMatrixGenerator.main)
@staticmethod @staticmethod
def main(arch_gen_matrix_dict, sources, output, ssh_id_file, repos, keep_workdir, parser_args): def main(arch_gen_matrix_dict, sources, output, ssh_id_file, repos, build_rpms, keep_workdir, parser_args):
""" """
The main function of the 'remote' command The main function of the 'remote' command
""" """
@ -1225,7 +1251,7 @@ class RemoteTestCaseMatrixGenerator(BaseTestCaseMatrixGenerator):
with RemoteTestCaseMatrixGenerator( with RemoteTestCaseMatrixGenerator(
hosts, username, arch_gen_matrix_dict, sources, output, hosts, username, arch_gen_matrix_dict, sources, output,
ssh_id_file, repos, keep_workdir, log.level) as generator: ssh_id_file, repos, build_rpms, keep_workdir, log.level) as generator:
generator.generate() generator.generate()
@ -1317,6 +1343,12 @@ def get_args():
help="Don't delete the workdir created on the remote host after finishing.", help="Don't delete the workdir created on the remote host after finishing.",
default=False default=False
) )
parser.add_argument(
"--build-rpms",
action="store_true",
help="Build RPMs from sources copied to the runner and install them.",
default=False
)
parser.add_argument( parser.add_argument(
"--repofrompath", "--repofrompath",
metavar="<repo>,<path/url>", metavar="<repo>,<path/url>",
@ -1349,6 +1381,7 @@ def main(args):
arches = args.arch arches = args.arch
image_types = args.image_type image_types = args.image_type
repos = args.repofrompath repos = args.repofrompath
build_rpms = args.build_rpms
keep_workdir = args.keep_workdir keep_workdir = args.keep_workdir
# determine the SSH ID file to be used # determine the SSH ID file to be used
@ -1400,7 +1433,7 @@ def main(args):
log.debug("arch_gen_matrix_dict:\n%s", json.dumps(arch_gen_matrix_dict, indent=2, sort_keys=True)) log.debug("arch_gen_matrix_dict:\n%s", json.dumps(arch_gen_matrix_dict, indent=2, sort_keys=True))
args.func(arch_gen_matrix_dict, sources, output, ssh_id_file, repos, keep_workdir, args) args.func(arch_gen_matrix_dict, sources, output, ssh_id_file, repos, build_rpms, keep_workdir, args)
if __name__ == '__main__': if __name__ == '__main__':