From 5af25f0df0ac218a08f9dca2d0e72d9cbe545c86 Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Mon, 9 Sep 2024 21:53:48 -0600 Subject: [PATCH] tests: add OS_IMAGE_TYPE setting to allow for minimal tests Allow setting CLOUD_INIT_OS_IMAGE_TYPE="mimimal" to support running the full integration test suite against Ubuntu minimal images. Required for SC-1750: Daily jenkins ubuntu minimal test runner for Ubuntu Focal, Jammy and Noble releases. --- doc/rtd/development/integration_tests.rst | 30 ++++++++++++++++++- integration-requirements.txt | 2 +- tests/integration_tests/clouds.py | 5 ++++ tests/integration_tests/conftest.py | 12 ++++++-- .../integration_tests/integration_settings.py | 12 ++++++++ 5 files changed, 57 insertions(+), 4 deletions(-) diff --git a/doc/rtd/development/integration_tests.rst b/doc/rtd/development/integration_tests.rst index aecb0224455..2f8104279dd 100644 --- a/doc/rtd/development/integration_tests.rst +++ b/doc/rtd/development/integration_tests.rst @@ -263,7 +263,7 @@ the form: ``[::::::]`` where ``image_id`` is a cloud's image ID, ``os`` is the OS name, and ``release`` is the OS release name. So, for example, Ubuntu 24.04 LTS (Noble Numbat) on LXD is ``ubuntu:noble::ubuntu::noble::24.04`` or RHEL8 on Amazon is -``ami-justanexample::rhel::8``. When a full specification is given, +``ami-justanexample::rhel::9::9.3``. When a full specification is given, only tests which are intended for use on that OS and release will be executed. @@ -285,6 +285,33 @@ variable to be the desired image specification. OS_IMAGE = 'jammy' +To run integration tests on a specific type/family of image, modify the +``OS_IMAGE_TYPE`` variable to be the desired image type. This comes from +`pycloudlib's ImageType enum`_, which can take the following values: + +- "generic" +- "minimal" +- "Pro" +- "Pro FIPS" + +.. tab-set:: + + .. tab-item:: Inline environment variable + + .. code-block:: bash + + CLOUD_INIT_PLATFORM=lxd_container CLOUD_INIT_OS_IMAGE=noble CLOUD_INIT_OS_IMAGE_TYPE=minimal tox -e integration_tests + + .. tab-item:: user_settings.py file + + .. code-block:: python + + OS_PLATFORM = 'lxd_container' + OS_IMAGE = 'noble' + OS_IMAGE_TYPE = 'minimal' + +Note: Not all clouds and OSes support all image types + Image setup =========== @@ -427,3 +454,4 @@ Customizing the launch arguments before launching an instance manually: .. _Pytest marks: https://github.com/canonical/cloud-init/blob/af7eb1deab12c7208853c5d18b55228e0ba29c4d/tests/integration_tests/conftest.py#L220-L224 .. _IntegrationCloud: https://github.com/canonical/cloud-init/blob/af7eb1deab12c7208853c5d18b55228e0ba29c4d/tests/integration_tests/clouds.py#L102 .. _pycloudlib configuration documentation: https://pycloudlib.readthedocs.io/en/latest/configuration.html +.. _pycloudlib's ImageType enum: https://github.com/canonical/pycloudlib/blob/1!10.0.0/pycloudlib/cloud.py#L28 diff --git a/integration-requirements.txt b/integration-requirements.txt index 31f717207f5..da50f5fda75 100644 --- a/integration-requirements.txt +++ b/integration-requirements.txt @@ -2,7 +2,7 @@ # PyPI requirements for cloud-init integration testing # https://docs.cloud-init.io/en/latest/development/integration_tests.html # -pycloudlib>=1!6.7.0,<1!9.3 +pycloudlib>=1!9.1.0,<1!10 # Avoid breaking change in `testpaths` treatment forced # test/unittests/conftest.py to be loaded by our integration-tests tox env diff --git a/tests/integration_tests/clouds.py b/tests/integration_tests/clouds.py index 82acde409e2..345d1545887 100644 --- a/tests/integration_tests/clouds.py +++ b/tests/integration_tests/clouds.py @@ -275,6 +275,11 @@ class _LxdIntegrationCloud(IntegrationCloud): instance_tag: str cloud_instance: _BaseLXD + def _get_initial_image(self, **kwargs) -> str: + return super()._get_initial_image( + image_type=self._image_type, **kwargs + ) + def _get_or_set_profile_list(self, release): return None diff --git a/tests/integration_tests/conftest.py b/tests/integration_tests/conftest.py index d5697e238d6..b62dae82af4 100644 --- a/tests/integration_tests/conftest.py +++ b/tests/integration_tests/conftest.py @@ -12,6 +12,7 @@ from typing import Dict, Generator, Iterator, List, Type import pytest +from pycloudlib.cloud import ImageType from pycloudlib.lxd.instance import LXDInstance from tests.integration_tests import integration_settings @@ -80,8 +81,15 @@ def session_cloud() -> Generator[IntegrationCloud, None, None]: f"{integration_settings.PLATFORM} is an invalid PLATFORM " f"specified in settings. Must be one of {list(platforms.keys())}" ) - - cloud = platforms[integration_settings.PLATFORM]() + image_types = [member.value for member in ImageType.__members__.values()] + try: + image_type = ImageType(integration_settings.OS_IMAGE_TYPE) + except ValueError: + raise ValueError( + f"{integration_settings.OS_IMAGE_TYPE} is an invalid OS_IMAGE_TYPE" + f" specified in settings. Must be one of {image_types}" + ) + cloud = platforms[integration_settings.PLATFORM](image_type=image_type) cloud.emit_settings_to_log() yield cloud cloud.destroy() diff --git a/tests/integration_tests/integration_settings.py b/tests/integration_tests/integration_settings.py index 66dcd7066f9..fb736abf5f7 100644 --- a/tests/integration_tests/integration_settings.py +++ b/tests/integration_tests/integration_settings.py @@ -39,6 +39,17 @@ # to this format internally; in this case, to "None::ubuntu::focal::20.04".) OS_IMAGE = "focal" + +# Determines unique image type or flavor to exercise if the cloud supports +# image-type lookup for daily_image and released_images. +# +# One of the following pycloudlib.cloud.ImageType values: +# - generic +# - minimal +# - Pro +# - Pro FIPS +OS_IMAGE_TYPE = "generic" + # Populate if you want to use a pre-launched instance instead of # creating a new one. The exact contents will be platform dependent EXISTING_INSTANCE_ID: Optional[str] = None @@ -47,6 +58,7 @@ # IMAGE GENERATION SETTINGS ################################################################## + # Depending on where we are in the development / test / SRU cycle, we'll want # different methods of getting the source code to our SUT. Because of # this there are a number of different ways to initialize