-
Notifications
You must be signed in to change notification settings - Fork 188
[WIP] builtextend: produce a squashfs artifact #261
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| #!/usr/bin/python3 -u | ||
| # An operation that mutates a build by generating a squashfs rootfs. | ||
|
|
||
| import os | ||
| import sys | ||
| import json | ||
| import yaml | ||
| import shutil | ||
| import argparse | ||
|
|
||
| sys.path.insert(0, '/usr/lib/coreos-assembler') | ||
| from cmdlib import run_supermin, run_verbose, write_json, sha256sum_file | ||
|
|
||
| # Parse args and dispatch | ||
| parser = argparse.ArgumentParser() | ||
| parser.add_argument("--build", help="Build ID") | ||
| args = parser.parse_args() | ||
|
|
||
| # default to latest build if not specified | ||
| if not args.build: | ||
| with open('builds/builds.json') as f: | ||
| j = json.load(f) | ||
| args.build = j['builds'][0] | ||
|
|
||
| print(f"Targeting build: {args.build}") | ||
|
|
||
| with open('src/config/manifest.yaml') as f: | ||
| manifest = yaml.safe_load(f) | ||
|
|
||
| base_name = manifest['rojig']['name'] | ||
| img_prefix = f'{base_name}-{args.build}' | ||
| artifact_name = f'{img_prefix}.rootfs.squashfs' | ||
|
|
||
| builddir = f'builds/{args.build}' | ||
| buildmeta_path = f'{builddir}/meta.json' | ||
| with open(buildmeta_path) as f: | ||
| buildmeta = json.load(f) | ||
|
|
||
| tmpdir = 'tmp/buildpost-squashfs' | ||
| if os.path.isdir(tmpdir): | ||
| shutil.rmtree(tmpdir) | ||
| os.mkdir(tmpdir) | ||
|
|
||
|
|
||
| def generate_squashfs(workdir): | ||
| ref = buildmeta['ref'] | ||
| tmp_img = f'{tmpdir}/{artifact_name}' | ||
| script = f'''#!/usr/bin/env bash | ||
| set -xeuo pipefail | ||
| ostree checkout --repo {workdir}/repo/ {ref} /tmp/rootfs | ||
| /sbin/mksquashfs /tmp/rootfs {workdir}/{tmp_img} | ||
| ''' | ||
|
|
||
| run_supermin(workdir, script) | ||
| checksum = sha256sum_file(tmp_img) | ||
| buildmeta['images']['squashfs'] = { | ||
| 'path': artifact_name, | ||
| 'sha256': checksum | ||
| } | ||
| os.rename(tmp_img, f"{builddir}/{artifact_name}") | ||
| write_json(buildmeta_path, buildmeta) | ||
| print(f"Updated: {buildmeta_path}") | ||
|
|
||
|
|
||
| # Do it! | ||
| generate_squashfs(os.getcwd()) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,12 +2,15 @@ | |
|
|
||
| import hashlib | ||
| import json | ||
| import multiprocessing | ||
| import os | ||
| import shutil | ||
| import subprocess | ||
| import sys | ||
| import tempfile | ||
| from datetime import datetime | ||
|
|
||
| libdir = '/usr/lib/coreos-assembler/' | ||
|
|
||
| def run_verbose(args, **kwargs): | ||
| print("+ {}".format(subprocess.list2cmdline(args))) | ||
|
|
@@ -50,3 +53,82 @@ def rm_allow_noent(path): | |
| os.unlink(path) | ||
| except FileNotFoundError: | ||
| pass | ||
|
|
||
|
|
||
| def run_supermin(workdir, script=''): | ||
| vmpreparedir = f"{workdir}/tmp/supermin.prepare" | ||
| if os.path.isdir(vmpreparedir): | ||
| shutil.rmtree(vmpreparedir) | ||
| os.makedirs(vmpreparedir, exist_ok=True) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An |
||
|
|
||
| vmbuilddir = f"{workdir}/tmp/supermin.build" | ||
| if os.path.isdir(vmbuilddir): | ||
| shutil.rmtree(vmbuilddir) | ||
| os.makedirs(vmbuilddir, exist_ok=True) | ||
|
|
||
| rpms = [] | ||
| with open(f"{libdir}/vmdeps.txt") as vmdeps: | ||
| for line in vmdeps: | ||
| if not line or line.startswith('#'): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd write |
||
| continue | ||
| for pkg in line.split(): | ||
| rpms.append(pkg) | ||
|
|
||
| run_verbose(['supermin', | ||
| '--prepare', | ||
| '--use-installed', | ||
| '-o', f"{vmpreparedir}"] + rpms) | ||
|
|
||
| with open(f"{libdir}/supermin-init-prelude.sh") as prelude: | ||
| sm_init = prelude.read() | ||
|
|
||
| with open(f"{workdir}/tmp/cmd.sh", "w+") as scriptfile: | ||
| scriptfile.write(script) | ||
| initscript = f'''#!/usr/bin/env bash | ||
| set -xeuo pipefail | ||
| workdir={workdir} | ||
| {sm_init} | ||
| RC=0 | ||
| sh {workdir}/tmp/cmd.sh || RC=$? | ||
| echo $RC > {workdir}/tmp/rc | ||
| /sbin/fstrim -v {workdir}/cache | ||
| /sbin/poweroff -f | ||
| ''' | ||
| with open(f"{vmpreparedir}/init", "w+") as vminit: | ||
| vminit.write(initscript) | ||
| os.chmod(f"{vmpreparedir}/init", 0o755) | ||
| run_verbose(['tar', | ||
| '-C', f"{vmpreparedir}", | ||
| '-czf', f"{vmpreparedir}/init.tar.gz", | ||
| '--remove-files', | ||
| 'init']) | ||
|
|
||
| run_verbose(['supermin', | ||
| '--build', f"{vmpreparedir}", | ||
| '--size', '5G', | ||
| '-f', 'ext2', | ||
| '-o', f"{vmbuilddir}"]) | ||
|
|
||
| nproc = multiprocessing.cpu_count() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| run_verbose(['qemu-kvm', '-nodefaults', '-nographic', '-no-reboot', | ||
| '-smp', f"{nproc}", | ||
| '-m', '2048', | ||
| '-kernel', f"{vmbuilddir}/kernel", | ||
| '-initrd', f"{vmbuilddir}/initrd", | ||
| '-netdev', 'user,id=eth0,hostname=supermin', | ||
| '-device', 'virtio-net-pci,netdev=eth0', | ||
| '-device', 'virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x3', | ||
| '-drive', f"if=none,id=drive-scsi0-0-0-0,snapshot=on,file={vmbuilddir}/root", | ||
| '-device', 'scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=1', | ||
| '-drive', f"if=none,id=drive-scsi0-0-0-1,discard=unmap,file={workdir}/cache/cache.qcow2", | ||
| '-device', 'scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=1,drive=drive-scsi0-0-0-1,id=scsi0-0-0-1', | ||
| '-virtfs', f"local,id=workdir,path={workdir},security_model=none,mount_tag=workdir", | ||
| '-serial', 'stdio', '-append', 'root=/dev/sda console=ttyS0 selinux=1 enforcing=0 autorelabel=1']) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hopefully a next step after this would be to rewrite |
||
|
|
||
| rc = 99 | ||
| with open(f"{workdir}/tmp/rc") as rcfile: | ||
| rc = int(rcfile.readline()) | ||
|
|
||
| if rc != 0: | ||
| raise Exception(f"failed to run supermin (rc: {rc})") | ||
| return | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just a stub right? The commit description says it's bootable this won't do that AFAICS.
This whole concept kind of depends on us reworking to use not-anaconda right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes and no.
This a basic ostree->squashfs conversion, and the resulting artifact can already be run by
systemd-nspawn --volatile --boot(I wouldn't say it's bootable, as it doesn't contain any bootloader). No very interesting per se, but (possibly) an intermediate step towards re-using this rootfs for embeddeding in live PXE/ISO artifacts.In that regard, this flow is already bypassing anaconda. It consumes an ostree ref and runs this build-extending script in a supermin VM.