[libvirt] [PATCH 00/10] ci: Several fixes and improvements

See the individual commits for details, but the gist of it is that after this series it's possible for users to hook into the build process and customize it according to their needs; on top of that, the whole thing is made more maintainable in the process. Andrea Bolognani (10): ci: Fix /etc/sub{u,g}id parsing ci: Drop $(CI_SUBMODULES) ci: Move everything to a separate directory ci: Create user's home directory in the container ci: Move source directory under $(CI_USER_HOME) ci: Introduce $(CI_BUILD_SCRIPT) ci: Generalize running commands inside the container ci: Introduce $(CI_PREPARE_SCRIPT) ci: Run $(CI_PREPARE_SCRIPT) as root ci: Stop using --workdir .gitignore | 2 +- .travis.yml | 8 +-- Makefile.am | 6 +- Makefile.ci => ci/Makefile | 109 +++++++++++++++++++------------------ ci/build.sh | 40 ++++++++++++++ ci/prepare.sh | 13 +++++ 6 files changed, 118 insertions(+), 60 deletions(-) rename Makefile.ci => ci/Makefile (79%) create mode 100644 ci/build.sh create mode 100644 ci/prepare.sh -- 2.21.0

The $ needs to be escaped when calling shell code from a Makefile. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- Makefile.ci | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.ci b/Makefile.ci index 977e0445c6..14d595a00f 100644 --- a/Makefile.ci +++ b/Makefile.ci @@ -114,8 +114,8 @@ ifeq ($(CI_ENGINE),podman) # need to be higher, but that only happens when your /etc/sub{u,g}id allow # users to have more IDs. Unless --keep-uid is supported, let's do this in a # way that should work for everyone. - CI_MAX_UID = $(shell sed -n "s/^$USER:[^:]\+://p" /etc/subuid) - CI_MAX_GID = $(shell sed -n "s/^$USER:[^:]\+://p" /etc/subgid) + CI_MAX_UID = $(shell sed -n "s/^$$USER:[^:]\+://p" /etc/subuid) + CI_MAX_GID = $(shell sed -n "s/^$$USER:[^:]\+://p" /etc/subgid) ifeq ($(CI_MAX_UID),) CI_MAX_UID = 65536 endif -- 2.21.0

We only use the list of submodules once, so no need to store it in a variable. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- Makefile.ci | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Makefile.ci b/Makefile.ci index 14d595a00f..86e936aef8 100644 --- a/Makefile.ci +++ b/Makefile.ci @@ -42,10 +42,6 @@ CI_MAKE_ARGS = # Any extra arguments to pass to configure CI_CONFIGURE_ARGS = -# Avoid pulling submodules over the network by locally -# cloning them -CI_SUBMODULES = $(shell git submodule | awk '{ print $$2 }') - # Location of the container images we're going to pull # Can be useful to overridde to use a locally built # image instead @@ -182,7 +178,7 @@ ci-prepare-tree: ci-check-engine cp /etc/group $(CI_SCRATCHDIR); \ echo "Cloning $(CI_GIT_ROOT) to $(CI_HOST_SRCDIR)"; \ git clone $(CI_GIT_ARGS) $(CI_GIT_ROOT) $(CI_HOST_SRCDIR) || exit 1; \ - for mod in $(CI_SUBMODULES) ; \ + for mod in $$(git submodule | awk '{ print $$2 }') ; \ do \ test -f $(CI_GIT_ROOT)/$$mod/.git || continue ; \ echo "Cloning $(CI_GIT_ROOT)/$$mod to $(CI_HOST_SRCDIR)/$$mod"; \ -- 2.21.0

We're going to have a few more CI-related files in a second, and it makes sense to have a separate directory for them rather than littering the root directory. $(CI_SCRATCHDIR) can now also be created inside the CI directory, and as a bonus the make rune necessary to start CI builds without running configure first becomes shorter. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- .gitignore | 2 +- .travis.yml | 8 ++++---- Makefile.am | 4 ++-- Makefile.ci => ci/Makefile | 17 ++++++++--------- 4 files changed, 15 insertions(+), 16 deletions(-) rename Makefile.ci => ci/Makefile (96%) diff --git a/.gitignore b/.gitignore index dd5d35c762..82495e8692 100644 --- a/.gitignore +++ b/.gitignore @@ -44,7 +44,7 @@ /autom4te.cache /build-aux/* /build/ -/ci-tree/ +/ci/scratch/ /confdefs.h /config.cache /config.guess diff --git a/.travis.yml b/.travis.yml index b510c81083..db573fd496 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,28 +22,28 @@ matrix: - IMAGE="ubuntu-18" - MAKE_ARGS="syntax-check distcheck" script: - - make -f Makefile.ci ci-build@$IMAGE CI_MAKE_ARGS="$MAKE_ARGS" + - make -C ci/ ci-build@$IMAGE CI_MAKE_ARGS="$MAKE_ARGS" - services: - docker env: - IMAGE="centos-7" - MAKE_ARGS="syntax-check distcheck" script: - - make -f Makefile.ci ci-build@$IMAGE CI_MAKE_ARGS="$MAKE_ARGS" + - make -C ci/ ci-build@$IMAGE CI_MAKE_ARGS="$MAKE_ARGS" - services: - docker env: - IMAGE="fedora-rawhide" - MINGW="mingw32" script: - - make -f Makefile.ci ci-build@$IMAGE CI_CONFIGURE="$MINGW-configure" + - make -C ci/ ci-build@$IMAGE CI_CONFIGURE="$MINGW-configure" - services: - docker env: - IMAGE="fedora-rawhide" - MINGW="mingw64" script: - - make -f Makefile.ci ci-build@$IMAGE CI_CONFIGURE="$MINGW-configure" + - make -C ci/ ci-build@$IMAGE CI_CONFIGURE="$MINGW-configure" - compiler: clang language: c os: osx diff --git a/Makefile.am b/Makefile.am index 27c49280c4..b743b4b08b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,7 +35,6 @@ EXTRA_DIST = \ libvirt-qemu.pc.in \ libvirt-lxc.pc.in \ libvirt-admin.pc.in \ - Makefile.ci \ Makefile.nonreentrant \ autogen.sh \ cfg.mk \ @@ -51,6 +50,7 @@ EXTRA_DIST = \ build-aux/prohibit-duplicate-header.pl \ build-aux/useless-if-before-free \ build-aux/vc-list-files \ + ci/Makefile \ $(NULL) pkgconfigdir = $(libdir)/pkgconfig @@ -123,4 +123,4 @@ gen-AUTHORS: fi ci-%: - $(MAKE) -f Makefile.ci $@ + $(MAKE) -C ci/ $@ diff --git a/Makefile.ci b/ci/Makefile similarity index 96% rename from Makefile.ci rename to ci/Makefile index 86e936aef8..350eb636cd 100644 --- a/Makefile.ci +++ b/ci/Makefile @@ -1,16 +1,15 @@ # -*- makefile -*- # vim: filetype=make -# Figure out name and path to this file. This isn't -# portable but we only care for modern GNU make -CI_MAKEFILE = $(abspath $(firstword $(MAKEFILE_LIST))) +# The root directory of the libvirt.git checkout +CI_GIT_ROOT = $(shell git rev-parse --show-toplevel) + +# The root directory for all CI-related contents +CI_ROOTDIR = $(CI_GIT_ROOT)/ci # The directory holding content on the host that we will # expose to the container. -CI_SCRATCHDIR = $(shell pwd)/ci-tree - -# The root directory of the libvirt.git checkout -CI_GIT_ROOT = $(shell git rev-parse --show-toplevel) +CI_SCRATCHDIR = $(CI_ROOTDIR)/scratch # The directory holding the clone of the git repo that # we will expose to the container @@ -178,7 +177,7 @@ ci-prepare-tree: ci-check-engine cp /etc/group $(CI_SCRATCHDIR); \ echo "Cloning $(CI_GIT_ROOT) to $(CI_HOST_SRCDIR)"; \ git clone $(CI_GIT_ARGS) $(CI_GIT_ROOT) $(CI_HOST_SRCDIR) || exit 1; \ - for mod in $$(git submodule | awk '{ print $$2 }') ; \ + for mod in $$(git submodule | awk '{ print $$2 }' | sed -E 's,^../,,g') ; \ do \ test -f $(CI_GIT_ROOT)/$$mod/.git || continue ; \ echo "Cloning $(CI_GIT_ROOT)/$$mod to $(CI_HOST_SRCDIR)/$$mod"; \ @@ -221,7 +220,7 @@ ci-build@%: ci-prepare-tree @test "$(CI_CLEAN)" = "1" && rm -rf $(CI_SCRATCHDIR) || : ci-check@%: - $(MAKE) -f $(CI_MAKEFILE) ci-build@$* CI_MAKE_ARGS="check" + $(MAKE) -C $(CI_ROOTDIR) ci-build@$* CI_MAKE_ARGS="check" ci-shell@%: ci-prepare-tree $(CI_ENGINE) run $(CI_ENGINE_ARGS) $(CI_IMAGE_PREFIX)$*$(CI_IMAGE_TAG) /bin/bash -- 2.21.0

Some applications expect the user's home directory to be present on the system and require workarounds when that's not the case. Creating the home directory along with everything else is easy enough for us, so let's just do that. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- ci/Makefile | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ci/Makefile b/ci/Makefile index 350eb636cd..f52a0bf621 100644 --- a/ci/Makefile +++ b/ci/Makefile @@ -65,6 +65,11 @@ CI_REUSE = 0 CI_UID = $(shell id -u) CI_GID = $(shell id -g) +# We also need the user's login and home directory to prepare the +# environment the way some programs expect it +CI_USER_LOGIN = $(shell echo "$$USER") +CI_USER_HOME = $(shell echo "$$HOME") + CI_ENGINE = auto # Container engine we are going to use, can be overridden per make # invocation, if it is not we try podman and then default to docker. @@ -87,6 +92,10 @@ CI_PWDB_MOUNTS = \ --volume $(CI_SCRATCHDIR)/passwd:/etc/passwd:ro,z \ $(NULL) +CI_HOME_MOUNTS = \ + --volume $(CI_SCRATCHDIR)/home:$(CI_USER_HOME):z \ + $(NULL) + # Docker containers can have very large ulimits # for nofiles - as much as 1048576. This makes # libvirt very slow at exec'ing programs. @@ -109,8 +118,8 @@ ifeq ($(CI_ENGINE),podman) # need to be higher, but that only happens when your /etc/sub{u,g}id allow # users to have more IDs. Unless --keep-uid is supported, let's do this in a # way that should work for everyone. - CI_MAX_UID = $(shell sed -n "s/^$$USER:[^:]\+://p" /etc/subuid) - CI_MAX_GID = $(shell sed -n "s/^$$USER:[^:]\+://p" /etc/subgid) + CI_MAX_UID = $(shell sed -n "s/^$(CI_USER_LOGIN):[^:]\+://p" /etc/subuid) + CI_MAX_GID = $(shell sed -n "s/^$(CI_USER_LOGIN):[^:]\+://p" /etc/subgid) ifeq ($(CI_MAX_UID),) CI_MAX_UID = 65536 endif @@ -159,6 +168,7 @@ CI_ENGINE_ARGS = \ --tty \ $(CI_PODMAN_ARGS) \ $(CI_PWDB_MOUNTS) \ + $(CI_HOME_MOUNTS) \ --volume $(CI_HOST_SRCDIR):$(CI_CONT_SRCDIR):z \ --workdir $(CI_CONT_SRCDIR) \ --ulimit nofile=$(CI_ULIMIT_FILES):$(CI_ULIMIT_FILES) \ @@ -175,6 +185,7 @@ ci-prepare-tree: ci-check-engine mkdir -p $(CI_SCRATCHDIR); \ cp /etc/passwd $(CI_SCRATCHDIR); \ cp /etc/group $(CI_SCRATCHDIR); \ + mkdir -p $(CI_SCRATCHDIR)/home; \ echo "Cloning $(CI_GIT_ROOT) to $(CI_HOST_SRCDIR)"; \ git clone $(CI_GIT_ARGS) $(CI_GIT_ROOT) $(CI_HOST_SRCDIR) || exit 1; \ for mod in $$(git submodule | awk '{ print $$2 }' | sed -E 's,^../,,g') ; \ -- 2.21.0

Now that we have a home directory for the user, storing the source there rather than in a custom top-level directory is the obvious choice. Later on we're also going to add some more files related to builds, and storing everything in the user's home directory will keep things nice and tidy. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- ci/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/Makefile b/ci/Makefile index f52a0bf621..dc7ee6c037 100644 --- a/ci/Makefile +++ b/ci/Makefile @@ -18,7 +18,7 @@ CI_HOST_SRCDIR = $(CI_SCRATCHDIR)/src # The directory holding the source inside the # container, i.e. where we want to expose # the $(CI_HOST_SRCDIR) directory from the host -CI_CONT_SRCDIR = /src +CI_CONT_SRCDIR = $(CI_USER_HOME)/libvirt # Relative directory to perform the build in. This # defaults to using a separate build dir, but can be -- 2.21.0

Instead of hardcoding build instructions into the Makefile, move them to a separate script that's mounted into the container. This gives us a couple of advantages: we no longer have to deal with the awkward quoting required when embedding shell code in a Makefile, and we also provide the users with a way to override the default build instructions with their own. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- Makefile.am | 1 + ci/Makefile | 48 ++++++++++++++++++------------------------------ ci/build.sh | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 30 deletions(-) create mode 100644 ci/build.sh diff --git a/Makefile.am b/Makefile.am index b743b4b08b..96fac92186 100644 --- a/Makefile.am +++ b/Makefile.am @@ -51,6 +51,7 @@ EXTRA_DIST = \ build-aux/useless-if-before-free \ build-aux/vc-list-files \ ci/Makefile \ + ci/build.sh \ $(NULL) pkgconfigdir = $(libdir)/pkgconfig diff --git a/ci/Makefile b/ci/Makefile index dc7ee6c037..f7e31b4f97 100644 --- a/ci/Makefile +++ b/ci/Makefile @@ -41,6 +41,9 @@ CI_MAKE_ARGS = # Any extra arguments to pass to configure CI_CONFIGURE_ARGS = +# Script containing build instructions +CI_BUILD_SCRIPT = $(CI_ROOTDIR)/build.sh + # Location of the container images we're going to pull # Can be useful to overridde to use a locally built # image instead @@ -96,6 +99,10 @@ CI_HOME_MOUNTS = \ --volume $(CI_SCRATCHDIR)/home:$(CI_USER_HOME):z \ $(NULL) +CI_SCRIPT_MOUNTS = \ + --volume $(CI_SCRATCHDIR)/build:$(CI_USER_HOME)/build:z \ + $(NULL) + # Docker containers can have very large ulimits # for nofiles - as much as 1048576. This makes # libvirt very slow at exec'ing programs. @@ -169,6 +176,7 @@ CI_ENGINE_ARGS = \ $(CI_PODMAN_ARGS) \ $(CI_PWDB_MOUNTS) \ $(CI_HOME_MOUNTS) \ + $(CI_SCRIPT_MOUNTS) \ --volume $(CI_HOST_SRCDIR):$(CI_CONT_SRCDIR):z \ --workdir $(CI_CONT_SRCDIR) \ --ulimit nofile=$(CI_ULIMIT_FILES):$(CI_ULIMIT_FILES) \ @@ -186,6 +194,8 @@ ci-prepare-tree: ci-check-engine cp /etc/passwd $(CI_SCRATCHDIR); \ cp /etc/group $(CI_SCRATCHDIR); \ mkdir -p $(CI_SCRATCHDIR)/home; \ + cp "$(CI_BUILD_SCRIPT)" $(CI_SCRATCHDIR)/build; \ + chmod +x "$(CI_SCRATCHDIR)/build"; \ echo "Cloning $(CI_GIT_ROOT) to $(CI_HOST_SRCDIR)"; \ git clone $(CI_GIT_ARGS) $(CI_GIT_ROOT) $(CI_HOST_SRCDIR) || exit 1; \ for mod in $$(git submodule | awk '{ print $$2 }' | sed -E 's,^../,,g') ; \ @@ -196,38 +206,16 @@ ci-prepare-tree: ci-check-engine done ; \ fi -# $CONFIGURE_OPTS is a env that can optionally be set in the container, -# populated at build time from the Dockerfile. A typical use case would -# be to pass --host/--target args to trigger cross-compilation -# -# This can be augmented by make local args in $(CI_CONFIGURE_ARGS) -# -# gl_public_submodule_commit= to disable gnulib's submodule check -# which breaks due to way we clone the submodules ci-build@%: ci-prepare-tree $(CI_ENGINE) run $(CI_ENGINE_ARGS) $(CI_IMAGE_PREFIX)$*$(CI_IMAGE_TAG) \ - /bin/bash -c '\ - mkdir -p $(CI_CONT_BUILDDIR) || exit 1 ; \ - cd $(CI_CONT_BUILDDIR) ; \ - NOCONFIGURE=1 $(CI_CONT_SRCDIR)/autogen.sh || exit 1 ; \ - $(CI_CONFIGURE) $${CONFIGURE_OPTS} $(CI_CONFIGURE_ARGS) ; \ - if test $$? != 0 ; \ - then \ - test -f config.log && cat config.log ; \ - exit 1 ; \ - fi; \ - find -name test-suite.log -delete ; \ - export VIR_TEST_DEBUG=1 ; \ - make -j$(CI_SMP) gl_public_submodule_commit= $(CI_MAKE_ARGS) ; \ - if test $$? != 0 ; then \ - LOGS=`find -name test-suite.log` ; \ - if test "$${LOGS}" != "" ; then \ - echo "=== LOG FILE(S) START ===" ; \ - cat $${LOGS} ; \ - echo "=== LOG FILE(S) END ===" ; \ - fi ; \ - exit 1 ;\ - fi' + /bin/bash -c ' \ + export CI_CONT_SRCDIR="$(CI_CONT_SRCDIR)"; \ + export CI_CONT_BUILDDIR="$(CI_CONT_BUILDDIR)"; \ + export CI_SMP="$(CI_SMP)"; \ + export CI_CONFIGURE="$(CI_CONFIGURE)"; \ + export CI_CONFIGURE_ARGS="$(CI_CONFIGURE_ARGS)"; \ + export CI_MAKE_ARGS="$(CI_MAKE_ARGS)"; \ + $(CI_USER_HOME)/build || exit 1' @test "$(CI_CLEAN)" = "1" && rm -rf $(CI_SCRATCHDIR) || : ci-check@%: diff --git a/ci/build.sh b/ci/build.sh new file mode 100644 index 0000000000..0874c2d1d9 --- /dev/null +++ b/ci/build.sh @@ -0,0 +1,40 @@ +# This script is used to build libvirt inside the container. +# +# You can customize it to your liking, or alternatively use a +# completely different script by passing +# +# CI_BUILD_SCRIPT=/path/to/your/build/script +# +# to make. + +mkdir -p "$CI_CONT_BUILDDIR" || exit 1 +cd "$CI_CONT_BUILDDIR" + +export VIR_TEST_DEBUG=1 +NOCONFIGURE=1 "$CI_CONT_SRCDIR/autogen.sh" || exit 1 + +# $CONFIGURE_OPTS is a env that can optionally be set in the container, +# populated at build time from the Dockerfile. A typical use case would +# be to pass --host/--target args to trigger cross-compilation +# +# This can be augmented by make local args in $CI_CONFIGURE_ARGS +"$CI_CONFIGURE" $CONFIGURE_OPTS $CI_CONFIGURE_ARGS +if test $? != 0; then + test -f config.log && cat config.log + exit 1 +fi +find -name test-suite.log -delete + +# gl_public_submodule_commit= to disable gnulib's submodule check +# which breaks due to way we clone the submodules +make -j"$CI_SMP" gl_public_submodule_commit= $CI_MAKE_ARGS + +if test $? != 0; then \ + LOGS=$(find -name test-suite.log) + if test "$LOGS"; then + echo "=== LOG FILE(S) START ===" + cat $LOGS + echo "=== LOG FILE(S) END ===" + fi + exit 1 +fi -- 2.21.0

Both for ci-build and ci-shell we want to execute basically the same setup and cleanup logic, the only difference being that for the former we then run the build script and with the latter a shell. Rework the targets so that they both call the generic ci-run-command rule passing an appropriate $(CI_COMMAND). Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- ci/Makefile | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ci/Makefile b/ci/Makefile index f7e31b4f97..2b5be97238 100644 --- a/ci/Makefile +++ b/ci/Makefile @@ -206,7 +206,7 @@ ci-prepare-tree: ci-check-engine done ; \ fi -ci-build@%: ci-prepare-tree +ci-run-command@%: ci-prepare-tree $(CI_ENGINE) run $(CI_ENGINE_ARGS) $(CI_IMAGE_PREFIX)$*$(CI_IMAGE_TAG) \ /bin/bash -c ' \ export CI_CONT_SRCDIR="$(CI_CONT_SRCDIR)"; \ @@ -215,16 +215,18 @@ ci-build@%: ci-prepare-tree export CI_CONFIGURE="$(CI_CONFIGURE)"; \ export CI_CONFIGURE_ARGS="$(CI_CONFIGURE_ARGS)"; \ export CI_MAKE_ARGS="$(CI_MAKE_ARGS)"; \ - $(CI_USER_HOME)/build || exit 1' + $(CI_COMMAND) || exit 1' @test "$(CI_CLEAN)" = "1" && rm -rf $(CI_SCRATCHDIR) || : +ci-shell@%: + $(MAKE) -C $(CI_ROOTDIR) ci-run-command@$* CI_COMMAND="/bin/bash" + +ci-build@%: + $(MAKE) -C $(CI_ROOTDIR) ci-run-command@$* CI_COMMAND="$(CI_USER_HOME)/build" + ci-check@%: $(MAKE) -C $(CI_ROOTDIR) ci-build@$* CI_MAKE_ARGS="check" -ci-shell@%: ci-prepare-tree - $(CI_ENGINE) run $(CI_ENGINE_ARGS) $(CI_IMAGE_PREFIX)$*$(CI_IMAGE_TAG) /bin/bash - @test "$(CI_CLEAN)" = "1" && rm -rf $(CI_SCRATCHDIR) || : - ci-help: @echo "Build libvirt inside containers used for CI" @echo -- 2.21.0

This script is run before $(CI_BUILD_SCRIPT) and can be used to tweak the environment as necessary before the build starts. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- Makefile.am | 1 + ci/Makefile | 8 +++++++- ci/prepare.sh | 9 +++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 ci/prepare.sh diff --git a/Makefile.am b/Makefile.am index 96fac92186..cf9ff94f4f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -52,6 +52,7 @@ EXTRA_DIST = \ build-aux/vc-list-files \ ci/Makefile \ ci/build.sh \ + ci/prepare.sh \ $(NULL) pkgconfigdir = $(libdir)/pkgconfig diff --git a/ci/Makefile b/ci/Makefile index 2b5be97238..17d85d407f 100644 --- a/ci/Makefile +++ b/ci/Makefile @@ -41,6 +41,9 @@ CI_MAKE_ARGS = # Any extra arguments to pass to configure CI_CONFIGURE_ARGS = +# Script containing environment preparation steps +CI_PREPARE_SCRIPT = $(CI_ROOTDIR)/prepare.sh + # Script containing build instructions CI_BUILD_SCRIPT = $(CI_ROOTDIR)/build.sh @@ -100,6 +103,7 @@ CI_HOME_MOUNTS = \ $(NULL) CI_SCRIPT_MOUNTS = \ + --volume $(CI_SCRATCHDIR)/prepare:$(CI_USER_HOME)/prepare:z \ --volume $(CI_SCRATCHDIR)/build:$(CI_USER_HOME)/build:z \ $(NULL) @@ -194,8 +198,9 @@ ci-prepare-tree: ci-check-engine cp /etc/passwd $(CI_SCRATCHDIR); \ cp /etc/group $(CI_SCRATCHDIR); \ mkdir -p $(CI_SCRATCHDIR)/home; \ + cp "$(CI_PREPARE_SCRIPT)" $(CI_SCRATCHDIR)/prepare; \ cp "$(CI_BUILD_SCRIPT)" $(CI_SCRATCHDIR)/build; \ - chmod +x "$(CI_SCRATCHDIR)/build"; \ + chmod +x "$(CI_SCRATCHDIR)/prepare" "$(CI_SCRATCHDIR)/build"; \ echo "Cloning $(CI_GIT_ROOT) to $(CI_HOST_SRCDIR)"; \ git clone $(CI_GIT_ARGS) $(CI_GIT_ROOT) $(CI_HOST_SRCDIR) || exit 1; \ for mod in $$(git submodule | awk '{ print $$2 }' | sed -E 's,^../,,g') ; \ @@ -209,6 +214,7 @@ ci-prepare-tree: ci-check-engine ci-run-command@%: ci-prepare-tree $(CI_ENGINE) run $(CI_ENGINE_ARGS) $(CI_IMAGE_PREFIX)$*$(CI_IMAGE_TAG) \ /bin/bash -c ' \ + $(CI_USER_HOME)/prepare || exit 1; \ export CI_CONT_SRCDIR="$(CI_CONT_SRCDIR)"; \ export CI_CONT_BUILDDIR="$(CI_CONT_BUILDDIR)"; \ export CI_SMP="$(CI_SMP)"; \ diff --git a/ci/prepare.sh b/ci/prepare.sh new file mode 100644 index 0000000000..f70107bd62 --- /dev/null +++ b/ci/prepare.sh @@ -0,0 +1,9 @@ +# This script is used to prepare the environment that will be used +# to build libvirt inside the container. +# +# You can customize it to your liking, or alternatively use a +# completely different script by passing +# +# CI_PREPARE_SCRIPT=/path/to/your/prepare/script +# +# to make. -- 2.21.0

In order for the prepare script to be really useful, it needs to be able to perform privileged operations such as installing additional packages or setting up custom mount points. In order to achieve that, we now run the container as root, run the prepare script with full privilege, and only then switch to the unprivileged account with sudo. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- ci/Makefile | 19 +++++++++++-------- ci/prepare.sh | 4 ++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ci/Makefile b/ci/Makefile index 17d85d407f..86a07049ac 100644 --- a/ci/Makefile +++ b/ci/Makefile @@ -174,7 +174,6 @@ CI_GIT_ARGS = \ # --tty Ensure we have ability to Ctrl-C the build CI_ENGINE_ARGS = \ --rm \ - --user $(CI_UID):$(CI_GID) \ --interactive \ --tty \ $(CI_PODMAN_ARGS) \ @@ -215,13 +214,17 @@ ci-run-command@%: ci-prepare-tree $(CI_ENGINE) run $(CI_ENGINE_ARGS) $(CI_IMAGE_PREFIX)$*$(CI_IMAGE_TAG) \ /bin/bash -c ' \ $(CI_USER_HOME)/prepare || exit 1; \ - export CI_CONT_SRCDIR="$(CI_CONT_SRCDIR)"; \ - export CI_CONT_BUILDDIR="$(CI_CONT_BUILDDIR)"; \ - export CI_SMP="$(CI_SMP)"; \ - export CI_CONFIGURE="$(CI_CONFIGURE)"; \ - export CI_CONFIGURE_ARGS="$(CI_CONFIGURE_ARGS)"; \ - export CI_MAKE_ARGS="$(CI_MAKE_ARGS)"; \ - $(CI_COMMAND) || exit 1' + sudo \ + --login \ + --user="#$(CI_UID)" \ + --group="#$(CI_GID)" \ + CI_CONT_SRCDIR="$(CI_CONT_SRCDIR)" \ + CI_CONT_BUILDDIR="$(CI_CONT_BUILDDIR)" \ + CI_SMP="$(CI_SMP)" \ + CI_CONFIGURE="$(CI_CONFIGURE)" \ + CI_CONFIGURE_ARGS="$(CI_CONFIGURE_ARGS)" \ + CI_MAKE_ARGS="$(CI_MAKE_ARGS)" \ + $(CI_COMMAND) || exit 1' @test "$(CI_CLEAN)" = "1" && rm -rf $(CI_SCRATCHDIR) || : ci-shell@%: diff --git a/ci/prepare.sh b/ci/prepare.sh index f70107bd62..da6fc9a1b5 100644 --- a/ci/prepare.sh +++ b/ci/prepare.sh @@ -7,3 +7,7 @@ # CI_PREPARE_SCRIPT=/path/to/your/prepare/script # # to make. +# +# Note that this script will have root privileges inside the +# container, so it can be used for things like installing additional +# packages. -- 2.21.0

Now that we're using sudo, the initial work directory is no longer relevant since the user will find themselves in their home directory when they get control anyway. Signed-off-by: Andrea Bolognani <abologna@redhat.com> --- ci/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/ci/Makefile b/ci/Makefile index 86a07049ac..35a35d6082 100644 --- a/ci/Makefile +++ b/ci/Makefile @@ -168,7 +168,6 @@ CI_GIT_ARGS = \ # as dev so that file ownership matches host # instead of root:root # --volume to pass in the cloned git repo & config -# --workdir to set cwd to vpath build location # --ulimit lower files limit for performance reasons # --interactive # --tty Ensure we have ability to Ctrl-C the build @@ -181,7 +180,6 @@ CI_ENGINE_ARGS = \ $(CI_HOME_MOUNTS) \ $(CI_SCRIPT_MOUNTS) \ --volume $(CI_HOST_SRCDIR):$(CI_CONT_SRCDIR):z \ - --workdir $(CI_CONT_SRCDIR) \ --ulimit nofile=$(CI_ULIMIT_FILES):$(CI_ULIMIT_FILES) \ --cap-add=SYS_PTRACE \ $(NULL) -- 2.21.0

On Fri, 2019-08-16 at 11:49 +0200, Andrea Bolognani wrote:
See the individual commits for details, but the gist of it is that after this series it's possible for users to hook into the build process and customize it according to their needs; on top of that, the whole thing is made more maintainable in the process.
Andrea Bolognani (10): ci: Fix /etc/sub{u,g}id parsing ci: Drop $(CI_SUBMODULES) ci: Move everything to a separate directory ci: Create user's home directory in the container ci: Move source directory under $(CI_USER_HOME) ci: Introduce $(CI_BUILD_SCRIPT) ci: Generalize running commands inside the container ci: Introduce $(CI_PREPARE_SCRIPT) ci: Run $(CI_PREPARE_SCRIPT) as root ci: Stop using --workdir
Test build to prove this actually works: https://travis-ci.org/andreabolognani/libvirt/builds/572691710 -- Andrea Bolognani / Red Hat / Virtualization

On Fri, Aug 16, 2019 at 11:49:44AM +0200, Andrea Bolognani wrote:
See the individual commits for details, but the gist of it is that after this series it's possible for users to hook into the build process and customize it according to their needs; on top of that, the whole thing is made more maintainable in the process.
Andrea Bolognani (10): ci: Fix /etc/sub{u,g}id parsing ci: Drop $(CI_SUBMODULES) ci: Move everything to a separate directory ci: Create user's home directory in the container ci: Move source directory under $(CI_USER_HOME) ci: Introduce $(CI_BUILD_SCRIPT) ci: Generalize running commands inside the container ci: Introduce $(CI_PREPARE_SCRIPT) ci: Run $(CI_PREPARE_SCRIPT) as root ci: Stop using --workdir
.gitignore | 2 +- .travis.yml | 8 +-- Makefile.am | 6 +- Makefile.ci => ci/Makefile | 109 +++++++++++++++++++------------------ ci/build.sh | 40 ++++++++++++++ ci/prepare.sh | 13 +++++ 6 files changed, 118 insertions(+), 60 deletions(-) rename Makefile.ci => ci/Makefile (79%) create mode 100644 ci/build.sh create mode 100644 ci/prepare.sh
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano
participants (2)
-
Andrea Bolognani
-
Ján Tomko