From 3e02227236fc860bdf0937b2734b35c373fdb263 Mon Sep 17 00:00:00 2001
From: James Falcon <james.falcon@canonical.com>
Date: Mon, 25 Apr 2022 15:43:57 -0500
Subject: [PATCH] Fix ds-identify not detecting NoCloud seed in config (#1381)

Reference:https://github.com/canonical/cloud-init/commit/3e02227236fc860bdf0937b2734b35c373fdb263
Conflict:NA

NoCloud seed config can be defined in /etc/cloud/cloud.cfg[.d].
However, ds-identify had no means of detecting this config and reported
NOT FOUND. This commit allows ds-identify to detect  and report it
properly.

LP: #1876375
---
 cloudinit/stages.py                 |  4 ++--
 tests/unittests/test_ds_identify.py | 25 +++++++++++++++++++++++++
 tools/ds-identify                   |  5 +++++
 3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/cloudinit/stages.py b/cloudinit/stages.py
index 59b0925..502c060 100644
--- a/cloudinit/stages.py
+++ b/cloudinit/stages.py
@@ -1045,11 +1045,11 @@ def read_runtime_config():
 def fetch_base_config():
     return util.mergemanydict(
         [
-            # builtin config
+            # builtin config, hardcoded in settings.py.
             util.get_builtin_cfg(),
             # Anything in your conf.d or 'default' cloud.cfg location.
             util.read_conf_with_confd(CLOUD_CONFIG),
-            # runtime config
+            # runtime config. I.e., /run/cloud-init/cloud.cfg
             read_runtime_config(),
             # Kernel/cmdline parameters override system config
             util.read_conf_from_cmdline(),
diff --git a/tests/unittests/test_ds_identify.py b/tests/unittests/test_ds_identify.py
index 43603ea..7342171 100644
--- a/tests/unittests/test_ds_identify.py
+++ b/tests/unittests/test_ds_identify.py
@@ -1,6 +1,7 @@
 # This file is part of cloud-init. See LICENSE file for license information.
 
 from collections import namedtuple
+from textwrap import dedent
 import copy
 import os
 from uuid import uuid4
@@ -610,6 +611,10 @@ class TestDsIdentify(DsIdentifyBase):
         """NoCloud is found with uppercase filesystem label."""
         self._test_ds_found('NoCloudUpper')
 
+    def test_nocloud_seed_in_cfg(self):
+        """NoCloud seed definition can go in /etc/cloud/cloud.cfg[.d]"""
+        self._test_ds_found("NoCloud-cfg")
+
     def test_nocloud_fatboot(self):
         """NoCloud fatboot label - LP: #184166."""
         self._test_ds_found('NoCloud-fatboot')
@@ -912,6 +917,26 @@ VALID_CFG = {
             'dev/vdb': 'pretend iso content for cidata\n',
         }
     },
+    "NoCloud-cfg": {
+        "ds": "NoCloud",
+        "files": {
+            # Also include a datasource list of more than just
+            # [NoCloud, None], because that would automatically select
+            # NoCloud without checking
+            "/etc/cloud/cloud.cfg": dedent(
+                """\
+                datasource_list: [ Azure, Openstack, NoCloud, None ]
+                datasource:
+                  NoCloud:
+                    user-data: |
+                      #cloud-config
+                      hostname: footbar
+                    meta-data: |
+                      instance_id: cloud-image
+                """
+            )
+        },
+    },
     'NoCloud-fbsd': {
         'ds': 'NoCloud',
         'mocks': [
diff --git a/tools/ds-identify b/tools/ds-identify
index 30d4b0f..f92c0d3 100755
--- a/tools/ds-identify
+++ b/tools/ds-identify
@@ -826,6 +826,11 @@ dscheck_NoCloud() {
         return ${DS_FOUND}
     fi
 
+    # This is a bit hacky, but a NoCloud false positive isn't the end of the world
+    if check_config "NoCloud" && check_config "user-data" && check_config "meta-data"; then
+        return ${DS_FOUND}
+    fi
+
     return ${DS_NOT_FOUND}
 }
 
-- 
2.33.0


