Compare commits
10 Commits
c587f511bc
...
b56f8facf3
| Author | SHA1 | Date |
|---|---|---|
|
|
b56f8facf3 | |
|
|
a064978a93 | |
|
|
96a86c132c | |
|
|
59a3fd49dc | |
|
|
235b55afcc | |
|
|
39a2d2d417 | |
|
|
47b5ce83bf | |
|
|
e58cc67615 | |
|
|
a215988280 | |
|
|
e2fda5e379 |
|
|
@ -3,3 +3,5 @@
|
||||||
*.qcow2
|
*.qcow2
|
||||||
repo/
|
repo/
|
||||||
_build/
|
_build/
|
||||||
|
*.repo/
|
||||||
|
*.tar
|
||||||
|
|
|
||||||
35
Makefile
35
Makefile
|
|
@ -39,7 +39,7 @@ endif
|
||||||
|
|
||||||
export CHECKPOINTS=build
|
export CHECKPOINTS=build
|
||||||
IMAGETYPES := regular ostree
|
IMAGETYPES := regular ostree
|
||||||
FORMATS := img qcow2 oci.tar repo rootfs ext4 tar
|
FORMATS := oci.tar repo tar
|
||||||
COMMON_TARGETS := qemu
|
COMMON_TARGETS := qemu
|
||||||
HOST_TARGETS := $(COMMON_TARGETS) $($(HOST_ARCH)_TARGETS)
|
HOST_TARGETS := $(COMMON_TARGETS) $($(HOST_ARCH)_TARGETS)
|
||||||
ALL_TARGETS := $(COMMON_TARGETS) $(foreach a,$(ARCHES), $($(a)_TARGETS))
|
ALL_TARGETS := $(COMMON_TARGETS) $(foreach a,$(ARCHES), $($(a)_TARGETS))
|
||||||
|
|
@ -66,9 +66,7 @@ help:
|
||||||
@echo
|
@echo
|
||||||
@echo Other extensions are also supported:
|
@echo Other extensions are also supported:
|
||||||
@echo \ \* .repo: Generate a repo with an ostree commit \(only works for ostree targets\)
|
@echo \ \* .repo: Generate a repo with an ostree commit \(only works for ostree targets\)
|
||||||
@echo \ \* .rootfs: Generate a directory with the rootfs content
|
|
||||||
@echo \ \* .tar: Generate a tar file with the rootfs content
|
@echo \ \* .tar: Generate a tar file with the rootfs content
|
||||||
@echo \ \* .ext4: Generate an ext4 filesystem with the rootfs content \(size from \"image_size\"\)
|
|
||||||
@echo \ \* oci.tar: Generate an oci container image with the rootfs content
|
@echo \ \* oci.tar: Generate an oci container image with the rootfs content
|
||||||
@echo
|
@echo
|
||||||
@echo You can pass variable declarations to osbuild-mpp with the DEFINES make variable.
|
@echo You can pass variable declarations to osbuild-mpp with the DEFINES make variable.
|
||||||
|
|
@ -76,28 +74,19 @@ help:
|
||||||
@echo For example, to add extra rpms to a minimal regular image, use:
|
@echo For example, to add extra rpms to a minimal regular image, use:
|
||||||
@echo " make cs9-qemu-minimal-regular.$(HOST_ARCH).qcow2 DEFINES='extra_rpms=[\"gdb\",\"strace\"]'"
|
@echo " make cs9-qemu-minimal-regular.$(HOST_ARCH).qcow2 DEFINES='extra_rpms=[\"gdb\",\"strace\"]'"
|
||||||
@echo
|
@echo
|
||||||
@echo To easily run the image with qemu, you can use the included runvm tool, like:
|
|
||||||
@echo \ \ ./runvm cs9-qemu-minimal-regular.$(HOST_ARCH).qcow2
|
|
||||||
@echo
|
|
||||||
@echo There are some additional targets:
|
@echo There are some additional targets:
|
||||||
@echo \ \ manifests: generates resolved json manifests for all images without building them.
|
@echo \ \ manifests: generates resolved json manifests for all images without building them.
|
||||||
@echo \ \ clean_caches: Removes intermediate image build artifacts \(that improve rebuild speed\)
|
@echo \ \ clean_caches: Removes intermediate image build artifacts \(that improve rebuild speed\)
|
||||||
@echo \ \ clean_downloads: Removes files downloaded during image builds
|
@echo \ \ clean_downloads: Removes files downloaded during image builds
|
||||||
@echo \ \ clean: Run clean_caches and clean_downloads
|
@echo \ \ clean: Run clean_caches and clean_downloads
|
||||||
@echo \ \ osbuildvm-images: Build a image that can be used to build images inside a VM
|
|
||||||
@echo
|
@echo
|
||||||
@echo There are also some common conversion rules:
|
@echo There are also some common conversion rules:
|
||||||
@echo \ \ foo.ext4.simg will build foo.ext4 and then convert it with img2simg
|
|
||||||
@echo \ \ foo.simg will build foo.img and then convert it with img2simg
|
|
||||||
@echo \ \ foo.tar.gz will build $foo.tar and then gzip it
|
@echo \ \ foo.tar.gz will build $foo.tar and then gzip it
|
||||||
@echo
|
@echo
|
||||||
@echo "When building a custom variant of an image (say with an extra package) you can use a"
|
@echo "When building a custom variant of an image (say with an extra package) you can use a"
|
||||||
@echo custom @suffix to change the name of the produced file. For example:
|
@echo custom @suffix to change the name of the produced file. For example:
|
||||||
@echo " make cs9-qemu-minimal-ostree@gdb.$(HOST_ARCH).qcow2 DEFINES='extra_rpms=[\"gdb\"]'"
|
@echo " make cs9-qemu-minimal-ostree@gdb.$(HOST_ARCH).qcow2 DEFINES='extra_rpms=[\"gdb\"]'"
|
||||||
@echo
|
@echo
|
||||||
@echo If you pass VM=1, then the images used from \"make osbuildvm-images\" will be used to do the
|
|
||||||
@echo actual building. This means that you don\'t need sudo rights to run osbuild, and it means
|
|
||||||
@echo architectures other than the current ones can be built.
|
|
||||||
@echo
|
@echo
|
||||||
@echo Available image targets \(for $(HOST_ARCH)\) are:
|
@echo Available image targets \(for $(HOST_ARCH)\) are:
|
||||||
@echo
|
@echo
|
||||||
|
|
@ -181,30 +170,8 @@ clean_caches:
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean: clean_downloads clean_caches
|
clean: clean_downloads clean_caches
|
||||||
|
|
||||||
ifeq ($(VM), 1)
|
|
||||||
VM_SUDO=
|
|
||||||
VM_OSBUILD="osbuildvm/osbuildvm --arch=$(HOST_ARCH)"
|
|
||||||
else
|
|
||||||
VM_SUDO=sudo
|
VM_SUDO=sudo
|
||||||
VM_OSBUILD=sudo osbuild
|
VM_OSBUILD=sudo osbuild
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: osbuildvm-images
|
|
||||||
osbuildvm-images: $(BUILDDIR)
|
|
||||||
osbuild-mpp osbuildvm/osbuildvm.mpp.yml _build/osbuildvm-$(HOST_ARCH).json
|
|
||||||
$(VM_OSBUILD) --store $(STOREDIR) --output-directory $(OUTPUTDIR) --export osbuildvm _build/osbuildvm-$(HOST_ARCH).json
|
|
||||||
cp $(OUTPUTDIR)/osbuildvm/disk.qcow2 _build/osbuildvm-$(HOST_ARCH).img
|
|
||||||
cp $(OUTPUTDIR)/osbuildvm/initramfs _build/osbuildvm-$(HOST_ARCH).initramfs
|
|
||||||
cp $(OUTPUTDIR)/osbuildvm/vmlinuz _build/osbuildvm-$(HOST_ARCH).vmlinuz
|
|
||||||
$(VM_SUDO) rm -rf $(OUTPUTDIR)/osbuildvm
|
|
||||||
|
|
||||||
%.ext4.simg : %.ext4
|
|
||||||
img2simg $< $@
|
|
||||||
rm $<
|
|
||||||
|
|
||||||
%.simg : %.img
|
|
||||||
img2simg $< $@
|
|
||||||
rm $<
|
|
||||||
|
|
||||||
%.tar.gz : %.tar
|
%.tar.gz : %.tar
|
||||||
gzip -f $<
|
gzip -f $<
|
||||||
|
|
|
||||||
2
NOTICES
2
NOTICES
|
|
@ -1,6 +1,6 @@
|
||||||
This software was forked from: https://gitlab.com/CentOS/automotive/sample-images
|
This software was forked from: https://gitlab.com/CentOS/automotive/sample-images
|
||||||
|
|
||||||
Copyright (c) 2021 AutoBase
|
Copyright Red Hat
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
# This service runs once each boot to remove potential leftover
|
||||||
|
# container state from previous boots.
|
||||||
|
|
||||||
|
# This is needed as we're using transient mode in podman where the
|
||||||
|
# database and other configs are stored in tmpfs, but some other files
|
||||||
|
# are not. If we don't run this after ane unclean boot then there may
|
||||||
|
# be leftover files that collect over time.
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Clean up podman transient data
|
||||||
|
RequiresMountsFor=%t/containers
|
||||||
|
Requires=boot-complete.target
|
||||||
|
After=local-fs.target boot-complete.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/bin/podman system prune --external
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
@ -3,6 +3,11 @@
|
||||||
driver = "overlay"
|
driver = "overlay"
|
||||||
runroot = "/run/containers/storage"
|
runroot = "/run/containers/storage"
|
||||||
graphroot = "/var/lib/containers/storage"
|
graphroot = "/var/lib/containers/storage"
|
||||||
|
# Enables a global transient storaga mode where all container metadata is stored on non-persistant media
|
||||||
|
# This guaranteea a fresh state on boot.
|
||||||
|
# However it is not compabible with a traditional model where containers persist across reboots.
|
||||||
|
# Use with `podman-clean-transient.service`
|
||||||
|
transient_store = true
|
||||||
|
|
||||||
[storage.options]
|
[storage.options]
|
||||||
# We add a custom "/usr/share/containers/storage" here to allow readonly in-image containers
|
# We add a custom "/usr/share/containers/storage" here to allow readonly in-image containers
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
podman build --no-cache \
|
||||||
|
--build-arg commit=cs9-qemu-container-ostree.x86_64.repo \
|
||||||
|
-f ./hosting/Dockerfile \
|
||||||
|
-t j7s-os:latest .
|
||||||
|
|
@ -33,15 +33,15 @@ pipelines:
|
||||||
- mpp-eval: distro_repos
|
- mpp-eval: distro_repos
|
||||||
- mpp-eval: target_repos
|
- mpp-eval: target_repos
|
||||||
- mpp-eval: extra_repos
|
- mpp-eval: extra_repos
|
||||||
- - id: copr-quadlet
|
- - id: copr-podman
|
||||||
baseurl: https://download.copr.fedorainfracloud.org/results/alexl/quadlet/centos-stream-9-$arch/
|
baseurl: https://download.copr.fedorainfracloud.org/results/alexl/podman-snapshot/centos-stream-9-x86_64/
|
||||||
packages:
|
packages:
|
||||||
mpp-join:
|
mpp-join:
|
||||||
- mpp-eval: base_rpms
|
- mpp-eval: base_rpms
|
||||||
- mpp-eval: image_rpms
|
- mpp-eval: image_rpms
|
||||||
- mpp-eval: extra_rpms
|
- mpp-eval: extra_rpms
|
||||||
- - podman
|
- - podman
|
||||||
- quadlet
|
- podman-quadlet
|
||||||
- curl
|
- curl
|
||||||
excludes:
|
excludes:
|
||||||
- dracut-config-rescue
|
- dracut-config-rescue
|
||||||
|
|
@ -53,11 +53,20 @@ pipelines:
|
||||||
mpp-embed:
|
mpp-embed:
|
||||||
id: storage.conf
|
id: storage.conf
|
||||||
path: ../files/storage.conf
|
path: ../files/storage.conf
|
||||||
|
inlinefile2:
|
||||||
|
type: org.osbuild.files
|
||||||
|
origin: org.osbuild.source
|
||||||
|
mpp-embed:
|
||||||
|
id: podman-clean-transient.service
|
||||||
|
path: ../files/podman-clean-transient.service
|
||||||
options:
|
options:
|
||||||
paths:
|
paths:
|
||||||
- from:
|
- from:
|
||||||
mpp-format-string: input://inlinefile/{embedded['storage.conf']}
|
mpp-format-string: input://inlinefile/{embedded['storage.conf']}
|
||||||
to: tree:///etc/containers/storage.conf
|
to: tree:///etc/containers/storage.conf
|
||||||
|
- from:
|
||||||
|
mpp-format-string: input://inlinefile2/{embedded['podman-clean-transient.service']}
|
||||||
|
to: tree:///etc/systemd/system/podman-clean-transient.service
|
||||||
- type: org.osbuild.copy
|
- type: org.osbuild.copy
|
||||||
inputs:
|
inputs:
|
||||||
inlinefile:
|
inlinefile:
|
||||||
|
|
@ -111,5 +120,6 @@ pipelines:
|
||||||
enabled_services:
|
enabled_services:
|
||||||
- NetworkManager.service
|
- NetworkManager.service
|
||||||
- rngd.service
|
- rngd.service
|
||||||
|
- podman-clean-transient
|
||||||
- mpp-import-pipelines:
|
- mpp-import-pipelines:
|
||||||
path: include/image.ipp.yml
|
path: include/image.ipp.yml
|
||||||
|
|
|
||||||
|
|
@ -47,12 +47,6 @@ pipelines:
|
||||||
- type: org.osbuild.locale
|
- type: org.osbuild.locale
|
||||||
options:
|
options:
|
||||||
language: en_US.UTF-8
|
language: en_US.UTF-8
|
||||||
- type: org.osbuild.users
|
|
||||||
options:
|
|
||||||
users:
|
|
||||||
guest:
|
|
||||||
password:
|
|
||||||
mpp-eval: guest_password
|
|
||||||
- type: org.osbuild.systemd
|
- type: org.osbuild.systemd
|
||||||
options:
|
options:
|
||||||
enabled_services:
|
enabled_services:
|
||||||
|
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
version: '2'
|
|
||||||
mpp-vars:
|
|
||||||
efiarch: x64
|
|
||||||
boot_rpms:
|
|
||||||
mpp-join:
|
|
||||||
- mpp-eval: boot_rpms
|
|
||||||
- - grub2-efi-x64
|
|
||||||
- grub2-pc
|
|
||||||
base_rpms:
|
|
||||||
mpp-join:
|
|
||||||
- mpp-eval: base_rpms
|
|
||||||
- - microcode_ctl
|
|
||||||
pipelines:
|
|
||||||
- name: build
|
|
||||||
runner: org.osbuild.centos9
|
|
||||||
stages:
|
|
||||||
- type: org.osbuild.rpm
|
|
||||||
inputs:
|
|
||||||
packages:
|
|
||||||
type: org.osbuild.files
|
|
||||||
origin: org.osbuild.source
|
|
||||||
mpp-depsolve:
|
|
||||||
architecture: $arch
|
|
||||||
module-platform-id: $distro_module_id
|
|
||||||
baseurl: $distro_baseurl/BaseOS/$arch/os/
|
|
||||||
repos:
|
|
||||||
mpp-eval: distro_repos
|
|
||||||
packages:
|
|
||||||
mpp-join:
|
|
||||||
- mpp-eval: build_rpms
|
|
||||||
- mpp-eval: extra_build_rpms
|
|
||||||
- - grub2-efi-x64
|
|
||||||
- grub2-efi-x64-cdboot
|
|
||||||
- grub2-tools-efi
|
|
||||||
- grub2-pc
|
|
||||||
- grub2-pc-modules
|
|
||||||
- grub2-tools
|
|
||||||
- shim-x64
|
|
||||||
options:
|
|
||||||
gpgkeys:
|
|
||||||
- mpp-eval: centos_gpg_key
|
|
||||||
- mpp-eval: redhat_gpg_key
|
|
||||||
exclude:
|
|
||||||
docs: true
|
|
||||||
- type: org.osbuild.selinux
|
|
||||||
options:
|
|
||||||
file_contexts: etc/selinux/targeted/contexts/files/file_contexts
|
|
||||||
labels:
|
|
||||||
/usr/bin/cp: system_u:object_r:install_exec_t:s0
|
|
||||||
/usr/bin/tar: system_u:object_r:install_exec_t:s0
|
|
||||||
|
|
@ -3,36 +3,46 @@ version: '2'
|
||||||
mpp-vars:
|
mpp-vars:
|
||||||
distro_name: cs9 # The default
|
distro_name: cs9 # The default
|
||||||
|
|
||||||
mpp-define-image:
|
|
||||||
size: $image_size
|
|
||||||
table:
|
|
||||||
uuid: $parttab_uuid
|
|
||||||
label: $partition_label
|
|
||||||
partitions:
|
|
||||||
- id: efi
|
|
||||||
start:
|
|
||||||
mpp-eval: "0 if partition_label == 'gpt' else 2048"
|
|
||||||
size: $efipart_size
|
|
||||||
type:
|
|
||||||
mpp-eval: "'C12A7328-F81F-11D2-BA4B-00A0C93EC93B' if partition_label == 'gpt' else 'ef'"
|
|
||||||
uuid: $efipart_uuid
|
|
||||||
- id: boot
|
|
||||||
size: $bootpart_size
|
|
||||||
type:
|
|
||||||
mpp-eval: "'0FC63DAF-8483-4772-8E79-3D69D8477DE4' if partition_label == 'gpt' else '83'"
|
|
||||||
uuid: $bootpart_uuid
|
|
||||||
- id: root
|
|
||||||
type:
|
|
||||||
mpp-eval: "'0FC63DAF-8483-4772-8E79-3D69D8477DE4' if partition_label == 'gpt' else '83'"
|
|
||||||
uuid: $rootpart_uuid
|
|
||||||
pipelines:
|
pipelines:
|
||||||
- mpp-import-pipelines:
|
- mpp-import-pipelines:
|
||||||
path: distro/$distro_name.ipp.yml
|
path: distro/$distro_name.ipp.yml
|
||||||
- mpp-import-pipelines:
|
- mpp-import-pipelines:
|
||||||
path: defaults.ipp.yml
|
path: defaults.ipp.yml
|
||||||
- mpp-import-pipelines:
|
- name: build
|
||||||
path: target-$target.ipp.yml
|
runner: org.osbuild.centos9
|
||||||
- mpp-import-pipeline:
|
stages:
|
||||||
path: build-$arch.ipp.yml
|
- type: org.osbuild.rpm
|
||||||
id: build
|
inputs:
|
||||||
|
packages:
|
||||||
|
type: org.osbuild.files
|
||||||
|
origin: org.osbuild.source
|
||||||
|
mpp-depsolve:
|
||||||
|
architecture: $arch
|
||||||
|
module-platform-id: $distro_module_id
|
||||||
|
baseurl: $distro_baseurl/BaseOS/$arch/os/
|
||||||
|
repos:
|
||||||
|
mpp-eval: distro_repos
|
||||||
|
packages:
|
||||||
|
mpp-join:
|
||||||
|
- mpp-eval: build_rpms
|
||||||
|
- mpp-eval: extra_build_rpms
|
||||||
|
- - grub2-efi-x64
|
||||||
|
- grub2-efi-x64-cdboot
|
||||||
|
- grub2-tools-efi
|
||||||
|
- grub2-pc
|
||||||
|
- grub2-pc-modules
|
||||||
|
- grub2-tools
|
||||||
|
- shim-x64
|
||||||
|
options:
|
||||||
|
gpgkeys:
|
||||||
|
- mpp-eval: centos_gpg_key
|
||||||
|
- mpp-eval: redhat_gpg_key
|
||||||
|
exclude:
|
||||||
|
docs: true
|
||||||
|
- type: org.osbuild.selinux
|
||||||
|
options:
|
||||||
|
file_contexts: etc/selinux/targeted/contexts/files/file_contexts
|
||||||
|
labels:
|
||||||
|
/usr/bin/cp: system_u:object_r:install_exec_t:s0
|
||||||
|
/usr/bin/tar: system_u:object_r:install_exec_t:s0
|
||||||
runner: org.osbuild.centos9
|
runner: org.osbuild.centos9
|
||||||
|
|
|
||||||
|
|
@ -5,36 +5,17 @@ mpp-vars:
|
||||||
default_ostree_ref: $distro_name/$arch/$target-$name
|
default_ostree_ref: $distro_name/$arch/$target-$name
|
||||||
default_ostree_os_version: $distro_version
|
default_ostree_os_version: $distro_version
|
||||||
default_osname: centos
|
default_osname: centos
|
||||||
default_uefi_vendor: centos
|
|
||||||
default_kernel_rpm: kernel
|
default_kernel_rpm: kernel
|
||||||
default_linux_firmware_rpm: linux-firmware
|
default_linux_firmware_rpm: linux-firmware
|
||||||
default_partition_label: gpt
|
|
||||||
default_extra_rpms: []
|
default_extra_rpms: []
|
||||||
default_extra_build_rpms: []
|
default_extra_build_rpms: []
|
||||||
default_extra_repos: []
|
default_extra_repos: []
|
||||||
default_target_repos: []
|
default_target_repos: []
|
||||||
default_root_password: $6$xoLqEUz0cGGJRx01$H3H/bFm0myJPULNMtbSsOFd/2BnHqHkMD92Sfxd.EKM9hXTWSmELG8cf205l6dktomuTcgKGGtGDgtvHVXSWU.
|
|
||||||
default_guest_password: $6$xoLqEUz0cGGJRx01$H3H/bFm0myJPULNMtbSsOFd/2BnHqHkMD92Sfxd.EKM9hXTWSmELG8cf205l6dktomuTcgKGGtGDgtvHVXSWU.
|
|
||||||
default_root_ssh_key: ""
|
|
||||||
default_ssh_permit_root_login: false
|
|
||||||
default_image_size: '8589934592'
|
|
||||||
default_efipart_size: 204800
|
|
||||||
default_bootpart_size: 614400
|
|
||||||
default_kernel_loglevel: 4
|
|
||||||
static_uuids:
|
static_uuids:
|
||||||
mpp-eval: locals().get('static_uuids', True)
|
mpp-eval: locals().get('static_uuids', True)
|
||||||
default_rootfs_uuid:
|
default_rootfs_uuid:
|
||||||
mpp-eval: ('76a22bf4-f153-4541-b6c7-0332c0dfaeac' if static_uuids else str(__import__('uuid').uuid4()))
|
mpp-eval: ('76a22bf4-f153-4541-b6c7-0332c0dfaeac' if static_uuids else str(__import__('uuid').uuid4()))
|
||||||
default_bootfs_uuid:
|
default_kernel_loglevel: 4
|
||||||
mpp-eval: ('156f0420-627b-4151-ae6f-fda298097515' if static_uuids else str(__import__('uuid').uuid4()))
|
|
||||||
default_parttab_uuid:
|
|
||||||
mpp-eval: ('d209c89e-ea5e-4fbd-b161-b461cce297e0' if static_uuids else str(__import__('uuid').uuid4()))
|
|
||||||
default_efipart_uuid:
|
|
||||||
mpp-eval: ('68b2905b-df3e-4fb3-80fa-49d1e773aa33' if static_uuids else str(__import__('uuid').uuid4()))
|
|
||||||
default_bootpart_uuid:
|
|
||||||
mpp-eval: ('61b2905b-df3e-4fb3-80fa-49d1e773aa32' if static_uuids else str(__import__('uuid').uuid4()))
|
|
||||||
default_rootpart_uuid:
|
|
||||||
mpp-eval: ('6264d520-3fb9-423f-8ab8-7a0a8e3d3562' if static_uuids else str(__import__('uuid').uuid4()))
|
|
||||||
default_use_efi_runtime: true
|
default_use_efi_runtime: true
|
||||||
default_kernel_opts:
|
default_kernel_opts:
|
||||||
- console=tty0
|
- console=tty0
|
||||||
|
|
@ -86,10 +67,6 @@ mpp-vars:
|
||||||
mpp-eval: locals().get('ostree_os_version', default_ostree_os_version)
|
mpp-eval: locals().get('ostree_os_version', default_ostree_os_version)
|
||||||
osname:
|
osname:
|
||||||
mpp-eval: locals().get('osname', default_osname)
|
mpp-eval: locals().get('osname', default_osname)
|
||||||
uefi_vendor:
|
|
||||||
mpp-eval: locals().get('uefi_vendor', default_uefi_vendor)
|
|
||||||
partition_label:
|
|
||||||
mpp-eval: locals().get('partition_label', default_partition_label)
|
|
||||||
extra_rpms:
|
extra_rpms:
|
||||||
mpp-eval: locals().get('extra_rpms', default_extra_rpms)
|
mpp-eval: locals().get('extra_rpms', default_extra_rpms)
|
||||||
extra_build_rpms:
|
extra_build_rpms:
|
||||||
|
|
@ -98,26 +75,10 @@ mpp-vars:
|
||||||
mpp-eval: locals().get('extra_repos', default_extra_repos)
|
mpp-eval: locals().get('extra_repos', default_extra_repos)
|
||||||
target_repos:
|
target_repos:
|
||||||
mpp-eval: locals().get('target_repos', default_target_repos)
|
mpp-eval: locals().get('target_repos', default_target_repos)
|
||||||
image_size:
|
|
||||||
mpp-eval: locals().get('image_size', default_image_size)
|
|
||||||
rootfs_uuid:
|
rootfs_uuid:
|
||||||
mpp-eval: locals().get('rootfs_uuid', default_rootfs_uuid)
|
mpp-eval: locals().get('rootfs_uuid', default_rootfs_uuid)
|
||||||
bootfs_uuid:
|
|
||||||
mpp-eval: locals().get('bootfs_uuid', default_bootfs_uuid)
|
|
||||||
parttab_uuid:
|
|
||||||
mpp-eval: locals().get('parttab_uuid', default_parttab_uuid)
|
|
||||||
rootpart_uuid:
|
|
||||||
mpp-eval: locals().get('rootpart_uuid', default_rootpart_uuid)
|
|
||||||
bootpart_uuid:
|
|
||||||
mpp-eval: locals().get('bootpart_uuid', default_bootpart_uuid)
|
|
||||||
efipart_uuid:
|
|
||||||
mpp-eval: locals().get('efipart_uuid', default_efipart_uuid)
|
|
||||||
kernel_opts:
|
kernel_opts:
|
||||||
mpp-eval: locals().get('kernel_opts', default_kernel_opts)
|
mpp-eval: locals().get('kernel_opts', default_kernel_opts)
|
||||||
efipart_size:
|
|
||||||
mpp-eval: locals().get('efipart_size', default_efipart_size)
|
|
||||||
bootpart_size:
|
|
||||||
mpp-eval: locals().get('bootpart_size', default_bootpart_size)
|
|
||||||
dracut_add_modules:
|
dracut_add_modules:
|
||||||
mpp-eval: locals().get('dracut_add_modules', default_dracut_add_modules)
|
mpp-eval: locals().get('dracut_add_modules', default_dracut_add_modules)
|
||||||
dracut_omit_modules:
|
dracut_omit_modules:
|
||||||
|
|
@ -128,14 +89,6 @@ mpp-vars:
|
||||||
mpp-eval: locals().get('dracut_add_drivers', default_dracut_add_drivers)
|
mpp-eval: locals().get('dracut_add_drivers', default_dracut_add_drivers)
|
||||||
dracut_install:
|
dracut_install:
|
||||||
mpp-eval: locals().get('dracut_install', default_dracut_install)
|
mpp-eval: locals().get('dracut_install', default_dracut_install)
|
||||||
root_password:
|
|
||||||
mpp-eval: locals().get('root_password', default_root_password)
|
|
||||||
root_ssh_key:
|
|
||||||
mpp-eval: locals().get('root_ssh_key', default_root_ssh_key)
|
|
||||||
ssh_permit_root_login:
|
|
||||||
mpp-eval: locals().get('ssh_permit_root_login', default_ssh_permit_root_login)
|
|
||||||
guest_password:
|
|
||||||
mpp-eval: locals().get('guest_password', default_guest_password)
|
|
||||||
ostree_repo_url:
|
ostree_repo_url:
|
||||||
mpp-eval: locals().get('ostree_repo_url', default_ostree_repo_url)
|
mpp-eval: locals().get('ostree_repo_url', default_ostree_repo_url)
|
||||||
ostree_remote_name:
|
ostree_remote_name:
|
||||||
|
|
@ -237,24 +190,6 @@ mpp-vars:
|
||||||
iA==
|
iA==
|
||||||
=+Gxh
|
=+Gxh
|
||||||
-----END PGP PUBLIC KEY BLOCK-----
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
fstab:
|
|
||||||
- uuid:
|
|
||||||
mpp-eval: rootfs_uuid
|
|
||||||
vfs_type: ext4
|
|
||||||
path: /
|
|
||||||
freq: 1
|
|
||||||
passno: 1
|
|
||||||
- label: ESP
|
|
||||||
vfs_type: vfat
|
|
||||||
path: /boot/efi
|
|
||||||
freq: 1
|
|
||||||
passno: 1
|
|
||||||
- uuid:
|
|
||||||
mpp-eval: bootfs_uuid
|
|
||||||
vfs_type: ext4
|
|
||||||
path: /boot
|
|
||||||
freq: 1
|
|
||||||
passno: 1
|
|
||||||
build_rpms:
|
build_rpms:
|
||||||
- dnf
|
- dnf
|
||||||
- dosfstools
|
- dosfstools
|
||||||
|
|
@ -275,9 +210,12 @@ mpp-vars:
|
||||||
boot_rpms:
|
boot_rpms:
|
||||||
- dracut-config-generic
|
- dracut-config-generic
|
||||||
- grub2-tools-minimal
|
- grub2-tools-minimal
|
||||||
|
- grub2-efi-x64
|
||||||
|
- grub2-pc
|
||||||
- $kernel_rpm
|
- $kernel_rpm
|
||||||
base_rpms:
|
base_rpms:
|
||||||
- $linux_firmware_rpm
|
- $linux_firmware_rpm
|
||||||
|
- microcode_ctl
|
||||||
- NetworkManager
|
- NetworkManager
|
||||||
- audit
|
- audit
|
||||||
- chrony
|
- chrony
|
||||||
|
|
|
||||||
|
|
@ -96,114 +96,3 @@ pipelines:
|
||||||
mpp-if: ostree_ref in locals().get("ostree_parent_refs", {})
|
mpp-if: ostree_ref in locals().get("ostree_parent_refs", {})
|
||||||
then:
|
then:
|
||||||
mpp-eval: ostree_parent_refs[ostree_ref]
|
mpp-eval: ostree_parent_refs[ostree_ref]
|
||||||
- name: image-tree
|
|
||||||
build: name:build
|
|
||||||
stages:
|
|
||||||
- type: org.osbuild.ostree.init-fs
|
|
||||||
- type: org.osbuild.ostree.pull
|
|
||||||
options:
|
|
||||||
repo: /ostree/repo
|
|
||||||
remote:
|
|
||||||
mpp-eval: ostree_remote_name
|
|
||||||
inputs:
|
|
||||||
commits:
|
|
||||||
type: org.osbuild.ostree
|
|
||||||
origin: org.osbuild.pipeline
|
|
||||||
references:
|
|
||||||
name:ostree-commit:
|
|
||||||
ref:
|
|
||||||
mpp-eval: ostree_ref
|
|
||||||
- type: org.osbuild.ostree.os-init
|
|
||||||
options:
|
|
||||||
osname:
|
|
||||||
mpp-eval: osname
|
|
||||||
- type: org.osbuild.ostree.config
|
|
||||||
options:
|
|
||||||
repo: /ostree/repo
|
|
||||||
config:
|
|
||||||
sysroot:
|
|
||||||
readonly: true
|
|
||||||
bootloader: none
|
|
||||||
- type: org.osbuild.ostree.remotes
|
|
||||||
options:
|
|
||||||
repo: /ostree/repo
|
|
||||||
remotes:
|
|
||||||
- name:
|
|
||||||
mpp-eval: ostree_remote_name
|
|
||||||
url:
|
|
||||||
mpp-eval: ostree_repo_url
|
|
||||||
- type: org.osbuild.mkdir
|
|
||||||
options:
|
|
||||||
paths:
|
|
||||||
- path: /boot/efi
|
|
||||||
mode: 448
|
|
||||||
- type: org.osbuild.ostree.deploy
|
|
||||||
options:
|
|
||||||
osname:
|
|
||||||
mpp-eval: osname
|
|
||||||
ref:
|
|
||||||
mpp-eval: ostree_ref
|
|
||||||
remote:
|
|
||||||
mpp-eval: ostree_remote_name
|
|
||||||
mounts:
|
|
||||||
- /boot
|
|
||||||
- /boot/efi
|
|
||||||
rootfs:
|
|
||||||
label: root
|
|
||||||
kernel_opts:
|
|
||||||
mpp-eval: kernel_opts
|
|
||||||
- type: org.osbuild.ostree.fillvar
|
|
||||||
options:
|
|
||||||
deployment:
|
|
||||||
osname:
|
|
||||||
mpp-eval: osname
|
|
||||||
ref:
|
|
||||||
mpp-eval: ostree_ref
|
|
||||||
- type: org.osbuild.users
|
|
||||||
mounts:
|
|
||||||
- type: org.osbuild.ostree.deployment
|
|
||||||
name: ostree.deployment
|
|
||||||
options:
|
|
||||||
deployment:
|
|
||||||
osname:
|
|
||||||
mpp-eval: osname
|
|
||||||
ref:
|
|
||||||
mpp-eval: ostree_ref
|
|
||||||
options:
|
|
||||||
users:
|
|
||||||
root:
|
|
||||||
password:
|
|
||||||
mpp-eval: root_password
|
|
||||||
key:
|
|
||||||
mpp-eval: root_ssh_key
|
|
||||||
- type: org.osbuild.fstab
|
|
||||||
options:
|
|
||||||
ostree:
|
|
||||||
deployment:
|
|
||||||
osname:
|
|
||||||
mpp-eval: osname
|
|
||||||
ref:
|
|
||||||
mpp-eval: ostree_ref
|
|
||||||
filesystems:
|
|
||||||
mpp-eval: fstab
|
|
||||||
- type: org.osbuild.ostree.selinux
|
|
||||||
options:
|
|
||||||
deployment:
|
|
||||||
osname:
|
|
||||||
mpp-eval: osname
|
|
||||||
ref:
|
|
||||||
mpp-eval: ostree_ref
|
|
||||||
- type: org.osbuild.grub2
|
|
||||||
options:
|
|
||||||
rootfs:
|
|
||||||
label: root
|
|
||||||
bootfs:
|
|
||||||
label: boot
|
|
||||||
uefi:
|
|
||||||
vendor:
|
|
||||||
mpp-eval: uefi_vendor
|
|
||||||
unified: false
|
|
||||||
install: true
|
|
||||||
legacy: true
|
|
||||||
write_defaults: false
|
|
||||||
greenboot: true
|
|
||||||
|
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
version: '2'
|
|
||||||
mpp-vars:
|
|
||||||
image_rpms:
|
|
||||||
mpp-join:
|
|
||||||
- mpp-eval: locals().get('extra_image_rpms', [])
|
|
||||||
- mpp-eval: boot_rpms
|
|
||||||
- mpp-eval: locals().get('extra_boot_rpms', [])
|
|
||||||
- - shim
|
|
||||||
pipelines:
|
|
||||||
- name: image-tree
|
|
||||||
build: name:build
|
|
||||||
stages:
|
|
||||||
mpp-join:
|
|
||||||
- - type: org.osbuild.copy
|
|
||||||
inputs:
|
|
||||||
tree:
|
|
||||||
type: org.osbuild.tree
|
|
||||||
origin: org.osbuild.pipeline
|
|
||||||
references:
|
|
||||||
- name:rootfs
|
|
||||||
options:
|
|
||||||
paths:
|
|
||||||
mpp-join:
|
|
||||||
- - from: input://tree/
|
|
||||||
to: tree:///
|
|
||||||
- type: org.osbuild.users
|
|
||||||
options:
|
|
||||||
users:
|
|
||||||
root:
|
|
||||||
password:
|
|
||||||
mpp-eval: root_password
|
|
||||||
key:
|
|
||||||
mpp-eval: root_ssh_key
|
|
||||||
- mpp-eval: target_stages
|
|
||||||
- - type: org.osbuild.dracut
|
|
||||||
options:
|
|
||||||
kernel:
|
|
||||||
- mpp-eval: rpms['rootfs'][kernel_rpm + '-core'].evra
|
|
||||||
add_modules:
|
|
||||||
mpp-eval: dracut_add_modules
|
|
||||||
omit_modules:
|
|
||||||
mpp-eval: dracut_omit_modules
|
|
||||||
add_drivers:
|
|
||||||
mpp-eval: dracut_add_drivers
|
|
||||||
filesystems:
|
|
||||||
mpp-eval: dracut_filesystems
|
|
||||||
install:
|
|
||||||
mpp-eval: dracut_install
|
|
||||||
- type: org.osbuild.fstab
|
|
||||||
options:
|
|
||||||
filesystems:
|
|
||||||
mpp-eval: fstab
|
|
||||||
- type: org.osbuild.grub2
|
|
||||||
options:
|
|
||||||
root_fs_uuid:
|
|
||||||
mpp-eval: rootfs_uuid
|
|
||||||
boot_fs_uuid:
|
|
||||||
mpp-eval: bootfs_uuid
|
|
||||||
kernel_opts:
|
|
||||||
mpp-eval: ''' '' .join(kernel_opts)'
|
|
||||||
uefi:
|
|
||||||
vendor:
|
|
||||||
mpp-eval: uefi_vendor
|
|
||||||
unified: false
|
|
||||||
legacy: true
|
|
||||||
write_defaults: false
|
|
||||||
greenboot: true
|
|
||||||
- type: org.osbuild.fix-bls
|
|
||||||
options:
|
|
||||||
prefix: /
|
|
||||||
- type: org.osbuild.selinux
|
|
||||||
options:
|
|
||||||
file_contexts: etc/selinux/targeted/contexts/files/file_contexts
|
|
||||||
|
|
@ -11,142 +11,10 @@ mpp-vars:
|
||||||
then: efi=runtime
|
then: efi=runtime
|
||||||
- mpp-eval: kernel_opts
|
- mpp-eval: kernel_opts
|
||||||
pipelines:
|
pipelines:
|
||||||
# Some variables need to be written to files, do that here
|
|
||||||
|
# ostree pipeline is in other file.
|
||||||
- mpp-import-pipelines:
|
- mpp-import-pipelines:
|
||||||
path: image-$image_type.ipp.yml
|
path: image-ostree.ipp.yml
|
||||||
- name: image
|
|
||||||
build: name:build
|
|
||||||
stages:
|
|
||||||
- type: org.osbuild.truncate
|
|
||||||
options:
|
|
||||||
filename: disk.img
|
|
||||||
size:
|
|
||||||
mpp-eval: image.size
|
|
||||||
- type: org.osbuild.sfdisk
|
|
||||||
devices:
|
|
||||||
device:
|
|
||||||
type: org.osbuild.loopback
|
|
||||||
options:
|
|
||||||
filename: disk.img
|
|
||||||
options:
|
|
||||||
mpp-format-json: '{image.layout}'
|
|
||||||
- type: org.osbuild.mkfs.fat
|
|
||||||
devices:
|
|
||||||
device:
|
|
||||||
type: org.osbuild.loopback
|
|
||||||
options:
|
|
||||||
filename: disk.img
|
|
||||||
start:
|
|
||||||
mpp-eval: image.layout['efi'].start
|
|
||||||
size:
|
|
||||||
mpp-eval: image.layout['efi'].size
|
|
||||||
options:
|
|
||||||
label: ESP
|
|
||||||
volid: 7B7795E7
|
|
||||||
- type: org.osbuild.mkfs.ext4
|
|
||||||
devices:
|
|
||||||
device:
|
|
||||||
type: org.osbuild.loopback
|
|
||||||
options:
|
|
||||||
filename: disk.img
|
|
||||||
start:
|
|
||||||
mpp-eval: image.layout['boot'].start
|
|
||||||
size:
|
|
||||||
mpp-eval: image.layout['boot'].size
|
|
||||||
options:
|
|
||||||
uuid:
|
|
||||||
mpp-eval: bootfs_uuid
|
|
||||||
label: boot
|
|
||||||
- type: org.osbuild.mkfs.ext4
|
|
||||||
devices:
|
|
||||||
device:
|
|
||||||
type: org.osbuild.loopback
|
|
||||||
options:
|
|
||||||
filename: disk.img
|
|
||||||
start:
|
|
||||||
mpp-eval: image.layout['root'].start
|
|
||||||
size:
|
|
||||||
mpp-eval: image.layout['root'].size
|
|
||||||
options:
|
|
||||||
uuid:
|
|
||||||
mpp-eval: rootfs_uuid
|
|
||||||
label: root
|
|
||||||
- type: org.osbuild.copy
|
|
||||||
inputs:
|
|
||||||
tree:
|
|
||||||
type: org.osbuild.tree
|
|
||||||
origin: org.osbuild.pipeline
|
|
||||||
references:
|
|
||||||
- name:image-tree
|
|
||||||
build-tree:
|
|
||||||
type: org.osbuild.tree
|
|
||||||
origin: org.osbuild.pipeline
|
|
||||||
references:
|
|
||||||
- name:build
|
|
||||||
options:
|
|
||||||
paths:
|
|
||||||
mpp-join:
|
|
||||||
- - from: input://tree/
|
|
||||||
to: mount://root/
|
|
||||||
- mpp-eval: locals().get('extra_image_copy_' + image_type, [])
|
|
||||||
devices:
|
|
||||||
efi:
|
|
||||||
type: org.osbuild.loopback
|
|
||||||
options:
|
|
||||||
filename: disk.img
|
|
||||||
start:
|
|
||||||
mpp-eval: image.layout['efi'].start
|
|
||||||
size:
|
|
||||||
mpp-eval: image.layout['efi'].size
|
|
||||||
boot:
|
|
||||||
type: org.osbuild.loopback
|
|
||||||
options:
|
|
||||||
filename: disk.img
|
|
||||||
start:
|
|
||||||
mpp-eval: image.layout['boot'].start
|
|
||||||
size:
|
|
||||||
mpp-eval: image.layout['boot'].size
|
|
||||||
root:
|
|
||||||
type: org.osbuild.loopback
|
|
||||||
options:
|
|
||||||
filename: disk.img
|
|
||||||
start:
|
|
||||||
mpp-eval: image.layout['root'].start
|
|
||||||
size:
|
|
||||||
mpp-eval: image.layout['root'].size
|
|
||||||
mounts:
|
|
||||||
- name: root
|
|
||||||
type: org.osbuild.ext4
|
|
||||||
source: root
|
|
||||||
target: /
|
|
||||||
- name: boot
|
|
||||||
type: org.osbuild.ext4
|
|
||||||
source: boot
|
|
||||||
target: /boot
|
|
||||||
- name: efi
|
|
||||||
type: org.osbuild.fat
|
|
||||||
source: efi
|
|
||||||
target: /boot/efi
|
|
||||||
options:
|
|
||||||
vg_name: osbuild
|
|
||||||
creation_host: osbuild
|
|
||||||
description: "Built with osbuild"
|
|
||||||
- name: qcow2
|
|
||||||
build: name:build
|
|
||||||
stages:
|
|
||||||
- type: org.osbuild.qemu
|
|
||||||
inputs:
|
|
||||||
image:
|
|
||||||
type: org.osbuild.files
|
|
||||||
origin: org.osbuild.pipeline
|
|
||||||
references:
|
|
||||||
name:image:
|
|
||||||
file: disk.img
|
|
||||||
options:
|
|
||||||
filename: disk.qcow2
|
|
||||||
format:
|
|
||||||
type: qcow2
|
|
||||||
compat: '1.1'
|
|
||||||
|
|
||||||
- name: container
|
- name: container
|
||||||
build: name:build
|
build: name:build
|
||||||
|
|
@ -165,85 +33,6 @@ pipelines:
|
||||||
Cmd:
|
Cmd:
|
||||||
- "/usr/bin/bash"
|
- "/usr/bin/bash"
|
||||||
|
|
||||||
# We need a smaller fstab for the non-partitioned case
|
|
||||||
- name: ext4-fstab
|
|
||||||
build: name:build
|
|
||||||
stages:
|
|
||||||
# We copy /etc to get the right selinux context on the new file
|
|
||||||
- type: org.osbuild.copy
|
|
||||||
inputs:
|
|
||||||
image-tree:
|
|
||||||
type: org.osbuild.tree
|
|
||||||
origin: org.osbuild.pipeline
|
|
||||||
references:
|
|
||||||
- name:image-tree
|
|
||||||
options:
|
|
||||||
paths:
|
|
||||||
- from: input://image-tree/etc
|
|
||||||
to: tree:///etc
|
|
||||||
- type: org.osbuild.fstab
|
|
||||||
options:
|
|
||||||
filesystems:
|
|
||||||
- uuid:
|
|
||||||
mpp-eval: rootfs_uuid
|
|
||||||
vfs_type: ext4
|
|
||||||
path: /
|
|
||||||
|
|
||||||
- name: ext4
|
|
||||||
build: name:build
|
|
||||||
stages:
|
|
||||||
- type: org.osbuild.truncate
|
|
||||||
options:
|
|
||||||
filename: rootfs.ext4
|
|
||||||
size:
|
|
||||||
mpp-eval: image.size
|
|
||||||
- type: org.osbuild.mkfs.ext4
|
|
||||||
devices:
|
|
||||||
device:
|
|
||||||
type: org.osbuild.loopback
|
|
||||||
options:
|
|
||||||
filename: rootfs.ext4
|
|
||||||
start: 0
|
|
||||||
size:
|
|
||||||
mpp-format-int: "{int(image.size) // 512}"
|
|
||||||
options:
|
|
||||||
uuid:
|
|
||||||
mpp-eval: rootfs_uuid
|
|
||||||
label: root
|
|
||||||
- type: org.osbuild.copy
|
|
||||||
inputs:
|
|
||||||
tree:
|
|
||||||
type: org.osbuild.tree
|
|
||||||
origin: org.osbuild.pipeline
|
|
||||||
references:
|
|
||||||
- name:image-tree
|
|
||||||
fstab:
|
|
||||||
type: org.osbuild.tree
|
|
||||||
origin: org.osbuild.pipeline
|
|
||||||
references:
|
|
||||||
- name:ext4-fstab
|
|
||||||
options:
|
|
||||||
paths:
|
|
||||||
mpp-join:
|
|
||||||
- - from: input://tree/
|
|
||||||
to: mount://root/
|
|
||||||
- from: input://fstab/etc/fstab
|
|
||||||
to: mount://root/etc/fstab
|
|
||||||
- mpp-eval: locals().get('extra_image_copy_' + image_type, [])
|
|
||||||
devices:
|
|
||||||
root:
|
|
||||||
type: org.osbuild.loopback
|
|
||||||
options:
|
|
||||||
filename: rootfs.ext4
|
|
||||||
start: 0
|
|
||||||
size:
|
|
||||||
mpp-format-int: "{int(image.size) // 512}"
|
|
||||||
mounts:
|
|
||||||
- name: root
|
|
||||||
type: org.osbuild.ext4
|
|
||||||
source: root
|
|
||||||
target: /
|
|
||||||
|
|
||||||
- name: tar
|
- name: tar
|
||||||
build: name:build
|
build: name:build
|
||||||
stages:
|
stages:
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
version: '2'
|
|
||||||
pipelines: []
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
echo "========> Building minimal."
|
||||||
sudo podman run --rm \
|
sudo podman run --rm \
|
||||||
--privileged \
|
--privileged \
|
||||||
-v $PWD:/project:Z \
|
-v $PWD:/project:Z \
|
||||||
-w /project \
|
-w /project \
|
||||||
localhost/j7s-os-builder:latest \
|
localhost/j7s-os-builder:latest \
|
||||||
make cs9-qemu-minimal-ostree.x86_64.repo
|
make cs9-qemu-container-ostree.x86_64.repo
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,394 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import select
|
|
||||||
import shlex
|
|
||||||
import socket
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
import signal
|
|
||||||
import shutil
|
|
||||||
import json
|
|
||||||
|
|
||||||
BLOCK_SIZE = 64*1024
|
|
||||||
|
|
||||||
def read_manifest(path):
|
|
||||||
if path == "-":
|
|
||||||
manifest = sys.stdin.read()
|
|
||||||
else:
|
|
||||||
with open(path) as f:
|
|
||||||
manifest = f.read()
|
|
||||||
|
|
||||||
return manifest
|
|
||||||
|
|
||||||
def parse_arguments(sys_argv):
|
|
||||||
parser = argparse.ArgumentParser(description="Build operating system images")
|
|
||||||
|
|
||||||
parser.add_argument("manifest_path", metavar="MANIFEST",
|
|
||||||
help="json file containing the manifest that should be built, or a '-' to read from stdin")
|
|
||||||
parser.add_argument("--store", metavar="DIRECTORY", type=os.path.abspath,
|
|
||||||
default=".osbuild",
|
|
||||||
help="directory where intermediary os trees are stored")
|
|
||||||
parser.add_argument("--checkpoint", metavar="ID", action="append", type=str, default=None,
|
|
||||||
help="stage to commit to the object store during build (can be passed multiple times)")
|
|
||||||
parser.add_argument("--export", metavar="ID", action="append", type=str, default=None,
|
|
||||||
help="object to export, can be passed multiple times")
|
|
||||||
parser.add_argument("--output-directory", metavar="DIRECTORY", type=os.path.abspath,
|
|
||||||
help="directory where result objects are stored")
|
|
||||||
parser.add_argument("--arch", metavar="ARCH", type=str, default=platform.machine(),
|
|
||||||
help="Arch to build for")
|
|
||||||
|
|
||||||
return parser.parse_args(sys_argv[1:])
|
|
||||||
|
|
||||||
def local_osbuild(manifest, opts):
|
|
||||||
cmd = ['osbuild'] + opts + ['-']
|
|
||||||
try:
|
|
||||||
p = subprocess.run(cmd, check=True, input=manifest.encode("utf8"), capture_output=True )
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
print(e.output)
|
|
||||||
sys.exit(e.returncode)
|
|
||||||
lines = p.stdout.decode("utf8").splitlines()
|
|
||||||
checkpoints = {}
|
|
||||||
for l in lines:
|
|
||||||
p = l.split()
|
|
||||||
checkpoint = p[0][:-1]
|
|
||||||
checkpoints[checkpoint] = p[1]
|
|
||||||
return checkpoints
|
|
||||||
|
|
||||||
def extract_dependencies(manifest):
|
|
||||||
j = json.loads(manifest)
|
|
||||||
version = j.get("version", None);
|
|
||||||
if version != '2':
|
|
||||||
print(f"Unsupported manifest version {version}, only version 2 supported")
|
|
||||||
sys.exit(1)
|
|
||||||
sources = j.get("sources", {});
|
|
||||||
curl = sources.get("org.osbuild.curl", {});
|
|
||||||
curl_items = curl.get("items", {});
|
|
||||||
shas = curl_items.keys()
|
|
||||||
return list(shas)
|
|
||||||
|
|
||||||
def find_images(arch):
|
|
||||||
base_image=f"osbuildvm-{arch}.img"
|
|
||||||
base_kernel=f"osbuildvm-{arch}.vmlinuz"
|
|
||||||
base_initrd=f"osbuildvm-{arch}.initramfs"
|
|
||||||
|
|
||||||
image_dir=None
|
|
||||||
image_dirs = [os.getcwd(), os.path.join(os.getcwd(), "_build"), "/usr/share/osbuildvm"]
|
|
||||||
for i in image_dirs:
|
|
||||||
if os.path.exists(os.path.join(i, base_image)):
|
|
||||||
image_dir = i
|
|
||||||
break
|
|
||||||
if not image_dir:
|
|
||||||
print(f"Unable to find {base_image}, tried: {image_dirs}", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
image = os.path.join(image_dir, base_image)
|
|
||||||
kernel = os.path.join(image_dir, base_kernel)
|
|
||||||
initrd = os.path.join(image_dir, base_initrd)
|
|
||||||
return (image, kernel, initrd)
|
|
||||||
|
|
||||||
def qemu_img(*args):
|
|
||||||
res = subprocess.run(["qemu-img"] + [*args],
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
check=True)
|
|
||||||
|
|
||||||
class QEmu(object):
|
|
||||||
def __init__(self, image1, image2, kernel, initrd, arch):
|
|
||||||
# This is where we store the sockets and the pidfile
|
|
||||||
self.tmpdir = tempfile.TemporaryDirectory(prefix="tmp-qemu-")
|
|
||||||
self.args = []
|
|
||||||
self.pid = 0
|
|
||||||
self.host_arch = platform.machine()
|
|
||||||
self.arch = arch
|
|
||||||
|
|
||||||
debug_serial = False
|
|
||||||
|
|
||||||
qemu_kvm_path = self.find_qemu()
|
|
||||||
|
|
||||||
self.args.append(qemu_kvm_path)
|
|
||||||
|
|
||||||
# Virtio serial ports
|
|
||||||
|
|
||||||
self.args.extend(["-device", "virtio-serial"])
|
|
||||||
out_socket_path = self.add_socket("output")
|
|
||||||
sync_socket_path = self.add_socket("sync")
|
|
||||||
stdout_socket_path = self.add_socket("stdout")
|
|
||||||
|
|
||||||
debug_cmdline="quiet loglevel=1"
|
|
||||||
if debug_serial:
|
|
||||||
self.args.extend(["-serial", "file:/dev/stdout"])
|
|
||||||
debug_cmdline=""
|
|
||||||
|
|
||||||
# Machine details
|
|
||||||
self.args.extend(["-m", "size=2G",
|
|
||||||
"-nodefaults",
|
|
||||||
"-vga", "none", "-vnc", "none"])
|
|
||||||
|
|
||||||
if self.kvm_supported():
|
|
||||||
self.args.extend(["-enable-kvm"])
|
|
||||||
|
|
||||||
if self.arch=="x86_64":
|
|
||||||
machine = "q35"
|
|
||||||
cpu = "qemu64"
|
|
||||||
if self.arch=="aarch64":
|
|
||||||
machine = "virt"
|
|
||||||
cpu = "cortex-a57"
|
|
||||||
|
|
||||||
if self.arch == self.host_arch:
|
|
||||||
cpu = "host"
|
|
||||||
|
|
||||||
self.args.extend(["-machine", machine,
|
|
||||||
"-cpu", cpu])
|
|
||||||
|
|
||||||
if self.arch=="aarch64":
|
|
||||||
self.args.extend(["-bios", "/usr/share/edk2/aarch64/QEMU_EFI.fd",
|
|
||||||
"-boot", "efi"])
|
|
||||||
|
|
||||||
pid_file = os.path.join(self.tmpdir.name, "qemu.pid")
|
|
||||||
self.args.extend(["-daemonize", "-pidfile" , pid_file,
|
|
||||||
"-kernel", kernel,
|
|
||||||
"-initrd", initrd,
|
|
||||||
"-append", f'root=/dev/vda console=ttyS0 init=/usr/bin/start.sh {debug_cmdline} ro',
|
|
||||||
"-drive", f"file={image1},index=0,media=disk,format=qcow2,snapshot=on,if=virtio",
|
|
||||||
"-drive", f"file={image2},index=1,media=disk,format=raw,if=virtio"])
|
|
||||||
|
|
||||||
p = subprocess.run(self.args, check=True)
|
|
||||||
|
|
||||||
with open(pid_file, "r") as f:
|
|
||||||
self.pid = int(f.read())
|
|
||||||
|
|
||||||
self.sock_out = self.connect_socket(out_socket_path)
|
|
||||||
self.sock_sync = self.connect_socket(sync_socket_path)
|
|
||||||
self.sock_stdout = self.connect_socket(stdout_socket_path)
|
|
||||||
|
|
||||||
def connect_socket(self, path):
|
|
||||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
||||||
sock.connect(path)
|
|
||||||
return sock
|
|
||||||
|
|
||||||
def add_socket(self, id):
|
|
||||||
socket_path = os.path.join(self.tmpdir.name, id + ".sock")
|
|
||||||
self.args.extend(["-chardev", f"socket,path={socket_path},server=on,wait=off,id={id}",
|
|
||||||
"-device", f"virtserialport,chardev={id},name={id}"])
|
|
||||||
return socket_path
|
|
||||||
|
|
||||||
def find_qemu(self):
|
|
||||||
if self.arch == self.host_arch:
|
|
||||||
binary_name = "qemu-kvm"
|
|
||||||
else:
|
|
||||||
binary_name = f"qemu-system-{self.arch}"
|
|
||||||
|
|
||||||
|
|
||||||
for d in ["/usr/bin", "/usr/libexec"]:
|
|
||||||
p = os.path.join(d, binary_name)
|
|
||||||
if os.path.isfile(p):
|
|
||||||
return p
|
|
||||||
|
|
||||||
print(f"Can't find {binary_name}", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def kvm_supported(self):
|
|
||||||
return self.arch == self.host_arch and os.path.exists("/dev/kvm")
|
|
||||||
|
|
||||||
def copy_out(self, destination):
|
|
||||||
while True:
|
|
||||||
readable, writable, exceptional = select.select([self.sock_out, self.sock_sync, self.sock_stdout], [], [])
|
|
||||||
|
|
||||||
read_something = False
|
|
||||||
|
|
||||||
if self.sock_stdout in readable:
|
|
||||||
data = self.sock_stdout.recv(BLOCK_SIZE)
|
|
||||||
while len(data) > 0:
|
|
||||||
res = sys.stdout.buffer.write(data)
|
|
||||||
data = data[res:]
|
|
||||||
sys.stdout.flush()
|
|
||||||
read_something = True
|
|
||||||
|
|
||||||
if self.sock_out in readable:
|
|
||||||
data = self.sock_out.recv(BLOCK_SIZE)
|
|
||||||
while len(data) > 0:
|
|
||||||
res = destination.write(data)
|
|
||||||
data = data[res:]
|
|
||||||
read_something = True
|
|
||||||
|
|
||||||
if read_something:
|
|
||||||
continue # Don't exit until there is no more to read from sock or sock_stdout
|
|
||||||
|
|
||||||
# If we had no buffered data in sock and sync_sock is readable that means we copied everything and can exit
|
|
||||||
if self.sock_sync in readable:
|
|
||||||
data = self.sock_sync.recv(BLOCK_SIZE)
|
|
||||||
break
|
|
||||||
|
|
||||||
def kill(self):
|
|
||||||
if self.pid != 0:
|
|
||||||
os.kill(self.pid, signal.SIGTERM)
|
|
||||||
self.pid = 0
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __exit__(self, type, value, traceback):
|
|
||||||
self.kill()
|
|
||||||
self.tmpdir.cleanup()
|
|
||||||
|
|
||||||
def create_ext4_image(path, size, root_dir):
|
|
||||||
with open(path, "w") as f:
|
|
||||||
f.truncate(size)
|
|
||||||
|
|
||||||
cmd = ["mkfs.ext4", "-d", root_dir, "-E", "no_copy_xattrs,root_owner=0:0", "-O", "^has_journal", path]
|
|
||||||
try:
|
|
||||||
p = subprocess.run(cmd, check=True,capture_output=True)
|
|
||||||
except subprocess.CalledProcessError as e:
|
|
||||||
print(f"Unable to create ext4 work fs: {e}", file=sys.stderr)
|
|
||||||
sys.exit(e.returncode)
|
|
||||||
|
|
||||||
def link_or_copy_file(source_path, dest_path):
|
|
||||||
try:
|
|
||||||
os.link(source_path, dest_path)
|
|
||||||
except Exception as e:
|
|
||||||
shutil.copyfile(source_path, dest_path, follow_symlinks=False)
|
|
||||||
|
|
||||||
def make_work_rootfs(args, tmpdirname, manifest, digests, main_sh, checkpoint_ids):
|
|
||||||
rootdir = os.path.join(tmpdirname, "root")
|
|
||||||
os.makedirs(rootdir, exist_ok=True)
|
|
||||||
|
|
||||||
with open (os.open(os.path.join(rootdir, "main.sh"), os.O_CREAT | os.O_WRONLY, 0o775), "w") as mainsh:
|
|
||||||
mainsh.write(main_sh)
|
|
||||||
|
|
||||||
with open (os.path.join(rootdir, "image.json"), "w") as image_json:
|
|
||||||
image_json.write(manifest)
|
|
||||||
|
|
||||||
orig_sources_dir = os.path.join(args.store, "sources/org.osbuild.files")
|
|
||||||
root_sources_dir = os.path.join(rootdir, "osbuild_store/sources/org.osbuild.files")
|
|
||||||
os.makedirs(root_sources_dir, mode=0o777, exist_ok=True)
|
|
||||||
root_input_dir = os.path.join(rootdir, "input")
|
|
||||||
os.makedirs(root_input_dir, mode=0o777, exist_ok=True)
|
|
||||||
|
|
||||||
for digest in digests:
|
|
||||||
link_or_copy_file(os.path.join(orig_sources_dir, digest),
|
|
||||||
os.path.join(root_sources_dir, digest))
|
|
||||||
|
|
||||||
for cp, cp_id in checkpoint_ids.items():
|
|
||||||
source_path = os.path.join(args.store, "refs_tars/" + cp_id + ".tar.gz")
|
|
||||||
if os.path.isfile(source_path):
|
|
||||||
link_or_copy_file(source_path,
|
|
||||||
os.path.join(root_input_dir, cp_id + ".tar.gz"))
|
|
||||||
|
|
||||||
return rootdir
|
|
||||||
|
|
||||||
# Moves any files recursively in root_src_dir to root_dst_dir, replacing if needed
|
|
||||||
# Keeps old files and directories in root_dst_dir
|
|
||||||
def move_merged(root_src_dir, root_dst_dir):
|
|
||||||
root_src_dir = os.path.abspath(root_src_dir)
|
|
||||||
root_dst_dir = os.path.abspath(root_dst_dir)
|
|
||||||
for src_dir, dirs, files in os.walk(root_src_dir):
|
|
||||||
dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
|
|
||||||
if not os.path.exists(dst_dir):
|
|
||||||
os.makedirs(dst_dir)
|
|
||||||
for file_ in files:
|
|
||||||
src_file = os.path.join(src_dir, file_)
|
|
||||||
dst_file = os.path.join(dst_dir, file_)
|
|
||||||
if os.path.exists(dst_file):
|
|
||||||
os.remove(dst_file)
|
|
||||||
shutil.move(src_file, dst_dir)
|
|
||||||
|
|
||||||
def run_in_vm(args, manifest, digests, tmpdirname, shell_to_run, checkpoint_ids):
|
|
||||||
image,kernel,initrd = find_images(args.arch)
|
|
||||||
|
|
||||||
rootdir = make_work_rootfs(args, tmpdirname, manifest, digests, shell_to_run, checkpoint_ids)
|
|
||||||
work_image = os.path.join(tmpdirname, "work.img")
|
|
||||||
create_ext4_image(work_image, 100*1024*1024*1024, rootdir)
|
|
||||||
shutil.rmtree(rootdir)
|
|
||||||
|
|
||||||
output_path = args.output_directory
|
|
||||||
os.makedirs(output_path, exist_ok=True)
|
|
||||||
|
|
||||||
exit_status = 1
|
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory(prefix="download-", dir=output_path) as output_tmpdir:
|
|
||||||
with QEmu(image, work_image, kernel, initrd, args.arch) as qemu:
|
|
||||||
with subprocess.Popen(["tar", "x", "-C", output_tmpdir], stdin=subprocess.PIPE) as proc:
|
|
||||||
qemu.copy_out(proc.stdin)
|
|
||||||
exit_status_path = os.path.join(output_tmpdir, "exit_status")
|
|
||||||
if os.path.isfile(exit_status_path):
|
|
||||||
with open(exit_status_path, "r") as f:
|
|
||||||
exit_status = int(f.read())
|
|
||||||
|
|
||||||
# Move osbuild outout to the real output dir
|
|
||||||
osbuild_output = os.path.join(output_tmpdir, "osbuild")
|
|
||||||
if os.path.isdir(osbuild_output):
|
|
||||||
move_merged(osbuild_output, output_path)
|
|
||||||
|
|
||||||
checkpoints_output = os.path.join(output_tmpdir, "checkpoints")
|
|
||||||
checkpoints_dest = os.path.join(args.store, "refs_tars")
|
|
||||||
if os.path.isdir(checkpoints_output):
|
|
||||||
os.makedirs(checkpoints_dest, exist_ok=True)
|
|
||||||
for tar in os.listdir(checkpoints_output):
|
|
||||||
if not os.path.isfile(os.path.join(checkpoints_dest, tar)):
|
|
||||||
shutil.move(os.path.join(checkpoints_output, tar),
|
|
||||||
checkpoints_dest)
|
|
||||||
|
|
||||||
sys.exit(exit_status)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
args = parse_arguments(sys.argv)
|
|
||||||
manifest = read_manifest(args.manifest_path)
|
|
||||||
|
|
||||||
print("Running osbuild on host to download files")
|
|
||||||
checkpoint_ids = local_osbuild(manifest, ['--store', args.store])
|
|
||||||
|
|
||||||
digests = extract_dependencies(manifest)
|
|
||||||
|
|
||||||
mainsh_data = f'''\
|
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
mkdir -p /work/osbuild_store
|
|
||||||
(
|
|
||||||
echo === Extracting checkpoints in vm ===
|
|
||||||
for tar in $(find /work/input/ -mindepth 1 -print ); do
|
|
||||||
echo extracting $(basename $tar)
|
|
||||||
tar xf $tar --acls --selinux --xattrs -C /work/osbuild_store
|
|
||||||
done
|
|
||||||
echo === Running osbuild in vm ===
|
|
||||||
osbuild --store /work/osbuild_store --output-directory /work/output/osbuild {' '.join(map(lambda e: "--export " + e, args.export))} {' '.join(map(lambda cp: "--checkpoint " + cp, args.checkpoint))} /work/image.json
|
|
||||||
RES=$?
|
|
||||||
echo $RES > /work/output/exit_status
|
|
||||||
|
|
||||||
echo === Osbuild exit status $RES ===
|
|
||||||
|
|
||||||
echo === Saving checkpoints ===
|
|
||||||
mkdir -p /work/output/checkpoints
|
|
||||||
for cp in $(find /work/osbuild_store/refs/ -mindepth 1 -printf "%f "); do
|
|
||||||
if test -f /work/input/$cp.tar.gz; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
obj=$(basename $(readlink /work/osbuild_store/refs/$cp))
|
|
||||||
tar cSf /work/output/checkpoints/$cp.tar.gz --acls --selinux --xattrs -C /work/osbuild_store/ refs/$cp objects/$obj
|
|
||||||
echo Saved $cp
|
|
||||||
done
|
|
||||||
) > /dev/virtio-ports/stdout 2>&1
|
|
||||||
|
|
||||||
tar cSf /dev/virtio-ports/output -C /work/output ./
|
|
||||||
|
|
||||||
# Signal output ended
|
|
||||||
sleep 3
|
|
||||||
echo DONE > /dev/virtio-ports/sync
|
|
||||||
|
|
||||||
# Block for it to be fully read
|
|
||||||
cat /dev/virtio-ports/sync
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
tmpdir = os.path.join(args.store, "tmp")
|
|
||||||
os.makedirs(tmpdir, exist_ok=True)
|
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory(prefix="osbuild-qemu-", dir=tmpdir) as tmpdirname:
|
|
||||||
run_in_vm(args, manifest, digests, tmpdirname, mainsh_data, checkpoint_ids)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|
@ -1,229 +0,0 @@
|
||||||
version: '2'
|
|
||||||
mpp-vars:
|
|
||||||
rootfs_uuid: 86a22bf4-f153-4541-b6c7-0332c0dfaead
|
|
||||||
rootfs_size: 2147483648
|
|
||||||
cs9_baseurl: http://mirror.stream.centos.org/9-stream
|
|
||||||
cs9_repos:
|
|
||||||
- id: baseos
|
|
||||||
baseurl: $cs9_baseurl/BaseOS/$arch/os/
|
|
||||||
- id: appstream
|
|
||||||
baseurl: $cs9_baseurl/AppStream/$arch/os/
|
|
||||||
centos_gpg_key: |
|
|
||||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
||||||
Version: GnuPG v2.0.22 (GNU/Linux)
|
|
||||||
|
|
||||||
mQINBFzMWxkBEADHrskpBgN9OphmhRkc7P/YrsAGSvvl7kfu+e9KAaU6f5MeAVyn
|
|
||||||
rIoM43syyGkgFyWgjZM8/rur7EMPY2yt+2q/1ZfLVCRn9856JqTIq0XRpDUe4nKQ
|
|
||||||
8BlA7wDVZoSDxUZkSuTIyExbDf0cpw89Tcf62Mxmi8jh74vRlPy1PgjWL5494b3X
|
|
||||||
5fxDidH4bqPZyxTBqPrUFuo+EfUVEqiGF94Ppq6ZUvrBGOVo1V1+Ifm9CGEK597c
|
|
||||||
aevcGc1RFlgxIgN84UpuDjPR9/zSndwJ7XsXYvZ6HXcKGagRKsfYDWGPkA5cOL/e
|
|
||||||
f+yObOnC43yPUvpggQ4KaNJ6+SMTZOKikM8yciyBwLqwrjo8FlJgkv8Vfag/2UR7
|
|
||||||
JINbyqHHoLUhQ2m6HXSwK4YjtwidF9EUkaBZWrrskYR3IRZLXlWqeOi/+ezYOW0m
|
|
||||||
vufrkcvsh+TKlVVnuwmEPjJ8mwUSpsLdfPJo1DHsd8FS03SCKPaXFdD7ePfEjiYk
|
|
||||||
nHpQaKE01aWVSLUiygn7F7rYemGqV9Vt7tBw5pz0vqSC72a5E3zFzIIuHx6aANry
|
|
||||||
Gat3aqU3qtBXOrA/dPkX9cWE+UR5wo/A2UdKJZLlGhM2WRJ3ltmGT48V9CeS6N9Y
|
|
||||||
m4CKdzvg7EWjlTlFrd/8WJ2KoqOE9leDPeXRPncubJfJ6LLIHyG09h9kKQARAQAB
|
|
||||||
tDpDZW50T1MgKENlbnRPUyBPZmZpY2lhbCBTaWduaW5nIEtleSkgPHNlY3VyaXR5
|
|
||||||
QGNlbnRvcy5vcmc+iQI3BBMBAgAhBQJczFsZAhsDBgsJCAcDAgYVCAIJCgsDFgIB
|
|
||||||
Ah4BAheAAAoJEAW1VbOEg8ZdjOsP/2ygSxH9jqffOU9SKyJDlraL2gIutqZ3B8pl
|
|
||||||
Gy/Qnb9QD1EJVb4ZxOEhcY2W9VJfIpnf3yBuAto7zvKe/G1nxH4Bt6WTJQCkUjcs
|
|
||||||
N3qPWsx1VslsAEz7bXGiHym6Ay4xF28bQ9XYIokIQXd0T2rD3/lNGxNtORZ2bKjD
|
|
||||||
vOzYzvh2idUIY1DgGWJ11gtHFIA9CvHcW+SMPEhkcKZJAO51ayFBqTSSpiorVwTq
|
|
||||||
a0cB+cgmCQOI4/MY+kIvzoexfG7xhkUqe0wxmph9RQQxlTbNQDCdaxSgwbF2T+gw
|
|
||||||
byaDvkS4xtR6Soj7BKjKAmcnf5fn4C5Or0KLUqMzBtDMbfQQihn62iZJN6ZZ/4dg
|
|
||||||
q4HTqyVpyuzMXsFpJ9L/FqH2DJ4exGGpBv00ba/Zauy7GsqOc5PnNBsYaHCply0X
|
|
||||||
407DRx51t9YwYI/ttValuehq9+gRJpOTTKp6AjZn/a5Yt3h6jDgpNfM/EyLFIY9z
|
|
||||||
V6CXqQQ/8JRvaik/JsGCf+eeLZOw4koIjZGEAg04iuyNTjhx0e/QHEVcYAqNLhXG
|
|
||||||
rCTTbCn3NSUO9qxEXC+K/1m1kaXoCGA0UWlVGZ1JSifbbMx0yxq/brpEZPUYm+32
|
|
||||||
o8XfbocBWljFUJ+6aljTvZ3LQLKTSPW7TFO+GXycAOmCGhlXh2tlc6iTc41PACqy
|
|
||||||
yy+mHmSv
|
|
||||||
=kkH7
|
|
||||||
-----END PGP PUBLIC KEY BLOCK-----
|
|
||||||
pipelines:
|
|
||||||
- runner: org.osbuild.centos9
|
|
||||||
name: build
|
|
||||||
stages:
|
|
||||||
- type: org.osbuild.rpm
|
|
||||||
inputs:
|
|
||||||
packages:
|
|
||||||
type: org.osbuild.files
|
|
||||||
origin: org.osbuild.source
|
|
||||||
mpp-depsolve:
|
|
||||||
architecture: $arch
|
|
||||||
module-platform-id: platform:el9
|
|
||||||
baseurl: $cs9_baseurl/BaseOS/$arch/os/
|
|
||||||
repos:
|
|
||||||
mpp-eval: cs9_repos
|
|
||||||
packages:
|
|
||||||
- dnf
|
|
||||||
- e2fsprogs
|
|
||||||
- policycoreutils
|
|
||||||
- python3-iniparse
|
|
||||||
- python39
|
|
||||||
- qemu-img
|
|
||||||
- selinux-policy-targeted
|
|
||||||
- tar
|
|
||||||
- xz
|
|
||||||
options:
|
|
||||||
gpgkeys:
|
|
||||||
- mpp-eval: centos_gpg_key
|
|
||||||
exclude:
|
|
||||||
docs: true
|
|
||||||
- type: org.osbuild.selinux
|
|
||||||
options:
|
|
||||||
file_contexts: etc/selinux/targeted/contexts/files/file_contexts
|
|
||||||
labels:
|
|
||||||
/usr/bin/cp: system_u:object_r:install_exec_t:s0
|
|
||||||
/usr/bin/tar: system_u:object_r:install_exec_t:s0
|
|
||||||
- name: rootfs
|
|
||||||
build: name:build
|
|
||||||
stages:
|
|
||||||
- type: org.osbuild.rpm
|
|
||||||
options:
|
|
||||||
gpgkeys:
|
|
||||||
- mpp-eval: centos_gpg_key
|
|
||||||
inputs:
|
|
||||||
packages:
|
|
||||||
type: org.osbuild.files
|
|
||||||
origin: org.osbuild.source
|
|
||||||
mpp-depsolve:
|
|
||||||
architecture: $arch
|
|
||||||
module-platform-id: platform:el9
|
|
||||||
baseurl: $cs9_baseurl/BaseOS/$arch/os/
|
|
||||||
repos:
|
|
||||||
mpp-join:
|
|
||||||
- mpp-eval: cs9_repos
|
|
||||||
- - id: osbuild
|
|
||||||
baseurl: https://download.copr.fedorainfracloud.org/results/@osbuild/osbuild/centos-stream-9-$arch
|
|
||||||
packages:
|
|
||||||
- bash
|
|
||||||
- dracut-config-generic
|
|
||||||
- kernel
|
|
||||||
- langpacks-en
|
|
||||||
- selinux-policy-targeted
|
|
||||||
- net-tools
|
|
||||||
- osbuild
|
|
||||||
- osbuild-tools
|
|
||||||
- osbuild-ostree
|
|
||||||
excludes:
|
|
||||||
- dracut-config-rescue
|
|
||||||
- type: org.osbuild.locale
|
|
||||||
options:
|
|
||||||
language: en_US.UTF-8
|
|
||||||
- type: org.osbuild.copy
|
|
||||||
inputs:
|
|
||||||
inlinefile:
|
|
||||||
type: org.osbuild.files
|
|
||||||
origin: org.osbuild.source
|
|
||||||
mpp-embed:
|
|
||||||
id: osbuilder.sh
|
|
||||||
text: |
|
|
||||||
#!/usr/bin/bash
|
|
||||||
function clean_up {
|
|
||||||
systemctl poweroff -f -f
|
|
||||||
}
|
|
||||||
trap clean_up EXIT
|
|
||||||
if grep -q "osbuilder_bash=1" /proc/cmdline; then bash; exit; fi
|
|
||||||
mount /dev/vdb /work
|
|
||||||
/work/main.sh
|
|
||||||
options:
|
|
||||||
paths:
|
|
||||||
- from:
|
|
||||||
mpp-format-string: input://inlinefile/{embedded['osbuilder.sh']}
|
|
||||||
to: tree:///usr/bin/start.sh
|
|
||||||
- type: org.osbuild.chmod
|
|
||||||
options:
|
|
||||||
items:
|
|
||||||
/usr/bin/start.sh:
|
|
||||||
mode: a+x
|
|
||||||
- type: org.osbuild.mkdir
|
|
||||||
options:
|
|
||||||
paths:
|
|
||||||
- path: /work
|
|
||||||
- type: org.osbuild.selinux
|
|
||||||
options:
|
|
||||||
file_contexts: etc/selinux/targeted/contexts/files/file_contexts
|
|
||||||
- type: org.osbuild.selinux
|
|
||||||
options:
|
|
||||||
file_contexts: etc/selinux/targeted/contexts/files/file_contexts
|
|
||||||
- name: image
|
|
||||||
build: name:build
|
|
||||||
stages:
|
|
||||||
- type: org.osbuild.truncate
|
|
||||||
options:
|
|
||||||
filename: disk.img
|
|
||||||
size:
|
|
||||||
mpp-format-string: '{rootfs_size}'
|
|
||||||
- type: org.osbuild.mkfs.ext4
|
|
||||||
devices:
|
|
||||||
device:
|
|
||||||
type: org.osbuild.loopback
|
|
||||||
options:
|
|
||||||
filename: disk.img
|
|
||||||
start: 0
|
|
||||||
size:
|
|
||||||
mpp-eval: rootfs_size
|
|
||||||
options:
|
|
||||||
uuid:
|
|
||||||
mpp-eval: rootfs_uuid
|
|
||||||
label: root
|
|
||||||
- type: org.osbuild.copy
|
|
||||||
inputs:
|
|
||||||
tree:
|
|
||||||
type: org.osbuild.tree
|
|
||||||
origin: org.osbuild.pipeline
|
|
||||||
references:
|
|
||||||
- name:rootfs
|
|
||||||
options:
|
|
||||||
paths:
|
|
||||||
- from: input://tree/
|
|
||||||
to: mount://root/
|
|
||||||
devices:
|
|
||||||
root:
|
|
||||||
type: org.osbuild.loopback
|
|
||||||
options:
|
|
||||||
filename: disk.img
|
|
||||||
start: 0
|
|
||||||
size:
|
|
||||||
mpp-eval: rootfs_size
|
|
||||||
mounts:
|
|
||||||
- name: root
|
|
||||||
type: org.osbuild.ext4
|
|
||||||
source: root
|
|
||||||
target: /
|
|
||||||
- name: osbuildvm
|
|
||||||
build: name:build
|
|
||||||
stages:
|
|
||||||
- type: org.osbuild.qemu
|
|
||||||
inputs:
|
|
||||||
image:
|
|
||||||
type: org.osbuild.files
|
|
||||||
origin: org.osbuild.pipeline
|
|
||||||
references:
|
|
||||||
name:image:
|
|
||||||
file: disk.img
|
|
||||||
options:
|
|
||||||
filename: disk.qcow2
|
|
||||||
format:
|
|
||||||
type: qcow2
|
|
||||||
compat: '1.1'
|
|
||||||
- type: org.osbuild.copy
|
|
||||||
inputs:
|
|
||||||
rootfs:
|
|
||||||
type: org.osbuild.tree
|
|
||||||
origin: org.osbuild.pipeline
|
|
||||||
references:
|
|
||||||
- name:rootfs
|
|
||||||
options:
|
|
||||||
paths:
|
|
||||||
- from:
|
|
||||||
mpp-format-string: input://rootfs/usr/lib/modules/{rpms['rootfs']['kernel-core'].evra}/vmlinuz
|
|
||||||
to: tree:///vmlinuz
|
|
||||||
- from:
|
|
||||||
mpp-format-string: input://rootfs/boot/initramfs-{rpms['rootfs']['kernel-core'].evra}.img
|
|
||||||
to: tree:///initramfs
|
|
||||||
- type: org.osbuild.chmod
|
|
||||||
options:
|
|
||||||
items:
|
|
||||||
/initramfs:
|
|
||||||
mode: a+r
|
|
||||||
449
runvm
449
runvm
|
|
@ -1,449 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import atexit
|
|
||||||
import binascii
|
|
||||||
import http.server
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import select
|
|
||||||
import shutil
|
|
||||||
import signal
|
|
||||||
import socket
|
|
||||||
import socketserver
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
import time
|
|
||||||
|
|
||||||
is_verbose = False
|
|
||||||
def print_verbose(s):
|
|
||||||
if is_verbose:
|
|
||||||
print(s)
|
|
||||||
|
|
||||||
def print_error(s):
|
|
||||||
print(s, file=sys.stderr)
|
|
||||||
|
|
||||||
def exit_error(s):
|
|
||||||
print_error(s)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def bool_arg(val):
|
|
||||||
return "on" if val else "off"
|
|
||||||
|
|
||||||
def find_qemu(arch):
|
|
||||||
binary_names = [ f"qemu-system-{arch}" ]
|
|
||||||
if arch == platform.machine():
|
|
||||||
binary_names.append("qemu-kvm")
|
|
||||||
|
|
||||||
for binary_name in binary_names:
|
|
||||||
if "QEMU_BUILD_DIR" in os.environ:
|
|
||||||
p = os.path.join(os.environ["QEMU_BUILD_DIR"], binary_name)
|
|
||||||
if os.path.isfile(p):
|
|
||||||
return p
|
|
||||||
else:
|
|
||||||
exit_error(f"Can't find {binary_name}")
|
|
||||||
|
|
||||||
qemu_bin_dirs = ["/usr/bin", "/usr/libexec"]
|
|
||||||
if "PATH" in os.environ:
|
|
||||||
qemu_bin_dirs += os.environ["PATH"].split(":")
|
|
||||||
|
|
||||||
for d in qemu_bin_dirs:
|
|
||||||
p = os.path.join(d, binary_name)
|
|
||||||
if os.path.isfile(p):
|
|
||||||
return p
|
|
||||||
|
|
||||||
exit_error(f"Can't find {binary_name}")
|
|
||||||
|
|
||||||
def qemu_available_accels(qemu):
|
|
||||||
cmd = qemu + ' -accel help'
|
|
||||||
info = subprocess.check_output(cmd.split(" ")).decode('utf-8')
|
|
||||||
accel_list = []
|
|
||||||
for accel in ('kvm', 'xen', 'hvf', 'hax', 'tcg'):
|
|
||||||
if info.find(accel) > 0:
|
|
||||||
accel_list.append(accel)
|
|
||||||
return accel_list
|
|
||||||
|
|
||||||
def random_id():
|
|
||||||
return binascii.b2a_hex(os.urandom(8)).decode('utf8')
|
|
||||||
|
|
||||||
def machine_id():
|
|
||||||
try:
|
|
||||||
with open("/etc/machine-id", "r") as f:
|
|
||||||
mid = f.read().strip()
|
|
||||||
except FileNotFoundError:
|
|
||||||
if sys.platform == "darwin":
|
|
||||||
# for macOS
|
|
||||||
import plistlib
|
|
||||||
cmd = "ioreg -rd1 -c IOPlatformExpertDevice -a"
|
|
||||||
plist_data = subprocess.check_output(cmd.split(" "))
|
|
||||||
mid = plistlib.loads(plist_data)[0]["IOPlatformUUID"].replace("-","")
|
|
||||||
else:
|
|
||||||
# fallback for the other distros
|
|
||||||
hostname = socket.gethostname()
|
|
||||||
mid = ''.join(hex(ord(x))[2:] for x in (hostname*16)[:16])
|
|
||||||
|
|
||||||
return mid
|
|
||||||
|
|
||||||
def generate_mac_address():
|
|
||||||
# create a new mac address based on our machine id
|
|
||||||
data = machine_id()
|
|
||||||
|
|
||||||
maclst = ["FE"] + [data[x:x+2] for x in range(-12, -2, 2)]
|
|
||||||
return ":".join(maclst)
|
|
||||||
|
|
||||||
def run_http_server(path):
|
|
||||||
writer, reader = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
||||||
child_pid = os.fork()
|
|
||||||
if child_pid == 0:
|
|
||||||
reader.close()
|
|
||||||
|
|
||||||
# Child
|
|
||||||
os.chdir(path)
|
|
||||||
|
|
||||||
class HTTPHandler(http.server.SimpleHTTPRequestHandler):
|
|
||||||
def log_message(self, format, *args):
|
|
||||||
pass # Silence logs
|
|
||||||
|
|
||||||
httpd = socketserver.TCPServer(("127.0.0.1", 0), HTTPHandler)
|
|
||||||
writer.send(str(httpd.server_address[1]).encode("utf8"))
|
|
||||||
writer.close()
|
|
||||||
|
|
||||||
httpd.serve_forever()
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
# Parent
|
|
||||||
writer.close()
|
|
||||||
atexit.register(os.kill, child_pid,signal.SIGTERM)
|
|
||||||
|
|
||||||
http_port = int(reader.recv(128).decode("utf8"))
|
|
||||||
reader.close()
|
|
||||||
|
|
||||||
return http_port
|
|
||||||
|
|
||||||
def find_ovmf(args):
|
|
||||||
dirs = [
|
|
||||||
"~/.local/share/ovmf",
|
|
||||||
"/usr/share/OVMF",
|
|
||||||
"/usr/share/edk2/ovmf/"
|
|
||||||
]
|
|
||||||
if args.ovmf_dir:
|
|
||||||
dirs.append(args.ovmf_dir)
|
|
||||||
|
|
||||||
for d in dirs:
|
|
||||||
path = os.path.expanduser(d)
|
|
||||||
if os.path.exists(path):
|
|
||||||
return path
|
|
||||||
|
|
||||||
raise RuntimeError("Could not find OMVF")
|
|
||||||
|
|
||||||
# location can differ depending on how qemu is installed
|
|
||||||
def find_edk2():
|
|
||||||
dirs = [
|
|
||||||
"/usr/local/share/qemu",
|
|
||||||
"/opt/homebrew/share/qemu"
|
|
||||||
]
|
|
||||||
|
|
||||||
for d in dirs:
|
|
||||||
path = os.path.expanduser(d)
|
|
||||||
if os.path.exists(path):
|
|
||||||
return path
|
|
||||||
|
|
||||||
raise RuntimeError("Could not find edk2 directory")
|
|
||||||
|
|
||||||
def qemu_run_command(qmp_socket_path, command):
|
|
||||||
sock2 = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
||||||
sock2.connect(qmp_socket_path)
|
|
||||||
r = sock2.recv(1024)
|
|
||||||
sock2.send('{"execute":"qmp_capabilities"}\n'.encode("utf8"))
|
|
||||||
r = sock2.recv(1024)
|
|
||||||
sock2.send(f'{command}\n'.encode("utf8"))
|
|
||||||
r = sock2.recv(1024)
|
|
||||||
sock2.close()
|
|
||||||
|
|
||||||
def virtio_serial_connect(virtio_socket_path):
|
|
||||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
||||||
while True:
|
|
||||||
time.sleep(0.1)
|
|
||||||
try:
|
|
||||||
sock.connect(virtio_socket_path)
|
|
||||||
return sock
|
|
||||||
except FileNotFoundError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def available_tcp_port(port_range_from = 1024):
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
||||||
port = port_range_from
|
|
||||||
port_range_to = port_range_from + 32 # limit for retry
|
|
||||||
while port < port_range_to:
|
|
||||||
try:
|
|
||||||
s.bind(('', port))
|
|
||||||
except OSError:
|
|
||||||
port += 1
|
|
||||||
continue
|
|
||||||
break
|
|
||||||
s.close()
|
|
||||||
return port
|
|
||||||
|
|
||||||
class WatchdogCommand:
|
|
||||||
START = 1
|
|
||||||
STOP = 2
|
|
||||||
|
|
||||||
def __init__(self, op, arg = None):
|
|
||||||
self.op = op
|
|
||||||
self.arg = arg
|
|
||||||
|
|
||||||
def parse_watchdog_commands(sock):
|
|
||||||
commands = []
|
|
||||||
data = sock.recv(16).decode("utf8")
|
|
||||||
for l in data.splitlines():
|
|
||||||
if l.startswith("START"):
|
|
||||||
try:
|
|
||||||
arg = int(l[5:])
|
|
||||||
except ValueError:
|
|
||||||
arg = 30 # Default if not specified
|
|
||||||
commands.append( WatchdogCommand(WatchdogCommand.START, arg) )
|
|
||||||
elif l.startswith("STOP"):
|
|
||||||
commands.append( WatchdogCommand(WatchdogCommand.STOP) )
|
|
||||||
else:
|
|
||||||
print_verbose(f"Unsupported watchdog command {l}")
|
|
||||||
return commands
|
|
||||||
|
|
||||||
def run_watchdog(watch_socket_path, qmp_socket_path):
|
|
||||||
sock = virtio_serial_connect(watch_socket_path)
|
|
||||||
|
|
||||||
p = select.poll()
|
|
||||||
p.register(sock, select.POLLIN)
|
|
||||||
|
|
||||||
watchdog_timeout = None
|
|
||||||
watchdog_delay = 30
|
|
||||||
|
|
||||||
while True:
|
|
||||||
timeout = None
|
|
||||||
if watchdog_timeout != None:
|
|
||||||
timeout = max(watchdog_timeout - time.time(), 0) * 1000
|
|
||||||
|
|
||||||
poll_res = p.poll(timeout)
|
|
||||||
|
|
||||||
if len(poll_res) > 0:
|
|
||||||
v = poll_res[0][1]
|
|
||||||
if v & select.POLLHUP:
|
|
||||||
sys.exit(0)
|
|
||||||
commands = parse_watchdog_commands(sock)
|
|
||||||
for cmd in commands:
|
|
||||||
if cmd.op == WatchdogCommand.START:
|
|
||||||
print_verbose(f"Starting watchdog for {cmd.arg} sec")
|
|
||||||
watchdog_timeout = time.time() + cmd.arg
|
|
||||||
if cmd.op == WatchdogCommand.STOP:
|
|
||||||
print_verbose(f"Stopped watchdog")
|
|
||||||
watchdog_timeout = None
|
|
||||||
|
|
||||||
if watchdog_timeout != None and time.time() >= watchdog_timeout:
|
|
||||||
print_verbose(f"Triggering watchdog")
|
|
||||||
qemu_run_command(qmp_socket_path, '{"execute": "system_reset"}')
|
|
||||||
|
|
||||||
# Queue a new timeout in case the next boot fails, until disabled
|
|
||||||
watchdog_timeout = time.time() + watchdog_delay
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
parser = argparse.ArgumentParser(description="Boot virtual machine images")
|
|
||||||
parser.add_argument("--verbose", default=False, action="store_true")
|
|
||||||
parser.add_argument("--arch", default=platform.machine(), action="store",
|
|
||||||
help=f"Arch to run for (default {platform.machine()})")
|
|
||||||
parser.add_argument("--publish-dir", action="store",
|
|
||||||
help=f"Publish the specified directory over http in the vm")
|
|
||||||
parser.add_argument("--memory", default="2G",
|
|
||||||
help=f"Memory size (default 2G)")
|
|
||||||
parser.add_argument("--nographics", default=False, action="store_true",
|
|
||||||
help=f"Run without graphics")
|
|
||||||
parser.add_argument("--watchdog", default=False, action="store_true",
|
|
||||||
help=f"Enable watchdog")
|
|
||||||
parser.add_argument("--tpm2", default=False, action="store_true",
|
|
||||||
help=f"Enable TPM2")
|
|
||||||
parser.add_argument("--snapshot", default=False, action="store_true",
|
|
||||||
help=f"Work on a snapshot of the image")
|
|
||||||
parser.add_argument("--ovmf-dir", action="store",
|
|
||||||
help="Specify directory for OVMF files (Open Virtual Machine Firmware)")
|
|
||||||
parser.add_argument("--secureboot", dest="secureboot", action="store_true", default=False,
|
|
||||||
help="Enable SecureBoot")
|
|
||||||
parser.add_argument("--ssh-port", type=int, default=2222,
|
|
||||||
help="SSH port forwarding to SSH_PORT (default 2222)")
|
|
||||||
parser.add_argument("--cdrom", action="store",
|
|
||||||
help="Specify .iso to load")
|
|
||||||
parser.add_argument("image", type=str, help="The image to boot")
|
|
||||||
parser.add_argument('extra_args', nargs=argparse.REMAINDER, metavar="...", help="extra qemu arguments")
|
|
||||||
|
|
||||||
args = parser.parse_args(sys.argv[1:])
|
|
||||||
|
|
||||||
global is_verbose
|
|
||||||
is_verbose = args.verbose
|
|
||||||
|
|
||||||
# arm64 is an alias for aarch64 on macOS
|
|
||||||
if args.arch == "arm64":
|
|
||||||
args.arch = "aarch64"
|
|
||||||
|
|
||||||
qemu = find_qemu(args.arch)
|
|
||||||
accel_list = qemu_available_accels(qemu)
|
|
||||||
qemu_args = [qemu]
|
|
||||||
|
|
||||||
if args.arch == "x86_64":
|
|
||||||
machine = "q35"
|
|
||||||
default_cpu = "qemu64,+ssse3,+sse4.1,+sse4.2,+popcnt"
|
|
||||||
|
|
||||||
ovmf = find_ovmf(args)
|
|
||||||
if args.secureboot:
|
|
||||||
qemu_args += [
|
|
||||||
"-drive", f"file={ovmf}/OVMF_CODE.secboot.fd,if=pflash,format=raw,unit=0,readonly=on",
|
|
||||||
"-drive", f"file={ovmf}/OVMF_VARS.secboot.fd,if=pflash,format=raw,unit=1,snapshot=on,readonly=off",
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
qemu_args += [
|
|
||||||
"-drive", f"file={ovmf}/OVMF_CODE.fd,if=pflash,format=raw,unit=0,readonly=on",
|
|
||||||
"-drive", f"file={ovmf}/OVMF_VARS.fd,if=pflash,format=raw,unit=1,snapshot=on,readonly=off",
|
|
||||||
]
|
|
||||||
elif args.arch == "aarch64":
|
|
||||||
machine = "virt"
|
|
||||||
default_cpu = "cortex-a57"
|
|
||||||
if sys.platform == "darwin":
|
|
||||||
edk2 = find_edk2()
|
|
||||||
qemu_args += [
|
|
||||||
"-device", "virtio-gpu-pci", # for display
|
|
||||||
"-display", "default,show-cursor=on", # for display
|
|
||||||
"-device", "qemu-xhci", # for keyboard
|
|
||||||
"-device", "usb-kbd", # for keyboard
|
|
||||||
"-device", "usb-tablet", # for mouse
|
|
||||||
"-smp", str(os.cpu_count()), # for max cores
|
|
||||||
"-drive", f"file={edk2}/edk2-aarch64-code.fd,if=pflash,format=raw,unit=0,readonly=on",
|
|
||||||
"-drive", f"file={edk2}/edk2-arm-vars.fd,if=pflash,format=raw,unit=1,snapshot=on,readonly=off"
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
qemu_args += [
|
|
||||||
"-bios", "/usr/share/edk2/aarch64/QEMU_EFI.fd",
|
|
||||||
"-boot", "efi"
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
exit_error(f"unsupported architecture {args.arch}")
|
|
||||||
|
|
||||||
accel_enabled = True
|
|
||||||
if 'kvm' in accel_list and os.path.exists("/dev/kvm"):
|
|
||||||
qemu_args += ['-enable-kvm']
|
|
||||||
elif 'hvf' in accel_list:
|
|
||||||
qemu_args += ['-accel', 'hvf']
|
|
||||||
else:
|
|
||||||
accel_enabled = False
|
|
||||||
print_verbose("Acceleration: off")
|
|
||||||
|
|
||||||
qemu_args += [
|
|
||||||
"-m", str(args.memory),
|
|
||||||
"-machine", machine,
|
|
||||||
"-cpu", "host" if accel_enabled else default_cpu
|
|
||||||
]
|
|
||||||
|
|
||||||
guestfwds=""
|
|
||||||
|
|
||||||
if args.publish_dir:
|
|
||||||
if shutil.which("netcat") is None:
|
|
||||||
print("Command `netcat` not found in path, ignoring publish-dir")
|
|
||||||
else:
|
|
||||||
httpd_port = run_http_server(args.publish_dir)
|
|
||||||
guestfwds = f"guestfwd=tcp:10.0.2.100:80-cmd:netcat 127.0.0.1 {httpd_port},"
|
|
||||||
print_verbose(f"publishing {args.publish_dir} on http://10.0.2.100/")
|
|
||||||
|
|
||||||
portfwd = {
|
|
||||||
available_tcp_port(args.ssh_port): 22
|
|
||||||
}
|
|
||||||
for local, remote in portfwd.items():
|
|
||||||
print_verbose(f"port: {local} → {remote}")
|
|
||||||
|
|
||||||
fwds = [f"hostfwd=tcp::{h}-:{g}" for h, g in portfwd.items()]
|
|
||||||
|
|
||||||
macstr = generate_mac_address()
|
|
||||||
print_verbose(f"MAC: {macstr}")
|
|
||||||
|
|
||||||
qemu_args += [
|
|
||||||
"-device", f"virtio-net-pci,netdev=n0,mac={macstr}",
|
|
||||||
"-netdev", "user,id=n0,net=10.0.2.0/24," + guestfwds + ",".join(fwds),
|
|
||||||
]
|
|
||||||
|
|
||||||
if args.nographics:
|
|
||||||
qemu_args += ["-nographic"]
|
|
||||||
|
|
||||||
runvm_id = random_id()
|
|
||||||
|
|
||||||
tmpdir = tempfile.TemporaryDirectory(prefix=f"runvm-{runvm_id}")
|
|
||||||
|
|
||||||
watchdog_pid = 0
|
|
||||||
if args.watchdog:
|
|
||||||
qmp_socket_path = os.path.join(tmpdir.name, "qmp-socket")
|
|
||||||
watch_socket_path = os.path.join(tmpdir.name, "watch-socket")
|
|
||||||
|
|
||||||
qemu_args += [
|
|
||||||
"-qmp", f"unix:{qmp_socket_path},server=on,wait=off",
|
|
||||||
"-device", "virtio-serial", "-chardev", f"socket,path={watch_socket_path},server=on,wait=off,id=watchdog",
|
|
||||||
"-device", "virtserialport,chardev=watchdog,name=watchdog.0"
|
|
||||||
]
|
|
||||||
|
|
||||||
watchdog_pid = os.fork()
|
|
||||||
if watchdog_pid == 0:
|
|
||||||
run_watchdog(watch_socket_path, qmp_socket_path)
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
if args.tpm2:
|
|
||||||
if shutil.which("swtpm") is None:
|
|
||||||
exit_error("Command `swtpm` not found in path, this is needed for tpm2 support")
|
|
||||||
|
|
||||||
tpm2_socket = os.path.join(tmpdir.name, "tpm-socket")
|
|
||||||
|
|
||||||
if args.snapshot:
|
|
||||||
tpm2_path = os.path.join(tmpdir.name, "tpm2_state")
|
|
||||||
else:
|
|
||||||
tpm2_path = ".tpm2_state"
|
|
||||||
os.makedirs(tpm2_path, exist_ok=True)
|
|
||||||
|
|
||||||
swtpm_args = ["swtpm", "socket", "--tpm2", "--tpmstate", f"dir={tpm2_path}", "--ctrl", f"type=unixio,path={tpm2_socket}" ]
|
|
||||||
res = subprocess.Popen(swtpm_args)
|
|
||||||
|
|
||||||
qemu_args += [
|
|
||||||
"-chardev", f"socket,id=chrtpm,path={tpm2_socket}",
|
|
||||||
"-tpmdev", "emulator,id=tpm0,chardev=chrtpm",
|
|
||||||
"-device", "tpm-tis,tpmdev=tpm0"
|
|
||||||
]
|
|
||||||
|
|
||||||
print_verbose(f"Image: {args.image}")
|
|
||||||
|
|
||||||
if args.image.endswith(".raw"):
|
|
||||||
qemu_args += [
|
|
||||||
"-drive", f"file={args.image},index=0,media=disk,format=raw,if=virtio,snapshot={bool_arg(args.snapshot)}",
|
|
||||||
]
|
|
||||||
else: # assume qcow2
|
|
||||||
qemu_args += [
|
|
||||||
"-drive", f"file={args.image},index=0,media=disk,format=qcow2,if=virtio,snapshot={bool_arg(args.snapshot)}",
|
|
||||||
]
|
|
||||||
|
|
||||||
if args.cdrom:
|
|
||||||
qemu_args += [
|
|
||||||
"-cdrom", args.cdrom,
|
|
||||||
"-boot", "d"
|
|
||||||
]
|
|
||||||
|
|
||||||
qemu_args += args.extra_args
|
|
||||||
|
|
||||||
print_verbose(f"Running: {' '.join(qemu_args)}")
|
|
||||||
|
|
||||||
try:
|
|
||||||
res = subprocess.run(qemu_args, check=False)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
exit_error("Aborted")
|
|
||||||
|
|
||||||
if watchdog_pid:
|
|
||||||
os.kill(watchdog_pid, signal.SIGTERM)
|
|
||||||
|
|
||||||
tmpdir.cleanup()
|
|
||||||
|
|
||||||
return res.returncode
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
#
|
#
|
||||||
# * Knows what target to export based on the extensions.
|
# * Knows what target to export based on the extensions.
|
||||||
# * Knows what the exported filename based on the extensions.
|
# * Knows what the exported filename based on the extensions.
|
||||||
# * Supports building natively or in a VM via osbuildvm.
|
|
||||||
# * Runs only the minimal required commands as root, and
|
# * Runs only the minimal required commands as root, and
|
||||||
# chowns the resulting files to the user
|
# chowns the resulting files to the user
|
||||||
# * Supports exporting an extra ostree commit and pulling that
|
# * Supports exporting an extra ostree commit and pulling that
|
||||||
|
|
@ -26,22 +25,14 @@ EXTENSION="$6"
|
||||||
|
|
||||||
# Map extension => export pipeline name
|
# Map extension => export pipeline name
|
||||||
declare -A EXPORT_BY_EXT
|
declare -A EXPORT_BY_EXT
|
||||||
EXPORT_BY_EXT[img]=image
|
|
||||||
EXPORT_BY_EXT[oci.tar]=container
|
EXPORT_BY_EXT[oci.tar]=container
|
||||||
EXPORT_BY_EXT[qcow2]=qcow2
|
|
||||||
EXPORT_BY_EXT[repo]=ostree-commit
|
EXPORT_BY_EXT[repo]=ostree-commit
|
||||||
EXPORT_BY_EXT[rootfs]=rootfs
|
|
||||||
EXPORT_BY_EXT[ext4]=ext4
|
|
||||||
EXPORT_BY_EXT[tar]=tar
|
EXPORT_BY_EXT[tar]=tar
|
||||||
|
|
||||||
# Map extension to name of exported file by pipeline
|
# Map extension to name of exported file by pipeline
|
||||||
declare -A EXPORT_FILE_BY_EXT
|
declare -A EXPORT_FILE_BY_EXT
|
||||||
EXPORT_FILE_BY_EXT[img]=disk.img
|
|
||||||
EXPORT_FILE_BY_EXT[qcow2]=disk.qcow2
|
|
||||||
EXPORT_FILE_BY_EXT[oci.tar]=container.tar
|
EXPORT_FILE_BY_EXT[oci.tar]=container.tar
|
||||||
EXPORT_FILE_BY_EXT[repo]=repo
|
EXPORT_FILE_BY_EXT[repo]=repo
|
||||||
EXPORT_FILE_BY_EXT[rootfs]=
|
|
||||||
EXPORT_FILE_BY_EXT[ext4]=rootfs.ext4
|
|
||||||
EXPORT_FILE_BY_EXT[tar]=rootfs.tar
|
EXPORT_FILE_BY_EXT[tar]=rootfs.tar
|
||||||
|
|
||||||
EXPORT=${EXPORT_BY_EXT[${EXTENSION}]}
|
EXPORT=${EXPORT_BY_EXT[${EXTENSION}]}
|
||||||
|
|
@ -54,8 +45,7 @@ if [ $ARCH == $HOST_ARCH -a $VM == 0 ]; then
|
||||||
SUDO="sudo"
|
SUDO="sudo"
|
||||||
OSBUILD="sudo osbuild"
|
OSBUILD="sudo osbuild"
|
||||||
else
|
else
|
||||||
SUDO=
|
echo "I don't support building for non-x86 nor in a VM."
|
||||||
OSBUILD="osbuildvm/osbuildvm --arch=$ARCH"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
EXPORT_ARGS="--export $EXPORT"
|
EXPORT_ARGS="--export $EXPORT"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue