Skip to content

Commit

Permalink
feat: add support for bootstrapping Debian
Browse files Browse the repository at this point in the history
  • Loading branch information
koehlma committed May 8, 2024
1 parent 5a24046 commit 9c08c42
Show file tree
Hide file tree
Showing 22 changed files with 243 additions and 18 deletions.
2 changes: 2 additions & 0 deletions bakery/layers/bakery/00-base.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ apt-get -y install \
fdisk \
file \
git \
gpg \
mmdebstrap \
python3 \
wget \
xz-utils \
Expand Down
8 changes: 8 additions & 0 deletions bakery/repositories/core/layers/debian-bookworm.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
root = true

recipes = [
"debian-bootstrap",
]

[parameters."debian-bootstrap"]
suite = "bookworm"
5 changes: 5 additions & 0 deletions bakery/repositories/core/recipes/debian-bootstrap/recipe.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
description = "bootstrap Debian from scratch"
priority = 10_000_000

[parameters]
suite = { default = "stable" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

set -euo pipefail

mmdebstrap \
--architectures="${RUGPI_ARCH}" \
"${RECIPE_PARAM_SUITE}" \
"${RUGPI_ROOT_DIR}"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console=serial0,115200 console=tty1 rootfstype=ext4 fsck.repair=yes rootwait
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Enable DRM VC4 V3D driver.
dtoverlay=vc4-kms-v3d
max_framebuffers=2

# We want to run the processor in its 64-bit mode.
arm_64bit=1
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.12 (GNU/Linux)

mQENBE/d7o8BCACrwqQacGJfn3tnMzGui6mv2lLxYbsOuy/+U4rqMmGEuo3h9m92
30E2EtypsoWczkBretzLUCFv+VUOxaA6sV9+puTqYGhhQZFuKUWcG7orf7QbZRuu
TxsEUepW5lg7MExmAu1JJzqM0kMQX8fVyWVDkjchZ/is4q3BPOUCJbUJOsE+kK/6
8kW6nWdhwSAjfDh06bA5wvoXNjYoDdnSZyVdcYCPEJXEg5jfF/+nmiFKMZBraHwn
eQsepr7rBXxNcEvDlSOPal11fg90KXpy7Umre1UcAZYJdQeWcHu7X5uoJx/MG5J8
ic6CwYmDaShIFa92f8qmFcna05+lppk76fsnABEBAAG0IFJhc3BiZXJyeSBQaSBB
cmNoaXZlIFNpZ25pbmcgS2V5iQE4BBMBAgAiBQJP3e6PAhsDBgsJCAcDAgYVCAIJ
CgsEFgIDAQIeAQIXgAAKCRCCsSmSf6MwPk6vB/9pePB3IukU9WC9Bammh3mpQTvL
OifbkzHkmAYxzjfK6D2I8pT0xMxy949+ThzJ7uL60p6T/32ED9DR3LHIMXZvKtuc
mQnSiNDX03E2p7lIP/htoxW2hDP2n8cdlNdt0M9IjaWBppsbO7IrDppG2B1aRLni
uD7v8bHRL2mKTtIDLX42Enl8aLAkJYgNWpZyPkDyOqamjijarIWjGEPCkaURF7g4
d44HvYhpbLMOrz1m6N5Bzoa5+nq3lmifeiWKxioFXU+Hy5bhtAM6ljVb59hbD2ra
X4+3LXC9oox2flmQnyqwoyfZqVgSQa0B41qEQo8t1bz6Q1Ti7fbMLThmbRHiuQEN
BE/d7o8BCADNlVtBZU63fm79SjHh5AEKFs0C3kwa0mOhp9oas/haDggmhiXdzeD3
49JWz9ZTx+vlTq0s+I+nIR1a+q+GL+hxYt4HhxoA6vlDMegVfvZKzqTX9Nr2VqQa
S4Kz3W5ULv81tw3WowK6i0L7pqDmvDqgm73mMbbxfHD0SyTt8+fk7qX6Ag2pZ4a9
ZdJGxvASkh0McGpbYJhk1WYD+eh4fqH3IaeJi6xtNoRdc5YXuzILnp+KaJyPE5CR
qUY5JibOD3qR7zDjP0ueP93jLqmoKltCdN5+yYEExtSwz5lXniiYOJp8LWFCgv5h
m8aYXkcJS1xVV9Ltno23YvX5edw9QY4hABEBAAGJAR8EGAECAAkFAk/d7o8CGwwA
CgkQgrEpkn+jMD5Figf/dIC1qtDMTbu5IsI5uZPX63xydaExQNYf98cq5H2fWF6O
yVR7ERzA2w33hI0yZQrqO6pU9SRnHRxCFvGv6y+mXXXMRcmjZG7GiD6tQWeN/3wb
EbAn5cg6CJ/Lk/BI4iRRfBX07LbYULCohlGkwBOkRo10T+Ld4vCCnBftCh5x2OtZ
TOWRULxP36y2PLGVNF+q9pho98qx+RIxvpofQM/842ZycjPJvzgVQsW4LT91KYAE
4TVf6JjwUM6HZDoiNcX6d7zOhNfQihXTsniZZ6rky287htsWVDNkqOi5T3oTxWUo
m++/7s3K3L0zWopdhMVcgg6Nt9gcjzqN1c0gy55L/g==
=mNSj
-----END PGP PUBLIC KEY BLOCK-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
deb http://archive.raspberrypi.com/debian/ RELEASE main
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
#deb-src http://archive.raspberrypi.com/debian/ RELEASE main
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
description = "setup Debian for Raspberry Pi"
priority = 9_000_000
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

set -euo pipefail

gpg --dearmor \
< "${RECIPE_DIR}/files/raspberrypi.gpg.key" \
> "${RUGPI_ROOT_DIR}/etc/apt/trusted.gpg.d/raspberrypi-archive-stable.gpg"

chmod 644 "${RUGPI_ROOT_DIR}/etc/apt/trusted.gpg.d/raspberrypi-archive-stable.gpg"
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/bash

set -euo pipefail

install -m 644 "${RECIPE_DIR}/files/raspberrypi.list" "/etc/apt/sources.list.d/"
sed -i "s/RELEASE/bookworm/g" "/etc/apt/sources.list.d/raspberrypi.list"

apt-get update -y
apt-get install -y raspberrypi-archive-keyring

apt-get install -y \
initramfs-tools \
raspi-firmware \
linux-image-rpi-v8 \
linux-headers-rpi-v8 \
linux-image-rpi-2712 \
linux-headers-rpi-2712

install -m 644 "${RECIPE_DIR}/files/cmdline.txt" "/boot/firmware/"
install -m 644 "${RECIPE_DIR}/files/config.txt" "/boot/firmware/"

# XXX: Currently Rugpi expects the files for the boot partition to be directly in
# `/boot` as this was the case before Debian Bookworm. Changing this is a breaking
# change of Rugpi. We may do this with the next major release. If that happens, the
# following two lines can/must be removed.
mv /boot/firmware/* /boot
rm -rf /boot/firmware
1 change: 1 addition & 0 deletions bakery/repositories/core/recipes/ssh/steps/00-packages
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
openssh-server
70 changes: 53 additions & 17 deletions crates/rugpi-bakery/src/bake/customize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub fn customize(
project: &Project,
arch: Architecture,
layer: &Layer,
src: &Path,
src: Option<&Path>,
target: &Path,
layer_path: &Path,
) -> Anyhow<()> {
Expand All @@ -47,8 +47,10 @@ pub fn customize(
.map(|job| job.recipe.modified)
.max()
.unwrap()
.max(layer.modified)
.max(mtime(src)?);
.max(layer.modified);
if let Some(src) = src {
last_modified = last_modified.max(mtime(src)?);
}
let mut force_run = false;
let used_files = project.dir.join(layer_path.join("rebuild-if-changed.txt"));
if used_files.exists() {
Expand All @@ -67,8 +69,12 @@ pub fn customize(
// Prepare system chroot.
let root_dir = tempdir()?;
let root_dir_path = root_dir.path();
info!("extracting system files");
run!(["tar", "-x", "-f", &src, "-C", root_dir_path])?;
if let Some(src) = src {
info!("extracting system files");
run!(["tar", "-x", "-f", &src, "-C", root_dir_path])?;
} else {
std::fs::create_dir_all(&root_dir_path)?;
}
apply_recipes(project, arch, &jobs, root_dir_path, layer_path)?;
info!("packing system files");
run!(["tar", "-c", "-f", &target, "-C", root_dir_path, "."])?;
Expand Down Expand Up @@ -158,20 +164,37 @@ fn apply_recipes(
root_dir_path: &Path,
layer_path: &Path,
) -> Anyhow<()> {
let _mounted_dev = Mounted::bind("/dev", root_dir_path.join("dev"))?;
let _mounted_dev_pts = Mounted::bind("/dev/pts", root_dir_path.join("dev/pts"))?;
let _mounted_sys = Mounted::bind("/sys", root_dir_path.join("sys"))?;
let _mounted_proc = Mounted::mount_fs("proc", "proc", root_dir_path.join("proc"))?;
let _mounted_run = Mounted::mount_fs("tmpfs", "tmpfs", root_dir_path.join("run"))?;
let _mounted_tmp = Mounted::mount_fs("tmpfs", "tmpfs", root_dir_path.join("tmp"))?;
let mut mount_stack = Vec::new();

let bakery_recipe_path = root_dir_path.join("run/rugpi/bakery/recipe");
fs::create_dir_all(&bakery_recipe_path)?;
fn mount_all(project: &Project, root_dir_path: &Path, stack: &mut Vec<Mounted>) -> Anyhow<()> {
stack.push(Mounted::bind("/dev", root_dir_path.join("dev"))?);
stack.push(Mounted::bind("/dev/pts", root_dir_path.join("dev/pts"))?);
stack.push(Mounted::bind("/sys", root_dir_path.join("sys"))?);
stack.push(Mounted::mount_fs(
"proc",
"proc",
root_dir_path.join("proc"),
)?);
stack.push(Mounted::mount_fs(
"tmpfs",
"tmpfs",
root_dir_path.join("run"),
)?);
stack.push(Mounted::mount_fs(
"tmpfs",
"tmpfs",
root_dir_path.join("tmp"),
)?);

let project_dir = root_dir_path.join("run/rugpi/bakery/project");
fs::create_dir_all(&project_dir)?;
let project_dir = root_dir_path.join("run/rugpi/bakery/project");
fs::create_dir_all(&project_dir)?;

stack.push(Mounted::bind(&project.dir, &project_dir)?);

Ok(())
}

let _mounted_project = Mounted::bind(&project.dir, &project_dir)?;
let project_dir = root_dir_path.join("run/rugpi/bakery/project");

for (idx, job) in jobs.iter().enumerate() {
let recipe = &job.recipe;
Expand All @@ -186,19 +209,27 @@ fn apply_recipes(
.unwrap_or(recipe.name.deref()),
&job.parameters,
);
let _mounted_recipe = Mounted::bind(&recipe.path, &bakery_recipe_path)?;

for step in &recipe.steps {
info!(" - {}", step.filename);
match &step.kind {
StepKind::Packages { packages } => {
if mount_stack.is_empty() {
mount_all(project, root_dir_path, &mut mount_stack)?;
}
let mut cmd = cmd!("chroot", root_dir_path, "apt-get", "install", "-y");
cmd.extend_args(packages);
ParentEnv.run(cmd.with_vars(vars! {
DEBIAN_FRONTEND = "noninteractive"
}))?;
}
StepKind::Install => {
if mount_stack.is_empty() {
mount_all(project, root_dir_path, &mut mount_stack)?;
}
let bakery_recipe_path = root_dir_path.join("run/rugpi/bakery/recipe");
fs::create_dir_all(&bakery_recipe_path)?;
let _mounted_recipe = Mounted::bind(&recipe.path, &bakery_recipe_path)?;
let script = format!("/run/rugpi/bakery/recipe/steps/{}", step.filename);
let mut vars = vars! {
DEBIAN_FRONTEND = "noninteractive",
Expand Down Expand Up @@ -233,5 +264,10 @@ fn apply_recipes(
}
}
}

while let Some(top) = mount_stack.pop() {
drop(top);
}

Ok(())
}
17 changes: 16 additions & 1 deletion crates/rugpi-bakery/src/bake/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,22 @@ impl<'p> LayerBakery<'p> {
let layer_path = PathBuf::from(format!(".rugpi/layers/{layer_id}"));
let target = self.project.dir.join(&layer_path).join("system.tar");
fs::create_dir_all(target.parent().unwrap()).ok();
customize::customize(self.project, self.arch, layer, &src, &target, &layer_path)?;
customize::customize(
self.project,
self.arch,
layer,
Some(&src),
&target,
&layer_path,
)?;
Ok(target)
} else if config.root {
layer_id.push("bare", "true");
let layer_id = layer_id.finalize();
let layer_path = PathBuf::from(format!(".rugpi/layers/{layer_id}"));
let target = self.project.dir.join(&layer_path).join("system.tar");
fs::create_dir_all(target.parent().unwrap()).ok();
customize::customize(self.project, self.arch, layer, None, &target, &layer_path)?;
Ok(target)
} else {
bail!("invalid layer configuration")
Expand Down
2 changes: 2 additions & 0 deletions crates/rugpi-bakery/src/project/layers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ pub struct LayerConfig {
/// An URL to fetch the layer from.
pub url: Option<String>,
pub parent: Option<String>,
#[serde(default)]
pub root: bool,
/// The recipes to include.
#[serde(default)]
pub recipes: HashSet<RecipeName>,
Expand Down
23 changes: 23 additions & 0 deletions tests/bootstrap/layers/customized.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
parent = "core/debian-bookworm"

recipes = [
"core/debian-raspberrypi",
"core/rugpi-ctrl",
"core/set-hostname",
"core/persist-root-home",
"core/ssh",
"core/apt-cleanup",
"rugpi-extra/avahi",
"setup-network",
]

[parameters."core/set-hostname"]
hostname = "rugpi-bootstrapped"

[parameters."core/apt-cleanup"]
autoremove = true

[parameters."core/ssh"]
root_authorized_keys = """
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC2tN+ZL8lGnx8rW+vm9ukX1uhKE7GREHitIVxIN3fVh406ksaZzY4FB7JqMqor4SBpR/Eigm6mSSE6KdwSYYC99hakLVvFUG6b6xvB7gOgre8M0JuL9XwBfaUfNln6Hl2Xirlml61JwOWa8Lh+T8mquw9OUK20tkXNPrigVKH+RMQA2V0AQrHnzo9GXMT5HEdAfaVVhL8S1inlKixiPbnvt+nWUSoKGLo+I08w5ZKI88C+saP6VqFiinp57uF0F3oqwcupZe0j6vxGuN5hFg8YGcICFnjXUAVjds8pfcf7aImvYZdp192jC9JAfzx3LzJZLn+kY9hIQkqip/tfTtp56eBb+j9i07PhrDsGiZVNOWf+YG3Cw5Ix6ltOL0dvF1/xFG7O+CGz62w8Y925ytuGgzBkVJ090eznnCjpw+lhNiNFmoqUjiJFjs/VSrqmC5bqdRrqF7YIs61uKl/EyAZaEoHZJazUFFauOjjPK0ksVbAAfqxG4nFmOG0URemSvNE= koehlma@Zaylee
"""
5 changes: 5 additions & 0 deletions tests/bootstrap/recipes/setup-network/files/dhcp.network
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[Match]
Name=en*

[Network]
DHCP=yes
1 change: 1 addition & 0 deletions tests/bootstrap/recipes/setup-network/recipe.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
description = "setup network"
7 changes: 7 additions & 0 deletions tests/bootstrap/recipes/setup-network/steps/00-install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash

set -euo pipefail

systemctl enable systemd-networkd.service

install -m 644 "${RECIPE_DIR}/files/dhcp.network" "/etc/systemd/network/"
6 changes: 6 additions & 0 deletions tests/bootstrap/rugpi-bakery.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[repositories]
rugpi-extra = { git = "https://github.com/silitics/rugpi-extra.git", branch = "v0.6" }

[images.tryboot]
layer = "customized"
include_firmware = "none"
28 changes: 28 additions & 0 deletions tests/bootstrap/run-bakery
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash

set -euo pipefail

DOCKER=${DOCKER:-"docker"}
DOCKER_FLAGS=${DOCKER_FLAGS:-""}

RUGPI_DEV=${RUGPI_DEV:-"false"}

if [ "${RUGPI_DEV}" = "false" ]; then
DOCKER_FLAGS="${DOCKER_FLAGS} --pull always"
RUGPI_VERSION=${RUGPI_VERSION:-"main"}
else
RUGPI_VERSION=${RUGPI_VERSION:-"dev"}
fi

RUGPI_BAKERY_IMAGE=${RUGPI_BAKERY_IMAGE:-"ghcr.io/silitics/rugpi-bakery:${RUGPI_VERSION}"}

if [ -t 0 ] && [ -t 1 ]; then
DOCKER_FLAGS="${DOCKER_FLAGS} -it"
fi

exec $DOCKER run --rm --privileged \
$DOCKER_FLAGS \
-v "$(pwd)":/project \
-v /dev:/dev \
"${RUGPI_BAKERY_IMAGE}" \
"$@"

0 comments on commit 9c08c42

Please sign in to comment.