1
0
mirror of https://github.com/coreos/fedora-coreos-config.git synced 2026-02-05 09:45:30 +01:00

tree: import changes from testing-devel at 765d3011b6

This commit is contained in:
CoreOS Bot
2026-01-28 21:41:48 +00:00
parent 14f11004e1
commit d830ec724c
2 changed files with 129 additions and 96 deletions

View File

@@ -45,7 +45,7 @@ RUN --mount=type=cache,rw,id=coreos-build-cache,target=/cache \
RUN --mount=type=cache,rw,id=coreos-build-cache,target=/cache \
--mount=type=secret,id=yumrepos,target=/etc/yum.repos.d/secret.repo \
--mount=type=secret,id=contentsets \
/src/build-rootfs --target-rootfs /target-rootfs
/src/build-rootfs --srcdir=/src make-rootfs --target-rootfs /target-rootfs
RUN --mount=type=bind,target=/run/src,rw \
rpm-ostree experimental compose build-chunked-oci \
--bootc --format-version=1 --rootfs /target-rootfs \

View File

@@ -20,101 +20,69 @@ import yaml
ARCH = os.uname().machine
SRCDIR = '/src'
INPUTHASH = '/run/inputhash'
HERMETIC_REPO = '/etc/yum.repos.d/cachi2.repo'
IS_HERMETIC = os.path.exists(HERMETIC_REPO)
def main():
parser = argparse.ArgumentParser(description='Build an FCOS rootfs.')
parser.add_argument('--target-rootfs', required=True, help='Path to the target rootfs.')
parser = argparse.ArgumentParser(description='Build a CoreOS rootfs.')
parser.add_argument('--srcdir', default='/src',
help='The source config directory')
subparsers = parser.add_subparsers(help='Subcommands', required=True)
cmd_make_rootfs = \
subparsers.add_parser('make-rootfs',
help='Generate a container root filesystem')
cmd_make_rootfs.add_argument('--target-rootfs', required=True,
help='Path to the target rootfs.')
cmd_make_rootfs.set_defaults(func=build_rootfs)
cmd_parse_treefile = \
subparsers.add_parser('parse-treefile',
help='Print flattened treefile to stdout')
cmd_parse_treefile.set_defaults(func=print_treefile)
args = parser.parse_args()
manifest_path = os.path.join(SRCDIR, os.getenv('MANIFEST'))
image_cfg_path = os.path.join(SRCDIR, os.getenv('IMAGE_CONFIG'))
version = os.getenv('VERSION')
stream = os.getenv('STREAM')
id = os.getenv('ID')
mutate_os_release = os.getenv('MUTATE_OS_RELEASE')
strict_mode = os.getenv('STRICT_MODE')
passwd_group_dir = os.getenv('PASSWD_GROUP_DIR')
# Convert srcdir arg into absolute path
args.srcdir = os.path.abspath(args.srcdir)
manifest = get_treefile(
manifest=manifest_path,
id=id,
stream=stream,
version=version
)
packages = list(manifest['packages'])
variables = {
'target_rootfs': getattr(args, 'target_rootfs', ''),
'srcdir': args.srcdir,
'manifest_name': os.getenv('MANIFEST'),
'image_config': os.getenv('IMAGE_CONFIG'),
'version': os.getenv('VERSION'),
'stream': os.getenv('STREAM'),
'osid': os.getenv('ID'),
'mutate_os_release': os.getenv('MUTATE_OS_RELEASE'),
'strict_mode': os.getenv('STRICT_MODE'),
'passwd_group_dir': os.getenv('PASSWD_GROUP_DIR')
}
repos = manifest.get('repos', [])
lockfile_repos = manifest.get('lockfile-repos', [])
if repos or lockfile_repos:
inject_yumrepos()
local_overrides = prepare_local_rpm_overrides(args.target_rootfs)
if local_overrides:
repos += ['overrides']
locked_nevras = get_locked_nevras(local_overrides)
if locked_nevras:
# Lockfile repos require special handling because we only want locked
# NEVRAs to appear there. For lack of a generic solution for any repo
# there, we only special-case the one place where we know we use this.
if lockfile_repos == ['fedora-coreos-pool']:
if not IS_HERMETIC:
modify_pool_repo(locked_nevras)
repos += lockfile_repos
elif len(lockfile_repos) > 0:
raise Exception(f"unknown lockfile-repo found in {lockfile_repos}")
overlays = gather_overlays(manifest)
nodocs = (manifest.get('documentation') is False)
recommends = manifest.get('recommends')
# We generate the initramfs using dracut ourselves later after our
# CoreOS postprocess scripts have run. If this version of rpm-ostree
# supports it we'll tell it to not run dracut in the initial compose.
no_initramfs = True if no_initramfs_arg_supported() else False
build_rootfs(
args.target_rootfs, manifest_path, packages, locked_nevras,
overlays, repos, nodocs, recommends, no_initramfs, passwd_group_dir
)
inject_live(args.target_rootfs)
inject_image_json(args.target_rootfs, image_cfg_path, stream)
inject_platforms_json(args.target_rootfs)
inject_content_manifest(args.target_rootfs, manifest)
inject_version_info(
rootfs=args.target_rootfs,
replace_version=mutate_os_release,
version=version
)
if strict_mode == '1':
verify_strict_mode(args.target_rootfs, locked_nevras)
run_postprocess_scripts(args.target_rootfs, manifest)
run_dracut(args.target_rootfs)
cleanup_extraneous_files(args.target_rootfs)
calculate_inputhash(args.target_rootfs, overlays, manifest)
args.func(**variables)
def get_treefile(manifest, id, stream, version):
def print_treefile(manifest_name, osid, stream, version, srcdir, **kwargs):
if not manifest_name or not osid or not stream or not version or not srcdir:
raise Exception("Must set env vars before calling. Source build-args.conf")
manifest_path = os.path.join(srcdir, manifest_name)
print(json.dumps(get_treefile(manifest_path, osid, stream, version)))
def get_treefile(manifest_path, osid, stream, version):
with tempfile.NamedTemporaryFile(suffix='.json', mode='w') as tmp_manifest:
# Substitute in a few values from build-args into the treefile.
major_version = version.split('.')[0]
json.dump({
"variables": {
"deriving": True,
"id": id,
"id": osid,
"stream": stream,
"osversion": f"{id}-{major_version}"
"osversion": f"{osid}-{major_version}"
},
"releasever": int(major_version), # Only needed/used by Fedora
"include": manifest
"include": manifest_path
}, tmp_manifest)
tmp_manifest.flush()
data = subprocess.check_output(['rpm-ostree', 'compose', 'tree',
@@ -122,7 +90,7 @@ def get_treefile(manifest, id, stream, version):
return json.loads(data)
def inject_yumrepos():
def inject_yumrepos(srcdir):
# first delete all the default repos
for repo in glob.glob('/etc/yum.repos.d/*.repo'):
if os.path.basename(repo) == 'secret.repo':
@@ -135,16 +103,62 @@ def inject_yumrepos():
# and now inject our repos
if not IS_HERMETIC:
for repo in glob.glob(f'{SRCDIR}/*.repo'):
for repo in glob.glob(f'{srcdir}/*.repo'):
shutil.copy(repo, "/etc/yum.repos.d")
def build_rootfs(
target_rootfs, manifest_path, packages, locked_nevras,
overlays, repos, nodocs, recommends, no_initramfs,
passwd_group_dir
):
def build_rootfs(target_rootfs, srcdir, manifest_name,
image_config, osid, stream, version,
strict_mode, passwd_group_dir, mutate_os_release):
# we allow strict_mode and passwd_group_dir to be None. Check all others.
if not target_rootfs or not manifest_name or not image_config or \
not osid or not stream or not version or not mutate_os_release:
raise Exception("Must set env vars before calling. Source build-args.conf")
manifest_path = os.path.join(srcdir, manifest_name)
image_cfg_path = os.path.join(srcdir, image_config)
manifest = get_treefile(
manifest_path=manifest_path,
osid=osid,
stream=stream,
version=version
)
packages = list(manifest['packages'])
repos = manifest.get('repos', [])
lockfile_repos = manifest.get('lockfile-repos', [])
if repos or lockfile_repos:
inject_yumrepos(srcdir)
local_overrides = prepare_local_rpm_overrides(target_rootfs, srcdir)
if local_overrides:
repos += ['overrides']
locked_nevras = get_locked_nevras(local_overrides, srcdir)
if locked_nevras:
# Lockfile repos require special handling because we only want locked
# NEVRAs to appear there. For lack of a generic solution for any repo
# there, we only special-case the one place where we know we use this.
if lockfile_repos == ['fedora-coreos-pool']:
if not IS_HERMETIC:
modify_pool_repo(locked_nevras)
repos += lockfile_repos
elif len(lockfile_repos) > 0:
raise Exception(f"unknown lockfile-repo found in {lockfile_repos}")
overlays = gather_overlays(manifest, srcdir)
nodocs = (manifest.get('documentation') is False)
recommends = manifest.get('recommends')
# We generate the initramfs using dracut ourselves later after our
# CoreOS postprocess scripts have run. If this version of rpm-ostree
# supports it we'll tell it to not run dracut in the initial compose.
no_initramfs = True if no_initramfs_arg_supported() else False
if passwd_group_dir is not None:
inject_passwd_group(os.path.join(SRCDIR, passwd_group_dir))
inject_passwd_group(os.path.join(srcdir, passwd_group_dir))
with tempfile.NamedTemporaryFile(mode='w') as argsfile:
for pkg in packages:
argsfile.write(f"--install={pkg}\n")
@@ -177,6 +191,25 @@ def build_rootfs(
if nodocs and tmpd is not None:
del tmpd
inject_live(target_rootfs, srcdir)
inject_image_json(target_rootfs, image_cfg_path, stream)
inject_platforms_json(target_rootfs, srcdir)
inject_content_manifest(target_rootfs, manifest)
inject_version_info(
rootfs=target_rootfs,
replace_version=mutate_os_release,
version=version
)
if strict_mode == '1':
verify_strict_mode(target_rootfs, locked_nevras)
run_postprocess_scripts(target_rootfs, manifest)
run_dracut(target_rootfs)
cleanup_extraneous_files(target_rootfs)
calculate_inputhash(target_rootfs, overlays, manifest)
def get_bootc_base_imagectl_help():
return subprocess.check_output(['/usr/libexec/bootc-base-imagectl', 'build-rootfs', '-h'], encoding='utf-8')
@@ -287,8 +320,8 @@ def run_dracut(rootfs):
'--no-hostonly', f"/usr/lib/modules/{kver}/initramfs.img", kver])
def prepare_local_rpm_overrides(rootfs):
overrides_repo = os.path.join(SRCDIR, 'overrides/rpm')
def prepare_local_rpm_overrides(rootfs, srcdir):
overrides_repo = os.path.join(srcdir, 'overrides/rpm')
if not os.path.isdir(f'{overrides_repo}/repodata'):
return None
@@ -331,10 +364,10 @@ def bwrap(rootfs, args, capture=False):
subprocess.check_call(args)
def get_locked_nevras(local_overrides):
lockfile_path = os.path.join(SRCDIR, f"manifest-lock.{ARCH}.json")
overrides_path = os.path.join(SRCDIR, "manifest-lock.overrides.yaml")
overrides_arch_path = os.path.join(SRCDIR, f"manifest-lock.overrides.{ARCH}.yaml")
def get_locked_nevras(local_overrides, srcdir):
lockfile_path = os.path.join(srcdir, f"manifest-lock.{ARCH}.json")
overrides_path = os.path.join(srcdir, "manifest-lock.overrides.yaml")
overrides_arch_path = os.path.join(srcdir, f"manifest-lock.overrides.{ARCH}.yaml")
# we go from lowest priority to highest here: base lockfiles, overrides, local overrides
locks = {}
@@ -392,13 +425,13 @@ def inject_version_info(rootfs, replace_version, version):
# This re-implements cosa's overlay logic.
def gather_overlays(manifest):
def gather_overlays(manifest, srcdir):
overlays = []
for layer in manifest.get('ostree-layers', []):
assert layer.startswith('overlay/')
overlays.append(os.path.join(SRCDIR, 'overlay.d', layer[len('overlay/'):]))
overlays.append(os.path.join(srcdir, 'overlay.d', layer[len('overlay/'):]))
rootfs_override = os.path.join(SRCDIR, 'overrides/rootfs')
rootfs_override = os.path.join(srcdir, 'overrides/rootfs')
if os.path.isdir(rootfs_override) and len(os.listdir(rootfs_override)) > 0:
print("Injecting rootfs override")
overlays.append(rootfs_override)
@@ -407,9 +440,9 @@ def gather_overlays(manifest):
# Inject live/ bits.
def inject_live(rootfs):
def inject_live(rootfs, srcdir):
target_path = os.path.join(rootfs, 'usr/share/coreos-assembler/live')
shutil.copytree(os.path.join(SRCDIR, "live"), target_path)
shutil.copytree(os.path.join(srcdir, "live"), target_path)
def inject_image_json(rootfs, image_cfg_path, stream):
@@ -578,8 +611,8 @@ def merge_dicts(x, y):
return ret
def inject_platforms_json(rootfs):
with open(os.path.join(SRCDIR, 'platforms.yaml')) as f:
def inject_platforms_json(rootfs, srcdir):
with open(os.path.join(srcdir, 'platforms.yaml')) as f:
platforms = yaml.safe_load(f)
fn = os.path.join(rootfs, 'usr/share/coreos-assembler/platforms.json')
if ARCH in platforms: