Commit: a95b833c
This commit is contained in:
James Pace 2022-08-23 20:51:43 -04:00
commit a8d8515b75
71 changed files with 6908 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
site/
image_output/
osbuild_store/
*~
*.swp

9
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,9 @@
include:
- project: 'redhat/edge/ci-cd/pipe-x/pipelines-as-code'
ref: gitlab-ci
file:
- '/.gitlab/trigger.yml'
stages:
- trigger

9
.gitleaks.toml Normal file
View File

@ -0,0 +1,9 @@
[allowlist]
description = "This repository contains a few passwords for demo accounts, it is fine"
paths = [
'''ignore\.d''',
]
files = [
'''*\.mpp\.json$'''
]

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 AutoBase
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

9
README.md Normal file
View File

@ -0,0 +1,9 @@
# Automotive sample images
This is the git repository for the Automotive SIG sample images. It contains recipes for
building some sample automotive images and information on how to download them.
For more information, visit:
* [Automotive SIG wiki page] (https://wiki.centos.org/SpecialInterestGroup/Automotive)
* [Automotive SIG documentation] (https://sigs.centos.org/automotive)

View File

@ -0,0 +1,43 @@
FROM centos:stream9-development
RUN dnf install -y 'dnf-command(config-manager)' && \
dnf config-manager --set-enabled crb && \
dnf copr enable -y @osbuild/osbuild
RUN dnf install -y \
"@Development Tools" \
# Some convenience packages \
bash-completion \
dnf \
emacs \
less \
strace \
vim \
git \
wget \
# Dependencies for building images \
osbuild-ostree \
osbuild-tools \
# Dependencies to build the kernel's RPM \
rpm-build \
hostname \
openssl-devel \
bc \
binutils-devel \
bpftool \
clang \
dwarves \
gcc-plugin-devel \
libcap-devel \
libcap-ng-devel \
libmnl-devel \
llvm \
net-tools \
numactl-devel \
perl-devel \
python3-devel \
python3-docutils \
rsync && \
dnf clean all
CMD ["/usr/bin/bash"]

107
image-builds.json Normal file
View File

@ -0,0 +1,107 @@
{
"product": "Automotive-sig_images",
"version": 1,
"builds": {
"minimal": {
"manifest": "minimal",
"type": "ostree",
"target": "qemu",
"format" : "qcow2",
"arches": [
"x86_64",
"aarch64"
],
"package-sets": [
"automotive-product"
]
},
"minimal-rpi": {
"manifest": "minimal",
"type": "regular",
"target": "rpi4",
"format" : "img",
"arches": [
"aarch64"
],
"package-sets": [
"cs9"
]
},
"qa": {
"manifest": "qa",
"type": "ostree",
"target": "qemu",
"format" : "qcow2",
"arches": [
"x86_64",
"aarch64"
],
"package-sets": [
"cs9"
]
},
"neptune": {
"manifest": "neptune",
"type": "ostree",
"target": "qemu",
"format" : "qcow2",
"arches": [
"x86_64",
"aarch64"
],
"package-sets": [
"cs9"
]
},
"neptune-rpi": {
"manifest": "neptune",
"type": "regular",
"target": "rpi4",
"format" : "img",
"arches": [
"aarch64"
],
"package-sets": [
"cs9"
]
},
"developer": {
"manifest": "developer",
"type": "regular",
"target": "qemu",
"format" : "qcow2",
"arches": [
"x86_64",
"aarch64"
],
"package-sets": [
"cs9"
]
},
"developer-rpi": {
"manifest": "developer",
"type": "regular",
"target": "rpi4",
"format" : "img",
"arches": [
"aarch64"
],
"package-sets": [
"cs9"
]
},
"container": {
"manifest": "container",
"type": "regular",
"target": "qemu",
"format" : "qcow2",
"arches": [
"x86_64",
"aarch64"
],
"package-sets": [
"cs9"
]
}
}
}

2
osbuild-manifests/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.json
!*.mpp.json

212
osbuild-manifests/Makefile Normal file
View File

@ -0,0 +1,212 @@
NULL=
EMPTY :=
SPACE := $(EMPTY) $(EMPTY)
COMMA := ,
ESCAPEDSPACE := \$(SPACE)
ESCAPEDSPACE_REPLACEMENT := @@SPACE@@
# This is useful to handle space in forech rules
handle-escaped-space = $(subst $(ESCAPEDSPACE),$(ESCAPEDSPACE_REPLACEMENT),$1)
apply-escaped-space = $(subst $(ESCAPEDSPACE_REPLACEMENT),$(SPACE),$1)
HOST_ARCH:=$(shell arch)
ARCHES := x86_64 aarch64
export VM=0
OSBUILD_MPP=osbuild-mpp
DEFINES=
DEFINES_ARGS:=$(foreach def,$(call handle-escaped-space,$(DEFINES)),-D '$(call apply-escaped-space,$(def))')
MPP_ARGS=
export OSBUILD_ARGS=
BUILDDIR=_build
export STOREDIR=$(BUILDDIR)/osbuild_store
export OUTPUTDIR=$(BUILDDIR)/image_output
IMAGEDIR=
DISTROS := $(basename $(basename $(notdir f,$(wildcard distro/*.ipp.yml))))
MANIFESTS := $(wildcard images/*.mpp.yml) $(foreach DIR,$(IMAGEDIR),$(wildcard $(DIR)/*))
EXTRA_MPP_ARGS= # For internal use
ifdef OSTREE_REPO
EXTRA_MPP_ARGS +=-D ostree_parent_refs='$(shell tools/ot-refs $(OSTREE_REPO))'
endif
export CHECKPOINTS=build
IMAGETYPES := regular ostree direct
FORMATS := img qcow2 oci.tar repo rootfs ext4 tar
aarch64_TARGETS := rpi4
COMMON_TARGETS := qemu aws
HOST_TARGETS := $(COMMON_TARGETS) $($(HOST_ARCH)_TARGETS)
ALL_TARGETS := $(COMMON_TARGETS) $(foreach a,$(ARCHES), $($(a)_TARGETS))
manifest-get-name = $(basename $(basename $(notdir $1)))
manifest-get-dir = $(notdir $(patsubst %/,%,$(dir $1)))
image-name-noarch = $1-$3-$(call manifest-get-name,$2)-$4
image-name = $(call image-name-noarch,$1,$2,$3,$4).$5
# variable name for image type
regular_IMAGETYPE := regular
ostree_IMAGETYPE := ostree
direct_IMAGETYPE := directboot
help:
@echo
@echo This makefile is a wrapper around osbuild-mpp and osbuild to easily build images
@echo
@echo To build a raw image, run \"make image.img\", or to build a qcow2 image, run \"make image.qcow2\".
@echo This will build any image from a file called \"image.mpp.yml\" in the \"images\" subdirectory. You can
@echo pass IMAGEDIR=/some/other/path to make also to pick up manifests from an external directory.
@echo
@echo For example, to build a minimal qcow2 image with ostree support targeting qemu, run:
@echo ' make cs9-qemu-minimal-ostree.$(HOST_ARCH).qcow2'
@echo
@echo Other extensions are also supported:
@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 \ \* .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
@echo You can pass variable declarations to osbuild-mpp with the DEFINES make variable.
@echo Multiple defines are separated by space, if you need a space inside a value escape it using \"\\ \".
@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
@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 \ \ 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_downloads: Removes files downloaded during image builds
@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 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
@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 " make cs9-qemu-minimal-ostree@gdb.$(HOST_ARCH).qcow2 DEFINES='extra_rpms=[\"gdb\"]'"
@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 Available image targets \(for $(HOST_ARCH)\) are:
@echo
@$(foreach d, $(DISTROS), $(foreach m, $(MANIFESTS), $(foreach t, $(HOST_TARGETS), $(foreach i,$(IMAGETYPES), echo -e " " $(call image-name,$d,$m,$t,$i,$(HOST_ARCH)).[$(subst $(SPACE),$(COMMA),$(FORMATS))];))))
@echo
# We pre-create all the toplevel dirs, so that they are owned by the user, not root (when created under sudo)
.PHONY: $(BUILDDIR)
$(BUILDDIR):
@mkdir -p $(BUILDDIR)
@mkdir -p $(STOREDIR)/{objects,refs,sources/org.osbuild.files,tmp}
@mkdir -p $(OUTPUTDIR)
# Template rule for producing osbuild json manifest from mpp yaml and image type
# $1 == distro name
# $2 == yaml manifest path
# $3 == Target name
# $4 == Image type
# $5 == Arch
define json-rule
$(BUILDDIR)/$(call image-name,$1,$2,$3,$4,$5).json: $2 $(BUILDDIR)
$(OSBUILD_MPP) -I . -D image_type="\"$($4_IMAGETYPE)\"" -D arch=\"$5\" -D distro_name="\"$1\"" -D target="\"$3\"" $(DEFINES_ARGS) $(EXTRA_MPP_ARGS) $(MPP_ARGS) $$< $$@
.PHONY: $(BUILDDIR)/$(call image-name,$1,$2,$3,$4,$5).json
endef
$(foreach d, $(DISTROS), \
$(foreach m, $(MANIFESTS), \
$(foreach a,$(ARCHES), \
$(foreach t,$(COMMON_TARGETS) $($(a)_TARGETS), \
$(foreach i,$(IMAGETYPES), \
$(eval $(call json-rule,$d,$m,$t,$i,$a)))))))
# Template rule for producing image from json manifest
# $1 == distro name
# $2 == Manifest path
# $3 == Target
# $4 == Image type
# $5 == Arch
# $6 == Export format (extension)
define image-rule
$(call image-name,$1,$2,$3,$4,$5).$6: $(BUILDDIR)/$(call image-name,$1,$2,$3,$4,$5).json
@tools/runosbuild "$$@" "$$<" "$3" "$4" "$5" "$6"
$(call image-name-noarch,$1,$2,$3,$4)@%.$5.$6: $(BUILDDIR)/$(call image-name,$1,$2,$3,$4,$5).json
@tools/runosbuild "$$@" "$$<" "$3" "$4" "$5" "$6"
endef
$(foreach d, $(DISTROS), \
$(foreach m, $(MANIFESTS), \
$(foreach a,$(ARCHES), \
$(foreach t, $(COMMON_TARGETS) $($(a)_TARGETS), \
$(foreach f,$(FORMATS), \
$(foreach i,$(IMAGETYPES), \
$(eval $(call image-rule,$d,$m,$t,$i,$a,$f))))))))
# Rule to pre-generate all manifests
manifests: $(foreach d, $(DISTROS),$(foreach m, $(MANIFESTS), $(foreach a,$(ARCHES), $(foreach t, $(COMMON_TARGETS) $($(a)_TARGETS), $(foreach i,$(IMAGETYPES), $(BUILDDIR)/$(call image-name,$d,$m,$t,$i,$a).json)))))
define packages-rule
.PHONY: packages-$(call manifest-get-name,$1).json
packages-$(call manifest-get-name,$1).json: $1
osbuild-mpp $$< -D arch=\"x86_64\" - | jq -f tools/extract-rpms.jq > $$@.x86_64
osbuild-mpp $$< -D arch=\"aarch64\" - | jq -f tools/extract-rpms.jq > $$@.aarch64
echo 1 | jq --indent 4 -f tools/create-packagelist.jq --slurpfile x86_64 $$@.x86_64 --slurpfile aarch64 $$@.aarch64 > $$@
endef
$(foreach m, $(MANIFESTS), $(eval $(call packages-rule,$m)))
.PHONY: clean_downloads
clean_downloads:
sudo rm -rf _build/osbuild_store/sources/org.osbuild.files/*
.PHONY: clean_caches
clean_caches:
sudo rm -rf $(STOREDIR)/refs/*
sudo rm -rf $(STOREDIR)/refs_tars/*
sudo rm -rf $(STOREDIR)/objects/*
sudo rm -rf $(STOREDIR)/tmp/*
sudo rm -rf $(STOREDIR)/image_output/*
.PHONY: clean
clean: clean_downloads clean_caches
ifeq ($(VM), 1)
VM_SUDO=
VM_OSBUILD="osbuildvm/osbuildvm --arch=$(HOST_ARCH)"
else
VM_SUDO=sudo
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
gzip -f $<

View File

@ -0,0 +1,27 @@
version: '2'
mpp-vars:
distro_name: cs9
distro_version: 9
distro_baseurl: http://mirror.stream.centos.org/9-stream
distro_repos:
- id: baseos
baseurl: $distro_baseurl/BaseOS/$arch/os/
- id: appstream
baseurl: $distro_baseurl/AppStream/$arch/os/
- id: automotive
baseurl: https://buildlogs.centos.org/9-stream/automotive/$arch/packages-main/
- id: autosd
baseurl: https://buildlogs.centos.org/9-stream/autosd/$arch/packages-main/
distro_devel_repos:
- id: crb
baseurl: $distro_baseurl/CRB/$arch/os/
distro_debug_repos:
- id: baseos-debug
baseurl: $distro_baseurl/BaseOS/$arch/debug/tree/
- id: appstream-debug
baseurl: $distro_baseurl/AppStream/$arch/debug/tree/
- id: crb-debug
baseurl: $distro_baseurl/CRB/$arch/debug/tree/
- id: autosd-debug
baseurl: https://buildlogs.centos.org/9-stream/autosd/$arch/packages-main/debug/
distro_module_id: platform:el9

View File

@ -0,0 +1,14 @@
[Unit]
Description=Demo engine service container
Requires=routingmanagerd.socket
[Container]
Image=localhost/auto-apps
Volume=/run/vsomeip:/run/vsomeip
Exec=/usr/bin/engine-service
[Service]
Restart=always
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,19 @@
## custom.conf
# GDM configuration storage
[daemon]
# Uncomment the line below to force the login screen to use Xorg
# WaylandEnable=false
AutomaticLoginEnable=True
AutomaticLogin=neptune
[security]
[xdmcp]
[chooser]
[debug]
# Uncomment the line below to turn on debugging
#Enable=true

View File

@ -0,0 +1,19 @@
## custom.conf
# GDM configuration storage
[daemon]
# Uncomment the line below to force the login screen to use Xorg
WaylandEnable=false
AutomaticLoginEnable=True
AutomaticLogin=neptune
[security]
[xdmcp]
[chooser]
[debug]
# Uncomment the line below to turn on debugging
#Enable=true

View File

@ -0,0 +1,14 @@
[Unit]
Description=Init neptune gdm session conf
ConditionPathExists=!/var/lib/AccountsService/users/neptune
Before=gdm.service
[Service]
Type=service
ExecStart=/bin/sh -c ' \
echo -e "[User]\nSession=neptune-%i\nXSession=neptune-xorg\nPasswordHint=\nIcon=/var/lib/AccountsService/icons/guest\nSystemAccount=false\n" \
> /var/lib/AccountsService/users/neptune'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,15 @@
[Unit]
Description=Demo radio service container
Requires=routingmanagerd.socket
Wants=engine.service
[Container]
Image=localhost/auto-apps
Volume=/run/vsomeip:/run/vsomeip
Exec=/usr/bin/radio-service
[Service]
Restart=always
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,16 @@
[storage]
driver = "overlay"
runroot = "/run/containers/storage"
graphroot = "/var/lib/containers/storage"
[storage.options]
# We add a custom "/usr/share/containers/storage" here to allow readonly in-image containers
additionalimagestores = [
"/usr/share/containers/storage"
]
[storage.options.overlay]
# Nodev for security (default in cs9)
# We use metacopy to allow better pagecache sharing of base-layers (default in cs9)
mountopt = "nodev,metacopy=on"

View File

@ -0,0 +1,79 @@
formatVersion: 1
formatType: am-configuration
---
# basic AM functionality - the builtin apps are in 'apps'.
# installations will go into the standard QStandardPath AppLocalDataLocation
# (e.g. ~/.local/share/Luxoft Sweden AB/Neptune UI) /am hierarchy
applications:
builtinAppsManifestDir: "${CONFIG_PWD}/apps"
installedAppsManifestDir: "${stdpath:AppLocalDataLocation}/neptune3-ui/manifests"
installationDir: "${stdpath:AppLocalDataLocation}/neptune3-ui/apps"
documentDir: "${stdpath:AppLocalDataLocation}/neptune3-ui/docs"
# QML apps will be able to import from modules...
runtimes:
qml:
importPaths: [ "${CONFIG_PWD}/imports_shared" ]
environmentVariables:
QT_PLUGIN_PATH: "${CONFIG_PWD}"
SERVER_CONF_PATH: "${CONFIG_PWD}/server.conf"
native:
importPaths: [ "${CONFIG_PWD}/imports_shared" ]
environmentVariables:
QT_PLUGIN_PATH: "${CONFIG_PWD}"
SERVER_CONF_PATH: "${CONFIG_PWD}/server.conf"
# ... as well as the SystemUI
ui:
fullscreen: yes
style: "${CONFIG_PWD}/styles/neptune"
iconThemeName: "neptune"
iconThemeSearchPaths: [ "${CONFIG_PWD}/imports_shared/assets/icons" ]
mainQml: "${CONFIG_PWD}/Main.qml"
importPaths: [ "${CONFIG_PWD}/imports_shared", "${CONFIG_PWD}/imports_system", "${CONFIG_PWD}/sysui" ]
windowIcon: "${CONFIG_PWD}/imports_shared/assets/icons/neptune/sysui/ic-menu-home.png"
enableTouchEmulation: yes
systemProperties:
public:
showCluster: no
showHUD: no
devMode: yes
enableCursorManagement: no
hardwareVariant: 'high'
#Qt Safe Renderer settings
qsrEnabled: no
qsrServerAddress: '127.0.0.1'
qsrServerPort: '1111'
showSystemAppsInLauncher: no
private:
appStoreServerUrl: 'http://demoappsdeploy.qt.io:8514'
userName: 't'
userPassword: 't'
imei: '112163001487801'
orientation: 'Landscape'
adjustSizesForScreen: yes
# development setup: no security
flags:
noSecurity: yes
noUiWatchdog: yes
# default logging
logging:
rules:
- "*=false"
- "qt.*=false"
- "qt.gamepad*=true"
- "am.*=false"
- "qml*=true"
- "cursor.navigation=false"
- "qt3ds.*=false"
- "shared.com.pelagicore.map.info=false"
- "*.warning=false"
- "*.critical=true"

View File

@ -0,0 +1,7 @@
[Desktop Entry]
Type=Application
Exec=neptune3-ui
StartupNotify=false
Terminal=false
Name[en_US]=neptune3-ui
Comment[en_US]=Launches neptune3-ui on logging in

View File

@ -0,0 +1,7 @@
[Desktop Entry]
Type=Application
Exec=env QT_QPA_PLATFORM=wayland QT_IM_MODULE=qtvirtualkeyboard neptune3-ui
StartupNotify=false
Terminal=false
Name[en_US]=neptune3-ui
Comment[en_US]=Launches neptune3-ui on logging in

View File

@ -0,0 +1,3 @@
[GNOME Session]
Name=Neptune XOrg
RequiredComponents=mutter;neptune3-ui-xorg;

View File

@ -0,0 +1,3 @@
[GNOME Session]
Name=Neptune
RequiredComponents=mutter;neptune3-ui;

View File

@ -0,0 +1,7 @@
[Desktop Entry]
Name=Neptune (Wayland)
Comment=This session logs you into Neptune
Exec=gnome-session --session=neptune
Type=Application
DesktopNames=GNOME
X-GDM-SessionRegisters=true

View File

@ -0,0 +1,7 @@
[Desktop Entry]
Name=Neptune (XOrg)
Comment=This session logs you into Neptune
Exec=gnome-session --session=neptune-xorg
Type=Application
DesktopNames=GNOME
X-GDM-SessionRegisters=true

View File

@ -0,0 +1,121 @@
version: '2'
mpp-vars:
name: container
pipelines:
- mpp-import-pipelines:
path: include/build.ipp.yml
- name: rootfs
build: name:build
stages:
- type: org.osbuild.kernel-cmdline
options:
root_fs_uuid:
mpp-eval: rootfs_uuid
kernel_opts:
mpp-eval: ''' '' .join(kernel_opts)'
- type: org.osbuild.rpm
options:
gpgkeys:
- mpp-eval: centos_gpg_key
- mpp-eval: redhat_gpg_key
disable_dracut: true
inputs:
packages:
type: org.osbuild.files
origin: org.osbuild.source
mpp-depsolve:
architecture: $arch
ignore-weak-deps: true
module-platform-id: $distro_module_id
baseurl: $distro_baseurl/BaseOS/$arch/os/
repos:
mpp-join:
- mpp-eval: distro_repos
- mpp-eval: target_repos
- mpp-eval: extra_repos
- - id: copr-quadlet
baseurl: https://download.copr.fedorainfracloud.org/results/alexl/quadlet/centos-stream-9-$arch/
- - id: copr-sample-apps
baseurl: https://download.copr.fedorainfracloud.org/results/alexl/cs9-sample-images/centos-stream-9-$arch/
packages:
mpp-join:
- mpp-eval: base_rpms
- mpp-eval: image_rpms
- mpp-eval: extra_rpms
- - podman
- quadlet
- curl
- vsomeip3-routingmanager
- auto-apps
excludes:
- dracut-config-rescue
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: storage.conf
path: ../files/storage.conf
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['storage.conf']}
to: tree:///etc/containers/storage.conf
- type: org.osbuild.skopeo
inputs:
images:
type: org.osbuild.containers
origin: org.osbuild.source
mpp-resolve-images:
images:
- source: registry.gitlab.com/centos/automotive/sample-images/demo/auto-apps
tag: latest
name: localhost/auto-apps
options:
destination:
type: containers-storage
storage-path: /usr/share/containers/storage
- type: org.osbuild.mkdir
options:
paths:
- path: /etc/containers/systemd
parents: true
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: radio.container
path: ../files/radio.container
inlinefile2:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: engine.container
path: ../files/engine.container
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['radio.container']}
to: tree:///etc/containers/systemd/radio.container
- from:
mpp-format-string: input://inlinefile2/{embedded['engine.container']}
to: tree:///etc/containers/systemd/engine.container
- type: org.osbuild.locale
options:
language: en_US.UTF-8
- type: org.osbuild.users
options:
users:
guest:
password:
mpp-eval: guest_password
- type: org.osbuild.systemd
options:
enabled_services:
- NetworkManager.service
- rngd.service
- mpp-import-pipelines:
path: include/image.ipp.yml

View File

@ -0,0 +1,114 @@
version: '2'
mpp-vars:
name: developer
pipelines:
- mpp-import-pipelines:
path: include/build.ipp.yml
- name: rootfs
build: name:build
stages:
- type: org.osbuild.kernel-cmdline
options:
root_fs_uuid:
mpp-eval: rootfs_uuid
kernel_opts:
mpp-eval: ''' '' .join(kernel_opts)'
- type: org.osbuild.rpm
options:
gpgkeys:
- mpp-eval: centos_gpg_key
- mpp-eval: redhat_gpg_key
disable_dracut: true
exclude:
docs: true
inputs:
packages:
type: org.osbuild.files
origin: org.osbuild.source
mpp-depsolve:
architecture: $arch
ignore-weak-deps: true
module-platform-id: $distro_module_id
baseurl: $distro_baseurl/BaseOS/$arch/os/
repos:
mpp-join:
- mpp-eval: distro_repos
- mpp-eval: distro_devel_repos
- mpp-eval: target_repos
- mpp-eval: extra_repos
- - id: osbuild
baseurl: https://download.copr.fedorainfracloud.org/results/@osbuild/osbuild/centos-stream-9-$arch
packages:
mpp-join:
- mpp-eval: base_rpms
- mpp-eval: image_rpms
- mpp-eval: extra_rpms
- - "@Development Tools"
# Some convenience packages
- bash-completion
- dnf
- emacs-nox
- less
- strace
- sudo
- vim
- git
- wget
- make
# Dependencies to build RPMs and images
- rpm-build
- hostname
- openssl-devel
- bc
- binutils-devel
- bpftool
- clang
- dwarves
- gcc-plugin-devel
- libcap-devel
- libcap-ng-devel
- libmnl-devel
- llvm
- net-tools
- numactl-devel
- osbuild-ostree
- osbuild-tools
- openssh-clients
- openssh-server
- perl-devel
- python3-devel
- python3-docutils
- rsync
- iputils
- iproute
- qemu-kvm
- fuse-devel
- kernel-rpm-macros
# Container tools
- podman
- buildah
- skopeo
excludes:
- dracut-config-rescue
- type: org.osbuild.locale
options:
language: en_US.UTF-8
- type: org.osbuild.users
options:
users:
guest:
password:
mpp-eval: guest_password
- type: org.osbuild.sshd.config
options:
config:
PermitRootLogin:
mpp-eval: ssh_permit_root_login
- type: org.osbuild.systemd
options:
enabled_services:
- NetworkManager.service
- rngd.service
- sshd.service
- mpp-import-pipelines:
path: include/image.ipp.yml

Binary file not shown.
1 l�i�n�u�x�.�e�f�i�,�L�i�n�u�x�,�i�n�i�t�r�d�=�\�E�F�I�\�L�i�n�u�x�\�i�n�i�t�r�a�m�f�s�.�i�m�g�,�D�i�r�e�c�t� �k�e�r�n�e�l� �b�o�o�t�
2

View File

@ -0,0 +1,67 @@
# This image demontrates how to use an encrypted rootfs
# Due to the use of luks_auto_unlock, the passphrase is copied to the initrd and
# the rootfs uses this to automatically unlock the system on the first boot.
# However, the autosig-sample-tpm-enroll service is also installed, and this
# will replace the passphrase with a TPM based token, meaning that later
# boots are tied to this machine only.
# Remember to pass --tpm2 to runvm when testing this.
version: '2'
mpp-vars:
name: encrypted
use_luks: true
luks_auto_unlock: true
extra_boot_rpms:
- clevis-dracut
pipelines:
- mpp-import-pipelines:
path: include/build.ipp.yml
- name: rootfs
build: name:build
stages:
- type: org.osbuild.kernel-cmdline
options:
root_fs_uuid:
mpp-eval: rootfs_uuid
kernel_opts:
mpp-eval: ''' '' .join(kernel_opts)'
- type: org.osbuild.rpm
options:
gpgkeys:
- mpp-eval: centos_gpg_key
- mpp-eval: redhat_gpg_key
disable_dracut: true
exclude:
docs: true
inputs:
packages:
type: org.osbuild.files
origin: org.osbuild.source
mpp-depsolve:
architecture: $arch
ignore-weak-deps: true
module-platform-id: $distro_module_id
baseurl: $distro_baseurl/BaseOS/$arch/os/
repos:
mpp-join:
- mpp-eval: distro_repos
- mpp-eval: target_repos
- mpp-eval: extra_repos
packages:
mpp-join:
- mpp-eval: base_rpms
- mpp-eval: image_rpms
- mpp-eval: extra_rpms
# Install the tools and service files
- - autosig-sample-tpm-enroll
excludes:
- dracut-config-rescue
- type: org.osbuild.locale
options:
language: en_US.UTF-8
- type: org.osbuild.systemd
options:
enabled_services:
- NetworkManager.service
- rngd.service
- mpp-import-pipelines:
path: include/image.ipp.yml

View File

@ -0,0 +1,125 @@
version: '2'
mpp-vars:
name: gadget
image_size: '3221225472'
pipelines:
- mpp-import-pipelines:
path: include/build.ipp.yml
- name: rootfs
build: name:build
stages:
- type: org.osbuild.kernel-cmdline
options:
root_fs_uuid:
mpp-eval: rootfs_uuid
kernel_opts:
mpp-eval: ''' '' .join(kernel_opts)'
- type: org.osbuild.rpm
options:
gpgkeys:
- mpp-eval: centos_gpg_key
- mpp-eval: redhat_gpg_key
disable_dracut: true
exclude:
docs: true
inputs:
packages:
type: org.osbuild.files
origin: org.osbuild.source
mpp-depsolve:
architecture: $arch
ignore-weak-deps: true
module-platform-id: $distro_module_id
baseurl: $distro_baseurl/BaseOS/$arch/os/
repos:
mpp-join:
- mpp-eval: distro_repos
- mpp-eval: distro_devel_repos
- mpp-eval: target_repos
- mpp-eval: extra_repos
- - id: osbuild
baseurl: https://download.copr.fedorainfracloud.org/results/@osbuild/osbuild/centos-stream-9-$arch
packages:
mpp-join:
- mpp-eval: base_rpms
- mpp-eval: image_rpms
- mpp-eval: extra_rpms
- - "@Development Tools"
- firewalld
# Some convenience packages
- bash-completion
- dnf
- emacs-nox
- less
- strace
- sudo
- vim
- git
- wget
- make
# Dependencies to build RPMs and images
- rpm-build
- hostname
- openssl-devel
- bc
- binutils-devel
- bpftool
- clang
- dwarves
- gcc-plugin-devel
- libcap-devel
- libcap-ng-devel
- libmnl-devel
- llvm
- net-tools
- numactl-devel
- osbuild-ostree
- osbuild-tools
- openssh-clients
- openssh-server
- perl-devel
- python3-devel
- python3-docutils
- rsync
- iputils
- iproute
- qemu-kvm
- fuse-devel
- kernel-rpm-macros
# Container tools
- podman
- buildah
- skopeo
# Gadget
- pi_gadget
excludes:
- dracut-config-rescue
- type: org.osbuild.locale
options:
language: en_US.UTF-8
- type: org.osbuild.users
options:
users:
guest:
password:
mpp-eval: guest_password
- type: org.osbuild.firewall
options:
enabled_services:
- cockpit
- ssh
- type: org.osbuild.sshd.config
options:
config:
PermitRootLogin:
mpp-eval: ssh_permit_root_login
- type: org.osbuild.systemd
options:
enabled_services:
- NetworkManager.service
- firewalld.service
- rngd.service
- sshd.service
- cockpit.socket
- mpp-import-pipelines:
path: include/image.ipp.yml

View File

@ -0,0 +1,62 @@
version: '2'
mpp-vars:
name: minimal
pipelines:
- mpp-import-pipelines:
path: include/build.ipp.yml
- name: rootfs
build: name:build
stages:
- type: org.osbuild.kernel-cmdline
options:
root_fs_uuid:
mpp-eval: rootfs_uuid
kernel_opts:
mpp-eval: ''' '' .join(kernel_opts)'
- type: org.osbuild.rpm
options:
gpgkeys:
- mpp-eval: centos_gpg_key
- mpp-eval: redhat_gpg_key
disable_dracut: true
exclude:
docs: true
inputs:
packages:
type: org.osbuild.files
origin: org.osbuild.source
mpp-depsolve:
architecture: $arch
ignore-weak-deps: true
module-platform-id: $distro_module_id
baseurl: $distro_baseurl/BaseOS/$arch/os/
repos:
mpp-join:
- mpp-eval: distro_repos
- mpp-eval: target_repos
- mpp-eval: extra_repos
- []
packages:
mpp-join:
- mpp-eval: base_rpms
- mpp-eval: image_rpms
- mpp-eval: extra_rpms
- []
excludes:
- dracut-config-rescue
- type: org.osbuild.locale
options:
language: en_US.UTF-8
- type: org.osbuild.users
options:
users:
guest:
password:
mpp-eval: guest_password
- type: org.osbuild.systemd
options:
enabled_services:
- NetworkManager.service
- rngd.service
- mpp-import-pipelines:
path: include/image.ipp.yml

View File

@ -0,0 +1,206 @@
version: '2'
mpp-vars:
name: neptune
display_server: wayland
pipelines:
- mpp-import-pipelines:
path: include/build.ipp.yml
- name: rootfs
build: name:build
stages:
- type: org.osbuild.kernel-cmdline
options:
root_fs_uuid:
mpp-eval: rootfs_uuid
kernel_opts:
mpp-eval: ''' '' .join(kernel_opts)'
- type: org.osbuild.rpm
options:
gpgkeys:
- mpp-eval: centos_gpg_key
- mpp-eval: redhat_gpg_key
disable_dracut: true
exclude:
docs: true
inputs:
packages:
type: org.osbuild.files
origin: org.osbuild.source
mpp-depsolve:
architecture: $arch
ignore-weak-deps: true
module-platform-id: $distro_module_id
baseurl: $distro_baseurl/BaseOS/$arch/os/
repos:
mpp-join:
- mpp-eval: distro_repos
- mpp-eval: target_repos
- mpp-eval: extra_repos
- - id: copr-neptune
baseurl: https://download.copr.fedorainfracloud.org/results/pingou/qtappmanager-fedora/centos-stream-9-$arch/
packages:
mpp-join:
- mpp-eval: base_rpms
- mpp-eval: image_rpms
- mpp-eval: extra_rpms
- - dnf
- firewalld
- gdm
- gnome-control-center
- gnome-session-xsession
- gnome-shell
- gnome-terminal
- langpacks-en
- neptune3-ui
- openssh-clients
- openssh-server
- plymouth
- polkit
- sudo
- xorg-x11-drv-fbdev
excludes:
- dracut-config-rescue
- gnome-tour
- type: org.osbuild.locale
options:
language: en_US.UTF-8
- type: org.osbuild.users
options:
users:
guest:
password:
mpp-eval: guest_password
neptune:
password: ''
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: custom.conf
path: ../files/etc/gdm/custom-$display_server.conf
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['custom.conf']}
to: tree:///etc/gdm/custom.conf
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: init-neptune-session@.service
path: ../files/etc/systemd/system/init-neptune-session@.service
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['init-neptune-session@.service']}
to: tree:///etc/systemd/system/init-neptune-session@.service
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: neptune-wayland.desktop
path: ../files/usr/share/wayland-sessions/neptune-wayland.desktop
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['neptune-wayland.desktop']}
to: tree:///usr/share/wayland-sessions/neptune-wayland.desktop
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: neptune-xorg.desktop
path: ../files/usr/share/xsessions/neptune-xorg.desktop
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['neptune-xorg.desktop']}
to: tree:///usr/share/xsessions/neptune-xorg.desktop
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: neptune.session
path: ../files/usr/share/gnome-session/sessions/neptune.session
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['neptune.session']}
to: tree:///usr/share/gnome-session/sessions/neptune.session
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: neptune-xorg.session
path: ../files/usr/share/gnome-session/sessions/neptune-xorg.session
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['neptune-xorg.session']}
to: tree:///usr/share/gnome-session/sessions/neptune-xorg.session
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: am-config-neptune.yaml
path: ../files/usr/lib64/neptune3/am-config-neptune.yaml
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['am-config-neptune.yaml']}
to: tree:///usr/lib64/neptune3/am-config-neptune.yaml
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: neptune3-ui.desktop
path: ../files/usr/share/applications/neptune3-ui.desktop
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['neptune3-ui.desktop']}
to: tree:///usr/share/applications/neptune3-ui.desktop
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: neptune3-ui-xorg.desktop
path: ../files/usr/share/applications/neptune3-ui-xorg.desktop
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['neptune3-ui-xorg.desktop']}
to: tree:///usr/share/applications/neptune3-ui-xorg.desktop
- type: org.osbuild.sshd.config
options:
config:
PermitRootLogin:
mpp-eval: ssh_permit_root_login
- type: org.osbuild.systemd
options:
enabled_services:
- NetworkManager.service
- firewalld.service
- rngd.service
- sshd.service
- mpp-eval: "'init-neptune-session@wayland.service' if display_server == 'wayland' else 'init-neptune-session@xorg.service'"
- mpp-import-pipelines:
path: include/image.ipp.yml

View File

@ -0,0 +1,46 @@
version: '2'
mpp-vars:
name: soafee
pipelines:
- mpp-import-pipelines:
path: include/build.ipp.yml
- name: rootfs
build: name:build
stages:
- type: org.osbuild.kernel-cmdline
options:
root_fs_uuid:
mpp-eval: rootfs_uuid
kernel_opts:
mpp-eval: ''' '' .join(kernel_opts)'
- type: org.osbuild.rpm
options:
gpgkeys:
- mpp-eval: centos_gpg_key
- mpp-eval: redhat_gpg_key
disable_dracut: true
inputs:
packages:
type: org.osbuild.files
origin: org.osbuild.source
mpp-depsolve:
architecture: $arch
ignore-weak-deps: true
module-platform-id: $distro_module_id
baseurl: $distro_baseurl/BaseOS/$arch/os/
repos:
mpp-join:
- mpp-eval: distro_repos
- mpp-eval: target_repos
- mpp-eval: extra_repos
packages:
mpp-join:
- mpp-eval: base_rpms
- mpp-eval: image_rpms
- mpp-eval: extra_rpms
- - podman
- curl
excludes:
- dracut-config-rescue
- mpp-import-pipelines:
path: include/image.ipp.yml

View File

@ -0,0 +1,79 @@
version: '2'
mpp-vars:
name: upgrade-demo
pipelines:
- mpp-import-pipelines:
path: include/build.ipp.yml
- name: rootfs
build: name:build
stages:
- type: org.osbuild.kernel-cmdline
options:
root_fs_uuid:
mpp-eval: rootfs_uuid
kernel_opts:
mpp-eval: ''' '' .join(kernel_opts)'
- type: org.osbuild.rpm
options:
gpgkeys:
- mpp-eval: centos_gpg_key
- mpp-eval: redhat_gpg_key
disable_dracut: true
exclude:
docs: true
inputs:
packages:
type: org.osbuild.files
origin: org.osbuild.source
mpp-depsolve:
architecture: $arch
ignore-weak-deps: true
module-platform-id: $distro_module_id
baseurl: $distro_baseurl/BaseOS/$arch/os/
repos:
mpp-join:
- mpp-eval: distro_repos
- mpp-eval: target_repos
- mpp-eval: extra_repos
packages:
mpp-join:
- mpp-eval: base_rpms
- mpp-eval: image_rpms
- mpp-eval: extra_rpms
# Install the watchdog tools and service files
- - autosig-sample-watchdog
- autosig-sample-staticdelta
excludes:
- dracut-config-rescue
# Make sure we only try a failed boot once before rollback (default is 3)
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: greenboot.conf
text: "GREENBOOT_MAX_BOOT_ATTEMPTS=1\n"
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['greenboot.conf']}
to: tree:///etc/greenboot/greenboot.conf
- type: org.osbuild.locale
options:
language: en_US.UTF-8
- type: org.osbuild.systemd
options:
enabled_services:
- NetworkManager.service
- rngd.service
# Enable the watchdog ostree/greenboot integration
- watchdog-ostree-start.service
- watchdog-ostree-stop.service
# Work around bug for now (https://github.com/coreos/rpm-ostree/issues/3554)
- type: org.osbuild.mkdir
options:
paths:
- path: /var/lib/containers
- mpp-import-pipelines:
path: include/image.ipp.yml

View File

@ -0,0 +1,45 @@
version: '2'
mpp-vars:
efiarch: aa64
boot_rpms:
mpp-join:
- mpp-eval: boot_rpms
- - grub2-efi-aa64
base_rpms:
mpp-join:
- mpp-eval: base_rpms
- []
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-aa64
- grub2-efi-aa64-cdboot
- shim-aa64
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

View File

@ -0,0 +1,46 @@
version: '2'
mpp-vars:
efiarch: x64
boot_rpms:
mpp-join:
- mpp-eval: boot_rpms
- - grub2-efi-x64
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
- 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

View File

@ -0,0 +1,38 @@
version: '2'
mpp-vars:
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:
- mpp-import-pipelines:
path: distro/$distro_name.ipp.yml
- mpp-import-pipelines:
path: defaults.ipp.yml
- mpp-import-pipelines:
path: target-$target.ipp.yml
- mpp-import-pipeline:
path: build-$arch.ipp.yml
id: build
runner: org.osbuild.centos9

View File

@ -0,0 +1,315 @@
version: '2'
mpp-vars:
default_target: qemu
default_image_type: ostree
default_ostree_ref: $distro_name/$arch/$target-$name
default_ostree_os_version: $distro_version
default_osname: centos
default_uefi_vendor: centos
default_kernel_rpm: kernel-automotive
default_linux_firmware_rpm: linux-firmware-automotive
default_partition_label: gpt
default_extra_rpms: []
default_extra_build_rpms: []
default_extra_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:
mpp-eval: locals().get('static_uuids', True)
default_rootfs_uuid:
mpp-eval: ('76a22bf4-f153-4541-b6c7-0332c0dfaeac' if static_uuids else str(__import__('uuid').uuid4()))
default_bootfs_uuid:
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_luks_uuid:
mpp-eval: ('aedd1eef-f24e-425e-a9f3-bb5a1c996a95' if static_uuids else str(__import__('uuid').uuid4()))
default_use_luks: false
use_luks:
mpp-eval: locals().get('use_luks', default_use_luks)
default_luks_use_integrity: false
default_luks_auto_unlock: false
luks_auto_unlock:
mpp-eval: locals().get('luks_auto_unlock', default_luks_auto_unlock)
default_use_efi_runtime: true
default_kernel_opts:
- console=tty0
- console=ttyS0
- systemd.log_target=console
- systemd.journald.forward_to_console=1
default_dracut_add_modules:
- base
- bash
- dracut-systemd
- fs-lib
- i18n
- kernel-modules
- kernel-modules-extra
- rootfs-block
- shutdown
- systemd
- systemd-initrd
- terminfo
- udev-rules
- usrmount
default_dracut_omit_modules:
- mpp-if: not use_luks
then: dm
- lunmask
- mdraid
- memstrack
- nss-softokn
- nvdimm
- resume
- terminfo
default_dracut_filesystems:
- vfat
- ext4
default_dracut_add_drivers: []
default_dracut_install: []
default_ostree_repo_url: http://10.0.2.100/
default_ostree_remote_name: auto-sig
default_luks_passphrase: password
target:
mpp-eval: locals().get('target', default_target)
image_type:
mpp-eval: locals().get('image_type', default_image_type)
kernel_rpm:
mpp-eval: locals().get('kernel_rpm', default_kernel_rpm)
linux_firmware_rpm:
mpp-eval: locals().get('linux_firmware_rpm', default_linux_firmware_rpm)
ostree_ref:
mpp-eval: locals().get('ostree_ref', default_ostree_ref)
ostree_os_version:
mpp-eval: locals().get('ostree_os_version', default_ostree_os_version)
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:
mpp-eval: locals().get('extra_rpms', default_extra_rpms)
extra_build_rpms:
mpp-eval: locals().get('extra_build_rpms', default_extra_build_rpms)
extra_repos:
mpp-eval: locals().get('extra_repos', default_extra_repos)
target_repos:
mpp-eval: locals().get('target_repos', default_target_repos)
image_size:
mpp-eval: locals().get('image_size', default_image_size)
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)
luks_uuid:
mpp-eval: locals().get('luks_uuid', default_luks_uuid)
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:
mpp-eval: locals().get('dracut_add_modules', default_dracut_add_modules)
dracut_omit_modules:
mpp-eval: locals().get('dracut_omit_modules', default_dracut_omit_modules)
dracut_filesystems:
mpp-eval: locals().get('dracut_filesystems', default_dracut_filesystems)
dracut_add_drivers:
mpp-eval: locals().get('dracut_add_drivers', default_dracut_add_drivers)
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:
mpp-eval: locals().get('ostree_repo_url', default_ostree_repo_url)
ostree_remote_name:
mpp-eval: locals().get('ostree_remote_name', default_ostree_remote_name)
luks_passphrase:
mpp-eval: locals().get('luks_passphrase', default_luks_passphrase)
luks_use_integrity:
mpp-eval: locals().get('luks_use_integrity', default_luks_use_integrity)
use_efi_runtime:
mpp-eval: locals().get('use_efi_runtime', default_use_efi_runtime)
kernel_loglevel:
mpp-eval: locals().get('kernel_loglevel', default_kernel_loglevel)
default_target_stages: []
target_stages:
mpp-eval: locals().get('target_stages', default_target_stages)
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-----
redhat_gpg_key: |
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBErgSTsBEACh2A4b0O9t+vzC9VrVtL1AKvUWi9OPCjkvR7Xd8DtJxeeMZ5eF
0HtzIG58qDRybwUe89FZprB1ffuUKzdE+HcL3FbNWSSOXVjZIersdXyH3NvnLLLF
0DNRB2ix3bXG9Rh/RXpFsNxDp2CEMdUvbYCzE79K1EnUTVh1L0Of023FtPSZXX0c
u7Pb5DI5lX5YeoXO6RoodrIGYJsVBQWnrWw4xNTconUfNPk0EGZtEnzvH2zyPoJh
XGF+Ncu9XwbalnYde10OCvSWAZ5zTCpoLMTvQjWpbCdWXJzCm6G+/hx9upke546H
5IjtYm4dTIVTnc3wvDiODgBKRzOl9rEOCIgOuGtDxRxcQkjrC+xvg5Vkqn7vBUyW
9pHedOU+PoF3DGOM+dqv+eNKBvh9YF9ugFAQBkcG7viZgvGEMGGUpzNgN7XnS1gj
/DPo9mZESOYnKceve2tIC87p2hqjrxOHuI7fkZYeNIcAoa83rBltFXaBDYhWAKS1
PcXS1/7JzP0ky7d0L6Xbu/If5kqWQpKwUInXtySRkuraVfuK3Bpa+X1XecWi24JY
HVtlNX025xx1ewVzGNCTlWn1skQN2OOoQTV4C8/qFpTW6DTWYurd4+fE0OJFJZQF
buhfXYwmRlVOgN5i77NTIJZJQfYFj38c/Iv5vZBPokO6mffrOTv3MHWVgQARAQAB
tDNSZWQgSGF0LCBJbmMuIChyZWxlYXNlIGtleSAyKSA8c2VjdXJpdHlAcmVkaGF0
LmNvbT6JAjYEEwECACAFAkrgSTsCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAK
CRAZni+R/UMdUWzpD/9s5SFR/ZF3yjY5VLUFLMXIKUztNN3oc45fyLdTI3+UClKC
2tEruzYjqNHhqAEXa2sN1fMrsuKec61Ll2NfvJjkLKDvgVIh7kM7aslNYVOP6BTf
C/JJ7/ufz3UZmyViH/WDl+AYdgk3JqCIO5w5ryrC9IyBzYv2m0HqYbWfphY3uHw5
un3ndLJcu8+BGP5F+ONQEGl+DRH58Il9Jp3HwbRa7dvkPgEhfFR+1hI+Btta2C7E
0/2NKzCxZw7Lx3PBRcU92YKyaEihfy/aQKZCAuyfKiMvsmzs+4poIX7I9NQCJpyE
IGfINoZ7VxqHwRn/d5mw2MZTJjbzSf+Um9YJyA0iEEyD6qjriWQRbuxpQXmlAJbh
8okZ4gbVFv1F8MzK+4R8VvWJ0XxgtikSo72fHjwha7MAjqFnOq6eo6fEC/75g3NL
Ght5VdpGuHk0vbdENHMC8wS99e5qXGNDued3hlTavDMlEAHl34q2H9nakTGRF5Ki
JUfNh3DVRGhg8cMIti21njiRh7gyFI2OccATY7bBSr79JhuNwelHuxLrCFpY7V25
OFktl15jZJaMxuQBqYdBgSay2G0U6D1+7VsWufpzd/Abx1/c3oi9ZaJvW22kAggq
dzdA27UUYjWvx42w9menJwh/0jeQcTecIUd0d0rFcw/c1pvgMMl/Q73yzKgKYw==
=zbHE
-----END PGP PUBLIC KEY BLOCK-----
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBFsy23UBEACUKSphFEIEvNpy68VeW4Dt6qv+mU6am9a2AAl10JANLj1oqWX+
oYk3en1S6cVe2qehSL5DGVa3HMUZkP3dtbD4SgzXzxPodebPcr4+0QNWigkUisri
XGL5SCEcOP30zDhZvg+4mpO2jMi7Kc1DLPzBBkgppcX91wa0L1pQzBcvYMPyV/Dh
KbQHR75WdkP6OA2JXdfC94nxYq+2e0iPqC1hCP3Elh+YnSkOkrawDPmoB1g4+ft/
xsiVGVy/W0ekXmgvYEHt6si6Y8NwXgnTMqxeSXQ9YUgVIbTpsxHQKGy76T5lMlWX
4LCOmEVomBJg1SqF6yi9Vu8TeNThaDqT4/DddYInd0OO69s0kGIXalVgGYiW2HOD
x2q5R1VGCoJxXomz+EbOXY+HpKPOHAjU0DB9MxbU3S248LQ69nIB5uxysy0PSco1
sdZ8sxRNQ9Dw6on0Nowx5m6Thefzs5iK3dnPGBqHTT43DHbnWc2scjQFG+eZhe98
Ell/kb6vpBoY4bG9/wCG9qu7jj9Z+BceCNKeHllbezVLCU/Hswivr7h2dnaEFvPD
O4GqiWiwOF06XaBMVgxA8p2HRw0KtXqOpZk+o+sUvdPjsBw42BB96A1yFX4jgFNA
PyZYnEUdP6OOv9HSjnl7k/iEkvHq/jGYMMojixlvXpGXhnt5jNyc4GSUJQARAQAB
tDNSZWQgSGF0LCBJbmMuIChhdXhpbGlhcnkga2V5KSA8c2VjdXJpdHlAcmVkaGF0
LmNvbT6JAjkEEwECACMFAlsy23UCGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIX
gAAKCRD3b2bD1AgnknqOD/9fB2ASuG2aJIiap4kK58R+RmOVM4qgclAnaG57+vjI
nKvyfV3NH/keplGNRxwqHekfPCqvkpABwhdGEXIE8ILqnPewIMr6PZNZWNJynZ9i
eSMzVuCG7jDoGyQ5/6B0f6xeBtTeBDiRl7+Alehet1twuGL1BJUYG0QuLgcEzkaE
/gkuumeVcazLzz7L12D22nMk66GxmgXfqS5zcbqOAuZwaA6VgSEgFdV2X2JU79zS
BQJXv7NKc+nDXFG7M7EHjY3Rma3HXkDbkT8bzh9tJV7Z7TlpT829pStWQyoxKCVq
sEX8WsSapTKA3P9YkYCwLShgZu4HKRFvHMaIasSIZWzLu+RZH/4yyHOhj0QB7XMY
eHQ6fGSbtJ+K6SrpHOOsKQNAJ0hVbSrnA1cr5+2SDfel1RfYt0W9FA6DoH/S5gAR
dzT1u44QVwwp3U+eFpHphFy//uzxNMtCjjdkpzhYYhOCLNkDrlRPb+bcoL/6ePSr
016PA7eEnuC305YU1Ml2WcCn7wQV8x90o33klJmEkWtXh3X39vYtI4nCPIvZn1eP
Vy+F+wWt4vN2b8oOdlzc2paOembbCo2B+Wapv5Y9peBvlbsDSgqtJABfK8KQq/jK
Yl3h5elIa1I3uNfczeHOnf1enLOUOlq630yeM/yHizz99G1g+z/guMh5+x/OHraW
iA==
=+Gxh
-----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:
- mpp-if: use_luks
then: cryptsetup
- dnf
- dosfstools
- e2fsprogs
- efibootmgr
- grub2-tools
- grub2-tools-minimal
- mpp-if: use_luks
then: lvm2
- policycoreutils
- python3-iniparse
- python3
- qemu-img
- rpm-ostree
- selinux-policy-targeted
- skopeo
- systemd
- tar
- xz
boot_rpms:
- dracut-config-generic
- grub2-tools-minimal
- $kernel_rpm
base_rpms:
- $linux_firmware_rpm
- NetworkManager
- audit
- chrony
- e2fsprogs
- efibootmgr
- glibc-langpack-en
- hostname
- passwd
- rng-tools
- rootfiles
- selinux-policy-targeted
- systemd-udev
- mpp-if: use_luks
then: lvm2

View File

@ -0,0 +1,180 @@
version: '2'
mpp-vars:
image_rpms:
mpp-join:
- mpp-eval: locals().get('extra_image_rpms', [])
- []
pipelines:
- name: kernel-tree
build: name:build
stages:
- type: org.osbuild.kernel-cmdline
options:
root_fs_uuid:
mpp-eval: rootfs_uuid
kernel_opts:
mpp-eval: ''' '' .join(kernel_opts)'
- type: org.osbuild.rpm
options:
gpgkeys:
- mpp-eval: centos_gpg_key
- mpp-eval: redhat_gpg_key
disable_dracut: true
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-join:
- mpp-eval: distro_repos
- - id: cs9-shim
baseurl: https://download.copr.fedorainfracloud.org/results/alexl/cs9-shim/fedora-35-$arch/
packages:
mpp-join:
- mpp-eval: base_rpms
- mpp-eval: boot_rpms
- mpp-eval: locals().get('extra_boot_rpms', [])
- - shim-unsigned-$efiarch
excludes:
- dracut-config-rescue
- type: org.osbuild.mkdir
options:
paths:
- path: /boot/efi/EFI/Linux
parents: true
- type: org.osbuild.copy
inputs:
bootcsv:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: directboot.csv
path: directboot.csv
extra-tree:
type: org.osbuild.tree
origin: org.osbuild.pipeline
references:
- name:extra-tree-content
options:
paths:
mpp-join:
- - from:
mpp-format-string: input://bootcsv/{embedded['directboot.csv']}
to: tree:///boot/efi/EFI/Linux/boot.csv
- mpp-eval: extra_tree_content
- type: org.osbuild.dracut
options:
kernel:
- mpp-eval: rpms['kernel-tree'][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
extra:
- /boot/efi/EFI/Linux/initramfs.img
- --kernel-cmdline
- mpp-format-string: root=UUID={rootfs_uuid} {' ' .join(kernel_opts)}
- 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
extra-tree:
type: org.osbuild.tree
origin: org.osbuild.pipeline
references:
- name:extra-tree-content
options:
paths:
mpp-join:
- - from: input://tree/
to: tree:///
- mpp-eval: extra_tree_content
- type: org.osbuild.copy
inputs:
kernel:
type: org.osbuild.tree
origin: org.osbuild.pipeline
references:
- name:kernel-tree
options:
paths:
- from: input://kernel/lib/modules
to: tree:///lib/
- from: input://kernel/boot/efi/EFI/BOOT
to: tree:////boot/efi/EFI/
- from: input://kernel/boot/efi/EFI/Linux
to: tree:////boot/efi/EFI/
- type: org.osbuild.copy
inputs:
kernel:
type: org.osbuild.tree
origin: org.osbuild.pipeline
references:
- name:kernel-tree
options:
paths:
- from: input://kernel/lib/modules
to: tree:///lib/
- from: input://kernel/boot/efi/EFI/BOOT
to: tree:////boot/efi/EFI/
- from: input://kernel/boot/efi/EFI/Linux
to: tree:////boot/efi/EFI/
- mpp-if: arch == 'aarch64'
then:
type: org.osbuild.gunzip
inputs:
file:
type: org.osbuild.files
origin: org.osbuild.pipeline
references:
name:kernel-tree:
file:
mpp-format-string: boot/vmlinuz-{rpms['kernel-tree'][kernel_rpm + '-core'].evra}
options:
path: /boot/efi/EFI/Linux/linux.efi
else:
type: org.osbuild.copy
inputs:
kernel:
type: org.osbuild.tree
origin: org.osbuild.pipeline
references:
- name:kernel-tree
options:
paths:
- from:
mpp-format-string: input://kernel/boot/vmlinuz-{rpms['kernel-tree'][kernel_rpm + '-core'].evra}
to: tree:///boot/efi/EFI/Linux/linux.efi
- 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.fstab
options:
filesystems:
mpp-eval: fstab
- type: org.osbuild.selinux
options:
file_contexts: etc/selinux/targeted/contexts/files/file_contexts

View File

@ -0,0 +1,214 @@
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', [])
- - nss-altfiles
- greenboot
- greenboot-grub2
- greenboot-reboot
- greenboot-status
- greenboot-rpm-ostree-grub2
- polkit # Needed by rpm-ostree upgrade (until fix for https://github.com/coreos/rpm-ostree/issues/3554 is in)
pipelines:
- name: ostree-tree
build: name:build
stages:
mpp-join:
- - type: org.osbuild.copy
inputs:
tree:
type: org.osbuild.tree
origin: org.osbuild.pipeline
references:
- name:rootfs
extra-tree:
type: org.osbuild.tree
origin: org.osbuild.pipeline
references:
- name:extra-tree-content
options:
paths:
mpp-join:
- - from: input://tree/
to: tree:///
- mpp-eval: extra_tree_content
- type: org.osbuild.systemd
options:
enabled_services:
- greenboot-grub2-set-counter.service
- greenboot-grub2-set-success.service
- greenboot-healthcheck.service
- greenboot-rpm-ostree-grub2-check-fallback.service
- greenboot-status.service
- greenboot-task-runner.service
- mpp-eval: target_stages
- - type: org.osbuild.selinux
options:
file_contexts: etc/selinux/targeted/contexts/files/file_contexts
- type: org.osbuild.ostree.preptree
options:
etc_group_members:
- wheel
- docker
initramfs-args:
- mpp-if: dracut_add_modules
then: "--add"
- mpp-if: dracut_add_modules
then:
mpp-eval: "' '.join(dracut_add_modules)"
- mpp-if: dracut_omit_modules
then: "--omit"
- mpp-if: dracut_omit_modules
then:
mpp-eval: "' '.join(dracut_omit_modules)"
- mpp-if: dracut_filesystems
then: "--filesystems"
- mpp-if: dracut_filesystems
then:
mpp-eval: "' '.join(dracut_filesystems)"
- mpp-if: dracut_add_drivers
then: "--add-drivers"
- mpp-if: dracut_add_drivers
then:
mpp-eval: "' '.join(dracut_add_drivers)"
- mpp-if: dracut_install
then: "--install"
- mpp-if: dracut_install
then:
mpp-eval: "' '.join(dracut_install)"
- name: ostree-commit
build: name:build
stages:
- type: org.osbuild.ostree.init
options:
path: /repo
- type: org.osbuild.ostree.commit
inputs:
tree:
type: org.osbuild.tree
origin: org.osbuild.pipeline
references:
- name:ostree-tree
options:
ref:
mpp-eval: ostree_ref
os_version:
mpp-eval: ostree_os_version
parent:
mpp-if: ostree_ref in locals().get("ostree_parent_refs", {})
then:
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: true
install: true
legacy: false
write_defaults: false
greenboot: true

View File

@ -0,0 +1,79 @@
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
extra-tree:
type: org.osbuild.tree
origin: org.osbuild.pipeline
references:
- name:extra-tree-content
options:
paths:
mpp-join:
- - from: input://tree/
to: tree:///
- mpp-eval: extra_tree_content
- 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: true
legacy: false
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

View File

@ -0,0 +1,413 @@
version: '2'
mpp-vars:
extra_tree_content:
- mpp-if: use_luks and luks_auto_unlock
then:
from: input://extra-tree/luks-key
to: tree:///usr/.auto-unlock-key
dracut_install:
mpp-join:
- mpp-eval: dracut_install
- mpp-if: use_luks and luks_auto_unlock
then:
- /usr/.auto-unlock-key
kernel_opts:
mpp-join:
- - ro
- loglevel=$kernel_loglevel
- mpp-if: use_efi_runtime
then: efi=runtime
- mpp-eval: kernel_opts
- mpp-if: use_luks
then:
- rd.luks.uuid=$luks_uuid
- rd.luks.options=discard
- mpp-if: luks_auto_unlock
then: rd.luks.key=$luks_uuid=/usr/.auto-unlock-key
pipelines:
# Some variables need to be written to files, do that here
- name: extra-tree-content
build: name:build
stages:
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: luks-key
text: $luks_passphrase
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['luks-key']}
to: tree:///luks-key
- mpp-import-pipelines:
path: image-$image_type.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
- mpp-if: use_luks
then:
type: org.osbuild.luks2.format
devices:
device:
type: org.osbuild.loopback
options:
filename: disk.img
start:
mpp-eval: image.layout['root'].start
size:
mpp-eval: image.layout['root'].size
lock: true
options:
passphrase:
mpp-eval: luks_passphrase
uuid:
mpp-eval: luks_uuid
label: luks-rootfs
pbkdf:
method: argon2i
memory: 32
parallelism: 1
iterations: 4
integrity:
mpp-if: luks_use_integrity
then: hmac-sha256
- mpp-if: use_luks
then:
type: org.osbuild.lvm2.create
devices:
luks:
type: org.osbuild.loopback
options:
filename: disk.img
start:
mpp-eval: image.layout['root'].start
size:
mpp-eval: image.layout['root'].size
device:
type: org.osbuild.luks2
parent: luks
options:
passphrase:
mpp-eval: luks_passphrase
options:
volumes:
- name: root
extents: 100%FREE
- type: org.osbuild.mkfs.ext4
devices:
luks:
mpp-if: use_luks
then:
type: org.osbuild.loopback
options:
filename: disk.img
start:
mpp-eval: image.layout['root'].start
size:
mpp-eval: image.layout['root'].size
lvm:
mpp-if: use_luks
then:
type: org.osbuild.luks2
parent: luks
options:
passphrase:
mpp-eval: luks_passphrase
device:
mpp-if: use_luks
then:
type: org.osbuild.lvm2.lv
parent: lvm
options:
volume: root
else:
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
extra-tree:
mpp-if: "'extra_image_source_' + image_type in locals()"
then:
type: org.osbuild.tree
origin: org.osbuild.pipeline
references:
- mpp-format-string: "name:{locals().get('extra_image_source_' + image_type)}"
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:
mpp-if: use_luks
then:
type: org.osbuild.lvm2.lv
parent: root-luks
options:
volume: root
else:
type: org.osbuild.loopback
options:
filename: disk.img
start:
mpp-eval: image.layout['root'].start
size:
mpp-eval: image.layout['root'].size
root-raw:
mpp-if: use_luks
then:
type: org.osbuild.loopback
options:
filename: disk.img
start:
mpp-eval: image.layout['root'].start
size:
mpp-eval: image.layout['root'].size
root-luks:
mpp-if: use_luks
then:
type: org.osbuild.luks2
parent: root-raw
options:
passphrase:
mpp-eval: luks_passphrase
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
- mpp-if: use_luks
then:
type: org.osbuild.lvm2.metadata
devices:
luks:
type: org.osbuild.loopback
options:
filename: disk.img
start:
mpp-eval: image.layout['root'].start
size:
mpp-eval: image.layout['root'].size
device:
type: org.osbuild.luks2
parent: luks
options:
passphrase:
mpp-eval: luks_passphrase
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
build: name:build
stages:
- type: org.osbuild.oci-archive
inputs:
base:
type: org.osbuild.tree
origin: org.osbuild.pipeline
references:
- name:rootfs
options:
filename: container.tar
architecture: $arch
config:
Cmd:
- "/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
build: name:build
stages:
- type: org.osbuild.tar
inputs:
tree:
type: org.osbuild.tree
origin: org.osbuild.pipeline
references:
- name:rootfs
options:
filename: rootfs.tar
root-node: omit

View File

@ -0,0 +1,76 @@
version: '2'
mpp-vars:
extra_image_rpms:
- openssh-server
- sudo
- tuned
- cloud-init
- cloud-utils-growpart
- gdisk
- NetworkManager-cloud-setup
- rsync
- qemu-guest-agent
extra_build_rpms:
- python3-pyyaml
target_stages:
- type: org.osbuild.sshd.config
options:
config:
PermitRootLogin:
mpp-eval: ssh_permit_root_login
- type: org.osbuild.systemd
options:
enabled_services:
- sshd
- NetworkManager
- nm-cloud-setup.service
- nm-cloud-setup.timer
- cloud-init
- cloud-init-local
- cloud-config
- cloud-final
- reboot.target
- tuned
default_target: multi-user.target
- type: org.osbuild.systemd-logind
options:
filename: 00-getty-fixes.conf
config:
Login:
NAutoVTs: 0
- type: org.osbuild.cloud-init
options:
filename: 00-cs-default-user.cfg
config:
system_info:
default_user:
name: ec2-user
- type: org.osbuild.systemd.unit
options:
unit: nm-cloud-setup.service
dropin: 10-enable-for-ec2.conf
config:
Service:
Environment: NM_CLOUD_SETUP_EC2=yes
- type: org.osbuild.locale
options:
language: en_US.UTF-8
- type: org.osbuild.timezone
options:
zone: UTC
- type: org.osbuild.chrony
options:
servers:
- hostname: 169.254.169.123
prefer: true
iburst: true
minpoll: 4
maxpoll: 4
leapsectz: ""
- type: org.osbuild.keymap
options:
keymap: us
x11-keymap:
layouts:
- us
pipelines: []

View File

@ -0,0 +1,2 @@
version: '2'
pipelines: []

View File

@ -0,0 +1,69 @@
version: '2'
mpp-vars:
extra_image_source_ostree: ostree-tree
extra_image_copy_ostree:
- from: input://extra-tree/lib/ostree-boot/efi/
to: mount://root/boot/efi/
rpi4_use_uefi: false
extra_image_source_directboot: rpi-direct-files
extra_image_copy_directboot:
mpp-if: not rpi4_use_uefi
then:
- from: input://extra-tree/
to: mount://root/boot/efi/
else: []
extra_image_rpms:
- pi4-firmware-blob
- pi_resize
dracut_add_drivers:
mpp-join:
- mpp-eval: dracut_add_drivers
- - bcm2835
- bcm2835-mailbox
- sdhci
partition_label: dos
target_repos:
- id: cs9-rpi4-fw
baseurl: https://download.copr.fedorainfracloud.org/results/alexl/cs9-rpi4-fw/centos-stream-9-aarch64/
rpi4_direct_cmdline_txt: console=serial0,115200 console=tty1 modprobe.blacklist=vc4
rpi4_direct_config_txt: |
kernel=EFI/Linux/linux.efi
initramfs EFI/Linux/initramfs.img followkernel
arm_64bit=1
enable_uart=1
uart_2ndstage=1
dtoverlay=miniuart-bt
display_auto_detect=1
dtoverlay=vc4-kms-v3d-pi4
max_framebuffers=2
disable_overscan=1
pipelines:
- name: rpi-direct-files
runner: org.osbuild.centos9
stages:
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: config.txt
text: $rpi4_direct_config_txt
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['config.txt']}
to: tree:///config.txt
- type: org.osbuild.copy
inputs:
inlinefile:
type: org.osbuild.files
origin: org.osbuild.source
mpp-embed:
id: cmdline.txt
text: $rpi4_direct_cmdline_txt
options:
paths:
- from:
mpp-format-string: input://inlinefile/{embedded['cmdline.txt']}
to: tree:///cmdline.txt

View File

@ -0,0 +1,394 @@
#!/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()

View File

@ -0,0 +1,229 @@
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
osbuild-manifests/runvm Executable file
View File

@ -0,0 +1,449 @@
#!/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())

View File

@ -0,0 +1,18 @@
def intersect(x;y):
( (x|unique) + (y|unique) | sort) as $sorted
| reduce range(1; $sorted|length) as $i
([];
if $sorted[$i] == $sorted[$i-1] then . + [$sorted[$i]] else . end) ;
def difference($a; $b):
($a | unique) - $b;
{
cs9: {
common: ((intersect($aarch64;$x86_64)) | sort_by(ascii_downcase)),
arch: {
x86_64: (($x86_64 - $aarch64) | sort_by(ascii_downcase)),
aarch64: (($aarch64 - $x86_64) | sort_by(ascii_downcase))
}
}
}

View File

@ -0,0 +1,88 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: MIT-0
set -e
[ "$DEBUG" == 'true' ] && set -x
ARGC=$#
if [ $ARGC -ne 3 ]; then
echo "USAGE: $(basename $0) <Image Path> <S3 Bucket Name> <AMI Image Size in GB>"
exit 1
fi
IMAGE_FILE_PATH=$1
IMPORT_BUCKET_NAME=$2
AMI_DISK_SIZE_GB=$3
declare -A ARCHS_MAP=( ["x86_64"]="x86_64" ["aarch64"]="arm64")
IMAGE_NAME="$(basename -- ${IMAGE_FILE_PATH})"
AMI_NAME="${IMAGE_NAME%.*}"
IMAGE_ARCH="${AMI_NAME##*.}"
TMPDIR=$(mktemp -d)
IMAGE_IMPORT_JSON_FILE="${TMPDIR}/image-import.json"
AMI_REGISTER_JSON_FILE="${TMPDIR}/register-ami.json"
aws s3 cp "${IMAGE_FILE_PATH}" "s3://${IMPORT_BUCKET_NAME}"
cat <<EOF > "${IMAGE_IMPORT_JSON_FILE}"
{
"Description": "CentOS Stream 9 with Container support",
"Format": "RAW",
"UserBucket": {
"S3Bucket": "${IMPORT_BUCKET_NAME}",
"S3Key": "${IMAGE_NAME}"
}
}
EOF
echo "Importing image file into snapshot "
IMPORT_TASK_ID=$(aws ec2 import-snapshot --disk-container "file://${IMAGE_IMPORT_JSON_FILE}" | jq -r '.ImportTaskId')
IMPORT_STATUS=$(aws ec2 describe-import-snapshot-tasks --import-task-ids $IMPORT_TASK_ID | jq -r '.ImportSnapshotTasks[].SnapshotTaskDetail.Status')
x=0
while [ "$IMPORT_STATUS" = "active" ] && [ $x -lt 120 ]
do
IMPORT_STATUS=$(aws ec2 describe-import-snapshot-tasks --import-task-ids $IMPORT_TASK_ID | jq -r '.ImportSnapshotTasks[].SnapshotTaskDetail.Status')
IMPORT_STATUS_MSG=$(aws ec2 describe-import-snapshot-tasks --import-task-ids $IMPORT_TASK_ID | jq -r '.ImportSnapshotTasks[].SnapshotTaskDetail.StatusMessage')
echo "Import Status: ${IMPORT_STATUS} / ${IMPORT_STATUS_MSG}"
x=$(( $x + 1 ))
sleep 15
done
if [ $x -eq 120 ]; then
echo "ERROR: Import task taking too long, exiting..."; exit 1;
elif [ "$IMPORT_STATUS" = "completed" ]; then
echo "Import completed Successfully"
else
echo "Import Failed, exiting"; exit 2;
fi
SNAPSHOT_ID=$(aws ec2 describe-import-snapshot-tasks --import-task-ids $IMPORT_TASK_ID | jq -r '.ImportSnapshotTasks[].SnapshotTaskDetail.SnapshotId')
aws ec2 wait snapshot-completed --snapshot-ids $SNAPSHOT_ID
echo "Registering AMI with Snapshot $SNAPSHOT_ID"
cat <<EOF > "${AMI_REGISTER_JSON_FILE}"
{
"Architecture": "${ARCHS_MAP[$IMAGE_ARCH]}",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/sda1",
"Ebs": {
"DeleteOnTermination": true,
"SnapshotId": "${SNAPSHOT_ID}",
"VolumeSize": ${AMI_DISK_SIZE_GB},
"VolumeType": "gp2"
}
}
],
"Description": "CS9 image with container support for ${IMAGE_ARCH}",
"RootDeviceName": "/dev/sda1",
"BootMode": "uefi",
"VirtualizationType": "hvm",
"EnaSupport": true
}
EOF
aws ec2 register-image --name ${AMI_NAME} --cli-input-json="file://${AMI_REGISTER_JSON_FILE}"
echo "AMI name: "${AMI_NAME}

View File

@ -0,0 +1,19 @@
def basenames:
.path | split("/") | last;
def parseURL:
capture("^((?<scheme>[^:/?#]+):)?(//(?<authority>(?<domain>[^/?#:]*)(:(?<port>[0-9]*))?))?(?<path>[^?#]*)(\\?(?<query>([^#]*)))?(#(?<fragment>(.*)))?");
def splitRPM:
capture("(?<name>(.*))\\.(?<arch>[a-zA-Z0-9_]+).rpm");
def manifestUrls:
.sources["org.osbuild.curl"].items | to_entries[] | .value | parseURL;
def urlsToRpms:
basenames | splitRPM;
def mergeArches:
reduce .[] as $item ({}; .[$item.arch][$item.name] = true) | with_entries(.value = (.value | keys));
manifestUrls | select(.domain == "mirror.stream.centos.org") | urlsToRpms | .name

View File

@ -0,0 +1,50 @@
#!/usr/bin/bash
# Generates single-file from-scratch and delta update files for all or some of the
# refs in an OSTree repo.
#
# To use it run "generate-deltas REPODIR DESTDIR" which will look at all the refs in the
# repo and make updates to the latest version putting them in the DESTDIR directory.
# To apply these on a live system, do something like:
# $ ostree static-delta apply-offline cs9-x86_64-qemu-upgrade-demo-79da0b2f1b119e99137eaef9680fae9820a9edcd5cac4f6d7c23279498c578f6.update
# $ rpm-ostree rebase 79da0b2f1b119e99137eaef9680fae9820a9edcd5cac4f6d7c23279498c578f6
if [ "$#" -lt 2 ]; then
echo "Usage generate-deltas REPODIR DESTDIR [REFS..]"
exit 1
fi
REPO=$1
DIR=$2
shift 2
if [ "$#" -gt 0 ]; then
REFS="$@"
else
REFS=$(ostree --repo=$REPO refs)
fi
mkdir -p $DIR
NUM_DELTAS=3
for REF in $REFS; do
REF_AS_FILE=$(echo $REF | sed "s%/%-%g" )
HEAD=$(ostree --repo=$REPO rev-parse $REF)
# Generate full update for HEAD:
echo Generating non-delta update for $REF commit $HEAD
ostree static-delta generate --repo=$REPO --inline --min-fallback-size=0 --empty --filename=$DIR/$REF_AS_FILE-$HEAD.update $HEAD
# Generate deltas to HEAD from up to the last 3 parents
PARENT=$HEAD
for i in seq $NUM_DELTAS; do
if ! PARENT=$(ostree --repo=$REPO rev-parse $PARENT^ 2>/dev/null); then
break;
fi
echo Generating delta update for $REF commit $HEAD from commit $PARENT
ostree static-delta generate --repo=$REPO --inline --min-fallback-size=0 --from=$PARENT --filename=$DIR/$REF_AS_FILE-$PARENT-$HEAD.update $HEAD
done
done

22
osbuild-manifests/tools/ot-refs Executable file
View File

@ -0,0 +1,22 @@
#!/bin/bash
# This is a helper used by the makefile to handle the OSTREE_REPO mpp
# support. It creates a json dict mapping all the refs in the repo
# (if it exists) to the latest commit. This is then passed to osbuild-mpp
# as the ostree_parent_refs variable that is used by the manifests to pick
# the right parent commit.
REPOPATH=$1
FIRST=1
echo -n "{"
if test -d $REPOPATH; then
for ref in $(ostree refs --repo=$REPOPATH); do
if [ $FIRST == 1 ]; then
FIRST=0
else
echo -n ,
fi
echo -n \"$ref\":\"$(ostree rev-parse --repo=$REPOPATH $ref)\"
done
fi
echo -n "}"

View File

@ -0,0 +1,106 @@
#!/bin/bash
# This is a helper for the makefile rule to build a particular image
# from the preprocessed json manifest. It is a shellscript rather
# than just some make lines because some of the complexities just
# are painful to do in make.
#
# Features:
#
# * Knows what target to export 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
# chowns the resulting files to the user
# * Supports exporting an extra ostree commit and pulling that
# into an existing repo.
set -e
DEST="$1"
JSON="$2"
TARGET="$3"
IMAGETYPE="$4"
ARCH="$5"
EXTENSION="$6"
# Map extension => export pipeline name
declare -A EXPORT_BY_EXT
EXPORT_BY_EXT[img]=image
EXPORT_BY_EXT[oci.tar]=container
EXPORT_BY_EXT[qcow2]=qcow2
EXPORT_BY_EXT[repo]=ostree-commit
EXPORT_BY_EXT[rootfs]=rootfs
EXPORT_BY_EXT[ext4]=ext4
EXPORT_BY_EXT[tar]=tar
# Map extension to name of exported file by pipeline
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[repo]=repo
EXPORT_FILE_BY_EXT[rootfs]=
EXPORT_FILE_BY_EXT[ext4]=rootfs.ext4
EXPORT_FILE_BY_EXT[tar]=rootfs.tar
EXPORT=${EXPORT_BY_EXT[${EXTENSION}]}
EXPORT_FILE=${EXPORT_FILE_BY_EXT[${EXTENSION}]}
HOST_ARCH=$(arch)
CURRENT_UIDGID="$(id -u):$(id -g)"
if [ $ARCH == $HOST_ARCH -a $VM == 0 ]; then
SUDO="sudo"
OSBUILD="sudo osbuild"
else
SUDO=
OSBUILD="osbuildvm/osbuildvm --arch=$ARCH"
fi
EXPORT_ARGS="--export $EXPORT"
CHECKPOINT_ARGS=
for CP in $CHECKPOINTS; do
CHECKPOINT_ARGS="${CHECKPOINT_ARGS} --checkpoint ${CP}"
done
CHOWNARGS=
if [ $EXTENSION == repo ]; then
CHOWNARGS=-R # Chown entire repo dir as it doesn't care about permissions
fi
EXPORTDIRS=$OUTPUTDIR/$EXPORT
# If OSTREE_REPO is set, and we're building an image that has an
# ostree commit, then we also export that commit to the repo specified
# by OSTREE_REPO.
ALSO_EXPORT_OSTREE=0
if [ "$OSTREE_REPO" != "" -a "$IMAGETYPE" == "ostree" ]; then
ALSO_EXPORT_OSTREE=1
if [ $EXPORT != "ostree-commit" ]; then
EXPORT_ARGS="$EXPORT_ARGS --export ostree-commit"
EXPORTDIRS="$EXPORTDIRS $OUTPUTDIR/ostree-commit"
fi
# Ensure we have a repo to export to
ostree init --repo=$OSTREE_REPO --mode archive
fi
set -x
$SUDO rm -rf $EXPORTDIRS
mkdir -p $EXPORTDIRS # Own export dirs by user, not root
$OSBUILD $CHECKPOINT_ARGS --store $STOREDIR --output-directory $OUTPUTDIR $EXPORT_ARGS $OSBUILD_ARGS $JSON
if [ $ALSO_EXPORT_OSTREE == "1" ]; then
ostree pull-local --repo=$OSTREE_REPO $OUTPUTDIR/ostree-commit/repo
fi
# Extract and chown exported file
rm -rf $DEST
$SUDO chown $CHOWNARGS $CURRENT_UIDGID $OUTPUTDIR/$EXPORT/$EXPORT_FILE
$SUDO mv $OUTPUTDIR/$EXPORT/$EXPORT_FILE $DEST
$SUDO rm -rf $EXPORTDIRS

View File

@ -0,0 +1,602 @@
{
"cs9": {
"common": [
"acl-2.3.1-3.el9",
"alsa-lib-1.2.7.2-1.el9",
"alternatives-1.20-2.el9",
"annobin-10.73-3.el9",
"audit-3.0.7-103.el9",
"audit-libs-3.0.7-103.el9",
"autoconf-2.69-38.el9",
"automake-1.16.2-6.el9",
"basesystem-11-13.el9",
"bash-5.1.8-4.el9",
"bc-1.07.1-14.el9",
"binutils-2.35.2-24.el9",
"binutils-gold-2.35.2-24.el9",
"bison-3.7.4-5.el9",
"boost-1.75.0-8.el9",
"boost-atomic-1.75.0-8.el9",
"boost-chrono-1.75.0-8.el9",
"boost-container-1.75.0-8.el9",
"boost-context-1.75.0-8.el9",
"boost-contract-1.75.0-8.el9",
"boost-coroutine-1.75.0-8.el9",
"boost-date-time-1.75.0-8.el9",
"boost-devel-1.75.0-8.el9",
"boost-fiber-1.75.0-8.el9",
"boost-filesystem-1.75.0-8.el9",
"boost-graph-1.75.0-8.el9",
"boost-iostreams-1.75.0-8.el9",
"boost-locale-1.75.0-8.el9",
"boost-log-1.75.0-8.el9",
"boost-math-1.75.0-8.el9",
"boost-nowide-1.75.0-8.el9",
"boost-numpy3-1.75.0-8.el9",
"boost-program-options-1.75.0-8.el9",
"boost-python3-1.75.0-8.el9",
"boost-random-1.75.0-8.el9",
"boost-regex-1.75.0-8.el9",
"boost-serialization-1.75.0-8.el9",
"boost-stacktrace-1.75.0-8.el9",
"boost-system-1.75.0-8.el9",
"boost-test-1.75.0-8.el9",
"boost-thread-1.75.0-8.el9",
"boost-timer-1.75.0-8.el9",
"boost-type_erasure-1.75.0-8.el9",
"boost-wave-1.75.0-8.el9",
"brotli-1.0.9-6.el9",
"brotli-devel-1.0.9-6.el9",
"bubblewrap-0.4.1-6.el9",
"bzip2-1.0.8-8.el9",
"bzip2-devel-1.0.8-8.el9",
"bzip2-libs-1.0.8-8.el9",
"ca-certificates-2022.2.54-90.0.el9",
"cairo-1.17.4-7.el9",
"centos-gpg-keys-9.0-12.el9",
"centos-stream-release-9.0-12.el9",
"centos-stream-repos-9.0-12.el9",
"checkpolicy-3.4-1.el9",
"chrony-4.2-1.el9",
"clevis-18-102.el9",
"cmake-3.20.2-7.el9",
"cmake-data-3.20.2-7.el9",
"cmake-filesystem-3.20.2-7.el9",
"cmake-rpm-macros-3.20.2-7.el9",
"conmon-2.1.2-2.el9",
"container-selinux-2.189.0-1.el9",
"containers-common-1-39.el9",
"coreutils-8.32-32.el9",
"coreutils-common-8.32-32.el9",
"cpio-2.13-16.el9",
"cpp-11.3.1-2.1.el9",
"cracklib-2.9.6-27.el9",
"cracklib-dicts-2.9.6-27.el9",
"criu-3.17-2.el9",
"criu-libs-3.17-2.el9",
"crun-1.4.5-2.el9",
"crypto-policies-20220427-1.gitb2323a1.el9",
"cryptsetup-2.4.3-4.el9",
"cryptsetup-libs-2.4.3-4.el9",
"curl-7.76.1-18.el9",
"cyrus-sasl-lib-2.1.27-20.el9",
"dbus-1.12.20-5.el9",
"dbus-broker-28-5.el9",
"dbus-common-1.12.20-5.el9",
"dbus-libs-1.12.20-5.el9",
"dejavu-sans-fonts-2.37-18.el9",
"device-mapper-1.02.185-1.el9",
"device-mapper-event-1.02.185-1.el9",
"device-mapper-event-libs-1.02.185-1.el9",
"device-mapper-libs-1.02.185-1.el9",
"device-mapper-persistent-data-0.9.0-13.el9",
"dhcp-client-4.4.2-17.b1.el9",
"dhcp-common-4.4.2-17.b1.el9",
"diffutils-3.7-12.el9",
"dnf-4.12.0-2.el9",
"dnf-data-4.12.0-2.el9",
"dosfstools-4.2-3.el9",
"dracut-057-10.git20220721.el9",
"dracut-config-generic-057-10.git20220721.el9",
"dwarves-1.22-1.el9",
"dwz-0.14-3.el9",
"e2fsprogs-1.46.5-3.el9",
"e2fsprogs-libs-1.46.5-3.el9",
"ed-1.14.2-12.el9",
"efi-filesystem-4-8.el9",
"efi-srpm-macros-4-8.el9",
"efibootmgr-16-12.el9",
"efivar-libs-38-2.el9",
"elfutils-0.187-5.el9",
"elfutils-debuginfod-client-0.187-5.el9",
"elfutils-default-yama-scope-0.187-5.el9",
"elfutils-devel-0.187-5.el9",
"elfutils-libelf-0.187-5.el9",
"elfutils-libelf-devel-0.187-5.el9",
"elfutils-libs-0.187-5.el9",
"emacs-common-27.1-3.el9",
"emacs-filesystem-27.1-3.el9",
"emacs-nox-27.1-3.el9",
"expat-2.4.7-1.el9",
"file-5.39-8.el9",
"file-libs-5.39-8.el9",
"filesystem-3.16-2.el9",
"findutils-4.8.0-5.el9",
"flex-2.6.4-9.el9",
"flexiblas-3.0.4-8.el9",
"flexiblas-netlib-3.0.4-8.el9",
"flexiblas-openblas-openmp-3.0.4-8.el9",
"fontconfig-2.14.0-1.el9",
"fonts-filesystem-2.0.5-7.el9.1",
"fonts-srpm-macros-2.0.5-7.el9.1",
"freetype-2.10.4-9.el9",
"freetype-devel-2.10.4-9.el9",
"fuse-2.9.9-15.el9",
"fuse-common-3.10.2-5.el9",
"fuse-libs-2.9.9-15.el9",
"fuse-overlayfs-1.9-1.el9",
"fuse3-3.10.2-5.el9",
"fuse3-libs-3.10.2-5.el9",
"fwupd-1.5.9-3.el9",
"gawk-5.1.0-6.el9",
"gawk-all-langpacks-5.1.0-6.el9",
"gcc-11.3.1-2.1.el9",
"gcc-c++-11.3.1-2.1.el9",
"gcc-plugin-annobin-11.3.1-2.1.el9",
"gcc-plugin-devel-11.3.1-2.1.el9",
"gdb-10.2-10.el9",
"gdb-headless-10.2-10.el9",
"gdbm-libs-1.19-4.el9",
"gettext-0.21-7.el9",
"gettext-libs-0.21-7.el9",
"ghc-srpm-macros-1.5.0-6.el9",
"git-2.31.1-2.el9.2",
"git-core-2.31.1-2.el9.2",
"git-core-doc-2.31.1-2.el9.2",
"glib2-2.68.4-5.el9",
"glib2-devel-2.68.4-5.el9",
"glibc-2.34-39.el9",
"glibc-common-2.34-39.el9",
"glibc-devel-2.34-39.el9",
"glibc-gconv-extra-2.34-39.el9",
"glibc-langpack-en-2.34-39.el9",
"gmp-6.2.0-10.el9",
"gmp-c++-6.2.0-10.el9",
"gmp-devel-6.2.0-10.el9",
"gnupg2-2.3.3-1.el9",
"gnutls-3.7.3-10.el9",
"go-srpm-macros-3.0.9-9.el9",
"gpgme-1.15.1-6.el9",
"gpm-libs-1.20.7-29.el9",
"graphite2-1.3.14-9.el9",
"graphite2-devel-1.3.14-9.el9",
"greenboot-0.14.0-3.el9",
"grep-3.6-5.el9",
"groff-base-1.22.4-10.el9",
"grub2-common-2.06-38.el9",
"grub2-tools-2.06-38.el9",
"grub2-tools-minimal-2.06-38.el9",
"gzip-1.12-1.el9",
"harfbuzz-2.7.4-8.el9",
"harfbuzz-devel-2.7.4-8.el9",
"harfbuzz-icu-2.7.4-8.el9",
"hostapd-2.10-1.el9",
"hostname-3.23-6.el9",
"ima-evm-utils-1.4-4.el9",
"info-6.7-15.el9",
"inih-49-6.el9",
"initscripts-service-10.11.4-1.el9",
"ipcalc-1.0.0-5.el9",
"iproute-5.18.0-1.el9",
"iptables-libs-1.8.8-2.el9",
"iptables-nft-1.8.8-2.el9",
"iputils-20210202-7.el9",
"jansson-2.14-1.el9",
"jbigkit-libs-2.1-23.el9",
"jitterentropy-3.4.0-1.el9",
"jose-11-3.el9",
"jq-1.6-9.el9",
"json-c-0.14-11.el9",
"json-glib-1.6.6-1.el9",
"kbd-2.4.0-8.el9",
"kbd-misc-2.4.0-8.el9",
"kernel-automotive-5.14.0-133.95.el9s",
"kernel-automotive-core-5.14.0-133.95.el9s",
"kernel-automotive-modules-5.14.0-133.95.el9s",
"kernel-headers-5.14.0-134.el9",
"kernel-srpm-macros-1.0-11.el9",
"keyutils-libs-1.6.1-4.el9",
"kmod-28-7.el9",
"kmod-libs-28-7.el9",
"kpartx-0.8.7-10.el9",
"krb5-libs-1.19.1-22.el9",
"langpacks-core-font-en-3.0-16.el9",
"less-590-1.el9",
"libacl-2.3.1-3.el9",
"libaio-0.3.111-13.el9",
"libarchive-3.5.3-3.el9",
"libassuan-2.5.5-3.el9",
"libattr-2.5.1-3.el9",
"libbabeltrace-1.5.8-10.el9",
"libblkid-2.37.4-3.el9",
"libblkid-devel-2.37.4-3.el9",
"libbpf-0.6.0-1.el9",
"libbrotli-1.0.9-6.el9",
"libcap-2.48-8.el9",
"libcap-ng-0.8.2-7.el9",
"libcbor-0.7.0-5.el9",
"libcom_err-1.46.5-3.el9",
"libcomps-0.1.18-1.el9",
"libcurl-7.76.1-18.el9",
"libcurl-devel-7.76.1-18.el9",
"libdb-5.3.28-53.el9",
"libdnf-0.67.0-1.el9",
"libdwarves1-1.22-1.el9",
"libeconf-0.4.1-2.el9",
"libedit-3.1-37.20210216cvs.el9",
"libestr-0.1.11-4.el9",
"libevent-2.1.12-6.el9",
"libfastjson-0.99.9-3.el9",
"libfdisk-2.37.4-3.el9",
"libffi-3.4.2-7.el9",
"libffi-devel-3.4.2-7.el9",
"libfido2-1.6.0-7.el9",
"libgcab1-1.4-6.el9",
"libgcc-11.3.1-2.1.el9",
"libgcrypt-1.10.0-4.el9",
"libgfortran-11.3.1-2.1.el9",
"libgomp-11.3.1-2.1.el9",
"libgpg-error-1.42-5.el9",
"libgudev-237-1.el9",
"libgusb-0.3.6-3.el9",
"libibverbs-37.2-1.el9",
"libicu-67.1-9.el9",
"libicu-devel-67.1-9.el9",
"libidn2-2.3.0-7.el9",
"libjcat-0.1.6-3.el9",
"libjose-11-3.el9",
"libjpeg-turbo-2.0.90-5.el9",
"libjpeg-turbo-devel-2.0.90-5.el9",
"libkcapi-1.3.1-3.el9",
"libkcapi-hmaccalc-1.3.1-3.el9",
"libksba-1.5.1-4.el9",
"liblockfile-1.14-9.el9",
"libluksmeta-9-12.el9",
"libmnl-1.0.4-15.el9",
"libmodulemd-2.13.0-2.el9",
"libmount-2.37.4-3.el9",
"libmount-devel-2.37.4-3.el9",
"libmpc-1.2.1-4.el9",
"libmpc-devel-1.2.1-4.el9",
"libndp-1.8-4.el9",
"libnet-1.2-6.el9",
"libnetfilter_conntrack-1.0.8-4.el9",
"libnfnetlink-1.0.1-21.el9",
"libnftnl-1.2.2-1.el9",
"libnghttp2-1.43.0-5.el9",
"libnl3-3.7.0-1.el9",
"libogg-1.3.4-6.el9",
"libogg-devel-1.3.4-6.el9",
"libpcap-1.10.0-4.el9",
"libpkgconf-1.7.3-9.el9",
"libpng-1.6.37-12.el9",
"libpng-devel-1.6.37-12.el9",
"libpsl-0.21.1-5.el9",
"libpwquality-1.4.4-8.el9",
"libqb-2.0.6-1.el9",
"librepo-1.14.2-2.el9",
"libreport-filesystem-2.15.2-6.el9",
"libseccomp-2.5.2-2.el9",
"libselinux-3.4-3.el9",
"libselinux-devel-3.4-3.el9",
"libselinux-utils-3.4-3.el9",
"libsemanage-3.4-1.el9",
"libsepol-3.4-1.1.el9",
"libsepol-devel-3.4-1.1.el9",
"libsigsegv-2.13-4.el9",
"libslirp-4.4.0-4.el9",
"libsmartcols-2.37.4-3.el9",
"libsolv-0.7.22-1.el9",
"libss-1.46.5-3.el9",
"libssh-0.9.6-3.el9",
"libssh-config-0.9.6-3.el9",
"libstdc++-11.3.1-2.1.el9",
"libstdc++-devel-11.3.1-2.1.el9",
"libtasn1-4.16.0-7.el9",
"libtiff-4.4.0-2.el9",
"libtiff-devel-4.4.0-2.el9",
"libtool-2.4.6-45.el9",
"libunistring-0.9.10-15.el9",
"libusbx-1.0.26-1.el9",
"libuser-0.63-7.el9",
"libutempter-1.2.1-6.el9",
"libuuid-2.37.4-3.el9",
"libuv-1.42.0-1.el9",
"libverto-0.3.2-3.el9",
"libvorbis-1.3.7-5.el9",
"libvorbis-devel-1.3.7-5.el9",
"libwebp-1.2.0-3.el9",
"libwebp-devel-1.2.0-3.el9",
"libX11-1.7.0-7.el9",
"libX11-common-1.7.0-7.el9",
"libXau-1.0.9-8.el9",
"libxcb-1.13.1-9.el9",
"libxcrypt-4.4.18-3.el9",
"libxcrypt-compat-4.4.18-3.el9",
"libxcrypt-devel-4.4.18-3.el9",
"libXext-1.3.4-8.el9",
"libxml2-2.9.13-2.el9",
"libxmlb-0.3.3-1.el9",
"libXrender-0.9.10-16.el9",
"libyaml-0.2.5-7.el9",
"libzstd-1.5.1-2.el9",
"libzstd-devel-1.5.1-2.el9",
"linux-firmware-automotive-20220310-132.el9s",
"linux-firmware-whence-20220509-126.el9",
"llvm-libs-14.0.5-1.el9",
"lua-libs-5.4.2-4.el9",
"lua-srpm-macros-1-6.el9",
"luksmeta-9-12.el9",
"lvm2-2.03.16-1.el9",
"lvm2-libs-2.03.16-1.el9",
"lz4-libs-1.9.3-5.el9",
"m4-1.4.19-1.el9",
"make-4.3-7.el9",
"memstrack-0.2.4-1.el9",
"mokutil-0.4.0-9.el9",
"mpfr-4.1.0-7.el9",
"mpfr-devel-4.1.0-7.el9",
"mtools-4.0.26-4.el9",
"nano-5.6.1-5.el9",
"ncurses-6.2-8.20210508.el9",
"ncurses-base-6.2-8.20210508.el9",
"ncurses-c++-libs-6.2-8.20210508.el9",
"ncurses-devel-6.2-8.20210508.el9",
"ncurses-libs-6.2-8.20210508.el9",
"net-tools-2.0-0.62.20160912git.el9",
"netavark-1.0.1-39.el9",
"nettle-3.7.3-2.el9",
"NetworkManager-1.39.10-1.el9",
"NetworkManager-libnm-1.39.10-1.el9",
"nftables-1.0.4-2.el9",
"npth-1.6-8.el9",
"nss-altfiles-2.18.1-20.el9",
"ocaml-srpm-macros-6-6.el9",
"oniguruma-6.9.6-1.el9.5",
"openblas-0.3.15-3.el9",
"openblas-openmp-0.3.15-3.el9",
"openblas-srpm-macros-2-11.el9",
"openldap-2.6.2-2.el9",
"openldap-compat-2.6.2-2.el9",
"openssh-8.7p1-19.el9",
"openssh-clients-8.7p1-19.el9",
"openssh-server-8.7p1-19.el9",
"openssl-3.0.1-38.el9",
"openssl-devel-3.0.1-38.el9",
"openssl-libs-3.0.1-38.el9",
"openssl-pkcs11-0.4.11-7.el9",
"opus-1.3.1-10.el9",
"opus-devel-1.3.1-10.el9",
"os-prober-1.77-9.el9",
"ostree-2022.3-2.el9",
"ostree-libs-2022.3-2.el9",
"p11-kit-0.24.1-2.el9",
"p11-kit-trust-0.24.1-2.el9",
"pam-1.5.1-12.el9",
"passwd-0.80-12.el9",
"patch-2.7.6-16.el9",
"pcre-8.44-3.el9.3",
"pcre-cpp-8.44-3.el9.3",
"pcre-devel-8.44-3.el9.3",
"pcre-utf16-8.44-3.el9.3",
"pcre-utf32-8.44-3.el9.3",
"pcre2-10.40-2.el9",
"pcre2-devel-10.40-2.el9",
"pcre2-syntax-10.40-2.el9",
"pcre2-utf16-10.40-2.el9",
"pcre2-utf32-10.40-2.el9",
"perl-AutoSplit-5.74-479.el9",
"perl-B-1.80-479.el9",
"perl-base-2.27-479.el9",
"perl-Benchmark-1.23-479.el9",
"perl-Carp-1.50-460.el9",
"perl-Class-Struct-0.66-479.el9",
"perl-constant-1.33-461.el9",
"perl-Data-Dumper-2.174-462.el9",
"perl-devel-5.32.1-479.el9",
"perl-Devel-PPPort-3.62-4.el9",
"perl-DynaLoader-1.47-479.el9",
"perl-Encode-3.08-462.el9",
"perl-Errno-1.30-479.el9",
"perl-Error-0.17029-7.el9",
"perl-Exporter-5.74-461.el9",
"perl-ExtUtils-Command-7.60-3.el9",
"perl-ExtUtils-Constant-0.25-479.el9",
"perl-ExtUtils-Install-2.20-4.el9",
"perl-ExtUtils-MakeMaker-7.60-3.el9",
"perl-ExtUtils-Manifest-1.73-4.el9",
"perl-ExtUtils-ParseXS-3.40-460.el9",
"perl-Fcntl-1.13-479.el9",
"perl-File-Basename-2.85-479.el9",
"perl-File-Compare-1.100.600-479.el9",
"perl-File-Copy-2.34-479.el9",
"perl-File-Find-1.37-479.el9",
"perl-File-Path-2.18-4.el9",
"perl-File-stat-1.09-479.el9",
"perl-File-Temp-0.231.100-4.el9",
"perl-Getopt-Long-2.52-4.el9",
"perl-Getopt-Std-1.12-479.el9",
"perl-Git-2.31.1-2.el9.2",
"perl-HTTP-Tiny-0.076-460.el9",
"perl-if-0.60.800-479.el9",
"perl-interpreter-5.32.1-479.el9",
"perl-IO-1.43-479.el9",
"perl-IPC-Open3-1.21-479.el9",
"perl-lib-0.65-479.el9",
"perl-libs-5.32.1-479.el9",
"perl-locale-1.09-479.el9",
"perl-MIME-Base64-3.16-4.el9",
"perl-mro-1.23-479.el9",
"perl-overload-1.31-479.el9",
"perl-overloading-0.02-479.el9",
"perl-parent-0.238-460.el9",
"perl-PathTools-3.78-461.el9",
"perl-Pod-Escapes-1.07-460.el9",
"perl-Pod-Perldoc-3.28.01-461.el9",
"perl-Pod-Simple-3.42-4.el9",
"perl-Pod-Usage-2.01-4.el9",
"perl-podlators-4.14-460.el9",
"perl-POSIX-1.94-479.el9",
"perl-Scalar-List-Utils-1.56-461.el9",
"perl-SelectSaver-1.02-479.el9",
"perl-Socket-2.031-4.el9",
"perl-srpm-macros-1-41.el9",
"perl-Storable-3.21-460.el9",
"perl-subs-1.03-479.el9",
"perl-Symbol-1.08-479.el9",
"perl-Term-ANSIColor-5.01-461.el9",
"perl-Term-Cap-1.17-460.el9",
"perl-TermReadKey-2.38-11.el9",
"perl-Test-Harness-3.42-461.el9",
"perl-Text-ParseWords-3.30-460.el9",
"perl-Text-Tabs+Wrap-2013.0523-460.el9",
"perl-Thread-Queue-3.14-460.el9",
"perl-threads-2.25-460.el9",
"perl-threads-shared-1.61-460.el9",
"perl-Time-Local-1.300-7.el9",
"perl-vars-1.05-479.el9",
"perl-version-0.99.28-4.el9",
"pigz-2.5-4.el9",
"pixman-0.40.0-5.el9",
"pkgconf-1.7.3-9.el9",
"pkgconf-m4-1.7.3-9.el9",
"pkgconf-pkg-config-1.7.3-9.el9",
"podman-4.1.1-3.el9",
"podman-catatonit-4.1.1-3.el9",
"policycoreutils-3.4-1.el9",
"policycoreutils-python-utils-3.4-1.el9",
"polkit-0.117-10.el9",
"polkit-libs-0.117-10.el9",
"polkit-pkla-compat-0.1-21.el9",
"popt-1.18-8.el9",
"procps-ng-3.3.17-5.el9",
"protobuf-3.14.0-13.el9",
"protobuf-c-1.3.3-12.el9",
"psmisc-23.4-3.el9",
"publicsuffix-list-dafsa-20210518-3.el9",
"python-rpm-macros-3.9-52.el9",
"python-srpm-macros-3.9-52.el9",
"python-unversioned-command-3.9.13-2.el9",
"python3-3.9.13-2.el9",
"python3-audit-3.0.7-103.el9",
"python3-devel-3.9.13-2.el9",
"python3-dnf-4.12.0-2.el9",
"python3-gpg-1.15.1-6.el9",
"python3-hawkey-0.67.0-1.el9",
"python3-iniparse-0.4-45.el9",
"python3-libcomps-0.1.18-1.el9",
"python3-libdnf-0.67.0-1.el9",
"python3-libs-3.9.13-2.el9",
"python3-libselinux-3.4-3.el9",
"python3-libsemanage-3.4-1.el9",
"python3-numpy-1.20.1-5.el9",
"python3-packaging-20.9-5.el9",
"python3-pip-wheel-21.2.3-6.el9",
"python3-policycoreutils-3.4-1.el9",
"python3-pyparsing-2.4.7-9.el9",
"python3-rpm-4.16.1.3-15.el9",
"python3-rpm-generators-12-8.el9",
"python3-rpm-macros-3.9-52.el9",
"python3-setools-4.4.0-5.el9",
"python3-setuptools-53.0.0-10.el9",
"python3-setuptools-wheel-53.0.0-10.el9",
"python3-six-1.15.0-9.el9",
"qemu-img-7.0.0-8.el9",
"qt5-srpm-macros-5.15.3-1.el9",
"readline-8.1-4.el9",
"redhat-rpm-config-196-1.el9",
"rng-tools-6.15-1.el9",
"rootfiles-8.1-31.el9",
"rpm-4.16.1.3-15.el9",
"rpm-build-4.16.1.3-15.el9",
"rpm-build-libs-4.16.1.3-15.el9",
"rpm-libs-4.16.1.3-15.el9",
"rpm-ostree-2022.8-3.el9",
"rpm-ostree-libs-2022.8-3.el9",
"rpm-plugin-selinux-4.16.1.3-15.el9",
"rpm-sign-libs-4.16.1.3-15.el9",
"rsyslog-8.2102.0-105.el9",
"rust-srpm-macros-17-4.el9",
"sed-4.8-9.el9",
"selinux-policy-34.1.38-1.el9",
"selinux-policy-targeted-34.1.38-1.el9",
"setup-2.13.7-7.el9",
"shadow-utils-4.9-4.el9",
"shadow-utils-subid-4.9-4.el9",
"shared-mime-info-2.1-4.el9",
"skopeo-1.9.0-1.el9",
"slirp4netns-1.2.0-2.el9",
"source-highlight-3.1.9-11.el9",
"sqlite-3.34.1-5.el9",
"sqlite-devel-3.34.1-5.el9",
"sqlite-libs-3.34.1-5.el9",
"strace-5.18-2.el9",
"sudo-1.9.5p2-7.el9",
"sysprof-capture-devel-3.40.1-3.el9",
"systemd-250-7.el9",
"systemd-libs-250-7.el9",
"systemd-pam-250-7.el9",
"systemd-rpm-macros-250-7.el9",
"systemd-udev-250-7.el9",
"systemtap-sdt-devel-4.7-2.el9",
"tar-1.34-5.el9",
"tpm2-tools-5.2-1.el9",
"tpm2-tss-3.0.3-7.el9",
"tzdata-2022a-1.el9",
"unzip-6.0-56.el9",
"usbguard-1.0.0-10.el9",
"userspace-rcu-0.12.1-6.el9",
"util-linux-2.37.4-3.el9",
"util-linux-core-2.37.4-3.el9",
"vim-common-8.2.2637-16.el9",
"vim-enhanced-8.2.2637-16.el9",
"vim-filesystem-8.2.2637-16.el9",
"wget-1.21.1-7.el9",
"which-2.21-28.el9",
"wpa_supplicant-2.10-4.el9",
"xfsprogs-5.14.2-1.el9",
"xml-common-0.6.3-58.el9",
"xz-5.2.5-8.el9",
"xz-devel-5.2.5-8.el9",
"xz-libs-5.2.5-8.el9",
"yajl-2.1.0-20.el9",
"yum-4.12.0-2.el9",
"zip-3.0-33.el9",
"zlib-1.2.11-33.el9",
"zlib-devel-1.2.11-33.el9",
"zstd-1.5.1-2.el9"
],
"arch": {
"aarch64": [
"grub2-efi-aa64-2.06-38.el9",
"grub2-efi-aa64-cdboot-2.06-38.el9",
"libasan-11.3.1-2.1.el9",
"libatomic-11.3.1-2.1.el9",
"libubsan-11.3.1-2.1.el9",
"shim-aa64-15-15.el8_2"
],
"x86_64": [
"glibc-headers-2.34-39.el9",
"grub2-efi-x64-2.06-38.el9",
"grub2-efi-x64-cdboot-2.06-38.el9",
"grub2-tools-efi-2.06-38.el9",
"libipt-2.0.4-3.el9",
"libquadmath-11.3.1-2.1.el9",
"libquadmath-devel-11.3.1-2.1.el9",
"libsmbios-2.4.3-4.el9",
"microcode_ctl-20220510-1.el9",
"shim-x64-15-15.el8_2"
]
}
}
}

11
sample-apps/.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
*.src.rpm
*~
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
radio-client
radio-service
engine-service
auto-apps-*.tar.gz
auto-apps.spec
Makefile

View File

@ -0,0 +1,35 @@
project(auto-apps)
cmake_minimum_required (VERSION 2.10)
include(GNUInstallDirs)
find_package (vsomeip3 2.6.0 REQUIRED)
find_package( Boost 1.55 COMPONENTS system thread log REQUIRED )
set (INSTALL_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE PATH "Installation directory for libraries")
set (INSTALL_BIN_DIR ${CMAKE_INSTALL_BINDIR} CACHE PATH "Installation directory for executables")
set (INSTALL_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH "Installation directory for header files")
include_directories (
${Boost_INCLUDE_DIR}
${VSOMEIP_INCLUDE_DIRS}
)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_executable(radio-service radio-service.cpp services.hpp radio-stations.cpp)
target_link_libraries(radio-service vsomeip3 ${Boost_LIBRARIES})
add_executable(radio-client radio-client.cpp services.hpp)
target_link_libraries(radio-client vsomeip3 ${Boost_LIBRARIES})
add_executable(engine-service engine-service.cpp services.hpp)
target_link_libraries(engine-service vsomeip3 ${Boost_LIBRARIES})
install (
TARGETS radio-service radio-client engine-service
RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin
)

17
sample-apps/COPYING Normal file
View File

@ -0,0 +1,17 @@
Permission is hereby granted, without written agreement and without
license or royalty fees, to use, copy, modify, and distribute this
software and its documentation for any purpose, provided that the
above copyright notice and the following two paragraphs appear in
all copies of this software.
IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

View File

@ -0,0 +1,14 @@
FROM centos:stream9-development AS installroot
RUN dnf update -y
# Enable copr
RUN dnf install -y 'dnf-command(copr)'
RUN dnf copr -y enable alexl/cs9-sample-images
RUN dnf install --installroot /installroot -y --nogpgcheck vsomeip3 bash \
boost-system boost-thread boost-log boost-chrono boost-date-time boost-atomic \
boost-log boost-filesystem boost-regex auto-apps
FROM scratch
COPY --from=installroot /installroot ./

View File

@ -0,0 +1,17 @@
PREFIX=registry.gitlab.com/centos/automotive/sample-images
IMAGE=${PREFIX}/demo/auto-apps
build:
podman build -f Containerfile.auto-apps -t ${IMAGE}:latest-$$(arch) .
push:
podman push ${IMAGE}:latest-$$(arch)
multiarch:
podman pull ${IMAGE}:latest-aarch64
podman pull ${IMAGE}:latest-x86_64
podman manifest rm ${IMAGE}:latest || true
podman manifest create ${IMAGE}:latest ${IMAGE}:latest-x86_64 ${IMAGE}:latest-aarch64
push-multiarch:
podman manifest push --all --format v2s2 ${IMAGE}:latest docker://${IMAGE}:latest

15
sample-apps/Makefile.rpm Normal file
View File

@ -0,0 +1,15 @@
VERSION=0.1
TOPDIR=$(shell pwd)
auto-apps-$(VERSION).tar.gz:
git archive HEAD . --prefix=auto-apps-$(VERSION)/ --output=auto-apps-$(VERSION).tar.gz
srpm: auto-apps-$(VERSION).tar.gz auto-apps.spec.in
sed s/@@VERSION@@/$(VERSION)/g auto-apps.spec.in > auto-apps.spec
rpmbuild -bs --define "_srcrpmdir $(TOPDIR)" --define "_sourcedir $(TOPDIR)" auto-apps.spec
rpm: auto-apps-$(VERSION).tar.gz auto-apps.spec.in
sed s/@@VERSION@@/$(VERSION)/g auto-apps.spec.in > auto-apps.spec
rpmbuild -ba --define "_srcrpmdir $(TOPDIR)" --define "_sourcedir $(TOPDIR)" auto-apps.spec

67
sample-apps/README.md Normal file
View File

@ -0,0 +1,67 @@
# Sample automotive applications
This directory contains a set of applications that demonstrate how
typical automotive applications use SOME/IP to talk to each
other. These apps work both natively and in a container, as
demonstated by the container sample image [described
here](https://sigs.centos.org/automotive/building/containers/).
## The apps
### engine-service
This is a very simple service with a single event that signals that
the car is reversing, which is regularly emitted.
### radio-service
This is a service that emulates a radio, regularly publishing
information about the current song, radio station and volume. It
accepts requests to turn on/off, switch channel, and change volume.
If the engine service is available it will listen for events from it
and temporarily lower the volume while reversing.
### radio-client
This is a command line program that displays the current state of the
radio service, as well as allow you to control it. The keyboard controls
are displayed on the screen.
## Building
The apps depend on boost and vsomeip3, and can be build with cmake like this:
```
$ cmake .
$ make
```
There is also a makefile that allows building rpms and srpms:
```
$ make -f Makefile.rpm srpm
$ make -f Makefile.rpm rpm
```
These rpms, in addition to required dependencies (dlt-daemon,
vsomeip3) are pre-build for cs9 it in [this copr
repo](https://copr.fedorainfracloud.org/coprs/alexl/cs9-sample-images/packages/).
Additionally, there is a
[Containerfile.auto-apps](Containerfile.auto-apps) file that allows
installing these apps into a container, using the above rpms. You can
build it like this:
```
$ podman build -f Containerfile.auto-apps
```
Or use the Makefile.container helpers:
```
$ make -f Makefile.container build
```
A pre-built version of these containers for aarch64 and x86-64 is
available in the [automotive sig container
repo](https://gitlab.com/CentOS/automotive/sample-images/container_registry/2944592).

View File

@ -0,0 +1,32 @@
Name: auto-apps
Version: @@VERSION@@
Release: 1%{?dist}
Summary: Sample auto apps
License: MIT
Source0: auto-apps-%{version}.tar.gz
BuildRequires: cmake make gcc-c++ boost-devel vsomeip3-devel
%description
Sample auto applications
%prep
%autosetup
%build
%cmake
%cmake_build
%install
%cmake_install
%files
%{_bindir}/engine-service
%{_bindir}/radio-client
%{_bindir}/radio-service
%changelog
* Mon Mar 14 2022 Alexander Larsson <alexl@redhat.com>
- Initial version

View File

@ -0,0 +1,181 @@
#include <csignal>
#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>
using namespace std::literals::chrono_literals;
#include <vsomeip/vsomeip.hpp>
#include "services.hpp"
class engine_service {
public:
engine_service() :
app(vsomeip::runtime::get()->create_application("Engine")),
is_registered(false),
main_blocked(false),
main_running(true),
in_reverse(false),
is_offered(false),
main_thread(std::bind(&engine_service::run, this)) {
}
bool init() {
std::lock_guard<std::mutex> its_lock(main_mutex);
if (!app->init()) {
std::cerr << "Couldn't initialize application" << std::endl;
return false;
}
app->register_state_handler(
std::bind(&engine_service::on_state, this,
std::placeholders::_1));
app->register_message_handler(
ENGINE_SERVICE_ID,
ENGINE_INSTANCE_ID,
ENGINE_GET_REVERSE_METHOD_ID,
std::bind(&engine_service::on_get_reverse, this,
std::placeholders::_1));
std::set<vsomeip::eventgroup_t> its_groups;
its_groups.insert(ENGINE_EVENTGROUP_ID);
app->offer_event(
ENGINE_SERVICE_ID,
ENGINE_INSTANCE_ID,
ENGINE_REVERSE_EVENT_ID,
its_groups,
vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(),
false, true, nullptr, vsomeip::reliability_type_e::RT_UNKNOWN);
main_blocked = true;
main_condition.notify_one();
return true;
}
void start() {
app->start();
}
void stop() {
main_running = false;
main_blocked = true;
main_condition.notify_one();
app->clear_all_handler();
stop_offer();
main_thread.join();
app->stop();
}
void offer() {
app->offer_service(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID);
is_offered = true;
}
void stop_offer() {
app->stop_offer_service(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID);
}
void on_state(vsomeip::state_type_e _state) {
std::cout << "Application " << app->get_name() << " is "
<< (_state == vsomeip::state_type_e::ST_REGISTERED ?
"registered." : "deregistered.") << std::endl;
if (_state == vsomeip::state_type_e::ST_REGISTERED) {
if (!is_registered) {
is_registered = true;
}
} else {
is_registered = false;
}
}
// Call with lock held
std::shared_ptr<vsomeip::payload> get_reverse_payload() {
return payload_with_arg (in_reverse ? 1 : 0);
}
void on_get_reverse(const std::shared_ptr<vsomeip::message> &_message) {
std::cout << "ENGINE: Received get_reverse" << std::endl;
std::shared_ptr<vsomeip::message> its_response = vsomeip::runtime::get()->create_response(_message);
{
std::lock_guard<std::mutex> its_lock(main_mutex);
its_response->set_payload(get_reverse_payload());
}
app->send(its_response);
}
void run() {
std::unique_lock<std::mutex> its_lock(main_mutex);
while (!main_blocked)
main_condition.wait(its_lock);
offer();
while (main_running) {
auto timeout = 10s;
if (in_reverse) {
timeout = 4s;
std::cout << "ENGINE: Reversing..." << std::endl;
} else {
std::cout << "ENGINE: Driving..." << std::endl;
}
// Sleep a bit
bool timed_out = main_condition.wait_for(its_lock, timeout) == std::cv_status::timeout;
if (timed_out) {
// Change direction
in_reverse = !in_reverse;
std::shared_ptr<vsomeip::payload> payload = get_reverse_payload();
app->notify(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID, ENGINE_REVERSE_EVENT_ID, payload);
}
}
}
private:
std::shared_ptr<vsomeip::application> app;
bool is_registered;
// main_blocked / is_offered must be initialized before starting the threads!
std::thread main_thread;
std::mutex main_mutex;
std::condition_variable main_condition;
bool main_blocked;
bool main_running;
bool is_offered;
// Engine state:
bool in_reverse;
};
engine_service *its_engine_ptr(nullptr);
static void handle_signal(int _signal) {
if (its_engine_ptr != nullptr &&
(_signal == SIGINT || _signal == SIGTERM))
its_engine_ptr->stop();
}
int main() {
engine_service its_engine;
its_engine_ptr = &its_engine;
signal(SIGINT, handle_signal);
signal(SIGTERM, handle_signal);
if (!its_engine.init()) {
return 1;
}
its_engine.start();
// Work around dlt-daemon timeout on exit
_exit(0);
}

View File

@ -0,0 +1,266 @@
#include <iomanip>
#include <iostream>
#include <condition_variable>
#include <thread>
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <vsomeip/vsomeip.hpp>
using namespace std::literals::chrono_literals;
#include "services.hpp"
std::shared_ptr< vsomeip::application > app;
std::mutex mutex;
std::condition_variable condition;
bool running = true;
bool data_changed = false;
bool service_available = false;
bool in_reverse = false;
std::string radio_station = "";
std::string song = "";
std::string artist = "";
uint32_t volume = 0;
bool sent_off = false;
static std::string volume_meter(uint32_t volume)
{
std::string vol_str = "";
for (uint32_t i = 0; i <= 20; i++) {
if (volume > i * 5 || volume == 100)
vol_str += "#";
else
vol_str += " ";
}
return vol_str;
}
void on_volume_message(const std::shared_ptr<vsomeip::message> &_event) {
std::unique_lock<std::mutex> its_lock(mutex);
volume = get_arg0(_event);
data_changed = true;
condition.notify_one();
}
void on_song_message(const std::shared_ptr<vsomeip::message> &_event) {
std::unique_lock<std::mutex> its_lock(mutex);
song = get_arg0_string(_event);
data_changed = true;
condition.notify_one();
}
void on_artist_message(const std::shared_ptr<vsomeip::message> &_event) {
std::unique_lock<std::mutex> its_lock(mutex);
artist = get_arg0_string(_event);
data_changed = true;
condition.notify_one();
}
void on_station_message(const std::shared_ptr<vsomeip::message> &_event) {
radio_station = get_arg0_string(_event);
data_changed = true;
condition.notify_one();
}
void input_thread() {
while (true) {
int c = getchar();
switch (c) {
case 'q':
{
std::unique_lock<std::mutex> its_lock(mutex);
running = false;
condition.notify_one();
app->stop();
}
return; /* End thread */
break;
case '+':
{
std::shared_ptr< vsomeip::message > request = new_request (RADIO_CHANGE_VOLUME_METHOD_ID, 10);
app->send(request);
}
break;
case '-':
{
std::shared_ptr< vsomeip::message > request = new_request (RADIO_CHANGE_VOLUME_METHOD_ID, (uint32_t)(int32_t)-10);
app->send(request);
}
break;
case ' ':
{
std::shared_ptr< vsomeip::message > request = new_request (RADIO_SWITCH_STATION_METHOD_ID, 0);
app->send(request);
}
break;
case '\e':
{
std::shared_ptr< vsomeip::message > request = new_request (RADIO_SET_PLAYING_METHOD_ID, sent_off ? 1 : 0);
sent_off = !sent_off;
app->send(request);
}
break;
default:
// pass
break;
}
}
}
void run() {
std::unique_lock<std::mutex> its_lock(mutex);
app->register_message_handler(
RADIO_SERVICE_ID, RADIO_INSTANCE_ID, RADIO_VOLUME_EVENT_ID,
on_volume_message);
app->register_message_handler(
RADIO_SERVICE_ID, RADIO_INSTANCE_ID, RADIO_STATION_EVENT_ID,
on_station_message);
app->register_message_handler(
RADIO_SERVICE_ID, RADIO_INSTANCE_ID, RADIO_SONG_EVENT_ID,
on_song_message);
app->register_message_handler(
RADIO_SERVICE_ID, RADIO_INSTANCE_ID, RADIO_ARTIST_EVENT_ID,
on_artist_message);
std::set<vsomeip::eventgroup_t> its_groups;
its_groups.insert(RADIO_EVENTGROUP_ID);
app->request_event(RADIO_SERVICE_ID,
RADIO_INSTANCE_ID,
RADIO_SONG_EVENT_ID,
its_groups,
vsomeip::event_type_e::ET_FIELD);
app->request_event(RADIO_SERVICE_ID,
RADIO_INSTANCE_ID,
RADIO_ARTIST_EVENT_ID,
its_groups,
vsomeip::event_type_e::ET_FIELD);
app->request_event(RADIO_SERVICE_ID,
RADIO_INSTANCE_ID,
RADIO_VOLUME_EVENT_ID,
its_groups,
vsomeip::event_type_e::ET_FIELD);
app->request_event(RADIO_SERVICE_ID,
RADIO_INSTANCE_ID,
RADIO_STATION_EVENT_ID,
its_groups,
vsomeip::event_type_e::ET_FIELD);
app->subscribe(RADIO_SERVICE_ID, RADIO_INSTANCE_ID, RADIO_EVENTGROUP_ID);
while (running) {
if (data_changed) {
std::cout
<< "\e[s" // Save cursor
<< "\e[6;1H" // Goto row 6
<< "\e[1J" // Clear to start of screen
<< "\e[1;1H" // Goto row 1;
;
if (service_available) {
std::cout
<< "Station: " << radio_station << std::endl
<< "Song: " << song << std::endl
<< "Artist: " << artist << std::endl
<< "Volume: [" << volume_meter(volume) << "] " << std::endl
<< (in_reverse ?
"------------------------------[REVERSING]-" :
"------------------------------------------")
<< std::endl;
} else {
std::cout
<< "Connecting to radio service";
}
std::cout
<< "\e[u" // Restore cursor
<< std::flush;
data_changed = false;
}
condition.wait_for(its_lock, 5s);
}
}
void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) {
std::unique_lock<std::mutex> its_lock(mutex);
service_available = _is_available;
data_changed = true;
condition.notify_one();
}
void on_engine_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) {
std::unique_lock<std::mutex> its_lock(mutex);
if (!_is_available)
{
in_reverse = false;
data_changed = true;
condition.notify_one();
}
}
void on_engine_reverse_event(const std::shared_ptr<vsomeip::message> &_event) {
std::unique_lock<std::mutex> its_lock(mutex);
bool reversed = get_arg0(_event) != 0;
in_reverse = reversed;
data_changed = true;
condition.notify_one();
}
int main(int argc, const char *argv[]) {
struct termios old_tio, new_tio;
unsigned char c;
tcgetattr(STDIN_FILENO,&old_tio);
new_tio=old_tio;
/* disable canonical mode (buffered i/o) and local echo */
new_tio.c_lflag &=(~ICANON & ~ECHO);
tcsetattr(STDIN_FILENO,TCSANOW,&new_tio);
std::cout
<< "\e[2J" // Clear screen
<< "\e[1;1H" // Goto row 1
<< "\e[6;1H" // Goto row 6
<< " Usage: volume: +/-, station: SPACE on/off: ESC, quit: Q" << std::endl;
app = vsomeip::runtime::get()->create_application("Radio client");
app->init();
app->register_availability_handler(RADIO_SERVICE_ID, RADIO_INSTANCE_ID, on_availability);
app->request_service(RADIO_SERVICE_ID, RADIO_INSTANCE_ID);
app->register_availability_handler(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID, on_engine_availability);
app->request_service(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID);
std::set<vsomeip::eventgroup_t> its_groups;
its_groups.insert(ENGINE_EVENTGROUP_ID);
app->request_event(ENGINE_SERVICE_ID,
ENGINE_INSTANCE_ID,
ENGINE_REVERSE_EVENT_ID,
its_groups,
vsomeip::event_type_e::ET_FIELD);
app->subscribe(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID, ENGINE_EVENTGROUP_ID);
app->register_message_handler(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID, ENGINE_REVERSE_EVENT_ID,
on_engine_reverse_event);
std::thread input(input_thread);
std::thread sender(run);
app->start();
sender.join();
input.join();
app->clear_all_handler();
app->release_service(RADIO_SERVICE_ID, RADIO_INSTANCE_ID);
app->release_service(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID);
tcsetattr(STDIN_FILENO,TCSANOW,&old_tio);
// Work around dlt-daemon timeout on exit
_exit(0);
return 0;
}

View File

@ -0,0 +1,437 @@
#include <csignal>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <condition_variable>
#include <thread>
#include <chrono>
using namespace std::literals::chrono_literals;
#include <vsomeip/vsomeip.hpp>
#include "services.hpp"
#include "radio-stations.hpp"
class radio_service {
public:
radio_service() :
app(vsomeip::runtime::get()->create_application("Radio")),
verbose(false),
main_blocked(false),
main_running(true),
is_offered(false),
engine_available(false),
next_volume(50),
next_radio_station(0),
next_playing(false),
next_reversed(false),
main_thread(std::bind(&radio_service::run, this)) {
}
bool init() {
std::lock_guard<std::mutex> its_lock(main_mutex);
if (!app->init()) {
std::cerr << "Couldn't initialize application" << std::endl;
return false;
}
app->register_message_handler(
RADIO_SERVICE_ID,
RADIO_INSTANCE_ID,
RADIO_SET_PLAYING_METHOD_ID,
std::bind(&radio_service::on_message_set_playing, this,
std::placeholders::_1));
app->register_message_handler(
RADIO_SERVICE_ID,
RADIO_INSTANCE_ID,
RADIO_IS_PLAYING_METHOD_ID,
std::bind(&radio_service::on_message_is_playing, this,
std::placeholders::_1));
app->register_message_handler(
RADIO_SERVICE_ID,
RADIO_INSTANCE_ID,
RADIO_GET_VOLUME_METHOD_ID,
std::bind(&radio_service::on_message_get_volume, this,
std::placeholders::_1));
app->register_message_handler(
RADIO_SERVICE_ID,
RADIO_INSTANCE_ID,
RADIO_CHANGE_VOLUME_METHOD_ID,
std::bind(&radio_service::on_message_change_volume, this,
std::placeholders::_1));
app->register_message_handler(
RADIO_SERVICE_ID,
RADIO_INSTANCE_ID,
RADIO_SWITCH_STATION_METHOD_ID,
std::bind(&radio_service::on_message_switch_station, this,
std::placeholders::_1));
std::set<vsomeip::eventgroup_t> its_groups_radio;
its_groups_radio.insert(RADIO_EVENTGROUP_ID);
app->offer_event(
RADIO_SERVICE_ID,
RADIO_INSTANCE_ID,
RADIO_VOLUME_EVENT_ID,
its_groups_radio,
vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(),
false, true, nullptr, vsomeip::reliability_type_e::RT_UNKNOWN);
app->offer_event(
RADIO_SERVICE_ID,
RADIO_INSTANCE_ID,
RADIO_STATION_EVENT_ID,
its_groups_radio,
vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(),
false, true, nullptr, vsomeip::reliability_type_e::RT_UNKNOWN);
app->offer_event(
RADIO_SERVICE_ID,
RADIO_INSTANCE_ID,
RADIO_SONG_EVENT_ID,
its_groups_radio,
vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(),
false, true, nullptr, vsomeip::reliability_type_e::RT_UNKNOWN);
app->offer_event(
RADIO_SERVICE_ID,
RADIO_INSTANCE_ID,
RADIO_ARTIST_EVENT_ID,
its_groups_radio,
vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(),
false, true, nullptr, vsomeip::reliability_type_e::RT_UNKNOWN);
app->register_availability_handler(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID,
std::bind(&radio_service::on_engine_availability, this,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
app->request_service(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID);
std::set<vsomeip::eventgroup_t> its_groups;
its_groups.insert(ENGINE_EVENTGROUP_ID);
app->request_event(
ENGINE_SERVICE_ID,
ENGINE_INSTANCE_ID,
ENGINE_REVERSE_EVENT_ID,
its_groups,
vsomeip::event_type_e::ET_FIELD);
app->subscribe(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID, ENGINE_EVENTGROUP_ID);
app->register_message_handler(
ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID, ENGINE_REVERSE_EVENT_ID,
std::bind(&radio_service::on_engine_reverse_event, this,
std::placeholders::_1));
main_blocked = true;
main_condition.notify_one();
return true;
}
void start() {
set_playing(true);
app->start();
}
void stop() {
main_running = false;
main_blocked = true;
main_condition.notify_one();
app->clear_all_handler();
app->unsubscribe(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID, ENGINE_EVENTGROUP_ID);
app->release_event(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID, ENGINE_REVERSE_EVENT_ID);
app->release_service(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID);
stop_offer();
main_thread.join();
app->stop();
}
void offer() {
app->offer_service(RADIO_SERVICE_ID, RADIO_INSTANCE_ID);
is_offered = true;
}
void stop_offer() {
app->stop_offer_service(RADIO_SERVICE_ID, RADIO_INSTANCE_ID);
}
void run() {
uint32_t current_volume = next_volume;
bool currently_playing = false;
bool current_reversed = false;
uint32_t saved_volume;
bool next_volume_is_auto = false;
bool volume_is_auto = false;
uint32_t current_station = 0xffffffff;
const radio_station_info_t *station_info = NULL;
uint32_t current_song = 0;
bool goto_next_song = true;
std::chrono::time_point<std::chrono::system_clock> next_song_at;
std::unique_lock<std::mutex> its_lock(main_mutex);
std::cout << "RADIO: Started main thread" << std::endl;
offer();
while (main_running) {
bool display = false;
if (next_reversed != current_reversed) {
if (next_reversed) {
saved_volume = current_volume;
next_volume = 30;
next_volume_is_auto = true;
std::cout << "RADIO: Lowering volume due to reverse" << std::endl;
} else {
if (volume_is_auto) {
next_volume = saved_volume;
std::cout << "RADIO: Restoring volume due to cancelled reverse" << std::endl;
}
}
current_reversed = next_reversed;
}
if (next_volume != current_volume) {
current_volume = next_volume;
volume_is_auto = next_volume_is_auto;
next_volume_is_auto = false;
display = true;
app->notify(RADIO_SERVICE_ID, RADIO_INSTANCE_ID, RADIO_VOLUME_EVENT_ID, payload_with_arg (current_volume));
}
if (next_radio_station != current_station) {
current_station = next_radio_station;
goto_next_song = true;
station_info = get_radio_stations(current_station);
display = true;
app->notify(RADIO_SERVICE_ID, RADIO_INSTANCE_ID, RADIO_STATION_EVENT_ID, payload_with_string (station_info->name));
}
if (next_playing) {
if (!currently_playing) {
std::cout << "RADIO: Started playing" << std::endl;
goto_next_song = true;
}
currently_playing = true;
if (goto_next_song) {
auto old = current_song;
do {
current_song = rand() % station_info->n_songs;
} while (old == current_song);
goto_next_song = false;
next_song_at = std::chrono::system_clock::now() + 3s + (rand() % 3000) * 1ms;
display = true;
}
if (display) {
struct song_info_t *song = &station_info->songs[current_song];
app->notify(RADIO_SERVICE_ID, RADIO_INSTANCE_ID, RADIO_SONG_EVENT_ID, payload_with_string (song->name));
app->notify(RADIO_SERVICE_ID, RADIO_INSTANCE_ID, RADIO_ARTIST_EVENT_ID, payload_with_string (song->artist));
std::cout << "RADIO: Playing song \""
<< song->name << "\" by " << song->artist
<< " (on " << station_info->name << ") "
<< std::dec << current_volume << "% volume"
<< std::endl;
}
} else {
if (currently_playing)
std::cout << "RADIO: Paused playing" << std::endl;
app->notify(RADIO_SERVICE_ID, RADIO_INSTANCE_ID, RADIO_SONG_EVENT_ID, payload_with_string ("-off-"));
app->notify(RADIO_SERVICE_ID, RADIO_INSTANCE_ID, RADIO_ARTIST_EVENT_ID, payload_with_string (""));
currently_playing = false;
}
if (main_condition.wait_until(its_lock, next_song_at) == std::cv_status::timeout) {
goto_next_song = true;
}
}
}
void on_message_set_playing(const std::shared_ptr<vsomeip::message> &_request) {
bool arg = get_arg0(_request) != 0;
bool was_playing;
if (verbose)
std::cout << "RADIO: Received set_playing "
<< arg
<< " from Client/Session ["
<< std::setw(4) << std::setfill('0') << std::hex << _request->get_client() << "/"
<< std::setw(4) << std::setfill('0') << std::hex << _request->get_session() << "] "
<< std::endl;
was_playing = set_playing (arg);
std::shared_ptr<vsomeip::message> its_response = response (_request, was_playing ? 1 : 0);
app->send(its_response);
}
void on_message_is_playing(const std::shared_ptr<vsomeip::message> &_request) {
if (verbose)
std::cout << "RADIO: Received is_playing "
<< "from Client/Session ["
<< std::setw(4) << std::setfill('0') << std::hex << _request->get_client() << "/"
<< std::setw(4) << std::setfill('0') << std::hex << _request->get_session() << "] "
<< std::endl;
std::shared_ptr<vsomeip::message> its_response = response (_request, get_playing () ? 1 : 0);
app->send(its_response);
}
void on_message_change_volume(const std::shared_ptr<vsomeip::message> &_request) {
int32_t arg = (int32_t)get_arg0(_request);
uint32_t result;
if (verbose)
std::cout << "RADIO: Received change_volume "
<< arg
<< " from Client/Session ["
<< std::setw(4) << std::setfill('0') << std::hex << _request->get_client() << "/"
<< std::setw(4) << std::setfill('0') << std::hex << _request->get_session() << "] "
<< std::endl;
result = change_volume (arg);
std::shared_ptr<vsomeip::message> its_response = response (_request, result);
app->send(its_response);
}
void on_message_get_volume(const std::shared_ptr<vsomeip::message> &_request) {
if (verbose)
std::cout << "RADIO: Received get_volume "
<< "from Client/Session ["
<< std::setw(4) << std::setfill('0') << std::hex << _request->get_client() << "/"
<< std::setw(4) << std::setfill('0') << std::hex << _request->get_session() << "] "
<< std::endl;
uint32_t volume = get_volume();
std::shared_ptr<vsomeip::message> its_response = response (_request, volume);
app->send(its_response);
}
void on_message_switch_station(const std::shared_ptr<vsomeip::message> &_request) {
if (verbose)
std::cout << "RADIO: Received switch_station "
<< "from Client/Session ["
<< std::setw(4) << std::setfill('0') << std::hex << _request->get_client() << "/"
<< std::setw(4) << std::setfill('0') << std::hex << _request->get_session() << "] "
<< std::endl;
switch_station();
std::shared_ptr<vsomeip::message> its_response = response (_request, 0);
app->send(its_response);
}
void on_engine_reverse_event(const std::shared_ptr<vsomeip::message> &_event) {
bool reversed = get_arg0(_event) != 0;
if (verbose)
std::cout << "RADIO: Received event: "
<< (reversed ? "engine reversed" : "engine forward")
<< std::endl;
set_reversed(reversed);
}
void on_engine_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) {
std::cout << "Engine Service is "
<< (_is_available ? "available." : "NOT available.")
<< std::endl;
std::lock_guard<std::mutex> its_lock(main_mutex);
engine_available = _is_available;
}
private:
bool set_playing (bool new_playing) {
std::unique_lock<std::mutex> its_lock(main_mutex);
bool old = new_playing;
if (next_playing != new_playing) {
next_playing = new_playing;
main_condition.notify_one();
}
return old;
}
bool get_playing (void) {
std::unique_lock<std::mutex> its_lock(main_mutex);
return next_playing;
}
uint32_t change_volume (int32_t delta_volume) {
std::unique_lock<std::mutex> its_lock(main_mutex);
int32_t new_volume;
new_volume = (int32_t)next_volume + delta_volume;
if (new_volume < 0)
new_volume = 0;
else {
if (new_volume > 100)
new_volume = 100;
}
if (next_volume != new_volume) {
next_volume = new_volume;
main_condition.notify_one();
}
return new_volume;
}
uint32_t get_volume (void) {
std::unique_lock<std::mutex> its_lock(main_mutex);
return next_volume;
}
void switch_station (void) {
std::unique_lock<std::mutex> its_lock(main_mutex);
next_radio_station = (next_radio_station + 1) % n_radio_stations();
main_condition.notify_one();
}
void set_reversed (bool new_reversed) {
std::unique_lock<std::mutex> its_lock(main_mutex);
next_reversed = new_reversed;
main_condition.notify_one();
}
std::shared_ptr< vsomeip::application > app;
std::thread main_thread;
std::mutex main_mutex;
std::condition_variable main_condition;
bool main_blocked;
bool main_running;
bool is_offered;
bool engine_available;
bool verbose;
uint32_t next_volume;
uint32_t next_radio_station;
bool next_playing;
bool next_reversed;
};
radio_service *its_radio_ptr(nullptr);
static void handle_signal(int _signal) {
if (its_radio_ptr != nullptr &&
(_signal == SIGINT || _signal == SIGTERM))
its_radio_ptr->stop();
}
int main() {
radio_service its_radio;
its_radio_ptr = &its_radio;
signal(SIGINT, handle_signal);
signal(SIGTERM, handle_signal);
if (!its_radio.init()) {
return 1;
}
its_radio.start();
// Work around dlt-daemon timeout on exit
_exit(0);
}

View File

@ -0,0 +1,508 @@
#include "radio-stations.hpp"
#define SONGS(_station) (_station ## _songs), sizeof(_station ## _songs)/sizeof(struct song_info_t)
static struct song_info_t radio_los_santos_songs[] = {
{ "YG", "I'm A Real 1", 2013 },
{ "100s", "Life of a Mack", 2013 },
{ "Ab-Soul feat. Kendrick Lamar", "ILLuminate", 2012 },
{ "A$AP Rocky feat. Aston Matthews & Joey Fatts", "R-Cali", 2013 },
{ "Marion Band$ feat. Nipsey Hussle", "Hold Up", 2013 },
{ "BJ the Chicago Kid feat. Freddie Gibbs & Problem", "Smokin' and Ridin'", 2013 },
{ "Kendrick Lamar", "A.D.H.D", 2011 },
{ "Jay Rock feat. Kendrick Lamar", "Hood Gone Love It", 2011 },
{ "The Game feat. 2 Chainz & Rick Ross", "Ali Bomaye", 2012 },
{ "Freddie Gibbs", "Still Livin'", 2012 },
{ "DJ Esco feat. Future", "How It Was", 2013 },
{ "Problem feat. Glasses Malone", "Say That Then", 2013 },
{ "Clyde Carson feat. The Team", "Slow Down", 2012 },
{ "Gucci Mane feat. Ciara", "Too Hood", 2011 },
{ "Gangrene", "Bassheads", 2013 },
{ "Danny Brown & Action Bronson", "Bad News", 2013 },
{ "G-Side feat. G-Mane", "Relaxin'", 2010 },
{ "A$AP Ferg", "Work", 2013 },
{ "Trouble feat. Gucci Mane", "Everyday", 2012 },
{ "Kendrick Lamar", "Swimming Pools, Drank", 2012 },
{ "Travi$ Scott feat. 2 Chainz & T.I.", "Upper Echelon", 2013 },
{ "Danny Brown feat. A$AP Rocky & Zelooperz", "Kush Coma", 2013 },
{ "Ace Hood feat. Future & Rick Ross", "Bugatti", 2013 },
{ "Schoolboy Q feat. Kendrick Lamar", "Collard Greens", 2013 },
{ "Chuck Inglish feat. Ab-Soul & Mac Miller", "Came Thru/Easily", 2013 },
{ "Young Scooter feat. Gucci Mane", "Work", 2013 },
{ "Problem & IamSu feat. Bad Lucc & Sage The Gemini", "Do It Big", 2013 },
{ "Skeme", "Millions", 2013 },
{ "Ab-Soul feat. Schoolboy Q", "Hunnid Stax", 2014 },
{ "Freddie Gibbs & Mike Dean", "Sellin' Dope", 2014 },
{ "Young Scooter feat. Trinidad James", "I Can't Wait", 2013 },
};
static struct song_info_t space_103_2_songs[] = {
{ "Bootsy's Rubber Band", "I'd Rather Be With You", 1976 },
{ "D-Train", "You're the One for Me", 1981 },
{ "Eddie Murphy", "Party All the Time", 1985 },
{ "Evelyn \"Champagne\" King", "I'm in Love, 12\" Version", 1981 },
{ "Kano", "Can't Hold Back, Your Loving", 1981 },
{ "Kleeer", "Tonight", 1984 },
{ "Bernard Wright", "Haboglabotribin", 1981 },
{ "One Way", "Cutie Pie", 1982 },
{ "Rick James", "Give It to Me Baby", 1981 },
{ "Sho Nuff", "Funkasize You", 1978 },
{ "Stevie Wonder", "Skeletons", 1987 },
{ "Taana Gardner", "Heartbeat, Club Version", 1981 },
{ "Zapp", "Heartbreaker, Pts. 1-2", 1983 },
{ "Dazz Band", "Joystick", 1983 },
{ "Roger", "Do It Roger", 1981 },
{ "Imagination", "Flashback", 1981 },
{ "Parliament", "Mothership Connection, Star Child", 1975 },
{ "The Fatback Band", "Gotta Get My Hands On Some, Money", 1979 },
{ "Billy Ocean", "Nights, Feel Like Gettin' Down", 1981 },
{ "Parliament", "Flash Light", 1977 },
{ "Cameo", "Back and Forth", 1986 },
{ "Central Line", "Walking Into Sunshine", 1981 },
};
static struct song_info_t west_cost_classics_songs[] = {
{ "2Pac", "Ambitionz Az a Ridah", 1996 },
{ "Compton's Most Wanted", "Late Night Hype", 1990 },
{ "DJ Quik", "Dollaz + Sense", 1995 },
{ "Dr. Dre feat. Snoop Dogg", "Still D.R.E", 1999 },
{ "King Tee", "Played Like a Piano", 1990 },
{ "Dr. Dre feat. Snoop Dogg, Kurupt & Nate Dogg", "The Next Episode", 1999 },
{ "Ice Cube", "You Know How We Do It", 1994 },
{ "Kausion feat. Ice Cube", "What You Wanna Do?", 1995 },
{ "Kurupt", "C-Walk", 1998 },
{ "Mack 10 & Tha Dogg Pound", "Nothin' But the Cavi Hit", 1996 },
{ "MC Eiht", "Streiht Up Menace", 1993 },
{ "N.W.A", "Appetite for Destruction", 1991 },
{ "N.W.A", "Gangsta Gangsta", 1988 },
{ "Tha Dogg Pound", "What Would U Do?", 1995 },
{ "Snoop Dogg", "Gin and Juice", 1993 },
{ "Geto Boys", "Mind Playing Tricks on Me", 1991 },
{ "Too $hort", "So You Want to Be a Gangster", 1992 },
{ "Jayo Felony", "Sherm Stick", 1995 },
{ "Warren G", "This D.J.", 1994 },
{ "CPO feat. MC Ren", "Ballad Of A Menace", 1990 },
{ "E-40 feat. The Click", "Captain Save a Hoe", 1994 },
{ "The Conscious Daughters", "We Roll Deep", 1993 },
{ "Eazy-E feat. Ice Cube", "No More ?'s", 1988 },
{ "South Central Cartel", "Servin' 'Em Heat", 1993 },
{ "The Lady of Rage feat. Snoop Dogg", "Afro Puffs", 1994 },
{ "Westside Connection", "Bow Down", 1996 },
{ "Spice 1 feat. MC Eiht", "The Murda Show", 1993 },
{ "Bone Thugs-N-Harmony", "1st of Tha Month", 1995 },
{ "Luniz feat. Michael Marshall", "I Got 5 On It", 1995 },
};
static struct song_info_t rebel_radio_songs[] = {
{ "Charlie Feathers", "Can't Hardly Stand It", 1956 },
{ "Hank Thompson", "It Don't Hurt Anymore", 1957 },
{ "Hasil Adkins", "Get Outta My Car", 1966 },
{ "Jerry Reed", "You Took All the Ramblin' Out of Me", 1972 },
{ "Johnny Cash", "The General Lee", 1981 },
{ "Johnny Paycheck", "(It Won't Be Long And I'll Be Hating You", 1968 },
{ "Ozark Mountain Daredevils", "If You Wanna Get to Heaven", 1973 },
{ "Waylon Jennings", "Are You Sure Hank Done It This Way", 1975 },
{ "Waylon Jennings", "I Ain't Living Long Like This", 1979 },
{ "Willie Nelson", "Whiskey River", 1973 },
{ "C.W. McCall", "Convoy", 1975 },
{ "Homer & Jethro", "She Made Toothpicks Of The Timber Of My Heart", 1963 },
{ "The Highwaymen", "Highwayman", 1985 },
{ "Tammy Wynette", "D-I-V-O-R-C-E", 1968 },
{ "Ray Price", "Crazy Arms", 1956 },
{ "Marvin Jackson", "Dippin' Snuff", 1957 },
{ "Charlie Feathers", "Get With It", 1956 },
};
static struct song_info_t los_santos_rock_radio_songs[] = {
{ "Billy Squier", "Lonely Is the Night", 1981 },
{ "Bob Seger & The Silver Bullet Band", "Hollywood Nights", 1978 },
{ "Bob Seger & The Silver Bullet Band", "Night Moves", 1976 },
{ "Chicago", "If You Leave Me Now", 1976 },
{ "Def Leppard", "Photograph", 1983 },
{ "Don Johnson", "Heartbeat", 1986 },
{ "Elton John", "Saturday Night's Alright for Fighting", 1973 },
{ "Foreigner", "Dirty White Boy", 1979 },
{ "Gerry Rafferty", "Baker Street", 1978 },
{ "The Greg Kihn Band", "The Breakup Song, They Don't Write 'Em", 1981 },
{ "Julian Lennon", "Too Late for Goodbyes", 1984 },
{ "Kenny Loggins", "I'm Free, Heaven Helps the Man", 1984 },
{ "Phil Collins", "I Don't Care Anymore", 1982 },
{ "Queen", "Radio Ga Ga", 1984 },
{ "Robert Plant", "Big Log", 1983 },
{ "Simple Minds", "All the Things She Said", 1985 },
{ "The Small Faces", "Ogdens' Nut Gone Flake", 1968 },
{ "Steve Winwood", "Higher Love", 1986 },
{ "Stevie Nicks", "I Can't Wait", 1985 },
{ "The Alan Parsons Project", "I Wouldn't Want To Be Like You", 1977 },
{ "The Doobie Brothers", "What a Fool Believes", 1979 },
{ "The Cult", "Rain", 1985 },
{ "Steve Miller Band", "Rock'n Me", 1976 },
{ "Creedence Clearwater Revival", "Fortunate Son", 1969 },
{ "Starship", "We Built This City", 1985 },
{ "Mountain", "Mississippi Queen", 1970 },
{ "Kenny Loggins", "Danger Zone", 1986 },
{ "Alannah Myles", "Black Velvet", 1989 },
{ "Pat Benatar", "Shadows of the Night", 1982 },
{ "Belinda Carlisle", "Circle in the Sand", 1987 },
{ "Kansas", "Carry On Wayward Son", 1976 },
{ "Boston", "Peace Of Mind", 1976 },
{ "Harry Chapin", "Cat's In the Cradle", 1974 },
{ "Survivor", "Burning Heart", 1986 },
{ "Humble Pie", "30 Days In the Hole", 1972 },
{ "ZZ Top", "Gimme All Your Lovin'", 1983 },
{ "Yes", "Roundabout", 1972 },
{ "Broken English", "Comin' On Strong", 1987 },
};
static struct song_info_t the_lowdown_songs[] = {
{ "Aaron Neville", "Hercules", 1973 },
{ "B.T. Express", "Do It, 'Til You're Satisfied", 1974 },
{ "El Chicano", "Viva Tirado", 1970 },
{ "George McCrae", "I Get Lifted", 1974 },
{ "Marlena Shaw", "California Soul", 1969 },
{ "Smokey Robinson", "Cruisin'", 1979 },
{ "The Delfonics", "Ready or Not Here I Come, Can't Hide from Love", 1968 },
{ "The Five Stairsteps", "O-O-H Child", 1970 },
{ "The Soul Searchers", "Ashley's Roachclip", 1974 },
{ "The Trammps", "Rubber Band", 1972 },
{ "The Undisputed Truth", "Smiling Faces Sometimes", 1971 },
{ "War", "The Cisco Kid", 1973 },
{ "Pleasure", "Bouncy Lady", 1975 },
{ "The Delfonics", "Funny Feeling", 1970 },
{ "Ohio Players", "Climax", 1974 },
{ "The Chakachas", "Stories", 1972 },
{ "Eric Burdon & War", "Magic Mountain", 1976 },
{ "Johnny \"Guitar\" Watson", "Superman Lover", 1976 },
{ "The Jackson Sisters", "I Believe In Miracles", 1973 },
{ "Brass Construction", "Changin'", 1975 },
};
static struct song_info_t the_blue_ark_songs[] = {
{ "Chronixx", "Odd Ras", 2012 },
{ "Dennis Brown", "Money In My Pocket", 1972 },
{ "Gregory Isaacs", "Night Nurse", 1982 },
{ "Half Pint", "Crazy Girl", 1997 },
{ "Joe Gibbs & The Professionals", "Chapter Three", 1978 },
{ "Junior Delgado", "Sons Of Slaves", 1977 },
{ "Konshens", "Gun Shot A Fire", 2012 },
{ "Lee \"Scratch\" Perry & The Upsetters", "I Am A Madman", 1986 },
{ "Lee \"Scratch\" Perry & The Full Experience", "Disco Devil", 1977 },
{ "The Upsetters", "Grumblin' Dub", 1977 },
{ "Tommy Lee Sparta", "Psycho", 2012 },
{ "Vybz Kartel feat. Popcaan", "We Never Fear Dem", 2011 },
{ "Yellowman", "Nobody Move, Nobody Get Hurt", 1984 },
{ "Protoje", "Kingston Be Wise", 2012 },
{ "Demarco", "Loyal, Royals Remix", 2014 },
{ "Busy Signal feat. Damian \"Jr. Gong\" Marley", "Kingston Town, Remix", 2012 },
{ "I-Octane", "Topic of the Day", 2011 },
{ "Vybz Kartel", "Addi Truth", 2014 },
{ "Lee \"Scratch\" Perry", "Money Come and Money Go", 2010 },
{ "Lee \"Scratch\" Perry", "Roast Fish & Cornbread", 1978 },
{ "Danny Hensworth", "Mr. Money Man", 1978 },
};
static struct song_info_t non_stop_pop_songs[] = {
{ "All Saints", "Pure Shores", 1999 },
{ "Britney Spears", "Gimme More", 2007 },
{ "Corona", "The Rhythm of the Night, Rapino Bros. 7'' Single", 1993 },
{ "Fergie feat. Ludacris", "Glamorous", 2006 },
{ "Hall & Oates", "Adult Education", 1983 },
{ "Jane Child", "Don't Wanna Fall In Love", 1990 },
{ "Kelly Rowland", "Work, Freemasons Remix", 2007 },
{ "Mis-Teeq", "Scandalous", 2003 },
{ "Modjo", "Lady, Hear Me Tonight", 2000 },
{ "N-Joi", "Anthem", 1990 },
{ "Pet Shop Boys", "West End Girls", 1985 },
{ "Rihanna", "Only Girl, In The World", 2010 },
{ "Robyn feat. Kleerup", "With Every Heartbeat", 2007 },
{ "Stardust", "Music Sounds Better With You", 1998 },
{ "Wham!", "Everything She Wants", 1984 },
{ "Amerie", "1 Thing", 2005 },
{ "Robert Howard & Kym Mazelle", "Wait", 1989 },
{ "Sly Fox", "Let's Go All the Way", 1985 },
{ "Taylor Dayne", "Tell It to My Heart", 1987 },
{ "Living In A Box", "Living In A Box", 1987 },
{ "INXS", "New Sensation", 1988 },
{ "Bobby Brown", "On Our Own", 1989 },
{ "Bronski Beat", "Smalltown Boy", 1984 },
{ "Naked Eyes", "Promises, Promises", 1983 },
{ "Simply Red", "Something Got Me Started, Hurley's House Mix", 1991 },
{ "Sneaker Pimps", "6 Underground", 1996 },
{ "Backstreet Boys", "I Want It That Way", 1999 },
{ "Jamiroquai", "Alright", 1996 },
{ "Morcheeba", "Tape Loop, Shortcheeba Mix", 1996 },
{ "Moloko", "The Time Is Now", 2000 },
{ "Gorillaz feat. De La Soul", "Feel Good Inc.", 2005 },
{ "Robbie Williams & Kylie Minogue", "Kids", 2000 },
{ "Dirty Vegas", "Days Go By", 2001 },
{ "Cassie", "Me & U", 2006 },
{ "Maroon 5 feat. Christina Aguilera", "Moves Like Jagger", 2011 },
{ "M.I.A.", "Bad Girls", 2012 },
{ "M83", "Midnight City", 2011 },
{ "Lady Gaga", "Applause", 2013 },
{ "Mike Posner", "Cooler Than Me", 2010 },
{ "Lorde", "Tennis Court", 2013 },
{ "The Black Eyed Peas", "Meet Me Halfway", 2009 },
{ "Real Life", "Send Me An Angel '89", 1989 },
};
static struct song_info_t east_los_songs[] = {
{ "Hechizeros Band", "El Sonidito", 2008 },
{ "Los Buitres de Culiacan", "El Cocaino", 2012 },
{ "Mexican Institute of Sound", "Es-Toy", 2012 },
{ "Niña Dioz", "Criminal Sound, El Hijo De La Cumbia Remix", 2010 },
{ "La Vida Bohème", "Radio Capital", 2011 },
{ "Fandango", "Autos, Moda y Rock and Roll", 1987 },
{ "Don Cheto", "El Tatuado", 2007 },
{ "La Sonora Dinamita", "Se Me Perdió La Cadenita", 1978 },
{ "Fiebre de Jack", "She's A Tease", 2010 },
{ "Maldita Vecindad", "Pachuco", 1991 },
{ "Jessy Bulbo", "Maldito", 2007 },
{ "Milkman", "Fresco", 2012 },
{ "La Liga ft. Alika", "Tengo El Don", 2012 },
{ "Los Tigres Del Norte", "La Granja", 2009 },
{ "Los Ángeles Negros", "El Rey Y Yo", 1970 },
};
static struct song_info_t worldwide_songs[] = {
{ "Cashmere Cat", "Mirror Maru", 2012 },
{ "The Hics", "Cold Air", 2013 },
{ "inc.", "The Place", 2013 },
{ "Trickski", "Beginning", 2011 },
{ "Mala", "Ghost", 2012 },
{ "Swindle", "Forest Funk", 2012 },
{ "Tom Browne", "Throw Down", 1979 },
{ "Donald Byrd", "You And The Music", 1975 },
{ "Candido", "Thousand Finger Man", 1970 },
{ "Toro Y Moi", "Harm in Change", 2013 },
{ "Kyodai", "Breaking", 2012 },
{ "Django Django", "Waveforms", 2011 },
{ "The Gaslamp Killer", "Nissim", 2012 },
{ "Owiny Sigoma Band", "Harpoon Land", 2013 },
{ "Guts", "Brand New Revolution", 2011 },
{ "Yuna", "Live Your Life, MELO-X MOTHERLAND GOD MIX", 2012 },
{ "Tucillo & Kiko Navarro feat. Amor", "Lovery, Slow Cuban Vibe Mix", 2012 },
{ "Richard Spaven", "1759, Outro", 2010 },
{ "Hackman", "Forgotten Notes", 2012 },
{ "Sinkane feat. Salvatore Principato", "Shark Week", 2014 },
{ "William Onyeabor", "Body & Soul", 1980 },
{ "Four Tet", "Kool FM", 2013 },
{ "Mount Kimbie", "Made To Stray", 2013 },
{ "Anushka", "World in a Room", 2014 },
{ "Smokey Robinson", "Why You Wanna See My Bad Side?", 1978 },
{ "Randy Crawford", "Street Life", 1979 },
{ "Flume", "What You Need", 2012 },
{ "Earl Sweatshirt feat. Vince Staples & Casey Veggies", "Hive", 2013 },
{ "Portishead", "Numb", 1994 },
{ "Jon Wayne", "Black Magic", 2013 },
{ "Roman GianArthur", "I-69", 2013 },
{ "Lion Babe", "Treat Me Like Fire", 2013 },
{ "Dam-Funk", "Killdat", 2009 },
{ "Jamie Lidell", "Runaway", 2014 },
{ "CHVRCHES", "Recover, Cid Rim Remix", 2013 },
{ "Jimmy Edgar", "Let Yrself Be", 2012 },
{ "Clap! Clap!", "Viajero", 2014 },
{ "Maga Bo feat. Rosangela Macedo and Marcelo Yuka", "No Balanço da Canoa", 2012 },
};
static struct song_info_t channel_x_songs[] = {
{ "Agent Orange", "Bored of You", 1980 },
{ "Black Flag", "My War", 1984 },
{ "Circle Jerks", "Rock House", 1985 },
{ "Fear", "The Mouth Don't Stop, The Trouble With Women Is", 1985 },
{ "OFF!", "What's Next", 2013 },
{ "Adolescents", "Amoeba", 1981 },
{ "Descendents", "Pervert", 1985 },
{ "The Germs", "Lexicon Devil", 1978 },
{ "The Weirdos", "Life of Crime", 1977 },
{ "T.S.O.L.", "Abolish Government/Silent Majority", 1981 },
{ "Youth Brigade", "Blown Away", 1983 },
{ "Suicidal Tendencies", "Subliminal", 1983 },
{ "D.O.A.", "The Enemy", 1980 },
{ "MDC", "John Wayne Was a Nazi", 1980 },
{ "The Zeros", "Don't Push Me Around", 1980 },
{ "X", "Los Angeles", 1980 },
{ "D.R.I.", "I Don't Need Society", 1985 },
{ "Redd Kross", "Linda Blair", 1982 },
};
static struct song_info_t radio_mirror_park_songs[] = {
{ "Battle Tapes", "Feel the Same", 2012 },
{ "Dan Croll", "From Nowhere, Baardsen Remix", 2012 },
{ "DJ Mehdi", "Lucky Boy, Outlines Remix", 2006 },
{ "Feathers", "Dark Matter", 2013 },
{ "Jai Paul", "Jasmine, Demo Version", 2012 },
{ "Living Days", "Little White Lie", 2010 },
{ "Miami Horror", "Sometimes", 2009 },
{ "Tony Castles", "Heart In The Pipes, KAUF Remix", 2011 },
{ "Toro Y Moi", "So Many Details", 2012 },
{ "Twin Shadow", "Shooting Holes", 2010 },
{ "Twin Shadow", "Old Love / New Love", 2013 },
{ "Y.A.C.H.T.", "Psychic City, Classixx Remix", 2009 },
{ "Black Strobe", "Boogie in Zero Gravity", 2012 },
{ "Age of Consent", "Colours", 2013 },
{ "Favored Nations", "The Set Up", 2013 },
{ "Neon Indian", "Change Of Coast", 2013 },
{ "Nite Jewel", "Nowhere To Go", 2013 },
{ "Yeasayer", "Don't Come Close", 2013 },
{ "The Chain Gang of 1974", "Sleepwalking", 2013 },
{ "Poolside", "Do You Believe?", 2010 },
{ "The C90s", "Shine A Light, Flight Facilities Remix", 2010 },
{ "HEALTH", "High Pressure Dave", 2013 },
{ "The Ruby Suns", "In Real Life", 2013 },
{ "Neon Indian", "Polish Girl", 2011 },
{ "Mitzi", "Truly Alive", 2013 },
{ "KAUF", "When You're Out", 2013 },
{ "Panama", "Always", 2014 },
{ "Twin Shadow", "Forget", 2010 },
{ "!!!", "One Girl/One Boy", 2013 },
{ "SBTRKT feat. Roses Gabor", "Pharaohs", 2011 },
{ "Yeasayer", "O.N.E.", 2010 },
{ "Toro Y Moi", "New Beat", 2011 },
{ "Niki and the Dove", "The Drummer", 2011 },
{ "Little Dragon", "Crystalfilm", 2011 },
{ "Hot Chip", "Flutes", 2012 },
{ "Dom", "Living In America", 2010 },
{ "Holy Ghost!", "Hold On", 2011 },
{ "Scenic", "Mesmerised", 2013 },
{ "Cut Copy", "Strangers in the Wind", 2008 },
{ "Age of Consent", "Heartbreak", 2012 },
};
static struct song_info_t vinewood_boulevard_songs[] = {
{ "Wavves", "Nine Is God", 2013 },
{ "FIDLAR", "Cocaine", 2013 },
{ "Bass Drum of Death", "Crawling After You", 2013 },
{ "Hot Snakes", "This Mystic Decade", 2004 },
{ "Moon Duo", "Sleepwalker", 2012 },
{ "Sam Flax", "Fire Doesn't Burn Itself", 2012 },
{ "Shark?", "California Grrls", 2013 },
{ "The Black Angels", "Black Grease", 2005 },
{ "METZ", "Wet Blanket", 2012 },
{ "Ceremony", "Hysteria", 2012 },
{ "Ty Segall Band", "Diddy Wah Diddy", 2012 },
{ "Thee Oh Sees", "The Dream", 2011 },
{ "The Men", "Turn It Around", 2012 },
{ "Bleached", "Next Stop", 2013 },
{ "JEFF the Brotherhood", "Sixpack", 2012 },
{ "Coliseum", "Used Blood", 2013 },
{ "The Soft Pack", "Answer to Yourself", 2009 },
{ "The Orwells", "Who Needs You", 2013 },
{ "Nobunny", "Gone For Good", 2010 },
{ "Mind Spiders", "Fall in Line", 2012 },
};
static struct song_info_t soulwax_songs[] = {
{ "Palmbomen", "Stock, Soulwax Remix", 2013 },
{ "Fatal Error", "Fatal Error", 1988 },
{ "Supersempfft", "Let's Beam Him Up", 1979 },
{ "Mim Suleiman", "Mingi", 2010 },
{ "FKClub", "The Strange Art, Inflagranti Remix", 2013 },
{ "Matias Aguayo", "El Sucu Tucu", 2013 },
{ "Daniel Avery", "Naive Response", 2013 },
{ "Joe Goddard feat. Valentina", "Gabriel, Soulwax Remix", 2012 },
{ "Daniel Maloso", "Body Music, Original Mix", 2012 },
{ "Green Velvet & Harvard Bass", "Lazer Beams", 2012 },
{ "Zombie Nation", "Tryouts", 2012 },
{ "Tom Rowlands", "Nothing But Pleasure", 2013 },
{ "Jackson and His Computerband", "Arp #1", 2013 },
{ "Goose", "Synrise, Soulwax Remix", 2013 },
{ "Transistorcake", "Mr. Croissant Taker", 2013 },
{ "Tiga", "Plush, Jacques Lu Cont Remix", 2012 },
{ "The Hacker", "Shockwave, Gesaffelstein Remix", 2012 },
{ "Pulp", "After You, Soulwax Remix", 2013 },
};
static struct song_info_t flylo_songs[] = {
{ "Flying Lotus feat. Niki Randa", "Getting There", 2012 },
{ "Clams Casino", "Crystals", 2013 },
{ "Flying Lotus", "Crosswerved", 2013 },
{ "Flying Lotus", "Be Spin", 2013 },
{ "Flying Lotus feat. Erykah Badu", "See Thru To U", 2013 },
{ "Flying Lotus", "The Diddler", 2013 },
{ "Flying Lotus", "Computer Face Rmx", 2011 },
{ "Hudson Mohawke", "100hm", 2013 },
{ "Flying Lotus feat. Niki Randa", "The Kill", 2013 },
{ "Tyler, the Creator", "Garbage", 2013 },
{ "Outkast", "Elevators, Me & You", 1996 },
{ "Captain Murphy", "Evil Grin", 2013 },
{ "Flying Lotus", "Catapult Man", 2013 },
{ "Dabrye", "Encoded Flow", 2006 },
{ "Machinedrum", "She Died There", 2011 },
{ "DJ Rashad", "It's Wack", 2013 },
{ "Thundercat", "Oh Sheit It's X", 2013 },
{ "Flying Lotus", "Stonecutters", 2013 },
{ "Shadow Child", "23", 2012 },
{ "Kingdom", "Stalker Ha", 2011 },
{ "Aphex Twin", "Windowlicker", 1999 },
{ "Curtis Mayfield", "Eddie You Should Know Better", 1972 },
{ "Doris", "You Never Come Closer", 1970 },
{ "Flying Lotus feat. Krayzie Bone", "Medication Medication", 2014 },
{ "XXYYXX", "Work Title: What We Want", 2014 },
{ "Lapalux", "Make Money", 2014 },
{ "The Gaslamp Killer", "Shred You To Bits", 2014 },
{ "Mono/Poly & Thundercat", "B Adams", 2014 },
{ "Flying Lotus", "Osaka Trade", 2013 },
{ "DOOM", "Masquatch", 2014 },
{ "Flying Lotus", "Early Mountain", 2014 },
{ "Dimlite", "Into Vogon Skulls", 2012 },
{ "KNOWER", "Fuck the Makeup, Skip the Shower", 2010 },
{ "Kaskade", "4 AM, Araabmuzik Remix", 2006 },
};
static struct song_info_t the_lab_songs[] = {
{ "Gangrene feat. Samuel T. Herring & Earl Sweatshirt", "Play It Cool", 2015 },
{ "Ab-Soul feat. Aloe Blacc", "Trouble", 2015 },
{ "Tunde Adebimpe feat. Sal P & Sinkane", "Speedline Miracle Masterpiece", 2015 },
{ "MC Eiht & Freddie Gibbs feat. Kokane", "Welcome to Los Santos", 2015 },
{ "Phantogram", "K.Y.S.A", 2015 },
{ "Vybz Kartel", "Fast Life", 2015 },
{ "King Avriel feat. A$AP Ferg", "20's 50's 100's", 2015 },
{ "MNDR feat. Killer Mike", "Lock & Load", 2015 },
{ "Popcaan feat. Freddie Gibbs", "Born Bad", 2015 },
{ "E-40 feat. Dam-Funk & Ariel Pink", "California", 2015 },
{ "Wavves", "Leave", 2015 },
{ "Curren$y & Freddie Gibbs", "Fetti", 2015 },
{ "Little Dragon", "Wanderer", 2015 },
};
static struct radio_station_info_t radio_stations[] = {
{ "Radio Los Santos", SONGS(radio_los_santos) },
{ "Space 103.2", SONGS(space_103_2) },
{ "West Coast Classics", SONGS(west_cost_classics) },
{ "Rebel Radio", SONGS(rebel_radio) },
{ "Los Santos Rock Radio", SONGS(los_santos_rock_radio) },
{ "The Lowdown 91.1", SONGS(the_lowdown) },
{ "The Blue Ark", SONGS(the_blue_ark) },
{ "Non-Stop-Pop FM", SONGS(non_stop_pop) },
{ "East Los FM", SONGS(east_los) },
{ "WorldWide FM", SONGS(worldwide) },
{ "Channel X", SONGS(channel_x) },
{ "Radio Mirror Park", SONGS(radio_mirror_park) },
{ "Vinewood Boulevard Radio", SONGS(vinewood_boulevard) },
{ "Soulwax FM", SONGS(soulwax) },
{ "FlyLo FM", SONGS(flylo) },
{ "The Lab", SONGS(the_lab) },
};
#define N_STATIONS sizeof(radio_stations)/sizeof(struct radio_station_info_t)
void
radio_stations_init(void)
{
for (uint32_t i = 0; i < N_STATIONS; i++)
radio_stations[i].id = i;
}
uint32_t
n_radio_stations(void)
{
return N_STATIONS;
}
const radio_station_info_t *
get_radio_stations(uint32_t id)
{
return &radio_stations[id];
}

View File

@ -0,0 +1,18 @@
#include <cstdint>
struct song_info_t {
const char *artist;
const char *name;
uint32_t year;
};
struct radio_station_info_t {
const char *name;
song_info_t *songs;
uint32_t n_songs;
uint32_t id;
};
void radio_stations_init(void);
uint32_t n_radio_stations(void);
const radio_station_info_t *get_radio_stations(uint32_t id);

119
sample-apps/services.hpp Normal file
View File

@ -0,0 +1,119 @@
#include <vsomeip/vsomeip.hpp>
#include <sstream>
#define RADIO_SERVICE_ID 0x1000
#define RADIO_INSTANCE_ID 1
#define RADIO_IS_PLAYING_METHOD_ID 1
#define RADIO_SET_PLAYING_METHOD_ID 2
#define RADIO_GET_VOLUME_METHOD_ID 3
#define RADIO_CHANGE_VOLUME_METHOD_ID 4
#define RADIO_SWITCH_STATION_METHOD_ID 5
#define RADIO_EVENTGROUP_ID 0x4001
#define RADIO_VOLUME_EVENT_ID 0x8000 + 1
#define RADIO_STATION_EVENT_ID 0x8000 + 2
#define RADIO_SONG_EVENT_ID 0x8000 + 3
#define RADIO_ARTIST_EVENT_ID 0x8000 + 4
#define ENGINE_SERVICE_ID 0x1001
#define ENGINE_INSTANCE_ID 1
#define ENGINE_GET_REVERSE_METHOD_ID 1
#define ENGINE_EVENTGROUP_ID 0x4002
#define ENGINE_REVERSE_EVENT_ID 0x8000 + 1
static uint32_t inline
payload_get_arg(std::shared_ptr<vsomeip::payload> its_payload)
{
vsomeip::byte_t *data = its_payload->get_data();
vsomeip::length_t l = its_payload->get_length();
if (l < 4)
return 0;
return (uint32_t)data[0]<< 24 | data[1]<< 16 | data[2]<< 8 | data[3];
}
static std::string inline
payload_get_string(std::shared_ptr<vsomeip::payload> its_payload)
{
vsomeip::byte_t *data = its_payload->get_data();
vsomeip::length_t l = its_payload->get_length();
std::stringstream ss;
for (vsomeip::length_t i=0; i<l; i++)
ss << (unsigned char)data[i];
return ss.str();
}
static std::shared_ptr<vsomeip::payload> inline
payload_with_arg(uint32_t arg)
{
std::shared_ptr<vsomeip::payload> its_payload = vsomeip::runtime::get()->create_payload();
std::vector<vsomeip::byte_t> its_payload_data;
its_payload_data.push_back((arg >> 24) & 0xff);
its_payload_data.push_back((arg >> 16) & 0xff);
its_payload_data.push_back((arg >> 8) & 0xff);
its_payload_data.push_back((arg >> 0) & 0xff);
its_payload->set_data(its_payload_data);
return its_payload;
}
static std::shared_ptr<vsomeip::payload> inline
payload_with_string(std::string arg)
{
std::shared_ptr<vsomeip::payload> its_payload = vsomeip::runtime::get()->create_payload();
std::vector<vsomeip::byte_t> its_payload_data;
for (vsomeip::byte_t i=0; i<arg.size(); i++) {
its_payload_data.push_back(arg[i]);
}
its_payload->set_data(its_payload_data);
return its_payload;
}
static std::shared_ptr< vsomeip::message > inline
new_request (uint32_t method, uint32_t arg)
{
std::shared_ptr< vsomeip::message > request;
request = vsomeip::runtime::get()->create_request();
request->set_service(RADIO_SERVICE_ID);
request->set_instance(RADIO_INSTANCE_ID);
request->set_method(method);
std::shared_ptr<vsomeip::payload> its_payload = payload_with_arg (arg);
request->set_payload(its_payload);
return request;
}
static uint32_t inline
get_arg0(const std::shared_ptr<vsomeip::message> _request) {
std::shared_ptr<vsomeip::payload> its_payload = _request->get_payload();
return payload_get_arg(its_payload);
}
static std::string inline
get_arg0_string(const std::shared_ptr<vsomeip::message> _request) {
std::shared_ptr<vsomeip::payload> its_payload = _request->get_payload();
return payload_get_string(its_payload);
}
static std::shared_ptr<vsomeip::message> inline
response (const std::shared_ptr<vsomeip::message> &_request,
uint32_t arg)
{
std::shared_ptr<vsomeip::message> its_response = vsomeip::runtime::get()->create_response(_request);
std::shared_ptr<vsomeip::payload> its_payload = payload_with_arg (arg);
its_response->set_payload(its_payload);
return its_response;
}

31
tinyrepo/README.rst Normal file
View File

@ -0,0 +1,31 @@
Tinyrepo
========
This folder contains some utility scripts that are used to sample images that
can be easily downloaded and used.
## Creating sample images
The sample images are a sub-set of the images one can build using the osbuild
manifest present in this repository.
The creating of the images is handled by the `build_images.sh` shell script
which simply calls sequentially different `make` commands, then compress the
resulting images and places them in a timestamped directory available to apache.
Finally, it creates a symlink between the newest folder and a `latest` folder,
thus giving a stable location where one can find the most recently built images.
## Cron job
The `build_images.sh` shell script present in this folder are ran via the
following cron job configuration:
::
0 2 * * 1 sh /path/to/automotive-sig/tinyrepo/build_images.sh /path/to/clone/of/automotive-sig/osbuild-manifests/ /path/to/root/folder/in/apache
This allows to build new images weekly.

46
tinyrepo/build_images.sh Normal file
View File

@ -0,0 +1,46 @@
#!/bin/bash
d=`date "+%Y%m%d"`
AUTOSIGREPO=$1
HTMLROOT=$2
pushd $AUTOSIGREPO/osbuild-manifests
# Let's update the git repo
git pull --rebase
# Clean all all cached data
make clean
rm *.log || true
rm *.img || true
rm *.qcow2 || true
rm *.img.xz || true
rm *.qcow2.xz || true
dnf clean all
sudo dnf clean all
# Build all images
sudo make cs9-rpi4-neptune-ostree.aarch64.img > cs9-rpi4-neptune-ostree.aarch64.log
sudo make cs9-rpi4-neptune-regular.aarch64.img > cs9-rpi4-neptune-regular.aarch64.log
sudo make cs9-qemu-developer-regular.aarch64.qcow2 > cs9-qemu-developer-regular.aarch64.log
sudo make cs9-qemu-developer-regular.aarch64.oci.tar > cs9-qemu-developer-regular.aarch64.oci.tar.log
sudo make osbuildvm-images > osbuildvm-images.log
# Compact them
xz cs9-rpi4-neptune-ostree.aarch64.img &
xz cs9-rpi4-neptune-regular.aarch64.img &
xz cs9-qemu-developer-regular.aarch64.qcow2 &
tar cfz osbuildvm-images.tar.gz _build/osbuildvm-aarch64.* &
wait
popd
# Move the images to apache
mkdir -p $HTMLROOT/images/$d
cp $AUTOSIGREPO/osbuild-manifests/*.xz $HTMLROOT/images/$d/
cp $AUTOSIGREPO/osbuild-manifests/*.tar $HTMLROOT/images/$d/
cp $AUTOSIGREPO/osbuild-manifests/*.tar.gz $HTMLROOT/images/$d/
# Update the `latest` symlink
ln -nsf $d $HTMLROOT/images/latest

20
tinyrepo/build_repos.sh Normal file
View File

@ -0,0 +1,20 @@
#!/bin/bash
d=`date "+%Y%m%d"`
AUTOSIGREPO=$1
HTMLROOT=$2
python $AUTOSIGREPO/tinyrepo/initiate_repo.py \
$HTMLROOT/cs9-stream/ \
--pkgslist=$HTMLROOT/cs9-stream/pkgslist_$d
for arch in aarch64 x86_64
do
mkdir -p $HTMLROOT/cs9-stream/$arch/$d
pushd $HTMLROOT/cs9-stream/$arch/$d
createrepo_c ../packages/ -o . -i ../../pkgslist_$d
popd
# Update the `latest` symlink
ln -nsf $d $HTMLROOT/cs9-stream/$arch/latest
done

145
tinyrepo/initiate_repo.py Normal file
View File

@ -0,0 +1,145 @@
#!/usr/bin/python3
"""
This script queries content resolver at: https://tiny.distro.builders to retrieve
a list of all the packages of interest for the automotive SIG.
Requirements:
- python-requests
"""
import argparse
import os
import re
import sys
import requests
environments = [
"https://tiny.distro.builders/workload--automotive-c9s-workload-development--automotive-c9s-env-minimum--automotive-c9s-repositories--aarch64.json",
"https://tiny.distro.builders/workload--automotive-c9s-workload-minimum--automotive-c9s-env-minimum--automotive-c9s-repositories--aarch64.json",
"https://tiny.distro.builders/workload--automotive-c9s-workload-neptune--automotive-c9s-env-minimum--automotive-c9s-repositories--aarch64.json",
"https://tiny.distro.builders/workload--automotive-c9s-workload-ostree--automotive-c9s-env-minimum--automotive-c9s-repositories--aarch64.json",
"https://tiny.distro.builders/workload--automotive-c9s-workload-podman--automotive-c9s-env-minimum--automotive-c9s-repositories--aarch64.json",
]
cs_urls = [
"http://mirror.stream.centos.org/9-stream/AppStream/{arch}/os/Packages/{nvr}",
"http://mirror.stream.centos.org/9-stream/BaseOS/{arch}/os/Packages/{nvr}",
"http://mirror.stream.centos.org/9-stream/CRB/{arch}/os/Packages/{nvr}",
"https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/BaseOS/{arch}/os/Packages/{nvr}",
"https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/AppStream/{arch}/os/Packages/{nvr}",
"https://composes.stream.centos.org/development/latest-CentOS-Stream/compose/CRB/{arch}/os/Packages/{nvr}",
]
epoch_re = re.compile("-\d+:")
def get_packages():
""" Queries content resolver and returns a tuple of two set, the first
set contains the name of every package, the second set contains the NVR
of every package.
"""
packages_set = set()
nvr_set = set()
for env in environments:
req = requests.get(env)
if not req.ok:
print(f"Failed to retrieve info from {env}")
continue
data = req.json()
data = data["data"]
for key in ("pkg_env_ids", "pkg_added_ids"):
for pkg in data[key]:
name = pkg.rsplit("-", 2)[0]
# Drop the architecture
nvr = pkg.rsplit(".", 1)[0]
# Drop epoch if there is one
if len(epoch_re.findall(nvr)) == 1:
for mat in epoch_re.findall(nvr):
nvr = nvr.replace(mat, "-")
elif len(epoch_re.findall(nvr)) > 1:
print("More than one -\d: matched in {nvr}")
packages_set.add(name)
nvr_set.add(nvr)
return (packages_set, nvr_set)
def download_nvrs(folder, nvrs):
""" Queries the CentOS-Stream mirror and download the package specified by
the given NVR.
"""
notfound = 0
out_files = []
for nvr in sorted(nvrs):
for arch in ("x86_64", "aarch64"):
out_filename = f"{nvr}.{arch}.rpm"
output_folder = os.path.join(folder, arch, "packages")
out_path = os.path.join(output_folder, out_filename)
if not os.path.exists(output_folder):
os.makedirs(output_folder)
if os.path.exists(out_path):
out_files.append(out_filename)
continue
found = False
for url in cs_urls:
nurl = f"{url}.{arch}.rpm".format(arch=arch, nvr=nvr)
req = requests.head(nurl)
# print(req.status_code, url)
if req.ok:
found = True
out_files.append(out_filename)
req = requests.get(nurl)
with open(out_path, "wb") as stream:
stream.write(req.content)
break
else:
# print(req.status_code, nurl)
# Check if it's a noarch RPM
nurl = f"{url}.noarch.rpm".format(arch=arch, nvr=nvr)
req = requests.head(nurl)
if req.ok:
found = True
out_files.append(f"{nvr}.noarch.rpm")
req = requests.get(nurl)
with open(out_path, "wb") as stream:
stream.write(req.content)
break
# else:
# print(req.status_code, nurl)
if not found:
print(f"Package {nvr}.{arch} not found on the mirrors")
notfound += 1
print(f"{notfound} packages not found on the mirrors")
return out_files
def parse_arguments(args):
"""Parse the CLI arguments and return the corresponding argparse object.
"""
parser = argparse.ArgumentParser(description="Instantiate george")
parser.add_argument("folder", nargs="?", default=".",
help="Folder in which to put the downloaded RPMs")
parser.add_argument("--pkgslist",
help="Name of the file in which to output the list of all the RPMs found")
return parser.parse_args(args)
if __name__ == "__main__":
args = parse_arguments(sys.argv[1:])
pkgs, nvrs = get_packages()
# print("-", "\n- ".join(sorted(pkgs)))
print(len(pkgs), "packages found")
print("Corresponding to", len(nvrs), "nvr")
out_files = download_nvrs(args.folder, nvrs)
if args.pkgslist:
with open(args.pkgslist, "w") as stream:
stream.write("\n".join(out_files))