diff --git a/.github/workflows/integration_test_app.yaml b/.github/workflows/integration_test_app.yaml index 089ee6a5..c81933f3 100644 --- a/.github/workflows/integration_test_app.yaml +++ b/.github/workflows/integration_test_app.yaml @@ -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 @@ -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 diff --git a/app/src/github_runner_image_builder/config.py b/app/src/github_runner_image_builder/config.py index 23802f0d..579fe295 100644 --- a/app/src/github_runner_image_builder/config.py +++ b/app/src/github_runner_image_builder/config.py @@ -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: @@ -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": @@ -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()) diff --git a/app/src/github_runner_image_builder/openstack_builder.py b/app/src/github_runner_image_builder/openstack_builder.py index c94743c4..36cc7f63 100644 --- a/app/src/github_runner_image_builder/openstack_builder.py +++ b/app/src/github_runner_image_builder/openstack_builder.py @@ -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, @@ -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) @@ -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. @@ -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. @@ -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 diff --git a/app/src/github_runner_image_builder/templates/cloud-init.sh.j2 b/app/src/github_runner_image_builder/templates/cloud-init.sh.j2 index f13fe4b4..2b4ebcfa 100644 --- a/app/src/github_runner_image_builder/templates/cloud-init.sh.j2 +++ b/app/src/github_runner_image_builder/templates/cloud-init.sh.j2 @@ -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() { @@ -88,6 +91,7 @@ function disable_unattended_upgrades() { function enable_network_fair_queuing_congestion() { /usr/bin/cat < Path: diff --git a/app/tests/integration/test_openstack_builder.py b/app/tests/integration/test_openstack_builder.py index 078ca204..29f2bc40 100644 --- a/app/tests/integration/test_openstack_builder.py +++ b/app/tests/integration/test_openstack_builder.py @@ -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 }, ), ), diff --git a/app/tests/integration/testdata/test_script.sh b/app/tests/integration/testdata/test_script.sh index 0fbf17ab..bfde83a6 100644 --- a/app/tests/integration/testdata/test_script.sh +++ b/app/tests/integration/testdata/test_script.sh @@ -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' diff --git a/app/tests/unit/test_config.py b/app/tests/unit/test_config.py index d3c646a7..dac4243d 100644 --- a/app/tests/unit/test_config.py +++ b/app/tests/unit/test_config.py @@ -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"), ], ) diff --git a/app/tests/unit/test_openstack_builder.py b/app/tests/unit/test_openstack_builder.py index 2a1278e2..97350053 100644 --- a/app/tests/unit/test_openstack_builder.py +++ b/app/tests/unit/test_openstack_builder.py @@ -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() {{ @@ -799,6 +802,7 @@ def test__generate_cloud_init_script( function enable_network_fair_queuing_congestion() {{ /usr/bin/cat <