Merge ~chad.smith/cloud-init:ubuntu/devel into cloud-init:ubuntu/devel
- Git
- lp:~chad.smith/cloud-init
- ubuntu/devel
- Merge into ubuntu/devel
Proposed by
Chad Smith
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 5db31ce1e2b61cecb458d8c4984a8db4d474f4f5 | ||||
Proposed branch: | ~chad.smith/cloud-init:ubuntu/devel | ||||
Merge into: | cloud-init:ubuntu/devel | ||||
Diff against target: |
992 lines (+630/-78) 11 files modified
cloudinit/sources/DataSourceOVF.py (+88/-37) cloudinit/sources/helpers/vmware/imc/config.py (+4/-0) cloudinit/sources/helpers/vmware/imc/config_custom_script.py (+153/-0) cloudinit/sources/helpers/vmware/imc/config_nic.py (+1/-1) debian/changelog (+10/-0) tests/unittests/test_datasource/test_ovf.py (+107/-4) tests/unittests/test_ds_identify.py (+84/-1) tests/unittests/test_vmware/__init__.py (+0/-0) tests/unittests/test_vmware/test_custom_script.py (+99/-0) tests/unittests/test_vmware_config_file.py (+7/-0) tools/ds-identify (+77/-35) |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Server Team CI bot | continuous-integration | Approve | |
Scott Moser | Pending | ||
Review via email: mp+334996@code.launchpad.net |
Commit message
Description of the change
Upstream snapshot for update into bionic
To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote : | # |
review:
Approve
(continuous-integration)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py |
2 | index 6ac621f..6e62f98 100644 |
3 | --- a/cloudinit/sources/DataSourceOVF.py |
4 | +++ b/cloudinit/sources/DataSourceOVF.py |
5 | @@ -21,6 +21,8 @@ from cloudinit import util |
6 | |
7 | from cloudinit.sources.helpers.vmware.imc.config \ |
8 | import Config |
9 | +from cloudinit.sources.helpers.vmware.imc.config_custom_script \ |
10 | + import PreCustomScript, PostCustomScript |
11 | from cloudinit.sources.helpers.vmware.imc.config_file \ |
12 | import ConfigFile |
13 | from cloudinit.sources.helpers.vmware.imc.config_nic \ |
14 | @@ -30,7 +32,7 @@ from cloudinit.sources.helpers.vmware.imc.config_passwd \ |
15 | from cloudinit.sources.helpers.vmware.imc.guestcust_error \ |
16 | import GuestCustErrorEnum |
17 | from cloudinit.sources.helpers.vmware.imc.guestcust_event \ |
18 | - import GuestCustEventEnum |
19 | + import GuestCustEventEnum as GuestCustEvent |
20 | from cloudinit.sources.helpers.vmware.imc.guestcust_state \ |
21 | import GuestCustStateEnum |
22 | from cloudinit.sources.helpers.vmware.imc.guestcust_util import ( |
23 | @@ -127,17 +129,31 @@ class DataSourceOVF(sources.DataSource): |
24 | self._vmware_cust_conf = Config(cf) |
25 | (md, ud, cfg) = read_vmware_imc(self._vmware_cust_conf) |
26 | self._vmware_nics_to_enable = get_nics_to_enable(nicspath) |
27 | - markerid = self._vmware_cust_conf.marker_id |
28 | - markerexists = check_marker_exists(markerid) |
29 | + imcdirpath = os.path.dirname(vmwareImcConfigFilePath) |
30 | + product_marker = self._vmware_cust_conf.marker_id |
31 | + hasmarkerfile = check_marker_exists( |
32 | + product_marker, os.path.join(self.paths.cloud_dir, 'data')) |
33 | + special_customization = product_marker and not hasmarkerfile |
34 | + customscript = self._vmware_cust_conf.custom_script_name |
35 | except Exception as e: |
36 | - LOG.debug("Error parsing the customization Config File") |
37 | - LOG.exception(e) |
38 | - set_customization_status( |
39 | - GuestCustStateEnum.GUESTCUST_STATE_RUNNING, |
40 | - GuestCustEventEnum.GUESTCUST_EVENT_CUSTOMIZE_FAILED) |
41 | - raise e |
42 | - finally: |
43 | - util.del_dir(os.path.dirname(vmwareImcConfigFilePath)) |
44 | + _raise_error_status( |
45 | + "Error parsing the customization Config File", |
46 | + e, |
47 | + GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED, |
48 | + vmwareImcConfigFilePath) |
49 | + |
50 | + if special_customization: |
51 | + if customscript: |
52 | + try: |
53 | + precust = PreCustomScript(customscript, imcdirpath) |
54 | + precust.execute() |
55 | + except Exception as e: |
56 | + _raise_error_status( |
57 | + "Error executing pre-customization script", |
58 | + e, |
59 | + GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED, |
60 | + vmwareImcConfigFilePath) |
61 | + |
62 | try: |
63 | LOG.debug("Preparing the Network configuration") |
64 | self._network_config = get_network_config_from_conf( |
65 | @@ -146,13 +162,13 @@ class DataSourceOVF(sources.DataSource): |
66 | True, |
67 | self.distro.osfamily) |
68 | except Exception as e: |
69 | - LOG.exception(e) |
70 | - set_customization_status( |
71 | - GuestCustStateEnum.GUESTCUST_STATE_RUNNING, |
72 | - GuestCustEventEnum.GUESTCUST_EVENT_NETWORK_SETUP_FAILED) |
73 | - raise e |
74 | + _raise_error_status( |
75 | + "Error preparing Network Configuration", |
76 | + e, |
77 | + GuestCustEvent.GUESTCUST_EVENT_NETWORK_SETUP_FAILED, |
78 | + vmwareImcConfigFilePath) |
79 | |
80 | - if markerid and not markerexists: |
81 | + if special_customization: |
82 | LOG.debug("Applying password customization") |
83 | pwdConfigurator = PasswordConfigurator() |
84 | adminpwd = self._vmware_cust_conf.admin_password |
85 | @@ -164,27 +180,41 @@ class DataSourceOVF(sources.DataSource): |
86 | else: |
87 | LOG.debug("Changing password is not needed") |
88 | except Exception as e: |
89 | - LOG.debug("Error applying Password Configuration: %s", e) |
90 | - set_customization_status( |
91 | - GuestCustStateEnum.GUESTCUST_STATE_RUNNING, |
92 | - GuestCustEventEnum.GUESTCUST_EVENT_CUSTOMIZE_FAILED) |
93 | - return False |
94 | - if markerid: |
95 | - LOG.debug("Handle marker creation") |
96 | + _raise_error_status( |
97 | + "Error applying Password Configuration", |
98 | + e, |
99 | + GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED, |
100 | + vmwareImcConfigFilePath) |
101 | + |
102 | + if customscript: |
103 | + try: |
104 | + postcust = PostCustomScript(customscript, imcdirpath) |
105 | + postcust.execute() |
106 | + except Exception as e: |
107 | + _raise_error_status( |
108 | + "Error executing post-customization script", |
109 | + e, |
110 | + GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED, |
111 | + vmwareImcConfigFilePath) |
112 | + |
113 | + if product_marker: |
114 | try: |
115 | - setup_marker_files(markerid) |
116 | + setup_marker_files( |
117 | + product_marker, |
118 | + os.path.join(self.paths.cloud_dir, 'data')) |
119 | except Exception as e: |
120 | - LOG.debug("Error creating marker files: %s", e) |
121 | - set_customization_status( |
122 | - GuestCustStateEnum.GUESTCUST_STATE_RUNNING, |
123 | - GuestCustEventEnum.GUESTCUST_EVENT_CUSTOMIZE_FAILED) |
124 | - return False |
125 | + _raise_error_status( |
126 | + "Error creating marker files", |
127 | + e, |
128 | + GuestCustEvent.GUESTCUST_EVENT_CUSTOMIZE_FAILED, |
129 | + vmwareImcConfigFilePath) |
130 | |
131 | self._vmware_cust_found = True |
132 | found.append('vmware-tools') |
133 | |
134 | # TODO: Need to set the status to DONE only when the |
135 | # customization is done successfully. |
136 | + util.del_dir(os.path.dirname(vmwareImcConfigFilePath)) |
137 | enable_nics(self._vmware_nics_to_enable) |
138 | set_customization_status( |
139 | GuestCustStateEnum.GUESTCUST_STATE_DONE, |
140 | @@ -539,31 +569,52 @@ def get_datasource_list(depends): |
141 | |
142 | |
143 | # To check if marker file exists |
144 | -def check_marker_exists(markerid): |
145 | +def check_marker_exists(markerid, marker_dir): |
146 | """ |
147 | Check the existence of a marker file. |
148 | Presence of marker file determines whether a certain code path is to be |
149 | executed. It is needed for partial guest customization in VMware. |
150 | + @param markerid: is an unique string representing a particular product |
151 | + marker. |
152 | + @param: marker_dir: The directory in which markers exist. |
153 | """ |
154 | if not markerid: |
155 | return False |
156 | - markerfile = "/.markerfile-" + markerid |
157 | + markerfile = os.path.join(marker_dir, ".markerfile-" + markerid + ".txt") |
158 | if os.path.exists(markerfile): |
159 | return True |
160 | return False |
161 | |
162 | |
163 | # Create a marker file |
164 | -def setup_marker_files(markerid): |
165 | +def setup_marker_files(markerid, marker_dir): |
166 | """ |
167 | Create a new marker file. |
168 | Marker files are unique to a full customization workflow in VMware |
169 | environment. |
170 | + @param markerid: is an unique string representing a particular product |
171 | + marker. |
172 | + @param: marker_dir: The directory in which markers exist. |
173 | + |
174 | """ |
175 | - if not markerid: |
176 | - return |
177 | - markerfile = "/.markerfile-" + markerid |
178 | - util.del_file("/.markerfile-*.txt") |
179 | + LOG.debug("Handle marker creation") |
180 | + markerfile = os.path.join(marker_dir, ".markerfile-" + markerid + ".txt") |
181 | + for fname in os.listdir(marker_dir): |
182 | + if fname.startswith(".markerfile"): |
183 | + util.del_file(os.path.join(marker_dir, fname)) |
184 | open(markerfile, 'w').close() |
185 | |
186 | + |
187 | +def _raise_error_status(prefix, error, event, config_file): |
188 | + """ |
189 | + Raise error and send customization status to the underlying VMware |
190 | + Virtualization Platform. Also, cleanup the imc directory. |
191 | + """ |
192 | + LOG.debug('%s: %s', prefix, error) |
193 | + set_customization_status( |
194 | + GuestCustStateEnum.GUESTCUST_STATE_RUNNING, |
195 | + event) |
196 | + util.del_dir(os.path.dirname(config_file)) |
197 | + raise error |
198 | + |
199 | # vi: ts=4 expandtab |
200 | diff --git a/cloudinit/sources/helpers/vmware/imc/config.py b/cloudinit/sources/helpers/vmware/imc/config.py |
201 | index 49d441d..2eaeff3 100644 |
202 | --- a/cloudinit/sources/helpers/vmware/imc/config.py |
203 | +++ b/cloudinit/sources/helpers/vmware/imc/config.py |
204 | @@ -100,4 +100,8 @@ class Config(object): |
205 | """Returns marker id.""" |
206 | return self._configFile.get(Config.MARKERID, None) |
207 | |
208 | + @property |
209 | + def custom_script_name(self): |
210 | + """Return the name of custom (pre/post) script.""" |
211 | + return self._configFile.get(Config.CUSTOM_SCRIPT, None) |
212 | # vi: ts=4 expandtab |
213 | diff --git a/cloudinit/sources/helpers/vmware/imc/config_custom_script.py b/cloudinit/sources/helpers/vmware/imc/config_custom_script.py |
214 | new file mode 100644 |
215 | index 0000000..a7d4ad9 |
216 | --- /dev/null |
217 | +++ b/cloudinit/sources/helpers/vmware/imc/config_custom_script.py |
218 | @@ -0,0 +1,153 @@ |
219 | +# Copyright (C) 2017 Canonical Ltd. |
220 | +# Copyright (C) 2017 VMware Inc. |
221 | +# |
222 | +# Author: Maitreyee Saikia <msaikia@vmware.com> |
223 | +# |
224 | +# This file is part of cloud-init. See LICENSE file for license information. |
225 | + |
226 | +import logging |
227 | +import os |
228 | +import stat |
229 | +from textwrap import dedent |
230 | + |
231 | +from cloudinit import util |
232 | + |
233 | +LOG = logging.getLogger(__name__) |
234 | + |
235 | + |
236 | +class CustomScriptNotFound(Exception): |
237 | + pass |
238 | + |
239 | + |
240 | +class CustomScriptConstant(object): |
241 | + RC_LOCAL = "/etc/rc.local" |
242 | + POST_CUST_TMP_DIR = "/root/.customization" |
243 | + POST_CUST_RUN_SCRIPT_NAME = "post-customize-guest.sh" |
244 | + POST_CUST_RUN_SCRIPT = os.path.join(POST_CUST_TMP_DIR, |
245 | + POST_CUST_RUN_SCRIPT_NAME) |
246 | + POST_REBOOT_PENDING_MARKER = "/.guest-customization-post-reboot-pending" |
247 | + |
248 | + |
249 | +class RunCustomScript(object): |
250 | + def __init__(self, scriptname, directory): |
251 | + self.scriptname = scriptname |
252 | + self.directory = directory |
253 | + self.scriptpath = os.path.join(directory, scriptname) |
254 | + |
255 | + def prepare_script(self): |
256 | + if not os.path.exists(self.scriptpath): |
257 | + raise CustomScriptNotFound("Script %s not found!! " |
258 | + "Cannot execute custom script!" |
259 | + % self.scriptpath) |
260 | + # Strip any CR characters from the decoded script |
261 | + util.load_file(self.scriptpath).replace("\r", "") |
262 | + st = os.stat(self.scriptpath) |
263 | + os.chmod(self.scriptpath, st.st_mode | stat.S_IEXEC) |
264 | + |
265 | + |
266 | +class PreCustomScript(RunCustomScript): |
267 | + def execute(self): |
268 | + """Executing custom script with precustomization argument.""" |
269 | + LOG.debug("Executing pre-customization script") |
270 | + self.prepare_script() |
271 | + util.subp(["/bin/sh", self.scriptpath, "precustomization"]) |
272 | + |
273 | + |
274 | +class PostCustomScript(RunCustomScript): |
275 | + def __init__(self, scriptname, directory): |
276 | + super(PostCustomScript, self).__init__(scriptname, directory) |
277 | + # Determine when to run custom script. When postreboot is True, |
278 | + # the user uploaded script will run as part of rc.local after |
279 | + # the machine reboots. This is determined by presence of rclocal. |
280 | + # When postreboot is False, script will run as part of cloud-init. |
281 | + self.postreboot = False |
282 | + |
283 | + def _install_post_reboot_agent(self, rclocal): |
284 | + """ |
285 | + Install post-reboot agent for running custom script after reboot. |
286 | + As part of this process, we are editing the rclocal file to run a |
287 | + VMware script, which in turn is resposible for handling the user |
288 | + script. |
289 | + @param: path to rc local. |
290 | + """ |
291 | + LOG.debug("Installing post-reboot customization from %s to %s", |
292 | + self.directory, rclocal) |
293 | + if not self.has_previous_agent(rclocal): |
294 | + LOG.info("Adding post-reboot customization agent to rc.local") |
295 | + new_content = dedent(""" |
296 | + # Run post-reboot guest customization |
297 | + /bin/sh %s |
298 | + exit 0 |
299 | + """) % CustomScriptConstant.POST_CUST_RUN_SCRIPT |
300 | + existing_rclocal = util.load_file(rclocal).replace('exit 0\n', '') |
301 | + st = os.stat(rclocal) |
302 | + # "x" flag should be set |
303 | + mode = st.st_mode | stat.S_IEXEC |
304 | + util.write_file(rclocal, existing_rclocal + new_content, mode) |
305 | + |
306 | + else: |
307 | + # We don't need to update rclocal file everytime a customization |
308 | + # is requested. It just needs to be done for the first time. |
309 | + LOG.info("Post-reboot guest customization agent is already " |
310 | + "registered in rc.local") |
311 | + LOG.debug("Installing post-reboot customization agent finished: %s", |
312 | + self.postreboot) |
313 | + |
314 | + def has_previous_agent(self, rclocal): |
315 | + searchstring = "# Run post-reboot guest customization" |
316 | + if searchstring in open(rclocal).read(): |
317 | + return True |
318 | + return False |
319 | + |
320 | + def find_rc_local(self): |
321 | + """ |
322 | + Determine if rc local is present. |
323 | + """ |
324 | + rclocal = "" |
325 | + if os.path.exists(CustomScriptConstant.RC_LOCAL): |
326 | + LOG.debug("rc.local detected.") |
327 | + # resolving in case of symlink |
328 | + rclocal = os.path.realpath(CustomScriptConstant.RC_LOCAL) |
329 | + LOG.debug("rc.local resolved to %s", rclocal) |
330 | + else: |
331 | + LOG.warning("Can't find rc.local, post-customization " |
332 | + "will be run before reboot") |
333 | + return rclocal |
334 | + |
335 | + def install_agent(self): |
336 | + rclocal = self.find_rc_local() |
337 | + if rclocal: |
338 | + self._install_post_reboot_agent(rclocal) |
339 | + self.postreboot = True |
340 | + |
341 | + def execute(self): |
342 | + """ |
343 | + This method executes post-customization script before or after reboot |
344 | + based on the presence of rc local. |
345 | + """ |
346 | + self.prepare_script() |
347 | + self.install_agent() |
348 | + if not self.postreboot: |
349 | + LOG.warning("Executing post-customization script inline") |
350 | + util.subp(["/bin/sh", self.scriptpath, "postcustomization"]) |
351 | + else: |
352 | + LOG.debug("Scheduling custom script to run post reboot") |
353 | + if not os.path.isdir(CustomScriptConstant.POST_CUST_TMP_DIR): |
354 | + os.mkdir(CustomScriptConstant.POST_CUST_TMP_DIR) |
355 | + # Script "post-customize-guest.sh" and user uploaded script are |
356 | + # are present in the same directory and needs to copied to a temp |
357 | + # directory to be executed post reboot. User uploaded script is |
358 | + # saved as customize.sh in the temp directory. |
359 | + # post-customize-guest.sh excutes customize.sh after reboot. |
360 | + LOG.debug("Copying post-customization script") |
361 | + util.copy(self.scriptpath, |
362 | + CustomScriptConstant.POST_CUST_TMP_DIR + "/customize.sh") |
363 | + LOG.debug("Copying script to run post-customization script") |
364 | + util.copy( |
365 | + os.path.join(self.directory, |
366 | + CustomScriptConstant.POST_CUST_RUN_SCRIPT_NAME), |
367 | + CustomScriptConstant.POST_CUST_RUN_SCRIPT) |
368 | + LOG.info("Creating post-reboot pending marker") |
369 | + util.ensure_file(CustomScriptConstant.POST_REBOOT_PENDING_MARKER) |
370 | + |
371 | +# vi: ts=4 expandtab |
372 | diff --git a/cloudinit/sources/helpers/vmware/imc/config_nic.py b/cloudinit/sources/helpers/vmware/imc/config_nic.py |
373 | index 2fb07c5..2d8900e 100644 |
374 | --- a/cloudinit/sources/helpers/vmware/imc/config_nic.py |
375 | +++ b/cloudinit/sources/helpers/vmware/imc/config_nic.py |
376 | @@ -161,7 +161,7 @@ class NicConfigurator(object): |
377 | if nic.primary and v4.gateways: |
378 | self.ipv4PrimaryGateway = v4.gateways[0] |
379 | subnet.update({'gateway': self.ipv4PrimaryGateway}) |
380 | - return [subnet] |
381 | + return ([subnet], route_list) |
382 | |
383 | # Add routes if there is no primary nic |
384 | if not self._primaryNic: |
385 | diff --git a/debian/changelog b/debian/changelog |
386 | index b13bdea..bbc29e5 100644 |
387 | --- a/debian/changelog |
388 | +++ b/debian/changelog |
389 | @@ -1,3 +1,13 @@ |
390 | +cloud-init (17.1-53-ga5dc0f42-0ubuntu1) bionic; urgency=medium |
391 | + |
392 | + * New upstream snapshot. |
393 | + - OVF: improve ds-identify to support finding OVF iso transport. |
394 | + (LP: #1731868) |
395 | + - VMware: Support for user provided pre and post-customization scripts |
396 | + [Maitreyee Saikia] |
397 | + |
398 | + -- Chad Smith <chad.smith@canonical.com> Fri, 08 Dec 2017 14:46:36 -0700 |
399 | + |
400 | cloud-init (17.1-51-g05b2308a-0ubuntu1) bionic; urgency=medium |
401 | |
402 | * New upstream snapshot. |
403 | diff --git a/tests/unittests/test_datasource/test_ovf.py b/tests/unittests/test_datasource/test_ovf.py |
404 | index 700da86..fc4eb36 100644 |
405 | --- a/tests/unittests/test_datasource/test_ovf.py |
406 | +++ b/tests/unittests/test_datasource/test_ovf.py |
407 | @@ -5,11 +5,17 @@ |
408 | # This file is part of cloud-init. See LICENSE file for license information. |
409 | |
410 | import base64 |
411 | -from collections import OrderedDict |
412 | +import os |
413 | |
414 | -from cloudinit.tests import helpers as test_helpers |
415 | +from collections import OrderedDict |
416 | +from textwrap import dedent |
417 | |
418 | +from cloudinit import util |
419 | +from cloudinit.tests.helpers import CiTestCase, wrap_and_call |
420 | +from cloudinit.helpers import Paths |
421 | from cloudinit.sources import DataSourceOVF as dsovf |
422 | +from cloudinit.sources.helpers.vmware.imc.config_custom_script import ( |
423 | + CustomScriptNotFound) |
424 | |
425 | OVF_ENV_CONTENT = """<?xml version="1.0" encoding="UTF-8"?> |
426 | <Environment xmlns="http://schemas.dmtf.org/ovf/environment/1" |
427 | @@ -42,7 +48,7 @@ def fill_properties(props, template=OVF_ENV_CONTENT): |
428 | return template.format(properties=properties) |
429 | |
430 | |
431 | -class TestReadOvfEnv(test_helpers.TestCase): |
432 | +class TestReadOvfEnv(CiTestCase): |
433 | def test_with_b64_userdata(self): |
434 | user_data = "#!/bin/sh\necho hello world\n" |
435 | user_data_b64 = base64.b64encode(user_data.encode()).decode() |
436 | @@ -72,7 +78,104 @@ class TestReadOvfEnv(test_helpers.TestCase): |
437 | self.assertIsNone(ud) |
438 | |
439 | |
440 | -class TestTransportIso9660(test_helpers.CiTestCase): |
441 | +class TestMarkerFiles(CiTestCase): |
442 | + |
443 | + def setUp(self): |
444 | + super(TestMarkerFiles, self).setUp() |
445 | + self.tdir = self.tmp_dir() |
446 | + |
447 | + def test_false_when_markerid_none(self): |
448 | + """Return False when markerid provided is None.""" |
449 | + self.assertFalse( |
450 | + dsovf.check_marker_exists(markerid=None, marker_dir=self.tdir)) |
451 | + |
452 | + def test_markerid_file_exist(self): |
453 | + """Return False when markerid file path does not exist, |
454 | + True otherwise.""" |
455 | + self.assertFalse( |
456 | + dsovf.check_marker_exists('123', self.tdir)) |
457 | + |
458 | + marker_file = self.tmp_path('.markerfile-123.txt', self.tdir) |
459 | + util.write_file(marker_file, '') |
460 | + self.assertTrue( |
461 | + dsovf.check_marker_exists('123', self.tdir) |
462 | + ) |
463 | + |
464 | + def test_marker_file_setup(self): |
465 | + """Test creation of marker files.""" |
466 | + markerfilepath = self.tmp_path('.markerfile-hi.txt', self.tdir) |
467 | + self.assertFalse(os.path.exists(markerfilepath)) |
468 | + dsovf.setup_marker_files(markerid='hi', marker_dir=self.tdir) |
469 | + self.assertTrue(os.path.exists(markerfilepath)) |
470 | + |
471 | + |
472 | +class TestDatasourceOVF(CiTestCase): |
473 | + |
474 | + with_logs = True |
475 | + |
476 | + def setUp(self): |
477 | + super(TestDatasourceOVF, self).setUp() |
478 | + self.datasource = dsovf.DataSourceOVF |
479 | + self.tdir = self.tmp_dir() |
480 | + |
481 | + def test_get_data_false_on_none_dmi_data(self): |
482 | + """When dmi for system-product-name is None, get_data returns False.""" |
483 | + paths = Paths({'seed_dir': self.tdir}) |
484 | + ds = self.datasource(sys_cfg={}, distro={}, paths=paths) |
485 | + retcode = wrap_and_call( |
486 | + 'cloudinit.sources.DataSourceOVF', |
487 | + {'util.read_dmi_data': None}, |
488 | + ds.get_data) |
489 | + self.assertFalse(retcode, 'Expected False return from ds.get_data') |
490 | + self.assertIn( |
491 | + 'DEBUG: No system-product-name found', self.logs.getvalue()) |
492 | + |
493 | + def test_get_data_no_vmware_customization_disabled(self): |
494 | + """When vmware customization is disabled via sys_cfg log a message.""" |
495 | + paths = Paths({'seed_dir': self.tdir}) |
496 | + ds = self.datasource( |
497 | + sys_cfg={'disable_vmware_customization': True}, distro={}, |
498 | + paths=paths) |
499 | + retcode = wrap_and_call( |
500 | + 'cloudinit.sources.DataSourceOVF', |
501 | + {'util.read_dmi_data': 'vmware'}, |
502 | + ds.get_data) |
503 | + self.assertFalse(retcode, 'Expected False return from ds.get_data') |
504 | + self.assertIn( |
505 | + 'DEBUG: Customization for VMware platform is disabled.', |
506 | + self.logs.getvalue()) |
507 | + |
508 | + def test_get_data_vmware_customization_disabled(self): |
509 | + """When cloud-init workflow for vmware is enabled via sys_cfg log a |
510 | + message. |
511 | + """ |
512 | + paths = Paths({'seed_dir': self.tdir}) |
513 | + ds = self.datasource( |
514 | + sys_cfg={'disable_vmware_customization': False}, distro={}, |
515 | + paths=paths) |
516 | + conf_file = self.tmp_path('test-cust', self.tdir) |
517 | + conf_content = dedent("""\ |
518 | + [CUSTOM-SCRIPT] |
519 | + SCRIPT-NAME = test-script |
520 | + [MISC] |
521 | + MARKER-ID = 12345345 |
522 | + """) |
523 | + util.write_file(conf_file, conf_content) |
524 | + with self.assertRaises(CustomScriptNotFound) as context: |
525 | + wrap_and_call( |
526 | + 'cloudinit.sources.DataSourceOVF', |
527 | + {'util.read_dmi_data': 'vmware', |
528 | + 'util.del_dir': True, |
529 | + 'search_file': self.tdir, |
530 | + 'wait_for_imc_cfg_file': conf_file, |
531 | + 'get_nics_to_enable': ''}, |
532 | + ds.get_data) |
533 | + customscript = self.tmp_path('test-script', self.tdir) |
534 | + self.assertIn('Script %s not found!!' % customscript, |
535 | + str(context.exception)) |
536 | + |
537 | + |
538 | +class TestTransportIso9660(CiTestCase): |
539 | |
540 | def setUp(self): |
541 | super(TestTransportIso9660, self).setUp() |
542 | diff --git a/tests/unittests/test_ds_identify.py b/tests/unittests/test_ds_identify.py |
543 | index 7a920d4..3f1a671 100644 |
544 | --- a/tests/unittests/test_ds_identify.py |
545 | +++ b/tests/unittests/test_ds_identify.py |
546 | @@ -32,6 +32,7 @@ POLICY_FOUND_OR_MAYBE = "search,found=all,maybe=all,notfound=disabled" |
547 | DI_DEFAULT_POLICY = "search,found=all,maybe=all,notfound=enabled" |
548 | DI_DEFAULT_POLICY_NO_DMI = "search,found=all,maybe=all,notfound=disabled" |
549 | DI_EC2_STRICT_ID_DEFAULT = "true" |
550 | +OVF_MATCH_STRING = 'http://schemas.dmtf.org/ovf/environment/1' |
551 | |
552 | SHELL_MOCK_TMPL = """\ |
553 | %(name)s() { |
554 | @@ -55,6 +56,7 @@ P_SEED_DIR = "var/lib/cloud/seed" |
555 | P_DSID_CFG = "etc/cloud/ds-identify.cfg" |
556 | |
557 | MOCK_VIRT_IS_KVM = {'name': 'detect_virt', 'RET': 'kvm', 'ret': 0} |
558 | +MOCK_VIRT_IS_VMWARE = {'name': 'detect_virt', 'RET': 'vmware', 'ret': 0} |
559 | MOCK_UNAME_IS_PPC64 = {'name': 'uname', 'out': UNAME_PPC64EL, 'ret': 0} |
560 | |
561 | |
562 | @@ -296,6 +298,48 @@ class TestDsIdentify(CiTestCase): |
563 | data, RC_FOUND, dslist=['OpenStack', 'None']) |
564 | self.assertIn("check for 'OpenStack' returned maybe", err) |
565 | |
566 | + def test_default_ovf_is_found(self): |
567 | + """OVF is identified found when ovf/ovf-env.xml seed file exists.""" |
568 | + self._test_ds_found('OVF-seed') |
569 | + |
570 | + def test_default_ovf_with_detect_virt_none_not_found(self): |
571 | + """OVF identifies not found when detect_virt returns "none".""" |
572 | + self._check_via_dict( |
573 | + {'ds': 'OVF'}, rc=RC_NOT_FOUND, policy_dmi="disabled") |
574 | + |
575 | + def test_default_ovf_returns_not_found_on_azure(self): |
576 | + """OVF datasource won't be found as false positive on Azure.""" |
577 | + ovfonazure = copy.deepcopy(VALID_CFG['OVF']) |
578 | + # Set azure asset tag to assert OVF content not found |
579 | + ovfonazure['files'][P_CHASSIS_ASSET_TAG] = ( |
580 | + '7783-7084-3265-9085-8269-3286-77\n') |
581 | + self._check_via_dict( |
582 | + ovfonazure, RC_FOUND, dslist=['Azure', DS_NONE]) |
583 | + |
584 | + def test_ovf_on_vmware_iso_found_by_cdrom_with_ovf_schema_match(self): |
585 | + """OVF is identified when iso9660 cdrom path contains ovf schema.""" |
586 | + self._test_ds_found('OVF') |
587 | + |
588 | + def test_ovf_on_vmware_iso_found_when_vmware_customization(self): |
589 | + """OVF is identified when vmware customization is enabled.""" |
590 | + self._test_ds_found('OVF-vmware-customization') |
591 | + |
592 | + def test_ovf_on_vmware_iso_found_by_cdrom_with_matching_fs_label(self): |
593 | + """OVF is identified when iso9660 cdrom label has ovf-transport.""" |
594 | + ovf_cdrom_by_label = copy.deepcopy(VALID_CFG['OVF']) |
595 | + # Unset matching cdrom ovf schema content |
596 | + ovf_cdrom_by_label['files']['dev/sr0'] = 'No content match' |
597 | + self._check_via_dict( |
598 | + ovf_cdrom_by_label, rc=RC_NOT_FOUND, policy_dmi="disabled") |
599 | + |
600 | + # Add recognized labels |
601 | + for valid_fs_label in ['ovf-transport', 'OVF-TRANSPORT']: |
602 | + ovf_cdrom_by_label['mocks'][0]['out'] = blkid_out([ |
603 | + {'DEVNAME': 'sr0', 'TYPE': 'iso9660', |
604 | + 'LABEL': valid_fs_label}]) |
605 | + self._check_via_dict( |
606 | + ovf_cdrom_by_label, rc=RC_FOUND, dslist=['OVF', DS_NONE]) |
607 | + |
608 | |
609 | def blkid_out(disks=None): |
610 | """Convert a list of disk dictionaries into blkid content.""" |
611 | @@ -305,7 +349,9 @@ def blkid_out(disks=None): |
612 | for disk in disks: |
613 | if not disk["DEVNAME"].startswith("/dev/"): |
614 | disk["DEVNAME"] = "/dev/" + disk["DEVNAME"] |
615 | - for key in disk: |
616 | + # devname needs to be first. |
617 | + lines.append("%s=%s" % ("DEVNAME", disk["DEVNAME"])) |
618 | + for key in [d for d in disk if d != "DEVNAME"]: |
619 | lines.append("%s=%s" % (key, disk[key])) |
620 | lines.append("") |
621 | return '\n'.join(lines) |
622 | @@ -383,6 +429,43 @@ VALID_CFG = { |
623 | 'policy_dmi': POLICY_FOUND_ONLY, |
624 | 'policy_no_dmi': POLICY_FOUND_ONLY, |
625 | }, |
626 | + 'OVF-seed': { |
627 | + 'ds': 'OVF', |
628 | + 'files': { |
629 | + os.path.join(P_SEED_DIR, 'ovf', 'ovf-env.xml'): 'present\n', |
630 | + } |
631 | + }, |
632 | + 'OVF-vmware-customization': { |
633 | + 'ds': 'OVF', |
634 | + 'mocks': [ |
635 | + # Include a mockes iso9660 potential, even though content not ovf |
636 | + {'name': 'blkid', 'ret': 0, |
637 | + 'out': blkid_out( |
638 | + [{'DEVNAME': 'sr0', 'TYPE': 'iso9660', 'LABEL': ''}]) |
639 | + }, |
640 | + MOCK_VIRT_IS_VMWARE, |
641 | + ], |
642 | + 'files': { |
643 | + 'dev/sr0': 'no match', |
644 | + # Setup vmware customization enabled |
645 | + 'usr/lib/vmware-tools/plugins/vmsvc/libdeployPkgPlugin.so': 'here', |
646 | + 'etc/cloud/cloud.cfg': 'disable_vmware_customization: false\n', |
647 | + } |
648 | + }, |
649 | + 'OVF': { |
650 | + 'ds': 'OVF', |
651 | + 'mocks': [ |
652 | + {'name': 'blkid', 'ret': 0, |
653 | + 'out': blkid_out( |
654 | + [{'DEVNAME': 'vda1', 'TYPE': 'vfat', 'PARTUUID': uuid4()}, |
655 | + {'DEVNAME': 'sr0', 'TYPE': 'iso9660', 'LABEL': ''}]) |
656 | + }, |
657 | + MOCK_VIRT_IS_VMWARE, |
658 | + ], |
659 | + 'files': { |
660 | + 'dev/sr0': 'pretend ovf iso has ' + OVF_MATCH_STRING + '\n', |
661 | + } |
662 | + }, |
663 | 'ConfigDrive': { |
664 | 'ds': 'ConfigDrive', |
665 | 'mocks': [ |
666 | diff --git a/tests/unittests/test_vmware/__init__.py b/tests/unittests/test_vmware/__init__.py |
667 | new file mode 100644 |
668 | index 0000000..e69de29 |
669 | --- /dev/null |
670 | +++ b/tests/unittests/test_vmware/__init__.py |
671 | diff --git a/tests/unittests/test_vmware/test_custom_script.py b/tests/unittests/test_vmware/test_custom_script.py |
672 | new file mode 100644 |
673 | index 0000000..2d9519b |
674 | --- /dev/null |
675 | +++ b/tests/unittests/test_vmware/test_custom_script.py |
676 | @@ -0,0 +1,99 @@ |
677 | +# Copyright (C) 2015 Canonical Ltd. |
678 | +# Copyright (C) 2017 VMware INC. |
679 | +# |
680 | +# Author: Maitreyee Saikia <msaikia@vmware.com> |
681 | +# |
682 | +# This file is part of cloud-init. See LICENSE file for license information. |
683 | + |
684 | +from cloudinit import util |
685 | +from cloudinit.sources.helpers.vmware.imc.config_custom_script import ( |
686 | + CustomScriptConstant, |
687 | + CustomScriptNotFound, |
688 | + PreCustomScript, |
689 | + PostCustomScript, |
690 | +) |
691 | +from cloudinit.tests.helpers import CiTestCase, mock |
692 | + |
693 | + |
694 | +class TestVmwareCustomScript(CiTestCase): |
695 | + def setUp(self): |
696 | + self.tmpDir = self.tmp_dir() |
697 | + |
698 | + def test_prepare_custom_script(self): |
699 | + """ |
700 | + This test is designed to verify the behavior based on the presence of |
701 | + custom script. Mainly needed for scenario where a custom script is |
702 | + expected, but was not properly copied. "CustomScriptNotFound" exception |
703 | + is raised in such cases. |
704 | + """ |
705 | + # Custom script does not exist. |
706 | + preCust = PreCustomScript("random-vmw-test", self.tmpDir) |
707 | + self.assertEqual("random-vmw-test", preCust.scriptname) |
708 | + self.assertEqual(self.tmpDir, preCust.directory) |
709 | + self.assertEqual(self.tmp_path("random-vmw-test", self.tmpDir), |
710 | + preCust.scriptpath) |
711 | + with self.assertRaises(CustomScriptNotFound): |
712 | + preCust.prepare_script() |
713 | + |
714 | + # Custom script exists. |
715 | + custScript = self.tmp_path("test-cust", self.tmpDir) |
716 | + util.write_file(custScript, "test-CR-strip/r/r") |
717 | + postCust = PostCustomScript("test-cust", self.tmpDir) |
718 | + self.assertEqual("test-cust", postCust.scriptname) |
719 | + self.assertEqual(self.tmpDir, postCust.directory) |
720 | + self.assertEqual(custScript, postCust.scriptpath) |
721 | + self.assertFalse(postCust.postreboot) |
722 | + postCust.prepare_script() |
723 | + # Check if all carraige returns are stripped from script. |
724 | + self.assertFalse("/r" in custScript) |
725 | + |
726 | + def test_rc_local_exists(self): |
727 | + """ |
728 | + This test is designed to verify the different scenarios associated |
729 | + with the presence of rclocal. |
730 | + """ |
731 | + # test when rc local does not exist |
732 | + postCust = PostCustomScript("test-cust", self.tmpDir) |
733 | + with mock.patch.object(CustomScriptConstant, "RC_LOCAL", "/no/path"): |
734 | + rclocal = postCust.find_rc_local() |
735 | + self.assertEqual("", rclocal) |
736 | + |
737 | + # test when rc local exists |
738 | + rclocalFile = self.tmp_path("vmware-rclocal", self.tmpDir) |
739 | + util.write_file(rclocalFile, "# Run post-reboot guest customization", |
740 | + omode="w") |
741 | + with mock.patch.object(CustomScriptConstant, "RC_LOCAL", rclocalFile): |
742 | + rclocal = postCust.find_rc_local() |
743 | + self.assertEqual(rclocalFile, rclocal) |
744 | + self.assertTrue(postCust.has_previous_agent, rclocal) |
745 | + |
746 | + # test when rc local is a symlink |
747 | + rclocalLink = self.tmp_path("dummy-rclocal-link", self.tmpDir) |
748 | + util.sym_link(rclocalFile, rclocalLink, True) |
749 | + with mock.patch.object(CustomScriptConstant, "RC_LOCAL", rclocalLink): |
750 | + rclocal = postCust.find_rc_local() |
751 | + self.assertEqual(rclocalFile, rclocal) |
752 | + |
753 | + def test_execute_post_cust(self): |
754 | + """ |
755 | + This test is to identify if rclocal was properly populated to be |
756 | + run after reboot. |
757 | + """ |
758 | + customscript = self.tmp_path("vmware-post-cust-script", self.tmpDir) |
759 | + rclocal = self.tmp_path("vmware-rclocal", self.tmpDir) |
760 | + # Create a temporary rclocal file |
761 | + open(customscript, "w") |
762 | + util.write_file(rclocal, "tests\nexit 0", omode="w") |
763 | + postCust = PostCustomScript("vmware-post-cust-script", self.tmpDir) |
764 | + with mock.patch.object(CustomScriptConstant, "RC_LOCAL", rclocal): |
765 | + # Test that guest customization agent is not installed initially. |
766 | + self.assertFalse(postCust.postreboot) |
767 | + self.assertIs(postCust.has_previous_agent(rclocal), False) |
768 | + postCust.install_agent() |
769 | + |
770 | + # Assert rclocal has been modified to have guest customization |
771 | + # agent. |
772 | + self.assertTrue(postCust.postreboot) |
773 | + self.assertTrue(postCust.has_previous_agent, rclocal) |
774 | + |
775 | +# vi: ts=4 expandtab |
776 | diff --git a/tests/unittests/test_vmware_config_file.py b/tests/unittests/test_vmware_config_file.py |
777 | index 0f8cda9..036f687 100644 |
778 | --- a/tests/unittests/test_vmware_config_file.py |
779 | +++ b/tests/unittests/test_vmware_config_file.py |
780 | @@ -335,5 +335,12 @@ class TestVmwareConfigFile(CiTestCase): |
781 | self.assertEqual('255.255.0.0', subnet.get('netmask'), |
782 | 'Subnet netmask') |
783 | |
784 | + def test_custom_script(self): |
785 | + cf = ConfigFile("tests/data/vmware/cust-dhcp-2nic.cfg") |
786 | + conf = Config(cf) |
787 | + self.assertIsNone(conf.custom_script_name) |
788 | + cf._insertKey("CUSTOM-SCRIPT|SCRIPT-NAME", "test-script") |
789 | + conf = Config(cf) |
790 | + self.assertEqual("test-script", conf.custom_script_name) |
791 | |
792 | # vi: ts=4 expandtab |
793 | diff --git a/tools/ds-identify b/tools/ds-identify |
794 | index ee5e05a..4c59d7b 100755 |
795 | --- a/tools/ds-identify |
796 | +++ b/tools/ds-identify |
797 | @@ -83,6 +83,7 @@ _DI_LOGGED="" |
798 | # set DI_MAIN='noop' in environment to source this file with no main called. |
799 | DI_MAIN=${DI_MAIN:-main} |
800 | |
801 | +DI_BLKID_OUTPUT="" |
802 | DI_DEFAULT_POLICY="search,found=all,maybe=all,notfound=${DI_DISABLED}" |
803 | DI_DEFAULT_POLICY_NO_DMI="search,found=all,maybe=all,notfound=${DI_ENABLED}" |
804 | DI_DMI_CHASSIS_ASSET_TAG="" |
805 | @@ -91,6 +92,7 @@ DI_DMI_SYS_VENDOR="" |
806 | DI_DMI_PRODUCT_SERIAL="" |
807 | DI_DMI_PRODUCT_UUID="" |
808 | DI_FS_LABELS="" |
809 | +DI_ISO9660_DEVS="" |
810 | DI_KERNEL_CMDLINE="" |
811 | DI_VIRT="" |
812 | DI_PID_1_PRODUCT_NAME="" |
813 | @@ -181,32 +183,43 @@ block_dev_with_label() { |
814 | return 0 |
815 | } |
816 | |
817 | -read_fs_labels() { |
818 | - cached "${DI_FS_LABELS}" && return 0 |
819 | +read_fs_info() { |
820 | + cached "${DI_BLKID_OUTPUT}" && return 0 |
821 | # do not rely on links in /dev/disk which might not be present yet. |
822 | # note that older blkid versions do not report DEVNAME in 'export' output. |
823 | - local out="" ret=0 oifs="$IFS" line="" delim="," |
824 | - local labels="" |
825 | if is_container; then |
826 | # blkid will in a container, or at least currently in lxd |
827 | # not provide useful information. |
828 | DI_FS_LABELS="$UNAVAILABLE:container" |
829 | - else |
830 | - out=$(blkid -c /dev/null -o export) || { |
831 | - ret=$? |
832 | - error "failed running [$ret]: blkid -c /dev/null -o export" |
833 | - return $ret |
834 | - } |
835 | - IFS="$CR" |
836 | - set -- $out |
837 | - IFS="$oifs" |
838 | - for line in "$@"; do |
839 | - case "${line}" in |
840 | - LABEL=*) labels="${labels}${line#LABEL=}${delim}";; |
841 | - esac |
842 | - done |
843 | - DI_FS_LABELS="${labels%${delim}}" |
844 | + DI_ISO9660_DEVS="$UNAVAILABLE:container" |
845 | + return |
846 | fi |
847 | + local oifs="$IFS" line="" delim="," |
848 | + local ret=0 out="" labels="" dev="" label="" ftype="" isodevs="" |
849 | + out=$(blkid -c /dev/null -o export) || { |
850 | + ret=$? |
851 | + error "failed running [$ret]: blkid -c /dev/null -o export" |
852 | + DI_FS_LABELS="$UNAVAILABLE:error" |
853 | + DI_ISO9660_DEVS="$UNAVAILABLE:error" |
854 | + return $ret |
855 | + } |
856 | + IFS="$CR" |
857 | + set -- $out |
858 | + IFS="$oifs" |
859 | + for line in "$@" ""; do |
860 | + case "${line}" in |
861 | + DEVNAME=*) dev=${line#DEVNAME=};; |
862 | + LABEL=*) label="${line#LABEL=}"; |
863 | + labels="${labels}${line#LABEL=}${delim}";; |
864 | + TYPE=*) ftype=${line#TYPE=};; |
865 | + "") if [ "$ftype" = "iso9660" ]; then |
866 | + isodevs="${isodevs} ${dev}=$label" |
867 | + fi |
868 | + ftype=""; devname=""; label=""; |
869 | + esac |
870 | + done |
871 | + DI_FS_LABELS="${labels%${delim}}" |
872 | + DI_ISO9660_DEVS="${isodevs# }" |
873 | } |
874 | |
875 | cached() { |
876 | @@ -214,10 +227,6 @@ cached() { |
877 | } |
878 | |
879 | |
880 | -has_cdrom() { |
881 | - [ -e "${PATH_ROOT}/dev/cdrom" ] |
882 | -} |
883 | - |
884 | detect_virt() { |
885 | local virt="${UNAVAILABLE}" r="" out="" |
886 | if [ -d /run/systemd ]; then |
887 | @@ -621,14 +630,13 @@ ovf_vmware_guest_customization() { |
888 | [ "${DI_VIRT}" = "vmware" ] || return 1 |
889 | |
890 | # we have to have the plugin to do vmware customization |
891 | - local found="" pkg="" pre="/usr/lib" |
892 | + local found="" pkg="" pre="${PATH_ROOT}/usr/lib" |
893 | for pkg in vmware-tools open-vm-tools; do |
894 | if [ -f "$pre/$pkg/plugins/vmsvc/libdeployPkgPlugin.so" ]; then |
895 | found="$pkg"; break; |
896 | fi |
897 | done |
898 | [ -n "$found" ] || return 1 |
899 | - |
900 | # vmware customization is disabled by default |
901 | # (disable_vmware_customization=true). If it is set to false, then |
902 | # user has requested customization. |
903 | @@ -644,20 +652,55 @@ ovf_vmware_guest_customization() { |
904 | return 1 |
905 | } |
906 | |
907 | +is_cdrom_ovf() { |
908 | + local dev="$1" label="$2" |
909 | + # skip devices that don't look like cdrom paths. |
910 | + case "$dev" in |
911 | + /dev/sr[0-9]|/dev/hd[a-z]) :;; |
912 | + *) debug 1 "skipping iso dev $d" |
913 | + return 1;; |
914 | + esac |
915 | + |
916 | + # fast path known 'OVF' labels |
917 | + [ "$label" = "OVF-TRANSPORT" -o "$label" = "ovf-transport" ] && return 0 |
918 | + |
919 | + # explicitly skip known labels of other types. rd_rdfe is azure. |
920 | + case "$label" in |
921 | + config-2|rd_rdfe_stable*) return 1;; |
922 | + esac |
923 | + |
924 | + local idstr="http://schemas.dmtf.org/ovf/environment/1" |
925 | + grep --quiet --ignore-case "$idstr" "${PATH_ROOT}$dev" |
926 | +} |
927 | + |
928 | dscheck_OVF() { |
929 | - local p="" |
930 | check_seed_dir ovf ovf-env.xml && return "${DS_FOUND}" |
931 | |
932 | + [ "${DI_VIRT}" = "none" ] && return ${DS_NOT_FOUND} |
933 | + |
934 | + # Azure provides ovf. Skip false positive by dis-allowing. |
935 | + is_azure_chassis && return $DS_NOT_FOUND |
936 | + |
937 | + local isodevs="${DI_ISO9660_DEVS}" |
938 | + case "$isodevs" in |
939 | + ""|$UNAVAILABLE:*) return ${DS_NOT_FOUND};; |
940 | + esac |
941 | + |
942 | + # DI_ISO9660_DEVS is <device>=label, like /dev/sr0=OVF-TRANSPORT |
943 | + for tok in $isodevs; do |
944 | + is_cdrom_ovf "${tok%%=*}" "${tok#*=}" && return $DS_FOUND |
945 | + done |
946 | + |
947 | if ovf_vmware_guest_customization; then |
948 | return ${DS_FOUND} |
949 | fi |
950 | |
951 | - has_cdrom || return ${DS_NOT_FOUND} |
952 | + return ${DS_NOT_FOUND} |
953 | +} |
954 | |
955 | - # FIXME: currently just return maybe if there is a cdrom |
956 | - # ovf iso9660 transport does not specify an fs label. |
957 | - # better would be to check if |
958 | - return ${DS_MAYBE} |
959 | +is_azure_chassis() { |
960 | + local azure_chassis="7783-7084-3265-9085-8269-3286-77" |
961 | + dmi_chassis_asset_tag_matches "${azure_chassis}" |
962 | } |
963 | |
964 | dscheck_Azure() { |
965 | @@ -667,8 +710,7 @@ dscheck_Azure() { |
966 | # UUID="112D211272645f72" LABEL="rd_rdfe_stable.161212-1209" |
967 | # TYPE="udf">/dev/sr0</device> |
968 | # |
969 | - local azure_chassis="7783-7084-3265-9085-8269-3286-77" |
970 | - dmi_chassis_asset_tag_matches "${azure_chassis}" && return $DS_FOUND |
971 | + is_azure_chassis && return $DS_FOUND |
972 | check_seed_dir azure ovf-env.xml && return ${DS_FOUND} |
973 | |
974 | [ "${DI_VIRT}" = "microsoft" ] || return ${DS_NOT_FOUND} |
975 | @@ -930,7 +972,7 @@ collect_info() { |
976 | read_dmi_product_name |
977 | read_dmi_product_serial |
978 | read_dmi_product_uuid |
979 | - read_fs_labels |
980 | + read_fs_info |
981 | } |
982 | |
983 | print_info() { |
984 | @@ -942,7 +984,7 @@ _print_info() { |
985 | local n="" v="" vars="" |
986 | vars="DMI_PRODUCT_NAME DMI_SYS_VENDOR DMI_PRODUCT_SERIAL" |
987 | vars="$vars DMI_PRODUCT_UUID PID_1_PRODUCT_NAME DMI_CHASSIS_ASSET_TAG" |
988 | - vars="$vars FS_LABELS KERNEL_CMDLINE VIRT" |
989 | + vars="$vars FS_LABELS ISO9660_DEVS KERNEL_CMDLINE VIRT" |
990 | vars="$vars UNAME_KERNEL_NAME UNAME_KERNEL_RELEASE UNAME_KERNEL_VERSION" |
991 | vars="$vars UNAME_MACHINE UNAME_NODENAME UNAME_OPERATING_SYSTEM" |
992 | vars="$vars DSNAME DSLIST" |
PASSED: Continuous integration, rev:5db31ce1e2b 61cecb458d8c498 4a8db4d474f4f5 /jenkins. ubuntu. com/server/ job/cloud- init-ci/ 604/
https:/
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: /jenkins. ubuntu. com/server/ job/cloud- init-ci/ 604/rebuild
https:/