Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
11a2e59
Add ubuntu 26.04 (resolute) support
yhaliaw Mar 4, 2026
36db9a3
Add downloading of resolute image
yhaliaw Mar 5, 2026
7b57328
Disable HWE kernel for resolute
yhaliaw Mar 5, 2026
7ee138d
Use tmate for debugging
yhaliaw Mar 6, 2026
75684f2
Print out debug info
yhaliaw Mar 6, 2026
350dc47
Remove check for bbr as TCP conestion_control for 26.04
yhaliaw Mar 6, 2026
93bd704
Enable bbr TCP congestion control in cloud init
yhaliaw Mar 6, 2026
0b5519f
Debug
yhaliaw Mar 6, 2026
8ecf281
Remove tcp_bbr support for 26.04
yhaliaw Mar 6, 2026
3d193b1
add debug
yhaliaw Mar 9, 2026
987896e
Test a fix for the sudo environment variable issue
yhaliaw Mar 9, 2026
4f47463
Attempt to fix resolute env var issue with fabric
yhaliaw Mar 9, 2026
d065977
Test inline passing of env var
yhaliaw Mar 9, 2026
5c0c2f4
Fix a unremoved variable
yhaliaw Mar 10, 2026
db1d1f4
Add debug
yhaliaw Mar 10, 2026
03febc3
Debug
yhaliaw Mar 10, 2026
a8d21a0
Debug
yhaliaw Mar 10, 2026
9d85ae3
Attempt tmate debug
yhaliaw Mar 11, 2026
50c615f
Fix debug
yhaliaw Mar 11, 2026
cc51a95
Test a fix for env var
yhaliaw Mar 11, 2026
b5cd650
Test fix
yhaliaw Mar 11, 2026
2d68ddf
Add more debug statements
yhaliaw Mar 11, 2026
cf27833
Test removing non-letter characters
yhaliaw Mar 11, 2026
d3417fe
Fix typo
yhaliaw Mar 11, 2026
1ab50fd
Test
yhaliaw Mar 11, 2026
294c05d
Test commands
yhaliaw Mar 11, 2026
d3e391e
Debug
yhaliaw Mar 11, 2026
597d497
Test script
yhaliaw Mar 11, 2026
b224ce5
Fix
yhaliaw Mar 11, 2026
f6d1f8c
Debug
yhaliaw Mar 11, 2026
70bfe23
Test
yhaliaw Mar 11, 2026
4074b74
Print envs
yhaliaw Mar 11, 2026
b7af606
Test
yhaliaw Mar 12, 2026
e9f38b9
Test flush to disk
yhaliaw Mar 12, 2026
7054cf6
Test
yhaliaw Mar 12, 2026
2c59024
Test
yhaliaw Mar 12, 2026
261c3fa
Test
yhaliaw Mar 12, 2026
57aba6b
Test
yhaliaw Mar 12, 2026
9027c8f
Test
yhaliaw Mar 12, 2026
1d05827
Update the test script
yhaliaw Mar 12, 2026
00440bb
Test
yhaliaw Mar 12, 2026
897caab
Test
yhaliaw Mar 12, 2026
66af9f7
TEST
yhaliaw Mar 12, 2026
be135aa
Fix test bash script
yhaliaw Mar 16, 2026
428c136
Update the test script
yhaliaw Mar 16, 2026
72017f4
Fix lints and unit test
yhaliaw Mar 16, 2026
4553a00
Add back assertions
yhaliaw Mar 16, 2026
9e8d010
Enable the test for other flavors
yhaliaw Mar 16, 2026
641b275
Test other flavors
yhaliaw Mar 16, 2026
5c8a0f5
Test
yhaliaw Mar 16, 2026
853c0f6
Test
yhaliaw Mar 16, 2026
5c4a70d
Merge branch 'main' into feat/resolute-support
yhaliaw Mar 16, 2026
27fe3d3
Test
yhaliaw Mar 17, 2026
7679e6f
Test sudo-rs logging disable
yhaliaw Mar 17, 2026
48c4869
Test disable sudo-rs logs
yhaliaw Mar 17, 2026
74016b0
Test another way to disable sudo-rs logging
yhaliaw Mar 17, 2026
0ca2137
Test
yhaliaw Mar 17, 2026
f96ebb4
Remove legacy code
yhaliaw Mar 17, 2026
fcd97d7
Test
yhaliaw Mar 17, 2026
2f9b7db
Fix comments
yhaliaw Mar 17, 2026
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
8 changes: 7 additions & 1 deletion .github/workflows/integration_test_app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: false
matrix:
image: [focal, jammy, noble]
image: [focal, jammy, noble, resolute]
arch: [amd64, arm64, s390x, ppc64le]
exclude:
- image: focal
Expand All @@ -27,6 +27,12 @@ jobs:
arch: ppc64le
- image: jammy
arch: s390x
- image: resolute
arch: arm64
- image: resolute
arch: ppc64le
- image: resolute
arch: s390x
steps:
- uses: actions/checkout@v6.0.2
- uses: canonical/setup-lxd@v0.1.3
Expand Down
7 changes: 6 additions & 1 deletion app/src/github_runner_image_builder/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,16 @@ class BaseImage(str, Enum):
FOCAL: The focal ubuntu LTS image.
JAMMY: The jammy ubuntu LTS image.
NOBLE: The noble ubuntu LTS image.
RESOLUTE: The resolute ubuntu LTS image.
"""

FOCAL = "focal"
JAMMY = "jammy"
NOBLE = "noble"
RESOLUTE = "resolute"

@classmethod
def get_version(cls, base: "BaseImage") -> Literal["20.04", "22.04", "24.04"]:
def get_version(cls, base: "BaseImage") -> Literal["20.04", "22.04", "24.04", "26.04"]:
"""Change the codename to version tag.

Args:
Expand All @@ -75,6 +77,8 @@ def get_version(cls, base: "BaseImage") -> Literal["20.04", "22.04", "24.04"]:
return "22.04"
case BaseImage.NOBLE:
return "24.04"
case BaseImage.RESOLUTE:
return "26.04"

@classmethod
def from_str(cls, tag_or_name: str) -> "BaseImage":
Expand All @@ -95,6 +99,7 @@ def from_str(cls, tag_or_name: str) -> "BaseImage":
"20.04": BaseImage.FOCAL.value,
"22.04": BaseImage.JAMMY.value,
"24.04": BaseImage.NOBLE.value,
"26.04": BaseImage.RESOLUTE.value,
}
BASE_CHOICES = tuple(
itertools.chain.from_iterable((tag, name) for (tag, name) in LTS_IMAGE_VERSION_TAG_MAP.items())
Expand Down
20 changes: 17 additions & 3 deletions app/src/github_runner_image_builder/openstack_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ def initialize(arch: Arch, cloud_name: str, prefix: str) -> None:
noble_image_path = cloud_image.download_and_validate_image(
arch=arch, base_image=BaseImage.NOBLE, release_date=noble_release_date
)
logger.info("Downloading Resolute image.")
resolute_image_path = cloud_image.download_and_validate_image(
arch=arch, base_image=BaseImage.RESOLUTE
)
logger.info("Uploading Focal image.")
store.upload_image(
arch=arch,
Expand All @@ -169,7 +173,14 @@ def initialize(arch: Arch, cloud_name: str, prefix: str) -> None:
image_path=noble_image_path,
keep_revisions=1,
)

logger.info("Uploading Resolute image.")
store.upload_image(
arch=arch,
cloud_name=cloud_name,
image_name=_get_base_image_name(arch=arch, base=BaseImage.RESOLUTE, prefix=prefix),
image_path=resolute_image_path,
keep_revisions=1,
)
with openstack.connect(cloud=cloud_name) as conn:
_create_keypair(conn=conn, prefix=prefix)
logger.info("Creating security group %s.", SHARED_SECURITY_GROUP_NAME)
Expand Down Expand Up @@ -600,7 +611,9 @@ def _wait_for_cloud_init_complete(


def _execute_external_script(
script_url: str, script_secrets: dict[str, str], ssh_conn: fabric.Connection
script_url: str,
script_secrets: dict[str, str],
ssh_conn: fabric.Connection,
) -> None:
"""Execute the external script on the OpenStack instance.

Expand Down Expand Up @@ -679,7 +692,7 @@ def _get_ssh_connection(
"""Get a valid SSH connection to OpenStack instance.

Args:
conn: The Openstach connection instance.
conn: The OpenStack connection instance.
server: The OpenStack server instance to check if cloud_init is complete.
ssh_key: The key to SSH RSA key to connect to the OpenStack server instance.

Expand Down Expand Up @@ -710,6 +723,7 @@ def _get_ssh_connection(
user="ubuntu",
connect_kwargs={"key_filename": str(ssh_key)},
connect_timeout=SSH_CONNECT_TIMEOUT,
inline_ssh_env=True,
)
result: fabric.Result | None = connection.run(
"echo hello world", warn=True, timeout=SSH_TEST_COMMAND_TIMEOUT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,11 @@ function install_apt_packages() {
DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get upgrade -y
echo "Installing apt packages $packages"
DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get install -y --no-install-recommends ${packages}
echo "Installing linux-generic-hwe-${hwe_version}"
DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get install -y --install-recommends linux-generic-hwe-${hwe_version}
# Skip installing the HWE kernel package on resolute since there is no HWE kernel for it.
if [ $RELEASE != "resolute" ]; then
echo "Installing linux-generic-hwe-${hwe_version}"
DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get install -y --install-recommends linux-generic-hwe-${hwe_version}
fi
}

function disable_unattended_upgrades() {
Expand All @@ -88,6 +91,7 @@ function disable_unattended_upgrades() {
function enable_network_fair_queuing_congestion() {
/usr/bin/cat <<EOF | /usr/bin/sudo /usr/bin/tee -a /etc/sysctl.conf
net.core.default_qdisc=fq
# 26.04 does not support bbr by default, this will have no effect on 26.04.
net.ipv4.tcp_congestion_control=bbr
EOF
/usr/sbin/sysctl -p
Expand Down
38 changes: 22 additions & 16 deletions app/tests/integration/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,63 +59,69 @@ class Commands:
Commands(
name="test sctp support", command="sudo apt-get install lksctp-tools -yq && checksctp"
),
# Exclude 26.04 from HWE kernel test since there is no HWE kernel for it.
Commands(
name="test that HWE kernel is installed",
command="uname -a | "
name="test that HWE kernel is installed (only for non-resolute)",
command="lsb_release -r | grep 26.04 || uname -a | "
"grep $(dpkg -l | grep linux-generic-hwe | awk '{print $3}' | cut -d'.' -f1-3)",
),
Commands(
name="test network congestion policy(fq)",
command="sudo sysctl -a | grep 'net.core.default_qdisc = fq'",
),
Commands(
name="test network congestion policy",
command="sudo sysctl -a | grep 'net.ipv4.tcp_congestion_control = bbr'",
name="test network congestion policy (only for non-resolute)",
command="lsb_release -r | grep 26.04 || "
"sudo sysctl -a | grep 'net.ipv4.tcp_congestion_control = bbr'",
),
Commands(
name="test external script",
command="cat /home/ubuntu/test.txt | grep 'hello world'",
),
Commands(
name="test external script secrets (should exist)",
command='grep -q "SHOULD_EXIST" secret.txt',
command='grep -q "EXIST" /home/ubuntu/secret.txt',
),
Commands(
name="test external script secrets (should not exist)",
command='! grep -q "SHOULD_NOT_EXIST" secret.txt',
command='! grep -q "MISSING" /home/ubuntu/secret.txt',
),
# following commands are security related - ensure no traces of the external script are
# kept in the image
Commands(
name="journal does not contain external script secrets",
command="! journalctl | grep 'SHOULD_EXIST'",
command="! journalctl | grep 'EXIST'",
),
Commands(
name="journal does not contain external script secrets",
command="! journalctl | grep 'SHOULD_NOT_EXIST'",
command="! journalctl | grep 'MISSING'",
),
# The sudo-rs in 26.04 cannot be disabled with "Defaults !syslog".
Commands(
name="journal does not contain external script url",
command=f"! journalctl | grep '{TESTDATA_TEST_SCRIPT_URL}'",
name="journal does not contain external script url (only for non-resolute)",
command=f"lsb_release -r | grep 26.04 || ! journalctl | grep '{TESTDATA_TEST_SCRIPT_URL}'",
),
Commands(
name="journal does not contain script content",
command="! journalctl | grep '/home/ubuntu/secret.txt'",
name="journal does not contain script content (only for non-resolute)",
command="lsb_release -r | grep 26.04 || ! journalctl | grep '/home/ubuntu/secret.txt'",
),
Commands(
name="/var/log/auth.logs does not contain external script secrets",
command="! grep 'SHOULD_EXIST' /var/log/auth.log*",
command="! grep 'EXIST' /var/log/auth.log*",
),
Commands(
name="/var/log/auth.logs does not contain external script secrets",
command="! grep 'SHOULD_NOT_EXIST' /var/log/auth.log*",
command="! grep 'MISSING' /var/log/auth.log*",
),
# The sudo-rs in 26.04 cannot be disabled with "Defaults !syslog".
Commands(
name="/var/log/auth.logs does not contain external script url",
command=f"! grep '{TESTDATA_TEST_SCRIPT_URL}' /var/log/auth.log*",
command="lsb_release -r | grep 26.04 || "
f"! grep '{TESTDATA_TEST_SCRIPT_URL}' /var/log/auth.log*",
),
Commands(
name="/var/log/auth.logs does not contain script content",
command="! grep '/home/ubuntu/secret.txt' /var/log/auth.log*",
command="lsb_release -r | grep 26.04 || "
"! grep '/home/ubuntu/secret.txt' /var/log/auth.log*",
),
)
4 changes: 2 additions & 2 deletions app/tests/integration/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

TESTDATA_TEST_SCRIPT_URL = (
"https://raw.githubusercontent.com/canonical/github-runner-image-builder-operator/"
"cc9d06c43a5feabd278265ab580eca14d5acffd4/app/tests/integration/testdata/test_script.sh"
"be135aa505b37aae29aec0ab13805909c46b7903/app/tests/integration/testdata/test_script.sh"
)


Expand Down Expand Up @@ -114,7 +114,7 @@ def create_lxd_vm_image(
return lxd_image


IMAGE_TO_TAG = {"focal": "20.04", "jammy": "22.04", "noble": "24.04"}
IMAGE_TO_TAG = {"focal": "20.04", "jammy": "22.04", "noble": "24.04", "resolute": "26.04"}


def _create_metadata_tar_gz(image: str, tmp_path: Path) -> Path:
Expand Down
4 changes: 2 additions & 2 deletions app/tests/integration/test_openstack_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ def image_ids_fixture(
script_config=config.ScriptConfig(
script_url=urllib.parse.urlparse(TESTDATA_TEST_SCRIPT_URL),
script_secrets={
"TEST_SECRET": "SHOULD_EXIST", # nosec: hardcoded_password_string
"TEST_NON_SECRET": "SHOULD_NOT_EXIST", # nosec: hardcoded_password_string
"SECRET": "EXIST", # nosec: hardcoded_password_string
"NOEXIST": "MISSING", # nosec: hardcoded_password_string
},
),
),
Expand Down
6 changes: 5 additions & 1 deletion app/tests/integration/testdata/test_script.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#!/bin/bash

# This script is not directly used in the integration tests.
# Modify the TESTDATA_TEST_SCRIPT_URL variable in the test code to point to this script on GitHub
# to change the script in the test.

sudo -H -u ubuntu bash -c 'echo "hello world" > /home/ubuntu/test.txt'
sudo -HE -u ubuntu bash -c 'echo "$TEST_SECRET" > /home/ubuntu/secret.txt'
sudo -H --preserve-env=SECRET -u ubuntu bash -c 'echo "$SECRET" > /home/ubuntu/secret.txt'
1 change: 1 addition & 0 deletions app/tests/unit/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def test_base_image(image: str, expected_base_image: BaseImage):
pytest.param(BaseImage.FOCAL, "20.04", id="focal"),
pytest.param(BaseImage.JAMMY, "22.04", id="jammy"),
pytest.param(BaseImage.NOBLE, "24.04", id="noble"),
pytest.param(BaseImage.RESOLUTE, "26.04", id="resolute"),
pytest.param(None, None, id="None"),
],
)
Expand Down
8 changes: 6 additions & 2 deletions app/tests/unit/test_openstack_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -783,8 +783,11 @@ def test__generate_cloud_init_script(
DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get upgrade -y
echo "Installing apt packages $packages"
DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get install -y --no-install-recommends ${{packages}}
echo "Installing linux-generic-hwe-${{hwe_version}}"
DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get install -y --install-recommends linux-generic-hwe-${{hwe_version}}
# Skip installing the HWE kernel package on resolute since there is no HWE kernel for it.
if [ $RELEASE != "resolute" ]; then
echo "Installing linux-generic-hwe-${{hwe_version}}"
DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get install -y --install-recommends linux-generic-hwe-${{hwe_version}}
fi
}}

function disable_unattended_upgrades() {{
Expand All @@ -799,6 +802,7 @@ def test__generate_cloud_init_script(
function enable_network_fair_queuing_congestion() {{
/usr/bin/cat <<EOF | /usr/bin/sudo /usr/bin/tee -a /etc/sysctl.conf
net.core.default_qdisc=fq
# 26.04 does not support bbr by default, this will have no effect on 26.04.
net.ipv4.tcp_congestion_control=bbr
EOF
/usr/sbin/sysctl -p
Expand Down
2 changes: 1 addition & 1 deletion charmcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ config:
description: |
The base ubuntu OS image to use for the runners. Codename (e.g. "noble") or version tag
(e.g. 24.04) is supported as input. Currently only supports LTS versions of focal and
higher, i.e. focal, jammy, noble.
higher, i.e. focal, jammy, noble, resolute.
build-flavor:
type: string
default: ""
Expand Down
7 changes: 6 additions & 1 deletion src/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@
ARCHITECTURES_PPC64LE = {"ppc64le", "ppc64el"}
ARCHITECTURES_X86 = {"x86_64", "amd64", "x64"}
CLOUD_NAME = "builder"
LTS_IMAGE_VERSION_TAG_MAP = {"20.04": "focal", "22.04": "jammy", "24.04": "noble"}
LTS_IMAGE_VERSION_TAG_MAP = {
"20.04": "focal",
"22.04": "jammy",
"24.04": "noble",
"26.04": "resolute",
}

ARCHITECTURE_CONFIG_NAME = "architecture"
BASE_IMAGE_CONFIG_NAME = "base-image"
Expand Down
Loading