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

Proposed by Chad Smith on 2019-06-04
Status: Merged
Merged at revision: 59d8c5e0f514782bf853a414d905ddb569bb1fff
Proposed branch: ~chad.smith/cloud-init:ubuntu/xenial
Merge into: cloud-init:ubuntu/xenial
Diff against target: 767 lines (+204/-315)
18 files modified
cloudinit/config/cc_growpart.py (+2/-1)
cloudinit/config/cc_resizefs.py (+3/-3)
cloudinit/config/cc_ubuntu_advantage.py (+1/-1)
cloudinit/net/network_state.py (+8/-0)
cloudinit/sources/DataSourceNoCloud.py (+23/-17)
cloudinit/util.py (+13/-9)
config/cloud.cfg.tmpl (+2/-2)
debian/changelog (+7/-0)
debian/patches/ubuntu-advantage-revert-tip.patch (+5/-255)
tests/unittests/test_datasource/test_azure.py (+0/-24)
tests/unittests/test_datasource/test_nocloud.py (+18/-0)
tests/unittests/test_distros/test_freebsd.py (+45/-0)
tests/unittests/test_ds_identify.py (+20/-0)
tests/unittests/test_handler/test_handler_resizefs.py (+1/-1)
tests/unittests/test_net.py (+46/-0)
tools/ds-identify (+8/-0)
tools/render-cloudcfg (+1/-1)
tools/run-container (+1/-1)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Needs Fixing on 2019-06-04
cloud-init Commiters 2019-06-04 Pending
Review via email: mp+368355@code.launchpad.net

Commit message

Refresh patches due to drift in cc_ubuntu_advantage.py
new-upstream-snapshot -v --update-patches-only

To post a comment you must log in.

FAILED: Continuous integration, rev:d12794c5048cecdc4887c7bd496794cb6fad029c
https://jenkins.ubuntu.com/server/job/cloud-init-ci/732/
Executed test runs:
    SUCCESS: Checkout
    SUCCESS: Unit & Style Tests
    FAILED: Ubuntu LTS: Build

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

review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/cloudinit/config/cc_growpart.py b/cloudinit/config/cc_growpart.py
2index bafca9d..564f376 100644
3--- a/cloudinit/config/cc_growpart.py
4+++ b/cloudinit/config/cc_growpart.py
5@@ -215,7 +215,8 @@ def device_part_info(devpath):
6 # FreeBSD doesn't know of sysfs so just get everything we need from
7 # the device, like /dev/vtbd0p2.
8 if util.is_FreeBSD():
9- m = re.search('^(/dev/.+)p([0-9])$', devpath)
10+ freebsd_part = "/dev/" + util.find_freebsd_part(devpath)
11+ m = re.search('^(/dev/.+)p([0-9])$', freebsd_part)
12 return (m.group(1), m.group(2))
13
14 if not os.path.exists(syspath):
15diff --git a/cloudinit/config/cc_resizefs.py b/cloudinit/config/cc_resizefs.py
16index 076b9d5..afd2e06 100644
17--- a/cloudinit/config/cc_resizefs.py
18+++ b/cloudinit/config/cc_resizefs.py
19@@ -81,7 +81,7 @@ def _resize_xfs(mount_point, devpth):
20
21
22 def _resize_ufs(mount_point, devpth):
23- return ('growfs', '-y', devpth)
24+ return ('growfs', '-y', mount_point)
25
26
27 def _resize_zfs(mount_point, devpth):
28@@ -101,7 +101,7 @@ def _can_skip_resize_ufs(mount_point, devpth):
29 """
30 # dumpfs -m /
31 # newfs command for / (/dev/label/rootfs)
32- newfs -O 2 -U -a 4 -b 32768 -d 32768 -e 4096 -f 4096 -g 16384
33+ newfs -L rootf -O 2 -U -a 4 -b 32768 -d 32768 -e 4096 -f 4096 -g 16384
34 -h 64 -i 8192 -j -k 6408 -m 8 -o time -s 58719232 /dev/label/rootf
35 """
36 cur_fs_sz = None
37@@ -110,7 +110,7 @@ def _can_skip_resize_ufs(mount_point, devpth):
38 for line in dumpfs_res.splitlines():
39 if not line.startswith('#'):
40 newfs_cmd = shlex.split(line)
41- opt_value = 'O:Ua:s:b:d:e:f:g:h:i:jk:m:o:'
42+ opt_value = 'O:Ua:s:b:d:e:f:g:h:i:jk:m:o:L:'
43 optlist, _args = getopt.getopt(newfs_cmd[1:], opt_value)
44 for o, a in optlist:
45 if o == "-s":
46diff --git a/cloudinit/config/cc_ubuntu_advantage.py b/cloudinit/config/cc_ubuntu_advantage.py
47index f488123..f846e9a 100644
48--- a/cloudinit/config/cc_ubuntu_advantage.py
49+++ b/cloudinit/config/cc_ubuntu_advantage.py
50@@ -36,7 +36,7 @@ schema = {
51 """),
52 'distros': distros,
53 'examples': [dedent("""\
54- # Attach the machine to a Ubuntu Advantage support contract with a
55+ # Attach the machine to an Ubuntu Advantage support contract with a
56 # UA contract token obtained from %s.
57 ubuntu_advantage:
58 token: <ua_contract_token>
59diff --git a/cloudinit/net/network_state.py b/cloudinit/net/network_state.py
60index 4d19f56..3702130 100644
61--- a/cloudinit/net/network_state.py
62+++ b/cloudinit/net/network_state.py
63@@ -707,6 +707,14 @@ class NetworkStateInterpreter(object):
64 item_params = dict((key, value) for (key, value) in
65 item_cfg.items() if key not in
66 NETWORK_V2_KEY_FILTER)
67+ # we accept the fixed spelling, but write the old for compatability
68+ # Xenial does not have an updated netplan which supports the
69+ # correct spelling. LP: #1756701
70+ params = item_params['parameters']
71+ grat_value = params.pop('gratuitous-arp', None)
72+ if grat_value:
73+ params['gratuitious-arp'] = grat_value
74+
75 v1_cmd = {
76 'type': cmd_type,
77 'name': item_name,
78diff --git a/cloudinit/sources/DataSourceNoCloud.py b/cloudinit/sources/DataSourceNoCloud.py
79index fcf5d58..8a9e5dd 100644
80--- a/cloudinit/sources/DataSourceNoCloud.py
81+++ b/cloudinit/sources/DataSourceNoCloud.py
82@@ -35,6 +35,26 @@ class DataSourceNoCloud(sources.DataSource):
83 root = sources.DataSource.__str__(self)
84 return "%s [seed=%s][dsmode=%s]" % (root, self.seed, self.dsmode)
85
86+ def _get_devices(self, label):
87+ if util.is_FreeBSD():
88+ devlist = [
89+ p for p in ['/dev/msdosfs/' + label, '/dev/iso9660/' + label]
90+ if os.path.exists(p)]
91+ else:
92+ # Query optical drive to get it in blkid cache for 2.6 kernels
93+ util.find_devs_with(path="/dev/sr0")
94+ util.find_devs_with(path="/dev/sr1")
95+
96+ fslist = util.find_devs_with("TYPE=vfat")
97+ fslist.extend(util.find_devs_with("TYPE=iso9660"))
98+
99+ label_list = util.find_devs_with("LABEL=%s" % label.upper())
100+ label_list.extend(util.find_devs_with("LABEL=%s" % label.lower()))
101+
102+ devlist = list(set(fslist) & set(label_list))
103+ devlist.sort(reverse=True)
104+ return devlist
105+
106 def _get_data(self):
107 defaults = {
108 "instance-id": "nocloud",
109@@ -99,20 +119,7 @@ class DataSourceNoCloud(sources.DataSource):
110
111 label = self.ds_cfg.get('fs_label', "cidata")
112 if label is not None:
113- # Query optical drive to get it in blkid cache for 2.6 kernels
114- util.find_devs_with(path="/dev/sr0")
115- util.find_devs_with(path="/dev/sr1")
116-
117- fslist = util.find_devs_with("TYPE=vfat")
118- fslist.extend(util.find_devs_with("TYPE=iso9660"))
119-
120- label_list = util.find_devs_with("LABEL=%s" % label.upper())
121- label_list.extend(util.find_devs_with("LABEL=%s" % label.lower()))
122-
123- devlist = list(set(fslist) & set(label_list))
124- devlist.sort(reverse=True)
125-
126- for dev in devlist:
127+ for dev in self._get_devices(label):
128 try:
129 LOG.debug("Attempting to use data from %s", dev)
130
131@@ -120,9 +127,8 @@ class DataSourceNoCloud(sources.DataSource):
132 seeded = util.mount_cb(dev, _pp2d_callback,
133 pp2d_kwargs)
134 except ValueError:
135- if dev in label_list:
136- LOG.warning("device %s with label=%s not a"
137- "valid seed.", dev, label)
138+ LOG.warning("device %s with label=%s not a"
139+ "valid seed.", dev, label)
140 continue
141
142 mydata = _merge_new_seed(mydata, seeded)
143diff --git a/cloudinit/util.py b/cloudinit/util.py
144index ea4199c..aa23b3f 100644
145--- a/cloudinit/util.py
146+++ b/cloudinit/util.py
147@@ -2337,17 +2337,21 @@ def parse_mtab(path):
148 return None
149
150
151-def find_freebsd_part(label_part):
152- if label_part.startswith("/dev/label/"):
153- target_label = label_part[5:]
154- (label_part, _err) = subp(['glabel', 'status', '-s'])
155- for labels in label_part.split("\n"):
156+def find_freebsd_part(fs):
157+ splitted = fs.split('/')
158+ if len(splitted) == 3:
159+ return splitted[2]
160+ elif splitted[2] in ['label', 'gpt', 'ufs']:
161+ target_label = fs[5:]
162+ (part, _err) = subp(['glabel', 'status', '-s'])
163+ for labels in part.split("\n"):
164 items = labels.split()
165- if len(items) > 0 and items[0].startswith(target_label):
166- label_part = items[2]
167+ if len(items) > 0 and items[0] == target_label:
168+ part = items[2]
169 break
170- label_part = str(label_part)
171- return label_part
172+ return str(part)
173+ else:
174+ LOG.warning("Unexpected input in find_freebsd_part: %s", fs)
175
176
177 def get_path_dev_freebsd(path, mnt_list):
178diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl
179index 25db43e..684c747 100644
180--- a/config/cloud.cfg.tmpl
181+++ b/config/cloud.cfg.tmpl
182@@ -32,8 +32,8 @@ preserve_hostname: false
183
184 {% if variant in ["freebsd"] %}
185 # This should not be required, but leave it in place until the real cause of
186-# not beeing able to find -any- datasources is resolved.
187-datasource_list: ['ConfigDrive', 'Azure', 'OpenStack', 'Ec2']
188+# not finding -any- datasources is resolved.
189+datasource_list: ['NoCloud', 'ConfigDrive', 'Azure', 'OpenStack', 'Ec2']
190 {% endif %}
191 # Example datasource config
192 # datasource:
193diff --git a/debian/changelog b/debian/changelog
194index 270b0f3..e14ee1c 100644
195--- a/debian/changelog
196+++ b/debian/changelog
197@@ -1,3 +1,10 @@
198+cloud-init (19.1-1-gbaa47854-0ubuntu1~16.04.2) UNRELEASED; urgency=medium
199+
200+ * refresh patches:
201+ + debian/patches/ubuntu-advantage-revert-tip.patch
202+
203+ -- Chad Smith <chad.smith@canonical.com> Tue, 04 Jun 2019 14:59:14 -0600
204+
205 cloud-init (19.1-1-gbaa47854-0ubuntu1~16.04.1) xenial; urgency=medium
206
207 * debian/patches/ubuntu-advantage-revert-tip.patch
208diff --git a/debian/patches/ubuntu-advantage-revert-tip.patch b/debian/patches/ubuntu-advantage-revert-tip.patch
209index 08bdc81..5f1e043 100644
210--- a/debian/patches/ubuntu-advantage-revert-tip.patch
211+++ b/debian/patches/ubuntu-advantage-revert-tip.patch
212@@ -9,257 +9,9 @@ Forwarded: not-needed
213 Last-Update: 2019-05-10
214 ---
215 This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
216-Index: cloud-init/cloudinit/config/cc_ubuntu_advantage.py
217-===================================================================
218---- cloud-init.orig/cloudinit/config/cc_ubuntu_advantage.py
219-+++ cloud-init/cloudinit/config/cc_ubuntu_advantage.py
220-@@ -1,143 +1,150 @@
221-+# Copyright (C) 2018 Canonical Ltd.
222-+#
223- # This file is part of cloud-init. See LICENSE file for license information.
224-
225--"""ubuntu_advantage: Configure Ubuntu Advantage support services"""
226-+"""Ubuntu advantage: manage ubuntu-advantage offerings from Canonical."""
227-
228-+import sys
229- from textwrap import dedent
230-
231--import six
232--
233-+from cloudinit import log as logging
234- from cloudinit.config.schema import (
235- get_schema_doc, validate_cloudconfig_schema)
236--from cloudinit import log as logging
237- from cloudinit.settings import PER_INSTANCE
238-+from cloudinit.subp import prepend_base_command
239- from cloudinit import util
240-
241-
242--UA_URL = 'https://ubuntu.com/advantage'
243--
244- distros = ['ubuntu']
245-+frequency = PER_INSTANCE
246-+
247-+LOG = logging.getLogger(__name__)
248-
249- schema = {
250- 'id': 'cc_ubuntu_advantage',
251- 'name': 'Ubuntu Advantage',
252-- 'title': 'Configure Ubuntu Advantage support services',
253-+ 'title': 'Install, configure and manage ubuntu-advantage offerings',
254- 'description': dedent("""\
255-- Attach machine to an existing Ubuntu Advantage support contract and
256-- enable or disable support services such as Livepatch, ESM,
257-- FIPS and FIPS Updates. When attaching a machine to Ubuntu Advantage,
258-- one can also specify services to enable. When the 'enable'
259-- list is present, any named service will be enabled and all absent
260-- services will remain disabled.
261--
262-- Note that when enabling FIPS or FIPS updates you will need to schedule
263-- a reboot to ensure the machine is running the FIPS-compliant kernel.
264-- See :ref:`Power State Change` for information on how to configure
265-- cloud-init to perform this reboot.
266-+ This module provides configuration options to setup ubuntu-advantage
267-+ subscriptions.
268-+
269-+ .. note::
270-+ Both ``commands`` value can be either a dictionary or a list. If
271-+ the configuration provided is a dictionary, the keys are only used
272-+ to order the execution of the commands and the dictionary is
273-+ merged with any vendor-data ubuntu-advantage configuration
274-+ provided. If a ``commands`` is provided as a list, any vendor-data
275-+ ubuntu-advantage ``commands`` are ignored.
276-+
277-+ Ubuntu-advantage ``commands`` is a dictionary or list of
278-+ ubuntu-advantage commands to run on the deployed machine.
279-+ These commands can be used to enable or disable subscriptions to
280-+ various ubuntu-advantage products. See 'man ubuntu-advantage' for more
281-+ information on supported subcommands.
282-+
283-+ .. note::
284-+ Each command item can be a string or list. If the item is a list,
285-+ 'ubuntu-advantage' can be omitted and it will automatically be
286-+ inserted as part of the command.
287- """),
288- 'distros': distros,
289- 'examples': [dedent("""\
290-- # Attach the machine to a Ubuntu Advantage support contract with a
291-- # UA contract token obtained from %s.
292-- ubuntu_advantage:
293-- token: <ua_contract_token>
294-- """ % UA_URL), dedent("""\
295-- # Attach the machine to an Ubuntu Advantage support contract enabling
296-- # only fips and esm services. Services will only be enabled if
297-- # the environment supports said service. Otherwise warnings will
298-- # be logged for incompatible services specified.
299-+ # Enable Extended Security Maintenance using your service auth token
300-+ ubuntu-advantage:
301-+ commands:
302-+ 00: ubuntu-advantage enable-esm <token>
303-+ """), dedent("""\
304-+ # Enable livepatch by providing your livepatch token
305- ubuntu-advantage:
306-- token: <ua_contract_token>
307-- enable:
308-- - fips
309-- - esm
310-+ commands:
311-+ 00: ubuntu-advantage enable-livepatch <livepatch-token>
312-+
313- """), dedent("""\
314-- # Attach the machine to an Ubuntu Advantage support contract and enable
315-- # the FIPS service. Perform a reboot once cloud-init has
316-- # completed.
317-- power_state:
318-- mode: reboot
319-+ # Convenience: the ubuntu-advantage command can be omitted when
320-+ # specifying commands as a list and 'ubuntu-advantage' will
321-+ # automatically be prepended.
322-+ # The following commands are equivalent
323- ubuntu-advantage:
324-- token: <ua_contract_token>
325-- enable:
326-- - fips
327-- """)],
328-+ commands:
329-+ 00: ['enable-livepatch', 'my-token']
330-+ 01: ['ubuntu-advantage', 'enable-livepatch', 'my-token']
331-+ 02: ubuntu-advantage enable-livepatch my-token
332-+ 03: 'ubuntu-advantage enable-livepatch my-token'
333-+ """)],
334- 'frequency': PER_INSTANCE,
335- 'type': 'object',
336- 'properties': {
337-- 'ubuntu_advantage': {
338-+ 'ubuntu-advantage': {
339- 'type': 'object',
340- 'properties': {
341-- 'enable': {
342-- 'type': 'array',
343-- 'items': {'type': 'string'},
344-- },
345-- 'token': {
346-- 'type': 'string',
347-- 'description': (
348-- 'A contract token obtained from %s.' % UA_URL)
349-+ 'commands': {
350-+ 'type': ['object', 'array'], # Array of strings or dict
351-+ 'items': {
352-+ 'oneOf': [
353-+ {'type': 'array', 'items': {'type': 'string'}},
354-+ {'type': 'string'}]
355-+ },
356-+ 'additionalItems': False, # Reject non-string & non-list
357-+ 'minItems': 1,
358-+ 'minProperties': 1,
359- }
360- },
361-- 'required': ['token'],
362-- 'additionalProperties': False
363-+ 'additionalProperties': False, # Reject keys not in schema
364-+ 'required': ['commands']
365- }
366- }
367- }
368-
369-+# TODO schema for 'assertions' and 'commands' are too permissive at the moment.
370-+# Once python-jsonschema supports schema draft 6 add support for arbitrary
371-+# object keys with 'patternProperties' constraint to validate string values.
372-+
373- __doc__ = get_schema_doc(schema) # Supplement python help()
374-
375--LOG = logging.getLogger(__name__)
376-+UA_CMD = "ubuntu-advantage"
377-
378-
379--def configure_ua(token=None, enable=None):
380-- """Call ua commandline client to attach or enable services."""
381-- error = None
382-- if not token:
383-- error = ('ubuntu_advantage: token must be provided')
384-- LOG.error(error)
385-- raise RuntimeError(error)
386--
387-- if enable is None:
388-- enable = []
389-- elif isinstance(enable, six.string_types):
390-- LOG.warning('ubuntu_advantage: enable should be a list, not'
391-- ' a string; treating as a single enable')
392-- enable = [enable]
393-- elif not isinstance(enable, list):
394-- LOG.warning('ubuntu_advantage: enable should be a list, not'
395-- ' a %s; skipping enabling services',
396-- type(enable).__name__)
397-- enable = []
398-+def run_commands(commands):
399-+ """Run the commands provided in ubuntu-advantage:commands config.
400-
401-- attach_cmd = ['ua', 'attach', token]
402-- LOG.debug('Attaching to Ubuntu Advantage. %s', ' '.join(attach_cmd))
403-- try:
404-- util.subp(attach_cmd)
405-- except util.ProcessExecutionError as e:
406-- msg = 'Failure attaching Ubuntu Advantage:\n{error}'.format(
407-- error=str(e))
408-- util.logexc(LOG, msg)
409-- raise RuntimeError(msg)
410-- enable_errors = []
411-- for service in enable:
412-+ Commands are run individually. Any errors are collected and reported
413-+ after attempting all commands.
414-+
415-+ @param commands: A list or dict containing commands to run. Keys of a
416-+ dict will be used to order the commands provided as dict values.
417-+ """
418-+ if not commands:
419-+ return
420-+ LOG.debug('Running user-provided ubuntu-advantage commands')
421-+ if isinstance(commands, dict):
422-+ # Sort commands based on dictionary key
423-+ commands = [v for _, v in sorted(commands.items())]
424-+ elif not isinstance(commands, list):
425-+ raise TypeError(
426-+ 'commands parameter was not a list or dict: {commands}'.format(
427-+ commands=commands))
428-+
429-+ fixed_ua_commands = prepend_base_command('ubuntu-advantage', commands)
430-+
431-+ cmd_failures = []
432-+ for command in fixed_ua_commands:
433-+ shell = isinstance(command, str)
434- try:
435-- cmd = ['ua', 'enable', service]
436-- util.subp(cmd, capture=True)
437-+ util.subp(command, shell=shell, status_cb=sys.stderr.write)
438- except util.ProcessExecutionError as e:
439-- enable_errors.append((service, e))
440-- if enable_errors:
441-- for service, error in enable_errors:
442-- msg = 'Failure enabling "{service}":\n{error}'.format(
443-- service=service, error=str(error))
444-- util.logexc(LOG, msg)
445-- raise RuntimeError(
446-- 'Failure enabling Ubuntu Advantage service(s): {}'.format(
447-- ', '.join('"{}"'.format(service)
448-- for service, _ in enable_errors)))
449-+ cmd_failures.append(str(e))
450-+ if cmd_failures:
451-+ msg = (
452-+ 'Failures running ubuntu-advantage commands:\n'
453-+ '{cmd_failures}'.format(
454-+ cmd_failures=cmd_failures))
455-+ util.logexc(LOG, msg)
456-+ raise RuntimeError(msg)
457-
458-
459- def maybe_install_ua_tools(cloud):
460- """Install ubuntu-advantage-tools if not present."""
461-- if util.which('ua'):
462-+ if util.which('ubuntu-advantage'):
463- return
464- try:
465- cloud.distro.update_package_sources()
466-@@ -152,28 +159,14 @@ def maybe_install_ua_tools(cloud):
467+--- a/cloudinit/config/cc_ubuntu_advantage.py
468++++ b/cloudinit/config/cc_ubuntu_advantage.py
469+@@ -152,28 +152,14 @@ def maybe_install_ua_tools(cloud):
470
471
472 def handle(name, cfg, cloud, log, args):
473@@ -294,10 +46,8 @@ Index: cloud-init/cloudinit/config/cc_ubuntu_advantage.py
474 + run_commands(cfgin.get('commands', []))
475
476 # vi: ts=4 expandtab
477-Index: cloud-init/cloudinit/config/tests/test_ubuntu_advantage.py
478-===================================================================
479---- cloud-init.orig/cloudinit/config/tests/test_ubuntu_advantage.py
480-+++ cloud-init/cloudinit/config/tests/test_ubuntu_advantage.py
481+--- a/cloudinit/config/tests/test_ubuntu_advantage.py
482++++ b/cloudinit/config/tests/test_ubuntu_advantage.py
483 @@ -1,7 +1,10 @@
484 # This file is part of cloud-init. See LICENSE file for license information.
485
486diff --git a/tests/unittests/test_datasource/test_azure.py b/tests/unittests/test_datasource/test_azure.py
487index 427ab7e..afb614e 100644
488--- a/tests/unittests/test_datasource/test_azure.py
489+++ b/tests/unittests/test_datasource/test_azure.py
490@@ -6,7 +6,6 @@ from cloudinit import url_helper
491 from cloudinit.sources import (
492 UNSET, DataSourceAzure as dsaz, InvalidMetaDataException)
493 from cloudinit.util import (b64e, decode_binary, load_file, write_file,
494- find_freebsd_part, get_path_dev_freebsd,
495 MountFailedError, json_dumps, load_json)
496 from cloudinit.version import version_string as vs
497 from cloudinit.tests.helpers import (
498@@ -391,29 +390,6 @@ scbus-1 on xpt0 bus 0
499 dev = ds.get_resource_disk_on_freebsd(1)
500 self.assertEqual("da1", dev)
501
502- @mock.patch('cloudinit.util.subp')
503- def test_find_freebsd_part_on_Azure(self, mock_subp):
504- glabel_out = '''
505-gptid/fa52d426-c337-11e6-8911-00155d4c5e47 N/A da0p1
506- label/rootfs N/A da0p2
507- label/swap N/A da0p3
508-'''
509- mock_subp.return_value = (glabel_out, "")
510- res = find_freebsd_part("/dev/label/rootfs")
511- self.assertEqual("da0p2", res)
512-
513- def test_get_path_dev_freebsd_on_Azure(self):
514- mnt_list = '''
515-/dev/label/rootfs / ufs rw 1 1
516-devfs /dev devfs rw,multilabel 0 0
517-fdescfs /dev/fd fdescfs rw 0 0
518-/dev/da1s1 /mnt/resource ufs rw 2 2
519-'''
520- with mock.patch.object(os.path, 'exists',
521- return_value=True):
522- res = get_path_dev_freebsd('/etc', mnt_list)
523- self.assertIsNotNone(res)
524-
525 @mock.patch(MOCKPATH + '_is_platform_viable')
526 def test_call_is_platform_viable_seed(self, m_is_platform_viable):
527 """Check seed_dir using _is_platform_viable and return False."""
528diff --git a/tests/unittests/test_datasource/test_nocloud.py b/tests/unittests/test_datasource/test_nocloud.py
529index b785362..18bea0b 100644
530--- a/tests/unittests/test_datasource/test_nocloud.py
531+++ b/tests/unittests/test_datasource/test_nocloud.py
532@@ -278,6 +278,24 @@ class TestNoCloudDataSource(CiTestCase):
533 self.assertEqual(netconf, dsrc.network_config)
534 self.assertNotIn(gateway, str(dsrc.network_config))
535
536+ @mock.patch("cloudinit.util.blkid")
537+ def test_nocloud_get_devices_freebsd(self, m_is_lxd, fake_blkid):
538+ populate_dir(os.path.join(self.paths.seed_dir, "nocloud"),
539+ {'user-data': b"ud", 'meta-data': "instance-id: IID\n"})
540+
541+ sys_cfg = {'datasource': {'NoCloud': {'fs_label': None}}}
542+
543+ self.mocks.enter_context(
544+ mock.patch.object(util, 'is_FreeBSD', return_value=True))
545+
546+ self.mocks.enter_context(
547+ mock.patch.object(os.path, 'exists', return_value=True))
548+
549+ dsrc = dsNoCloud(sys_cfg=sys_cfg, distro=None, paths=self.paths)
550+ ret = dsrc._get_devices('foo')
551+ self.assertEqual(['/dev/msdosfs/foo', '/dev/iso9660/foo'], ret)
552+ fake_blkid.assert_not_called()
553+
554
555 class TestParseCommandLineData(CiTestCase):
556
557diff --git a/tests/unittests/test_distros/test_freebsd.py b/tests/unittests/test_distros/test_freebsd.py
558new file mode 100644
559index 0000000..8af253a
560--- /dev/null
561+++ b/tests/unittests/test_distros/test_freebsd.py
562@@ -0,0 +1,45 @@
563+# This file is part of cloud-init. See LICENSE file for license information.
564+
565+from cloudinit.util import (find_freebsd_part, get_path_dev_freebsd)
566+from cloudinit.tests.helpers import (CiTestCase, mock)
567+
568+import os
569+
570+
571+class TestDeviceLookUp(CiTestCase):
572+
573+ @mock.patch('cloudinit.util.subp')
574+ def test_find_freebsd_part_label(self, mock_subp):
575+ glabel_out = '''
576+gptid/fa52d426-c337-11e6-8911-00155d4c5e47 N/A da0p1
577+ label/rootfs N/A da0p2
578+ label/swap N/A da0p3
579+'''
580+ mock_subp.return_value = (glabel_out, "")
581+ res = find_freebsd_part("/dev/label/rootfs")
582+ self.assertEqual("da0p2", res)
583+
584+ @mock.patch('cloudinit.util.subp')
585+ def test_find_freebsd_part_gpt(self, mock_subp):
586+ glabel_out = '''
587+ gpt/bootfs N/A vtbd0p1
588+gptid/3f4cbe26-75da-11e8-a8f2-002590ec6166 N/A vtbd0p1
589+ gpt/swapfs N/A vtbd0p2
590+ gpt/rootfs N/A vtbd0p3
591+ iso9660/cidata N/A vtbd2
592+'''
593+ mock_subp.return_value = (glabel_out, "")
594+ res = find_freebsd_part("/dev/gpt/rootfs")
595+ self.assertEqual("vtbd0p3", res)
596+
597+ def test_get_path_dev_freebsd_label(self):
598+ mnt_list = '''
599+/dev/label/rootfs / ufs rw 1 1
600+devfs /dev devfs rw,multilabel 0 0
601+fdescfs /dev/fd fdescfs rw 0 0
602+/dev/da1s1 /mnt/resource ufs rw 2 2
603+'''
604+ with mock.patch.object(os.path, 'exists',
605+ return_value=True):
606+ res = get_path_dev_freebsd('/etc', mnt_list)
607+ self.assertIsNotNone(res)
608diff --git a/tests/unittests/test_ds_identify.py b/tests/unittests/test_ds_identify.py
609index 8c18aa1..7575223 100644
610--- a/tests/unittests/test_ds_identify.py
611+++ b/tests/unittests/test_ds_identify.py
612@@ -435,6 +435,14 @@ class TestDsIdentify(DsIdentifyBase):
613 """Open Telecom identification."""
614 self._test_ds_found('OpenStack-OpenTelekom')
615
616+ def test_openstack_asset_tag_nova(self):
617+ """OpenStack identification via asset tag OpenStack Nova."""
618+ self._test_ds_found('OpenStack-AssetTag-Nova')
619+
620+ def test_openstack_asset_tag_copute(self):
621+ """OpenStack identification via asset tag OpenStack Compute."""
622+ self._test_ds_found('OpenStack-AssetTag-Compute')
623+
624 def test_openstack_on_non_intel_is_maybe(self):
625 """On non-Intel, openstack without dmi info is maybe.
626
627@@ -759,6 +767,18 @@ VALID_CFG = {
628 'files': {P_CHASSIS_ASSET_TAG: 'OpenTelekomCloud\n'},
629 'mocks': [MOCK_VIRT_IS_XEN],
630 },
631+ 'OpenStack-AssetTag-Nova': {
632+ # VMware vSphere can't modify product-name, LP: #1669875
633+ 'ds': 'OpenStack',
634+ 'files': {P_CHASSIS_ASSET_TAG: 'OpenStack Nova\n'},
635+ 'mocks': [MOCK_VIRT_IS_XEN],
636+ },
637+ 'OpenStack-AssetTag-Compute': {
638+ # VMware vSphere can't modify product-name, LP: #1669875
639+ 'ds': 'OpenStack',
640+ 'files': {P_CHASSIS_ASSET_TAG: 'OpenStack Compute\n'},
641+ 'mocks': [MOCK_VIRT_IS_XEN],
642+ },
643 'OVF-seed': {
644 'ds': 'OVF',
645 'files': {
646diff --git a/tests/unittests/test_handler/test_handler_resizefs.py b/tests/unittests/test_handler/test_handler_resizefs.py
647index 3518784..db9a041 100644
648--- a/tests/unittests/test_handler/test_handler_resizefs.py
649+++ b/tests/unittests/test_handler/test_handler_resizefs.py
650@@ -147,7 +147,7 @@ class TestResizefs(CiTestCase):
651 def test_resize_ufs_cmd_return(self):
652 mount_point = '/'
653 devpth = '/dev/sda2'
654- self.assertEqual(('growfs', '-y', devpth),
655+ self.assertEqual(('growfs', '-y', mount_point),
656 _resize_ufs(mount_point, devpth))
657
658 @mock.patch('cloudinit.util.is_container', return_value=False)
659diff --git a/tests/unittests/test_net.py b/tests/unittests/test_net.py
660index e85e964..b936bc9 100644
661--- a/tests/unittests/test_net.py
662+++ b/tests/unittests/test_net.py
663@@ -407,6 +407,37 @@ network:
664 - maas
665 """
666
667+NETPLAN_BOND_GRAT_ARP = """
668+network:
669+ bonds:
670+ bond0:
671+ interfaces:
672+ - ens3
673+ macaddress: 68:05:ca:64:d3:6c
674+ mtu: 9000
675+ parameters:
676+ gratuitious-arp: 1
677+ bond1:
678+ interfaces:
679+ - ens4
680+ macaddress: 68:05:ca:64:d3:6d
681+ mtu: 9000
682+ parameters:
683+ gratuitous-arp: 2
684+ ethernets:
685+ ens3:
686+ dhcp4: false
687+ dhcp6: false
688+ match:
689+ macaddress: 52:54:00:ab:cd:ef
690+ ens4:
691+ dhcp4: false
692+ dhcp6: false
693+ match:
694+ macaddress: 52:54:00:11:22:ff
695+ version: 2
696+"""
697+
698 NETPLAN_DHCP_FALSE = """
699 version: 2
700 ethernets:
701@@ -3589,6 +3620,21 @@ class TestNetplanRoundTrip(CiTestCase):
702 entry['expected_netplan'].splitlines(),
703 files['/etc/netplan/50-cloud-init.yaml'].splitlines())
704
705+ def test_render_output_supports_both_grat_arp_spelling(self):
706+ entry = {
707+ 'yaml': NETPLAN_BOND_GRAT_ARP,
708+ 'expected_netplan': NETPLAN_BOND_GRAT_ARP.replace('gratuitous',
709+ 'gratuitious'),
710+ }
711+ network_config = yaml.load(entry['yaml']).get('network')
712+ files = self._render_and_read(network_config=network_config)
713+ print(entry['expected_netplan'])
714+ print('-- expected ^ | v rendered --')
715+ print(files['/etc/netplan/50-cloud-init.yaml'])
716+ self.assertEqual(
717+ entry['expected_netplan'].splitlines(),
718+ files['/etc/netplan/50-cloud-init.yaml'].splitlines())
719+
720
721 class TestEniRoundTrip(CiTestCase):
722
723diff --git a/tools/ds-identify b/tools/ds-identify
724index 6518901..e16708f 100755
725--- a/tools/ds-identify
726+++ b/tools/ds-identify
727@@ -979,6 +979,14 @@ dscheck_OpenStack() {
728 return ${DS_FOUND}
729 fi
730
731+ # LP: #1669875 : allow identification of OpenStack by asset tag
732+ if dmi_chassis_asset_tag_matches "$nova"; then
733+ return ${DS_FOUND}
734+ fi
735+ if dmi_chassis_asset_tag_matches "$compute"; then
736+ return ${DS_FOUND}
737+ fi
738+
739 # LP: #1715241 : arch other than intel are not identified properly.
740 case "$DI_UNAME_MACHINE" in
741 i?86|x86_64) :;;
742diff --git a/tools/render-cloudcfg b/tools/render-cloudcfg
743index 8b7cb87..0957c32 100755
744--- a/tools/render-cloudcfg
745+++ b/tools/render-cloudcfg
746@@ -4,7 +4,7 @@ import argparse
747 import os
748 import sys
749
750-VARIANTS = ["bsd", "centos", "fedora", "rhel", "suse", "ubuntu", "unknown"]
751+VARIANTS = ["freebsd", "centos", "fedora", "rhel", "suse", "ubuntu", "unknown"]
752
753 if "avoid-pep8-E402-import-not-top-of-file":
754 _tdir = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
755diff --git a/tools/run-container b/tools/run-container
756index 852f4d1..1d24e15 100755
757--- a/tools/run-container
758+++ b/tools/run-container
759@@ -373,7 +373,7 @@ wait_for_boot() {
760 inside "$name" sh -c "echo proxy=$http_proxy >> /etc/yum.conf"
761 inside "$name" sed -i s/enabled=1/enabled=0/ \
762 /etc/yum/pluginconf.d/fastestmirror.conf
763- inside "$name" sh -c "sed -i '/^#baseurl=/s/#//' /etc/yum.repos.d/*.repo"
764+ inside "$name" sh -c "sed -i '/^#baseurl=/s/#// ; s/^mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo"
765 else
766 debug 1 "do not know how to configure proxy on $OS_NAME"
767 fi

Subscribers

People subscribed via source and target branches