Blame tests/unittests/test_handler/test_handler_growpart.py

Packit Service a04d08
# This file is part of cloud-init. See LICENSE file for license information.
Packit Service a04d08
Packit Service a04d08
from cloudinit import cloud
Packit Service a04d08
from cloudinit.config import cc_growpart
Packit Service 9bfd13
from cloudinit import subp
Packit Service a04d08
Packit Service a04d08
from cloudinit.tests.helpers import TestCase
Packit Service a04d08
Packit Service a04d08
import errno
Packit Service a04d08
import logging
Packit Service a04d08
import os
Packit Service a04d08
import re
Packit Service a04d08
import unittest
Packit Service 9bfd13
from contextlib import ExitStack
Packit Service 9bfd13
from unittest import mock
Packit Service a04d08
Packit Service a04d08
# growpart:
Packit Service a04d08
#   mode: auto  # off, on, auto, 'growpart'
Packit Service a04d08
#   devices: ['root']
Packit Service a04d08
Packit Service a04d08
HELP_GROWPART_RESIZE = """
Packit Service a04d08
growpart disk partition
Packit Service a04d08
   rewrite partition table so that partition takes up all the space it can
Packit Service a04d08
   options:
Packit Service a04d08
    -h | --help       print Usage and exit
Packit Service a04d08
<SNIP>
Packit Service a04d08
    -u | --update  R  update the the kernel partition table info after growing
Packit Service a04d08
                      this requires kernel support and 'partx --update'
Packit Service a04d08
                      R is one of:
Packit Service a04d08
                       - 'auto'  : [default] update partition if possible
Packit Service a04d08
<SNIP>
Packit Service a04d08
   Example:
Packit Service a04d08
    - growpart /dev/sda 1
Packit Service a04d08
      Resize partition 1 on /dev/sda
Packit Service a04d08
"""
Packit Service a04d08
Packit Service a04d08
HELP_GROWPART_NO_RESIZE = """
Packit Service a04d08
growpart disk partition
Packit Service a04d08
   rewrite partition table so that partition takes up all the space it can
Packit Service a04d08
   options:
Packit Service a04d08
    -h | --help       print Usage and exit
Packit Service a04d08
<SNIP>
Packit Service a04d08
   Example:
Packit Service a04d08
    - growpart /dev/sda 1
Packit Service a04d08
      Resize partition 1 on /dev/sda
Packit Service a04d08
"""
Packit Service a04d08
Packit Service 9bfd13
HELP_GPART = """
Packit Service 9bfd13
usage: gpart add -t type [-a alignment] [-b start] <SNIP> geom
Packit Service 9bfd13
       gpart backup geom
Packit Service 9bfd13
       gpart bootcode [-b bootcode] [-p partcode -i index] [-f flags] geom
Packit Service 9bfd13
<SNIP>
Packit Service 9bfd13
       gpart resize -i index [-a alignment] [-s size] [-f flags] geom
Packit Service 9bfd13
       gpart restore [-lF] [-f flags] provider [...]
Packit Service 9bfd13
       gpart recover [-f flags] geom
Packit Service 9bfd13
       gpart help
Packit Service 9bfd13
<SNIP>
Packit Service 9bfd13
"""
Packit Service 9bfd13
Packit Service a04d08
Packit Service a04d08
class TestDisabled(unittest.TestCase):
Packit Service a04d08
    def setUp(self):
Packit Service a04d08
        super(TestDisabled, self).setUp()
Packit Service a04d08
        self.name = "growpart"
Packit Service a04d08
        self.cloud_init = None
Packit Service a04d08
        self.log = logging.getLogger("TestDisabled")
Packit Service a04d08
        self.args = []
Packit Service a04d08
Packit Service a04d08
        self.handle = cc_growpart.handle
Packit Service a04d08
Packit Service a04d08
    def test_mode_off(self):
Packit Service a04d08
        # Test that nothing is done if mode is off.
Packit Service a04d08
Packit Service a04d08
        # this really only verifies that resizer_factory isn't called
Packit Service a04d08
        config = {'growpart': {'mode': 'off'}}
Packit Service a04d08
Packit Service a04d08
        with mock.patch.object(cc_growpart, 'resizer_factory') as mockobj:
Packit Service a04d08
            self.handle(self.name, config, self.cloud_init, self.log,
Packit Service a04d08
                        self.args)
Packit Service a04d08
            self.assertEqual(mockobj.call_count, 0)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class TestConfig(TestCase):
Packit Service a04d08
    def setUp(self):
Packit Service a04d08
        super(TestConfig, self).setUp()
Packit Service a04d08
        self.name = "growpart"
Packit Service a04d08
        self.paths = None
Packit Service a04d08
        self.cloud = cloud.Cloud(None, self.paths, None, None, None)
Packit Service a04d08
        self.log = logging.getLogger("TestConfig")
Packit Service a04d08
        self.args = []
Packit Service a04d08
Packit Service a04d08
        self.cloud_init = None
Packit Service a04d08
        self.handle = cc_growpart.handle
Packit Service a04d08
Packit Service a04d08
    @mock.patch.dict("os.environ", clear=True)
Packit Service a04d08
    def test_no_resizers_auto_is_fine(self):
Packit Service a04d08
        with mock.patch.object(
Packit Service 9bfd13
                subp, 'subp',
Packit Service a04d08
                return_value=(HELP_GROWPART_NO_RESIZE, "")) as mockobj:
Packit Service a04d08
Packit Service a04d08
            config = {'growpart': {'mode': 'auto'}}
Packit Service a04d08
            self.handle(self.name, config, self.cloud_init, self.log,
Packit Service a04d08
                        self.args)
Packit Service a04d08
Packit Service 9bfd13
            mockobj.assert_has_calls([
Packit Service 9bfd13
                mock.call(['growpart', '--help'], env={'LANG': 'C'}),
Packit Service 9bfd13
                mock.call(['gpart', 'help'], env={'LANG': 'C'}, rcs=[0, 1])])
Packit Service a04d08
Packit Service a04d08
    @mock.patch.dict("os.environ", clear=True)
Packit Service a04d08
    def test_no_resizers_mode_growpart_is_exception(self):
Packit Service a04d08
        with mock.patch.object(
Packit Service 9bfd13
                subp, 'subp',
Packit Service a04d08
                return_value=(HELP_GROWPART_NO_RESIZE, "")) as mockobj:
Packit Service a04d08
            config = {'growpart': {'mode': "growpart"}}
Packit Service a04d08
            self.assertRaises(
Packit Service a04d08
                ValueError, self.handle, self.name, config,
Packit Service a04d08
                self.cloud_init, self.log, self.args)
Packit Service a04d08
Packit Service a04d08
            mockobj.assert_called_once_with(
Packit Service a04d08
                ['growpart', '--help'], env={'LANG': 'C'})
Packit Service a04d08
Packit Service a04d08
    @mock.patch.dict("os.environ", clear=True)
Packit Service a04d08
    def test_mode_auto_prefers_growpart(self):
Packit Service a04d08
        with mock.patch.object(
Packit Service 9bfd13
                subp, 'subp',
Packit Service a04d08
                return_value=(HELP_GROWPART_RESIZE, "")) as mockobj:
Packit Service a04d08
            ret = cc_growpart.resizer_factory(mode="auto")
Packit Service a04d08
            self.assertIsInstance(ret, cc_growpart.ResizeGrowPart)
Packit Service a04d08
Packit Service a04d08
            mockobj.assert_called_once_with(
Packit Service a04d08
                ['growpart', '--help'], env={'LANG': 'C'})
Packit Service a04d08
Packit Service 9bfd13
    @mock.patch.dict("os.environ", clear=True)
Packit Service 9bfd13
    def test_mode_auto_falls_back_to_gpart(self):
Packit Service 9bfd13
        with mock.patch.object(
Packit Service 9bfd13
                subp, 'subp',
Packit Service 9bfd13
                return_value=("", HELP_GPART)) as mockobj:
Packit Service 9bfd13
            ret = cc_growpart.resizer_factory(mode="auto")
Packit Service 9bfd13
            self.assertIsInstance(ret, cc_growpart.ResizeGpart)
Packit Service 9bfd13
Packit Service 9bfd13
            mockobj.assert_has_calls([
Packit Service 9bfd13
                mock.call(['growpart', '--help'], env={'LANG': 'C'}),
Packit Service 9bfd13
                mock.call(['gpart', 'help'], env={'LANG': 'C'}, rcs=[0, 1])])
Packit Service 9bfd13
Packit Service a04d08
    def test_handle_with_no_growpart_entry(self):
Packit Service a04d08
        # if no 'growpart' entry in config, then mode=auto should be used
Packit Service a04d08
Packit Service a04d08
        myresizer = object()
Packit Service a04d08
        retval = (("/", cc_growpart.RESIZE.CHANGED, "my-message",),)
Packit Service a04d08
Packit Service a04d08
        with ExitStack() as mocks:
Packit Service a04d08
            factory = mocks.enter_context(
Packit Service a04d08
                mock.patch.object(cc_growpart, 'resizer_factory',
Packit Service a04d08
                                  return_value=myresizer))
Packit Service a04d08
            rsdevs = mocks.enter_context(
Packit Service a04d08
                mock.patch.object(cc_growpart, 'resize_devices',
Packit Service a04d08
                                  return_value=retval))
Packit Service a04d08
            mocks.enter_context(
Packit Service a04d08
                mock.patch.object(cc_growpart, 'RESIZERS',
Packit Service a04d08
                                  (('mysizer', object),)
Packit Service a04d08
                                  ))
Packit Service a04d08
Packit Service a04d08
            self.handle(self.name, {}, self.cloud_init, self.log, self.args)
Packit Service a04d08
Packit Service a04d08
            factory.assert_called_once_with('auto')
Packit Service a04d08
            rsdevs.assert_called_once_with(myresizer, ['/'])
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class TestResize(unittest.TestCase):
Packit Service a04d08
    def setUp(self):
Packit Service a04d08
        super(TestResize, self).setUp()
Packit Service a04d08
        self.name = "growpart"
Packit Service a04d08
        self.log = logging.getLogger("TestResize")
Packit Service a04d08
Packit Service a04d08
    def test_simple_devices(self):
Packit Service a04d08
        # test simple device list
Packit Service a04d08
        # this patches out devent2dev, os.stat, and device_part_info
Packit Service a04d08
        # so in the end, doesn't test a lot
Packit Service a04d08
        devs = ["/dev/XXda1", "/dev/YYda2"]
Packit Service a04d08
        devstat_ret = Bunch(st_mode=25008, st_ino=6078, st_dev=5,
Packit Service a04d08
                            st_nlink=1, st_uid=0, st_gid=6, st_size=0,
Packit Service a04d08
                            st_atime=0, st_mtime=0, st_ctime=0)
Packit Service a04d08
        enoent = ["/dev/NOENT"]
Packit Service a04d08
        real_stat = os.stat
Packit Service a04d08
        resize_calls = []
Packit Service a04d08
Packit Service a04d08
        class myresizer(object):
Packit Service a04d08
            def resize(self, diskdev, partnum, partdev):
Packit Service a04d08
                resize_calls.append((diskdev, partnum, partdev))
Packit Service a04d08
                if partdev == "/dev/YYda2":
Packit Service a04d08
                    return (1024, 2048)
Packit Service a04d08
                return (1024, 1024)  # old size, new size
Packit Service a04d08
Packit Service a04d08
        def mystat(path):
Packit Service a04d08
            if path in devs:
Packit Service a04d08
                return devstat_ret
Packit Service a04d08
            if path in enoent:
Packit Service a04d08
                e = OSError("%s: does not exist" % path)
Packit Service a04d08
                e.errno = errno.ENOENT
Packit Service a04d08
                raise e
Packit Service a04d08
            return real_stat(path)
Packit Service a04d08
Packit Service a04d08
        try:
Packit Service a04d08
            opinfo = cc_growpart.device_part_info
Packit Service a04d08
            cc_growpart.device_part_info = simple_device_part_info
Packit Service a04d08
            os.stat = mystat
Packit Service a04d08
Packit Service a04d08
            resized = cc_growpart.resize_devices(myresizer(), devs + enoent)
Packit Service a04d08
Packit Service a04d08
            def find(name, res):
Packit Service a04d08
                for f in res:
Packit Service a04d08
                    if f[0] == name:
Packit Service a04d08
                        return f
Packit Service a04d08
                return None
Packit Service a04d08
Packit Service a04d08
            self.assertEqual(cc_growpart.RESIZE.NOCHANGE,
Packit Service a04d08
                             find("/dev/XXda1", resized)[1])
Packit Service a04d08
            self.assertEqual(cc_growpart.RESIZE.CHANGED,
Packit Service a04d08
                             find("/dev/YYda2", resized)[1])
Packit Service a04d08
            self.assertEqual(cc_growpart.RESIZE.SKIPPED,
Packit Service a04d08
                             find(enoent[0], resized)[1])
Packit Service a04d08
            # self.assertEqual(resize_calls,
Packit Service a04d08
            #                 [("/dev/XXda", "1", "/dev/XXda1"),
Packit Service a04d08
            #                  ("/dev/YYda", "2", "/dev/YYda2")])
Packit Service a04d08
        finally:
Packit Service a04d08
            cc_growpart.device_part_info = opinfo
Packit Service a04d08
            os.stat = real_stat
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
def simple_device_part_info(devpath):
Packit Service a04d08
    # simple stupid return (/dev/vda, 1) for /dev/vda
Packit Service a04d08
    ret = re.search("([^0-9]*)([0-9]*)$", devpath)
Packit Service a04d08
    x = (ret.group(1), ret.group(2))
Packit Service a04d08
    return x
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
class Bunch(object):
Packit Service a04d08
    def __init__(self, **kwds):
Packit Service a04d08
        self.__dict__.update(kwds)
Packit Service a04d08
Packit Service a04d08
Packit Service a04d08
# vi: ts=4 expandtab