From 3718a70f76d44c399a05224e842215ab3d91c299 Mon Sep 17 00:00:00 2001 From: Alex Lowe Date: Thu, 19 Mar 2026 12:47:25 -0400 Subject: [PATCH 1/4] ci(spread): support snapcraft test command - Comment out top-level path/environment/include so snapcraft test can manage them - Remove type/allocate stub from craft backend so snapcraft test can inject its own adhoc configuration - Switch snap install to use $CRAFT_ARTIFACT env var set by snapcraft test - Configure root SSH login in cloud-config.yaml for the craft backend - Run apt-get update in prepare to ensure package lists are fresh Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- spread.yaml | 20 ++++++++++---------- spread/cloud-config.yaml | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/spread.yaml b/spread.yaml index a5e6a9e71..d1b9fd231 100644 --- a/spread.yaml +++ b/spread.yaml @@ -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 @@ -127,8 +127,6 @@ backends: - ubuntu-25.10-64: workers: 4 craft: - type: adhoc - allocate: "false" systems: - ubuntu-20.04-64: - ubuntu-22.04-64: @@ -136,6 +134,8 @@ backends: - ubuntu-25.10-64: 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 @@ -143,7 +143,7 @@ prepare: | sudo snap install snapd || sudo snap refresh snapd sudo snap wait system seed.loaded - sudo snap install --dangerous --classic tests/spread/*.snap + sudo snap install --dangerous --classic "$CRAFT_ARTIFACT" # Select older LXD channels for older bases. . /etc/os-release diff --git a/spread/cloud-config.yaml b/spread/cloud-config.yaml index a823d4fbf..52d7e07ba 100644 --- a/spread/cloud-config.yaml +++ b/spread/cloud-config.yaml @@ -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 From dbd0c23c65fc21af5a87e23ae6c23b0794a87986 Mon Sep 17 00:00:00 2001 From: Alex Lowe Date: Thu, 19 Mar 2026 12:54:29 -0400 Subject: [PATCH 2/4] ci: add Snapcraft test workflow Runs `snapcraft test` on all available Linux platforms using canonical/craft-actions for setup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/craft-test.yaml | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/craft-test.yaml diff --git a/.github/workflows/craft-test.yaml b/.github/workflows/craft-test.yaml new file mode 100644 index 000000000..8a4389bbd --- /dev/null +++ b/.github/workflows/craft-test.yaml @@ -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 From d9371a74cb6daaadef367c49a6d168768b610528 Mon Sep 17 00:00:00 2001 From: Alex Lowe Date: Thu, 19 Mar 2026 13:19:36 -0400 Subject: [PATCH 3/4] ci(spread): add non-suffixed system names for craft backend GitHub Actions runners use system names like 'ubuntu-22.04' (without the '-64' suffix), so spread's provider filter fails to match the '-64'-suffixed names. Add both variants. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- spread.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spread.yaml b/spread.yaml index d1b9fd231..a6706f51a 100644 --- a/spread.yaml +++ b/spread.yaml @@ -132,6 +132,10 @@ backends: - 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 From 07b2be31323a115f4600655efa18910ee1e1cb19 Mon Sep 17 00:00:00 2001 From: Alex Lowe Date: Thu, 19 Mar 2026 14:10:29 -0400 Subject: [PATCH 4/4] fix: grab .extension file from fetch-service --- spread.yaml | 4 - spread/.extension | 242 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 183 insertions(+), 63 deletions(-) diff --git a/spread.yaml b/spread.yaml index a6706f51a..f10a43525 100644 --- a/spread.yaml +++ b/spread.yaml @@ -128,10 +128,6 @@ backends: workers: 4 craft: 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: diff --git a/spread/.extension b/spread/.extension index 237f84561..2e9b6918d 100755 --- a/spread/.extension +++ b/spread/.extension @@ -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