1d03c82c2SDoug Rabson#! /bin/sh 2d03c82c2SDoug Rabson 3d03c82c2SDoug Rabson# Build an Open Container Initiative (OCI) container image 4d03c82c2SDoug Rabson 5d03c82c2SDoug Rabsoncurdir=$1; shift 6d03c82c2SDoug Rabsonrev=$1; shift 7d03c82c2SDoug Rabsonbranch=$1; shift 8d03c82c2SDoug Rabsonarch=$1; shift 9d03c82c2SDoug Rabsonimage=$1; shift 10e8a5b9fdSDoug Rabsonoutput=$1; shift 11d03c82c2SDoug Rabson 12d03c82c2SDoug Rabsonmajor=${rev%.*} 13d03c82c2SDoug Rabsonminor=${rev#*.} 14d03c82c2SDoug Rabson 15d03c82c2SDoug Rabsonabi=FreeBSD:${major}:${arch} 16e8a5b9fdSDoug Rabsonver=${rev}-${branch}-${arch} 17d03c82c2SDoug Rabson 18d03c82c2SDoug Rabsonecho "Building OCI freebsd${major}-${image} image for ${abi}" 19d03c82c2SDoug Rabson 20d03c82c2SDoug Rabson. ${curdir}/tools/oci-image-${image}.conf 21d03c82c2SDoug Rabson 22e8a5b9fdSDoug Rabsoninit_repo() { 23e8a5b9fdSDoug Rabson local workdir=$1; shift 24d03c82c2SDoug Rabson local abi=$1; shift 25d03c82c2SDoug Rabson 26e8a5b9fdSDoug Rabson mkdir -p ${workdir}/repos 27d03c82c2SDoug Rabson cat > ${workdir}/repos/base.conf <<EOF 28d03c82c2SDoug RabsonFreeBSD-base: { 29d03c82c2SDoug Rabson url: "file:///usr/obj/usr/src/repo/${abi}/latest" 30d03c82c2SDoug Rabson signature_type: "none" 31d03c82c2SDoug Rabson fingerprints: "none" 32d03c82c2SDoug Rabson} 33d03c82c2SDoug RabsonEOF 34d03c82c2SDoug Rabson cp /etc/pkg/FreeBSD.conf ${workdir}/repos 35d03c82c2SDoug Rabson} 36d03c82c2SDoug Rabson 37e8a5b9fdSDoug Rabson# Install packages using pkg(8) into a container with rootfs at $3 38d03c82c2SDoug Rabsoninstall_packages() { 39d03c82c2SDoug Rabson local abi=$1; shift 40d03c82c2SDoug Rabson local workdir=$1; shift 41e8a5b9fdSDoug Rabson local rootdir=${workdir}/rootfs 42d03c82c2SDoug Rabson if [ ! -d ${rootdir}/usr/share/keys/pkg/trusted ]; then 43d03c82c2SDoug Rabson mkdir -p ${rootdir}/usr/share/keys/pkg/trusted 44d03c82c2SDoug Rabson fi 45d03c82c2SDoug Rabson cp /usr/share/keys/pkg/trusted/* ${rootdir}/usr/share/keys/pkg/trusted 46d03c82c2SDoug Rabson # We install the packages and then remove repository metadata (keeping the 47d03c82c2SDoug Rabson # metadata for what was installed). This trims more than 40Mb from the 48d03c82c2SDoug Rabson # resulting image. 49d03c82c2SDoug Rabson env IGNORE_OSVERSION=yes ABI=${abi} pkg --rootdir ${rootdir} --repo-conf-dir ${workdir}/repos \ 50d03c82c2SDoug Rabson install -yq "$@" || exit $? 51d03c82c2SDoug Rabson rm -rf ${rootdir}/var/db/pkg/repos 52d03c82c2SDoug Rabson} 53d03c82c2SDoug Rabson 54e8a5b9fdSDoug Rabsonset_cmd() { 55e8a5b9fdSDoug Rabson local workdir=$1; shift 56e8a5b9fdSDoug Rabson oci_cmd="$@" 57e8a5b9fdSDoug Rabson} 58e8a5b9fdSDoug Rabson 59e8a5b9fdSDoug Rabson# Convert FreeBSD architecture to OCI-style. See 60e8a5b9fdSDoug Rabson# https://github.com/containerd/platforms/blob/main/platforms.go for details 61e8a5b9fdSDoug Rabsonnormalize_arch() { 62e8a5b9fdSDoug Rabson local arch=$1; shift 63e8a5b9fdSDoug Rabson case ${arch} in 64e8a5b9fdSDoug Rabson i386) 65e8a5b9fdSDoug Rabson arch=386 66e8a5b9fdSDoug Rabson ;; 67e8a5b9fdSDoug Rabson aarch64) 68e8a5b9fdSDoug Rabson arch=arm64 69e8a5b9fdSDoug Rabson ;; 70e8a5b9fdSDoug Rabson amd64) ;; 71e8a5b9fdSDoug Rabson riscv64) ;; 72e8a5b9fdSDoug Rabson *) 73e8a5b9fdSDoug Rabson echo "Architecture ${arch} not supported for container images" 74e8a5b9fdSDoug Rabson ;; 75e8a5b9fdSDoug Rabson esac 76e8a5b9fdSDoug Rabson echo ${arch} 77e8a5b9fdSDoug Rabson} 78e8a5b9fdSDoug Rabson 79e8a5b9fdSDoug Rabsoncreate_container() { 80e8a5b9fdSDoug Rabson local workdir=$1; shift 81e8a5b9fdSDoug Rabson local base_workdir=$1; shift 82e8a5b9fdSDoug Rabson oci_cmd= 83e8a5b9fdSDoug Rabson if [ -d ${workdir}/rootfs ]; then 84e8a5b9fdSDoug Rabson chflags -R 0 ${workdir}/rootfs 85e8a5b9fdSDoug Rabson rm -rf ${workdir}/rootfs 86e8a5b9fdSDoug Rabson fi 87e8a5b9fdSDoug Rabson mkdir -p ${workdir}/rootfs 88e8a5b9fdSDoug Rabson if [ "${base_workdir}" != "" ]; then 89e8a5b9fdSDoug Rabson tar -C ${workdir}/rootfs -xf ${base_workdir}/rootfs.tar.gz 90e8a5b9fdSDoug Rabson fi 91e8a5b9fdSDoug Rabson} 92e8a5b9fdSDoug Rabson 93e8a5b9fdSDoug Rabsoncommit_container() { 94e8a5b9fdSDoug Rabson local workdir=$1; shift 95e8a5b9fdSDoug Rabson local image=$1; shift 96e8a5b9fdSDoug Rabson local output=$1; shift 97e8a5b9fdSDoug Rabson 98*3a79ca65SDoug Rabson # Note: the diff_id (needed for image config) is the hash of the 99*3a79ca65SDoug Rabson # uncompressed tar. 100*3a79ca65SDoug Rabson # 101*3a79ca65SDoug Rabson # For compatibility with Podman, we must disable sparse-file 102*3a79ca65SDoug Rabson # handling. See https://github.com/containers/podman/issues/25270 for 103*3a79ca65SDoug Rabson # more details. 104*3a79ca65SDoug Rabson tar -C ${workdir}/rootfs --strip-components 1 --no-read-sparse -cf ${workdir}/rootfs.tar . 105e8a5b9fdSDoug Rabson local diff_id=$(sha256 -q < ${workdir}/rootfs.tar) 106e8a5b9fdSDoug Rabson gzip -f ${workdir}/rootfs.tar 107e8a5b9fdSDoug Rabson local create_time=$(date -u +%Y-%m-%dT%TZ) 108e8a5b9fdSDoug Rabson local root_hash=$(sha256 -q < ${workdir}/rootfs.tar.gz) 109e8a5b9fdSDoug Rabson local root_size=$(stat -f %z ${workdir}/rootfs.tar.gz) 110e8a5b9fdSDoug Rabson 111e8a5b9fdSDoug Rabson oci_arch=$(normalize_arch ${arch}) 112e8a5b9fdSDoug Rabson 113e8a5b9fdSDoug Rabson config= 114e8a5b9fdSDoug Rabson if [ -n "${oci_cmd}" ]; then 115e8a5b9fdSDoug Rabson config=",\"config\":{\"cmd\":[\"${oci_cmd}\"]}" 116e8a5b9fdSDoug Rabson fi 117e8a5b9fdSDoug Rabson echo "{\"created\":\"${create_time}\",\"architecture\":\"${oci_arch}\",\"os\":\"freebsd\"${config},\"rootfs\":{\"type\":\"layers\",\"diff_ids\":[\"sha256:${diff_id}\"]},\"history\":[{\"created\":\"${create_time}\",\"created_by\":\"make-oci-image.sh\"}]}" > ${workdir}/config.json 118e8a5b9fdSDoug Rabson local config_hash=$(sha256 -q < ${workdir}/config.json) 119e8a5b9fdSDoug Rabson local config_size=$(stat -f %z ${workdir}/config.json) 120e8a5b9fdSDoug Rabson 121e8a5b9fdSDoug Rabson echo "{\"schemaVersion\":2,\"mediaType\":\"application/vnd.oci.image.manifest.v1+json\",\"config\":{\"mediaType\":\"application/vnd.oci.image.config.v1+json\",\"digest\":\"sha256:${config_hash}\",\"size\":${config_size}},\"layers\":[{\"mediaType\":\"application/vnd.oci.image.layer.v1.tar+gzip\",\"digest\":\"sha256:${root_hash}\",\"size\":${root_size}}],\"annotations\":{}}" > ${workdir}/manifest.json 122e8a5b9fdSDoug Rabson local manifest_hash=$(sha256 -q < ${workdir}/manifest.json) 123e8a5b9fdSDoug Rabson local manifest_size=$(stat -f %z ${workdir}/manifest.json) 124e8a5b9fdSDoug Rabson 125e8a5b9fdSDoug Rabson mkdir -p ${workdir}/oci/blobs/sha256 126e8a5b9fdSDoug Rabson echo "{\"imageLayoutVersion\": \"1.0.0\"}" > ${workdir}/oci/oci-layout 127e8a5b9fdSDoug Rabson echo "{\"schemaVersion\":2,\"manifests\":[{\"mediaType\":\"application/vnd.oci.image.manifest.v1+json\",\"digest\":\"sha256:${manifest_hash}\",\"size\":${manifest_size},\"annotations\":{\"org.opencontainers.image.ref.name\":\"freebsd-${image}:${ver}\"}}]}" > ${workdir}/oci/index.json 128e8a5b9fdSDoug Rabson ln ${workdir}/rootfs.tar.gz ${workdir}/oci/blobs/sha256/${root_hash} 129e8a5b9fdSDoug Rabson ln ${workdir}/config.json ${workdir}/oci/blobs/sha256/${config_hash} 130e8a5b9fdSDoug Rabson ln ${workdir}/manifest.json ${workdir}/oci/blobs/sha256/${manifest_hash} 131e8a5b9fdSDoug Rabson 132e8a5b9fdSDoug Rabson tar -C ${workdir}/oci --xz --strip-components 1 --no-read-sparse -a -cf ${output} . 133e8a5b9fdSDoug Rabson} 134e8a5b9fdSDoug Rabson 135e8a5b9fdSDoug Rabson# Prefix with "container-image-" so that we can create a unique work area under 136e8a5b9fdSDoug Rabson# ${.OBJDIR}. We can assume that make has set our working directory to 137e8a5b9fdSDoug Rabson# ${.OBJDIR}. 138e8a5b9fdSDoug Rabsonworkdir=${PWD}/container-image-${image} 139e8a5b9fdSDoug Rabsoninit_repo ${workdir} ${abi} 140e8a5b9fdSDoug Rabson 141d03c82c2SDoug Rabsonif [ -n "${OCI_BASE_IMAGE}" ]; then 142e8a5b9fdSDoug Rabson base_workdir=${PWD}/container-image-${OCI_BASE_IMAGE} 143d03c82c2SDoug Rabsonelse 144e8a5b9fdSDoug Rabson base_workdir= 145d03c82c2SDoug Rabsonfi 146d03c82c2SDoug Rabson 147e8a5b9fdSDoug Rabsoncreate_container ${workdir} ${base_workdir} 148d03c82c2SDoug Rabsonoci_image_build 149e8a5b9fdSDoug Rabsoncommit_container ${workdir} ${image} ${output} 150