From 2919fb47aa7059b560ef89bf0d7a3029d246a0d5 Mon Sep 17 00:00:00 2001 From: Brett Holman Date: Wed, 10 Nov 2021 12:55:39 -0700 Subject: [PATCH 01/10] add growpart integration test --- .../modules/test_grow_part.py | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tests/integration_tests/modules/test_grow_part.py diff --git a/tests/integration_tests/modules/test_grow_part.py b/tests/integration_tests/modules/test_grow_part.py new file mode 100644 index 00000000000..387e3f844b4 --- /dev/null +++ b/tests/integration_tests/modules/test_grow_part.py @@ -0,0 +1,55 @@ +import os +import pytest +import pathlib +from uuid import uuid4 +from pycloudlib.lxd.instance import LXDInstance + +from cloudinit.subp import subp +from tests.integration_tests.instances import IntegrationInstance + +DISK_PATH = '/tmp/test_disk_setup_{}'.format(uuid4()) + + +def setup_and_mount_lxd_disk(instance: LXDInstance): + subp('lxc config device add {} test-disk-setup-disk disk source={}'.format( + instance.name, DISK_PATH).split()) + + +@pytest.fixture(scope='class', autouse=True) +def create_disk(): + """Create 16M sparse file""" + pathlib.Path(DISK_PATH).touch() + os.truncate(DISK_PATH, 1 << 24) + yield + os.remove(DISK_PATH) + + +# Create undersized partition in bootcmd +ALIAS_USERDATA = """\ +#cloud-config +bootcmd: + - parted /dev/sdb --script \ + mklabel gpt \ + mkpart primary 0 1MiB + - parted /dev/sdb --script print +growpart: + devices: + - "/" + - "/dev/sdb1" +runcmd: + - parted /dev/sdb --script print +""" + + +@pytest.mark.user_data(ALIAS_USERDATA) +@pytest.mark.lxd_setup.with_args(setup_and_mount_lxd_disk) +@pytest.mark.ubuntu +@pytest.mark.lxd_vm +class TestGrowPart: + """Test growpart""" + + def test_grow_part(self, client: IntegrationInstance): + """Verify """ + log = client.read_from_file('/var/log/cloud-init.log') + assert ("cc_growpart.py[INFO]: '/dev/sdb1' resized:" + " changed (/dev/sdb, 1) from") in log From 7311d7e8bca1b23b714babc7622701d05aae1f2c Mon Sep 17 00:00:00 2001 From: Brett Holman Date: Fri, 12 Nov 2021 11:34:27 -0700 Subject: [PATCH 02/10] add test for #1049 --- tests/integration_tests/modules/test_combined.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration_tests/modules/test_combined.py b/tests/integration_tests/modules/test_combined.py index 9cd1648a682..ea7503dc976 100644 --- a/tests/integration_tests/modules/test_combined.py +++ b/tests/integration_tests/modules/test_combined.py @@ -35,6 +35,7 @@ servers: ['ntp.ubuntu.com'] runcmd: - echo 'hello world' > /var/tmp/runcmd_output + - # """ From 62c6db7a0ad60914d46684893fda1e3ee7405b94 Mon Sep 17 00:00:00 2001 From: Brett Holman Date: Fri, 12 Nov 2021 12:27:58 -0700 Subject: [PATCH 03/10] verify LANG is set to C for growpart --- tests/unittests/test_handler/test_handler_growpart.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unittests/test_handler/test_handler_growpart.py b/tests/unittests/test_handler/test_handler_growpart.py index 7f039b79969..81c135d3397 100644 --- a/tests/unittests/test_handler/test_handler_growpart.py +++ b/tests/unittests/test_handler/test_handler_growpart.py @@ -130,6 +130,7 @@ def test_mode_auto_prefers_growpart(self): mockobj.assert_called_once_with( ['growpart', '--help'], env={'LANG': 'C'}) + @mock.patch.dict("os.environ", {'LANG': 'cs_CZ.UTF-8'}, clear=True) @mock.patch.dict("os.environ", clear=True) def test_mode_auto_falls_back_to_gpart(self): with mock.patch.object( From 99d01456e492f94a7d2d1d6174ae75d17d193c20 Mon Sep 17 00:00:00 2001 From: Brett Holman Date: Fri, 12 Nov 2021 15:03:47 -0700 Subject: [PATCH 04/10] add test for #1046 --- .../test_handler/test_handler_growpart.py | 66 ++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/tests/unittests/test_handler/test_handler_growpart.py b/tests/unittests/test_handler/test_handler_growpart.py index 81c135d3397..e0d31f54c0f 100644 --- a/tests/unittests/test_handler/test_handler_growpart.py +++ b/tests/unittests/test_handler/test_handler_growpart.py @@ -13,6 +13,8 @@ import unittest from contextlib import ExitStack from unittest import mock +import tempfile +import stat # growpart: # mode: auto # off, on, auto, 'growpart' @@ -58,6 +60,28 @@ """ +class Dir: + '''Stub object''' + def __init__(self, name): + self.name = name + self.st_mode = name + + def is_dir(self, *args, **kwargs): + return True + + def stat(self, *args, **kwargs): + return self + + +class Scanner: + '''Stub object''' + def __enter__(self): + return (Dir(''), Dir(''),) + + def __exit__(self, *args): + pass + + class TestDisabled(unittest.TestCase): def setUp(self): super(TestDisabled, self).setUp() @@ -91,6 +115,13 @@ def setUp(self): self.cloud_init = None self.handle = cc_growpart.handle + self.tmppath = '/tmp/cloudinit-test-file' + self.tmpdir = os.scandir('/tmp') + self.tmpfile = open(self.tmppath, 'w') + + def tearDown(self): + self.tmpfile.close() + os.remove(self.tmppath) @mock.patch.dict("os.environ", clear=True) def test_no_resizers_auto_is_fine(self): @@ -131,7 +162,40 @@ def test_mode_auto_prefers_growpart(self): ['growpart', '--help'], env={'LANG': 'C'}) @mock.patch.dict("os.environ", {'LANG': 'cs_CZ.UTF-8'}, clear=True) - @mock.patch.dict("os.environ", clear=True) + @mock.patch.object(tempfile, 'mkdtemp', return_value='/tmp/much-random') + @mock.patch.object(stat, 'S_ISDIR', return_value=False) + @mock.patch.object(os.path, 'samestat', return_value=True) + @mock.patch.object(os.path, "join", return_value='/tmp') + @mock.patch.object(os, 'scandir', return_value=Scanner()) + @mock.patch.object(os, 'mkdir') + @mock.patch.object(os, 'unlink') + @mock.patch.object(os, 'rmdir') + @mock.patch.object(os, 'open', return_value=1) + @mock.patch.object(os, 'close') + @mock.patch.object(os, 'lseek', return_value=1024) + @mock.patch.object(os, 'lstat', return_value='interesting metadata') + def test_force_lang_check_tempfile(self, *args, **kwargs): + with mock.patch.object( + subp, + 'subp', + return_value=(HELP_GROWPART_RESIZE, "")) as mockobj: + + ret = cc_growpart.resizer_factory(mode="auto") + self.assertIsInstance(ret, cc_growpart.ResizeGrowPart) + diskdev = '/dev/sdb' + partnum = 1 + partdev = '/dev/sdb' + ret.resize(diskdev, partnum, partdev) + mockobj.assert_has_calls([ + mock.call( + ["growpart", '--dry-run', diskdev, partnum], + env={'LANG': 'C', 'TMPDIR': '/tmp'}), + mock.call( + ["growpart", diskdev, partnum], + env={'LANG': 'C', 'TMPDIR': '/tmp'}), + ]) + + @mock.patch.dict("os.environ", {'LANG': 'cs_CZ.UTF-8'}, clear=True) def test_mode_auto_falls_back_to_gpart(self): with mock.patch.object( subp, 'subp', From e1968d0146693ec837941563d781803541c18730 Mon Sep 17 00:00:00 2001 From: Brett Holman Date: Fri, 12 Nov 2021 15:10:55 -0700 Subject: [PATCH 05/10] file rename --- .../modules/{test_grow_part.py => test_growpart.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/integration_tests/modules/{test_grow_part.py => test_growpart.py} (100%) diff --git a/tests/integration_tests/modules/test_grow_part.py b/tests/integration_tests/modules/test_growpart.py similarity index 100% rename from tests/integration_tests/modules/test_grow_part.py rename to tests/integration_tests/modules/test_growpart.py From d359b754b60c71ed9b68ae00611c16884764b5ee Mon Sep 17 00:00:00 2001 From: Brett Holman Date: Mon, 15 Nov 2021 13:11:11 -0700 Subject: [PATCH 06/10] noop --- tests/integration_tests/modules/test_combined.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration_tests/modules/test_combined.py b/tests/integration_tests/modules/test_combined.py index ea7503dc976..d8f51e6f92e 100644 --- a/tests/integration_tests/modules/test_combined.py +++ b/tests/integration_tests/modules/test_combined.py @@ -36,6 +36,7 @@ runcmd: - echo 'hello world' > /var/tmp/runcmd_output - # + """ From e1bb50ffcc75f78766f5c91019b418bf3e073fd3 Mon Sep 17 00:00:00 2001 From: Brett Holman Date: Mon, 15 Nov 2021 13:30:30 -0700 Subject: [PATCH 07/10] fix weird environment difference failure --- tests/unittests/test_handler/test_handler_growpart.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unittests/test_handler/test_handler_growpart.py b/tests/unittests/test_handler/test_handler_growpart.py index e0d31f54c0f..5609e0949bb 100644 --- a/tests/unittests/test_handler/test_handler_growpart.py +++ b/tests/unittests/test_handler/test_handler_growpart.py @@ -162,7 +162,8 @@ def test_mode_auto_prefers_growpart(self): ['growpart', '--help'], env={'LANG': 'C'}) @mock.patch.dict("os.environ", {'LANG': 'cs_CZ.UTF-8'}, clear=True) - @mock.patch.object(tempfile, 'mkdtemp', return_value='/tmp/much-random') + @mock.patch.object(temp_utils, 'mkdtemp', return_value='/tmp/much-random') + @mock.patch.object(os, 'mkdtemp', return_value='/tmp/much-random') @mock.patch.object(stat, 'S_ISDIR', return_value=False) @mock.patch.object(os.path, 'samestat', return_value=True) @mock.patch.object(os.path, "join", return_value='/tmp') From 81e3e9bd16789371d8d0b99a3ae09bc769f9be35 Mon Sep 17 00:00:00 2001 From: Brett Holman Date: Mon, 15 Nov 2021 13:50:43 -0700 Subject: [PATCH 08/10] fix mkdtemp mock object source --- tests/unittests/test_handler/test_handler_growpart.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unittests/test_handler/test_handler_growpart.py b/tests/unittests/test_handler/test_handler_growpart.py index 5609e0949bb..834580c306e 100644 --- a/tests/unittests/test_handler/test_handler_growpart.py +++ b/tests/unittests/test_handler/test_handler_growpart.py @@ -3,6 +3,7 @@ from cloudinit import cloud from cloudinit.config import cc_growpart from cloudinit import subp +from cloudinit import temp_utils from cloudinit.tests.helpers import TestCase @@ -163,7 +164,6 @@ def test_mode_auto_prefers_growpart(self): @mock.patch.dict("os.environ", {'LANG': 'cs_CZ.UTF-8'}, clear=True) @mock.patch.object(temp_utils, 'mkdtemp', return_value='/tmp/much-random') - @mock.patch.object(os, 'mkdtemp', return_value='/tmp/much-random') @mock.patch.object(stat, 'S_ISDIR', return_value=False) @mock.patch.object(os.path, 'samestat', return_value=True) @mock.patch.object(os.path, "join", return_value='/tmp') From 2e3ad2f8dd5953f596caea99ff8ee0d67ff894ee Mon Sep 17 00:00:00 2001 From: Brett Holman Date: Mon, 15 Nov 2021 14:14:34 -0700 Subject: [PATCH 09/10] more env-specific fixes --- tests/unittests/test_handler/test_handler_growpart.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unittests/test_handler/test_handler_growpart.py b/tests/unittests/test_handler/test_handler_growpart.py index 834580c306e..b7d5d7ba5c4 100644 --- a/tests/unittests/test_handler/test_handler_growpart.py +++ b/tests/unittests/test_handler/test_handler_growpart.py @@ -10,11 +10,11 @@ import errno import logging import os +import shutil import re import unittest from contextlib import ExitStack from unittest import mock -import tempfile import stat # growpart: @@ -173,6 +173,7 @@ def test_mode_auto_prefers_growpart(self): @mock.patch.object(os, 'rmdir') @mock.patch.object(os, 'open', return_value=1) @mock.patch.object(os, 'close') + @mock.patch.object(shutil, 'rmtree') @mock.patch.object(os, 'lseek', return_value=1024) @mock.patch.object(os, 'lstat', return_value='interesting metadata') def test_force_lang_check_tempfile(self, *args, **kwargs): From 57c01d40850e36a9a2b5325ac79b89f370d03e1d Mon Sep 17 00:00:00 2001 From: Brett Holman Date: Wed, 17 Nov 2021 08:10:29 -0700 Subject: [PATCH 10/10] add lsblk size assertion --- tests/integration_tests/modules/test_growpart.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/integration_tests/modules/test_growpart.py b/tests/integration_tests/modules/test_growpart.py index 387e3f844b4..af1e3a15f86 100644 --- a/tests/integration_tests/modules/test_growpart.py +++ b/tests/integration_tests/modules/test_growpart.py @@ -1,6 +1,7 @@ import os import pytest import pathlib +import json from uuid import uuid4 from pycloudlib.lxd.instance import LXDInstance @@ -53,3 +54,9 @@ def test_grow_part(self, client: IntegrationInstance): log = client.read_from_file('/var/log/cloud-init.log') assert ("cc_growpart.py[INFO]: '/dev/sdb1' resized:" " changed (/dev/sdb, 1) from") in log + + lsblk = json.loads(client.execute('lsblk --json')) + sdb = [x for x in lsblk['blockdevices'] if x['name'] == 'sdb'][0] + assert len(sdb['children']) == 1 + assert sdb['children'][0]['name'] == 'sdb1' + assert sdb['size'] == '16M'