Skip to content

Commit 8c75ebd

Browse files
committed
cidata: split user-data
Split scripts in `user-data.TEMPLATE`. No modification to the script lines. Signed-off-by: Akihiro Suda <[email protected]>
1 parent 5fb7526 commit 8c75ebd

14 files changed

+427
-421
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/sh
2+
# This script pretends that /bin/ash can be used as /bin/bash, so all following
3+
# cloud-init scripts can use `#!/bin/bash` and `set -o pipefail`.
4+
test -f /etc/alpine-release || exit 0
5+
6+
# Redirect bash to ash (built with CONFIG_ASH_BASH_COMPAT) and hope for the best :)
7+
# It does support `set -o pipefail`, but not `[[`.
8+
# /bin/bash can't be a symlink because /bin/ash is a symlink to /bin/busybox
9+
cat >/bin/bash <<'EOF'
10+
#!/bin/sh
11+
exec /bin/ash "$@"
12+
EOF
13+
chmod +x /bin/bash
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/bin/bash
2+
set -eux -o pipefail
3+
4+
# Restrict the rest of this script to Alpine until it has been tested with other distros
5+
test -f /etc/alpine-release || exit 0
6+
7+
# Data directories that should be persisted across reboots
8+
DATADIRS="/home /usr/local /etc/containerd /var/lib/containerd"
9+
10+
# When running from RAM try to move persistent data to data-volume
11+
# FIXME: the test for tmpfs mounts is probably Alpine-specific
12+
if [ "$(awk '$2 == "/" {print $3}' /proc/mounts)" == "tmpfs" ]; then
13+
mkdir -p /mnt/data
14+
if [ -e /dev/disk/by-label/data-volume ]; then
15+
mount -t ext4 /dev/disk/by-label/data-volume /mnt/data
16+
else
17+
# Find an unpartitioned disk and create data-volume
18+
DISKS=$(lsblk --list --noheadings --output name,type | awk '$2 == "disk" {print $1}')
19+
for DISK in ${DISKS}; do
20+
IN_USE=false
21+
# Looking for a disk that is not mounted or partitioned
22+
for PART in $(awk '/^\/dev\// {gsub("/dev/", ""); print $1}' /proc/mounts); do
23+
if [ "${DISK}" == "${PART}" -o -e /sys/block/${DISK}/${PART} ]; then
24+
IN_USE=true
25+
break
26+
fi
27+
done
28+
if [ "${IN_USE}" == "false" ]; then
29+
echo 'type=83' | sfdisk --label dos /dev/${DISK}
30+
PART=$(lsblk --list /dev/${DISK} --noheadings --output name,type | awk '$2 == "part" {print $1}')
31+
mkfs.ext4 -L data-volume /dev/${PART}
32+
mount -t ext4 /dev/disk/by-label/data-volume /mnt/data
33+
for DIR in ${DATADIRS}; do
34+
DEST="/mnt/data$(dirname ${DIR})"
35+
mkdir -p ${DIR} ${DEST}
36+
mv ${DIR} ${DEST}
37+
done
38+
break
39+
fi
40+
done
41+
fi
42+
for DIR in ${DATADIRS}; do
43+
if [ -d /mnt/data${DIR} ]; then
44+
[ -e ${DIR} ] && rm -rf ${DIR}
45+
ln -s /mnt/data${DIR} ${DIR}
46+
fi
47+
done
48+
fi
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/bin/bash
2+
set -eux -o pipefail
3+
4+
# This script prepares Alpine for lima; there is nothing in here for other distros
5+
test -f /etc/alpine-release || exit 0
6+
7+
# Configure apk repos
8+
BRANCH=edge
9+
VERSION_ID=$(awk -F= '$1=="VERSION_ID" {print $2}' /etc/os-release)
10+
case ${VERSION_ID} in
11+
*_alpha*|*_beta*) BRANCH=edge;;
12+
*.*.*) BRANCH=v${VERSION_ID%.*};;
13+
esac
14+
15+
for REPO in main community; do
16+
URL="https://dl-cdn.alpinelinux.org/alpine/${BRANCH}/${REPO}"
17+
if ! grep -q "^${URL}$" /etc/apk/repositories; then
18+
echo "${URL}" >> /etc/apk/repositories
19+
fi
20+
done
21+
22+
# Alpine doesn't use PAM so we need to explicitly allow public key auth
23+
usermod -p '*' ""{{.User}}""
24+
25+
# Alpine disables TCP forwarding, which is needed by the lima-guestagent
26+
sed -i 's/AllowTcpForwarding no/AllowTcpForwarding yes/g' /etc/ssh/sshd_config
27+
rc-service sshd reload
28+
29+
# Create directory for the lima-guestagent socket (normally done by systemd)
30+
mkdir -p /run/user/{{.UID}}
31+
chown "{{.User}}" /run/user/{{.UID}}
32+
chmod 700 /run/user/{{.UID}}
33+
34+
# Install the openrc lima-guestagent service script
35+
mv /var/lib/lima-guestagent/lima-guestagent.openrc /etc/init.d/lima-guestagent
36+
37+
# mount /sys/fs/cgroup
38+
rc-service cgroups start
39+
40+
# `limactl stop` tells acpid to powerdown
41+
rc-update add acpid
42+
rc-service acpid start
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/bin/bash
2+
set -eux -o pipefail
3+
4+
# This script does not work unless systemd is available
5+
command -v systemctl 2>&1 >/dev/null || exit 0
6+
7+
# Set up env
8+
for f in .profile .bashrc; do
9+
if ! grep -q "# Lima BEGIN" "/home/{{.User}}.linux/$f"; then
10+
cat >>"/home/{{.User}}.linux/$f" <<EOF
11+
# Lima BEGIN
12+
# Make sure iptables and mount.fuse3 are available
13+
PATH="$PATH:/usr/sbin:/sbin"
14+
# fuse-overlayfs is the most stable snapshotter for rootless
15+
CONTAINERD_SNAPSHOTTER="fuse-overlayfs"
16+
export PATH CONTAINERD_SNAPSHOTTER
17+
# Lima END
18+
EOF
19+
chown "{{.User}}" "/home/{{.User}}.linux/$f"
20+
fi
21+
done
22+
# Enable cgroup delegation (only meaningful on cgroup v2)
23+
if [ ! -e "/etc/systemd/system/[email protected]/lima.conf" ]; then
24+
mkdir -p "/etc/systemd/system/[email protected]"
25+
cat >"/etc/systemd/system/[email protected]/lima.conf" <<EOF
26+
[Service]
27+
Delegate=yes
28+
EOF
29+
fi
30+
systemctl daemon-reload
31+
32+
# Set up sysctl
33+
sysctl_conf="/etc/sysctl.d/99-lima.conf"
34+
if [ ! -e "${sysctl_conf}" ]; then
35+
if [ -e "/proc/sys/kernel/unprivileged_userns_clone" ]; then
36+
echo "kernel.unprivileged_userns_clone=1" >> "${sysctl_conf}"
37+
fi
38+
echo "net.ipv4.ping_group_range = 0 2147483647" >> "${sysctl_conf}"
39+
echo "net.ipv4.ip_unprivileged_port_start=0" >> "${sysctl_conf}"
40+
sysctl --system
41+
fi
42+
43+
# Set up subuid
44+
for f in /etc/subuid /etc/subgid; do
45+
grep -qw "{{.User}}" $f || echo "{{.User}}:100000:65536" >> $f
46+
done
47+
48+
# Start systemd session
49+
loginctl enable-linger "{{.User}}"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/bin/bash
2+
set -eux -o pipefail
3+
4+
# Create mount points
5+
{{- range $val := .Mounts}}
6+
mkdir -p "{{$val}}"
7+
chown "{{$.User}}" "{{$val}}" || true
8+
{{- end}}
9+
10+
# Install or update the guestagent binary
11+
mkdir -p -m 600 /mnt/lima-cidata
12+
mount -t iso9660 -o ro /dev/disk/by-label/cidata /mnt/lima-cidata
13+
install -m 755 /mnt/lima-cidata/lima-guestagent /usr/local/bin/lima-guestagent
14+
umount /mnt/lima-cidata
15+
16+
# Launch the guestagent service
17+
if [ -f /etc/alpine-release ]; then
18+
rc-update add lima-guestagent default
19+
rc-service lima-guestagent start
20+
else
21+
until [ -e "/run/user/{{.UID}}/systemd/private" ]; do sleep 3; done
22+
sudo -iu "{{.User}}" "XDG_RUNTIME_DIR=/run/user/{{.UID}}" lima-guestagent install-systemd
23+
fi
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/bin/bash
2+
set -eux -o pipefail
3+
4+
# Install minimum dependencies
5+
if command -v apt-get 2>&1 >/dev/null; then
6+
export DEBIAN_FRONTEND=noninteractive
7+
apt-get update
8+
{{- if .Mounts}}
9+
apt-get install -y sshfs
10+
{{- end }}
11+
{{- if or .Containerd.System .Containerd.User }}
12+
apt-get install -y iptables
13+
{{- end }}
14+
{{- if .Containerd.User}}
15+
apt-get install -y uidmap fuse3 dbus-user-session
16+
{{- end }}
17+
elif command -v dnf 2>&1 >/dev/null; then
18+
: {{/* make sure the "elif" block is never empty */}}
19+
{{- if .Mounts}}
20+
dnf install -y fuse-sshfs
21+
{{- end}}
22+
{{- if or .Containerd.System .Containerd.User }}
23+
dnf install -y iptables
24+
{{- end }}
25+
{{- if .Containerd.User}}
26+
dnf install -y shadow-utils fuse3
27+
if [ ! -f /usr/bin/fusermount ]; then
28+
# Workaround for https://github.com/containerd/stargz-snapshotter/issues/340
29+
ln -s fusermount3 /usr/bin/fusermount
30+
fi
31+
{{- end}}
32+
elif command -v apk 2>&1 >/dev/null; then
33+
: {{/* make sure the "elif" block is never empty */}}
34+
{{- if .Mounts}}
35+
if ! command -v sshfs 2>&1 >/dev/null; then
36+
apk update
37+
apk add sshfs
38+
fi
39+
modprobe fuse
40+
{{- end}}
41+
fi
42+
# Modify /etc/fuse.conf to allow "-o allow_root"
43+
{{- if .Mounts }}
44+
if ! grep -q "^user_allow_other" /etc/fuse.conf ; then
45+
echo "user_allow_other" >> /etc/fuse.conf
46+
fi
47+
{{- end}}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/bin/bash
2+
set -eux -o pipefail
3+
4+
# This script does not work unless systemd is available
5+
command -v systemctl 2>&1 >/dev/null || exit 0
6+
7+
if [ ! -x /usr/local/bin/nerdctl ]; then
8+
mkdir -p -m 600 /mnt/lima-cidata
9+
mount -t iso9660 -o ro /dev/disk/by-label/cidata /mnt/lima-cidata
10+
tar Cxzf /usr/local /mnt/lima-cidata/nerdctl-full.tgz
11+
umount /mnt/lima-cidata
12+
fi
13+
{{- if .Containerd.System}}
14+
mkdir -p /etc/containerd
15+
cat >"/etc/containerd/config.toml" <<EOF
16+
version = 2
17+
[proxy_plugins]
18+
[proxy_plugins."stargz"]
19+
type = "snapshot"
20+
address = "/run/containerd-stargz-grpc/containerd-stargz-grpc.sock"
21+
EOF
22+
systemctl enable --now containerd buildkit stargz-snapshotter
23+
{{- end}}
24+
{{- if .Containerd.User}}
25+
modprobe tap || true
26+
if [ ! -e "/home/{{.User}}.linux/.config/containerd/config.toml" ]; then
27+
mkdir -p "/home/{{.User}}.linux/.config/containerd"
28+
cat >"/home/{{.User}}.linux/.config/containerd/config.toml" <<EOF
29+
version = 2
30+
[proxy_plugins]
31+
[proxy_plugins."fuse-overlayfs"]
32+
type = "snapshot"
33+
address = "/run/user/{{.UID}}/containerd-fuse-overlayfs.sock"
34+
[proxy_plugins."stargz"]
35+
type = "snapshot"
36+
address = "/run/user/{{.UID}}/containerd-stargz-grpc/containerd-stargz-grpc.sock"
37+
EOF
38+
chown -R "{{.User}}" "/home/{{.User}}.linux/.config"
39+
fi
40+
selinux=
41+
if command -v selinuxenabled 2>&1 >/dev/null && selinuxenabled; then
42+
selinux=1
43+
fi
44+
if [ ! -e "/home/{{.User}}}}.linux/.config/systemd/user/containerd.service" ]; then
45+
until [ -e "/run/user/{{.UID}}/systemd/private" ]; do sleep 3; done
46+
if [ -n "$selinux" ]; then
47+
echo "Temporarily disabling SELinux, during installing containerd units"
48+
setenforce 0
49+
fi
50+
sudo -iu "{{.User}}" "XDG_RUNTIME_DIR=/run/user/{{.UID}}" systemctl --user enable --now dbus
51+
sudo -iu "{{.User}}" "XDG_RUNTIME_DIR=/run/user/{{.UID}}" containerd-rootless-setuptool.sh install
52+
sudo -iu "{{.User}}" "XDG_RUNTIME_DIR=/run/user/{{.UID}}" containerd-rootless-setuptool.sh install-buildkit
53+
sudo -iu "{{.User}}" "XDG_RUNTIME_DIR=/run/user/{{.UID}}" containerd-rootless-setuptool.sh install-fuse-overlayfs
54+
if ! sudo -iu "{{.User}}" "XDG_RUNTIME_DIR=/run/user/{{.UID}}" containerd-rootless-setuptool.sh install-stargz; then
55+
echo >&2 "WARNING: rootless stargz does not seem supported on this host (kernel older than 5.11?)"
56+
fi
57+
if [ -n "$selinux" ]; then
58+
echo "Restoring SELinux"
59+
setenforce 1
60+
fi
61+
fi
62+
{{- end}}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#cloud-config
2+
# vim:syntax=yaml
3+
4+
growpart:
5+
mode: auto
6+
devices: ['/']
7+
8+
users:
9+
- name: "{{.User}}"
10+
uid: "{{.UID}}"
11+
homedir: "/home/{{.User}}.linux"
12+
shell: /bin/bash
13+
sudo: ALL=(ALL) NOPASSWD:ALL
14+
lock_passwd: true
15+
ssh-authorized-keys:
16+
{{- range $val := .SSHPubKeys}}
17+
- {{$val}}
18+
{{- end}}
19+
20+
write_files:
21+
- content: |
22+
#!/bin/sh
23+
set -eu
24+
# TODO: rename lima-cidata.boot to lima-cidata,
25+
# after deduplicating it in 25-guestagent-base-boot.sh
26+
LIMA_CIDATA_MNT="/mnt/lima-cidata.boot"
27+
LIMA_CIDATA_DEV="/dev/disk/by-label/cidata"
28+
mkdir -p -m 700 "${LIMA_CIDATA_MNT}"
29+
mount -o ro,mode=0700,dmode=0700,overriderockperm,exec,uid=0 "${LIMA_CIDATA_DEV}" "${LIMA_CIDATA_MNT}"
30+
export LIMA_CIDATA_MNT
31+
CODE=0
32+
for f in "${LIMA_CIDATA_MNT}"/boot/*; do
33+
echo "Executing $f"
34+
if ! "$f"; then
35+
echo "Failed to execute $f"
36+
CODE=1
37+
fi
38+
done
39+
exit "$CODE"
40+
owner: root:root
41+
path: /var/lib/cloud/scripts/per-boot/00-lima.boot.sh
42+
permissions: '0755'
43+
# TODO: embed lima-guestagent.openrc in 10-alpine-prep.boot.sh
44+
- content: |
45+
#!/sbin/openrc-run
46+
supervisor=supervise-daemon
47+
48+
name="lima-guestagent"
49+
description="Forward ports to the lima-hostagent"
50+
51+
export XDG_RUNTIME_DIR="/run/user/{{.UID}}"
52+
command=/usr/local/bin/lima-guestagent
53+
command_args="daemon"
54+
command_background=true
55+
command_user="{{.User}}:{{.User}}"
56+
pidfile="${XDG_RUNTIME_DIR}/lima-guestagent.pid"
57+
owner: root:root
58+
path: /var/lib/lima-guestagent/lima-guestagent.openrc
59+
permissions: '0755'
60+
{{- if .Provision}}
61+
# TODO: move Provision scripts to ISO
62+
- content: |
63+
#!/bin/bash
64+
set -eu -o pipefail
65+
{{- range $i, $val := .Provision}}
66+
{{- $script := printf "/var/lib/lima-guestagent/provision-%02d-%s" $i $val.Mode}}
67+
{{- if eq $val.Mode "system"}}
68+
{{$script}}
69+
{{- else}}
70+
until [ -e "/run/user/{{.UID}}/systemd/private" ]; do sleep 3; done
71+
sudo -iu "{{.User}}" "XDG_RUNTIME_DIR=/run/user/{{.UID}}" {{$script}}
72+
{{- end}}
73+
{{- end}}
74+
owner: root:root
75+
path: /var/lib/cloud/scripts/per-boot/50-execute-provision-scripts.boot.sh
76+
permissions: '0755'
77+
{{- end}}
78+
{{- range $i, $val := .Provision}}
79+
- content: {{printf "%q" $val.Script}}
80+
owner: root:root
81+
path: {{printf "/var/lib/lima-guestagent/provision-%02d-%s" $i $val.Mode}}
82+
permissions: '0755'
83+
{{- end}}

0 commit comments

Comments
 (0)