From a3812a4ab4eeb2aa185eb4a2de186cc60ddd7c03 Mon Sep 17 00:00:00 2001 From: Igor Galić Date: Wed, 14 Nov 2018 22:02:18 +0000 Subject: resizefs: Prefix discovered devpath with '/dev/' when path does not exist In some environments, like FreeBSD, gpart can return the device basename instead of the full path. If this discovered devpath does not exist and is missing the '/dev/' prefix, add that prefix in an attempt to find the device. --- .../test_handler/test_handler_resizefs.py | 48 ++++++++++++++++++---- 1 file changed, 40 insertions(+), 8 deletions(-) (limited to 'tests/unittests/test_handler') diff --git a/tests/unittests/test_handler/test_handler_resizefs.py b/tests/unittests/test_handler/test_handler_resizefs.py index feca56c2..6ebacb1a 100644 --- a/tests/unittests/test_handler/test_handler_resizefs.py +++ b/tests/unittests/test_handler/test_handler_resizefs.py @@ -173,6 +173,38 @@ class TestResizefs(CiTestCase): self.assertEqual(('zpool', 'online', '-e', 'vmzroot', disk), ret) + @mock.patch('cloudinit.util.is_container', return_value=False) + @mock.patch('cloudinit.util.get_mount_info') + @mock.patch('cloudinit.util.get_device_info_from_zpool') + @mock.patch('cloudinit.util.parse_mount') + def test_handle_modern_zfsroot(self, mount_info, zpool_info, parse_mount, + is_container): + devpth = 'zroot/ROOT/default' + disk = 'da0p3' + fs_type = 'zfs' + mount_point = '/' + + mount_info.return_value = (devpth, fs_type, mount_point) + zpool_info.return_value = disk + parse_mount.return_value = (devpth, fs_type, mount_point) + + cfg = {'resize_rootfs': True} + + def fake_stat(devpath): + if devpath == disk: + raise OSError("not here") + FakeStat = namedtuple( + 'FakeStat', ['st_mode', 'st_size', 'st_mtime']) # minimal stat + return FakeStat(25008, 0, 1) # fake char block device + + with mock.patch('cloudinit.config.cc_resizefs.do_resize') as dresize: + with mock.patch('cloudinit.config.cc_resizefs.os.stat') as m_stat: + m_stat.side_effect = fake_stat + handle('cc_resizefs', cfg, _cloud=None, log=LOG, args=[]) + + self.assertEqual(('zpool', 'online', '-e', 'zroot', '/dev/' + disk), + dresize.call_args[0][0]) + class TestRootDevFromCmdline(CiTestCase): @@ -246,39 +278,39 @@ class TestMaybeGetDevicePathAsWritableBlock(CiTestCase): def test_maybe_get_writable_device_path_does_not_exist(self): """When devpath does not exist, a warning is logged.""" - info = 'dev=/I/dont/exist mnt_point=/ path=/dev/none' + info = 'dev=/dev/I/dont/exist mnt_point=/ path=/dev/none' devpath = wrap_and_call( 'cloudinit.config.cc_resizefs.util', {'is_container': {'return_value': False}}, - maybe_get_writable_device_path, '/I/dont/exist', info, LOG) + maybe_get_writable_device_path, '/dev/I/dont/exist', info, LOG) self.assertIsNone(devpath) self.assertIn( - "WARNING: Device '/I/dont/exist' did not exist." + "WARNING: Device '/dev/I/dont/exist' did not exist." ' cannot resize: %s' % info, self.logs.getvalue()) def test_maybe_get_writable_device_path_does_not_exist_in_container(self): """When devpath does not exist in a container, log a debug message.""" - info = 'dev=/I/dont/exist mnt_point=/ path=/dev/none' + info = 'dev=/dev/I/dont/exist mnt_point=/ path=/dev/none' devpath = wrap_and_call( 'cloudinit.config.cc_resizefs.util', {'is_container': {'return_value': True}}, - maybe_get_writable_device_path, '/I/dont/exist', info, LOG) + maybe_get_writable_device_path, '/dev/I/dont/exist', info, LOG) self.assertIsNone(devpath) self.assertIn( - "DEBUG: Device '/I/dont/exist' did not exist in container." + "DEBUG: Device '/dev/I/dont/exist' did not exist in container." ' cannot resize: %s' % info, self.logs.getvalue()) def test_maybe_get_writable_device_path_raises_oserror(self): """When unexpected OSError is raises by os.stat it is reraised.""" - info = 'dev=/I/dont/exist mnt_point=/ path=/dev/none' + info = 'dev=/dev/I/dont/exist mnt_point=/ path=/dev/none' with self.assertRaises(OSError) as context_manager: wrap_and_call( 'cloudinit.config.cc_resizefs', {'util.is_container': {'return_value': True}, 'os.stat': {'side_effect': OSError('Something unexpected')}}, - maybe_get_writable_device_path, '/I/dont/exist', info, LOG) + maybe_get_writable_device_path, '/dev/I/dont/exist', info, LOG) self.assertEqual( 'Something unexpected', str(context_manager.exception)) -- cgit v1.2.3 From 4ce8a2858dffcb1f9518b50d884b341f68ac5e63 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Wed, 28 Nov 2018 18:23:33 +0000 Subject: tests: fix incorrect order of mocks in test_handle_zfs_root. The order of parameters to test_handle_zfs_root did not match the order of the mocks applied. Thanks to Jason Zions for pointing this out. --- tests/unittests/test_handler/test_handler_resizefs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tests/unittests/test_handler') diff --git a/tests/unittests/test_handler/test_handler_resizefs.py b/tests/unittests/test_handler/test_handler_resizefs.py index 6ebacb1a..35187847 100644 --- a/tests/unittests/test_handler/test_handler_resizefs.py +++ b/tests/unittests/test_handler/test_handler_resizefs.py @@ -151,9 +151,9 @@ class TestResizefs(CiTestCase): _resize_ufs(mount_point, devpth)) @mock.patch('cloudinit.util.is_container', return_value=False) - @mock.patch('cloudinit.util.get_mount_info') - @mock.patch('cloudinit.util.get_device_info_from_zpool') @mock.patch('cloudinit.util.parse_mount') + @mock.patch('cloudinit.util.get_device_info_from_zpool') + @mock.patch('cloudinit.util.get_mount_info') def test_handle_zfs_root(self, mount_info, zpool_info, parse_mount, is_container): devpth = 'vmzroot/ROOT/freebsd' -- cgit v1.2.3 From a4007d063f96b82545aa678ef2cb472ea3b48b1e Mon Sep 17 00:00:00 2001 From: James Baxter Date: Thu, 6 Dec 2018 18:26:32 +0000 Subject: write_files: add support for appending to files. Add 'append: true' to write_files entries to append 'content' to file specified by 'path' key. This modifies the file open mode to append. --- cloudinit/config/cc_write_files.py | 7 ++++++- tests/unittests/test_handler/test_handler_write_files.py | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'tests/unittests/test_handler') diff --git a/cloudinit/config/cc_write_files.py b/cloudinit/config/cc_write_files.py index 31d1db61..0b6546e2 100644 --- a/cloudinit/config/cc_write_files.py +++ b/cloudinit/config/cc_write_files.py @@ -49,6 +49,10 @@ binary gzip data can be specified and will be decoded before being written. ... path: /bin/arch permissions: '0555' + - content: | + 15 * * * * root ship_logs + path: /etc/crontab + append: true """ import base64 @@ -113,7 +117,8 @@ def write_files(name, files): contents = extract_contents(f_info.get('content', ''), extractions) (u, g) = util.extract_usergroup(f_info.get('owner', DEFAULT_OWNER)) perms = decode_perms(f_info.get('permissions'), DEFAULT_PERMS) - util.write_file(path, contents, mode=perms) + omode = 'ab' if util.get_cfg_option_bool(f_info, 'append') else 'wb' + util.write_file(path, contents, omode=omode, mode=perms) util.chownbyname(path, u, g) diff --git a/tests/unittests/test_handler/test_handler_write_files.py b/tests/unittests/test_handler/test_handler_write_files.py index 7fa8fd21..bc8756ca 100644 --- a/tests/unittests/test_handler/test_handler_write_files.py +++ b/tests/unittests/test_handler/test_handler_write_files.py @@ -52,6 +52,18 @@ class TestWriteFiles(FilesystemMockingTestCase): "test_simple", [{"content": expected, "path": filename}]) self.assertEqual(util.load_file(filename), expected) + def test_append(self): + self.patchUtils(self.tmp) + existing = "hello " + added = "world\n" + expected = existing + added + filename = "/tmp/append.file" + util.write_file(filename, existing) + write_files( + "test_append", + [{"content": added, "path": filename, "append": "true"}]) + self.assertEqual(util.load_file(filename), expected) + def test_yaml_binary(self): self.patchUtils(self.tmp) data = util.load_yaml(YAML_TEXT) -- cgit v1.2.3