summaryrefslogtreecommitdiff
path: root/tests/integration_tests/test_upgrade.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/integration_tests/test_upgrade.py')
-rw-r--r--tests/integration_tests/test_upgrade.py188
1 files changed, 188 insertions, 0 deletions
diff --git a/tests/integration_tests/test_upgrade.py b/tests/integration_tests/test_upgrade.py
new file mode 100644
index 00000000..b13d4703
--- /dev/null
+++ b/tests/integration_tests/test_upgrade.py
@@ -0,0 +1,188 @@
+import json
+import logging
+import os
+
+import pytest
+
+from tests.integration_tests.clouds import ImageSpecification, IntegrationCloud
+from tests.integration_tests.conftest import get_validated_source
+from tests.integration_tests.util import verify_clean_log
+
+LOG = logging.getLogger("integration_testing.test_upgrade")
+
+LOG_TEMPLATE = """\n\
+=== `systemd-analyze` before:
+{pre_systemd_analyze}
+=== `systemd-analyze` after:
+{post_systemd_analyze}
+
+=== `systemd-analyze blame` before (first 10 lines):
+{pre_systemd_blame}
+=== `systemd-analyze blame` after (first 10 lines):
+{post_systemd_blame}
+
+=== `cloud-init analyze show` before:')
+{pre_analyze_totals}
+=== `cloud-init analyze show` after:')
+{post_analyze_totals}
+
+=== `cloud-init analyze blame` before (first 10 lines): ')
+{pre_cloud_blame}
+=== `cloud-init analyze blame` after (first 10 lines): ')
+{post_cloud_blame}
+"""
+
+UNSUPPORTED_INSTALL_METHOD_MSG = (
+ "Install method '{}' not supported for this test"
+)
+USER_DATA = """\
+#cloud-config
+hostname: SRU-worked
+"""
+
+
+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,
+ }
+
+ with session_cloud.launch(
+ launch_kwargs=launch_kwargs,
+ user_data=USER_DATA,
+ ) as instance:
+ # get pre values
+ pre_hostname = instance.execute("hostname")
+ pre_cloud_id = instance.execute("cloud-id")
+ pre_result = instance.execute("cat /run/cloud-init/result.json")
+ pre_network = instance.execute("cat /etc/netplan/50-cloud-init.yaml")
+ pre_systemd_analyze = instance.execute("systemd-analyze")
+ pre_systemd_blame = instance.execute("systemd-analyze blame")
+ pre_cloud_analyze = instance.execute("cloud-init analyze show")
+ pre_cloud_blame = instance.execute("cloud-init analyze blame")
+
+ # Ensure no issues pre-upgrade
+ log = instance.read_from_file("/var/log/cloud-init.log")
+ assert not json.loads(pre_result)["v1"]["errors"]
+
+ try:
+ verify_clean_log(log)
+ except AssertionError:
+ LOG.warning(
+ "There were errors/warnings/tracebacks pre-upgrade. "
+ "Any failures may be due to pre-upgrade problem"
+ )
+
+ # Upgrade
+ instance.install_new_cloud_init(source, take_snapshot=False)
+
+ # 'cloud-init init' helps us understand if our pickling upgrade paths
+ # have broken across re-constitution of a cached datasource. Some
+ # platforms invalidate their datasource cache on reboot, so we run
+ # it here to ensure we get a dirty run.
+ assert instance.execute("cloud-init init").ok
+
+ # Reboot
+ instance.execute("hostname something-else")
+ instance.restart()
+ assert instance.execute("cloud-init status --wait --long").ok
+
+ # get post values
+ post_hostname = instance.execute("hostname")
+ post_cloud_id = instance.execute("cloud-id")
+ post_result = instance.execute("cat /run/cloud-init/result.json")
+ post_network = instance.execute("cat /etc/netplan/50-cloud-init.yaml")
+ post_systemd_analyze = instance.execute("systemd-analyze")
+ post_systemd_blame = instance.execute("systemd-analyze blame")
+ post_cloud_analyze = instance.execute("cloud-init analyze show")
+ post_cloud_blame = instance.execute("cloud-init analyze blame")
+
+ # Ensure no issues post-upgrade
+ assert not json.loads(pre_result)["v1"]["errors"]
+
+ log = instance.read_from_file("/var/log/cloud-init.log")
+ verify_clean_log(log)
+
+ # Ensure important things stayed the same
+ assert pre_hostname == post_hostname
+ assert pre_cloud_id == post_cloud_id
+ try:
+ assert pre_result == post_result
+ except AssertionError:
+ if instance.settings.PLATFORM == "azure":
+ pre_json = json.loads(pre_result)
+ post_json = json.loads(post_result)
+ assert pre_json["v1"]["datasource"].startswith(
+ "DataSourceAzure"
+ )
+ assert post_json["v1"]["datasource"].startswith(
+ "DataSourceAzure"
+ )
+ assert pre_network == post_network
+
+ # Calculate and log all the boot numbers
+ pre_analyze_totals = [
+ x
+ for x in pre_cloud_analyze.splitlines()
+ if x.startswith("Finished stage") or x.startswith("Total Time")
+ ]
+ post_analyze_totals = [
+ x
+ for x in post_cloud_analyze.splitlines()
+ if x.startswith("Finished stage") or x.startswith("Total Time")
+ ]
+
+ # pylint: disable=logging-format-interpolation
+ LOG.info(
+ LOG_TEMPLATE.format(
+ pre_systemd_analyze=pre_systemd_analyze,
+ post_systemd_analyze=post_systemd_analyze,
+ pre_systemd_blame="\n".join(
+ pre_systemd_blame.splitlines()[:10]
+ ),
+ post_systemd_blame="\n".join(
+ post_systemd_blame.splitlines()[:10]
+ ),
+ pre_analyze_totals="\n".join(pre_analyze_totals),
+ post_analyze_totals="\n".join(post_analyze_totals),
+ pre_cloud_blame="\n".join(pre_cloud_blame.splitlines()[:10]),
+ post_cloud_blame="\n".join(post_cloud_blame.splitlines()[:10]),
+ )
+ )
+
+
+@pytest.mark.ci
+@pytest.mark.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 this isn't running on CI, we should know
+ pytest.fail(UNSUPPORTED_INSTALL_METHOD_MSG.format(source))
+ else:
+ pytest.skip(UNSUPPORTED_INSTALL_METHOD_MSG.format(source))
+ return # type checking doesn't understand that skip raises
+
+ launch_kwargs = {"image_id": session_cloud.initial_image_id}
+
+ with session_cloud.launch(launch_kwargs=launch_kwargs) as instance:
+ instance.install_new_cloud_init(
+ source, take_snapshot=False, clean=False
+ )
+ instance.restart()
+ assert instance.execute("cloud-init status --wait --long").ok