Skip to content

Add remodel tests for Ubuntu Core 20 => 22 and 22 => 24 (New) #1858

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
124 changes: 124 additions & 0 deletions providers/base/bin/remodel_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/usr/bin/env python3
# Copyright 2025 Canonical Ltd.
# All rights reserved.
#
# Written by:
# Authors: Philip Meulengracht <[email protected]>

import argparse
import os
import platform
import subprocess
from urllib.request import urlretrieve


def get_platform():
plt = platform.platform()
if "raspi-aarch64" in plt:
return "pi-arm64"
elif "raspi" in plt:
return "pi-armhf"
elif "x86_64" in plt:
return "amd64"
raise SystemExit(f"platform not supported for remodeling test: {plt}")


# Currently images used in certifications are sourced from cdimage,
# those images builds using the models supplied in canonical/models.
# Make sure we use the same models that come from the same authority,
# otherwise remodeling will fail.
def download_model(uc_ver):
base_uri = "https://raw.githubusercontent.com/canonical/models/"
branch = "refs/heads/master/"
model = f"ubuntu-core-{uc_ver}-{get_platform()}-dangerous.model"
print(f"downloading model for remodeling: {base_uri + branch + model}")
path, _ = urlretrieve(base_uri + branch + model)
return path


# downloads a snap to the tmp folder
def download_snap(name, out, channel):
dir = os.getcwd()
os.chdir("/tmp")
subprocess.run(
[
"snap",
"download",
name,
f"--channel=latest/{channel}",
f"--basename={out}",
]
)
os.chdir(dir)


def download_snaps(uc_ver):
# use stable for remodel, we are not testing the snaps we are
# remodeling to, but rather the process works.
channel = "stable"
download_snap(f"core{uc_ver}", "base", channel)
if "pi" in get_platform():
download_snap("pi", "gadget", f"--channel={uc_ver}/{channel}")
download_snap("pi-kernel", "kernel", f"--channel={uc_ver}/{channel}")
else:
download_snap("pc", "gadget", f"--channel={uc_ver}/{channel}")
download_snap("pc-kernel", "kernel", f"--channel={uc_ver}/{channel}")


def main():
"""Run remodel of an Ubuntu Core host."""

parser = argparse.ArgumentParser()
parser.add_argument(
"target",
help="which verison of ubuntu-core that should be remodeled to",
choices=["22", "24"],
)

# resolve the snaps for the remodel if offline has been requested
# (currently offline was used for testing in certain scenarios during
# test development) - for normal testing offline should not be needed
parser.add_argument(
"--offline",
help="whether the remodel should be offline",
action="store_true",
)
args = parser.parse_args()

# resolve the model for the current platform
model_path = download_model(args.target)

if args.offline:
download_snaps(args.target)

# instantiate the offline remodel
print("initiating offline device remodel")
subprocess.run(
[
"sudo",
"snap",
"remodel",
"--offline",
"--snap",
"/tmp/base.snap",
"--assertion",
"/tmp/base.assert",
"--snap",
"/tmp/gadget.snap",
"--assertion",
"/tmp/gadget.assert",
"--snap",
"/tmp/kernel.snap",
"--assertion",
"/tmp/kernel.assert",
model_path,
]
)
else:
# instantiate the remodel
print("initiating device remodel")
subprocess.run(["sudo", "snap", "remodel", model_path])


if __name__ == "__main__":
exit(main())
122 changes: 122 additions & 0 deletions providers/base/units/ubuntucore/jobs.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,128 @@ _verification:
plugin: manual
category_id: ubuntucore

id: ubuntucore/remodels
_summary: Create a list of remodel tests
_description:
Remodeling is supported for the below versions, and variants of the remodeling
test must be created for each
category_id: ubuntucore
plugin: resource
command:
echo source: 22
echo destination: 24
echo
echo source: 20
echo destination: 22

id: ubuntucore/remodel-{source}-to-{destination}
category_id: ubuntucore
_summary: Remodel Ubuntu Core {source} to {destination}
_purpose:
Verify the system can remodel from ubuntu core {source} to {destination} under normal
circumstances. The requirement is that the official models from canonical
are used for the running Ubuntu Core host. Multiple reboots will happen
as a part of this test.
unit: template
template-id: ubuntucore/remodel
template-resource: ubuntucore/remodels
requires: os.distributor_id == 'Ubuntu Core'
template-unit: job
plugin: shell
user: root
estimated_duration: 60.0
command:
set -e
snap model
snap model | grep "ubuntu-core-{source}"
remodel_test.py {destination}

id: ubuntucore/remodel-reboot-{source}-first
category_id: ubuntucore
_summary: First remodel checkpoint to reboot system during remodel.
_purpose:
A system reboot will be requested as a part of requesting a remodel, this serves
to be a checkpoint for that, and waits for the reboot to be requested.
unit: template
template-id: ubuntucore/remodel-reboot-first
template-resource: ubuntucore/remodels
requires: os.distributor_id == 'Ubuntu Core'
template-unit: job
plugin: shell
user: root
flags: noreturn
estimated_duration: 30.0
command:
set -e
max_attempts=30
attempt_num=1
success=false
while [ $success = false ] && [ $attempt_num -le $max_attempts ]; do
journalctl -b -u snapd | grep "Waiting for system reboot"
if [ $? -eq 0 ]; then
success=true
else
echo "Attemp $attempt_num: waiting for reboot request"
attempt_num=$(( attempt_num + 1 ))
sleep 1
fi
done
reboot

id: ubuntucore/remodel-reboot-{source}-second
category_id: ubuntucore
_summary: Second remodel checkpoint to reboot system during remodel.
_purpose:
At this point, the remodel will start, the first reboot was to create a
recovery system and the next will be to start the remodel itself.
This will take a while and do several reboots but not be observed by
checkbox
unit: template
template-id: ubuntucore/remodel-reboot-second
template-resource: ubuntucore/remodels
requires: os.distributor_id == 'Ubuntu Core'
template-unit: job
plugin: shell
user: root
flags: noreturn
estimated_duration: 300.0
command:
set -e
max_attempts=60
attempt_num=1
success=false
while [ $success = false ] && [ $attempt_num -le $max_attempts ]; do
journalctl -b -u snapd | grep "Waiting for system reboot"
if [ $? -eq 0 ]; then
success=true
else
echo "Attemp $attempt_num: waiting for reboot request"
attempt_num=$(( attempt_num + 1 ))
sleep 5
fi
done
reboot

id: ubuntucore/remodel-{source}-to-{destination}-verify
category_id: ubuntucore
_summary: Verify remodel of Ubuntu Core {source} to {destination}
unit: template
template-id: ubuntucore/remodel-verify
template-resource: ubuntucore/remodels
requires: os.distributor_id == 'Ubuntu Core'
template-unit: job
plugin: shell
user: root
estimated_duration: 0.1
command:
set -e
cat /proc/cmdline
snap model
snap changes
systemctl is-active ssh
cat /proc/cmdline | grep snapd_recovery_mode=run
snap model | grep "ubuntu-core-{destination}"

unit: template
template-resource: lsb
template-filter: lsb.distributor_id == 'Ubuntu Core'
Expand Down
26 changes: 26 additions & 0 deletions providers/base/units/ubuntucore/test-plan.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,29 @@ include:
ubuntucore/os-recovery-mode
ubuntucore/os-fail-boot-(?!with-refresh-control).*
ubuntucore/sshd

id: ubuntucore-20-team
unit: test plan
_name: Automated tests from the Ubuntu Core Team for Ubuntu Core 20
_description: Runs automated OS feature tests for Ubuntu Core 20 devices.
bootstrap_include:
os
ubuntucore/remodels
include:
ubuntucore/remodel-20-to-22
ubuntucore/remodel-reboot-20-first
ubuntucore/remodel-reboot-20-second
ubuntucore/remodel-20-to-22-verify

id: ubuntucore-22-team
unit: test plan
_name: Automated tests from the Ubuntu Core Team for Ubuntu Core 20
_description: Runs automated OS feature tests for Ubuntu Core 20 devices.
bootstrap_include:
os
ubuntucore/remodels
include:
ubuntucore/remodel-22-to-24
ubuntucore/remodel-reboot-22-first
ubuntucore/remodel-reboot-22-second
ubuntucore/remodel-22-to-24-verify
Loading