summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Falcon <james.falcon@canonical.com>2023-03-27 14:34:12 -0500
committerGitHub <noreply@github.com>2023-03-27 14:34:12 -0500
commit2562f93383889fe492a98170428a055fbbd0b073 (patch)
treebb5fdb2ab0f7f48afa34cd6dcde78446228b0356
parentad33cbbaa1664cea25d457bef25626edc4a9bbab (diff)
downloadcloud-init-git-2562f93383889fe492a98170428a055fbbd0b073.tar.gz
integration tests: Refactor instance checking (#1989)
Using individual release and platform marks to specify our test support matrix was leading to too many marks specifying different combinations of things. Rather, we can rely on the "skipif" mark to perform any needed release or platform checks.
-rw-r--r--integration-requirements.txt1
-rw-r--r--tests/integration_tests/bugs/test_gh626.py7
-rw-r--r--tests/integration_tests/bugs/test_gh632.py7
-rw-r--r--tests/integration_tests/bugs/test_gh668.py7
-rw-r--r--tests/integration_tests/bugs/test_gh671.py3
-rw-r--r--tests/integration_tests/bugs/test_gh868.py10
-rw-r--r--tests/integration_tests/bugs/test_lp1835584.py16
-rw-r--r--tests/integration_tests/bugs/test_lp1897099.py6
-rw-r--r--tests/integration_tests/bugs/test_lp1898997.py12
-rw-r--r--tests/integration_tests/bugs/test_lp1901011.py3
-rw-r--r--tests/integration_tests/bugs/test_lp1910835.py4
-rw-r--r--tests/integration_tests/bugs/test_lp1912844.py6
-rw-r--r--tests/integration_tests/clouds.py65
-rw-r--r--tests/integration_tests/cmd/test_status.py16
-rw-r--r--tests/integration_tests/conftest.py25
-rw-r--r--tests/integration_tests/datasources/test_detect_openstack.py3
-rw-r--r--tests/integration_tests/datasources/test_ec2_ipv6.py3
-rw-r--r--tests/integration_tests/datasources/test_lxd_discovery.py15
-rw-r--r--tests/integration_tests/datasources/test_lxd_hotplug.py17
-rw-r--r--tests/integration_tests/datasources/test_network_dependency.py8
-rw-r--r--tests/integration_tests/datasources/test_nocloud.py7
-rw-r--r--tests/integration_tests/datasources/test_oci_networking.py7
-rw-r--r--tests/integration_tests/datasources/test_tmp_noexec.py10
-rw-r--r--tests/integration_tests/integration_settings.py6
-rw-r--r--tests/integration_tests/modules/test_ansible.py18
-rw-r--r--tests/integration_tests/modules/test_apt.py39
-rw-r--r--tests/integration_tests/modules/test_ca_certs.py5
-rw-r--r--tests/integration_tests/modules/test_combined.py37
-rw-r--r--tests/integration_tests/modules/test_disk_setup.py21
-rw-r--r--tests/integration_tests/modules/test_growpart.py8
-rw-r--r--tests/integration_tests/modules/test_hotplug.py26
-rw-r--r--tests/integration_tests/modules/test_keys_to_console.py13
-rw-r--r--tests/integration_tests/modules/test_lxd.py46
-rw-r--r--tests/integration_tests/modules/test_package_update_upgrade_install.py4
-rw-r--r--tests/integration_tests/modules/test_persistence.py5
-rw-r--r--tests/integration_tests/modules/test_power_state_change.py9
-rw-r--r--tests/integration_tests/modules/test_set_password.py6
-rw-r--r--tests/integration_tests/modules/test_ssh_keys_provided.py4
-rw-r--r--tests/integration_tests/modules/test_ssh_keysfile.py20
-rw-r--r--tests/integration_tests/modules/test_ubuntu_advantage.py31
-rw-r--r--tests/integration_tests/modules/test_ubuntu_autoinstall.py4
-rw-r--r--tests/integration_tests/modules/test_ubuntu_drivers.py3
-rw-r--r--tests/integration_tests/modules/test_user_events.py20
-rw-r--r--tests/integration_tests/modules/test_users_groups.py15
-rw-r--r--tests/integration_tests/modules/test_version_change.py13
-rw-r--r--tests/integration_tests/modules/test_wireguard.py22
-rw-r--r--tests/integration_tests/releases.py92
-rw-r--r--tests/integration_tests/test_paths.py6
-rw-r--r--tests/integration_tests/test_upgrade.py29
-rw-r--r--tox.ini11
50 files changed, 460 insertions, 311 deletions
diff --git a/integration-requirements.txt b/integration-requirements.txt
index 03d4fc25..85e2efcb 100644
--- a/integration-requirements.txt
+++ b/integration-requirements.txt
@@ -3,3 +3,4 @@
#
pycloudlib==1!1
pytest
+packaging
diff --git a/tests/integration_tests/bugs/test_gh626.py b/tests/integration_tests/bugs/test_gh626.py
index b80b677a..6df52d9c 100644
--- a/tests/integration_tests/bugs/test_gh626.py
+++ b/tests/integration_tests/bugs/test_gh626.py
@@ -9,6 +9,7 @@ import yaml
from tests.integration_tests import random_mac_address
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
MAC_ADDRESS = random_mac_address()
NETWORK_CONFIG = """\
@@ -28,8 +29,10 @@ iface eth0 inet dhcp
ethernet-wol g"""
-@pytest.mark.lxd_container
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(
+ PLATFORM not in ["lxd_container", "lxd_vm"],
+ reason="Test requires custom networking provided by LXD",
+)
@pytest.mark.lxd_config_dict(
{
"user.network-config": NETWORK_CONFIG,
diff --git a/tests/integration_tests/bugs/test_gh632.py b/tests/integration_tests/bugs/test_gh632.py
index d83d244b..9e67fe59 100644
--- a/tests/integration_tests/bugs/test_gh632.py
+++ b/tests/integration_tests/bugs/test_gh632.py
@@ -6,12 +6,15 @@ no traceback if the metadata disk cannot be found.
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import verify_clean_log
# With some datasource hacking, we can run this on a NoCloud instance
-@pytest.mark.lxd_container
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(
+ PLATFORM not in ["lxd_container", "lxd_vm"],
+ reason="Tested behavior is emulated using NoCloud",
+)
def test_datasource_rbx_no_stacktrace(client: IntegrationInstance):
client.write_to_file(
"/etc/cloud/cloud.cfg.d/90_dpkg.cfg",
diff --git a/tests/integration_tests/bugs/test_gh668.py b/tests/integration_tests/bugs/test_gh668.py
index 95edb48d..2a97c488 100644
--- a/tests/integration_tests/bugs/test_gh668.py
+++ b/tests/integration_tests/bugs/test_gh668.py
@@ -9,6 +9,7 @@ import pytest
from tests.integration_tests import random_mac_address
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
DESTINATION_IP = "172.16.0.10"
GATEWAY_IP = "10.0.0.100"
@@ -32,8 +33,10 @@ ethernets:
EXPECTED_ROUTE = "{} via {}".format(DESTINATION_IP, GATEWAY_IP)
-@pytest.mark.lxd_container
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(
+ PLATFORM not in ["lxd_container", "lxd_vm"],
+ reason="Test requires custom networking provided by LXD",
+)
@pytest.mark.lxd_config_dict(
{
"user.network-config": NETWORK_CONFIG,
diff --git a/tests/integration_tests/bugs/test_gh671.py b/tests/integration_tests/bugs/test_gh671.py
index 2d7c8118..e93bd70b 100644
--- a/tests/integration_tests/bugs/test_gh671.py
+++ b/tests/integration_tests/bugs/test_gh671.py
@@ -10,6 +10,7 @@ import crypt
import pytest
from tests.integration_tests.clouds import IntegrationCloud
+from tests.integration_tests.integration_settings import PLATFORM
OLD_PASSWORD = "DoIM33tTheComplexityRequirements!??"
NEW_PASSWORD = "DoIM33tTheComplexityRequirementsNow!??"
@@ -22,7 +23,7 @@ def _check_password(instance, unhashed_password):
assert shadow_password == hashed_password
-@pytest.mark.azure
+@pytest.mark.skipif(PLATFORM != "azure", reason="Test is Azure specific")
def test_update_default_password(setup_image, session_cloud: IntegrationCloud):
os_profile = {
"os_profile": {
diff --git a/tests/integration_tests/bugs/test_gh868.py b/tests/integration_tests/bugs/test_gh868.py
index a62e8b36..67ac9b3a 100644
--- a/tests/integration_tests/bugs/test_gh868.py
+++ b/tests/integration_tests/bugs/test_gh868.py
@@ -2,6 +2,7 @@
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import verify_clean_log
USERDATA = """\
@@ -15,12 +16,9 @@ chef:
@pytest.mark.adhoc # Can't be regularly reaching out to chef install script
-@pytest.mark.ec2
-@pytest.mark.gce
-@pytest.mark.azure
-@pytest.mark.oci
-@pytest.mark.lxd_container
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(
+ "openstack" == PLATFORM, reason="Firewall preventing openstack run"
+)
@pytest.mark.user_data(USERDATA)
def test_chef_license(client: IntegrationInstance):
log = client.read_from_file("/var/log/cloud-init.log")
diff --git a/tests/integration_tests/bugs/test_lp1835584.py b/tests/integration_tests/bugs/test_lp1835584.py
index 4e732446..7f110379 100644
--- a/tests/integration_tests/bugs/test_lp1835584.py
+++ b/tests/integration_tests/bugs/test_lp1835584.py
@@ -30,9 +30,11 @@ import re
import pytest
from pycloudlib.cloud import ImageType
-from tests.integration_tests.clouds import ImageSpecification, IntegrationCloud
+from tests.integration_tests.clouds import IntegrationCloud
from tests.integration_tests.conftest import get_validated_source
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE
def _check_iid_insensitive_across_kernel_upgrade(
@@ -67,17 +69,15 @@ def _check_iid_insensitive_across_kernel_upgrade(
assert 1 == ssh_runs, "config_ssh ran too many times {}".format(ssh_runs)
-@pytest.mark.azure
+@pytest.mark.skipif(PLATFORM != "azure", reason="Test is Azure specific")
@pytest.mark.integration_cloud_args(image_type=ImageType.PRO_FIPS)
def test_azure_kernel_upgrade_case_insensitive_uuid(
session_cloud: IntegrationCloud,
):
- cfg_image_spec = ImageSpecification.from_os_image()
- if (cfg_image_spec.os, cfg_image_spec.release) != ("ubuntu", "bionic"):
+ if (CURRENT_RELEASE.os, CURRENT_RELEASE.series) != ("ubuntu", "bionic"):
pytest.skip(
- "Test only supports ubuntu:bionic not {0.os}:{0.release}".format(
- cfg_image_spec
- )
+ f"Test only supports ubuntu:bionic not {CURRENT_RELEASE.os}: "
+ f"{CURRENT_RELEASE.series}"
)
source = get_validated_source(session_cloud)
if not source.installs_new_version():
@@ -87,7 +87,7 @@ def test_azure_kernel_upgrade_case_insensitive_uuid(
with session_cloud.launch(
launch_kwargs={
"image_id": session_cloud.cloud_instance.daily_image(
- cfg_image_spec.image_id, image_type=ImageType.PRO_FIPS
+ CURRENT_RELEASE.image_id, image_type=ImageType.PRO_FIPS
)
}
) as instance:
diff --git a/tests/integration_tests/bugs/test_lp1897099.py b/tests/integration_tests/bugs/test_lp1897099.py
index 1f5030ce..b0981790 100644
--- a/tests/integration_tests/bugs/test_lp1897099.py
+++ b/tests/integration_tests/bugs/test_lp1897099.py
@@ -7,6 +7,8 @@ https://bugs.launchpad.net/cloud-init/+bug/1897099
import pytest
+from tests.integration_tests.integration_settings import PLATFORM
+
USER_DATA = """\
#cloud-config
bootcmd:
@@ -19,7 +21,9 @@ swap:
@pytest.mark.user_data(USER_DATA)
-@pytest.mark.no_container("Containers cannot configure swap")
+@pytest.mark.skipif(
+ PLATFORM == "lxd_container", reason="Containers cannot configure swap"
+)
def test_fallocate_fallback(client):
log = client.read_from_file("/var/log/cloud-init.log")
assert "/swap.img" in client.execute("cat /proc/swaps")
diff --git a/tests/integration_tests/bugs/test_lp1898997.py b/tests/integration_tests/bugs/test_lp1898997.py
index d8ea54c3..ec92aeb6 100644
--- a/tests/integration_tests/bugs/test_lp1898997.py
+++ b/tests/integration_tests/bugs/test_lp1898997.py
@@ -12,6 +12,8 @@ default gateway.
import pytest
from tests.integration_tests import random_mac_address
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, FOCAL
from tests.integration_tests.util import verify_clean_log
MAC_ADDRESS = random_mac_address()
@@ -44,10 +46,14 @@ version: 2
"volatile.eth0.hwaddr": MAC_ADDRESS,
}
)
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(
+ PLATFORM != "lxd_vm",
+ reason="Test requires custom networking provided by LXD",
+)
+@pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL, reason="Tested on Focal and above"
+)
@pytest.mark.lxd_use_exec
-@pytest.mark.not_bionic
-@pytest.mark.ubuntu
class TestInterfaceListingWithOpenvSwitch:
def test_ovs_member_interfaces_not_excluded(self, client):
# We need to install openvswitch for our provided network configuration
diff --git a/tests/integration_tests/bugs/test_lp1901011.py b/tests/integration_tests/bugs/test_lp1901011.py
index 7de8bd77..e94caf9b 100644
--- a/tests/integration_tests/bugs/test_lp1901011.py
+++ b/tests/integration_tests/bugs/test_lp1901011.py
@@ -7,9 +7,10 @@ See https://github.com/canonical/cloud-init/pull/800
import pytest
from tests.integration_tests.clouds import IntegrationCloud
+from tests.integration_tests.integration_settings import PLATFORM
-@pytest.mark.azure
+@pytest.mark.skipif(PLATFORM != "azure", reason="Test is Azure specific")
@pytest.mark.parametrize(
"instance_type,is_ephemeral",
[
diff --git a/tests/integration_tests/bugs/test_lp1910835.py b/tests/integration_tests/bugs/test_lp1910835.py
index 1844594c..aa0fb75c 100644
--- a/tests/integration_tests/bugs/test_lp1910835.py
+++ b/tests/integration_tests/bugs/test_lp1910835.py
@@ -19,13 +19,15 @@ will match.
"""
import pytest
+from tests.integration_tests.integration_settings import PLATFORM
+
USER_DATA_TMPL = """\
#cloud-config
ssh_authorized_keys:
- {}"""
-@pytest.mark.azure
+@pytest.mark.skipif(PLATFORM != "azure", reason="Test is Azure specific")
def test_crlf_in_azure_metadata_ssh_keys(session_cloud, setup_image):
authorized_keys_path = "/home/{}/.ssh/authorized_keys".format(
session_cloud.cloud_instance.username
diff --git a/tests/integration_tests/bugs/test_lp1912844.py b/tests/integration_tests/bugs/test_lp1912844.py
index 55511ed2..b5aafa76 100644
--- a/tests/integration_tests/bugs/test_lp1912844.py
+++ b/tests/integration_tests/bugs/test_lp1912844.py
@@ -17,6 +17,7 @@ the traceback that they cause. We work around this by calling
import pytest
from tests.integration_tests import random_mac_address
+from tests.integration_tests.integration_settings import PLATFORM
MAC_ADDRESS = random_mac_address()
@@ -85,7 +86,10 @@ def ovs_enabled_session_cloud(session_cloud):
session_cloud.snapshot_id = old_snapshot_id
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(
+ PLATFORM != "lxd_vm",
+ reason="Test requires custom networking provided by LXD",
+)
def test_get_interfaces_by_mac_doesnt_traceback(ovs_enabled_session_cloud):
"""Launch our OVS-enabled image and confirm the bug doesn't reproduce."""
launch_kwargs = {
diff --git a/tests/integration_tests/clouds.py b/tests/integration_tests/clouds.py
index 945a5fb6..404d0a08 100644
--- a/tests/integration_tests/clouds.py
+++ b/tests/integration_tests/clouds.py
@@ -7,7 +7,7 @@ import re
import string
from abc import ABC, abstractmethod
from copy import deepcopy
-from typing import Optional, Type
+from typing import Type
from uuid import UUID
from pycloudlib import (
@@ -28,6 +28,7 @@ import cloudinit
from cloudinit.subp import ProcessExecutionError, subp
from tests.integration_tests import integration_settings
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.releases import CURRENT_RELEASE
from tests.integration_tests.util import emit_dots_on_travis
log = logging.getLogger("integration_testing")
@@ -46,52 +47,6 @@ def _get_ubuntu_series() -> list:
return out.splitlines()
-class ImageSpecification:
- """A specification of an image to launch for testing.
-
- If either of ``os`` and ``release`` are not specified, an attempt will be
- made to infer the correct values for these on instantiation.
-
- :param image_id:
- The image identifier used by the rest of the codebase to launch this
- image.
- :param os:
- An optional string describing the operating system this image is for
- (e.g. "ubuntu", "rhel", "freebsd").
- :param release:
- A optional string describing the operating system release (e.g.
- "focal", "8"; the exact values here will depend on the OS).
- """
-
- def __init__(
- self,
- image_id: str,
- os: Optional[str] = None,
- release: Optional[str] = None,
- ):
- if image_id in _get_ubuntu_series():
- if os is None:
- os = "ubuntu"
- if release is None:
- release = image_id
-
- self.image_id = image_id
- self.os = os
- self.release = release
- log.info(
- "Detected image: image_id=%s os=%s release=%s",
- self.image_id,
- self.os,
- self.release,
- )
-
- @classmethod
- def from_os_image(cls):
- """Return an ImageSpecification for integration_settings.OS_IMAGE."""
- parts = integration_settings.OS_IMAGE.split("::", 2)
- return cls(*parts)
-
-
class IntegrationCloud(ABC):
datasource: str
cloud_instance: BaseCloud
@@ -127,12 +82,9 @@ class IntegrationCloud(ABC):
raise NotImplementedError
def _get_initial_image(self, **kwargs) -> str:
- image = ImageSpecification.from_os_image()
- try:
- return self.cloud_instance.daily_image(image.image_id, **kwargs)
- except (ValueError, IndexError) as ex:
- log.debug("Exception while executing `daily_image`: %s", ex)
- return image.image_id
+ return CURRENT_RELEASE.image_id or self.cloud_instance.daily_image(
+ CURRENT_RELEASE.series, **kwargs
+ )
def _perform_launch(self, launch_kwargs, **kwargs) -> BaseInstance:
pycloudlib_instance = self.cloud_instance.launch(**launch_kwargs)
@@ -398,17 +350,16 @@ class OpenstackCloud(IntegrationCloud):
)
def _get_initial_image(self, **kwargs):
- image = ImageSpecification.from_os_image()
try:
- UUID(image.image_id)
+ UUID(CURRENT_RELEASE.image_id)
except ValueError as e:
raise RuntimeError(
"When using Openstack, `OS_IMAGE` MUST be specified with "
"a 36-character UUID image ID. Passing in a release name is "
"not valid here.\n"
- "OS image id: {}".format(image.image_id)
+ "OS image id: {}".format(CURRENT_RELEASE.image_id)
) from e
- return image.image_id
+ return CURRENT_RELEASE.image_id
class IbmCloud(IntegrationCloud):
diff --git a/tests/integration_tests/cmd/test_status.py b/tests/integration_tests/cmd/test_status.py
index 2582855d..bc65bff5 100644
--- a/tests/integration_tests/cmd/test_status.py
+++ b/tests/integration_tests/cmd/test_status.py
@@ -3,8 +3,10 @@ from time import sleep
import pytest
-from tests.integration_tests.clouds import ImageSpecification, IntegrationCloud
+from tests.integration_tests.clouds import IntegrationCloud
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, IS_UBUNTU, JAMMY
# We're implementing our own here in case cloud-init status --wait
@@ -37,8 +39,11 @@ def _remove_nocloud_dir_and_reboot(client: IntegrationInstance):
client.instance._wait_for_execute(old_boot_id=old_boot_id)
-@pytest.mark.ubuntu
-@pytest.mark.lxd_container
+@pytest.mark.skipif(not IS_UBUNTU, reason="Only ever tested on Ubuntu")
+@pytest.mark.skipif(
+ PLATFORM != "lxd_container",
+ reason="Test is LXD specific",
+)
def test_wait_when_no_datasource(session_cloud: IntegrationCloud, setup_image):
"""Ensure that when no datasource is found, we get status: disabled
@@ -59,10 +64,7 @@ def test_wait_when_no_datasource(session_cloud: IntegrationCloud, setup_image):
# No ubuntu user if cloud-init didn't run
client.instance.username = "root"
# Jammy and above will use LXD datasource by default
- if ImageSpecification.from_os_image().release in [
- "bionic",
- "focal",
- ]:
+ if CURRENT_RELEASE < JAMMY:
_remove_nocloud_dir_and_reboot(client)
status_out = _wait_for_cloud_init(client).stdout.strip()
assert "status: disabled" in status_out
diff --git a/tests/integration_tests/conftest.py b/tests/integration_tests/conftest.py
index fabeb608..a4815f42 100644
--- a/tests/integration_tests/conftest.py
+++ b/tests/integration_tests/conftest.py
@@ -18,7 +18,6 @@ from tests.integration_tests.clouds import (
Ec2Cloud,
GceCloud,
IbmCloud,
- ImageSpecification,
IntegrationCloud,
LxdContainerCloud,
LxdVmCloud,
@@ -58,34 +57,10 @@ def pytest_runtest_setup(item):
platform, then skip the test. If platform specific marks are not
specified, then we assume the test can be run anywhere.
"""
- all_platforms = platforms.keys()
test_marks = [mark.name for mark in item.iter_markers()]
- supported_platforms = set(all_platforms).intersection(test_marks)
- current_platform = integration_settings.PLATFORM
- unsupported_message = "Cannot run on platform {}".format(current_platform)
- if "no_container" in test_marks:
- if "lxd_container" in test_marks:
- raise RuntimeError(
- "lxd_container and no_container marks simultaneously set "
- "on test"
- )
- if current_platform == "lxd_container":
- pytest.skip(unsupported_message)
- if supported_platforms and current_platform not in supported_platforms:
- pytest.skip(unsupported_message)
-
- image = ImageSpecification.from_os_image()
- current_os = image.os
- supported_os_set = set(os_list).intersection(test_marks)
- if current_os and supported_os_set and current_os not in supported_os_set:
- pytest.skip("Cannot run on OS {}".format(current_os))
if "unstable" in test_marks and not integration_settings.RUN_UNSTABLE:
pytest.skip("Test marked unstable. Manually remove mark to run it")
- current_release = image.release
- if "not_{}".format(current_release) in test_marks:
- pytest.skip("Cannot run on release {}".format(current_release))
-
# disable_subp_usage is defined at a higher level, but we don't
# want it applied here
diff --git a/tests/integration_tests/datasources/test_detect_openstack.py b/tests/integration_tests/datasources/test_detect_openstack.py
index c70e9815..73246f8f 100644
--- a/tests/integration_tests/datasources/test_detect_openstack.py
+++ b/tests/integration_tests/datasources/test_detect_openstack.py
@@ -1,10 +1,11 @@
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
-@pytest.mark.lxd_vm
@pytest.mark.lxd_use_exec
+@pytest.mark.skipif(PLATFORM != "lxd_vm", reason="Modifies grub config")
def test_lxd_datasource_kernel_override(client: IntegrationInstance):
"""This test is twofold: it tests kernel commandline override, which also
validates OpenStack Ironic requirements. OpenStack Ironic does not
diff --git a/tests/integration_tests/datasources/test_ec2_ipv6.py b/tests/integration_tests/datasources/test_ec2_ipv6.py
index 7bb45b40..aff7ddd2 100644
--- a/tests/integration_tests/datasources/test_ec2_ipv6.py
+++ b/tests/integration_tests/datasources/test_ec2_ipv6.py
@@ -3,6 +3,7 @@ import re
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
def _test_crawl(client, ip):
@@ -18,7 +19,7 @@ def _test_crawl(client, ip):
assert float(result[0]) < 20
-@pytest.mark.ec2
+@pytest.mark.skipif(PLATFORM != "ec2", reason="test is ec2 specific")
def test_dual_stack(client: IntegrationInstance):
# Drop IPv4 responses
assert client.execute("iptables -I INPUT -s 169.254.169.254 -j DROP").ok
diff --git a/tests/integration_tests/datasources/test_lxd_discovery.py b/tests/integration_tests/datasources/test_lxd_discovery.py
index f3ca7158..4f907434 100644
--- a/tests/integration_tests/datasources/test_lxd_discovery.py
+++ b/tests/integration_tests/datasources/test_lxd_discovery.py
@@ -3,8 +3,9 @@ import json
import pytest
import yaml
-from tests.integration_tests.clouds import ImageSpecification
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, IS_UBUNTU
from tests.integration_tests.util import lxd_has_nocloud, verify_clean_log
@@ -36,7 +37,7 @@ def _customize_environment(client: IntegrationInstance):
"datasource_list: [LXD, NoCloud]\n",
)
# This is also to ensure that NoCloud can be detected
- if ImageSpecification.from_os_image().release == "jammy":
+ if CURRENT_RELEASE.series == "jammy":
# Add nocloud-net seed files because Jammy no longer delivers NoCloud
# (LP: #1958460).
client.execute("mkdir -p /var/lib/cloud/seed/nocloud-net")
@@ -48,9 +49,11 @@ def _customize_environment(client: IntegrationInstance):
client.restart()
-@pytest.mark.lxd_container
-@pytest.mark.lxd_vm
-@pytest.mark.ubuntu # Because netplan
+@pytest.mark.skipif(not IS_UBUNTU, reason="Netplan usage")
+@pytest.mark.skipif(
+ PLATFORM not in ["lxd_container", "lxd_vm"],
+ reason="Test is LXD specific",
+)
def test_lxd_datasource_discovery(client: IntegrationInstance):
"""Test that DataSourceLXD is detected instead of NoCloud."""
@@ -95,7 +98,7 @@ def test_lxd_datasource_discovery(client: IntegrationInstance):
] == sorted(list(ds_cfg.keys()))
if (
client.settings.PLATFORM == "lxd_vm"
- and ImageSpecification.from_os_image().release == "bionic"
+ and CURRENT_RELEASE.series == "bionic"
):
# pycloudlib injects user.vendor_data for lxd_vm on bionic
# to start the lxd-agent.
diff --git a/tests/integration_tests/datasources/test_lxd_hotplug.py b/tests/integration_tests/datasources/test_lxd_hotplug.py
index 81cff252..536f4e36 100644
--- a/tests/integration_tests/datasources/test_lxd_hotplug.py
+++ b/tests/integration_tests/datasources/test_lxd_hotplug.py
@@ -5,9 +5,10 @@ import pytest
from cloudinit import safeyaml
from cloudinit.subp import subp
from cloudinit.util import is_true
-from tests.integration_tests.clouds import ImageSpecification
from tests.integration_tests.decorators import retry
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, JAMMY
from tests.integration_tests.util import (
get_feature_flag_value,
lxd_has_nocloud,
@@ -62,8 +63,11 @@ def _prefer_lxd_datasource_over_nocloud(client: IntegrationInstance):
# TODO: Once LXD adds MACs to the devices endpoint, support LXD VMs here
# Currently the names are too unpredictable to be worth testing on VMs.
-@pytest.mark.lxd_container
@pytest.mark.user_data(USER_DATA)
+@pytest.mark.skipif(
+ PLATFORM != "lxd_container",
+ reason="Test is LXD specific",
+)
class TestLxdHotplug:
@pytest.fixture(autouse=True, scope="class")
def class_teardown(self, class_client: IntegrationInstance):
@@ -113,14 +117,7 @@ class TestLxdHotplug:
assert "eth2" not in client.execute("ip address")
pre_netplan = client.read_from_file("/etc/netplan/50-cloud-init.yaml")
assert "eth2" not in pre_netplan
- if ImageSpecification.from_os_image().release in [
- "bionic",
- "focal",
- ]: # pyright: ignore
- top_key = "user"
- else:
- top_key = "cloud-init"
-
+ top_key = "user" if CURRENT_RELEASE < JAMMY else "cloud-init"
assert subp(
[
"lxc",
diff --git a/tests/integration_tests/datasources/test_network_dependency.py b/tests/integration_tests/datasources/test_network_dependency.py
index bd7fe658..7b692047 100644
--- a/tests/integration_tests/datasources/test_network_dependency.py
+++ b/tests/integration_tests/datasources/test_network_dependency.py
@@ -1,6 +1,8 @@
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import IS_UBUNTU
def _customize_environment(client: IntegrationInstance):
@@ -15,8 +17,10 @@ def _customize_environment(client: IntegrationInstance):
# This test should be able to work on any cloud whose datasource specifies
# a NETWORK dependency
-@pytest.mark.gce
-@pytest.mark.ubuntu # Because netplan
+@pytest.mark.skipif(not IS_UBUNTU, reason="Netplan usage")
+@pytest.mark.skipif(
+ PLATFORM != "gce", reason="Datasource doesn't specify a NETWORK dependency"
+)
def test_network_activation_disabled(client: IntegrationInstance):
"""Test that the network is not activated during init mode."""
_customize_environment(client)
diff --git a/tests/integration_tests/datasources/test_nocloud.py b/tests/integration_tests/datasources/test_nocloud.py
index d9410410..1b4c1abc 100644
--- a/tests/integration_tests/datasources/test_nocloud.py
+++ b/tests/integration_tests/datasources/test_nocloud.py
@@ -4,6 +4,7 @@ from pycloudlib.lxd.instance import LXDInstance
from cloudinit.subp import subp
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
VENDOR_DATA = """\
#cloud-config
@@ -57,10 +58,12 @@ def setup_nocloud(instance: LXDInstance):
)
-# Only running on LXD container because we need NoCloud with custom setup
-@pytest.mark.lxd_container
@pytest.mark.lxd_setup.with_args(setup_nocloud)
@pytest.mark.lxd_use_exec
+@pytest.mark.skipif(
+ PLATFORM != "lxd_container",
+ reason="Requires NoCloud with custom setup",
+)
def test_nocloud_seedfrom_vendordata(client: IntegrationInstance):
"""Integration test for #570.
diff --git a/tests/integration_tests/datasources/test_oci_networking.py b/tests/integration_tests/datasources/test_oci_networking.py
index dc0d343b..802e8ec7 100644
--- a/tests/integration_tests/datasources/test_oci_networking.py
+++ b/tests/integration_tests/datasources/test_oci_networking.py
@@ -6,6 +6,7 @@ import yaml
from tests.integration_tests.clouds import IntegrationCloud
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import verify_clean_log
DS_CFG = """\
@@ -43,7 +44,7 @@ def extract_interface_names(network_config: dict) -> Set[str]:
return set(interfaces)
-@pytest.mark.oci
+@pytest.mark.skipif(PLATFORM != "oci", reason="Test is OCI specific")
def test_oci_networking_iscsi_instance(client: IntegrationInstance, tmpdir):
customize_environment(client, tmpdir, configure_secondary_nics=False)
result_net_files = client.execute("ls /run/net-*.conf")
@@ -92,7 +93,7 @@ def client_with_secondary_vnic(
client.instance.remove_network_interface(ip_address)
-@pytest.mark.oci
+@pytest.mark.skipif(PLATFORM != "oci", reason="Test is OCI specific")
def test_oci_networking_iscsi_instance_secondary_vnics(
client_with_secondary_vnic: IntegrationInstance, tmpdir
):
@@ -142,7 +143,7 @@ def customize_netcfg(
client.restart()
-@pytest.mark.oci
+@pytest.mark.skipif(PLATFORM != "oci", reason="Test is OCI specific")
def test_oci_networking_system_cfg(client: IntegrationInstance, tmpdir):
customize_netcfg(client, tmpdir)
log = client.read_from_file("/var/log/cloud-init.log")
diff --git a/tests/integration_tests/datasources/test_tmp_noexec.py b/tests/integration_tests/datasources/test_tmp_noexec.py
index a060e20f..5aa8537d 100644
--- a/tests/integration_tests/datasources/test_tmp_noexec.py
+++ b/tests/integration_tests/datasources/test_tmp_noexec.py
@@ -1,6 +1,7 @@
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import verify_clean_log
@@ -14,11 +15,10 @@ def customize_client(client: IntegrationInstance):
@pytest.mark.adhoc
-@pytest.mark.azure
-@pytest.mark.ec2
-@pytest.mark.gce
-@pytest.mark.oci
-@pytest.mark.openstack
+@pytest.mark.skipif(
+ PLATFORM not in ["azure", "ec2", "gce", "oci", "openstack"],
+ reason=f"Test hasn't been tested on {PLATFORM}",
+)
def test_dhcp_tmp_noexec(client: IntegrationInstance):
customize_client(client)
assert (
diff --git a/tests/integration_tests/integration_settings.py b/tests/integration_tests/integration_settings.py
index c4f28fcb..aca5bf91 100644
--- a/tests/integration_tests/integration_settings.py
+++ b/tests/integration_tests/integration_settings.py
@@ -33,9 +33,9 @@ INSTANCE_TYPE: Optional[str] = None
# Determines the base image to use or generate new images from.
#
# This can be the name of an Ubuntu release, or in the format
-# <image_id>[::<os>[::<release>]]. If given, os and release should describe
-# the image specified by image_id. (Ubuntu releases are converted to this
-# format internally; in this case, to "focal::ubuntu::focal".)
+# <image_id>[::<os>[::<release>[::<version>]]. If given, os and release should
+# describe the image specified by image_id. (Ubuntu releases are converted
+# to this format internally; in this case, to "None::ubuntu::focal::20.04".)
OS_IMAGE = "focal"
# Populate if you want to use a pre-launched instance instead of
diff --git a/tests/integration_tests/modules/test_ansible.py b/tests/integration_tests/modules/test_ansible.py
index 3d0f96cb..aea29b7d 100644
--- a/tests/integration_tests/modules/test_ansible.py
+++ b/tests/integration_tests/modules/test_ansible.py
@@ -1,5 +1,7 @@
import pytest
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, FOCAL
from tests.integration_tests.util import verify_clean_log
# This works by setting up a local repository and web server
@@ -291,7 +293,9 @@ def test_ansible_pull_pip(client):
# Ansible packaged in bionic is 2.5.1. This test relies on ansible collections,
# which requires Ansible 2.9+, so no bionic. The functionality is covered
# in `test_ansible_pull_pip` using pip rather than the bionic package.
-@pytest.mark.not_bionic
+@pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL, reason="Test requires Ansible 2.9+"
+)
@pytest.mark.user_data(
USER_DATA + INSTALL_METHOD.format(package="ansible", method="distro")
)
@@ -300,10 +304,14 @@ def test_ansible_pull_distro(client):
@pytest.mark.user_data(ANSIBLE_CONTROL)
-@pytest.mark.lxd_vm
-# Not bionic because test uses pip install and version in pip is removing
-# support for python version in bionic
-@pytest.mark.not_bionic
+@pytest.mark.skipif(
+ PLATFORM != "lxd_vm",
+ reason="Test requires starting LXD containers",
+)
+@pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL,
+ reason="Pip install is not supported for Ansible on release",
+)
def test_ansible_controller(client):
log = client.read_from_file("/var/log/cloud-init.log")
verify_clean_log(log)
diff --git a/tests/integration_tests/modules/test_apt.py b/tests/integration_tests/modules/test_apt.py
index 27ce2c5a..45c7a45a 100644
--- a/tests/integration_tests/modules/test_apt.py
+++ b/tests/integration_tests/modules/test_apt.py
@@ -5,8 +5,9 @@ import pytest
from cloudinit import gpg
from cloudinit.config import cc_apt_configure
-from tests.integration_tests.clouds import ImageSpecification
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, IS_UBUNTU
USER_DATA = """\
#cloud-config
@@ -114,7 +115,7 @@ TEST_KEY = "1FF0 D853 5EF7 E719 E5C8 1B9C 083D 06FB E4D3 04DF"
TEST_SIGNED_BY_KEY = "A2EB 2DEC 0BD7 519B 7B38 BE38 376A 290E C806 8B11"
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Apt usage")
@pytest.mark.user_data(USER_DATA)
class TestApt:
def get_keys(self, class_client: IntegrationInstance):
@@ -165,10 +166,11 @@ class TestApt:
Ported from
tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.py
"""
- release = ImageSpecification.from_os_image().release
ppa_path_contents = class_client.read_from_file(
"/etc/apt/sources.list.d/"
- "simplestreams-dev-ubuntu-trunk-{}.list".format(release)
+ "simplestreams-dev-ubuntu-trunk-{}.list".format(
+ CURRENT_RELEASE.series
+ )
)
assert (
"://ppa.launchpad.net/simplestreams-dev/trunk/ubuntu"
@@ -181,11 +183,10 @@ class TestApt:
def test_signed_by(self, class_client: IntegrationInstance):
"""Test the apt signed-by functionality."""
- release = ImageSpecification.from_os_image().release
source = (
"deb [signed-by=/etc/apt/cloud-init.gpg.d/test_signed_by.gpg] "
"http://ppa.launchpad.net/juju/stable/ubuntu"
- " {} main".format(release)
+ " {} main".format(CURRENT_RELEASE.series)
)
path_contents = class_client.read_from_file(
"/etc/apt/sources.list.d/test_signed_by.list"
@@ -251,27 +252,27 @@ class TestApt:
def test_sources_write(self, class_client: IntegrationInstance):
"""Test overwrite or append to sources file"""
- release = ImageSpecification.from_os_image().release
test_write_content = class_client.read_from_file(
"/etc/apt/sources.list.d/test_write.list"
)
expected_contents = (
"deb [signed-by=/etc/apt/cloud-init.gpg.d/test_write.gpg] "
- f"http://ppa.launchpad.net/juju/devel/ubuntu {release} main"
+ "http://ppa.launchpad.net/juju/devel/ubuntu "
+ f"{CURRENT_RELEASE.series} main"
)
assert expected_contents.strip() == test_write_content.strip()
def test_sources_append(self, class_client: IntegrationInstance):
- release = ImageSpecification.from_os_image().release
+ series = CURRENT_RELEASE.series
test_append_content = class_client.read_from_file(
"/etc/apt/sources.list.d/test_append.list"
)
expected_contents = (
"deb [signed-by=/etc/apt/cloud-init.gpg.d/test_append.gpg] "
- f"http://ppa.launchpad.net/juju/stable/ubuntu {release} main\n"
+ f"http://ppa.launchpad.net/juju/stable/ubuntu {series} main\n"
"deb [signed-by=/etc/apt/cloud-init.gpg.d/test_append.gpg] "
- f"http://ppa.launchpad.net/juju/devel/ubuntu {release} main"
+ f"http://ppa.launchpad.net/juju/devel/ubuntu {series} main"
)
assert expected_contents.strip() == test_append_content.strip()
@@ -290,10 +291,12 @@ apt:
DEFAULT_DATA = _DEFAULT_DATA.format(uri="")
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Apt usage")
@pytest.mark.user_data(DEFAULT_DATA)
class TestDefaults:
- @pytest.mark.openstack
+ @pytest.mark.skipif(
+ PLATFORM != "openstack", reason="Test is Openstack specific"
+ )
def test_primary_on_openstack(self, class_client: IntegrationInstance):
"""Test apt default primary source on openstack.
@@ -312,12 +315,12 @@ class TestDefaults:
sources_list = class_client.read_from_file("/etc/apt/sources.list")
# 3 lines from main, universe, and multiverse
- release = ImageSpecification.from_os_image().release
- sec_url = f"deb http://security.ubuntu.com/ubuntu {release}-security"
+ series = CURRENT_RELEASE.series
+ sec_url = f"deb http://security.ubuntu.com/ubuntu {series}-security"
if class_client.settings.PLATFORM == "azure":
sec_url = (
f"deb http://azure.archive.ubuntu.com/ubuntu/"
- f" {release}-security"
+ f" {series}-security"
)
sec_src_url = sec_url.replace("deb ", "# deb-src ")
assert 3 == sources_list.count(sec_url)
@@ -354,7 +357,7 @@ apt_pipelining: false
"""
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Apt usage")
@pytest.mark.user_data(DISABLED_DATA)
class TestDisabled:
def test_disable_suites(self, class_client: IntegrationInstance):
@@ -390,7 +393,7 @@ apt:
"""
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Apt usage")
@pytest.mark.user_data(APT_PROXY_DATA)
def test_apt_proxy(client: IntegrationInstance):
"""Test the apt proxy data gets written correctly."""
diff --git a/tests/integration_tests/modules/test_ca_certs.py b/tests/integration_tests/modules/test_ca_certs.py
index 2baedda9..65f8f4d7 100644
--- a/tests/integration_tests/modules/test_ca_certs.py
+++ b/tests/integration_tests/modules/test_ca_certs.py
@@ -11,6 +11,7 @@ import os.path
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.releases import IS_UBUNTU
from tests.integration_tests.util import get_inactive_modules, verify_clean_log
USER_DATA = """\
@@ -57,7 +58,9 @@ ca_certs:
"""
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ not IS_UBUNTU, reason="CA cert functionality is distro specific"
+)
@pytest.mark.user_data(USER_DATA)
class TestCaCerts:
def test_certs_updated(self, class_client: IntegrationInstance):
diff --git a/tests/integration_tests/modules/test_combined.py b/tests/integration_tests/modules/test_combined.py
index 8481b454..3c238e1f 100644
--- a/tests/integration_tests/modules/test_combined.py
+++ b/tests/integration_tests/modules/test_combined.py
@@ -16,9 +16,10 @@ import pytest
import cloudinit.config
from cloudinit.util import is_true
-from tests.integration_tests.clouds import ImageSpecification
from tests.integration_tests.decorators import retry
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, IS_UBUNTU
from tests.integration_tests.util import (
get_feature_flag_value,
get_inactive_modules,
@@ -83,7 +84,7 @@ timezone: US/Aleutian
@pytest.mark.ci
@pytest.mark.user_data(USER_DATA)
class TestCombined:
- @pytest.mark.ubuntu # Because netplan
+ @pytest.mark.skipif(not IS_UBUNTU, reason="Uses netplan")
def test_netplan_permissions(self, class_client: IntegrationInstance):
"""
Test that netplan config file is generated with proper permissions
@@ -303,19 +304,20 @@ class TestCombined:
assert data["base64_encoded_keys"] == []
assert data["merged_cfg"] == "redacted for non-root user"
- image_spec = ImageSpecification.from_os_image()
- image_spec = ImageSpecification.from_os_image()
- assert data["sys_info"]["dist"][0] == image_spec.os
+ assert data["sys_info"]["dist"][0] == CURRENT_RELEASE.os
v1_data = data["v1"]
assert re.match(r"\d\.\d+\.\d+-\d+", v1_data["kernel_release"])
- assert v1_data["variant"] == image_spec.os
- assert v1_data["distro"] == image_spec.os
- assert v1_data["distro_release"] == image_spec.release
+ assert v1_data["variant"] == CURRENT_RELEASE.os
+ assert v1_data["distro"] == CURRENT_RELEASE.os
+ assert v1_data["distro_release"] == CURRENT_RELEASE.series
assert v1_data["machine"] == "x86_64"
assert re.match(r"3.\d+\.\d+", v1_data["python_version"])
- @pytest.mark.lxd_container
+ @pytest.mark.skipif(
+ PLATFORM != "lxd_container",
+ reason="Test is LXD container specific",
+ )
def test_instance_json_lxd(self, class_client: IntegrationInstance):
client = class_client
instance_json_file = client.read_from_file(
@@ -351,7 +353,7 @@ class TestCombined:
assert v1_data["local_hostname"] == client.instance.name
assert v1_data["region"] is None
- @pytest.mark.lxd_vm
+ @pytest.mark.skipif(PLATFORM != "lxd_vm", reason="Test is LXD VM specific")
def test_instance_json_lxd_vm(self, class_client: IntegrationInstance):
client = class_client
instance_json_file = client.read_from_file(
@@ -396,7 +398,7 @@ class TestCombined:
assert v1_data["local_hostname"] == client.instance.name
assert v1_data["region"] is None
- @pytest.mark.ec2
+ @pytest.mark.skipif(PLATFORM != "ec2", reason="Test is ec2 specific")
def test_instance_json_ec2(self, class_client: IntegrationInstance):
client = class_client
instance_json_file = client.read_from_file(
@@ -419,7 +421,7 @@ class TestCombined:
assert v1_data["local_hostname"].startswith("ip-")
assert v1_data["region"] == client.cloud.cloud_instance.region
- @pytest.mark.gce
+ @pytest.mark.skipif(PLATFORM != "gce", reason="Test is GCE specific")
def test_instance_json_gce(self, class_client: IntegrationInstance):
client = class_client
instance_json_file = client.read_from_file(
@@ -438,10 +440,13 @@ class TestCombined:
assert v1_data["instance_id"] == client.instance.instance_id
assert v1_data["local_hostname"] == client.instance.name
- @pytest.mark.lxd_container
- @pytest.mark.azure
- @pytest.mark.gce
- @pytest.mark.ec2
+ @pytest.mark.skipif(
+ PLATFORM not in ["lxd_container", "azure", "gce", "ec2"],
+ reason=(
+ f"Test was written for {PLATFORM} but can likely run on "
+ "other platforms."
+ ),
+ )
def test_instance_cloud_id_across_reboot(
self, class_client: IntegrationInstance
):
diff --git a/tests/integration_tests/modules/test_disk_setup.py b/tests/integration_tests/modules/test_disk_setup.py
index 1aa22ef0..084f03f5 100644
--- a/tests/integration_tests/modules/test_disk_setup.py
+++ b/tests/integration_tests/modules/test_disk_setup.py
@@ -7,6 +7,8 @@ from pycloudlib.lxd.instance import LXDInstance
from cloudinit.subp import subp
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, FOCAL, IS_UBUNTU
from tests.integration_tests.util import verify_clean_log
DISK_PATH = "/tmp/test_disk_setup_{}".format(uuid4())
@@ -52,8 +54,10 @@ mounts:
@pytest.mark.user_data(ALIAS_USERDATA)
@pytest.mark.lxd_setup.with_args(setup_and_mount_lxd_disk)
-@pytest.mark.ubuntu
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(not IS_UBUNTU, reason="Only ever tested on Ubuntu")
+@pytest.mark.skipif(
+ PLATFORM != "lxd_vm", reason="Test requires additional mounted device"
+)
class TestDeviceAliases:
"""Test devices aliases work on disk setup/mount"""
@@ -124,8 +128,10 @@ mounts:
@pytest.mark.user_data(PARTPROBE_USERDATA)
@pytest.mark.lxd_setup.with_args(setup_and_mount_lxd_disk)
-@pytest.mark.ubuntu
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(not IS_UBUNTU, reason="Only ever tested on Ubuntu")
+@pytest.mark.skipif(
+ PLATFORM != "lxd_vm", reason="Test requires additional mounted device"
+)
class TestPartProbeAvailability:
"""Test disk setup works with partprobe
@@ -149,9 +155,10 @@ class TestPartProbeAvailability:
assert sdb["children"][0]["mountpoints"] == ["/mnt1"]
assert sdb["children"][1]["mountpoints"] == ["/mnt2"]
- # Not bionic because the LXD agent gets in the way of us
- # changing the userdata
- @pytest.mark.not_bionic
+ @pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL,
+ reason="LXD agent gets in the way of changing userdata",
+ )
def test_disk_setup_when_mounted(
self, create_disk, client: IntegrationInstance
):
diff --git a/tests/integration_tests/modules/test_growpart.py b/tests/integration_tests/modules/test_growpart.py
index 67251817..b42c016c 100644
--- a/tests/integration_tests/modules/test_growpart.py
+++ b/tests/integration_tests/modules/test_growpart.py
@@ -8,6 +8,8 @@ from pycloudlib.lxd.instance import LXDInstance
from cloudinit.subp import subp
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import IS_UBUNTU
DISK_PATH = "/tmp/test_disk_setup_{}".format(uuid4())
@@ -48,8 +50,10 @@ runcmd:
@pytest.mark.user_data(ALIAS_USERDATA)
@pytest.mark.lxd_setup.with_args(setup_and_mount_lxd_disk)
-@pytest.mark.ubuntu
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(not IS_UBUNTU, reason="Only ever tested on Ubuntu")
+@pytest.mark.skipif(
+ PLATFORM != "lxd_vm", reason="Test requires additional mounted device"
+)
class TestGrowPart:
"""Test growpart"""
diff --git a/tests/integration_tests/modules/test_hotplug.py b/tests/integration_tests/modules/test_hotplug.py
index 0bad761e..120715e4 100644
--- a/tests/integration_tests/modules/test_hotplug.py
+++ b/tests/integration_tests/modules/test_hotplug.py
@@ -5,6 +5,8 @@ import pytest
import yaml
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, FOCAL
USER_DATA = """\
#cloud-config
@@ -40,11 +42,17 @@ def _get_ip_addr(client):
return ips
-@pytest.mark.openstack
-# On Bionic, we traceback when attempting to detect the hotplugged
-# device in the updated metadata. This is because Bionic is specifically
-# configured not to provide network metadata.
-@pytest.mark.not_bionic
+@pytest.mark.skipif(
+ PLATFORM != "openstack",
+ reason=(
+ f"Test was written for {PLATFORM} but can likely run on "
+ "other platforms."
+ ),
+)
+@pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL,
+ reason="Openstack network metadata support was added in focal.",
+)
@pytest.mark.user_data(USER_DATA)
def test_hotplug_add_remove(client: IntegrationInstance):
ips_before = _get_ip_addr(client)
@@ -85,7 +93,13 @@ def test_hotplug_add_remove(client: IntegrationInstance):
)
-@pytest.mark.openstack
+@pytest.mark.skipif(
+ PLATFORM != "openstack",
+ reason=(
+ f"Test was written for {PLATFORM} but can likely run on "
+ "other platforms."
+ ),
+)
def test_no_hotplug_in_userdata(client: IntegrationInstance):
ips_before = _get_ip_addr(client)
log = client.read_from_file("/var/log/cloud-init.log")
diff --git a/tests/integration_tests/modules/test_keys_to_console.py b/tests/integration_tests/modules/test_keys_to_console.py
index 5e2b3645..b10cbc60 100644
--- a/tests/integration_tests/modules/test_keys_to_console.py
+++ b/tests/integration_tests/modules/test_keys_to_console.py
@@ -6,6 +6,7 @@ import pytest
from tests.integration_tests.decorators import retry
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import get_console_log
BLACKLIST_USER_DATA = """\
@@ -88,11 +89,13 @@ class TestKeysToConsoleDisabled:
@pytest.mark.user_data(ENABLE_KEYS_TO_CONSOLE_USER_DATA)
@retry(tries=30, delay=1)
-@pytest.mark.ec2
-@pytest.mark.lxd_container
-@pytest.mark.oci
-@pytest.mark.openstack
-# No Azure because no console log on Azure
+@pytest.mark.skipif(
+ PLATFORM not in ["ec2", "lxd_container", "oci", "openstack"],
+ reason=(
+ "No Azure because no console log on Azure. "
+ "Other platforms need testing."
+ ),
+)
def test_duplicate_messaging_console_log(client: IntegrationInstance):
"""Test that output can be enabled disabled."""
assert (
diff --git a/tests/integration_tests/modules/test_lxd.py b/tests/integration_tests/modules/test_lxd.py
index f84cdff6..40941ab4 100644
--- a/tests/integration_tests/modules/test_lxd.py
+++ b/tests/integration_tests/modules/test_lxd.py
@@ -8,8 +8,10 @@ import warnings
import pytest
import yaml
-from tests.integration_tests.clouds import ImageSpecification, IntegrationCloud
+from tests.integration_tests.clouds import IntegrationCloud
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, FOCAL
from tests.integration_tests.util import verify_clean_log
BRIDGE_USER_DATA = """\
@@ -149,7 +151,9 @@ lxd:
"""
-@pytest.mark.no_container
+@pytest.mark.skipif(
+ PLATFORM == "lxd_container", reason="Containers cannot run LXD"
+)
@pytest.mark.user_data(BRIDGE_USER_DATA)
class TestLxdBridge:
@pytest.mark.parametrize("binary_name", ["lxc", "lxd"])
@@ -202,7 +206,7 @@ def validate_preseed_storage_pools(client, preseed_cfg):
def validate_preseed_projects(client: IntegrationInstance, preseed_cfg):
# Support for projects by lxd init --preseed was added in lxd 4.12
# https://discuss.linuxcontainers.org/t/lxd-4-12-has-been-released/10424#projects-now-supported-by-lxd-init-dump-and-preseed-9
- if ImageSpecification.from_os_image().release in ("bionic", "focal"):
+ if CURRENT_RELEASE.series in ("bionic", "focal"):
return
for src_project in preseed_cfg.get("projects", []):
proj_name = src_project["name"]
@@ -226,17 +230,23 @@ def validate_preseed_projects(client: IntegrationInstance, preseed_cfg):
assert project == src_project
-@pytest.mark.no_container
+@pytest.mark.skipif(
+ PLATFORM == "lxd_container", reason="Containers cannot manipulate storage"
+)
@pytest.mark.user_data(STORAGE_USER_DATA.format("btrfs"))
def test_storage_btrfs(client):
validate_storage(client, "btrfs-progs", "mkfs.btrfs")
-@pytest.mark.no_container
-@pytest.mark.not_bionic
+@pytest.mark.skipif(
+ PLATFORM == "lxd_container", reason="Containers cannot manipulate LXD"
+)
+@pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL, reason="tested on Focal and later"
+)
def test_storage_preseed_btrfs(setup_image, session_cloud: IntegrationCloud):
- cfg_image_spec = ImageSpecification.from_os_image()
- if cfg_image_spec.release in ("bionic",):
+ # TODO: If test is marked as not bionic, why is there a bionic section?
+ if CURRENT_RELEASE.series in ("bionic",):
nictype = "nictype: bridged"
parent = "parent: lxdbr0"
network = ""
@@ -256,7 +266,9 @@ def test_storage_preseed_btrfs(setup_image, session_cloud: IntegrationCloud):
validate_preseed_projects(client, preseed_cfg)
-@pytest.mark.no_container
+@pytest.mark.skipif(
+ PLATFORM == "lxd_container", reason="Containers cannot manipulate LVM"
+)
@pytest.mark.user_data(STORAGE_USER_DATA.format("lvm"))
def test_storage_lvm(client):
log = client.read_from_file("/var/log/cloud-init.log")
@@ -281,17 +293,23 @@ def test_basic_preseed(client):
validate_preseed_projects(client, preseed_cfg)
-@pytest.mark.no_container
+@pytest.mark.skipif(
+ PLATFORM == "lxd_container", reason="Containers cannot manipulate ZFS"
+)
@pytest.mark.user_data(STORAGE_USER_DATA.format("zfs"))
def test_storage_zfs(client):
validate_storage(client, "zfsutils-linux", "zpool")
-@pytest.mark.no_container
-@pytest.mark.not_bionic
+@pytest.mark.skipif(
+ PLATFORM == "lxd_container", reason="Containers cannot manipulate LXD"
+)
+@pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL, reason="Tested on focal and later"
+)
def test_storage_preseed_zfs(setup_image, session_cloud: IntegrationCloud):
- cfg_image_spec = ImageSpecification.from_os_image()
- if cfg_image_spec.release in ("bionic",):
+ # TODO: If test is marked as not bionic, why is there a bionic section?
+ if CURRENT_RELEASE.series in ("bionic",):
nictype = "nictype: bridged"
parent = "parent: lxdbr0"
network = ""
diff --git a/tests/integration_tests/modules/test_package_update_upgrade_install.py b/tests/integration_tests/modules/test_package_update_upgrade_install.py
index d668d81c..c54365b8 100644
--- a/tests/integration_tests/modules/test_package_update_upgrade_install.py
+++ b/tests/integration_tests/modules/test_package_update_upgrade_install.py
@@ -16,6 +16,8 @@ import re
import pytest
+from tests.integration_tests.releases import IS_UBUNTU
+
USER_DATA = """\
#cloud-config
packages:
@@ -26,7 +28,7 @@ package_upgrade: true
"""
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Uses Apt")
@pytest.mark.user_data(USER_DATA)
class TestPackageUpdateUpgradeInstall:
def assert_package_installed(self, pkg_out, name, version=None):
diff --git a/tests/integration_tests/modules/test_persistence.py b/tests/integration_tests/modules/test_persistence.py
index 9979cc06..67f48284 100644
--- a/tests/integration_tests/modules/test_persistence.py
+++ b/tests/integration_tests/modules/test_persistence.py
@@ -5,6 +5,7 @@ from pathlib import Path
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import (
ASSETS_DIR,
verify_ordered_items_in_text,
@@ -14,7 +15,9 @@ PICKLE_PATH = Path("/var/lib/cloud/instance/obj.pkl")
TEST_PICKLE = ASSETS_DIR / "trusty_with_mime.pkl"
-@pytest.mark.lxd_container
+@pytest.mark.skipif(
+ PLATFORM != "lxd_container", reason=f"Not tested on {PLATFORM}"
+)
def test_log_message_on_missing_version_file(client: IntegrationInstance):
client.push_file(TEST_PICKLE, PICKLE_PATH)
client.restart()
diff --git a/tests/integration_tests/modules/test_power_state_change.py b/tests/integration_tests/modules/test_power_state_change.py
index 5cd19764..dd5bd478 100644
--- a/tests/integration_tests/modules/test_power_state_change.py
+++ b/tests/integration_tests/modules/test_power_state_change.py
@@ -9,6 +9,8 @@ import pytest
from tests.integration_tests.clouds import IntegrationCloud
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import IS_UBUNTU
from tests.integration_tests.util import verify_ordered_items_in_text
USER_DATA = """\
@@ -51,8 +53,11 @@ def _can_connect(instance):
# run anywhere, I can only get it to run in an lxd container, and even then
# occasionally some timing issues will crop up.
@pytest.mark.unstable
-@pytest.mark.ubuntu
-@pytest.mark.lxd_container
+@pytest.mark.skipif(not IS_UBUNTU, reason="Only ever tested on Ubuntu")
+@pytest.mark.skipif(
+ PLATFORM != "lxd_container",
+ reason="Test is unstable but most stable on lxd containers",
+)
class TestPowerChange:
@pytest.mark.parametrize(
"mode,delay,timeout,expected",
diff --git a/tests/integration_tests/modules/test_set_password.py b/tests/integration_tests/modules/test_set_password.py
index 765dd30c..48fe536c 100644
--- a/tests/integration_tests/modules/test_set_password.py
+++ b/tests/integration_tests/modules/test_set_password.py
@@ -11,8 +11,8 @@ only specify one user-data per instance.
import pytest
import yaml
-from tests.integration_tests.clouds import ImageSpecification
from tests.integration_tests.decorators import retry
+from tests.integration_tests.releases import CURRENT_RELEASE, IS_UBUNTU
from tests.integration_tests.util import get_console_log
COMMON_USER_DATA = """\
@@ -182,7 +182,7 @@ class Mixin:
def test_sshd_config_file(self, class_client):
"""Test that SSH config is written in the correct file."""
- if ImageSpecification.from_os_image().release in {"bionic"}:
+ if CURRENT_RELEASE.series == "bionic":
sshd_file_target = "/etc/ssh/sshd_config"
else:
sshd_file_target = "/etc/ssh/sshd_config.d/50-cloud-init.conf"
@@ -191,7 +191,7 @@ class Mixin:
# We look for the exact line match, to avoid a commented line matching
assert "PasswordAuthentication yes" in sshd_config.splitlines()
- @pytest.mark.ubuntu
+ @pytest.mark.skipif(not IS_UBUNTU, reason="Use of systemctl")
def test_check_ssh_service(self, class_client):
"""Ensure we check the sshd status because we modified the config"""
log = class_client.read_from_file("/var/log/cloud-init.log")
diff --git a/tests/integration_tests/modules/test_ssh_keys_provided.py b/tests/integration_tests/modules/test_ssh_keys_provided.py
index b6069376..576b78eb 100644
--- a/tests/integration_tests/modules/test_ssh_keys_provided.py
+++ b/tests/integration_tests/modules/test_ssh_keys_provided.py
@@ -9,7 +9,7 @@ system.
import pytest
-from tests.integration_tests.clouds import ImageSpecification
+from tests.integration_tests.releases import CURRENT_RELEASE
USER_DATA = """\
#cloud-config
@@ -143,7 +143,7 @@ class TestSshKeysProvided:
"HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub",
"HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub",
)
- if ImageSpecification.from_os_image().release in {"bionic"}:
+ if CURRENT_RELEASE.series == "bionic":
sshd_config_path = "/etc/ssh/sshd_config"
else:
sshd_config_path = "/etc/ssh/sshd_config.d/50-cloud-init.conf"
diff --git a/tests/integration_tests/modules/test_ssh_keysfile.py b/tests/integration_tests/modules/test_ssh_keysfile.py
index 8330a1ce..628ad91f 100644
--- a/tests/integration_tests/modules/test_ssh_keysfile.py
+++ b/tests/integration_tests/modules/test_ssh_keysfile.py
@@ -4,8 +4,8 @@ import paramiko
import pytest
from paramiko.ssh_exception import SSHException
-from tests.integration_tests.clouds import ImageSpecification
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.releases import CURRENT_RELEASE, IS_UBUNTU
from tests.integration_tests.util import get_test_rsa_keypair
TEST_USER1_KEYS = get_test_rsa_keypair("test1")
@@ -91,7 +91,7 @@ def common_verify(client, expected_keys):
home_dir = "/home/{}".format(user)
# Home permissions aren't consistent between releases. On ubuntu
# this can change to 750 once focal is unsupported.
- if ImageSpecification.from_os_image().release in ("bionic", "focal"):
+ if CURRENT_RELEASE.series in ("bionic", "focal"):
home_perms = "755"
else:
home_perms = "750"
@@ -125,7 +125,9 @@ def common_verify(client, expected_keys):
DEFAULT_KEYS_USERDATA = _USERDATA.format(bootcmd='""')
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ not IS_UBUNTU, reason="Tests permissions specific to Ubuntu releases"
+)
@pytest.mark.user_data(DEFAULT_KEYS_USERDATA)
def test_authorized_keys_default(client: IntegrationInstance):
expected_keys = [
@@ -154,7 +156,9 @@ AUTHORIZED_KEYS2_USERDATA = _USERDATA.format(
)
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ not IS_UBUNTU, reason="Tests permissions specific to Ubuntu releases"
+)
@pytest.mark.user_data(AUTHORIZED_KEYS2_USERDATA)
def test_authorized_keys2(client: IntegrationInstance):
expected_keys = [
@@ -183,7 +187,9 @@ NESTED_KEYS_USERDATA = _USERDATA.format(
)
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ not IS_UBUNTU, reason="Tests permissions specific to Ubuntu releases"
+)
@pytest.mark.user_data(NESTED_KEYS_USERDATA)
def test_nested_keys(client: IntegrationInstance):
expected_keys = [
@@ -204,7 +210,9 @@ EXTERNAL_KEYS_USERDATA = _USERDATA.format(
)
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ not IS_UBUNTU, reason="Tests permissions specific to Ubuntu releases"
+)
@pytest.mark.user_data(EXTERNAL_KEYS_USERDATA)
def test_external_keys(client: IntegrationInstance):
expected_keys = [
diff --git a/tests/integration_tests/modules/test_ubuntu_advantage.py b/tests/integration_tests/modules/test_ubuntu_advantage.py
index 547ec9e7..0b3ed2d7 100644
--- a/tests/integration_tests/modules/test_ubuntu_advantage.py
+++ b/tests/integration_tests/modules/test_ubuntu_advantage.py
@@ -5,12 +5,20 @@ import os
import pytest
from pycloudlib.cloud import ImageType
-from tests.integration_tests.clouds import ImageSpecification, IntegrationCloud
+from tests.integration_tests.clouds import IntegrationCloud
from tests.integration_tests.conftest import get_validated_source
from tests.integration_tests.instances import (
CloudInitSource,
IntegrationInstance,
)
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import (
+ BIONIC,
+ CURRENT_RELEASE,
+ FOCAL,
+ IS_UBUNTU,
+ JAMMY,
+)
from tests.integration_tests.util import verify_clean_log
LOG = logging.getLogger("integration_testing.test_ubuntu_advantage")
@@ -109,7 +117,7 @@ def get_services_status(client: IntegrationInstance) -> dict:
@pytest.mark.adhoc
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Test is Ubuntu specific")
@pytest.mark.skipif(
not CLOUD_INIT_UA_TOKEN, reason="CLOUD_INIT_UA_TOKEN env var not provided"
)
@@ -136,12 +144,11 @@ class TestUbuntuAdvantage:
def maybe_install_cloud_init(session_cloud: IntegrationCloud):
- cfg_image_spec = ImageSpecification.from_os_image()
source = get_validated_source(session_cloud)
launch_kwargs = {
"image_id": session_cloud.cloud_instance.daily_image(
- cfg_image_spec.image_id, image_type=ImageType.PRO
+ CURRENT_RELEASE.image_id, image_type=ImageType.PRO
)
}
@@ -192,16 +199,16 @@ def maybe_install_cloud_init(session_cloud: IntegrationCloud):
return {"image_id": session_cloud.snapshot_id}
-@pytest.mark.azure
-@pytest.mark.ec2
-@pytest.mark.gce
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ not all([IS_UBUNTU, CURRENT_RELEASE in [BIONIC, FOCAL, JAMMY]]),
+ reason="Test runs on Ubuntu LTS releases only",
+)
+@pytest.mark.skipif(
+ PLATFORM not in ["azure", "ec2", "gce"],
+ reason=f"Pro isn't offered on {PLATFORM}.",
+)
class TestUbuntuAdvantagePro:
def test_custom_services(self, session_cloud: IntegrationCloud):
- release = ImageSpecification.from_os_image().release
- if release not in {"bionic", "focal", "jammy"}:
- pytest.skip(f"Cannot run on non LTS release: {release}")
-
launch_kwargs = maybe_install_cloud_init(session_cloud)
with session_cloud.launch(
user_data=AUTO_ATTACH_CUSTOM_SERVICES,
diff --git a/tests/integration_tests/modules/test_ubuntu_autoinstall.py b/tests/integration_tests/modules/test_ubuntu_autoinstall.py
index d340afc5..ad077977 100644
--- a/tests/integration_tests/modules/test_ubuntu_autoinstall.py
+++ b/tests/integration_tests/modules/test_ubuntu_autoinstall.py
@@ -2,6 +2,8 @@
import pytest
+from tests.integration_tests.releases import IS_UBUNTU
+
USER_DATA = """\
#cloud-config
autoinstall:
@@ -16,7 +18,7 @@ snap:
LOG_MSG = "Valid autoinstall schema. Config will be processed by subiquity"
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Test is Ubuntu specific")
@pytest.mark.user_data(USER_DATA)
class TestUbuntuAutoinstall:
def test_autoinstall_schema_valid_when_snap_present(self, class_client):
diff --git a/tests/integration_tests/modules/test_ubuntu_drivers.py b/tests/integration_tests/modules/test_ubuntu_drivers.py
index 4fbfba3c..66649c17 100644
--- a/tests/integration_tests/modules/test_ubuntu_drivers.py
+++ b/tests/integration_tests/modules/test_ubuntu_drivers.py
@@ -3,6 +3,7 @@ import re
import pytest
from tests.integration_tests.clouds import IntegrationCloud
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import verify_clean_log
USER_DATA = """\
@@ -16,7 +17,7 @@ drivers:
@pytest.mark.adhoc # Expensive instance type
-@pytest.mark.oci
+@pytest.mark.skipif(PLATFORM != "oci", reason="Test is OCI specific")
def test_ubuntu_drivers_installed(session_cloud: IntegrationCloud):
with session_cloud.launch(
launch_kwargs={"instance_type": "VM.GPU2.1"}, user_data=USER_DATA
diff --git a/tests/integration_tests/modules/test_user_events.py b/tests/integration_tests/modules/test_user_events.py
index e4a4241f..79d88022 100644
--- a/tests/integration_tests/modules/test_user_events.py
+++ b/tests/integration_tests/modules/test_user_events.py
@@ -9,6 +9,7 @@ import pytest
import yaml
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
def _add_dummy_bridge_to_netplan(client: IntegrationInstance):
@@ -26,12 +27,11 @@ def _add_dummy_bridge_to_netplan(client: IntegrationInstance):
client.write_to_file("/etc/netplan/50-cloud-init.yaml", dumped_netplan)
-@pytest.mark.lxd_container
-@pytest.mark.lxd_vm
-@pytest.mark.ec2
-@pytest.mark.gce
-@pytest.mark.oci
-@pytest.mark.openstack
+@pytest.mark.skipif(
+ PLATFORM
+ not in ["lxd_container", "lxd_vm", "ec2", "gce", "oci", "openstack"],
+ reason="Default boot events testing is datasource specific",
+)
def test_boot_event_disabled_by_default(client: IntegrationInstance):
log = client.read_from_file("/var/log/cloud-init.log")
if "network config is disabled" in log:
@@ -92,7 +92,13 @@ def _test_network_config_applied_on_reboot(client: IntegrationInstance):
assert "dummy0" not in client.execute("ls /sys/class/net")
-@pytest.mark.azure
+@pytest.mark.skipif(
+ PLATFORM != "azure",
+ reason=(
+ f"{PLATFORM} doesn't support updates every boot event by default "
+ "(or hasn't been testing for it)."
+ ),
+)
def test_boot_event_enabled_by_default(client: IntegrationInstance):
_test_network_config_applied_on_reboot(client)
diff --git a/tests/integration_tests/modules/test_users_groups.py b/tests/integration_tests/modules/test_users_groups.py
index 91eca345..cc6a4bfb 100644
--- a/tests/integration_tests/modules/test_users_groups.py
+++ b/tests/integration_tests/modules/test_users_groups.py
@@ -8,8 +8,8 @@ import re
import pytest
-from tests.integration_tests.clouds import ImageSpecification
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.releases import CURRENT_RELEASE, IS_UBUNTU, JAMMY
from tests.integration_tests.util import verify_clean_log
USER_DATA = """\
@@ -56,7 +56,7 @@ class TestUsersGroups:
confirms that they have been configured correctly in the system under test.
"""
- @pytest.mark.ubuntu
+ @pytest.mark.skipif(not IS_UBUNTU, reason="Test assumes 'ubuntu' user")
@pytest.mark.parametrize(
"getent_args,regex",
[
@@ -108,6 +108,10 @@ class TestUsersGroups:
@pytest.mark.user_data(USER_DATA)
+@pytest.mark.skipif(
+ CURRENT_RELEASE < JAMMY,
+ reason="Requires version of sudo not available in older releases",
+)
def test_sudoers_includedir(client: IntegrationInstance):
"""Ensure we don't add additional #includedir to sudoers.
@@ -117,13 +121,6 @@ def test_sudoers_includedir(client: IntegrationInstance):
https://github.com/canonical/cloud-init/pull/783
"""
- if ImageSpecification.from_os_image().release in [
- "bionic",
- "focal",
- ]:
- raise pytest.skip(
- "Test requires version of sudo installed on groovy and later"
- )
client.execute("sed -i 's/#include/@include/g' /etc/sudoers")
sudoers = client.read_from_file("/etc/sudoers")
diff --git a/tests/integration_tests/modules/test_version_change.py b/tests/integration_tests/modules/test_version_change.py
index 3168cd60..9df436b8 100644
--- a/tests/integration_tests/modules/test_version_change.py
+++ b/tests/integration_tests/modules/test_version_change.py
@@ -3,6 +3,7 @@ from pathlib import Path
import pytest
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.util import ASSETS_DIR, verify_clean_log
PICKLE_PATH = Path("/var/lib/cloud/instance/obj.pkl")
@@ -41,12 +42,12 @@ def test_reboot_without_version_change(client: IntegrationInstance):
)
-@pytest.mark.ec2
-@pytest.mark.gce
-@pytest.mark.oci
-@pytest.mark.openstack
-@pytest.mark.lxd_container
-@pytest.mark.lxd_vm
+@pytest.mark.skipif(
+ PLATFORM
+ not in ["ec2", "gce", "oci", "openstack", "lxd_container", "lxd_vm"],
+ reason=f"Test hasn't been tested on {PLATFORM}.",
+)
+# TODO: The below comment likely isn't true anymore
# No Azure because the cache gets purged every reboot, so we'll never
# get to the point where we need to purge cache due to version change
def test_cache_purged_on_version_change(client: IntegrationInstance):
diff --git a/tests/integration_tests/modules/test_wireguard.py b/tests/integration_tests/modules/test_wireguard.py
index e658a9df..e685a269 100644
--- a/tests/integration_tests/modules/test_wireguard.py
+++ b/tests/integration_tests/modules/test_wireguard.py
@@ -4,6 +4,8 @@ from pycloudlib.lxd.instance import LXDInstance
from cloudinit.subp import subp
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import IS_UBUNTU
ASCII_TEXT = "ASCII text"
@@ -55,13 +57,13 @@ def load_wireguard_kernel_module_lxd(instance: LXDInstance):
@pytest.mark.ci
@pytest.mark.user_data(USER_DATA)
-@pytest.mark.lxd_vm
-@pytest.mark.gce
-@pytest.mark.ec2
-@pytest.mark.azure
-@pytest.mark.openstack
-@pytest.mark.oci
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ not IS_UBUNTU, reason="Hasn't been tested on other distros"
+)
+@pytest.mark.skipif(
+ PLATFORM not in ["lxd_vm", "gce", "ec2", "azure", "openstack", "oci"],
+ reason=f"Test hasn't been tested on {PLATFORM}",
+)
class TestWireguard:
@pytest.mark.parametrize(
"cmd,expected_out",
@@ -119,8 +121,10 @@ class TestWireguard:
@pytest.mark.ci
@pytest.mark.user_data(USER_DATA)
@pytest.mark.lxd_setup.with_args(load_wireguard_kernel_module_lxd)
-@pytest.mark.lxd_container
-@pytest.mark.ubuntu
+@pytest.mark.skipif(
+ PLATFORM != "lxd_container", reason=f"Not testing on {PLATFORM}"
+)
+@pytest.mark.skipif(not IS_UBUNTU, reason="Has only been tested on Ubuntu")
class TestWireguardWithoutKmod:
def test_wireguard_tools_installed(
self, class_client: IntegrationInstance
diff --git a/tests/integration_tests/releases.py b/tests/integration_tests/releases.py
new file mode 100644
index 00000000..b2ab9cee
--- /dev/null
+++ b/tests/integration_tests/releases.py
@@ -0,0 +1,92 @@
+import functools
+import logging
+from typing import Optional
+
+from packaging import version
+
+from cloudinit import subp
+from cloudinit.subp import ProcessExecutionError
+from tests.integration_tests import integration_settings
+
+log = logging.getLogger("integration_testing")
+
+
+def get_all_ubuntu_series() -> list:
+ """Use distro-info-data's ubuntu.csv to get a list of Ubuntu series"""
+ out = ""
+ try:
+ out, _err = subp.subp(["ubuntu-distro-info", "-a"])
+ except ProcessExecutionError:
+ log.info(
+ "ubuntu-distro-info (from the distro-info package) must be"
+ " installed to guess Ubuntu os/release"
+ )
+ return out.splitlines()
+
+
+def ubuntu_version_from_series(series) -> str:
+ try:
+ out, _err = subp.subp(
+ ["ubuntu-distro-info", "--release", "--series", series]
+ )
+ except subp.ProcessExecutionError as e:
+ raise ValueError(
+ f"'{series}' is not a recognized Ubuntu release"
+ ) from e
+ return out.strip().rstrip(" LTS")
+
+
+@functools.total_ordering
+class Release:
+ def __init__(
+ self,
+ os: str,
+ series: str,
+ version: str,
+ image_id: Optional[str] = None,
+ ):
+ self.os = os
+ self.series = series
+ self.version = version
+ self.image_id = image_id
+
+ def __repr__(self):
+ return f"Release({self.os}, {self.version})"
+
+ def __lt__(self, other: "Release"):
+ if self.os != other.os:
+ raise ValueError(f"{self.os} cannot be compared to {other.os}!")
+ return version.parse(self.version) < version.parse(other.version)
+
+ @classmethod
+ def from_os_image(
+ cls,
+ os_image: str = integration_settings.OS_IMAGE,
+ ) -> "Release":
+ """Get the individual parts from an OS_IMAGE definition.
+
+ Returns a namedtuple containing id, os, and release of the image."""
+ parts = os_image.split("::", 2)
+ if len(parts) == 1:
+ image_id = None
+ os = "ubuntu"
+ series = parts[0]
+ version = ubuntu_version_from_series(series)
+ elif len(parts) == 4:
+ image_id, os, series, version = parts
+ else:
+ raise ValueError(
+ "OS_IMAGE must either contain release name or be in the form "
+ "of <image_id>[::<os>[::<release>[::<version>]]]"
+ )
+ return cls(os, series, version, image_id)
+
+
+BIONIC = Release("ubuntu", "bionic", "18.04")
+FOCAL = Release("ubuntu", "focal", "20.04")
+JAMMY = Release("ubuntu", "jammy", "22.04")
+KINETIC = Release("ubuntu", "kinetic", "22.10")
+LUNAR = Release("ubuntu", "lunar", "23.04")
+
+CURRENT_RELEASE = Release.from_os_image()
+IS_UBUNTU = CURRENT_RELEASE.os == "ubuntu"
diff --git a/tests/integration_tests/test_paths.py b/tests/integration_tests/test_paths.py
index 14513c82..b63da5a4 100644
--- a/tests/integration_tests/test_paths.py
+++ b/tests/integration_tests/test_paths.py
@@ -10,6 +10,7 @@ from cloudinit.cmd.devel.logs import (
INSTALLER_APPORT_SENSITIVE_FILES,
)
from tests.integration_tests.instances import IntegrationInstance
+from tests.integration_tests.releases import CURRENT_RELEASE, FOCAL
from tests.integration_tests.util import verify_clean_log
DEFAULT_CLOUD_DIR = "/var/lib/cloud"
@@ -111,7 +112,10 @@ class TestHonorCloudDir:
# because the test ensures nothing is running under /var/lib/cloud.
# Since LXD is doing this and not cloud-init, we should just not run
# on Bionic to avoid it.
- @pytest.mark.not_bionic
+ @pytest.mark.skipif(
+ CURRENT_RELEASE < FOCAL,
+ reason="LXD inserts conflicting setup on releases prior to focal",
+ )
def test_honor_cloud_dir(self, custom_client: IntegrationInstance):
"""Integration test for LP: #1976564
diff --git a/tests/integration_tests/test_upgrade.py b/tests/integration_tests/test_upgrade.py
index 5ef82e88..787bda44 100644
--- a/tests/integration_tests/test_upgrade.py
+++ b/tests/integration_tests/test_upgrade.py
@@ -4,8 +4,10 @@ import os
import pytest
-from tests.integration_tests.clouds import ImageSpecification, IntegrationCloud
+from tests.integration_tests.clouds import IntegrationCloud
from tests.integration_tests.conftest import get_validated_source
+from tests.integration_tests.integration_settings import PLATFORM
+from tests.integration_tests.releases import CURRENT_RELEASE, FOCAL, IS_UBUNTU
from tests.integration_tests.util import verify_clean_log
LOG = logging.getLogger("integration_testing.test_upgrade")
@@ -41,23 +43,20 @@ hostname: SRU-worked
"""
+# The issues that we see on Bionic VMs don't appear anywhere
+# else, including when calling KVM directly. It likely has to
+# do with the extra lxd-agent setup happening on bionic.
+# Given that we still have Bionic covered on all other platforms,
+# the risk of skipping bionic here seems low enough.
+@pytest.mark.skipif(
+ PLATFORM == "lxd_vm" and CURRENT_RELEASE < FOCAL,
+ reason="Update test doesn't run on Bionic LXD VMs",
+)
def test_clean_boot_of_upgraded_package(session_cloud: IntegrationCloud):
source = get_validated_source(session_cloud)
if not source.installs_new_version():
pytest.skip(UNSUPPORTED_INSTALL_METHOD_MSG.format(source))
return # type checking doesn't understand that skip raises
- if (
- ImageSpecification.from_os_image().release == "bionic"
- and session_cloud.settings.PLATFORM == "lxd_vm"
- ):
- # The issues that we see on Bionic VMs don't appear anywhere
- # else, including when calling KVM directly. It likely has to
- # do with the extra lxd-agent setup happening on bionic.
- # Given that we still have Bionic covered on all other platforms,
- # the risk of skipping bionic here seems low enough.
- pytest.skip("Upgrade test doesn't run on LXD VMs and bionic")
- return
-
launch_kwargs = {
"image_id": session_cloud.initial_image_id,
}
@@ -172,11 +171,11 @@ def test_clean_boot_of_upgraded_package(session_cloud: IntegrationCloud):
@pytest.mark.ci
-@pytest.mark.ubuntu
+@pytest.mark.skipif(not IS_UBUNTU, reason="Only ever tested on Ubuntu")
def test_subsequent_boot_of_upgraded_package(session_cloud: IntegrationCloud):
source = get_validated_source(session_cloud)
if not source.installs_new_version():
- if os.environ.get("TRAVIS"):
+ if os.environ.get("GITHUB_ACTIONS"):
# If this isn't running on CI, we should know
pytest.fail(UNSUPPORTED_INSTALL_METHOD_MSG.format(source))
else:
diff --git a/tox.ini b/tox.ini
index b49272ac..c0a3b868 100644
--- a/tox.ini
+++ b/tox.ini
@@ -296,27 +296,16 @@ markers =
adhoc: only run on adhoc basis, not in any CI environment (travis or jenkins)
allow_all_subp: allow all subp usage (disable_subp_usage)
allow_subp_for: allow subp usage for the given commands (disable_subp_usage)
- azure: test will only run on Azure platform
ci: run this integration test as part of CI test runs
ds_sys_cfg: a sys_cfg dict to be used by datasource fixtures
- ec2: test will only run on EC2 platform
- gce: test will only run on GCE platform
hypothesis_slow: hypothesis test too slow to run as unit test
- ibm: test will only run on IBM platform
instance_name: the name to be used for the test instance
integration_cloud_args: args for IntegrationCloud customization
is_iscsi: whether is an instance has iscsi net cfg or not
lxd_config_dict: set the config_dict passed on LXD instance creation
- lxd_container: test will only run in LXD container
lxd_setup: specify callable to be called between init and start
lxd_use_exec: `execute` will use `lxc exec` instead of SSH
- lxd_vm: test will only run in LXD VM
- no_container: test cannot run in a container
- not_bionic: test cannot run on the bionic release
- oci: test will only run on OCI platform
- openstack: test will only run on openstack platform
serial: tests that do not work in parallel, skipped with py3-fast
- ubuntu: this test should run on Ubuntu
unstable: skip this test because it is flakey
user_data: the user data to be passed to the test instance
allow_dns_lookup: disable autochecking for host network configuration