4eb3b8
From 005d0a98c69d154a00e9fd599c7fbe5aef73c933 Mon Sep 17 00:00:00 2001
e24810
From: Amy Chen <xiachen@redhat.com>
4eb3b8
Date: Thu, 25 Nov 2021 18:30:48 +0800
e24810
Subject: [PATCH] fix error on upgrade caused by new vendordata2 attributes
e24810
e24810
RH-Author: xiachen <None>
4eb3b8
RH-MergeRequest: 35: fix error on upgrade caused by new vendordata2 attributes
4eb3b8
RH-Commit: [1/1] 9e00a7744838afbbdc5eb14628b7f572beba9f19
4eb3b8
RH-Bugzilla: 2021538
e24810
RH-Acked-by: Mohamed Gamal Morsy <mmorsy@redhat.com>
e24810
RH-Acked-by: Eduardo Otubo <otubo@redhat.com>
4eb3b8
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
e24810
e24810
commit d132356cc361abef2d90d4073438f3ab759d5964
e24810
Author: James Falcon <TheRealFalcon@users.noreply.github.com>
e24810
Date:   Mon Apr 19 11:31:28 2021 -0500
e24810
e24810
    fix error on upgrade caused by new vendordata2 attributes (#869)
e24810
e24810
    In #777, we added 'vendordata2' and 'vendordata2_raw' attributes to
e24810
    the DataSource class, but didn't use the upgrade framework to deal
e24810
    with an unpickle after upgrade. This commit adds the necessary
e24810
    upgrade code.
e24810
e24810
    Additionally, added a smaller-scope upgrade test to our integration
e24810
    tests that will be run on every CI run so we catch these issues
e24810
    immediately in the future.
e24810
e24810
    LP: #1922739
e24810
e24810
Signed-off-by: Amy Chen <xiachen@redhat.com>
e24810
---
e24810
 cloudinit/sources/__init__.py           | 12 +++++++++++-
e24810
 cloudinit/tests/test_upgrade.py         |  4 ++++
e24810
 tests/integration_tests/clouds.py       |  4 ++--
e24810
 tests/integration_tests/test_upgrade.py | 25 ++++++++++++++++++++++++-
e24810
 4 files changed, 41 insertions(+), 4 deletions(-)
e24810
e24810
diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py
e24810
index 1ad1880d..7d74f8d9 100644
e24810
--- a/cloudinit/sources/__init__.py
e24810
+++ b/cloudinit/sources/__init__.py
e24810
@@ -24,6 +24,7 @@ from cloudinit import util
e24810
 from cloudinit.atomic_helper import write_json
e24810
 from cloudinit.event import EventType
e24810
 from cloudinit.filters import launch_index
e24810
+from cloudinit.persistence import CloudInitPickleMixin
e24810
 from cloudinit.reporting import events
e24810
 
e24810
 DSMODE_DISABLED = "disabled"
e24810
@@ -134,7 +135,7 @@ URLParams = namedtuple(
e24810
     'URLParms', ['max_wait_seconds', 'timeout_seconds', 'num_retries'])
e24810
 
e24810
 
e24810
-class DataSource(metaclass=abc.ABCMeta):
e24810
+class DataSource(CloudInitPickleMixin, metaclass=abc.ABCMeta):
e24810
 
e24810
     dsmode = DSMODE_NETWORK
e24810
     default_locale = 'en_US.UTF-8'
e24810
@@ -196,6 +197,8 @@ class DataSource(metaclass=abc.ABCMeta):
e24810
     # non-root users
e24810
     sensitive_metadata_keys = ('merged_cfg', 'security-credentials',)
e24810
 
e24810
+    _ci_pkl_version = 1
e24810
+
e24810
     def __init__(self, sys_cfg, distro, paths, ud_proc=None):
e24810
         self.sys_cfg = sys_cfg
e24810
         self.distro = distro
e24810
@@ -218,6 +221,13 @@ class DataSource(metaclass=abc.ABCMeta):
e24810
         else:
e24810
             self.ud_proc = ud_proc
e24810
 
e24810
+    def _unpickle(self, ci_pkl_version: int) -> None:
e24810
+        """Perform deserialization fixes for Paths."""
e24810
+        if not hasattr(self, 'vendordata2'):
e24810
+            self.vendordata2 = None
e24810
+        if not hasattr(self, 'vendordata2_raw'):
e24810
+            self.vendordata2_raw = None
e24810
+
e24810
     def __str__(self):
e24810
         return type_utils.obj_name(self)
e24810
 
e24810
diff --git a/cloudinit/tests/test_upgrade.py b/cloudinit/tests/test_upgrade.py
e24810
index f79a2536..fd3c5812 100644
e24810
--- a/cloudinit/tests/test_upgrade.py
e24810
+++ b/cloudinit/tests/test_upgrade.py
e24810
@@ -43,3 +43,7 @@ class TestUpgrade:
e24810
     def test_blacklist_drivers_set_on_networking(self, previous_obj_pkl):
e24810
         """We always expect Networking.blacklist_drivers to be initialised."""
e24810
         assert previous_obj_pkl.distro.networking.blacklist_drivers is None
e24810
+
e24810
+    def test_vendordata_exists(self, previous_obj_pkl):
e24810
+        assert previous_obj_pkl.vendordata2 is None
e24810
+        assert previous_obj_pkl.vendordata2_raw is None
e24810
diff --git a/tests/integration_tests/clouds.py b/tests/integration_tests/clouds.py
e24810
index 9527a413..1d0b9d83 100644
e24810
--- a/tests/integration_tests/clouds.py
e24810
+++ b/tests/integration_tests/clouds.py
e24810
@@ -100,14 +100,14 @@ class IntegrationCloud(ABC):
e24810
             # Even if we're using the default key, it may still have a
e24810
             # different name in the clouds, so we need to set it separately.
e24810
             self.cloud_instance.key_pair.name = settings.KEYPAIR_NAME
e24810
-        self._released_image_id = self._get_initial_image()
e24810
+        self.released_image_id = self._get_initial_image()
e24810
         self.snapshot_id = None
e24810
 
e24810
     @property
e24810
     def image_id(self):
e24810
         if self.snapshot_id:
e24810
             return self.snapshot_id
e24810
-        return self._released_image_id
e24810
+        return self.released_image_id
e24810
 
e24810
     def emit_settings_to_log(self) -> None:
e24810
         log.info(
e24810
diff --git a/tests/integration_tests/test_upgrade.py b/tests/integration_tests/test_upgrade.py
e24810
index c20cb3c1..48e0691b 100644
e24810
--- a/tests/integration_tests/test_upgrade.py
e24810
+++ b/tests/integration_tests/test_upgrade.py
e24810
@@ -1,4 +1,5 @@
e24810
 import logging
e24810
+import os
e24810
 import pytest
e24810
 import time
e24810
 from pathlib import Path
e24810
@@ -8,6 +9,8 @@ from tests.integration_tests.conftest import (
e24810
     get_validated_source,
e24810
     session_start_time,
e24810
 )
e24810
+from tests.integration_tests.instances import CloudInitSource
e24810
+
e24810
 
e24810
 log = logging.getLogger('integration_testing')
e24810
 
e24810
@@ -63,7 +66,7 @@ def test_upgrade(session_cloud: IntegrationCloud):
e24810
         return  # type checking doesn't understand that skip raises
e24810
 
e24810
     launch_kwargs = {
e24810
-        'image_id': session_cloud._get_initial_image(),
e24810
+        'image_id': session_cloud.released_image_id,
e24810
     }
e24810
 
e24810
     image = ImageSpecification.from_os_image()
e24810
@@ -93,6 +96,26 @@ def test_upgrade(session_cloud: IntegrationCloud):
e24810
         instance.install_new_cloud_init(source, take_snapshot=False)
e24810
         instance.execute('hostname something-else')
e24810
         _restart(instance)
e24810
+        assert instance.execute('cloud-init status --wait --long').ok
e24810
         _output_to_compare(instance, after_path, netcfg_path)
e24810
 
e24810
     log.info('Wrote upgrade test logs to %s and %s', before_path, after_path)
e24810
+
e24810
+
e24810
+@pytest.mark.ci
e24810
+@pytest.mark.ubuntu
e24810
+def test_upgrade_package(session_cloud: IntegrationCloud):
e24810
+    if get_validated_source(session_cloud) != CloudInitSource.DEB_PACKAGE:
e24810
+        not_run_message = 'Test only supports upgrading to build deb'
e24810
+        if os.environ.get('TRAVIS'):
e24810
+            # If this isn't running on CI, we should know
e24810
+            pytest.fail(not_run_message)
e24810
+        else:
e24810
+            pytest.skip(not_run_message)
e24810
+
e24810
+    launch_kwargs = {'image_id': session_cloud.released_image_id}
e24810
+
e24810
+    with session_cloud.launch(launch_kwargs=launch_kwargs) as instance:
e24810
+        instance.install_deb()
e24810
+        instance.restart()
e24810
+        assert instance.execute('cloud-init status --wait --long').ok
e24810
-- 
e24810
2.27.0
e24810