diff options
author | Colin Walters <walters@verbum.org> | 2016-03-03 21:17:53 -0500 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2016-03-16 17:15:58 -0400 |
commit | f51d651b10c61ab97039dab4558d0685460af58c (patch) | |
tree | 08f8337cdce362da71b1da5857c5d134f3cee231 | |
parent | 0b068c668a182ceca4d581ad46fdc6b1ac087afd (diff) | |
download | ostree-f51d651b10c61ab97039dab4558d0685460af58c.tar.gz |
docs: Add a section on writing buildsystems
And add a test that is a demo buildsystem.
-rw-r--r-- | Makefile-tests.am | 1 | ||||
-rw-r--r-- | docs/manual/buildsystem-and-repos.md | 180 | ||||
-rw-r--r-- | mkdocs.yml | 1 | ||||
-rwxr-xr-x | tests/test-demo-buildsystem.sh | 104 |
4 files changed, 286 insertions, 0 deletions
diff --git a/Makefile-tests.am b/Makefile-tests.am index f93b91f7..cd686c4b 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -67,6 +67,7 @@ test_scripts = \ tests/test-auto-summary.sh \ tests/test-prune.sh \ tests/test-refs.sh \ + tests/test-demo-buildsystem.sh \ $(NULL) if BUILDOPT_FUSE diff --git a/docs/manual/buildsystem-and-repos.md b/docs/manual/buildsystem-and-repos.md new file mode 100644 index 00000000..d418cb0e --- /dev/null +++ b/docs/manual/buildsystem-and-repos.md @@ -0,0 +1,180 @@ +# Writing a buildsystem and managing repositories + +OSTree is not a package system. It does not directly support building +source code. Rather, it is a tool for transporting and managing +content, along with package-system independent aspects like bootloader +management for updates. + +We'll assume here that we're planning to generate commits on a build +server, then have client systems replicate it. Doing client-side +assembly is also possible of course, but this discussion will focus +primarily on server-side concerns. + +## Build vs buy + +Therefore, you need to either pick an existing tool for writing +content into an OSTree repository, or to write your own. An example +tool is [rpm-ostree](https://github.com/projectatomic/rpm-ostree) - it +takes as input RPMs, and commits them (currently oriented for a server +side, but aiming to do client side too). + +## Initializing + +For this initial discussion, we're assuming you have a single +`archive-z2` repository: + +``` +mkdir repo +ostree --repo=repo init --mode=archive-z2 +``` + +You can export this via a static webserver, and configure clients to +pull from it. + +## Writing your own OSTree buildsystem + +There exist many, many systems that basically follow this pattern: + +``` +$pkg --installroot=/path/to/tmpdir install foo bar baz +$imagesystem commit --root=/path/to/tmpdir +``` + +For various values of `$pkg` such as `yum`, `apt-get`, etc., and +values of `$imagesystem` could be simple tarballs, Amazon Machine +Images, ISOs, etc. + +Now obviously in this document, we're going to talk about the +situation where `$imagesystem` is OSTree. The general idea with +OSTree is that wherever you might store a series of tarballs for +applications or OS images, OSTree is likely going to be better. For +example, it supports GPG signatures, binary deltas, writing bootloader +configuration, etc. + +OSTree does not include a package/component build system simply +because there already exist plenty of good ones - rather, it is +intended to provide an infrastructure layer. + +The above mentioned `rpm-ostree compose tree` chooses RPM as the value +of `$pkg` - so binaries are built as RPMs, then committed as a whole +into an OSTree commit. + +But let's discuss building our own. If you're just experimenting, +it's quite easy to start with the command line. We'll assume for this +purpose that you have a build process that outputs a directory tree - +we'll call this tool `$pkginstallroot` (which could be `yum +--installroot` or `dbootstrap`, etc.). + +Your initial prototype is going to look like: + +``` +$pkginstallroot /path/to/tmpdir +ostree --repo=repo commit -s 'build' -b exampleos/x86_64/standard --tree=dir=/path/to/tmpdir +``` + +Alternatively, if your build system can generate a tarball, you can +commit that tarball into OSTree. For example, +[OpenEmbedded](http://www.openembedded.org/) can output a tarball, and +one can commit it via: + +``` +ostree commit -s 'build' -b exampleos/x86_64/standard --tree=tar=myos.tar +``` + +## Constructing trees from unions + +The above is a very simplistic model, and you will quickly notice that +it's slow. This is because OSTree has to re-checksum and recompress +the content each time it's committed. (Most of the CPU time is spent +in compression which gets thrown away if the content turns out to be +already stored). + +A more advanced approach is to store components in OSTree itself, then +union them, and recommit them. At this point, we recommend taking a +look at the OSTree API, and choose a programming language supported by +[GObject Introspection](https://wiki.gnome.org/Projects/GObjectIntrospection) +to write your buildsystem scripts. Python may be a good choice, or +you could choose custom C code, etc. + +For the purposes of this tutorial we will use shell script, but it's +strongly recommended to choose a real programming language for your +build system. + +Let's say that your build system produces separate artifacts (whether +those are RPMs, zip files, or whatever). These artifacts should be +the result of `make install DESTDIR=` or similar. Basically +equivalent to RPMs/debs. + +Further, in order to make things fast, we will need a separate +`bare-user` repository in order to perform checkouts quickly via +hardlinks. We'll then export content into the `archive-z2` repository +for use by client systems. + +``` +mkdir build-repo +ostree --repo=build-repo init --mode=bare-user +``` + +You can begin committing those as individual branches: + +``` +ostree --repo=build-repo commit -b exampleos/x86_64/bash --tree=tar=bash-4.2-bin.tar.gz +ostree --repo=build-repo commit -b exampleos/x86_64/systemd --tree=tar=systemd-224-bin.tar.gz +``` + +Set things up so that whenever a package changes, you redo the +`commit` with the new package version - conceptually, the branch +tracks the individual package versions over time, and defaults to +"latest". This isn't required - one could also include the version in +the branch name, and have metadata outside to determine "latest" (or +the desired version). + +Now, to construct our final tree: + +``` +rm exampleos-build -rf +for package in bash systemd; do + ostree --repo=build-repo checkout -U --union exampleos/x86_64/${package} exampleos-build +done +# Set up a "rofiles-fuse" mount point; this ensures that any processes +# we run for post-processing of the tree don't corrupt the hardlinks. +mkdir -p mnt +rofiles-fuse exampleos-build mnt +# Now run global "triggers", generate cache files: +ldconfig -r mnt + (Insert other programs here) +fusermount -u mnt +ostree --repo=build-repo commit -b exampleos/x86_64/standard --link-checkout-speedup exampleos-build +``` + +There are a number of interesting things going on here. The major +architectural change is that we're using `--link-checkout-speedup`. +This is a way to tell OSTree that our checkout is made via hardlinks, +and to scan the repository in order to build up a reverse `(device, +inode) -> checksum` mapping. + +In order for this mapping to be accurate, we needed the `rofiles-fuse` +to ensure that any changed files had new inodes (and hence a new +checksum). + +## Migrating content between repositories + +Now that we have content in our `build-repo` repository (in +`bare-user` mode), we need to move the `exampleos/x86_64/standard` +branch content into the repository just named `repo` (in `archive-z2` +mode) for export, which will involve zlib compression of new objects. +We likely want to generate static deltas after that as well. + +Let's copy the content: + +``` +ostree --repo=repo pull-local build-repo exampleos/x86_64/standard +``` + +Clients can now incrementally download new objects - however, this +would also be a good time to generate a delta from the previous +commit. + +``` +ostree --repo=repo static-delta generate exampleos/x86_64/standard +``` @@ -9,3 +9,4 @@ pages: - Atomic Upgrades: 'manual/atomic-upgrades.md' - Adapting Existing Systems: 'manual/adapting-existing.md' - Formats: 'manual/formats.md' + - Build Systems and Repos: 'manual/buildsystem-and-repos.md' diff --git a/tests/test-demo-buildsystem.sh b/tests/test-demo-buildsystem.sh new file mode 100755 index 00000000..500eac68 --- /dev/null +++ b/tests/test-demo-buildsystem.sh @@ -0,0 +1,104 @@ +#!/bin/bash +# +# Copyright (C) 2016 Colin Walters <walters@verbum.org> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +if ! fusermount --version >/dev/null 2>&1; then + echo "1..0 # SKIP no fusermount" + exit 0 +fi + +. $(dirname $0)/libtest.sh + +echo "1..1" + +# Run "triggers" like ldconfig, gtk-update-icon-cache, etc. +demo_triggers() { + root=$1 + shift + mkdir -p ${root}/usr/lib + echo updated ldconfig at $(date) > ${root}/usr/lib/ld.so.cache.new + mv ${root}/usr/lib/ld.so.cache{.new,} +} + +# Make a binary in /usr/bin/$pkg which contains $version +exampleos_build_commit_package() { + pkg=$1 + version=$2 + mkdir -p ${pkg}-package/usr/bin/ + echo "${pkg}-content ${version}" > ${pkg}-package/usr/bin/${pkg} + # Use a dummy subject for this. + ostree --repo=build-repo commit -b exampleos/x86_64/${pkg} -s '' --tree=dir=${pkg}-package + rm ${pkg}-package -rf +} + +exampleos_recompose() { + rm exampleos-build -rf + for pkg in ${packages}; do + ostree --repo=build-repo checkout -U --union exampleos/x86_64/${pkg} exampleos-build + done + + # Now that we have our rootfs, run triggers + rofiles-fuse exampleos-build mnt + demo_triggers mnt/ + fusermount -u mnt + + # Then we commit it, using --link-checkout-speedup to effectively + # only re-checksum the ldconfig file. We also have dummy commit + # message here. + ostree --repo=build-repo commit -b exampleos/x86_64/standard -s 'exampleos build' --link-checkout-speedup exampleos-build +} + +packages="bash systemd" + +mkdir build-repo +ostree --repo=build-repo init --mode=bare-user +mkdir repo +ostree --repo=repo init --mode=archive-z2 +# Our FUSE mount point +mkdir mnt + +# "Build" some packages which are really just files with +# the version number inside. +exampleos_build_commit_package bash 0.4.7 +exampleos_build_commit_package systemd 224 + +# Now union the packages and commit +exampleos_recompose + +# This is our first commit - let's publish it. +ostree --repo=repo pull-local build-repo exampleos/x86_64/standard + +# Now, update the bash package - this is a new commit on the branch +# exampleos/x86_64/bash. +exampleos_build_commit_package bash 0.5.0 + +# We now have two commits +exampleos_recompose + +# Publish again: +ostree --repo=repo pull-local build-repo exampleos/x86_64/standard +# Optional: Generate a static delta vs the previous build +ostree --repo=repo static-delta generate exampleos/x86_64/standard +# Optional: Regenerate the summary file +ostree --repo=repo summary -u + +# Try: ostree --repo=demo-repo ls -R exampleos/x86_64/standard + +echo "ok demo buildsystem" |