commit a8d8515b7548cc937beb48daa7d475f42ab3421a Author: James Pace Date: Tue Aug 23 20:51:43 2022 -0400 Import from https://gitlab.com/CentOS/automotive/sample-images Commit: a95b833c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..33842bf --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +site/ +image_output/ +osbuild_store/ + +*~ +*.swp diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..d1ec923 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,9 @@ +include: + - project: 'redhat/edge/ci-cd/pipe-x/pipelines-as-code' + ref: gitlab-ci + file: + - '/.gitlab/trigger.yml' + +stages: + - trigger + diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 0000000..3385a49 --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,9 @@ +[allowlist] + description = "This repository contains a few passwords for demo accounts, it is fine" + paths = [ + '''ignore\.d''', + ] + files = [ + '''*\.mpp\.json$''' + ] + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..95d9d18 --- /dev/null +++ b/LICENSE @@ -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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..fd69cc7 --- /dev/null +++ b/README.md @@ -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) diff --git a/containers/kernel-dev/Containerfile b/containers/kernel-dev/Containerfile new file mode 100644 index 0000000..7658d5e --- /dev/null +++ b/containers/kernel-dev/Containerfile @@ -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"] diff --git a/image-builds.json b/image-builds.json new file mode 100644 index 0000000..8a4e525 --- /dev/null +++ b/image-builds.json @@ -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" + ] + } + } + } diff --git a/osbuild-manifests/.gitignore b/osbuild-manifests/.gitignore new file mode 100644 index 0000000..426b97a --- /dev/null +++ b/osbuild-manifests/.gitignore @@ -0,0 +1,2 @@ +*.json +!*.mpp.json diff --git a/osbuild-manifests/Makefile b/osbuild-manifests/Makefile new file mode 100644 index 0000000..a32ae18 --- /dev/null +++ b/osbuild-manifests/Makefile @@ -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 $< diff --git a/osbuild-manifests/distro/cs9.ipp.yml b/osbuild-manifests/distro/cs9.ipp.yml new file mode 100644 index 0000000..e27dff9 --- /dev/null +++ b/osbuild-manifests/distro/cs9.ipp.yml @@ -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 diff --git a/osbuild-manifests/files/engine.container b/osbuild-manifests/files/engine.container new file mode 100644 index 0000000..f04c192 --- /dev/null +++ b/osbuild-manifests/files/engine.container @@ -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 diff --git a/osbuild-manifests/files/etc/gdm/custom-wayland.conf b/osbuild-manifests/files/etc/gdm/custom-wayland.conf new file mode 100644 index 0000000..f28188e --- /dev/null +++ b/osbuild-manifests/files/etc/gdm/custom-wayland.conf @@ -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 diff --git a/osbuild-manifests/files/etc/gdm/custom-xorg.conf b/osbuild-manifests/files/etc/gdm/custom-xorg.conf new file mode 100644 index 0000000..cb95e0f --- /dev/null +++ b/osbuild-manifests/files/etc/gdm/custom-xorg.conf @@ -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 diff --git a/osbuild-manifests/files/etc/systemd/system/init-neptune-session@.service b/osbuild-manifests/files/etc/systemd/system/init-neptune-session@.service new file mode 100644 index 0000000..783c456 --- /dev/null +++ b/osbuild-manifests/files/etc/systemd/system/init-neptune-session@.service @@ -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 \ No newline at end of file diff --git a/osbuild-manifests/files/radio.container b/osbuild-manifests/files/radio.container new file mode 100644 index 0000000..f1b6bbb --- /dev/null +++ b/osbuild-manifests/files/radio.container @@ -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 diff --git a/osbuild-manifests/files/storage.conf b/osbuild-manifests/files/storage.conf new file mode 100644 index 0000000..dc3722b --- /dev/null +++ b/osbuild-manifests/files/storage.conf @@ -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" diff --git a/osbuild-manifests/files/usr/lib64/neptune3/am-config-neptune.yaml b/osbuild-manifests/files/usr/lib64/neptune3/am-config-neptune.yaml new file mode 100644 index 0000000..ecb7645 --- /dev/null +++ b/osbuild-manifests/files/usr/lib64/neptune3/am-config-neptune.yaml @@ -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" \ No newline at end of file diff --git a/osbuild-manifests/files/usr/share/applications/neptune3-ui-xorg.desktop b/osbuild-manifests/files/usr/share/applications/neptune3-ui-xorg.desktop new file mode 100644 index 0000000..817c635 --- /dev/null +++ b/osbuild-manifests/files/usr/share/applications/neptune3-ui-xorg.desktop @@ -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 \ No newline at end of file diff --git a/osbuild-manifests/files/usr/share/applications/neptune3-ui.desktop b/osbuild-manifests/files/usr/share/applications/neptune3-ui.desktop new file mode 100644 index 0000000..5e28c33 --- /dev/null +++ b/osbuild-manifests/files/usr/share/applications/neptune3-ui.desktop @@ -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 \ No newline at end of file diff --git a/osbuild-manifests/files/usr/share/gnome-session/sessions/neptune-xorg.session b/osbuild-manifests/files/usr/share/gnome-session/sessions/neptune-xorg.session new file mode 100644 index 0000000..b085438 --- /dev/null +++ b/osbuild-manifests/files/usr/share/gnome-session/sessions/neptune-xorg.session @@ -0,0 +1,3 @@ +[GNOME Session] +Name=Neptune XOrg +RequiredComponents=mutter;neptune3-ui-xorg; \ No newline at end of file diff --git a/osbuild-manifests/files/usr/share/gnome-session/sessions/neptune.session b/osbuild-manifests/files/usr/share/gnome-session/sessions/neptune.session new file mode 100644 index 0000000..fbf0a52 --- /dev/null +++ b/osbuild-manifests/files/usr/share/gnome-session/sessions/neptune.session @@ -0,0 +1,3 @@ +[GNOME Session] +Name=Neptune +RequiredComponents=mutter;neptune3-ui; \ No newline at end of file diff --git a/osbuild-manifests/files/usr/share/wayland-sessions/neptune-wayland.desktop b/osbuild-manifests/files/usr/share/wayland-sessions/neptune-wayland.desktop new file mode 100644 index 0000000..de97c29 --- /dev/null +++ b/osbuild-manifests/files/usr/share/wayland-sessions/neptune-wayland.desktop @@ -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 \ No newline at end of file diff --git a/osbuild-manifests/files/usr/share/xsessions/neptune-xorg.desktop b/osbuild-manifests/files/usr/share/xsessions/neptune-xorg.desktop new file mode 100644 index 0000000..6656d71 --- /dev/null +++ b/osbuild-manifests/files/usr/share/xsessions/neptune-xorg.desktop @@ -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 \ No newline at end of file diff --git a/osbuild-manifests/images/container.mpp.yml b/osbuild-manifests/images/container.mpp.yml new file mode 100644 index 0000000..d741808 --- /dev/null +++ b/osbuild-manifests/images/container.mpp.yml @@ -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 diff --git a/osbuild-manifests/images/developer.mpp.yml b/osbuild-manifests/images/developer.mpp.yml new file mode 100644 index 0000000..4f14934 --- /dev/null +++ b/osbuild-manifests/images/developer.mpp.yml @@ -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 diff --git a/osbuild-manifests/images/directboot.csv b/osbuild-manifests/images/directboot.csv new file mode 100644 index 0000000..7e8f63d Binary files /dev/null and b/osbuild-manifests/images/directboot.csv differ diff --git a/osbuild-manifests/images/encrypted.mpp.yml b/osbuild-manifests/images/encrypted.mpp.yml new file mode 100644 index 0000000..29f918a --- /dev/null +++ b/osbuild-manifests/images/encrypted.mpp.yml @@ -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 diff --git a/osbuild-manifests/images/gadget.mpp.yml b/osbuild-manifests/images/gadget.mpp.yml new file mode 100644 index 0000000..5450897 --- /dev/null +++ b/osbuild-manifests/images/gadget.mpp.yml @@ -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 diff --git a/osbuild-manifests/images/minimal.mpp.yml b/osbuild-manifests/images/minimal.mpp.yml new file mode 100644 index 0000000..6a5f5b2 --- /dev/null +++ b/osbuild-manifests/images/minimal.mpp.yml @@ -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 diff --git a/osbuild-manifests/images/neptune.mpp.yml b/osbuild-manifests/images/neptune.mpp.yml new file mode 100644 index 0000000..7c2b767 --- /dev/null +++ b/osbuild-manifests/images/neptune.mpp.yml @@ -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 diff --git a/osbuild-manifests/images/soafee.mpp.yml b/osbuild-manifests/images/soafee.mpp.yml new file mode 100644 index 0000000..4f7246e --- /dev/null +++ b/osbuild-manifests/images/soafee.mpp.yml @@ -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 diff --git a/osbuild-manifests/images/upgrade-demo.mpp.yml b/osbuild-manifests/images/upgrade-demo.mpp.yml new file mode 100644 index 0000000..aca0c6a --- /dev/null +++ b/osbuild-manifests/images/upgrade-demo.mpp.yml @@ -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 diff --git a/osbuild-manifests/include/build-aarch64.ipp.yml b/osbuild-manifests/include/build-aarch64.ipp.yml new file mode 100644 index 0000000..b0ef9eb --- /dev/null +++ b/osbuild-manifests/include/build-aarch64.ipp.yml @@ -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 diff --git a/osbuild-manifests/include/build-x86_64.ipp.yml b/osbuild-manifests/include/build-x86_64.ipp.yml new file mode 100644 index 0000000..3039545 --- /dev/null +++ b/osbuild-manifests/include/build-x86_64.ipp.yml @@ -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 diff --git a/osbuild-manifests/include/build.ipp.yml b/osbuild-manifests/include/build.ipp.yml new file mode 100644 index 0000000..d4c4cf8 --- /dev/null +++ b/osbuild-manifests/include/build.ipp.yml @@ -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 diff --git a/osbuild-manifests/include/defaults.ipp.yml b/osbuild-manifests/include/defaults.ipp.yml new file mode 100644 index 0000000..c277ccf --- /dev/null +++ b/osbuild-manifests/include/defaults.ipp.yml @@ -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 diff --git a/osbuild-manifests/include/image-directboot.ipp.yml b/osbuild-manifests/include/image-directboot.ipp.yml new file mode 100644 index 0000000..1be2b19 --- /dev/null +++ b/osbuild-manifests/include/image-directboot.ipp.yml @@ -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 diff --git a/osbuild-manifests/include/image-ostree.ipp.yml b/osbuild-manifests/include/image-ostree.ipp.yml new file mode 100644 index 0000000..ac6579c --- /dev/null +++ b/osbuild-manifests/include/image-ostree.ipp.yml @@ -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 diff --git a/osbuild-manifests/include/image-regular.ipp.yml b/osbuild-manifests/include/image-regular.ipp.yml new file mode 100644 index 0000000..77dce25 --- /dev/null +++ b/osbuild-manifests/include/image-regular.ipp.yml @@ -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 diff --git a/osbuild-manifests/include/image.ipp.yml b/osbuild-manifests/include/image.ipp.yml new file mode 100644 index 0000000..636e40b --- /dev/null +++ b/osbuild-manifests/include/image.ipp.yml @@ -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 diff --git a/osbuild-manifests/include/target-aws.ipp.yml b/osbuild-manifests/include/target-aws.ipp.yml new file mode 100644 index 0000000..64e89f4 --- /dev/null +++ b/osbuild-manifests/include/target-aws.ipp.yml @@ -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: [] \ No newline at end of file diff --git a/osbuild-manifests/include/target-qemu.ipp.yml b/osbuild-manifests/include/target-qemu.ipp.yml new file mode 100644 index 0000000..3ba1623 --- /dev/null +++ b/osbuild-manifests/include/target-qemu.ipp.yml @@ -0,0 +1,2 @@ +version: '2' +pipelines: [] diff --git a/osbuild-manifests/include/target-rpi4.ipp.yml b/osbuild-manifests/include/target-rpi4.ipp.yml new file mode 100644 index 0000000..d626e71 --- /dev/null +++ b/osbuild-manifests/include/target-rpi4.ipp.yml @@ -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 diff --git a/osbuild-manifests/osbuildvm/osbuildvm b/osbuild-manifests/osbuildvm/osbuildvm new file mode 100755 index 0000000..1b41cf7 --- /dev/null +++ b/osbuild-manifests/osbuildvm/osbuildvm @@ -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() diff --git a/osbuild-manifests/osbuildvm/osbuildvm.mpp.yml b/osbuild-manifests/osbuildvm/osbuildvm.mpp.yml new file mode 100644 index 0000000..57bd219 --- /dev/null +++ b/osbuild-manifests/osbuildvm/osbuildvm.mpp.yml @@ -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 diff --git a/osbuild-manifests/runvm b/osbuild-manifests/runvm new file mode 100755 index 0000000..e027045 --- /dev/null +++ b/osbuild-manifests/runvm @@ -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()) diff --git a/osbuild-manifests/tools/create-packagelist.jq b/osbuild-manifests/tools/create-packagelist.jq new file mode 100644 index 0000000..8364fc2 --- /dev/null +++ b/osbuild-manifests/tools/create-packagelist.jq @@ -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)) + } + } +} diff --git a/osbuild-manifests/tools/export-image-aws.sh b/osbuild-manifests/tools/export-image-aws.sh new file mode 100755 index 0000000..b11148f --- /dev/null +++ b/osbuild-manifests/tools/export-image-aws.sh @@ -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) " + 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 < "${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 < "${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} diff --git a/osbuild-manifests/tools/extract-rpms.jq b/osbuild-manifests/tools/extract-rpms.jq new file mode 100644 index 0000000..3b02a9a --- /dev/null +++ b/osbuild-manifests/tools/extract-rpms.jq @@ -0,0 +1,19 @@ +def basenames: + .path | split("/") | last; + +def parseURL: + capture("^((?[^:/?#]+):)?(//(?(?[^/?#:]*)(:(?[0-9]*))?))?(?[^?#]*)(\\?(?([^#]*)))?(#(?(.*)))?"); + +def splitRPM: + capture("(?(.*))\\.(?[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 diff --git a/osbuild-manifests/tools/generate-deltas b/osbuild-manifests/tools/generate-deltas new file mode 100755 index 0000000..aa0a592 --- /dev/null +++ b/osbuild-manifests/tools/generate-deltas @@ -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 diff --git a/osbuild-manifests/tools/ot-refs b/osbuild-manifests/tools/ot-refs new file mode 100755 index 0000000..4e873cc --- /dev/null +++ b/osbuild-manifests/tools/ot-refs @@ -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 "}" diff --git a/osbuild-manifests/tools/runosbuild b/osbuild-manifests/tools/runosbuild new file mode 100755 index 0000000..f626466 --- /dev/null +++ b/osbuild-manifests/tools/runosbuild @@ -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 diff --git a/package_list/cs9-image-manifest.lock.json b/package_list/cs9-image-manifest.lock.json new file mode 100644 index 0000000..f789d7d --- /dev/null +++ b/package_list/cs9-image-manifest.lock.json @@ -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" + ] + } + } +} \ No newline at end of file diff --git a/sample-apps/.gitignore b/sample-apps/.gitignore new file mode 100644 index 0000000..669a440 --- /dev/null +++ b/sample-apps/.gitignore @@ -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 diff --git a/sample-apps/CMakeLists.txt b/sample-apps/CMakeLists.txt new file mode 100644 index 0000000..f301f12 --- /dev/null +++ b/sample-apps/CMakeLists.txt @@ -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 +) diff --git a/sample-apps/COPYING b/sample-apps/COPYING new file mode 100644 index 0000000..d5075a3 --- /dev/null +++ b/sample-apps/COPYING @@ -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. diff --git a/sample-apps/Containerfile.auto-apps b/sample-apps/Containerfile.auto-apps new file mode 100644 index 0000000..d998c76 --- /dev/null +++ b/sample-apps/Containerfile.auto-apps @@ -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 ./ diff --git a/sample-apps/Makefile.container b/sample-apps/Makefile.container new file mode 100644 index 0000000..d99f509 --- /dev/null +++ b/sample-apps/Makefile.container @@ -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 diff --git a/sample-apps/Makefile.rpm b/sample-apps/Makefile.rpm new file mode 100644 index 0000000..b57a9f0 --- /dev/null +++ b/sample-apps/Makefile.rpm @@ -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 diff --git a/sample-apps/README.md b/sample-apps/README.md new file mode 100644 index 0000000..3020fa5 --- /dev/null +++ b/sample-apps/README.md @@ -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). diff --git a/sample-apps/auto-apps.spec.in b/sample-apps/auto-apps.spec.in new file mode 100644 index 0000000..d4b8cb1 --- /dev/null +++ b/sample-apps/auto-apps.spec.in @@ -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 +- Initial version diff --git a/sample-apps/engine-service.cpp b/sample-apps/engine-service.cpp new file mode 100644 index 0000000..4c2d5ec --- /dev/null +++ b/sample-apps/engine-service.cpp @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include + +using namespace std::literals::chrono_literals; + +#include + +#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 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 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 get_reverse_payload() { + return payload_with_arg (in_reverse ? 1 : 0); + } + + void on_get_reverse(const std::shared_ptr &_message) { + std::cout << "ENGINE: Received get_reverse" << std::endl; + std::shared_ptr its_response = vsomeip::runtime::get()->create_response(_message); + + { + std::lock_guard its_lock(main_mutex); + its_response->set_payload(get_reverse_payload()); + } + + app->send(its_response); + } + + void run() { + std::unique_lock 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 payload = get_reverse_payload(); + + app->notify(ENGINE_SERVICE_ID, ENGINE_INSTANCE_ID, ENGINE_REVERSE_EVENT_ID, payload); + } + } + } + +private: + std::shared_ptr 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); +} diff --git a/sample-apps/radio-client.cpp b/sample-apps/radio-client.cpp new file mode 100644 index 0000000..b920e34 --- /dev/null +++ b/sample-apps/radio-client.cpp @@ -0,0 +1,266 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +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 &_event) { + std::unique_lock its_lock(mutex); + volume = get_arg0(_event); + data_changed = true; + condition.notify_one(); +} + +void on_song_message(const std::shared_ptr &_event) { + std::unique_lock its_lock(mutex); + song = get_arg0_string(_event); + data_changed = true; + condition.notify_one(); +} + +void on_artist_message(const std::shared_ptr &_event) { + std::unique_lock its_lock(mutex); + artist = get_arg0_string(_event); + data_changed = true; + condition.notify_one(); +} + +void on_station_message(const std::shared_ptr &_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 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 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 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 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 its_lock(mutex); + if (!_is_available) + { + in_reverse = false; + data_changed = true; + condition.notify_one(); + } +} + +void on_engine_reverse_event(const std::shared_ptr &_event) { + std::unique_lock 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 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; +} diff --git a/sample-apps/radio-service.cpp b/sample-apps/radio-service.cpp new file mode 100644 index 0000000..feceb0f --- /dev/null +++ b/sample-apps/radio-service.cpp @@ -0,0 +1,437 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std::literals::chrono_literals; + +#include + +#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 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 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 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 next_song_at; + std::unique_lock 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 &_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 its_response = response (_request, was_playing ? 1 : 0); + app->send(its_response); + } + + void on_message_is_playing(const std::shared_ptr &_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 its_response = response (_request, get_playing () ? 1 : 0); + app->send(its_response); + } + + void on_message_change_volume(const std::shared_ptr &_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 its_response = response (_request, result); + app->send(its_response); + } + + void on_message_get_volume(const std::shared_ptr &_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 its_response = response (_request, volume); + app->send(its_response); + } + + void on_message_switch_station(const std::shared_ptr &_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 its_response = response (_request, 0); + app->send(its_response); + } + + void on_engine_reverse_event(const std::shared_ptr &_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 its_lock(main_mutex); + engine_available = _is_available; + } + +private: + bool set_playing (bool new_playing) { + std::unique_lock 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 its_lock(main_mutex); + return next_playing; + } + + uint32_t change_volume (int32_t delta_volume) { + std::unique_lock 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 its_lock(main_mutex); + return next_volume; + } + + void switch_station (void) { + std::unique_lock 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 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); +} diff --git a/sample-apps/radio-stations.cpp b/sample-apps/radio-stations.cpp new file mode 100644 index 0000000..079a5ee --- /dev/null +++ b/sample-apps/radio-stations.cpp @@ -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]; +} diff --git a/sample-apps/radio-stations.hpp b/sample-apps/radio-stations.hpp new file mode 100644 index 0000000..2860fa3 --- /dev/null +++ b/sample-apps/radio-stations.hpp @@ -0,0 +1,18 @@ +#include + +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); diff --git a/sample-apps/services.hpp b/sample-apps/services.hpp new file mode 100644 index 0000000..c894a34 --- /dev/null +++ b/sample-apps/services.hpp @@ -0,0 +1,119 @@ +#include +#include + +#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 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 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 inline +payload_with_arg(uint32_t arg) +{ + std::shared_ptr its_payload = vsomeip::runtime::get()->create_payload(); + std::vector 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 inline +payload_with_string(std::string arg) +{ + std::shared_ptr its_payload = vsomeip::runtime::get()->create_payload(); + std::vector its_payload_data; + for (vsomeip::byte_t i=0; iset_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 its_payload = payload_with_arg (arg); + request->set_payload(its_payload); + + return request; +} + +static uint32_t inline +get_arg0(const std::shared_ptr _request) { + std::shared_ptr its_payload = _request->get_payload(); + + return payload_get_arg(its_payload); +} + +static std::string inline +get_arg0_string(const std::shared_ptr _request) { + std::shared_ptr its_payload = _request->get_payload(); + + return payload_get_string(its_payload); +} + +static std::shared_ptr inline +response (const std::shared_ptr &_request, + uint32_t arg) +{ + std::shared_ptr its_response = vsomeip::runtime::get()->create_response(_request); + std::shared_ptr its_payload = payload_with_arg (arg); + + its_response->set_payload(its_payload); + + return its_response; +} diff --git a/tinyrepo/README.rst b/tinyrepo/README.rst new file mode 100644 index 0000000..103ef6c --- /dev/null +++ b/tinyrepo/README.rst @@ -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. + + diff --git a/tinyrepo/build_images.sh b/tinyrepo/build_images.sh new file mode 100644 index 0000000..a92b0de --- /dev/null +++ b/tinyrepo/build_images.sh @@ -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 diff --git a/tinyrepo/build_repos.sh b/tinyrepo/build_repos.sh new file mode 100644 index 0000000..a40885a --- /dev/null +++ b/tinyrepo/build_repos.sh @@ -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 diff --git a/tinyrepo/initiate_repo.py b/tinyrepo/initiate_repo.py new file mode 100644 index 0000000..9e65624 --- /dev/null +++ b/tinyrepo/initiate_repo.py @@ -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))