def test_lvm_resize(self):
        # LVM resize should work only if a single device is configured. More
        # than one device should fail.
        lvm_pass = ["/dev/XXdm-0"]
        lvm_fail = ["/dev/XXdm-1", "/dev/YYdm-1"]
        devstat_ret = Bunch(st_mode=25008,
                            st_ino=6078,
                            st_dev=5,
                            st_nlink=1,
                            st_uid=0,
                            st_gid=6,
                            st_size=0,
                            st_atime=0,
                            st_mtime=0,
                            st_ctime=0)
        real_stat = os.stat
        resize_calls = []

        class myresizer(object):
            def resize(self, diskdev, partnum, partdev):
                resize_calls.append((diskdev, partnum, partdev))
                if partdev == "/dev/XXdm-0":
                    return (1024, 2048)
                return (1024, 1024)  # old size, new size

        def mystat(path):
            if path in lvm_pass or path in lvm_fail:
                return devstat_ret
            return real_stat(path)

        try:
            opinfo = cc_growpart.device_part_info
            cc_growpart.device_part_info = simple_device_part_info_lvm
            os.stat = mystat

            resized = cc_growpart.resize_devices(myresizer(), lvm_pass)
            not_resized = cc_growpart.resize_devices(myresizer(), lvm_fail)

            def find(name, res):
                for f in res:
                    if f[0] == name:
                        return f
                return None

            self.assertEqual(cc_growpart.RESIZE.CHANGED,
                             find("/dev/XXdm-0", resized)[1])
            self.assertEqual(cc_growpart.RESIZE.NOCHANGE,
                             find("/dev/XXdm-1", not_resized)[1])
            self.assertEqual(cc_growpart.RESIZE.NOCHANGE,
                             find("/dev/YYdm-1", not_resized)[1])
        finally:
            cc_growpart.device_part_info = opinfo
            os.stat = real_stat
Esempio n. 2
0
    def test_simple_devices(self):
        # test simple device list
        # this patches out devent2dev, os.stat, and device_part_info
        # so in the end, doesn't test a lot
        devs = ["/dev/XXda1", "/dev/YYda2"]
        devstat_ret = Bunch(st_mode=25008,
                            st_ino=6078,
                            st_dev=5,
                            st_nlink=1,
                            st_uid=0,
                            st_gid=6,
                            st_size=0,
                            st_atime=0,
                            st_mtime=0,
                            st_ctime=0)
        enoent = ["/dev/NOENT"]
        real_stat = os.stat
        resize_calls = []

        class myresizer(object):
            def resize(self, diskdev, partnum, partdev):
                resize_calls.append((diskdev, partnum, partdev))
                if partdev == "/dev/YYda2":
                    return (1024, 2048)
                return (1024, 1024)  # old size, new size

        def mystat(path):
            if path in devs:
                return devstat_ret
            if path in enoent:
                e = OSError("%s: does not exist" % path)
                e.errno = errno.ENOENT
                raise e
            return real_stat(path)

        try:
            opinfo = cc_growpart.device_part_info
            cc_growpart.device_part_info = simple_device_part_info
            os.stat = mystat

            resized = cc_growpart.resize_devices(myresizer(), devs + enoent)

            def find(name, res):
                for f in res:
                    if f[0] == name:
                        return f
                return None

            self.assertEqual(cc_growpart.RESIZE.NOCHANGE,
                             find("/dev/XXda1", resized)[1])
            self.assertEqual(cc_growpart.RESIZE.CHANGED,
                             find("/dev/YYda2", resized)[1])
            self.assertEqual(cc_growpart.RESIZE.SKIPPED,
                             find(enoent[0], resized)[1])
            # self.assertEqual(resize_calls,
            #                 [("/dev/XXda", "1", "/dev/XXda1"),
            #                  ("/dev/YYda", "2", "/dev/YYda2")])
        finally:
            cc_growpart.device_part_info = opinfo
            os.stat = real_stat
Esempio n. 3
0
    def test_resize_failed(self, common_mocks, mocker, caplog):
        def _subp_side_effect(value, **kwargs):
            if value[0] == "dmsetup":
                return ("1 dependencies : (vdx1)", )
            elif value[0] == "cryptsetup" and "resize" in value:
                raise subp.ProcessExecutionError()
            return mock.Mock()

        self.m_subp = mocker.patch(
            "cloudinit.config.cc_growpart.subp.subp",
            side_effect=_subp_side_effect,
        )

        info = cc_growpart.resize_devices(self.resizer, ["/fake_encrypted"])
        assert len(info) == 2
        assert info[0][0] == "/dev/vdx1"
        assert info[0][2].startswith("no change necessary")
        assert info[1][0] == "/fake_encrypted"
        assert info[1][1] == "FAILED"
        assert ("Resizing encrypted device (/dev/mapper/fake) failed"
                in info[1][2])
        # Assert we still cleanup
        all_subp_args = list(
            chain(*[args[0][0] for args in self.m_subp.call_args_list]))
        assert "luksKillSlot" in all_subp_args
        self.m_unlink.assert_called_once()
Esempio n. 4
0
 def test_resize_skipped(self, common_mocks, mocker, caplog):
     mocker.patch("pathlib.Path.exists", return_value=False)
     info = cc_growpart.resize_devices(self.resizer, ["/fake_encrypted"])
     assert len(info) == 2
     assert info[1] == (
         "/fake_encrypted",
         "SKIPPED",
         "No encryption keyfile found",
     )
    def test_simple_devices(self):
        # test simple device list
        # this patches out devent2dev, os.stat, and device_part_info
        # so in the end, doesn't test a lot
        devs = ["/dev/XXda1", "/dev/YYda2"]
        devstat_ret = Bunch(st_mode=25008, st_ino=6078, st_dev=5L,
                            st_nlink=1, st_uid=0, st_gid=6, st_size=0,
                            st_atime=0, st_mtime=0, st_ctime=0)
        enoent = ["/dev/NOENT"]
        real_stat = os.stat
        resize_calls = []

        class myresizer(object):
            def resize(self, diskdev, partnum, partdev):
                resize_calls.append((diskdev, partnum, partdev))
                if partdev == "/dev/YYda2":
                    return (1024, 2048)
                return (1024, 1024)  # old size, new size

        def mystat(path):
            if path in devs:
                return devstat_ret
            if path in enoent:
                e = OSError("%s: does not exist" % path)
                e.errno = errno.ENOENT
                raise e
            return real_stat(path)

        try:
            opinfo = cc_growpart.device_part_info
            cc_growpart.device_part_info = simple_device_part_info
            os.stat = mystat

            resized = cc_growpart.resize_devices(myresizer(), devs + enoent)

            def find(name, res):
                for f in res:
                    if f[0] == name:
                        return f
                return None

            self.assertEqual(cc_growpart.RESIZE.NOCHANGE,
                             find("/dev/XXda1", resized)[1])
            self.assertEqual(cc_growpart.RESIZE.CHANGED,
                             find("/dev/YYda2", resized)[1])
            self.assertEqual(cc_growpart.RESIZE.SKIPPED,
                             find(enoent[0], resized)[1])
            # self.assertEqual(resize_calls,
            #                 [("/dev/XXda", "1", "/dev/XXda1"),
            #                  ("/dev/YYda", "2", "/dev/YYda2")])
        finally:
            cc_growpart.device_part_info = opinfo
            os.stat = real_stat
Esempio n. 6
0
    def test_encrypted_but_cryptsetup_not_found(self, common_mocks, mocker,
                                                caplog):
        mocker.patch(
            "cloudinit.config.cc_growpart.subp.which",
            return_value=None,
        )
        info = cc_growpart.resize_devices(self.resizer, ["/fake_encrypted"])

        assert len(info) == 1
        assert "skipped as it is not encrypted" in info[0][2]
        assert "cryptsetup not found" in caplog.text
        self.assert_no_resize_or_cleanup()
Esempio n. 7
0
    def test_resize_when_encrypted(self, common_mocks, caplog):
        info = cc_growpart.resize_devices(self.resizer, ["/fake_encrypted"])
        assert len(info) == 2
        assert info[0][0] == "/dev/vdx1"
        assert info[0][2].startswith("no change necessary")
        assert info[1][0] == "/fake_encrypted"
        assert (info[1][2] ==
                "Successfully resized encrypted volume '/dev/mapper/fake'")
        assert ("/dev/mapper/fake is a mapped device pointing to /dev/dm-1"
                in caplog.text)
        assert "Determined that /dev/dm-1 is encrypted" in caplog.text

        self.assert_resize_and_cleanup()
Esempio n. 8
0
 def test_missing_keydata(self, common_mocks, mocker, caplog):
     # Note that this will be standard behavior after first boot
     # on a system with an encrypted root partition
     mocker.patch("pathlib.Path.open", side_effect=FileNotFoundError())
     info = cc_growpart.resize_devices(self.resizer, ["/fake_encrypted"])
     assert len(info) == 2
     assert info[0][0] == "/dev/vdx1"
     assert info[0][2].startswith("no change necessary")
     assert info[1][0] == "/fake_encrypted"
     assert info[1][1] == "FAILED"
     assert (info[1][2] ==
             "Resizing encrypted device (/dev/mapper/fake) failed: Could "
             "not load encryption key. This is expected if the volume has "
             "been previously resized.")
     self.assert_no_resize_or_cleanup()
Esempio n. 9
0
    def test_dmsetup_not_found(self, common_mocks, mocker, caplog):
        def _subp_side_effect(value, **kwargs):
            if value[0] == "dmsetup":
                raise subp.ProcessExecutionError()

        mocker.patch(
            "cloudinit.config.cc_growpart.subp.subp",
            side_effect=_subp_side_effect,
        )
        info = cc_growpart.resize_devices(self.resizer, ["/fake_encrypted"])
        assert len(info) == 1
        assert info[0][0] == "/fake_encrypted"
        assert info[0][1] == "FAILED"
        assert ("Resizing encrypted device (/dev/mapper/fake) failed"
                in info[0][2])
        self.assert_no_resize_or_cleanup()
Esempio n. 10
0
    def test_unparsable_dmsetup(self, common_mocks, mocker, caplog):
        def _subp_side_effect(value, **kwargs):
            if value[0] == "dmsetup":
                return ("2 dependencies", )
            return mock.Mock()

        mocker.patch(
            "cloudinit.config.cc_growpart.subp.subp",
            side_effect=_subp_side_effect,
        )
        info = cc_growpart.resize_devices(self.resizer, ["/fake_encrypted"])
        assert len(info) == 1
        assert info[0][0] == "/fake_encrypted"
        assert info[0][1] == "FAILED"
        assert ("Resizing encrypted device (/dev/mapper/fake) failed"
                in info[0][2])
        self.assert_no_resize_or_cleanup()
Esempio n. 11
0
 def test_resize_when_unencrypted(self, common_mocks):
     info = cc_growpart.resize_devices(self.resizer, ["/"])
     assert len(info) == 1
     assert info[0][0] == "/"
     assert "encrypted" not in info[0][2]
     self.assert_no_resize_or_cleanup()