Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -177,25 +177,25 @@ write_archive_info() {
}

patch_osbuild() {
return # we have no patches right now
## Add a few patches that either haven't made it into a release or
## that will be obsoleted with other work that will be done soon.

## To make it easier to apply patches we'll move around the osbuild
## code on the system first:
#rmdir /usr/lib/osbuild/osbuild
#mv /usr/lib/python3.13/site-packages/osbuild /usr/lib/osbuild/
#mkdir /usr/lib/osbuild/tools
#mv /usr/bin/osbuild-mpp /usr/lib/osbuild/tools/
rmdir /usr/lib/osbuild/osbuild
mv /usr/lib/python3.13/site-packages/osbuild /usr/lib/osbuild/
mkdir /usr/lib/osbuild/tools
mv /usr/bin/osbuild-mpp /usr/lib/osbuild/tools/

## Now all the software is under the /usr/lib/osbuild dir and we can patch
#cat foo.patch | patch -d /usr/lib/osbuild -p1
#
patch -d /usr/lib/osbuild -p1 < /usr/lib/coreos-assembler/0001-live-artifacts-read-os-name-from-usr-lib-os-release.patch

## And then move the files back; supermin appliance creation will need it back
## in the places delivered by the RPM.
#mv /usr/lib/osbuild/tools/osbuild-mpp /usr/bin/osbuild-mpp
#mv /usr/lib/osbuild/osbuild /usr/lib/python3.13/site-packages/osbuild
#mkdir /usr/lib/osbuild/osbuild
mv /usr/lib/osbuild/tools/osbuild-mpp /usr/bin/osbuild-mpp
mv /usr/lib/osbuild/osbuild /usr/lib/python3.13/site-packages/osbuild
mkdir /usr/lib/osbuild/osbuild
}

if [ $# -ne 0 ]; then
Expand Down
2 changes: 1 addition & 1 deletion cmd/coreos-assembler.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

// commands we'd expect to use in the local dev path
var buildCommands = []string{"init", "fetch", "build", "osbuild", "run", "prune", "clean", "list"}
var advancedBuildCommands = []string{"buildfetch", "buildupload", "oc-adm-release", "push-container"}
var advancedBuildCommands = []string{"import", "buildfetch", "buildupload", "oc-adm-release", "push-container"}
var buildextendCommands = []string{"aliyun", "applehv", "aws", "azure", "digitalocean", "exoscale", "extensions-container", "gcp", "hyperv", "ibmcloud", "kubevirt", "live", "metal", "metal4k", "nutanix", "openstack", "oraclecloud", "qemu", "secex", "virtualbox", "vmware", "vultr"}

var utilityCommands = []string{"aws-replicate", "coreos-prune", "compress", "copy-container", "diff", "koji-upload", "kola", "push-container-manifest", "remote-build-container", "remote-session", "sign", "tag", "update-variant"}
Expand Down
7 changes: 4 additions & 3 deletions pkg/builds/cosa_v1.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package builds

// generated by 'make schema'
// source hash: 4bb5641ee8c32b122c412cbaefe3d068685ea6cbffcf3162e600a01268c92146
// source hash: 445150ada0fe019c7bb33c793185b312111ed7538a59e1a0b424c10c6c2dbc0d

type AdvisoryDiff []AdvisoryDiffItems

Expand Down Expand Up @@ -56,6 +56,7 @@ type Build struct {
CosaDelayedMetaMerge bool `json:"coreos-assembler.delayed-meta-merge,omitempty"`
CosaImageChecksum string `json:"coreos-assembler.image-config-checksum,omitempty"`
CosaImageVersion int `json:"coreos-assembler.image-genver,omitempty"`
CosaImportedOciImage bool `json:"coreos-assembler.oci-imported,omitempty"`
Extensions *Extensions `json:"extensions,omitempty"`
ExtensionsContainer *PrimaryImage `json:"extensions-container,omitempty"`
FedoraCoreOsParentCommit string `json:"fedora-coreos.parent-commit,omitempty"`
Expand All @@ -64,15 +65,15 @@ type Build struct {
GitDirty string `json:"coreos-assembler.config-dirty,omitempty"`
IbmCloud []Cloudartifact `json:"ibmcloud,omitempty"`
ImageInputChecksum string `json:"coreos-assembler.image-input-checksum,omitempty"`
InputHashOfTheRpmOstree string `json:"rpm-ostree-inputhash"`
InputHashOfTheRpmOstree string `json:"rpm-ostree-inputhash,omitempty"`
Koji *Koji `json:"koji,omitempty"`
KubevirtContainer *PrimaryImage `json:"kubevirt,omitempty"`
MetaStamp float64 `json:"coreos-assembler.meta-stamp,omitempty"`
Name string `json:"name"`
Oscontainer *PrimaryImage `json:"oscontainer,omitempty"`
OstreeCommit string `json:"ostree-commit"`
OstreeContentBytesWritten int `json:"ostree-content-bytes-written,omitempty"`
OstreeContentChecksum string `json:"ostree-content-checksum"`
OstreeContentChecksum string `json:"ostree-content-checksum,omitempty"`
OstreeNCacheHits int `json:"ostree-n-cache-hits,omitempty"`
OstreeNContentTotal int `json:"ostree-n-content-total,omitempty"`
OstreeNContentWritten int `json:"ostree-n-content-written,omitempty"`
Expand Down
15 changes: 11 additions & 4 deletions pkg/builds/schema_doc.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Generated by ./generate-schema.sh
// Source hash: 4bb5641ee8c32b122c412cbaefe3d068685ea6cbffcf3162e600a01268c92146
// Source hash: 445150ada0fe019c7bb33c793185b312111ed7538a59e1a0b424c10c6c2dbc0d
// DO NOT EDIT

package builds
Expand Down Expand Up @@ -255,10 +255,8 @@ var generatedSchemaJSON = `{
"buildid",
"name",
"ostree-commit",
"ostree-content-checksum",
"ostree-timestamp",
"ostree-version",
"rpm-ostree-inputhash"
"ostree-version"
],
"optional": [
"aliyun",
Expand All @@ -273,13 +271,15 @@ var generatedSchemaJSON = `{
"images",
"koji",
"oscontainer",
"ostree-content-checksum",
"extensions",
"extensions-container",
"parent-pkgdiff",
"pkgdiff",
"parent-advisories-diff",
"advisories-diff",
"release-payload",
"rpm-ostree-inputhash",
"summary",
"s3",
"coreos-assembler.basearch",
Expand All @@ -297,6 +297,7 @@ var generatedSchemaJSON = `{
"coreos-assembler.meta-stamp",
"coreos-assembler.overrides-active",
"coreos-assembler.yumrepos-git",
"coreos-assembeler.oci-imported",
"fedora-coreos.parent-commit",
"fedora-coreos.parent-version",
"ref"
Expand Down Expand Up @@ -378,6 +379,12 @@ var generatedSchemaJSON = `{
"default": "",
"minLength": 1
},
"coreos-assembler.oci-imported": {
"$id": "#/properties/coreos-assembler.oci-imported",
"type": "boolean",
"title": "COSA imported OCI image",
"default": "False"
},
"coreos-assembler.code-source": {
"$id": "#/properties/coreos-assembler.code-source",
"type": "string",
Expand Down
30 changes: 30 additions & 0 deletions src/0001-live-artifacts-read-os-name-from-usr-lib-os-release.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
From 7593b65dc77bf5dbb26fe9c54386759ab7f740a7 Mon Sep 17 00:00:00 2001
From: Bipin B Narayan <bbnaraya@redhat.com>
Date: Mon, 14 Jul 2025 19:43:12 +0530
Subject: [PATCH] live-artifacts: read os name from /usr/lib/os-release

With importing ociarchive, the treefile.json doesn't contain osname.
---
stages/org.osbuild.coreos.live-artifacts.mono | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/stages/org.osbuild.coreos.live-artifacts.mono b/stages/org.osbuild.coreos.live-artifacts.mono
index 1384a343..4a95b607 100755
--- a/stages/org.osbuild.coreos.live-artifacts.mono
+++ b/stages/org.osbuild.coreos.live-artifacts.mono
@@ -131,10 +131,8 @@ def make_stream_hash(src, dest):


def get_os_name(tree):
- file = os.path.join(tree, 'usr/share/rpm-ostree/treefile.json')
- with open(file, encoding='utf8') as f:
- treefile = json.load(f)
- return treefile['metadata']['name']
+ os_release = osrelease.parse_files(os.path.join(tree, 'usr', 'lib', 'os-release'))
+ return f"{os_release['ID']}-{os_release['VARIANT_ID']}"


def ensure_glob(pathname, n="", **kwargs):
--
2.50.1

2 changes: 1 addition & 1 deletion src/cmd-coreos-prune
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Build = collections.namedtuple("Build", ["id", "images", "arch", "meta_json"])
# set metadata caching to 5m
CACHE_MAX_AGE_METADATA = 60 * 5
# These lists are up to date as of schema hash
# 4bb5641ee8c32b122c412cbaefe3d068685ea6cbffcf3162e600a01268c92146. If changing
# 445150ada0fe019c7bb33c793185b312111ed7538a59e1a0b424c10c6c2dbc0d. If changing
# this hash, ensure that the list of SUPPORTED and UNSUPPORTED artifacts below
# is up to date.
SUPPORTED = ["amis", "aws-winli", "gcp"]
Expand Down
152 changes: 152 additions & 0 deletions src/cmd-import
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
#!/usr/bin/python3

Comment thread
jlebon marked this conversation as resolved.
'''
This command takes a containers-transports(5) ref to an OCI image and converts
it into a `cosa build`, as if one did `cosa build ostree`. One can then e.g.
`cosa buildextend-qemu` right away.
'''

import argparse
import datetime
import json
import os
import subprocess
import tempfile
import shutil
import sys
from stat import (
S_IREAD,
S_IRGRP,
S_IROTH)
from cosalib.builds import Builds
from cosalib.cmdlib import (
rfc3339_time,
get_basearch,
sha256sum_file,
import_oci_archive)


def main():
args = parse_args()

# immediate inspect to error out early if it doesn't exists/we don't have ACLs and to do some upfront checks
metadata = skopeo_inspect(args.srcimg)

# let raise if missing
assert metadata['Labels']['containers.bootc'] == '1'
buildid = metadata['Labels']['org.opencontainers.image.version']

builds = Builds()
if builds.has(buildid):
print(f"ERROR: Build ID {buildid} already exists!")
sys.exit(1)

with tempfile.TemporaryDirectory(prefix='cosa-import-', dir='tmp') as tmpd:
# create the OCI archive and manifest
tmp_oci_archive = generate_oci_archive(args, tmpd)
tmp_oci_manifest = generate_oci_manifest(args, tmpd)

# import into the tmp/repo to get the ostree-commit but also so it's cached
ostree_commit = import_oci_archive(tmpd, tmp_oci_archive, buildid)

# create meta.json
build_meta = generate_build_meta(tmp_oci_archive, tmp_oci_manifest, metadata, ostree_commit)

# move into official location
finalize_build(builds, build_meta, tmp_oci_archive, tmp_oci_manifest)


def parse_args():
parser = argparse.ArgumentParser(prog='cosa import')
parser.add_argument("srcimg", metavar='IMAGE',
help="image to import (containers-transports(5) format)")
return parser.parse_args()


def generate_oci_archive(args, tmpd):
tmpf = os.path.join(tmpd, 'out.ociarchive')
subprocess.check_call(['skopeo', 'copy', '--preserve-digests', args.srcimg,
f"oci-archive:{tmpf}"])
return tmpf


def generate_oci_manifest(args, tmpd):
tmpf = os.path.join(tmpd, 'oci-manifest.json')
with open(tmpf, 'wb') as f:
f.write(subprocess.check_output(["skopeo", "inspect", "--raw", args.srcimg]))
os.fchmod(f.fileno(), S_IREAD | S_IRGRP | S_IROTH)
return tmpf


def generate_build_meta(tmp_oci_archive, tmp_oci_manifest, metadata, ostree_commit):
name = metadata['Labels']['com.coreos.osname']
buildid = metadata['Labels']['org.opencontainers.image.version']
created_timestamp = parse_timestamp(metadata['Created'])
arch = get_basearch()

return {
'ostree-commit': ostree_commit,
'ostree-version': buildid,
'buildid': buildid,
'name': name,
'coreos-assembler.basearch': arch,
'coreos-assembler.build-timestamp': created_timestamp,
'coreos-assembler.oci-imported': True,
'ostree-timestamp': created_timestamp,
'images': {
'ostree': {
"path": f"{name}-{buildid}-ostree.{arch}.ociarchive",
"sha256": sha256sum_file(tmp_oci_archive),
'size': os.path.getsize(tmp_oci_archive),
"skip-compression": True
},
'oci-manifest': {
'path': f'{name}-{buildid}-ostree.{arch}-manifest.json',
'sha256': sha256sum_file(tmp_oci_manifest),
'size': os.path.getsize(tmp_oci_manifest),
"skip-compression": True,
},
},
}


def finalize_build(builds, build_meta, tmp_oci_archive, tmp_oci_manifest):
buildid = build_meta['buildid']
arch = build_meta['coreos-assembler.basearch']

destdir = f'builds/{buildid}/{arch}'
os.makedirs(destdir)

shutil.move(tmp_oci_archive, f'{destdir}/{build_meta['images']['ostree']['path']}')
shutil.move(tmp_oci_manifest, f'{destdir}/{build_meta['images']['oci-manifest']['path']}')

with open(f'{destdir}/meta.json', 'w') as f:
json.dump(build_meta, f, indent=4)

# and finally the real deal: insert the build and bump latest symlink
builds.insert_build(buildid, arch)
builds.bump_timestamp()

if os.path.exists('builds/latest'):
os.remove('builds/latest')
os.symlink(f'{buildid}', 'builds/latest', target_is_directory=True)

print(f'Imported OCI image as build {buildid}')


def skopeo_inspect(image):
return json.loads(subprocess.check_output(['skopeo', 'inspect', '-n', image]))


def parse_timestamp(timestamp):
# datetime's doesn't support nanoseconds.
# So trim it.
if len(timestamp) > 26 and timestamp[19] == '.':
timestamp = timestamp[:26] + "Z"

timestamp = datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%fZ')
return rfc3339_time(timestamp.replace(tzinfo=datetime.timezone.utc))


if __name__ == '__main__':
main()
16 changes: 8 additions & 8 deletions src/cmd-osbuild
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,7 @@ postprocess_qemu_secex() {

# Here we generate the input JSON we pass to runvm_osbuild for all of our image builds
generate_runvm_osbuild_config() {
runvm_osbuild_config_json="${workdir}/tmp/runvm-osbuild-config-${build}.json"
echo "${runvm_osbuild_config_json}" # Let the caller know where the config will be
if [ -f "${runvm_osbuild_config_json}" ]; then
return # only need to generate this once per build
fi
rm -f "${workdir}"/tmp/runvm-osbuild-config-*.json # clean up any previous configs
local outfile=$1; shift

# reread these values from the build itself rather than rely on the ones loaded
# by prepare_build since the config might've changed since then
Expand Down Expand Up @@ -223,7 +218,7 @@ generate_runvm_osbuild_config() {
echo "Disk sizes: metal: ${metal_image_size_mb}M (estimated), cloud: ${cloud_image_size_mb}M" >&2

# Generate the JSON describing the disk we want to build
yaml2json /dev/stdin "${runvm_osbuild_config_json}" <<EOF
yaml2json /dev/stdin "${outfile}" <<EOF
artifact-name-prefix: "${name}-${build}"
build-version: "${build}"
container-imgref: "${container_imgref}"
Expand Down Expand Up @@ -399,7 +394,12 @@ main() {
platforms=("${tobuild[@]}")

# Run OSBuild now to build the platforms that were requested.
runvm_osbuild_config_json="$(generate_runvm_osbuild_config)"
runvm_osbuild_config_json="${workdir}/tmp/runvm-osbuild-config-${build}.json"
if [ ! -f "${runvm_osbuild_config_json}" ]; then
rm -f "${workdir}"/tmp/runvm-osbuild-config-*.json # clean up any previous configs
generate_runvm_osbuild_config "$runvm_osbuild_config_json"
fi

outdir=$(mktemp -p "${tmp_builddir}" -d)
runvm_with_cache -- /usr/lib/coreos-assembler/runvm-osbuild \
--config "${runvm_osbuild_config_json}" \
Expand Down
20 changes: 20 additions & 0 deletions src/cmd-prune
Original file line number Diff line number Diff line change
Expand Up @@ -183,5 +183,25 @@ for build in builds_to_delete:
error_during_pruning = True
print(f"{e}")

# and delete any "unowned" blob refs from the tmp repo
if os.path.exists('tmp/repo'):
prefix = 'ostree/container/blob/'
referenced_blobs = set()
for build in builds.get_builds():
meta = builds.get_build_meta(build['id'])
build_dir = builds.get_build_dir(build['id'])
with open(os.path.join(build_dir, meta['images']['oci-manifest']['path'])) as f:
oci_manifest = json.load(f)
referenced_blobs.update([prefix + layer['digest'].replace(':', '_3A_')
for layer in oci_manifest['layers']])
blobs = set(subprocess.check_output(['ostree', 'refs', '--repo=tmp/repo',
'--list', 'ostree/container/blob'],
encoding='utf-8').splitlines())
blobs_to_delete = blobs.difference(referenced_blobs)
if len(blobs_to_delete) > 0:
print(f"Deleting {len(blobs_to_delete)} blob refs")
subprocess.check_output(['ostree', 'refs', '--repo=tmp/repo',
'--delete'] + list(blobs_to_delete))

if error_during_pruning:
sys.exit(1)
Loading
Loading