summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConrad Hoffmann <1226676+bitfehler@users.noreply.github.com>2020-01-14 21:27:59 +0100
committerDaniel Watkins <oddbloke@ubuntu.com>2020-01-14 15:27:59 -0500
commitbb4131a2bd36d9e8932fdcb61432260f16159cde (patch)
treebe3501e7efbdfe21d221e4d221120f88ebdbba62
parent863394ba0b5f18483b350daec30af8434be8811b (diff)
downloadcloud-init-git-bb4131a2bd36d9e8932fdcb61432260f16159cde.tar.gz
Only use gpart if it is the BSD gpart (#131)
Currently, cloud-init will happily try to run `gpart` on Linux even though on most distributions this a different tool [1]. Extend the availability check to make sure the `gpart` present is really the BSD variant, to avoid accidental execution. Also add a pointer to the docs, so that people do not try to install gpart on Linux in the expectation it will work with this module. [1] https://github.com/baruch/gpart
-rw-r--r--cloudinit/config/cc_growpart.py26
-rw-r--r--tests/unittests/test_handler/test_handler_growpart.py29
2 files changed, 44 insertions, 11 deletions
diff --git a/cloudinit/config/cc_growpart.py b/cloudinit/config/cc_growpart.py
index aa9716e7..1b512a06 100644
--- a/cloudinit/config/cc_growpart.py
+++ b/cloudinit/config/cc_growpart.py
@@ -22,11 +22,11 @@ mountpoint in the filesystem or a path to the block device in ``/dev``.
The utility to use for resizing can be selected using the ``mode`` config key.
If ``mode`` key is set to ``auto``, then any available utility (either
-``growpart`` or ``gpart``) will be used. If neither utility is available, no
-error will be raised. If ``mode`` is set to ``growpart``, then the ``growpart``
-utility will be used. If this utility is not available on the system, this will
-result in an error. If ``mode`` is set to ``off`` or ``false``, then
-``cc_growpart`` will take no action.
+``growpart`` or BSD ``gpart``) will be used. If neither utility is available,
+no error will be raised. If ``mode`` is set to ``growpart``, then the
+``growpart`` utility will be used. If this utility is not available on the
+system, this will result in an error. If ``mode`` is set to ``off`` or
+``false``, then ``cc_growpart`` will take no action.
There is some functionality overlap between this module and the ``growroot``
functionality of ``cloud-initramfs-tools``. However, there are some situations
@@ -132,7 +132,7 @@ class ResizeGrowPart(object):
try:
(out, _err) = util.subp(["growpart", "--help"], env=myenv)
- if re.search(r"--update\s+", out, re.DOTALL):
+ if re.search(r"--update\s+", out):
return True
except util.ProcessExecutionError:
@@ -161,9 +161,17 @@ class ResizeGrowPart(object):
class ResizeGpart(object):
def available(self):
- if not util.which('gpart'):
- return False
- return True
+ myenv = os.environ.copy()
+ myenv['LANG'] = 'C'
+
+ try:
+ (_out, err) = util.subp(["gpart", "help"], env=myenv, rcs=[0, 1])
+ if re.search(r"gpart recover ", err):
+ return True
+
+ except util.ProcessExecutionError:
+ pass
+ return False
def resize(self, diskdev, partnum, partdev):
"""
diff --git a/tests/unittests/test_handler/test_handler_growpart.py b/tests/unittests/test_handler/test_handler_growpart.py
index a3e46351..1f39ebe7 100644
--- a/tests/unittests/test_handler/test_handler_growpart.py
+++ b/tests/unittests/test_handler/test_handler_growpart.py
@@ -52,6 +52,18 @@ growpart disk partition
Resize partition 1 on /dev/sda
"""
+HELP_GPART = """
+usage: gpart add -t type [-a alignment] [-b start] <SNIP> geom
+ gpart backup geom
+ gpart bootcode [-b bootcode] [-p partcode -i index] [-f flags] geom
+<SNIP>
+ gpart resize -i index [-a alignment] [-s size] [-f flags] geom
+ gpart restore [-lF] [-f flags] provider [...]
+ gpart recover [-f flags] geom
+ gpart help
+<SNIP>
+"""
+
class TestDisabled(unittest.TestCase):
def setUp(self):
@@ -97,8 +109,9 @@ class TestConfig(TestCase):
self.handle(self.name, config, self.cloud_init, self.log,
self.args)
- mockobj.assert_called_once_with(
- ['growpart', '--help'], env={'LANG': 'C'})
+ mockobj.assert_has_calls([
+ mock.call(['growpart', '--help'], env={'LANG': 'C'}),
+ mock.call(['gpart', 'help'], env={'LANG': 'C'}, rcs=[0, 1])])
@mock.patch.dict("os.environ", clear=True)
def test_no_resizers_mode_growpart_is_exception(self):
@@ -124,6 +137,18 @@ class TestConfig(TestCase):
mockobj.assert_called_once_with(
['growpart', '--help'], env={'LANG': 'C'})
+ @mock.patch.dict("os.environ", clear=True)
+ def test_mode_auto_falls_back_to_gpart(self):
+ with mock.patch.object(
+ util, 'subp',
+ return_value=("", HELP_GPART)) as mockobj:
+ ret = cc_growpart.resizer_factory(mode="auto")
+ self.assertIsInstance(ret, cc_growpart.ResizeGpart)
+
+ mockobj.assert_has_calls([
+ mock.call(['growpart', '--help'], env={'LANG': 'C'}),
+ mock.call(['gpart', 'help'], env={'LANG': 'C'}, rcs=[0, 1])])
+
def test_handle_with_no_growpart_entry(self):
# if no 'growpart' entry in config, then mode=auto should be used