From 095c7b7f1a22e707331a1e5bf6f87d01e448452b Mon Sep 17 00:00:00 2001 From: wangyueliang Date: Fri, 12 Jul 2024 19:27:35 +0800 Subject: [PATCH] sync cmdlib and create_disk from upstream v0.16.0 [upstream] cmdlib.py: 7275f9d1a cmdlib: merge inner lists when merging dicts c91c3b026 cmdlib: handle dupes when merging lists fc39e2949 Drop support for `ignition-network-kcmdline` in `image.yaml` 1151356cb cmdlib: make locks use long lifetimes 68f31d5e1 cmdlib: import `datetime` module itself e02480568 cmdlib: Ensure bare-user tmpdir is in $workdir/tmp 6222e3fc6 build: Use lockfiles to guard ostree repo and `image.json` extraction cmdlib.sh: 25a1ae43d cmdlib: Drop unsafety for cache disk cd3937f80 Support `cosa build` on RISCV64 ff13f17ec cmdlib: stop using 9p hack for composes ee9f2c935 src/cmdlib: update mv to mv -f 86bc2a973 platform/metal: set serial console baud rate on x86_64 7c819e45a cmdlib: use lowercase query tags for `dnf repoquery --qf` c5e63ec4f cmdlib.sh: include GPG keys in supermin VM 1e7dbca45 cmdlib: completely avoid 9p for OSTree compose b193ffe8f cmdlib: support passing qemu args to runvm_with_cache b5d09ecbb cmdlib: cleanup tmp builddir if allocated e4d5d1ee0 cmdlib.sh: correctly escape runvm command args 606e61b67 cmdlib.sh: make tarball generation optional ae54f59bc cmdlib: use useless `cat $file |` instead of `<` for clarity 8ababba0f cmdlib: use `repo-packages` for `overrides/rpm` only as necessary ca97fcadf cmdlib: swap single and double quotes 8c8b7338a cmdlib: use `repo-packages` for `overrides/rpm` 2ec70d8db cmdlib: fold `commit_ostree_layer` into `commit_overlay` 6b9ceee4a cmdlib: embed overlay/ convention into `commit_overlay` 6f5dd1942 cmdlib: use `commit_overlay` instead of `commit_ostree_layer` ea7287c11 cmdlib: consistently use `overlay/` prefix for injected overlays 6181ff688 cmdlib: drop `impl_rpmostree_compose` 3c8c89814 cmdlib: factor out runnning supermin with cache f9332a538 cmdlib: mount supermin root disk by UUID 4d8a3842e cmdlib: Explain to people they can set `COSA_NO_KVM` cd28cca77 build: Use `cache=unsafe` for `cache.qcow2` and transient builds 5ee768b7e build: Lower zlib compression level for tmp/repo b8f61207c build: Error if builddir is not writable f6914117f cmdlib: Drop dead "is fedora" or "is RHEL" detection code 03d47c766 build: Add more metadata into exported container 3fac91896 cmdlib: consistently commit layers with same options e2ec123f9 cmdlib: forbid overlay when building, not preflight 73a7eb6be cmdlib: drop support for `overlay.d/cosa-no-autolayer` 4de7c4c03 cmdlib: support `overlay.d/cosa-no-autolayer` option 97675be8b cmdlib: rename overlay refs 0d3ce33b0 Enable `module_hotfixes=true` for overrides/rpm 19531a659 cmd-build: Add support for content_sets.yaml create_disk.sh: d6f76e486 create_disk: Use fsfreeze 9bd074de7 create_disk: Create image layer refs by default d6246b782 create_disk.sh: explicitly ask for RSA 4096-bit keys e3c184176 create_disk.sh: don't set an expiry date on secex pubkey 6da782ddd create_disk.sh: add more details to secex pubkey user ID f35e2c8a7 s390x: support Ignition private key for official builds 97aca9b72 s390x: generate GPG keys for Ignition config protection 39bf542d2 Require platforms.yaml in config 255ff1dba (tag: v0.15.0) create_disk.sh: using the target system's `grub2-install` to install BIOS/PReP bootloader e8676668f create_disk.sh: naively try to workaround more 9p woes 7967f6280 create_disk: correctly configure BLS grub_users setting (CVE-2022-3675) b4cb85788 create_disk: Fix s390x regression from previous change c3ee1e555 create_disk: Set repository options early 7087e1bc5 create_disk.sh: factor out `chroot_run` function 4753a1466 create_disk.sh: drop --rootfs arg 369b3b4e9 create_disk.sh: isolate s390x secex path a bit more f056599a9 create_disk.sh: dedupe s390x sgdisk boot and root args 0dac8f364 create_disk.sh: dedupe `sgdisk -p` call 434da3f90 create_disk.sh: unfreeze bootfs and rootfs before unmounting 60991507f create_disk.sh: replace tab by space 35f28d6f3 create_disk.sh: work around bootupd mount leak d56128415 create_disk: use -p when creating grub2 directory 80da54553 create_disk.sh: Only create luks directory once f60412d9b create_disk.sh: address ShellCheck lints 7c85dd96b create_disk.sh: use /bin/bash interpreter 3e983db56 create_disk.sh: execute rdcore on s390x within chroot 0d37558b0 create_disk: delete dead --disk argument 45fc1e751 create_disk.sh: add missing trailing newline in grub.cfg 33987224a create_disk: fix literal `$ignition_firstboot` karg on s390x 9e7627126 src/create_disk.sh: change bls-append-except-default seperator d66057c6e src/create_disk.sh: add new field to ostree/repo/config for GRUB password support c9036faec Serialize `grub-script` literally into image.json 7ed3daebe create-disk: Handle layered container image deploys --- build.sh | 2 +- mantle/cmd/kola/testiso.go | 4 +- src/cmdlib.sh | 282 ++++++++++++++++++++++++++----------- src/cosalib/cmdlib.py | 100 +++++++------ src/create_disk.sh | 142 ++++++++++++------- 5 files changed, 350 insertions(+), 180 deletions(-) diff --git a/build.sh b/build.sh index 2c05b828..113a875c 100755 --- a/build.sh +++ b/build.sh @@ -120,7 +120,7 @@ write_archive_info() { . "${srcdir}/src/cmdlib.sh" mkdir -p /cosa /lib/coreos-assembler touch -f /lib/coreos-assembler/.clean - prepare_git_artifacts "${srcdir}" /cosa/coreos-assembler-git.tar.gz /cosa/coreos-assembler-git.json + prepare_git_artifacts "${srcdir}" /cosa/coreos-assembler-git.json /cosa/coreos-assembler-git.tar.gz } if [ $# -ne 0 ]; then diff --git a/mantle/cmd/kola/testiso.go b/mantle/cmd/kola/testiso.go index 57fa42b8..510c9c51 100644 --- a/mantle/cmd/kola/testiso.go +++ b/mantle/cmd/kola/testiso.go @@ -172,8 +172,8 @@ StandardError=kmsg+console ExecStart=/bin/sh -c "journalctl -t nestos-installer-service | /usr/bin/awk '/[Dd]ownload/ {exit 1}'" ExecStart=/bin/sh -c "/usr/bin/udevadm settle" ExecStart=/bin/sh -c "/usr/bin/mount /dev/disk/by-label/root /mnt" -ExecStart=/bin/sh -c "/usr/bin/jq -er '.[\"build\"] == \"%s\"' /mnt/.coreos-aleph-version.json" -ExecStart=/bin/sh -c "/usr/bin/jq -er '.[\"ostree-commit\"] == \"%s\"' /mnt/.coreos-aleph-version.json" +ExecStart=/bin/sh -c "/usr/bin/jq -er '.[\"build\"] == \"%s\"' /mnt/.nestos-aleph-version.json" +ExecStart=/bin/sh -c "/usr/bin/jq -er '.[\"ostree-commit\"] == \"%s\"' /mnt/.nestos-aleph-version.json" [Install] RequiredBy=nestos-installer.target ` diff --git a/src/cmdlib.sh b/src/cmdlib.sh index 9338042e..8b1d9978 100755 --- a/src/cmdlib.sh +++ b/src/cmdlib.sh @@ -5,10 +5,6 @@ set -euo pipefail DIR=$(dirname "$(realpath "${BASH_SOURCE[0]}")") RFC3339="%Y-%m-%dT%H:%M:%SZ" -# Detect what platform we are on -export ISFEDORA=1 -export ISEL='' - info() { echo "info: $*" 1>&2 } @@ -22,6 +18,12 @@ fatal() { exit 1 } +# Execute a command, also writing the cmdline to stdout +runv() { + echo "Running: " "$@" + "$@" +} + # Get target base architecture basearch=$(python3 -c ' import gi @@ -35,10 +37,12 @@ arch=$(uname -m) export arch case $arch in - "x86_64") DEFAULT_TERMINAL="ttyS0" ;; - "ppc64le") DEFAULT_TERMINAL="hvc0" ;; - "aarch64") DEFAULT_TERMINAL="ttyAMA0" ;; - "s390x") DEFAULT_TERMINAL="ttysclp0";; + "x86_64") DEFAULT_TERMINAL="ttyS0,115200n8" ;; + "ppc64le") DEFAULT_TERMINAL="hvc0" ;; + "aarch64") DEFAULT_TERMINAL="ttyAMA0" ;; + "s390x") DEFAULT_TERMINAL="ttysclp0" ;; + # minimal support; the rest of cosa isn't yet riscv64-aware + "riscv64") DEFAULT_TERMINAL="ttyS0" ;; *) fatal "Architecture ${arch} not supported" esac export DEFAULT_TERMINAL @@ -91,10 +95,6 @@ depcheck() { preflight() { depcheck - if [ "$(stat -f --printf="%T" .)" = "overlayfs" ] && [ -z "${COSA_SKIP_OVERLAY:-}" ]; then - fatal "$(pwd) must be a volume" - fi - # See https://pagure.io/centos-infra/issue/48 if test "$(umask)" = 0000; then fatal "Your umask is unset, please use umask 0022 or so" @@ -107,7 +107,7 @@ preflight_kvm() { if test -z "${COSA_NO_KVM:-}"; then if ! test -c /dev/kvm; then - fatal "Missing /dev/kvm" + fatal "Missing /dev/kvm; you can set COSA_NO_KVM=1 to bypass this at the cost of performance." fi if ! [ -w /dev/kvm ]; then if ! has_privileges; then @@ -121,6 +121,12 @@ preflight_kvm() { fi } +# Use this for things like disabling fsync. +# For more information, see the docs of `cosa init --transient`. +is_transient() { + test -f "${workdir}"/tmp/nosa-transient +} + # Picks between yaml or json based on which version exists. Errors out if both # exists. If neither exist, prefers the extension in ${2}, or otherwise YAML. pick_yaml_or_else_json() { @@ -145,11 +151,20 @@ yaml2json() { prepare_build() { preflight preflight_kvm + workdir="$(pwd)" + if ! [ -d builds ]; then - fatal "No $(pwd)/builds found; did you run coreos-assembler init?" + fatal "No ${workdir}/builds found; did you run coreos-assembler init?" fi - workdir="$(pwd)" + if [ "$(stat -f --printf="%T" .)" = "overlayfs" ] && [ -z "${COSA_SKIP_OVERLAY:-}" ]; then + fatal "${workdir} must be a volume" + fi + + if test '!' -w "${workdir}"; then + ls -ald "${workdir}" + fatal "${workdir} is not writable" + fi # Be nice to people who have older versions that # didn't create this in `init`. @@ -214,6 +229,9 @@ prepare_build() { rm -f "${tmprepo}/summary" else ostree init --repo="${tmprepo}" --mode=archive + # This archive repo is transient, so lower the compression + # level to avoid burning excessive CPU. + ostree --repo="${tmprepo}" config set archive.zlib-level 2 fi # No need to fsync for transient flows @@ -228,24 +246,24 @@ prepare_build() { fi export configdir_gitrepo - manifest_tmp_json=${tmp_builddir}/manifest.json - rpm-ostree compose tree --repo="${tmprepo}" --print-only "${manifest}" > "${manifest_tmp_json}" + flattened_manifest=${tmp_builddir}/manifest.json + rpm-ostree compose tree --repo="${tmprepo}" --print-only "${manifest}" > "${flattened_manifest}" + export flattened_manifest # Abuse the rojig/name as the name of the VM images # Also grab rojig summary for image upload descriptions - name=$(jq -r '.rojig.name' < "${manifest_tmp_json}") - summary=$(jq -r '.rojig.summary' < "${manifest_tmp_json}") - ref=$(jq -r '.ref//""' < "${manifest_tmp_json}") + name=$(jq -r '.rojig.name' < "${flattened_manifest}") + summary=$(jq -r '.rojig.summary' < "${flattened_manifest}") + ref=$(jq -r '.ref//""' < "${flattened_manifest}") export name ref summary # And validate fields coreos-assembler requires, but not rpm-ostree required_fields=("automatic-version-prefix") for field in "${required_fields[@]}"; do - if ! jq -re '."'"${field}"'"' < "${manifest_tmp_json}" >/dev/null; then + if ! jq -re '."'"${field}"'"' < "${flattened_manifest}" >/dev/null; then echo "Missing required field in src/config/manifest.yaml: ${field}" 1>&2 exit 1 fi done - rm -f "${manifest_tmp_json}" # This dir is no longer used rm builds/work -rf @@ -289,13 +307,56 @@ commit_overlay() { # files, but we do. touch "${TMPDIR}/overlay/statoverride" echo -n "Committing ${name}: ${path} ... " - ostree commit --repo="${tmprepo}" --tree=dir="${TMPDIR}/overlay" -b "${name}" \ + ostree commit --repo="${tmprepo}" \ + --tree=dir="${TMPDIR}/overlay" -b "overlay/${name}" \ --owner-uid 0 --owner-gid 0 --no-xattrs --no-bindings --parent=none \ --mode-ro-executables --timestamp "${git_timestamp}" \ --statoverride <(sed -e '/^#/d' "${TMPDIR}/overlay/statoverride") \ --skip-list <(echo /statoverride) } +create_content_manifest(){ + local source_file=$1 + local destination=$2 + mkdir -p "${workdir}"/tmp/buildinfo + base_repos=$(jq .repos "${flattened_manifest}") + + # Get the data form content_sets.yaml and map the repo names given in '$base_repos' to their corresponding + # pulp repository IDs provided in https://www.redhat.com/security/data/metrics/repository-to-cpe.json + python3 -c " +import json, yaml; + +# Open the yaml and load the data +f = open('$source_file') +data = yaml.safe_load(f); +f.close(); +repos=[]; + +for base_repo in $base_repos: + if base_repo in data['repo_mapping']: + if data['repo_mapping'][base_repo]['name'] != '': + repo_name = data['repo_mapping'][base_repo]['name'].replace('\$ARCH', '$(arch)'); + repos.append(repo_name) + else: + print('Warning: No corresponding repo in repository-to-cpe.json for ' + base_repo) + else: + # Warning message for repositories with no entry in content_sets.yaml + print('Warning: No corresponding entry in content_sets.yaml for ' + base_repo) + +content_manifest_data = json.dumps({ + 'metadata': { + 'icm_version': 1, + 'icm_spec': 'https://raw.githubusercontent.com/containerbuildsystem/atomic-reactor/master/atomic_reactor/schemas/content_manifest.json', + 'image_layer_index': 1 + }, + 'content_sets': repos, + 'image_contents': [] + }); +with open('$destination', 'w') as outfile: + outfile.write(content_manifest_data) + " +} + # Implement support for automatic local overrides: # https://github.com/coreos/coreos-assembler/issues/118 # @@ -352,18 +413,7 @@ EOF if ! [ -d "${n}" ]; then continue fi - local bn ovlname - bn=$(basename "${n}") - ovlname="${name}-config-overlay-${bn}" - commit_overlay "${ovlname}" "${n}" - layers="${layers} ${ovlname}" - done - fi - - if [ -n "${layers}" ]; then - echo "ostree-layers:" >> "${override_manifest}" - for layer in ${layers}; do - echo " - ${layer}" >> "${override_manifest}" + commit_overlay "$(basename "${n}")" "${n}" done fi @@ -385,7 +435,11 @@ EOF # the same RPMs: the `dnf repoquery` below is to pick the latest one dnf repoquery --repofrompath=tmp,"file://${overridesdir}/rpm" \ --disablerepo '*' --enablerepo tmp --refresh --latest-limit 1 \ - --exclude '*.src' --qf '%{NAME}\t%{EVR}\t%{ARCH}' --quiet | python3 -c ' + --exclude '*.src' --qf '%{name}\t%{evr}\t%{arch}' \ + --quiet > "${tmp_overridesdir}/pkgs.txt" + + # shellcheck disable=SC2002 + cat "${tmp_overridesdir}/pkgs.txt" | python3 -c ' import sys, json lockfile = {"packages": {}} for line in sys.stdin: @@ -393,18 +447,38 @@ for line in sys.stdin: lockfile["packages"][name] = {"evra": f"{evr}.{arch}"} json.dump(lockfile, sys.stdout)' > "${local_overrides_lockfile}" + # for all the repo packages in the manifest for which we have an + # override, create a new repo-packages entry to make sure our overrides + # win. + # shellcheck disable=SC2002 + cat "${tmp_overridesdir}/pkgs.txt" | python3 -c " +import sys, yaml +flattened = yaml.safe_load(open('${flattened_manifest}')) +all_overrides = set() +for line in sys.stdin: + all_overrides.add(line.strip().split('\t')[0]) +repo_overrides = set() +for repopkg in flattened.get('repo-packages', []): + repo_overrides.update(all_overrides.intersection(set(repopkg['packages']))) +manifest = { + 'repos': ['coreos-assembler-local-overrides'], + 'repo-packages': [{ + 'repo': 'coreos-assembler-local-overrides', + 'packages': list(repo_overrides) + }] +} +yaml.dump(manifest, sys.stdout)" >> "${override_manifest}" + rm "${tmp_overridesdir}/pkgs.txt" + echo "Using RPM overrides from: ${overridesdir}/rpm" touch "${overrides_active_stamp}" - cat >> "${override_manifest}" < "${tmp_overridesdir}"/coreos-assembler-local-overrides.repo <> "${override_manifest}" << EOF ostree-override-layers: - - cosa-overrides-rootfs + - overlay/cosa-overrides-rootfs EOF fi } @@ -462,30 +533,40 @@ runcompose_tree() { # we need our overrides to be at the end of the list set - "$@" --ex-lockfile="${tmp_overridesdir}/local-overrides.json" fi - impl_rpmostree_compose tree --unified-core "${manifest}" "$@" + + local workdir=${workdir:-$(pwd)} + local repo=${tmprepo:-${workdir}/tmp/repo} + + rm -f "${changed_stamp}" + # shellcheck disable=SC2086 + set - ${COSA_RPMOSTREE_GDB:-} rpm-ostree compose tree \ + --touch-if-changed "${changed_stamp}" --cachedir="${workdir}"/cache \ + ${COSA_RPMOSTREE_ARGS:-} --unified-core "${manifest}" "$@" + + echo "Running: $*" + + # this is the heart of the privs vs no privs dual path if has_privileges; then + set - "$@" --repo "${repo}" --write-composejson-to "${composejson}" + # we hardcode a umask of 0022 here to make sure that composes are run + # with a consistent value, regardless of the environment + (umask 0022 && sudo -E "$@") sudo chown -R -h "${USER}":"${USER}" "${tmprepo}" + else + runvm_with_cache -- "$@" --repo "${repo}" --write-composejson-to "${composejson}" fi } runcompose_extensions() { local outputdir=$1; shift - impl_rpmostree_compose extensions "$@" --output-dir "$outputdir" - if has_privileges; then - sudo chown -R -h "${USER}":"${USER}" "${outputdir}" - fi -} - -impl_rpmostree_compose() { - local cmd=$1; shift local workdir=${workdir:-$(pwd)} local repo=${tmprepo:-${workdir}/tmp/repo} rm -f "${changed_stamp}" # shellcheck disable=SC2086 - set - ${COSA_RPMOSTREE_GDB:-} rpm-ostree compose "${cmd}" --repo="${repo}" \ + set - ${COSA_RPMOSTREE_GDB:-} rpm-ostree compose extensions --repo="${repo}" \ --touch-if-changed "${changed_stamp}" --cachedir="${workdir}"/cache \ - ${COSA_RPMOSTREE_ARGS:-} "$@" + ${COSA_RPMOSTREE_ARGS:-} "$@" --output-dir "$outputdir" echo "Running: $*" @@ -494,22 +575,28 @@ impl_rpmostree_compose() { # we hardcode a umask of 0022 here to make sure that composes are run # with a consistent value, regardless of the environment (umask 0022 && sudo -E "$@") + sudo chown -R -h "${USER}":"${USER}" "${outputdir}" else - # "cache2" has an explicit label so we can find it in qemu easily - if [ ! -f "${workdir}"/cache/cache2.qcow2 ]; then - qemu-img create -f qcow2 cache2.qcow2.tmp 10G - ( - # shellcheck source=src/libguestfish.sh - source /usr/lib/coreos-assembler/libguestfish.sh - virt-format --filesystem=xfs --label=cosa-cache -a cache2.qcow2.tmp) - mv -T cache2.qcow2.tmp "${workdir}"/cache/cache2.qcow2 - fi - # And remove the old one - rm -vf "${workdir}"/cache/cache.qcow2 - compose_qemu_args+=("-drive" "if=none,id=cache,discard=unmap,file=${workdir}/cache/cache2.qcow2" \ - "-device" "virtio-blk,drive=cache") - runvm "${compose_qemu_args[@]}" -- "$@" + runvm_with_cache -- "$@" + fi +} + +runvm_with_cache() { + # "cache2" has an explicit label so we can find it in qemu easily + if [ ! -f "${workdir}"/cache/cache2.qcow2 ]; then + qemu-img create -f qcow2 cache2.qcow2.tmp 10G + ( + # shellcheck source=src/libguestfish.sh + source /usr/lib/coreos-assembler/libguestfish.sh + virt-format --filesystem=xfs --label=cosa-cache -a cache2.qcow2.tmp) + mv -T cache2.qcow2.tmp "${workdir}"/cache/cache2.qcow2 fi + # And remove the old one + rm -vf "${workdir}"/cache/cache.qcow2 + local cachedriveargs="discard=unmap" + cache_args+=("-drive" "if=none,id=cache,$cachedriveargs,file=${workdir}/cache/cache2.qcow2" \ + "-device" "virtio-blk,drive=cache") + runvm "${cache_args[@]}" "$@" } # Strips out the digest field from lockfiles since they subtly conflict with @@ -590,7 +677,11 @@ runvm() { # tmp_builddir is set in prepare_build, but some stages may not # know that it exists. # shellcheck disable=SC2086 - export tmp_builddir="${tmp_builddir:-$(mktemp -p ${workdir}/tmp -d supermin.XXXX)}" + if [ -z "${tmp_builddir:-}" ]; then + tmp_builddir="$(mktemp -p ${workdir}/tmp -d supermin.XXXX)" + export tmp_builddir + local cleanup_tmpdir=1 + fi # shellcheck disable=SC2155 local vmpreparedir="${tmp_builddir}/supermin.prepare" @@ -615,6 +706,9 @@ runvm() { # include COSA in the image find /usr/lib/coreos-assembler/ -type f > "${vmpreparedir}/hostfiles" + # and include all GPG keys + find /etc/pki/rpm-gpg/ -type f >> "${vmpreparedir}/hostfiles" + # the reason we do a heredoc here is so that the var substition takes # place immediately instead of having to proxy them through to the VM cat > "${vmpreparedir}/init" < "${tmp_builddir}"/cmd.sh - echo "$@" >> "${tmp_builddir}"/cmd.sh + for arg in "$@"; do + # escape it appropriately so that spaces in args survive + printf '%q ' "$arg" >> "${tmp_builddir}"/cmd.sh + done touch "${runvm_console}" @@ -670,15 +768,14 @@ EOF esac kola_args=(kola qemuexec -m "${COSA_SUPERMIN_MEMORY:-${memory_default}}" --auto-cpus -U --workdir none \ - --console-to-file "${runvm_console}") + --console-to-file "${runvm_console}" --bind-rw "${workdir},workdir") base_qemu_args=(-drive 'if=none,id=root,format=raw,snapshot=on,file='"${vmbuilddir}"'/root,index=1' \ - -device 'virtio-blk,drive=root' + -device 'virtio-blk,drive=root' \ -kernel "${vmbuilddir}/kernel" -initrd "${vmbuilddir}/initrd" \ -no-reboot -nodefaults \ -device virtio-serial \ - -virtfs 'local,id=workdir,path='"${workdir}"',security_model=none,mount_tag=workdir' \ - -append "root=/dev/vda console=${DEFAULT_TERMINAL} selinux=1 enforcing=0 autorelabel=1" \ + -append "root=UUID=${superminrootfsuuid} console=${DEFAULT_TERMINAL} selinux=1 enforcing=0 autorelabel=1" \ ) # support local dev cases where src/config is a symlink. Note if you change or extend to this set, @@ -713,6 +810,12 @@ EOF fatal "Couldn't find rc file; failure inside supermin init?" fi rc="$(cat "${rc_file}")" + + if [ -n "${cleanup_tmpdir:-}" ]; then + rm -rf "${tmp_builddir}" + unset tmp_builddir + fi + return "${rc}" } @@ -791,9 +894,6 @@ prepare_git_artifacts() { is_dirty="true" fi - tar -C "${gitd}" -czf "${tarball}" --exclude-vcs . - chmod 0444 "${tarball}" - local rev local branch # shellcheck disable=SC2086 @@ -818,10 +918,6 @@ prepare_git_artifacts() { info "Directory ${gitd}, is from branch ${branch}, commit ${rev}" - local checksum name size - checksum=$(sha256sum "${tarball}" | awk '{print$1}') - name=$(basename "${tarball}") - size=$(find "${tarball}" -printf %s) # shellcheck disable=SC2046 disable=SC2086 cat > "${json}" < "${json}.new" <&2; exit 1;; esac +rootfs_args=$(getconfig_def "rootfs-args" "") bootfs=$(getconfig "bootfs") composefs=$(getconfig_def "composefs" "") @@ -149,32 +149,33 @@ if [[ ${secure_execution} -eq 1 ]]; then SDPART=1 BOOTVERITYHASHPN=5 ROOTVERITYHASHPN=6 + extrakargs="${extrakargs} swiotlb=262144" fi # Make the size relative if [ "${rootfs_size}" != "0" ]; then rootfs_size="+${rootfs_size}" fi + +# shellcheck disable=SC2031 case "$arch" in x86_64) EFIPN=2 - sgdisk -Z $disk \ + sgdisk -Z "$disk" \ -U "${uninitialized_gpt_uuid}" \ -n 1:0:+1M -c 1:BIOS-BOOT -t 1:21686148-6449-6E6F-744E-656564454649 \ -n ${EFIPN}:0:+127M -c ${EFIPN}:EFI-SYSTEM -t ${EFIPN}:C12A7328-F81F-11D2-BA4B-00A0C93EC93B \ -n ${BOOTPN}:0:+384M -c ${BOOTPN}:boot \ - -n ${ROOTPN}:0:${rootfs_size} -c ${ROOTPN}:root -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4 - sgdisk -p "$disk" + -n ${ROOTPN}:0:"${rootfs_size}" -c ${ROOTPN}:root -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4 ;; aarch64) RESERVEDPN=1 EFIPN=2 - sgdisk -Z $disk \ + sgdisk -Z "$disk" \ -U "${uninitialized_gpt_uuid}" \ -n ${RESERVEDPN}:0:+1M -c ${RESERVEDPN}:reserved -t ${RESERVEDPN}:8DA63339-0007-60C0-C436-083AC8230908 \ -n ${EFIPN}:0:+127M -c ${EFIPN}:EFI-SYSTEM -t ${EFIPN}:C12A7328-F81F-11D2-BA4B-00A0C93EC93B \ -n ${BOOTPN}:0:+384M -c ${BOOTPN}:boot \ - -n ${ROOTPN}:0:${rootfs_size} -c ${ROOTPN}:root -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4 - sgdisk -p "$disk" + -n ${ROOTPN}:0:"${rootfs_size}" -c ${ROOTPN}:root -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4 ;; s390x) sgdisk_args=() @@ -192,7 +193,7 @@ case "$arch" in fi # NB: in the bare metal case when targeting ECKD DASD disks, this # partition table is not what actually gets written to disk in the end: - # nestos-installer has code which transforms it into a DASD-compatible + # coreos-installer has code which transforms it into a DASD-compatible # partition table and copies each partition individually bitwise. sgdisk -Z "$disk" -U "${uninitialized_gpt_uuid}" "${sgdisk_args[@]}" ;; @@ -200,16 +201,16 @@ case "$arch" in PREPPN=1 RESERVEDPN=2 # ppc64le doesn't use special uuid for root partition - sgdisk -Z $disk \ + sgdisk -Z "$disk" \ -U "${uninitialized_gpt_uuid}" \ -n ${PREPPN}:0:+4M -c ${PREPPN}:PowerPC-PReP-boot -t ${PREPPN}:9E1A2D38-C612-4316-AA26-8B49521E5A8B \ -n ${RESERVEDPN}:0:+1M -c ${RESERVEDPN}:reserved -t ${RESERVEDPN}:8DA63339-0007-60C0-C436-083AC8230908 \ -n ${BOOTPN}:0:+384M -c ${BOOTPN}:boot \ - -n ${ROOTPN}:0:${rootfs_size} -c ${ROOTPN}:root -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4 - sgdisk -p "$disk" + -n ${ROOTPN}:0:"${rootfs_size}" -c ${ROOTPN}:root -t ${ROOTPN}:0FC63DAF-8483-4772-8E79-3D69D8477DE4 ;; esac +sgdisk -p "$disk" udevtrig boot_dev="${disk}${BOOTPN}" @@ -260,13 +261,16 @@ case "${rootfs_type}" in # So basically, we're choosing performance over half-implemented security. # Eventually, we'd like both - once XFS gains verity (probably not too hard), # we could unconditionally enable it there. - mkfs.ext4 -b $(getconf PAGE_SIZE) -O verity -L root "${root_dev}" -U "${rootfs_uuid}" + # shellcheck disable=SC2086 + mkfs.ext4 -b "$(getconf PAGE_SIZE)" -O verity -L root "${root_dev}" -U "${rootfs_uuid}" ${rootfs_args} ;; btrfs) - mkfs.btrfs -L root "${root_dev}" -U "${rootfs_uuid}" + # shellcheck disable=SC2086 + mkfs.btrfs -L root "${root_dev}" -U "${rootfs_uuid}" ${rootfs_args} ;; xfs|"") - mkfs.xfs "${root_dev}" -L root -m reflink=1 -m uuid="${rootfs_uuid}" + # shellcheck disable=SC2086 + mkfs.xfs "${root_dev}" -L root -m reflink=1 -m uuid="${rootfs_uuid}" ${rootfs_args} ;; *) echo "Unknown rootfs_type: $rootfs_type" 1>&2 @@ -283,15 +287,15 @@ rootfs=/tmp/rootfs rm -rf ${rootfs} mkdir -p ${rootfs} mount -o discard "${root_dev}" ${rootfs} -chcon $(matchpathcon -n /) ${rootfs} +chcon "$(matchpathcon -n /)" ${rootfs} mkdir ${rootfs}/boot -chcon $(matchpathcon -n /boot) $rootfs/boot +chcon "$(matchpathcon -n /boot)" $rootfs/boot mount "${boot_dev}" $rootfs/boot -chcon $(matchpathcon -n /boot) $rootfs/boot +chcon "$(matchpathcon -n /boot)" $rootfs/boot # FAT doesn't support SELinux labeling, it uses "genfscon", so we # don't need to give it a label manually. if [ ${EFIPN:+x} ]; then - mkdir $rootfs/boot/efi + mkdir ${rootfs}/boot/efi mount "${disk}${EFIPN}" $rootfs/boot/efi fi if [[ ${secure_execution} -eq 1 ]]; then @@ -319,9 +323,13 @@ if [ "${rootfs_type}" = "ext4verity" ] && [ -z "${composefs}" ]; then fi # Compute kargs -# Note that $ignition_firstboot is interpreted by grub at boot time, -# *not* the shell here. Hence the backslash escape. -allkargs="$extrakargs \$ignition_firstboot" +allkargs="$extrakargs" +# shellcheck disable=SC2031 +if [ "$arch" != s390x ]; then + # Note that $ignition_firstboot is interpreted by grub at boot time, + # *not* the shell here. Hence the backslash escape. + allkargs+=" \$ignition_firstboot" +fi if test -n "${deploy_via_container}"; then kargsargs="" @@ -329,12 +337,21 @@ if test -n "${deploy_via_container}"; then do kargsargs+="--karg=$karg " done + # shellcheck disable=SC2086 ostree container image deploy --imgref "${ostree_container}" \ ${container_imgref:+--target-imgref $container_imgref} \ + --write-commitid-to /tmp/commit.txt \ --stateroot "$os_name" --sysroot $rootfs $kargsargs + deploy_commit=$(cat /tmp/commit.txt) + rm /tmp/commit.txt else # Pull the container image... time ostree container image pull $rootfs/ostree/repo "${ostree_container}" + # But we default to not leaving a ref for the image around, so the + # layers will get GC'd on the first update if the + # user doesn't switch to a container image. + ostree --repo=$rootfs/ostree/repo refs --delete ostree/container/image + ostree --repo=$rootfs/ostree/repo prune --refs-only --depth=0 # Deploy it, using an optional remote prefix if test -n "${remote_name}"; then deploy_ref="${remote_name}:${ref}" @@ -347,12 +364,13 @@ else do kargsargs+="--karg-append=$karg " done + # shellcheck disable=SC2086 ostree admin deploy "${deploy_ref}" --sysroot $rootfs --os "$os_name" $kargsargs + deploy_commit=$commit fi -# Note that at the current time, this only supports deploying non-layered -# container images; xref https://github.com/ostreedev/ostree-rs-ext/issues/143 -deploy_root="$rootfs/ostree/deploy/${os_name}/deploy/${commit}.0" -test -d "${deploy_root}" +# Sanity check +deploy_root="$rootfs/ostree/deploy/${os_name}/deploy/${deploy_commit}.0" +test -d "${deploy_root}" || (echo "failed to find $deploy_root"; exit 1) # This will allow us to track the version that an install # originally used; if we later need to understand something @@ -369,7 +387,7 @@ test -d "${deploy_root}" # convenient to have here as a strong cross-reference. # imgid: The full image name, the same as will end up in the # `images` dict in `meta.json`. -cat > $rootfs/.coreos-aleph-version.json << EOF +cat > $rootfs/.nestos-aleph-version.json << EOF { "build": "${buildid}", "ref": "${ref}", @@ -378,22 +396,20 @@ cat > $rootfs/.coreos-aleph-version.json << EOF } EOF -# we use pure BLS on most architectures; this may -# be overridden below -bootloader_backend=none - install_uefi() { # https://github.com/coreos/fedora-coreos-tracker/issues/510 # See also https://github.com/ostreedev/ostree/pull/1873#issuecomment-524439883 - /usr/bin/bootupctl backend install --src-root="${deploy_root}" "${rootfs}" + # Unshare mount ns to work around https://github.com/coreos/bootupd/issues/367 + unshare -m /usr/bin/bootupctl backend install --src-root="${deploy_root}" "${rootfs}" # We have a "static" grub config file that basically configures grub to look # in the RAID called "md-boot", if it exists, or the partition labeled "boot". local target_efi="$rootfs/boot/efi" - local grubefi=$(find "${target_efi}/EFI/" -maxdepth 1 -type d | grep -v BOOT) + local grubefi + grubefi=$(find "${target_efi}/EFI/" -maxdepth 1 -type d | grep -v BOOT) local vendor_id="${grubefi##*/}" local vendordir="${target_efi}/EFI/${vendor_id}" mkdir -p "${vendordir}" - cat > ${vendordir}/grub.cfg << 'EOF' + cat > "${vendordir}/grub.cfg" << 'EOF' if [ -e (md/md-boot) ]; then # The search command might pick a RAID component rather than the RAID, # since the /boot RAID currently uses superblock 1.0. See the comment in @@ -433,6 +449,18 @@ install_grub_cfg() { fi } +# For some commands, we need to make sure to use the binary and userspace of the +# target system. XXX: Switch to bwrap. +chroot_run() { + for mnt in dev proc sys run var tmp; do + mount --rbind "/$mnt" "${deploy_root}/$mnt" + done + chroot "${deploy_root}" "$@" + for mnt in dev proc sys run var tmp; do + umount --recursive "${deploy_root}/$mnt" + done +} + generate_gpgkeys() { local pkey pkey="${1}" @@ -445,6 +473,7 @@ generate_gpgkeys() { } # Other arch-specific bootloader changes +# shellcheck disable=SC2031 case "$arch" in x86_64) # UEFI @@ -452,11 +481,13 @@ x86_64) if [ "${x86_bios_bootloader}" = 1 ]; then # And BIOS grub in addition. See also # https://github.com/coreos/fedora-coreos-tracker/issues/32 - grub2-install \ + # Install BIOS/PReP bootloader using the target system's grub2-install, + # see https://github.com/coreos/coreos-assembler/issues/3156 + chroot_run /sbin/grub2-install \ --target i386-pc \ --boot-directory $rootfs/boot \ --modules mdraid1x \ - $disk + "$disk" fi ;; aarch64) @@ -465,11 +496,11 @@ aarch64) ;; ppc64le) # to populate PReP Boot, i.e. support pseries - grub2-install --target=powerpc-ieee1275 --boot-directory $rootfs/boot --no-nvram "${disk}${PREPPN}" + chroot_run /sbin/grub2-install --target=powerpc-ieee1275 --boot-directory $rootfs/boot --no-nvram "${disk}${PREPPN}" install_grub_cfg ;; s390x) - bootloader_backend=zipl + ostree config --repo $rootfs/ostree/repo set sysroot.bootloader zipl rdcore_zipl_args=("--boot-mount=$rootfs/boot" "--append-karg=ignition.firstboot") # in the secex case, we run zipl at the end; in the non-secex case, we need # to run it now because zipl wants rw access to the bootfs @@ -481,6 +512,18 @@ s390x) ;; esac +# enable support for GRUB password +# shellcheck disable=SC2031 +if [ "$arch" != s390x ]; then + ostree config --repo $rootfs/ostree/repo set sysroot.bls-append-except-default 'grub_users=""' +fi + +# For local secex build we create an empty file and later mount-bind real private key to it, +# so rdcore could append it to initrd. Best approach is to teach rdcore how to append file +# with different source and dest- paths. +if [[ ${secure_execution} -eq 1 ]] && [[ ! -e /dev/disk/by-id/virtio-genprotimg ]]; then + touch "${deploy_root}/usr/lib/nestos/ignition.asc" +fi touch $rootfs/boot/ignition.firstboot # Finally, add the immutable bit to the physical root; we don't @@ -495,8 +538,9 @@ chattr +i $rootfs fstrim -a -v # Ensure the filesystem journals are flushed for fs in $rootfs/boot $rootfs; do - mount -o remount,ro $fs - xfs_freeze -f $fs + mount -o remount,ro "$fs" + fsfreeze -f "$fs" + fsfreeze -u "$fs" done umount -R $rootfs @@ -541,8 +585,8 @@ rdcore_replacement() { se_parmfile="${se_tmp_boot}/parmfile" # Ignition GPG private key - mkdir -p "${se_tmp_boot}/usr/lib/coreos" - generate_gpgkeys "${se_tmp_boot}/usr/lib/coreos/ignition.asc" + mkdir -p "${se_tmp_boot}/usr/lib/nestos" + generate_gpgkeys "${se_tmp_boot}/usr/lib/nestos/ignition.asc" blsfile=$(find "${rootfs}"/boot/loader/entries/*.conf) echo "$(grep options "${blsfile}" | cut -d' ' -f2-)" "${se_kargs_append[@]}" > "${se_parmfile}" @@ -567,12 +611,12 @@ if [[ ${secure_execution} -eq 1 ]]; then if [ ! -e /dev/disk/by-id/virtio-genprotimg ]; then echo "Building local Secure Execution Image, running zipl and genprotimg" generate_gpgkeys "/tmp/ignition.asc" - mount --rbind "/tmp/ignition.asc" "${deploy_root}/usr/lib/coreos/ignition.asc" + mount --rbind "/tmp/ignition.asc" "${deploy_root}/usr/lib/nestos/ignition.asc" # run zipl with root hashes as kargs rdcore_zipl_args+=("--secex-mode=enforce" "--hostkey=/dev/disk/by-id/virtio-hostkey") rdcore_zipl_args+=("--append-karg=rootfs.roothash=$(cat /tmp/root-roothash)") rdcore_zipl_args+=("--append-karg=bootfs.roothash=$(cat /tmp/boot-roothash)") - rdcore_zipl_args+=("--append-file=/usr/lib/coreos/ignition.asc") + rdcore_zipl_args+=("--append-file=/usr/lib/nestos/ignition.asc") chroot_run /usr/lib/dracut/modules.d/50rdcore/rdcore zipl "${rdcore_zipl_args[@]}" else echo "Building release Secure Execution Image, zipl and genprotimg will be run later" -- Gitee