Merge ~chad.smith/cloud-init:ubuntu/artful into cloud-init:ubuntu/artful

Proposed by Chad Smith
Status: Merged
Merged at revision: e5596beef0618204dedd94e1cd593a8cfb6bb6c7
Proposed branch: ~chad.smith/cloud-init:ubuntu/artful
Merge into: cloud-init:ubuntu/artful
Diff against target: 656 lines (+630/-0)
4 files modified
debian/changelog (+9/-0)
debian/patches/cpick-11172924-IBMCloud-Disable-config-drive-and-nocloud-only-if (+230/-0)
debian/patches/cpick-6ef92c98-IBMCloud-recognize-provisioning-environment-during (+389/-0)
debian/patches/series (+2/-0)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Scott Moser Pending
Review via email: mp+344901@code.launchpad.net

Commit message

Cherry pick fixes for IBMCloud upgrades from 17.1 -> 18.2 (artful-proposed)

Addresses the following bugs:
LP: #1766401
LP: #1767166

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:5a8b71fdc0b9313bfac2c8eedde1ced0004d5d2a
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1085/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    SUCCESS: MAAS Compatability Testing
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1085/rebuild

review: Approve (continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote :

PASSED: Continuous integration, rev:e5596beef0618204dedd94e1cd593a8cfb6bb6c7
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1087/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    SUCCESS: Ubuntu LTS: Build
    SUCCESS: Ubuntu LTS: Integration
    SUCCESS: MAAS Compatability Testing
    IN_PROGRESS: Declarative: Post Actions

Click here to trigger a rebuild:
https://jenkins.ubuntu.com/server/job/cloud-init-ci/1087/rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index 982d0c8..c438253 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,12 @@
6+cloud-init (18.2-4-g05926e48-0ubuntu1~17.10.2) artful-proposed; urgency=medium
7+
8+ * cherry-pick 11172924: IBMCloud: Disable config-drive and nocloud
9+ only if IBMCloud (LP: #1766401)
10+ * cherry-pick 6ef92c98: IBMCloud: recognize provisioning environment
11+ during debug (LP: #1767166)
12+
13+ -- Chad Smith <chad.smith@canonical.com> Tue, 01 May 2018 10:36:14 -0600
14+
15 cloud-init (18.2-4-g05926e48-0ubuntu1~17.10.1) artful-proposed; urgency=medium
16
17 * debian/new-upstream-snapshot: Remove script, now maintained elsewhere.
18diff --git a/debian/patches/cpick-11172924-IBMCloud-Disable-config-drive-and-nocloud-only-if b/debian/patches/cpick-11172924-IBMCloud-Disable-config-drive-and-nocloud-only-if
19new file mode 100644
20index 0000000..534aa73
21--- /dev/null
22+++ b/debian/patches/cpick-11172924-IBMCloud-Disable-config-drive-and-nocloud-only-if
23@@ -0,0 +1,230 @@
24+From 11172924a48a47a7231d19d9cefe628dfddda8bf Mon Sep 17 00:00:00 2001
25+From: Scott Moser <smoser@ubuntu.com>
26+Date: Mon, 30 Apr 2018 13:21:51 -0600
27+Subject: [PATCH] IBMCloud: Disable config-drive and nocloud only if IBMCloud
28+ is enabled.
29+
30+Ubuntu images on IBMCloud for 16.04 have some seed data in
31+/var/lib/cloud/data/seed/nocloud-net. In order to have systems with
32+IBMCloud enabled, we modified ds-identify detection to skip that seed
33+if the system was on IBMCloud. That change did not consider the
34+fact that IBMCloud might not be in the datasource list.
35+
36+There was similar logic in the ConfigDrive datasource in ds-identify
37+and the datasource itself.
38+
39+Config drive is now updated to only check and avoid IBMCloud if IBMCloud
40+is enabled. The check in ds-identify for nocloud was dropped. If a
41+user provides a nocloud seed on IBMCloud, then that can be used.
42+
43+This means that systems running Xenial will continue to get their
44+old datasources.
45+
46+LP: #1766401
47+---
48+ cloudinit/sources/DataSourceConfigDrive.py | 11 +++--
49+ tests/unittests/test_ds_identify.py | 77 +++++++++++++++++++++++++++---
50+ tools/ds-identify | 17 +++++--
51+ 3 files changed, 91 insertions(+), 14 deletions(-)
52+
53+--- a/cloudinit/sources/DataSourceConfigDrive.py
54++++ b/cloudinit/sources/DataSourceConfigDrive.py
55+@@ -69,7 +69,8 @@
56+ util.logexc(LOG, "Failed reading config drive from %s", sdir)
57+
58+ if not found:
59+- for dev in find_candidate_devs():
60++ dslist = self.sys_cfg.get('datasource_list')
61++ for dev in find_candidate_devs(dslist=dslist):
62+ try:
63+ # Set mtype if freebsd and turn off sync
64+ if dev.startswith("/dev/cd"):
65+@@ -211,7 +212,7 @@
66+ util.logexc(LOG, "Failed writing file: %s", filename)
67+
68+
69+-def find_candidate_devs(probe_optical=True):
70++def find_candidate_devs(probe_optical=True, dslist=None):
71+ """Return a list of devices that may contain the config drive.
72+
73+ The returned list is sorted by search order where the first item has
74+@@ -227,6 +228,9 @@
75+ * either vfat or iso9660 formated
76+ * labeled with 'config-2' or 'CONFIG-2'
77+ """
78++ if dslist is None:
79++ dslist = []
80++
81+ # query optical drive to get it in blkid cache for 2.6 kernels
82+ if probe_optical:
83+ for device in OPTICAL_DEVICES:
84+@@ -257,7 +261,8 @@
85+ devices = [d for d in candidates
86+ if d in by_label or not util.is_partition(d)]
87+
88+- if devices:
89++ LOG.debug("devices=%s dslist=%s", devices, dslist)
90++ if devices and "IBMCloud" in dslist:
91+ # IBMCloud uses config-2 label, but limited to a single UUID.
92+ ibm_platform, ibm_path = get_ibm_platform()
93+ if ibm_path in devices:
94+--- a/tests/unittests/test_ds_identify.py
95++++ b/tests/unittests/test_ds_identify.py
96+@@ -178,17 +178,18 @@
97+ data, RC_FOUND, dslist=[data.get('ds'), DS_NONE])
98+
99+ def _check_via_dict(self, data, rc, dslist=None, **kwargs):
100+- found_rc, out, err, cfg, files = self._call_via_dict(data, **kwargs)
101++ ret = self._call_via_dict(data, **kwargs)
102+ good = False
103+ try:
104+- self.assertEqual(rc, found_rc)
105++ self.assertEqual(rc, ret.rc)
106+ if dslist is not None:
107+- self.assertEqual(dslist, cfg['datasource_list'])
108++ self.assertEqual(dslist, ret.cfg['datasource_list'])
109+ good = True
110+ finally:
111+ if not good:
112+- _print_run_output(rc, out, err, cfg, files)
113+- return rc, out, err, cfg, files
114++ _print_run_output(ret.rc, ret.stdout, ret.stderr, ret.cfg,
115++ ret.files)
116++ return ret
117+
118+ def test_wb_print_variables(self):
119+ """_print_info reports an array of discovered variables to stderr."""
120+@@ -237,13 +238,40 @@
121+ def test_config_drive(self):
122+ """ConfigDrive datasource has a disk with LABEL=config-2."""
123+ self._test_ds_found('ConfigDrive')
124+- return
125+
126+ def test_config_drive_upper(self):
127+ """ConfigDrive datasource has a disk with LABEL=CONFIG-2."""
128+ self._test_ds_found('ConfigDriveUpper')
129+ return
130+
131++ def test_config_drive_seed(self):
132++ """Config Drive seed directory."""
133++ self._test_ds_found('ConfigDrive-seed')
134++
135++ def test_config_drive_interacts_with_ibmcloud_config_disk(self):
136++ """Verify ConfigDrive interaction with IBMCloud.
137++
138++ If ConfigDrive is enabled and not IBMCloud, then ConfigDrive
139++ should claim the ibmcloud 'config-2' disk.
140++ If IBMCloud is enabled, then ConfigDrive should skip."""
141++ data = copy.deepcopy(VALID_CFG['IBMCloud-config-2'])
142++ files = data.get('files', {})
143++ if not files:
144++ data['files'] = files
145++ cfgpath = 'etc/cloud/cloud.cfg.d/99_networklayer_common.cfg'
146++
147++ # with list including IBMCloud, config drive should be not found.
148++ files[cfgpath] = 'datasource_list: [ ConfigDrive, IBMCloud ]\n'
149++ ret = self._check_via_dict(data, shell_true)
150++ self.assertEqual(
151++ ret.cfg.get('datasource_list'), ['IBMCloud', 'None'])
152++
153++ # But if IBMCloud is not enabled, config drive should claim this.
154++ files[cfgpath] = 'datasource_list: [ ConfigDrive, NoCloud ]\n'
155++ ret = self._check_via_dict(data, shell_true)
156++ self.assertEqual(
157++ ret.cfg.get('datasource_list'), ['ConfigDrive', 'None'])
158++
159+ def test_ibmcloud_template_userdata_in_provisioning(self):
160+ """Template provisioned with user-data during provisioning stage.
161+
162+@@ -295,6 +323,37 @@
163+ self._check_via_dict(
164+ data, rc=RC_FOUND, dslist=['ConfigDrive', DS_NONE])
165+
166++ def test_ibmcloud_with_nocloud_seed(self):
167++ """NoCloud seed should be preferred over IBMCloud.
168++
169++ A nocloud seed should be preferred over IBMCloud even if enabled.
170++ Ubuntu 16.04 images have <vlc>/seed/nocloud-net. LP: #1766401."""
171++ data = copy.deepcopy(VALID_CFG['IBMCloud-config-2'])
172++ files = data.get('files', {})
173++ if not files:
174++ data['files'] = files
175++ files.update(VALID_CFG['NoCloud-seed']['files'])
176++ ret = self._check_via_dict(data, shell_true)
177++ self.assertEqual(
178++ ['NoCloud', 'IBMCloud', 'None'],
179++ ret.cfg.get('datasource_list'))
180++
181++ def test_ibmcloud_with_configdrive_seed(self):
182++ """ConfigDrive seed should be preferred over IBMCloud.
183++
184++ A ConfigDrive seed should be preferred over IBMCloud even if enabled.
185++ Ubuntu 16.04 images have a fstab entry that mounts the
186++ METADATA disk into <vlc>/seed/config_drive. LP: ##1766401."""
187++ data = copy.deepcopy(VALID_CFG['IBMCloud-config-2'])
188++ files = data.get('files', {})
189++ if not files:
190++ data['files'] = files
191++ files.update(VALID_CFG['ConfigDrive-seed']['files'])
192++ ret = self._check_via_dict(data, shell_true)
193++ self.assertEqual(
194++ ['ConfigDrive', 'IBMCloud', 'None'],
195++ ret.cfg.get('datasource_list'))
196++
197+ def test_policy_disabled(self):
198+ """A Builtin policy of 'disabled' should return not found.
199+
200+@@ -631,6 +690,12 @@
201+ },
202+ ],
203+ },
204++ 'ConfigDrive-seed': {
205++ 'ds': 'ConfigDrive',
206++ 'files': {
207++ os.path.join(P_SEED_DIR, 'config_drive', 'openstack',
208++ 'latest', 'meta_data.json'): 'md\n'},
209++ },
210+ 'Hetzner': {
211+ 'ds': 'Hetzner',
212+ 'files': {P_SYS_VENDOR: 'Hetzner\n'},
213+--- a/tools/ds-identify
214++++ b/tools/ds-identify
215+@@ -600,7 +600,6 @@
216+ *\ ds=nocloud*) return ${DS_FOUND};;
217+ esac
218+
219+- is_ibm_cloud && return ${DS_NOT_FOUND}
220+ for d in nocloud nocloud-net; do
221+ check_seed_dir "$d" meta-data user-data && return ${DS_FOUND}
222+ check_writable_seed_dir "$d" meta-data user-data && return ${DS_FOUND}
223+@@ -611,11 +610,12 @@
224+ return ${DS_NOT_FOUND}
225+ }
226+
227++is_ds_enabled() {
228++ local name="$1" pad=" ${DI_DSLIST} "
229++ [ "${pad#* $name }" != "${pad}" ]
230++}
231++
232+ check_configdrive_v2() {
233+- is_ibm_cloud && return ${DS_NOT_FOUND}
234+- if has_fs_with_label CONFIG-2 config-2; then
235+- return ${DS_FOUND}
236+- fi
237+ # look in /config-drive <vlc>/seed/config_drive for a directory
238+ # openstack/YYYY-MM-DD format with a file meta_data.json
239+ local d=""
240+@@ -630,6 +630,13 @@
241+ debug 1 "config drive seeded directory had only 'latest'"
242+ return ${DS_FOUND}
243+ fi
244++
245++ is_ds_enabled "IBMCloud"
246++ debug 1 "is_ds_enabled returned $?: $DI_DSLIST"
247++ is_ds_enabled "IBMCloud" && is_ibm_cloud && return ${DS_NOT_FOUND}
248++ if has_fs_with_label CONFIG-2 config-2; then
249++ return ${DS_FOUND}
250++ fi
251+ return ${DS_NOT_FOUND}
252+ }
253+
254diff --git a/debian/patches/cpick-6ef92c98-IBMCloud-recognize-provisioning-environment-during b/debian/patches/cpick-6ef92c98-IBMCloud-recognize-provisioning-environment-during
255new file mode 100644
256index 0000000..b428120
257--- /dev/null
258+++ b/debian/patches/cpick-6ef92c98-IBMCloud-recognize-provisioning-environment-during
259@@ -0,0 +1,389 @@
260+From 6ef92c98c3d2b127b05d6708337efc8a81e00071 Mon Sep 17 00:00:00 2001
261+From: Scott Moser <smoser@ubuntu.com>
262+Date: Thu, 26 Apr 2018 16:24:24 -0500
263+Subject: [PATCH] IBMCloud: recognize provisioning environment during debug
264+ boots.
265+
266+When images are deployed from template in a production environment
267+the artifacts of the provisioning stage (provisioningConfiguration.cfg)
268+that cloud-init referenced are cleaned up. However, when provisioned
269+in "debug" mode (internal to IBM) the artifacts are left.
270+
271+This changes the 'is_ibm_provisioning' implementations in both
272+ds-identify and in the IBM datasource to identify the provisioning
273+stage more correctly. The change is to consider provisioning only
274+if the provisioing file existed and there was no log file or
275+the log file was older than this boot.
276+
277+LP: #1767166
278+---
279+ cloudinit/sources/DataSourceIBMCloud.py | 42 +++++++++-----
280+ cloudinit/tests/helpers.py | 13 ++++-
281+ tests/unittests/test_datasource/test_ibmcloud.py | 50 ++++++++++++++++
282+ tests/unittests/test_ds_identify.py | 72 +++++++++++++++++++++---
283+ tools/ds-identify | 21 ++++++-
284+ 5 files changed, 175 insertions(+), 23 deletions(-)
285+
286+--- a/cloudinit/sources/DataSourceIBMCloud.py
287++++ b/cloudinit/sources/DataSourceIBMCloud.py
288+@@ -8,17 +8,11 @@
289+ * template: This is the legacy method of launching instances.
290+ When booting from an image template, the system boots first into
291+ a "provisioning" mode. There, host <-> guest mechanisms are utilized
292+- to execute code in the guest and provision it.
293++ to execute code in the guest and configure it. The configuration
294++ includes configuring the system network and possibly installing
295++ packages and other software stack.
296+
297+- Cloud-init will disable itself when it detects that it is in the
298+- provisioning mode. It detects this by the presence of
299+- a file '/root/provisioningConfiguration.cfg'.
300+-
301+- When provided with user-data, the "first boot" will contain a
302+- ConfigDrive-like disk labeled with 'METADATA'. If there is no user-data
303+- provided, then there is no data-source.
304+-
305+- Cloud-init never does any network configuration in this mode.
306++ After the provisioning is finished, the system reboots.
307+
308+ * os_code: Essentially "launch by OS Code" (Operating System Code).
309+ This is a more modern approach. There is no specific "provisioning" boot.
310+@@ -138,8 +132,30 @@
311+ return os.path.exists("/proc/xen")
312+
313+
314+-def _is_ibm_provisioning():
315+- return os.path.exists("/root/provisioningConfiguration.cfg")
316++def _is_ibm_provisioning(
317++ prov_cfg="/root/provisioningConfiguration.cfg",
318++ inst_log="/root/swinstall.log",
319++ boot_ref="/proc/1/environ"):
320++ """Return boolean indicating if this boot is ibm provisioning boot."""
321++ if os.path.exists(prov_cfg):
322++ msg = "config '%s' exists." % prov_cfg
323++ result = True
324++ if os.path.exists(inst_log):
325++ if os.path.exists(boot_ref):
326++ result = (os.stat(inst_log).st_mtime >
327++ os.stat(boot_ref).st_mtime)
328++ msg += (" log '%s' from %s boot." %
329++ (inst_log, "current" if result else "previous"))
330++ else:
331++ msg += (" log '%s' existed, but no reference file '%s'." %
332++ (inst_log, boot_ref))
333++ result = False
334++ else:
335++ msg += " log '%s' did not exist." % inst_log
336++ else:
337++ result, msg = (False, "config '%s' did not exist." % prov_cfg)
338++ LOG.debug("ibm_provisioning=%s: %s", result, msg)
339++ return result
340+
341+
342+ def get_ibm_platform():
343+@@ -189,7 +205,7 @@
344+ else:
345+ return (Platforms.TEMPLATE_LIVE_METADATA, metadata_path)
346+ elif _is_ibm_provisioning():
347+- return (Platforms.TEMPLATE_PROVISIONING_NODATA, None)
348++ return (Platforms.TEMPLATE_PROVISIONING_NODATA, None)
349+ return not_found
350+
351+
352+--- a/cloudinit/tests/helpers.py
353++++ b/cloudinit/tests/helpers.py
354+@@ -8,6 +8,7 @@
355+ import shutil
356+ import sys
357+ import tempfile
358++import time
359+ import unittest
360+
361+ import mock
362+@@ -285,7 +286,8 @@
363+ os.path: [('isfile', 1), ('exists', 1),
364+ ('islink', 1), ('isdir', 1), ('lexists', 1)],
365+ os: [('listdir', 1), ('mkdir', 1),
366+- ('lstat', 1), ('symlink', 2)]
367++ ('lstat', 1), ('symlink', 2),
368++ ('stat', 1)]
369+ }
370+
371+ if hasattr(os, 'scandir'):
372+@@ -354,6 +356,15 @@
373+ return ret
374+
375+
376++def populate_dir_with_ts(path, data):
377++ """data is {'file': ('contents', mtime)}. mtime relative to now."""
378++ populate_dir(path, dict((k, v[0]) for k, v in data.items()))
379++ btime = time.time()
380++ for fpath, (_contents, mtime) in data.items():
381++ ts = btime + mtime if mtime else btime
382++ os.utime(os.path.sep.join((path, fpath)), (ts, ts))
383++
384++
385+ def dir2dict(startdir, prefix=None):
386+ flist = {}
387+ if prefix is None:
388+--- a/tests/unittests/test_datasource/test_ibmcloud.py
389++++ b/tests/unittests/test_datasource/test_ibmcloud.py
390+@@ -259,4 +259,54 @@
391+ ret['metadata'])
392+
393+
394++class TestIsIBMProvisioning(test_helpers.FilesystemMockingTestCase):
395++ """Test the _is_ibm_provisioning method."""
396++ inst_log = "/root/swinstall.log"
397++ prov_cfg = "/root/provisioningConfiguration.cfg"
398++ boot_ref = "/proc/1/environ"
399++ with_logs = True
400++
401++ def _call_with_root(self, rootd):
402++ self.reRoot(rootd)
403++ return ibm._is_ibm_provisioning()
404++
405++ def test_no_config(self):
406++ """No provisioning config means not provisioning."""
407++ self.assertFalse(self._call_with_root(self.tmp_dir()))
408++
409++ def test_config_only(self):
410++ """A provisioning config without a log means provisioning."""
411++ rootd = self.tmp_dir()
412++ test_helpers.populate_dir(rootd, {self.prov_cfg: "key=value"})
413++ self.assertTrue(self._call_with_root(rootd))
414++
415++ def test_config_with_old_log(self):
416++ """A config with a log from previous boot is not provisioning."""
417++ rootd = self.tmp_dir()
418++ data = {self.prov_cfg: ("key=value\nkey2=val2\n", -10),
419++ self.inst_log: ("log data\n", -30),
420++ self.boot_ref: ("PWD=/", 0)}
421++ test_helpers.populate_dir_with_ts(rootd, data)
422++ self.assertFalse(self._call_with_root(rootd=rootd))
423++ self.assertIn("from previous boot", self.logs.getvalue())
424++
425++ def test_config_with_new_log(self):
426++ """A config with a log from this boot is provisioning."""
427++ rootd = self.tmp_dir()
428++ data = {self.prov_cfg: ("key=value\nkey2=val2\n", -10),
429++ self.inst_log: ("log data\n", 30),
430++ self.boot_ref: ("PWD=/", 0)}
431++ test_helpers.populate_dir_with_ts(rootd, data)
432++ self.assertTrue(self._call_with_root(rootd=rootd))
433++ self.assertIn("from current boot", self.logs.getvalue())
434++
435++ def test_config_and_log_no_reference(self):
436++ """If the config and log existed, but no reference, assume not."""
437++ rootd = self.tmp_dir()
438++ test_helpers.populate_dir(
439++ rootd, {self.prov_cfg: "key=value", self.inst_log: "log data\n"})
440++ self.assertFalse(self._call_with_root(rootd=rootd))
441++ self.assertIn("no reference file", self.logs.getvalue())
442++
443++
444+ # vi: ts=4 expandtab
445+--- a/tests/unittests/test_ds_identify.py
446++++ b/tests/unittests/test_ds_identify.py
447+@@ -1,5 +1,6 @@
448+ # This file is part of cloud-init. See LICENSE file for license information.
449+
450++from collections import namedtuple
451+ import copy
452+ import os
453+ from uuid import uuid4
454+@@ -7,7 +8,7 @@
455+ from cloudinit import safeyaml
456+ from cloudinit import util
457+ from cloudinit.tests.helpers import (
458+- CiTestCase, dir2dict, populate_dir)
459++ CiTestCase, dir2dict, populate_dir, populate_dir_with_ts)
460+
461+ from cloudinit.sources import DataSourceIBMCloud as dsibm
462+
463+@@ -66,7 +67,6 @@
464+ P_SEED_DIR = "var/lib/cloud/seed"
465+ P_DSID_CFG = "etc/cloud/ds-identify.cfg"
466+
467+-IBM_PROVISIONING_CHECK_PATH = "/root/provisioningConfiguration.cfg"
468+ IBM_CONFIG_UUID = "9796-932E"
469+
470+ MOCK_VIRT_IS_KVM = {'name': 'detect_virt', 'RET': 'kvm', 'ret': 0}
471+@@ -74,11 +74,17 @@
472+ MOCK_VIRT_IS_XEN = {'name': 'detect_virt', 'RET': 'xen', 'ret': 0}
473+ MOCK_UNAME_IS_PPC64 = {'name': 'uname', 'out': UNAME_PPC64EL, 'ret': 0}
474+
475++shell_true = 0
476++shell_false = 1
477+
478+-class TestDsIdentify(CiTestCase):
479++CallReturn = namedtuple('CallReturn',
480++ ['rc', 'stdout', 'stderr', 'cfg', 'files'])
481++
482++
483++class DsIdentifyBase(CiTestCase):
484+ dsid_path = os.path.realpath('tools/ds-identify')
485+
486+- def call(self, rootd=None, mocks=None, args=None, files=None,
487++ def call(self, rootd=None, mocks=None, func="main", args=None, files=None,
488+ policy_dmi=DI_DEFAULT_POLICY,
489+ policy_no_dmi=DI_DEFAULT_POLICY_NO_DMI,
490+ ec2_strict_id=DI_EC2_STRICT_ID_DEFAULT):
491+@@ -135,7 +141,7 @@
492+ mocklines.append(write_mock(d))
493+
494+ endlines = [
495+- 'main %s' % ' '.join(['"%s"' % s for s in args])
496++ func + ' ' + ' '.join(['"%s"' % s for s in args])
497+ ]
498+
499+ with open(wrap, "w") as fp:
500+@@ -159,7 +165,7 @@
501+ cfg = {"_INVALID_YAML": contents,
502+ "_EXCEPTION": str(e)}
503+
504+- return rc, out, err, cfg, dir2dict(rootd)
505++ return CallReturn(rc, out, err, cfg, dir2dict(rootd))
506+
507+ def _call_via_dict(self, data, rootd=None, **kwargs):
508+ # return output of self.call with a dict input like VALID_CFG[item]
509+@@ -191,6 +197,8 @@
510+ ret.files)
511+ return ret
512+
513++
514++class TestDsIdentify(DsIdentifyBase):
515+ def test_wb_print_variables(self):
516+ """_print_info reports an array of discovered variables to stderr."""
517+ data = VALID_CFG['Azure-dmi-detection']
518+@@ -278,7 +286,10 @@
519+ Template provisioning with user-data has METADATA disk,
520+ datasource should return not found."""
521+ data = copy.deepcopy(VALID_CFG['IBMCloud-metadata'])
522+- data['files'] = {IBM_PROVISIONING_CHECK_PATH: 'xxx'}
523++ # change the 'is_ibm_provisioning' mock to return 1 (false)
524++ isprov_m = [m for m in data['mocks']
525++ if m["name"] == "is_ibm_provisioning"][0]
526++ isprov_m['ret'] = shell_true
527+ return self._check_via_dict(data, RC_NOT_FOUND)
528+
529+ def test_ibmcloud_template_userdata(self):
530+@@ -293,7 +304,8 @@
531+
532+ no disks attached. Datasource should return not found."""
533+ data = copy.deepcopy(VALID_CFG['IBMCloud-nodisks'])
534+- data['files'] = {IBM_PROVISIONING_CHECK_PATH: 'xxx'}
535++ data['mocks'].append(
536++ {'name': 'is_ibm_provisioning', 'ret': shell_true})
537+ return self._check_via_dict(data, RC_NOT_FOUND)
538+
539+ def test_ibmcloud_template_no_userdata(self):
540+@@ -505,6 +517,47 @@
541+ self._test_ds_found('Hetzner')
542+
543+
544++class TestIsIBMProvisioning(DsIdentifyBase):
545++ """Test the is_ibm_provisioning method in ds-identify."""
546++
547++ inst_log = "/root/swinstall.log"
548++ prov_cfg = "/root/provisioningConfiguration.cfg"
549++ boot_ref = "/proc/1/environ"
550++ funcname = "is_ibm_provisioning"
551++
552++ def test_no_config(self):
553++ """No provisioning config means not provisioning."""
554++ ret = self.call(files={}, func=self.funcname)
555++ self.assertEqual(shell_false, ret.rc)
556++
557++ def test_config_only(self):
558++ """A provisioning config without a log means provisioning."""
559++ ret = self.call(files={self.prov_cfg: "key=value"}, func=self.funcname)
560++ self.assertEqual(shell_true, ret.rc)
561++
562++ def test_config_with_old_log(self):
563++ """A config with a log from previous boot is not provisioning."""
564++ rootd = self.tmp_dir()
565++ data = {self.prov_cfg: ("key=value\nkey2=val2\n", -10),
566++ self.inst_log: ("log data\n", -30),
567++ self.boot_ref: ("PWD=/", 0)}
568++ populate_dir_with_ts(rootd, data)
569++ ret = self.call(rootd=rootd, func=self.funcname)
570++ self.assertEqual(shell_false, ret.rc)
571++ self.assertIn("from previous boot", ret.stderr)
572++
573++ def test_config_with_new_log(self):
574++ """A config with a log from this boot is provisioning."""
575++ rootd = self.tmp_dir()
576++ data = {self.prov_cfg: ("key=value\nkey2=val2\n", -10),
577++ self.inst_log: ("log data\n", 30),
578++ self.boot_ref: ("PWD=/", 0)}
579++ populate_dir_with_ts(rootd, data)
580++ ret = self.call(rootd=rootd, func=self.funcname)
581++ self.assertEqual(shell_true, ret.rc)
582++ self.assertIn("from current boot", ret.stderr)
583++
584++
585+ def blkid_out(disks=None):
586+ """Convert a list of disk dictionaries into blkid content."""
587+ if disks is None:
588+@@ -704,6 +757,7 @@
589+ 'ds': 'IBMCloud',
590+ 'mocks': [
591+ MOCK_VIRT_IS_XEN,
592++ {'name': 'is_ibm_provisioning', 'ret': shell_false},
593+ {'name': 'blkid', 'ret': 0,
594+ 'out': blkid_out(
595+ [{'DEVNAME': 'xvda1', 'TYPE': 'vfat', 'PARTUUID': uuid4()},
596+@@ -717,6 +771,7 @@
597+ 'ds': 'IBMCloud',
598+ 'mocks': [
599+ MOCK_VIRT_IS_XEN,
600++ {'name': 'is_ibm_provisioning', 'ret': shell_false},
601+ {'name': 'blkid', 'ret': 0,
602+ 'out': blkid_out(
603+ [{'DEVNAME': 'xvda1', 'TYPE': 'ext3', 'PARTUUID': uuid4(),
604+@@ -734,6 +789,7 @@
605+ 'ds': 'IBMCloud',
606+ 'mocks': [
607+ MOCK_VIRT_IS_XEN,
608++ {'name': 'is_ibm_provisioning', 'ret': shell_false},
609+ {'name': 'blkid', 'ret': 0,
610+ 'out': blkid_out(
611+ [{'DEVNAME': 'xvda1', 'TYPE': 'vfat', 'PARTUUID': uuid4()},
612+--- a/tools/ds-identify
613++++ b/tools/ds-identify
614+@@ -125,6 +125,7 @@
615+ DI_EC2_STRICT_ID_DEFAULT="true"
616+
617+ _IS_IBM_CLOUD=""
618++_IS_IBM_PROVISIONING=""
619+
620+ error() {
621+ set -- "ERROR:" "$@";
622+@@ -1013,7 +1014,25 @@
623+ }
624+
625+ is_ibm_provisioning() {
626+- [ -f "${PATH_ROOT}/root/provisioningConfiguration.cfg" ]
627++ local pcfg="${PATH_ROOT}/root/provisioningConfiguration.cfg"
628++ local logf="${PATH_ROOT}/root/swinstall.log"
629++ local is_prov=false msg="config '$pcfg' did not exist."
630++ if [ -f "$pcfg" ]; then
631++ msg="config '$pcfg' exists."
632++ is_prov=true
633++ if [ -f "$logf" ]; then
634++ if [ "$logf" -nt "$PATH_PROC_1_ENVIRON" ]; then
635++ msg="$msg log '$logf' from current boot."
636++ else
637++ is_prov=false
638++ msg="$msg log '$logf' from previous boot."
639++ fi
640++ else
641++ msg="$msg log '$logf' did not exist."
642++ fi
643++ fi
644++ debug 2 "ibm_provisioning=$is_prov: $msg"
645++ [ "$is_prov" = "true" ]
646+ }
647+
648+ is_ibm_cloud() {
649diff --git a/debian/patches/series b/debian/patches/series
650new file mode 100644
651index 0000000..2f90183
652--- /dev/null
653+++ b/debian/patches/series
654@@ -0,0 +1,2 @@
655+cpick-11172924-IBMCloud-Disable-config-drive-and-nocloud-only-if
656+cpick-6ef92c98-IBMCloud-recognize-provisioning-environment-during

Subscribers

People subscribed via source and target branches