Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/craft-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Snapcraft test

on:
pull_request:
merge_group:
push:
branches:
- main
- hotfix/*

concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: true

jobs:
craft-test:
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
runner:
- ubuntu-22.04
- ubuntu-24.04
- ubuntu-22.04-arm
- ubuntu-24.04-arm

steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- uses: canonical/craft-actions/snapcraft/setup@main
with:
channel: latest/edge

- name: Run spread tests
run: snapcraft test
28 changes: 14 additions & 14 deletions spread.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
project: testcraft

path: /testcraft
environment:
PROJECT_PATH: /testcraft
PATH: /snap/bin:$PATH
CRAFT_DEBUG: "1"
# path: /testcraft
# environment:
# PROJECT_PATH: /testcraft
# PATH: /snap/bin:$PATH
# CRAFT_DEBUG: "1"

include:
- tests/spread
# include:
# - tests/spread

exclude:
- .venv
Expand Down Expand Up @@ -133,23 +133,23 @@ backends:
- ubuntu-25.10-64:
workers: 4
craft:
type: adhoc
allocate: "false"
systems:
- ubuntu-20.04-64:
- ubuntu-22.04-64:
- ubuntu-24.04-64:
- ubuntu-25.10-64:
- ubuntu-20.04:
- ubuntu-22.04:
- ubuntu-24.04:
- ubuntu-25.10:

prepare: |
sudo apt-get update

sudo snap wait system seed.loaded
# IDK why but if we don't sleep after this we get:
# error: cannot install "snapd": Post "https://api.snapcraft.io/v2/snaps/refresh": context canceled
sleep 4
sudo snap install snapd || sudo snap refresh snapd
sudo snap wait system seed.loaded

sudo snap install --dangerous --classic tests/spread/*$(dpkg --print-architecture).snap
sudo snap install --dangerous --classic "$CRAFT_ARTIFACT"

# Select older LXD channels for older bases.
. /etc/os-release
Expand Down
242 changes: 183 additions & 59 deletions spread/.extension
Original file line number Diff line number Diff line change
@@ -1,66 +1,190 @@
#!/bin/bash

SCRIPTDIR=$(dirname "$(realpath "${0}")")

allocate-lxd-vm(){
# Allocate the relevant backend.
DISTRO=$(echo "$SPREAD_SYSTEM" | cut -d- -f1)
SERIES=$(echo "$SPREAD_SYSTEM" | cut -d- -f2)
VM_NAME="${VM_NAME:-${DISTRO}-${SERIES}-${RANDOM}}"
VM_NAME=$(echo "$VM_NAME" | tr . -)
DISK="${DISK:-20}"
CPU="${CPU:-4}"
MEM="${MEM:-8}"

cloud_config="$(mktemp)"
sed "s|SPREAD_PASSWORD|$SPREAD_PASSWORD|g" "${SCRIPTDIR}/cloud-config.yaml" > "$cloud_config"

lxc launch --vm \
"${DISTRO}:${SERIES}" \
"${VM_NAME}" \
--config user.user-data="$(cat "$cloud_config")" \
--config limits.cpu="${CPU}" \
--config limits.memory="${MEM}GiB" \
--device root,size="${DISK}GiB" >&2

# Wait for the spread user
while ! lxc exec "${VM_NAME}" -- id -u spread &>/dev/null; do sleep 0.5; done

# Wait for cloud-init to complete
lxc exec "${VM_NAME}" -- cloud-init status --wait &>/dev/null
# Wait for snap to complete seeding
lxc exec "${VM_NAME}" -- snap wait system seed.loaded &> /dev/null

rm "$cloud_config"

# Set the instance address for spread
while [[ -z $(lxc ls --format csv --columns 4 name="${VM_NAME}") ]]; do
sleep 0.1
done
lxc ls --format csv --columns 4 name="${VM_NAME}"
usage() {
echo "usage: $(basename "$0") [command]"
echo "valid commands:"
echo " allocate Create a backend instance to run tests on"
echo " discard Destroy a backend instance used to run tests"
echo " backend-prepare Set up the system to run tests"
echo " backend-restore Restore the system after the tests ran"
echo " backend-prepare-each Prepare the system before each test"
echo " backend-restore-each Restore the system after each test run"
}

discard-lxd-vm(){
instance_name="$(lxc ls --format csv --columns n4 "ipv4=$SPREAD_SYSTEM_ADDRESS"|cut -f1 -d','|head -n 1)"
lxc delete --force "${instance_name}"
prepare() {
case "$SPREAD_SYSTEM" in
fedora*)
dnf update -y
dnf install -y snapd curl jq
while ! snap install snapd; do
echo "waiting for snapd..."
sleep 2
done
;;
ubuntu*)
apt update
apt install -y curl jq
;;
esac

snap wait system seed.loaded
snap refresh --hold

if systemctl show unattended-upgrades.service --property=LoadState | grep -q 'LoadState=loaded'; then
if systemctl is-enabled unattended-upgrades.service; then
systemctl stop unattended-upgrades.service
systemctl mask unattended-upgrades.service
fi
fi
}

restore() {
case "$SPREAD_SYSTEM" in
ubuntu* | debian*)
apt autoremove -y --purge
;;
esac

rm -Rf "$PROJECT_PATH"
mkdir -p "$PROJECT_PATH"
}

prepare_each() {
true
}

restore_each() {
true
}

allocate_lxdvm() {
name=$(echo "$SPREAD_SYSTEM" | tr '[:punct:]' -)
system=$(echo "$SPREAD_SYSTEM" | tr / -)
if [[ "$system" =~ ^ubuntu- ]]; then
image="ubuntu:${system#ubuntu-}"
else
image="images:$(echo "$system" | tr - /)"
fi

VM_NAME="${VM_NAME:-spread-${name}-${RANDOM}}"
DISK="${DISK:-20}"
CPU="${CPU:-4}"
MEM="${MEM:-8}"

lxc launch --vm \
"${image}" \
"${VM_NAME}" \
-c limits.cpu="${CPU}" \
-c limits.memory="${MEM}GiB" \
-d root,size="${DISK}GiB"

while ! lxc exec "${VM_NAME}" -- true &>/dev/null; do sleep 0.5; done
lxc exec "${VM_NAME}" -- sed -i 's/^\s*#\?\s*\(PermitRootLogin\|PasswordAuthentication\)\>.*/\1 yes/' /etc/ssh/sshd_config
lxc exec "${VM_NAME}" -- bash -c "if [ -d /etc/ssh/sshd_config.d ]; then echo -e 'PermitRootLogin yes\nPasswordAuthentication yes' > /etc/ssh/sshd_config.d/00-spread.conf; fi"
lxc exec "${VM_NAME}" -- bash -c "echo root:${SPREAD_PASSWORD} | sudo chpasswd || true"

# Print the instance address to stdout
ADDR=""
while [ -z "$ADDR" ]; do ADDR=$(lxc ls -f csv | grep "^${VM_NAME}" | cut -d"," -f3 | cut -d" " -f1); done
echo "$ADDR" 1>&3
}

discard_lxdvm() {
instance_name="$(lxc ls -f csv | grep ",$SPREAD_SYSTEM_ADDRESS " | cut -f1 -d",")"
lxc delete -f "$instance_name"
}

allocate_ci() {
if [ -z "$CI" ]; then
echo "This backend is intended to be used only in CI systems."
exit 1
fi
sudo sed -i 's/^\s*#\?\s*\(PermitRootLogin\|PasswordAuthentication\)\>.*/\1 yes/' /etc/ssh/sshd_config
if [ -d /etc/ssh/sshd_config.d ]; then echo -e 'PermitRootLogin yes\nPasswordAuthentication yes' | sudo tee /etc/ssh/sshd_config.d/00-spread.conf; fi
sudo systemctl daemon-reload
sudo systemctl restart ssh

echo "root:${SPREAD_PASSWORD}" | sudo chpasswd || true

# Print the instance address to stdout
echo localhost >&3
}

discard_ci() {
true
}

allocate() {
exec 3>&1
exec 1>&2

case "$1" in
lxd-vm)
allocate_lxdvm
;;
ci)
allocate_ci
;;
*)
echo "unsupported backend $1" 2>&1
;;
esac
}

discard() {
case "$1" in
lxd-vm)
discard_lxdvm
;;
ci)
discard_ci
;;
*)
echo "unsupported backend $1" 2>&1
;;
esac
}

case $2 in
lxd-vm)
case $1 in
allocate)
allocate-lxd-vm
;;
discard)
discard-lxd-vm
;;
*)
echo Step not needed >&2
;;
esac
;;
*)
echo Unknown backend >&2
exit 1
;;
set -e

while getopts "" o; do
case "${o}" in
*)
usage
exit 1
;;
esac
done
shift $((OPTIND - 1))

CMD="$1"
PARM="$2"

if [ -z "$CMD" ]; then
usage
exit 0
fi

case "$CMD" in
allocate)
allocate "$PARM"
;;
discard)
discard "$PARM"
;;
backend-prepare)
prepare
;;
backend-restore)
restore
;;
backend-prepare-each)
prepare_each
;;
backend-restore-each)
restore_each
;;
*)
echo "unknown command $CMD" >&2
;;
esac
14 changes: 14 additions & 0 deletions spread/cloud-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,17 @@ users:
plain_text_passwd: spread
lock_passwd: false
sudo: ALL=(ALL) NOPASSWD:ALL

chpasswd:
list: |
root:SPREAD_PASSWORD
expire: false

runcmd:
- |
if [ -d /etc/ssh/sshd_config.d/ ]; then
echo 'PermitRootLogin yes' > /etc/ssh/sshd_config.d/00-spread.conf
else
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
fi
systemctl restart ssh || systemctl restart sshd
Loading