diff --git a/cmd/coreos-assembler.go b/cmd/coreos-assembler.go index 2824864fa5..0fd213ddc0 100644 --- a/cmd/coreos-assembler.go +++ b/cmd/coreos-assembler.go @@ -14,7 +14,7 @@ import ( // commands we'd expect to use in the local dev path var buildCommands = []string{"init", "fetch", "build", "run", "prune", "clean", "list"} var advancedBuildCommands = []string{"buildfetch", "buildupload", "oc-adm-release", "push-container"} -var buildextendCommands = []string{"aliyun", "applehv", "aws", "azure", "digitalocean", "exoscale", "extensions-container", "gcp", "hashlist-experimental", "hyperv", "ibmcloud", "kubevirt", "live", "metal", "metal4k", "nutanix", "openstack", "qemu", "secex", "virtualbox", "vmware", "vultr"} +var buildextendCommands = []string{"aliyun", "applehv", "aws", "azure", "digitalocean", "exoscale", "extensions-container", "gcp", "hashlist-experimental", "hyperv", "ibmcloud", "kubevirt", "layered", "live", "metal", "metal4k", "nutanix", "openstack", "qemu", "secex", "virtualbox", "vmware", "vultr"} var utilityCommands = []string{"aws-replicate", "compress", "copy-container", "koji-upload", "kola", "push-container-manifest", "remote-build-container", "remote-prune", "remote-session", "sign", "tag", "update-variant"} var otherCommands = []string{"shell", "meta"} diff --git a/pkg/builds/cosa_v1.go b/pkg/builds/cosa_v1.go index 443bfa9eb4..d6bbb6fdaa 100644 --- a/pkg/builds/cosa_v1.go +++ b/pkg/builds/cosa_v1.go @@ -1,7 +1,7 @@ package builds // generated by 'make schema' -// source hash: 4c19aed3b3d84af278780bff63728510bb3e70613e4c4eef8cabd7939eb31bd8 +// source hash: 6fb3ed460736f7d07147e5aecf581b1a417206ed30423d642620a2a0577b7952 type AdvisoryDiff []AdvisoryDiffItems @@ -60,6 +60,7 @@ type Build struct { InputHashOfTheRpmOstree string `json:"rpm-ostree-inputhash"` Koji *Koji `json:"koji,omitempty"` KubevirtContainer *Image `json:"kubevirt,omitempty"` + LayeredImages map[string]Artifact `json:"layered-images,omitempty"` MetaStamp float64 `json:"coreos-assembler.meta-stamp,omitempty"` Name string `json:"name"` Oscontainer *Image `json:"oscontainer,omitempty"` diff --git a/pkg/builds/schema_doc.go b/pkg/builds/schema_doc.go index 37e2269110..45f0cdb77b 100644 --- a/pkg/builds/schema_doc.go +++ b/pkg/builds/schema_doc.go @@ -1,5 +1,5 @@ // Generated by ./generate-schema.sh -// Source hash: 4c19aed3b3d84af278780bff63728510bb3e70613e4c4eef8cabd7939eb31bd8 +// Source hash: 6fb3ed460736f7d07147e5aecf581b1a417206ed30423d642620a2a0577b7952 // DO NOT EDIT package builds @@ -230,6 +230,7 @@ var generatedSchemaJSON = `{ "ibmcloud", "powervs", "images", + "layered-images", "koji", "oscontainer", "extensions", @@ -741,6 +742,18 @@ var generatedSchemaJSON = `{ } } }, + "layered-images": { + "$id": "#/properties/layered-images", + "type": "object", + "title": "Layered Images", + "propertyNames": { + "pattern": "^[a-z][-a-z0-9]*$" + }, + "additionalProperties": { + "type": "object", + "$ref": "#/definitions/artifact" + } + }, "ostree-commit": { "$id": "#/properties/ostree-commit", "type": "string", diff --git a/src/cmd-buildextend-layered b/src/cmd-buildextend-layered new file mode 100755 index 0000000000..1cf6238f14 --- /dev/null +++ b/src/cmd-buildextend-layered @@ -0,0 +1,155 @@ +#!/usr/bin/env bash +set -euo pipefail + +dn=$(dirname "$0") +# shellcheck source=src/cmdlib.sh +. "${dn}"/cmdlib.sh + +print_help() { + cat 1>&2 < + + Build a layered image on top of base oscontainer. +EOF +} + +if [ ! -f /etc/cosa-supermin ] && [ -z "${COSA_BUILDEXTEND_LAYERED_FORCE_INNER:-}" ]; then + + # This runs outside of supermin + + # Parse options + build= + force= + rc=0 + options=$(getopt --options h --longoptions help,force,build: -- "$@") || rc=$? + [ $rc -eq 0 ] || { + print_help + exit 1 + } + eval set -- "$options" + while true; do + case "$1" in + -h | --help) + print_help + exit 0 + ;; + --force) + force=1 + ;; + --build) + build=$2 + shift + ;; + --) + shift + break + ;; + -*) + fatal "$0: unrecognized option: $1" + ;; + *) + break + ;; + esac + shift + done + + if [ $# = 0 ]; then + print_help + exit 1 + fi + + name=$1; shift + + containerfile="src/config/Containerfile.${name}" + if [ ! -f "${containerfile}" ]; then + fatal "Containerfile does not exist: ${containerfile}" + fi + + if [ -z "${build}" ]; then + build=$(get_latest_build) + if [ -z "${build}" ]; then + fatal "No build found." + fi + fi + + osname=$(cosa meta --build="${build}" --get-value name) + imgname=${osname}-${build}-layered-${name}.${basearch}.ociarchive + + # check if the image already exists in the meta.json + if [ -z "${force}" ]; then + path=$(cosa meta --build="${build}" --get-value "layered-images.${name}.path") + if [ "${path}" != "None" ]; then + echo "layered-${name} image already exists:" + echo "$imgname" + exit 0 + fi + unset path + fi + + builddir=$(get_build_dir "$build") + if [ ! -d "${builddir}" ]; then + fatal "Build dir ${builddir} does not exist." + fi + + oscontainer_meta_path=$(cosa meta --build="${build}" --get-value images.ostree.path) + oscontainer="builds/${build}/${basearch}/${oscontainer_meta_path}" + tmp_builddir="tmp/buildextend-layered-${name}" + rm -rf "${tmp_builddir}" && mkdir -p "${tmp_builddir}" + outfile="${tmp_builddir}/${imgname}" + + # A common pattern in the local developer path is to wrap `podman` so that + # it actually runs on the host. If privileged (proxy for "developer setup") + # and `podman info` works, use podman directly. + if has_privileges && podman info &>/dev/null; then + COSA_BUILDEXTEND_LAYERED_FORCE_INNER=1 cosa buildextend-layered "${name}" "${containerfile}" "${oscontainer}" "${outfile}" + else + cosa supermin-run /usr/lib/coreos-assembler/cmd-buildextend-layered "${name}" "${containerfile}" "${oscontainer}" "${outfile}" + fi + + # everything below is standard "add to meta.json and mv artifact to builddir" + + sha256=$(sha256sum_str < "${outfile}") + cosa meta --build "${build}" --dump | python3 -c " +import sys, json +j = json.load(sys.stdin) +if 'layered-images' not in j: + j['layered-images'] = {} +j['layered-images']['${name}'] = { + 'path': '${imgname}', + 'sha256': '${sha256}', + 'size': $(stat -c '%s' "${outfile}") +} +json.dump(j, sys.stdout, indent=4)" | jq -s add > "${tmp_builddir}/meta.json.new" + + cosa meta --build "${build}" --artifact "layered-${name}" --artifact-json "$(readlink -f "${tmp_builddir}/meta.json.new")" + /usr/lib/coreos-assembler/finalize-artifact "${outfile}" "${builddir}/${imgname}" + + rm -rf "${tmp_builddir}" +else + # This runs inside supermin (or still outside if + # COSA_BUILDEXTEND_LAYERED_FORCE_INNER is set) + + name=$1; shift + containerfile=$1; shift + oscontainer=$1; shift + outfile=$1; shift + + set -- + # we'll mount in the config and yumrepos dir + set -- "$@" --volume "$(pwd)/src/config":/run/src/config:ro + if [ -e src/yumrepos ]; then + set -- "$@" --volume "$(pwd)/src/yumrepos":/run/src/yumrepos:ro + fi + + # mount ca-trust if some repos need a custom root CA. + set -- "$@" --volume /etc/pki/ca-trust:/etc/pki/ca-trust:ro + + # we disable labeling to not require the mounts above to be container_file_t + set -- "$@" --security-opt label=disable + + podman build -t "localhost/cosa-layered-${name}" -f "${containerfile}" \ + --from oci-archive:"${oscontainer}" "$@" + skopeo copy containers-storage:"localhost/cosa-layered-${name}" oci-archive:"${outfile}" +fi diff --git a/src/v1.json b/src/v1.json index 53cf4b0936..46f155cdd4 100644 --- a/src/v1.json +++ b/src/v1.json @@ -224,6 +224,7 @@ "ibmcloud", "powervs", "images", + "layered-images", "koji", "oscontainer", "extensions", @@ -735,6 +736,18 @@ } } }, + "layered-images": { + "$id": "#/properties/layered-images", + "type": "object", + "title": "Layered Images", + "propertyNames": { + "pattern": "^[a-z][-a-z0-9]*$" + }, + "additionalProperties": { + "type": "object", + "$ref": "#/definitions/artifact" + } + }, "ostree-commit": { "$id": "#/properties/ostree-commit", "type": "string",