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

Proposed by Chad Smith
Status: Merged
Merged at revision: 10ab9a7c231b6f7d01da3a3a4c08cf4db01f5a87
Proposed branch: ~chad.smith/cloud-init:ubuntu/devel
Merge into: cloud-init:ubuntu/devel
Diff against target: 574 lines (+317/-15)
16 files modified
ChangeLog (+58/-0)
cloudinit/config/cc_puppet.py (+3/-0)
cloudinit/config/cc_resizefs.py (+22/-0)
cloudinit/settings.py (+1/-0)
cloudinit/sources/DataSourceHetzner.py (+6/-0)
cloudinit/util.py (+35/-9)
cloudinit/version.py (+1/-1)
debian/changelog (+11/-2)
packages/debian/control.in (+2/-1)
tests/data/mount_parse_ext.txt (+19/-0)
tests/data/mount_parse_zfs.txt (+21/-0)
tests/data/zpool_status_simple.txt (+10/-0)
tests/unittests/test_datasource/test_common.py (+2/-0)
tests/unittests/test_datasource/test_hetzner.py (+19/-1)
tests/unittests/test_handler/test_handler_resizefs.py (+57/-1)
tests/unittests/test_util.py (+50/-0)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Scott Moser Pending
Review via email: mp+342239@code.launchpad.net

Commit message

Sync upstream 18.2 release to Bionic for publish.

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:10ab9a7c231b6f7d01da3a3a4c08cf4db01f5a87
https://jenkins.ubuntu.com/server/job/cloud-init-ci/940/
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/940/rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/ChangeLog b/ChangeLog
index be4c357..daa7ccf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,61 @@
118.2:
2 - Hetzner: Exit early if dmi system-manufacturer is not Hetzner.
3 - Add missing dependency on isc-dhcp-client to trunk ubuntu packaging.
4 (LP: #1759307)
5 - FreeBSD: resizefs module now able to handle zfs/zpool.
6 [Dominic Schlegel] (LP: #1721243)
7 - cc_puppet: Revert regression of puppet creating ssl and ssl_cert dirs
8 - Enable IBMCloud datasource in settings.py.
9 - IBMCloud: Initial IBM Cloud datasource.
10 - tests: remove jsonschema from xenial tox environment.
11 - tests: Fix newly added schema unit tests to skip if no jsonschema.
12 - ec2: Adjust ec2 datasource after exception_cb change.
13 - Reduce AzurePreprovisioning HTTP timeouts.
14 [Douglas Jordan] (LP: #1752977)
15 - Revert the logic of exception_cb in read_url.
16 [Kurt Garloff] (LP: #1702160, #1298921)
17 - ubuntu-advantage: Add new config module to support
18 ubuntu-advantage-tools
19 - Handle global dns entries in netplan (LP: #1750884)
20 - Identify OpenTelekomCloud Xen as OpenStack DS.
21 [Kurt Garloff] (LP: #1756471)
22 - datasources: fix DataSource subclass get_hostname method signature
23 (LP: #1757176)
24 - OpenNebula: Update network to return v2 config rather than ENI.
25 [Akihiko Ota]
26 - Add Hetzner Cloud DataSource
27 - net: recognize iscsi root cases without ip= on kernel command line.
28 (LP: #1752391)
29 - tests: fix flakes warning for unused variable
30 - tests: patch leaked stderr messages from snap unit tests
31 - cc_snap: Add new module to install and configure snapd and snap
32 packages.
33 - tests: Make pylint happy and fix python2.6 uses of assertRaisesRegex.
34 - netplan: render bridge port-priority values (LP: #1735821)
35 - util: Fix subp regression. Allow specifying subp command as a string.
36 (LP: #1755965)
37 - doc: fix all warnings issued by 'tox -e doc'
38 - FreeBSD: Set hostname to FQDN. [Dominic Schlegel] (LP: #1753499)
39 - tests: fix run_tree and bddeb
40 - tests: Fix some warnings in tests that popped up with newer python.
41 - set_hostname: When present in metadata, set it before network bringup.
42 (LP: #1746455)
43 - tests: Centralize and re-use skipTest based on json schema presense.
44 - This commit fixes get_hostname on the AzureDataSource.
45 [Douglas Jordan] (LP: #1754495)
46 - shellify: raise TypeError on bad input.
47 - Make salt minion module work on FreeBSD.
48 [Dominic Schlegel] (LP: #1721503)
49 - Simplify some comparisions. [Rémy Léone]
50 - Change some list creation and population to literal. [Rémy Léone]
51 - GCE: fix reading of user-data that is not base64 encoded. (LP: #1752711)
52 - doc: fix chef install from apt packages example in RTD.
53 - Implement puppet 4 support [Romanos Skiadas] (LP: #1446804)
54 - subp: Fix subp usage with non-ascii characters when no system locale.
55 (LP: #1751051)
56 - salt: configure grains in grains file rather than in minion config.
57 [Daniel Wallace]
58
118.1:5918.1:
2 - OVF: Fix VMware support for 64-bit platforms. [Sankar Tanguturi]60 - OVF: Fix VMware support for 64-bit platforms. [Sankar Tanguturi]
3 - ds-identify: Fix searching for iso9660 OVF cdroms. (LP: #1749980)61 - ds-identify: Fix searching for iso9660 OVF cdroms. (LP: #1749980)
diff --git a/cloudinit/config/cc_puppet.py b/cloudinit/config/cc_puppet.py
index 297e072..4190a20 100644
--- a/cloudinit/config/cc_puppet.py
+++ b/cloudinit/config/cc_puppet.py
@@ -140,6 +140,7 @@ def handle(name, cfg, cloud, log, _args):
140 # (TODO(harlowja) is this really needed??)140 # (TODO(harlowja) is this really needed??)
141 cleaned_lines = [i.lstrip() for i in contents.splitlines()]141 cleaned_lines = [i.lstrip() for i in contents.splitlines()]
142 cleaned_contents = '\n'.join(cleaned_lines)142 cleaned_contents = '\n'.join(cleaned_lines)
143 # Move to puppet_config.read_file when dropping py2.7
143 puppet_config.readfp( # pylint: disable=W1505144 puppet_config.readfp( # pylint: disable=W1505
144 StringIO(cleaned_contents),145 StringIO(cleaned_contents),
145 filename=p_constants.conf_path)146 filename=p_constants.conf_path)
@@ -150,6 +151,8 @@ def handle(name, cfg, cloud, log, _args):
150 # Puppet ssl sub-directory isn't created yet151 # Puppet ssl sub-directory isn't created yet
151 # Create it with the proper permissions and ownership152 # Create it with the proper permissions and ownership
152 util.ensure_dir(p_constants.ssl_dir, 0o771)153 util.ensure_dir(p_constants.ssl_dir, 0o771)
154 util.chownbyname(p_constants.ssl_dir, 'puppet', 'root')
155 util.ensure_dir(p_constants.ssl_cert_dir)
153156
154 util.chownbyname(p_constants.ssl_cert_dir, 'puppet', 'root')157 util.chownbyname(p_constants.ssl_cert_dir, 'puppet', 'root')
155 util.write_file(p_constants.ssl_cert_path, cfg)158 util.write_file(p_constants.ssl_cert_path, cfg)
diff --git a/cloudinit/config/cc_resizefs.py b/cloudinit/config/cc_resizefs.py
index cec22bb..c8e1752 100644
--- a/cloudinit/config/cc_resizefs.py
+++ b/cloudinit/config/cc_resizefs.py
@@ -84,6 +84,10 @@ def _resize_ufs(mount_point, devpth):
84 return ('growfs', devpth)84 return ('growfs', devpth)
8585
8686
87def _resize_zfs(mount_point, devpth):
88 return ('zpool', 'online', '-e', mount_point, devpth)
89
90
87def _get_dumpfs_output(mount_point):91def _get_dumpfs_output(mount_point):
88 dumpfs_res, err = util.subp(['dumpfs', '-m', mount_point])92 dumpfs_res, err = util.subp(['dumpfs', '-m', mount_point])
89 return dumpfs_res93 return dumpfs_res
@@ -148,6 +152,7 @@ RESIZE_FS_PREFIXES_CMDS = [
148 ('ext', _resize_ext),152 ('ext', _resize_ext),
149 ('xfs', _resize_xfs),153 ('xfs', _resize_xfs),
150 ('ufs', _resize_ufs),154 ('ufs', _resize_ufs),
155 ('zfs', _resize_zfs),
151]156]
152157
153RESIZE_FS_PRECHECK_CMDS = {158RESIZE_FS_PRECHECK_CMDS = {
@@ -188,6 +193,13 @@ def maybe_get_writable_device_path(devpath, info, log):
188 log.debug("Not attempting to resize devpath '%s': %s", devpath, info)193 log.debug("Not attempting to resize devpath '%s': %s", devpath, info)
189 return None194 return None
190195
196 # FreeBSD zpool can also just use gpt/<label>
197 # with that in mind we can not do an os.stat on "gpt/whatever"
198 # therefore return the devpath already here.
199 if devpath.startswith('gpt/'):
200 log.debug('We have a gpt label - just go ahead')
201 return devpath
202
191 try:203 try:
192 statret = os.stat(devpath)204 statret = os.stat(devpath)
193 except OSError as exc:205 except OSError as exc:
@@ -231,6 +243,16 @@ def handle(name, cfg, _cloud, log, args):
231243
232 (devpth, fs_type, mount_point) = result244 (devpth, fs_type, mount_point) = result
233245
246 # if we have a zfs then our device path at this point
247 # is the zfs label. For example: vmzroot/ROOT/freebsd
248 # we will have to get the zpool name out of this
249 # and set the resize_what variable to the zpool
250 # so the _resize_zfs function gets the right attribute.
251 if fs_type == 'zfs':
252 zpool = devpth.split('/')[0]
253 devpth = util.get_device_info_from_zpool(zpool)
254 resize_what = zpool
255
234 info = "dev=%s mnt_point=%s path=%s" % (devpth, mount_point, resize_what)256 info = "dev=%s mnt_point=%s path=%s" % (devpth, mount_point, resize_what)
235 log.debug("resize_info: %s" % info)257 log.debug("resize_info: %s" % info)
236258
diff --git a/cloudinit/settings.py b/cloudinit/settings.py
index 5fe749d..dde5749 100644
--- a/cloudinit/settings.py
+++ b/cloudinit/settings.py
@@ -37,6 +37,7 @@ CFG_BUILTIN = {
37 'Bigstep',37 'Bigstep',
38 'Scaleway',38 'Scaleway',
39 'Hetzner',39 'Hetzner',
40 'IBMCloud',
40 # At the end to act as a 'catch' when none of the above work...41 # At the end to act as a 'catch' when none of the above work...
41 'None',42 'None',
42 ],43 ],
diff --git a/cloudinit/sources/DataSourceHetzner.py b/cloudinit/sources/DataSourceHetzner.py
index 769fe13..5c75b65 100644
--- a/cloudinit/sources/DataSourceHetzner.py
+++ b/cloudinit/sources/DataSourceHetzner.py
@@ -44,6 +44,8 @@ class DataSourceHetzner(sources.DataSource):
44 self.dsmode = sources.DSMODE_NETWORK44 self.dsmode = sources.DSMODE_NETWORK
4545
46 def get_data(self):46 def get_data(self):
47 if not on_hetzner():
48 return False
47 nic = cloudnet.find_fallback_nic()49 nic = cloudnet.find_fallback_nic()
48 with cloudnet.EphemeralIPv4Network(nic, "169.254.0.1", 16,50 with cloudnet.EphemeralIPv4Network(nic, "169.254.0.1", 16,
49 "169.254.255.255"):51 "169.254.255.255"):
@@ -87,6 +89,10 @@ class DataSourceHetzner(sources.DataSource):
87 return self._network_config89 return self._network_config
8890
8991
92def on_hetzner():
93 return util.read_dmi_data('system-manufacturer') == "Hetzner"
94
95
90# Used to match classes to dependencies96# Used to match classes to dependencies
91datasources = [97datasources = [
92 (DataSourceHetzner, (sources.DEP_FILESYSTEM, )),98 (DataSourceHetzner, (sources.DEP_FILESYSTEM, )),
diff --git a/cloudinit/util.py b/cloudinit/util.py
index fb4ee5f..0ab2c48 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -2234,7 +2234,7 @@ def get_path_dev_freebsd(path, mnt_list):
2234 return path_found2234 return path_found
22352235
22362236
2237def get_mount_info_freebsd(path, log=LOG):2237def get_mount_info_freebsd(path):
2238 (result, err) = subp(['mount', '-p', path], rcs=[0, 1])2238 (result, err) = subp(['mount', '-p', path], rcs=[0, 1])
2239 if len(err):2239 if len(err):
2240 # find a path if the input is not a mounting point2240 # find a path if the input is not a mounting point
@@ -2248,23 +2248,49 @@ def get_mount_info_freebsd(path, log=LOG):
2248 return "/dev/" + label_part, ret[2], ret[1]2248 return "/dev/" + label_part, ret[2], ret[1]
22492249
22502250
2251def get_device_info_from_zpool(zpool):
2252 (zpoolstatus, err) = subp(['zpool', 'status', zpool])
2253 if len(err):
2254 return None
2255 r = r'.*(ONLINE).*'
2256 for line in zpoolstatus.split("\n"):
2257 if re.search(r, line) and zpool not in line and "state" not in line:
2258 disk = line.split()[0]
2259 LOG.debug('found zpool "%s" on disk %s', zpool, disk)
2260 return disk
2261
2262
2251def parse_mount(path):2263def parse_mount(path):
2252 (mountoutput, _err) = subp("mount")2264 (mountoutput, _err) = subp(['mount'])
2253 mount_locs = mountoutput.splitlines()2265 mount_locs = mountoutput.splitlines()
2266 # there are 2 types of mount outputs we have to parse therefore
2267 # the regex is a bit complex. to better understand this regex see:
2268 # https://regex101.com/r/2F6c1k/1
2269 # https://regex101.com/r/T2en7a/1
2270 regex = r'^(/dev/[\S]+|.*zroot\S*?) on (/[\S]*) ' + \
2271 '(?=(?:type)[\s]+([\S]+)|\(([^,]*))'
2254 for line in mount_locs:2272 for line in mount_locs:
2255 m = re.search(r'^(/dev/[\S]+) on (/.*) \((.+), .+, (.+)\)$', line)2273 m = re.search(regex, line)
2256 if not m:2274 if not m:
2257 continue2275 continue
2276 devpth = m.group(1)
2277 mount_point = m.group(2)
2278 # above regex will either fill the fs_type in group(3)
2279 # or group(4) depending on the format we have.
2280 fs_type = m.group(3)
2281 if fs_type is None:
2282 fs_type = m.group(4)
2283 LOG.debug('found line in mount -> devpth: %s, mount_point: %s, '
2284 'fs_type: %s', devpth, mount_point, fs_type)
2258 # check whether the dev refers to a label on FreeBSD2285 # check whether the dev refers to a label on FreeBSD
2259 # for example, if dev is '/dev/label/rootfs', we should2286 # for example, if dev is '/dev/label/rootfs', we should
2260 # continue finding the real device like '/dev/da0'.2287 # continue finding the real device like '/dev/da0'.
2261 devm = re.search('^(/dev/.+)p([0-9])$', m.group(1))2288 # this is only valid for non zfs file systems as a zpool
2262 if (not devm and is_FreeBSD()):2289 # can have gpt labels as disk.
2290 devm = re.search('^(/dev/.+)p([0-9])$', devpth)
2291 if not devm and is_FreeBSD() and fs_type != 'zfs':
2263 return get_mount_info_freebsd(path)2292 return get_mount_info_freebsd(path)
2264 devpth = m.group(1)2293 elif mount_point == path:
2265 mount_point = m.group(2)
2266 fs_type = m.group(3)
2267 if mount_point == path:
2268 return devpth, fs_type, mount_point2294 return devpth, fs_type, mount_point
2269 return None2295 return None
22702296
diff --git a/cloudinit/version.py b/cloudinit/version.py
index 4a682ad..ccd0f84 100644
--- a/cloudinit/version.py
+++ b/cloudinit/version.py
@@ -4,7 +4,7 @@
4#4#
5# This file is part of cloud-init. See LICENSE file for license information.5# This file is part of cloud-init. See LICENSE file for license information.
66
7__VERSION__ = "18.1"7__VERSION__ = "18.2"
88
9FEATURES = [9FEATURES = [
10 # supports network config version 110 # supports network config version 1
diff --git a/debian/changelog b/debian/changelog
index 6f022bb..cdfbf6a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,17 @@
1cloud-init (18.1-35-ge0f644b7-0ubuntu3) UNRELEASED; urgency=medium1cloud-init (18.2-0ubuntu1) bionic; urgency=medium
22
3 * debian/control: Add missing dependency on isc-dhcp-client (LP: #1759307).3 * debian/control: Add missing dependency on isc-dhcp-client (LP: #1759307).
4 * New upstream snapshot.
5 - release 18.2 (LP: #1759318)
6 - Hetzner: Exit early if dmi system-manufacturer is not Hetzner.
7 - Add missing dependency on isc-dhcp-client to trunk ubuntu packaging.
8 (LP: #1759307)
9 - FreeBSD: resizefs module now able to handle zfs/zpool.
10 [Dominic Schlegel] (LP: #1721243)
11 - cc_puppet: Revert regression of puppet creating ssl and ssl_cert dirs
12 - Enable IBMCloud datasource in settings.py.
413
5 -- Scott Moser <smoser@ubuntu.com> Tue, 27 Mar 2018 12:19:44 -040014 -- Chad Smith <chad.smith@canonical.com> Tue, 27 Mar 2018 14:59:58 -0600
615
7cloud-init (18.1-35-ge0f644b7-0ubuntu2) bionic; urgency=medium16cloud-init (18.1-35-ge0f644b7-0ubuntu2) bionic; urgency=medium
817
diff --git a/packages/debian/control.in b/packages/debian/control.in
index 265b261..46da6df 100644
--- a/packages/debian/control.in
+++ b/packages/debian/control.in
@@ -10,7 +10,8 @@ Standards-Version: 3.9.6
10Package: cloud-init10Package: cloud-init
11Architecture: all11Architecture: all
12Depends: ${misc:Depends},12Depends: ${misc:Depends},
13 ${${python}:Depends}13 ${${python}:Depends},
14 isc-dhcp-client
14Recommends: eatmydata, sudo, software-properties-common, gdisk15Recommends: eatmydata, sudo, software-properties-common, gdisk
15XB-Python-Version: ${python:Versions}16XB-Python-Version: ${python:Versions}
16Description: Init scripts for cloud instances17Description: Init scripts for cloud instances
diff --git a/tests/data/mount_parse_ext.txt b/tests/data/mount_parse_ext.txt
17new file mode 10064418new file mode 100644
index 0000000..da0c870
--- /dev/null
+++ b/tests/data/mount_parse_ext.txt
@@ -0,0 +1,19 @@
1/dev/mapper/vg00-lv_root on / type ext4 (rw,errors=remount-ro)
2proc on /proc type proc (rw,noexec,nosuid,nodev)
3sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
4none on /sys/fs/cgroup type tmpfs (rw)
5none on /sys/fs/fuse/connections type fusectl (rw)
6none on /sys/kernel/debug type debugfs (rw)
7none on /sys/kernel/security type securityfs (rw)
8udev on /dev type devtmpfs (rw,mode=0755)
9devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=0620)
10none on /tmp type tmpfs (rw)
11tmpfs on /run type tmpfs (rw,noexec,nosuid,size=10%,mode=0755)
12none on /run/lock type tmpfs (rw,noexec,nosuid,nodev,size=5242880)
13none on /run/shm type tmpfs (rw,nosuid,nodev)
14none on /run/user type tmpfs (rw,noexec,nosuid,nodev,size=104857600,mode=0755)
15none on /sys/fs/pstore type pstore (rw)
16/dev/mapper/vg00-lv_var on /var type ext4 (rw)
17rpc_pipefs on /run/rpc_pipefs type rpc_pipefs (rw)
18systemd on /sys/fs/cgroup/systemd type cgroup (rw,noexec,nosuid,nodev,none,name=systemd)
1910.0.1.1:/backup on /backup type nfs (rw,noexec,nosuid,nodev,bg,nolock,tcp,nfsvers=3,hard,addr=10.0.1.1)
0\ No newline at end of file20\ No newline at end of file
diff --git a/tests/data/mount_parse_zfs.txt b/tests/data/mount_parse_zfs.txt
1new file mode 10064421new file mode 100644
index 0000000..08af04f
--- /dev/null
+++ b/tests/data/mount_parse_zfs.txt
@@ -0,0 +1,21 @@
1vmzroot/ROOT/freebsd on / (zfs, local, nfsv4acls)
2devfs on /dev (devfs, local, multilabel)
3fdescfs on /dev/fd (fdescfs)
4vmzroot/root on /root (zfs, local, nfsv4acls)
5vmzroot/tmp on /tmp (zfs, local, nosuid, nfsv4acls)
6vmzroot/ROOT/freebsd/usr on /usr (zfs, local, nfsv4acls)
7vmzroot/ROOT/freebsd/usr/local on /usr/local (zfs, local, nfsv4acls)
8vmzroot/ROOT/freebsd/var on /var (zfs, local, nfsv4acls)
9vmzroot/ROOT/freebsd/var/cache on /var/cache (zfs, local, noexec, nosuid, nfsv4acls)
10vmzroot/ROOT/freebsd/var/crash on /var/crash (zfs, local, noexec, nosuid, nfsv4acls)
11vmzroot/var/cron on /var/cron (zfs, local, nosuid, nfsv4acls)
12vmzroot/ROOT/freebsd/var/db on /var/db (zfs, local, noatime, noexec, nosuid, nfsv4acls)
13vmzroot/ROOT/freebsd/var/empty on /var/empty (zfs, local, noexec, nosuid, read-only, nfsv4acls)
14vmzroot/var/log on /var/log (zfs, local, noexec, nosuid, nfsv4acls)
15vmzroot/var/log/pf on /var/log/pf (zfs, local, noexec, nosuid, nfsv4acls)
16vmzroot/var/mail on /var/mail (zfs, local, noexec, nosuid, nfsv4acls)
17vmzroot/ROOT/freebsd/var/run on /var/run (zfs, local, noexec, nosuid, nfsv4acls)
18vmzroot/var/spool on /var/spool (zfs, local, noexec, nosuid, nfsv4acls)
19vmzroot/var/tmp on /var/tmp (zfs, local, nosuid, nfsv4acls)
2010.0.0.1:/vol/test on /mnt/test (nfs, read-only)
2110.0.0.2:/vol/tes2 on /mnt/test2 (nfs, nosuid)
0\ No newline at end of file22\ No newline at end of file
diff --git a/tests/data/zpool_status_simple.txt b/tests/data/zpool_status_simple.txt
1new file mode 10064423new file mode 100644
index 0000000..a2c573a
--- /dev/null
+++ b/tests/data/zpool_status_simple.txt
@@ -0,0 +1,10 @@
1 pool: vmzroot
2 state: ONLINE
3 scan: none requested
4config:
5
6 NAME STATE READ WRITE CKSUM
7 vmzroot ONLINE 0 0 0
8 gpt/system ONLINE 0 0 0
9
10errors: No known data errors
0\ No newline at end of file11\ No newline at end of file
diff --git a/tests/unittests/test_datasource/test_common.py b/tests/unittests/test_datasource/test_common.py
index 6d2dc5b..ec33388 100644
--- a/tests/unittests/test_datasource/test_common.py
+++ b/tests/unittests/test_datasource/test_common.py
@@ -15,6 +15,7 @@ from cloudinit.sources import (
15 DataSourceEc2 as Ec2,15 DataSourceEc2 as Ec2,
16 DataSourceGCE as GCE,16 DataSourceGCE as GCE,
17 DataSourceHetzner as Hetzner,17 DataSourceHetzner as Hetzner,
18 DataSourceIBMCloud as IBMCloud,
18 DataSourceMAAS as MAAS,19 DataSourceMAAS as MAAS,
19 DataSourceNoCloud as NoCloud,20 DataSourceNoCloud as NoCloud,
20 DataSourceOpenNebula as OpenNebula,21 DataSourceOpenNebula as OpenNebula,
@@ -33,6 +34,7 @@ DEFAULT_LOCAL = [
33 ConfigDrive.DataSourceConfigDrive,34 ConfigDrive.DataSourceConfigDrive,
34 DigitalOcean.DataSourceDigitalOcean,35 DigitalOcean.DataSourceDigitalOcean,
35 Hetzner.DataSourceHetzner,36 Hetzner.DataSourceHetzner,
37 IBMCloud.DataSourceIBMCloud,
36 NoCloud.DataSourceNoCloud,38 NoCloud.DataSourceNoCloud,
37 OpenNebula.DataSourceOpenNebula,39 OpenNebula.DataSourceOpenNebula,
38 OVF.DataSourceOVF,40 OVF.DataSourceOVF,
diff --git a/tests/unittests/test_datasource/test_hetzner.py b/tests/unittests/test_datasource/test_hetzner.py
index f1d1525..a9c1259 100644
--- a/tests/unittests/test_datasource/test_hetzner.py
+++ b/tests/unittests/test_datasource/test_hetzner.py
@@ -73,7 +73,10 @@ class TestDataSourceHetzner(CiTestCase):
73 @mock.patch('cloudinit.net.find_fallback_nic')73 @mock.patch('cloudinit.net.find_fallback_nic')
74 @mock.patch('cloudinit.sources.helpers.hetzner.read_metadata')74 @mock.patch('cloudinit.sources.helpers.hetzner.read_metadata')
75 @mock.patch('cloudinit.sources.helpers.hetzner.read_userdata')75 @mock.patch('cloudinit.sources.helpers.hetzner.read_userdata')
76 def test_read_data(self, m_usermd, m_readmd, m_fallback_nic, m_net):76 @mock.patch('cloudinit.sources.DataSourceHetzner.on_hetzner')
77 def test_read_data(self, m_on_hetzner, m_usermd, m_readmd, m_fallback_nic,
78 m_net):
79 m_on_hetzner.return_value = True
77 m_readmd.return_value = METADATA.copy()80 m_readmd.return_value = METADATA.copy()
78 m_usermd.return_value = USERDATA81 m_usermd.return_value = USERDATA
79 m_fallback_nic.return_value = 'eth0'82 m_fallback_nic.return_value = 'eth0'
@@ -97,3 +100,18 @@ class TestDataSourceHetzner(CiTestCase):
97 self.assertIsInstance(ds.get_public_ssh_keys(), list)100 self.assertIsInstance(ds.get_public_ssh_keys(), list)
98 self.assertEqual(ds.get_userdata_raw(), USERDATA)101 self.assertEqual(ds.get_userdata_raw(), USERDATA)
99 self.assertEqual(ds.get_vendordata_raw(), METADATA.get('vendor_data'))102 self.assertEqual(ds.get_vendordata_raw(), METADATA.get('vendor_data'))
103
104 @mock.patch('cloudinit.sources.helpers.hetzner.read_metadata')
105 @mock.patch('cloudinit.net.find_fallback_nic')
106 @mock.patch('cloudinit.sources.DataSourceHetzner.on_hetzner')
107 def test_not_on_hetzner_returns_false(self, m_on_hetzner, m_find_fallback,
108 m_read_md):
109 """If helper 'on_hetzner' returns False, return False from get_data."""
110 m_on_hetzner.return_value = False
111 ds = self.get_ds()
112 ret = ds.get_data()
113
114 self.assertFalse(ret)
115 # These are a white box attempt to ensure it did not search.
116 m_find_fallback.assert_not_called()
117 m_read_md.assert_not_called()
diff --git a/tests/unittests/test_handler/test_handler_resizefs.py b/tests/unittests/test_handler/test_handler_resizefs.py
index c2a7f9f..7a7ba1f 100644
--- a/tests/unittests/test_handler/test_handler_resizefs.py
+++ b/tests/unittests/test_handler/test_handler_resizefs.py
@@ -1,7 +1,8 @@
1# This file is part of cloud-init. See LICENSE file for license information.1# This file is part of cloud-init. See LICENSE file for license information.
22
3from cloudinit.config.cc_resizefs import (3from cloudinit.config.cc_resizefs import (
4 can_skip_resize, handle, maybe_get_writable_device_path, _resize_btrfs)4 can_skip_resize, handle, maybe_get_writable_device_path, _resize_btrfs,
5 _resize_zfs, _resize_xfs, _resize_ext, _resize_ufs)
56
6from collections import namedtuple7from collections import namedtuple
7import logging8import logging
@@ -60,6 +61,9 @@ class TestResizefs(CiTestCase):
60 res = can_skip_resize(fs_type, resize_what, devpth)61 res = can_skip_resize(fs_type, resize_what, devpth)
61 self.assertTrue(res)62 self.assertTrue(res)
6263
64 def test_can_skip_resize_ext(self):
65 self.assertFalse(can_skip_resize('ext', '/', '/dev/sda1'))
66
63 def test_handle_noops_on_disabled(self):67 def test_handle_noops_on_disabled(self):
64 """The handle function logs when the configuration disables resize."""68 """The handle function logs when the configuration disables resize."""
65 cfg = {'resize_rootfs': False}69 cfg = {'resize_rootfs': False}
@@ -122,6 +126,51 @@ class TestResizefs(CiTestCase):
122 logs = self.logs.getvalue()126 logs = self.logs.getvalue()
123 self.assertIn("WARNING: Unable to find device '/dev/root'", logs)127 self.assertIn("WARNING: Unable to find device '/dev/root'", logs)
124128
129 def test_resize_zfs_cmd_return(self):
130 zpool = 'zroot'
131 devpth = 'gpt/system'
132 self.assertEqual(('zpool', 'online', '-e', zpool, devpth),
133 _resize_zfs(zpool, devpth))
134
135 def test_resize_xfs_cmd_return(self):
136 mount_point = '/mnt/test'
137 devpth = '/dev/sda1'
138 self.assertEqual(('xfs_growfs', mount_point),
139 _resize_xfs(mount_point, devpth))
140
141 def test_resize_ext_cmd_return(self):
142 mount_point = '/'
143 devpth = '/dev/sdb1'
144 self.assertEqual(('resize2fs', devpth),
145 _resize_ext(mount_point, devpth))
146
147 def test_resize_ufs_cmd_return(self):
148 mount_point = '/'
149 devpth = '/dev/sda2'
150 self.assertEqual(('growfs', devpth),
151 _resize_ufs(mount_point, devpth))
152
153 @mock.patch('cloudinit.util.get_mount_info')
154 @mock.patch('cloudinit.util.get_device_info_from_zpool')
155 @mock.patch('cloudinit.util.parse_mount')
156 def test_handle_zfs_root(self, mount_info, zpool_info, parse_mount):
157 devpth = 'vmzroot/ROOT/freebsd'
158 disk = 'gpt/system'
159 fs_type = 'zfs'
160 mount_point = '/'
161
162 mount_info.return_value = (devpth, fs_type, mount_point)
163 zpool_info.return_value = disk
164 parse_mount.return_value = (devpth, fs_type, mount_point)
165
166 cfg = {'resize_rootfs': True}
167
168 with mock.patch('cloudinit.config.cc_resizefs.do_resize') as dresize:
169 handle('cc_resizefs', cfg, _cloud=None, log=LOG, args=[])
170 ret = dresize.call_args[0][0]
171
172 self.assertEqual(('zpool', 'online', '-e', 'vmzroot', disk), ret)
173
125174
126class TestRootDevFromCmdline(CiTestCase):175class TestRootDevFromCmdline(CiTestCase):
127176
@@ -305,5 +354,12 @@ class TestMaybeGetDevicePathAsWritableBlock(CiTestCase):
305 ('btrfs', 'filesystem', 'resize', 'max', '/'),354 ('btrfs', 'filesystem', 'resize', 'max', '/'),
306 _resize_btrfs("/", "/dev/sda1"))355 _resize_btrfs("/", "/dev/sda1"))
307356
357 @mock.patch('cloudinit.util.is_FreeBSD')
358 def test_maybe_get_writable_device_path_zfs_freebsd(self, freebsd):
359 freebsd.return_value = True
360 info = 'dev=gpt/system mnt_point=/ path=/'
361 devpth = maybe_get_writable_device_path('gpt/system', info, LOG)
362 self.assertEqual('gpt/system', devpth)
363
308364
309# vi: ts=4 expandtab365# vi: ts=4 expandtab
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index 67d9607..8685b8e 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -366,6 +366,56 @@ class TestMountinfoParsing(helpers.ResourceUsingTestCase):
366 expected = ('none', 'tmpfs', '/run/lock')366 expected = ('none', 'tmpfs', '/run/lock')
367 self.assertEqual(expected, util.parse_mount_info('/run/lock', lines))367 self.assertEqual(expected, util.parse_mount_info('/run/lock', lines))
368368
369 @mock.patch('cloudinit.util.subp')
370 def test_get_device_info_from_zpool(self, zpool_output):
371 # mock subp command from util.get_mount_info_fs_on_zpool
372 zpool_output.return_value = (
373 self.readResource('zpool_status_simple.txt'), ''
374 )
375 # save function return values and do asserts
376 ret = util.get_device_info_from_zpool('vmzroot')
377 self.assertEqual('gpt/system', ret)
378 self.assertIsNotNone(ret)
379
380 @mock.patch('cloudinit.util.subp')
381 def test_get_device_info_from_zpool_on_error(self, zpool_output):
382 # mock subp command from util.get_mount_info_fs_on_zpool
383 zpool_output.return_value = (
384 self.readResource('zpool_status_simple.txt'), 'error'
385 )
386 # save function return values and do asserts
387 ret = util.get_device_info_from_zpool('vmzroot')
388 self.assertIsNone(ret)
389
390 @mock.patch('cloudinit.util.subp')
391 def test_parse_mount_with_ext(self, mount_out):
392 mount_out.return_value = (self.readResource('mount_parse_ext.txt'), '')
393 # this one is valid and exists in mount_parse_ext.txt
394 ret = util.parse_mount('/var')
395 self.assertEqual(('/dev/mapper/vg00-lv_var', 'ext4', '/var'), ret)
396 # another one that is valid and exists
397 ret = util.parse_mount('/')
398 self.assertEqual(('/dev/mapper/vg00-lv_root', 'ext4', '/'), ret)
399 # this one exists in mount_parse_ext.txt
400 ret = util.parse_mount('/sys/kernel/debug')
401 self.assertIsNone(ret)
402 # this one does not even exist in mount_parse_ext.txt
403 ret = util.parse_mount('/not/existing/mount')
404 self.assertIsNone(ret)
405
406 @mock.patch('cloudinit.util.subp')
407 def test_parse_mount_with_zfs(self, mount_out):
408 mount_out.return_value = (self.readResource('mount_parse_zfs.txt'), '')
409 # this one is valid and exists in mount_parse_zfs.txt
410 ret = util.parse_mount('/var')
411 self.assertEqual(('vmzroot/ROOT/freebsd/var', 'zfs', '/var'), ret)
412 # this one is the root, valid and also exists in mount_parse_zfs.txt
413 ret = util.parse_mount('/')
414 self.assertEqual(('vmzroot/ROOT/freebsd', 'zfs', '/'), ret)
415 # this one does not even exist in mount_parse_ext.txt
416 ret = util.parse_mount('/not/existing/mount')
417 self.assertIsNone(ret)
418
369419
370class TestReadDMIData(helpers.FilesystemMockingTestCase):420class TestReadDMIData(helpers.FilesystemMockingTestCase):
371421

Subscribers

People subscribed via source and target branches