def test_mount_order_unsorted(self, mock_exec_sudo):
        # As above, but this is out of order and gets sorted
        # so that root is mounted first (and skips the mkfs testing).
        config = self.load_config_file('lvm_tree_partition_ordering.yaml')
        parsed_graph = config_tree_to_graph(config)
        state = {}

        graph, call_order = create_graph(parsed_graph,
                                         self.fake_default_config,
                                         state)
        state['filesys'] = {
            'mkfs_root': {
                'device': '/dev/loopXp1',
                'fstype': 'xfs'
            },
            'mkfs_var': {
                'device': '/dev/loopXp2',
                'fstype': 'xfs',
            },
            'mkfs_boot': {
                'device': '/dev/loopXp3',
                'fstype': 'vfat',
            },
        }

        for node in call_order:
            if isinstance(node, MountPointNode):
                node.create()
        for node in reversed(call_order):
            if isinstance(node, MountPointNode):
                node.umount()

        # ensure that partitions are mounted in order / -> /boot -> /var
        self.assertListEqual(state['mount_order'], ['/', '/boot', '/var'])

        cmd_sequence = [
            # mount sequence
            mock.call(['mkdir', '-p', '/fake/']),
            mock.call(['mount', '/dev/loopXp1', '/fake/']),
            mock.call(['mkdir', '-p', '/fake/boot']),
            mock.call(['mount', '/dev/loopXp3', '/fake/boot']),
            mock.call(['mkdir', '-p', '/fake/var']),
            mock.call(['mount', '/dev/loopXp2', '/fake/var']),
            # umount sequence
            mock.call(['sync']),
            mock.call(['fstrim', '--verbose', '/fake/var']),
            mock.call(['umount', '/fake/var']),
            mock.call(['sync']),
            # no trim on vfat /fake/boot
            mock.call(['umount', '/fake/boot']),
            mock.call(['sync']),
            mock.call(['fstrim', '--verbose', '/fake/']),
            mock.call(['umount', '/fake/'])
        ]
        self.assertListEqual(mock_exec_sudo.call_args_list, cmd_sequence)
예제 #2
0
    def test_mount_order_unsorted(self, mock_exec_sudo):
        # As above, but this is out of order and gets sorted
        # so that root is mounted first (and skips the mkfs testing).
        config = self.load_config_file('lvm_tree_partition_ordering.yaml')
        parsed_graph = config_tree_to_graph(config)
        state = {}

        graph, call_order = create_graph(parsed_graph,
                                         self.fake_default_config, state)
        state['filesys'] = {
            'mkfs_root': {
                'device': '/dev/loopXp1',
                'fstype': 'xfs'
            },
            'mkfs_var': {
                'device': '/dev/loopXp2',
                'fstype': 'xfs',
            },
            'mkfs_boot': {
                'device': '/dev/loopXp3',
                'fstype': 'vfat',
            },
        }

        for node in call_order:
            if isinstance(node, MountPointNode):
                node.create()
        for node in reversed(call_order):
            if isinstance(node, MountPointNode):
                node.umount()

        # ensure that partitions are mounted in order / -> /boot -> /var
        self.assertListEqual(state['mount_order'], ['/', '/boot', '/var'])

        cmd_sequence = [
            # mount sequence
            mock.call(['mkdir', '-p', '/fake/']),
            mock.call(['mount', '/dev/loopXp1', '/fake/']),
            mock.call(['mkdir', '-p', '/fake/boot']),
            mock.call(['mount', '/dev/loopXp3', '/fake/boot']),
            mock.call(['mkdir', '-p', '/fake/var']),
            mock.call(['mount', '/dev/loopXp2', '/fake/var']),
            # umount sequence
            mock.call(['sync']),
            mock.call(['fstrim', '--verbose', '/fake/var']),
            mock.call(['umount', '/fake/var']),
            mock.call(['sync']),
            # no trim on vfat /fake/boot
            mock.call(['umount', '/fake/boot']),
            mock.call(['sync']),
            mock.call(['fstrim', '--verbose', '/fake/']),
            mock.call(['umount', '/fake/'])
        ]
        self.assertListEqual(mock_exec_sudo.call_args_list, cmd_sequence)
예제 #3
0
    def test_gpt_efi(self, mock_exec_sudo):
        # Test the command-sequence for a GPT/EFI partition setup
        tree = self.load_config_file('gpt_efi.yaml')
        config = config_tree_to_graph(tree)

        state = BlockDeviceState()

        graph, call_order = create_graph(config, self.fake_default_config,
                                         state)

        # Create a fake temp backing file (we check the size of it,
        # etc).
        # TODO(ianw): exec_sudo is generically mocked out, thus the
        # actual creation is mocked out ... but we could do this
        # without root and use parted to create the partitions on this
        # for slightly better testing.  An exercise for another day...
        self.tmp_dir = fixtures.TempDir()
        self.useFixture(self.tmp_dir)
        self.image_path = os.path.join(self.tmp_dir.path, "image.raw")
        # should be sparse...
        image_create(self.image_path, 1024 * 1024 * 1024)
        logger.debug("Temp image in %s", self.image_path)

        # Fake state for the loopback device
        state['blockdev'] = {}
        state['blockdev']['image0'] = {}
        state['blockdev']['image0']['image'] = self.image_path
        state['blockdev']['image0']['device'] = "/dev/loopX"

        for node in call_order:
            if isinstance(node, PartitionNode):
                node.create()

        # check the parted call looks right
        parted_cmd = [
            'sgdisk', self.image_path, '-n', '1:0:+8M', '-t', '1:EF00', '-c',
            '1:ESP', '-n', '2:0:+8M', '-t', '2:EF02', '-c', '2:BSP', '-n',
            '3:0:+1006M', '-t', '3:8300', '-c', '3:Root Part'
        ]
        cmd_sequence = [
            mock.call(parted_cmd),
            mock.call(['sync']),
            mock.call(['kpartx', '-avs', '/dev/loopX'])
        ]
        self.assertEqual(mock_exec_sudo.call_count, len(cmd_sequence))
        mock_exec_sudo.assert_has_calls(cmd_sequence)

        # Check two new partitions appear in state correctly
        self.assertDictEqual(state['blockdev']['ESP'],
                             {'device': '/dev/mapper/loopXp1'})
        self.assertDictEqual(state['blockdev']['BSP'],
                             {'device': '/dev/mapper/loopXp2'})
        self.assertDictEqual(state['blockdev']['Root Part'],
                             {'device': '/dev/mapper/loopXp3'})
예제 #4
0
    def test_gpt_efi(self, mock_exec_sudo):
        # Test the command-sequence for a GPT/EFI partition setup
        tree = self.load_config_file('gpt_efi.yaml')
        config = config_tree_to_graph(tree)

        state = BlockDeviceState()

        graph, call_order = create_graph(config, self.fake_default_config,
                                         state)

        # Create a fake temp backing file (we check the size of it,
        # etc).
        # TODO(ianw): exec_sudo is generically mocked out, thus the
        # actual creation is mocked out ... but we could do this
        # without root and use parted to create the partitions on this
        # for slightly better testing.  An exercise for another day...
        self.tmp_dir = fixtures.TempDir()
        self.useFixture(self.tmp_dir)
        self.image_path = os.path.join(self.tmp_dir.path, "image.raw")
        # should be sparse...
        image_create(self.image_path, 1024 * 1024 * 1024)
        logger.debug("Temp image in %s", self.image_path)

        # Fake state for the loopback device
        state['blockdev'] = {}
        state['blockdev']['image0'] = {}
        state['blockdev']['image0']['image'] = self.image_path
        state['blockdev']['image0']['device'] = "/dev/loopX"

        for node in call_order:
            if isinstance(node, PartitionNode):
                node.create()

        # check the parted call looks right
        parted_cmd = ['sgdisk', self.image_path,
                      '-n', '1:0:+8M', '-t', '1:EF00', '-c', '1:ESP',
                      '-n', '2:0:+8M', '-t', '2:EF02', '-c', '2:BSP',
                      '-n', '3:0:+1006M', '-t', '3:8300', '-c', '3:Root Part']
        cmd_sequence = [
            mock.call(parted_cmd),
            mock.call(['sync']),
            mock.call(['kpartx', '-avs', '/dev/loopX'])
        ]
        self.assertEqual(mock_exec_sudo.call_count, len(cmd_sequence))
        mock_exec_sudo.assert_has_calls(cmd_sequence)

        # Check two new partitions appear in state correctly
        self.assertDictEqual(state['blockdev']['ESP'],
                             {'device': '/dev/mapper/loopXp1'})
        self.assertDictEqual(state['blockdev']['BSP'],
                             {'device': '/dev/mapper/loopXp2'})
        self.assertDictEqual(state['blockdev']['Root Part'],
                             {'device': '/dev/mapper/loopXp3'})
예제 #5
0
    def test_validate_lvs_type(self, mock_exec_sudo):
        # Test the command-sequence for a more complicated LVM setup
        tree = self.load_config_file('lvm_tree_thin_provision.yaml')
        print(tree)
        tree[2]['lvm']['lvs'][0]['type'] = 'thin-pol'

        config = config_tree_to_graph(tree)

        state = BlockDeviceState()

        self.assertRaisesRegex(
            BlockDeviceSetupException,
            "Unsupported type:thin-pol, supported types: thin, thin-pool",
            create_graph,
            config,
            self.fake_default_config,
            state)
예제 #6
0
    def cmd_init(self):
        """Initialize block device setup

        This initializes the block device setup layer. One major task
        is to parse and check the configuration, write it down for
        later examiniation and execution.
        """
        with open(self.params['config'], "rt") as config_fd:
            self.config = yaml.safe_load(config_fd)
        logger.debug("Config before merge [%s]", self.config)
        self.config = config_tree_to_graph(self.config)
        logger.debug("Config before merge [%s]", self.config)
        self._merge_rootfs_params()
        logger.debug("Final config [%s]", self.config)
        # Write the final config
        with open(self.config_json_file_name, "wt") as fd:
            json.dump(self.config, fd)
        logger.info("Wrote final block device config to [%s]",
                    self.config_json_file_name)
예제 #7
0
    def cmd_init(self):
        """Initialize block device setup

        This initializes the block device setup layer. One major task
        is to parse and check the configuration, write it down for
        later examiniation and execution.
        """
        with open(self.params['config'], "rt") as config_fd:
            self.config = yaml.safe_load(config_fd)
        logger.debug("Config before merge [%s]", self.config)
        self.config = config_tree_to_graph(self.config)
        logger.debug("Config before merge [%s]", self.config)
        self._merge_into_config()
        logger.debug("Final config [%s]", self.config)
        # Write the final config
        with open(self.config_json_file_name, "wt") as fd:
            json.dump(self.config, fd)
        logger.info("Wrote final block device config to [%s]",
                    self.config_json_file_name)
예제 #8
0
    def test_lvm_thin_provision(self, mock_exec_sudo):
        # Test the command-sequence for a more complicated LVM setup
        tree = self.load_config_file('lvm_tree_thin_provision.yaml')
        config = config_tree_to_graph(tree)

        state = BlockDeviceState()

        graph, call_order = create_graph(config, self.fake_default_config,
                                         state)

        # Fake state for the two PV's specified by this config
        state['blockdev'] = {}
        state['blockdev']['root'] = {}
        state['blockdev']['root']['device'] = '/dev/fake/root'

        for node in call_order:
            # XXX: This has not mocked out the "lower" layers of
            # creating the devices, which we're assuming works OK, nor
            # the upper layers.
            if isinstance(node, (LVMNode, PvsNode,
                                 VgsNode, LvsNode)):
                # only the LVMNode actually does anything here...
                node.create()

        # ensure the sequence of calls correctly setup the devices
        cmd_sequence = [
            # create the pv's on the faked out block devices
            mock.call(['pvcreate', '/dev/fake/root', '--force']),
            # create a volume called "vg" out of these two pv's
            mock.call(['vgcreate', 'vg', '/dev/fake/root', '--force']),
            mock.call(['lvcreate', '--name', 'lv_thinpool',
                      '--type', 'thin-pool', '-L', '2936012800B', 'vg']),
            # create a bunch of lv's on vg using the pool
            mock.call(['lvcreate', '--name', 'lv_root', '--type', 'thin',
                      '--thin-pool', 'lv_thinpool', '-V', '1887436800B',
                       'vg']),
            mock.call(['lvcreate', '--name', 'lv_tmp', '--type', 'thin',
                      '--thin-pool', 'lv_thinpool', '-V', '104857600B', 'vg']),
            mock.call(['lvcreate', '--name', 'lv_var', '--type', 'thin',
                      '--thin-pool', 'lv_thinpool', '-V', '524288000B', 'vg']),
            mock.call(['lvcreate', '--name', 'lv_log', '--type', 'thin',
                      '--thin-pool', 'lv_thinpool', '-V', '104857600B', 'vg']),
            mock.call(['lvcreate', '--name', 'lv_audit', '--type', 'thin',
                      '--thin-pool', 'lv_thinpool', '-V', '104857600B', 'vg']),
            mock.call(['lvcreate', '--name', 'lv_home', '--type', 'thin',
                      '--thin-pool', 'lv_thinpool', '-V', '209715200B', 'vg'])]

        self.assertEqual(mock_exec_sudo.call_count, len(cmd_sequence))
        mock_exec_sudo.assert_has_calls(cmd_sequence)

        # Ensure the correct LVM state was preserved
        blockdev_state = {
            'root': {'device': '/dev/fake/root'},
            'lv_thinpool': {
                'vgs': 'vg',
                'size': '2800MiB',
                'extents': None,
                'opts': None,
                'device': '/dev/mapper/vg-lv_thinpool'
            },
            'lv_root': {
                'vgs': 'vg',
                'size': '1800MiB',
                'extents': None,
                'opts': None,
                'device': '/dev/mapper/vg-lv_root'
            },
            'lv_tmp': {
                'vgs': 'vg',
                'size': '100MiB',
                'extents': None,
                'opts': None,
                'device': '/dev/mapper/vg-lv_tmp'
            },
            'lv_var': {
                'vgs': 'vg',
                'size': '500MiB',
                'extents': None,
                'opts': None,
                'device': '/dev/mapper/vg-lv_var'
            },
            'lv_log': {
                'vgs': 'vg',
                'size': '100MiB',
                'extents': None,
                'opts': None,
                'device': '/dev/mapper/vg-lv_log'
            },
            'lv_audit': {
                'vgs': 'vg',
                'size': '100MiB',
                'extents': None,
                'opts': None,
                'device': '/dev/mapper/vg-lv_audit'
            },
            'lv_home': {
                'vgs': 'vg',
                'size': '200MiB',
                'extents': None,
                'opts': None,
                'device': '/dev/mapper/vg-lv_home'
            }
        }

        self.assertDictEqual(state['blockdev'], blockdev_state)
예제 #9
0
    def test_lvm_multiple_partitions(self):
        # Test the command-sequence for several partitions, one containing
        # volumes on it
        tree = self.load_config_file('lvm_tree_multiple_partitions.yaml')
        config = config_tree_to_graph(tree)

        state = BlockDeviceState()

        graph, call_order = create_graph(config, self.fake_default_config,
                                         state)

        # Fake state for the partitions on this config
        state['blockdev'] = {}
        state['blockdev']['image0'] = {}
        state['blockdev']['image0']['device'] = '/dev/fake/image0'
        state['blockdev']['image0']['image'] = 'image'
        state['blockdev']['root'] = {}
        state['blockdev']['root']['device'] = '/dev/fake/root'
        state['blockdev']['ESP'] = {}
        state['blockdev']['ESP']['device'] = '/dev/fake/ESP'
        state['blockdev']['BSP'] = {}
        state['blockdev']['BSP']['device'] = '/dev/fake/BSP'

        #
        # Creation test
        #

        # We mock out the following exec_sudo and other related calls
        # calls for the layers we are testing.
        exec_sudo_lvm = 'diskimage_builder.block_device.level1.lvm.exec_sudo'
        exec_sudo_part = ('diskimage_builder.block_device.'
                          'level1.partitioning.exec_sudo')
        exec_sudo_loop = ('diskimage_builder.block_device.'
                          'level0.localloop.exec_sudo')
        image_create = ('diskimage_builder.block_device.level0.'
                        'localloop.LocalLoopNode.create')
        size_of_block = ('diskimage_builder.block_device.level1.'
                         'partitioning.Partitioning._size_of_block_dev')
        create_mbr = ('diskimage_builder.block_device.level1.'
                      'partitioning.Partitioning._create_mbr')

        manager = mock.MagicMock()
        with mock.patch(exec_sudo_lvm) as mock_sudo_lvm, \
             mock.patch(exec_sudo_part) as mock_sudo_part, \
             mock.patch(exec_sudo_loop) as mock_sudo_loop, \
             mock.patch(image_create) as mock_image_create, \
             mock.patch(size_of_block) as mock_size_of_block, \
             mock.patch(create_mbr) as mock_create_mbr:

            manager.attach_mock(mock_sudo_lvm, 'sudo_lvm')
            manager.attach_mock(mock_sudo_part, 'sudo_part')
            manager.attach_mock(mock_sudo_loop, 'sudo_loop')
            manager.attach_mock(mock_image_create, 'image_create')
            manager.attach_mock(mock_size_of_block, 'size_of_block')
            manager.attach_mock(mock_create_mbr, 'create_mbr')

            for node in call_order:
                # We're just keeping this to the partition setup and
                # LVM creation; i.e. skipping mounting, mkfs, etc.
                if isinstance(node, (LVMNode, PvsNode,
                                     VgsNode, LvsNode,
                                     LocalLoopNode, PartitionNode)):
                    node.create()
                else:
                    logger.debug("Skipping node for test: %s", node)

            cmd_sequence = [
                # create the underlying block device
                mock.call.image_create(),
                mock.call.size_of_block('image'),
                # write out partition table
                mock.call.create_mbr(),
                # now mount partitions
                mock.call.sudo_part(['sync']),
                mock.call.sudo_part(['kpartx', '-uvs', '/dev/fake/image0']),
                # now create lvm environment
                mock.call.sudo_lvm(['pvcreate', '/dev/fake/root', '--force']),
                mock.call.sudo_lvm(
                    ['vgcreate', 'vg', '/dev/fake/root', '--force']),
                mock.call.sudo_lvm(
                    ['lvcreate', '--name', 'lv_root', '-l', '28%VG', 'vg']),
                mock.call.sudo_lvm(
                    ['lvcreate', '--name', 'lv_tmp', '-l', '4%VG', 'vg']),
                mock.call.sudo_lvm(
                    ['lvcreate', '--name', 'lv_var', '-l', '40%VG', 'vg']),
                mock.call.sudo_lvm(
                    ['lvcreate', '--name', 'lv_log', '-l', '23%VG', 'vg']),
                mock.call.sudo_lvm(
                    ['lvcreate', '--name', 'lv_audit', '-l', '4%VG', 'vg']),
                mock.call.sudo_lvm(
                    ['lvcreate', '--name', 'lv_home', '-l', '1%VG', 'vg']),
            ]
            manager.assert_has_calls(cmd_sequence)

        #
        # Umount/cleanup test
        #
        manager = mock.MagicMock()
        with mock.patch(exec_sudo_lvm) as mock_sudo_lvm, \
             mock.patch(exec_sudo_part) as mock_sudo_part, \
             mock.patch(exec_sudo_loop) as mock_sudo_loop:

            manager.attach_mock(mock_sudo_lvm, 'sudo_lvm')
            manager.attach_mock(mock_sudo_part, 'sudo_part')
            manager.attach_mock(mock_sudo_loop, 'sudo_loop')

            def run_it(phase):
                reverse_order = reversed(call_order)
                for node in reverse_order:
                    if isinstance(node, (LVMNode, PvsNode,
                                         VgsNode, LvsNode,
                                         LocalLoopNode, PartitionNode)):
                        getattr(node, phase)()
                    else:
                        logger.debug("Skipping node for test: %s", node)

            run_it('umount')
            run_it('cleanup')

            cmd_sequence = [
                # deactivate LVM first
                mock.call.sudo_lvm(['lvchange', '-an', '/dev/vg/lv_root']),
                mock.call.sudo_lvm(['lvchange', '-an', '/dev/vg/lv_tmp']),
                mock.call.sudo_lvm(['lvchange', '-an', '/dev/vg/lv_var']),
                mock.call.sudo_lvm(['lvchange', '-an', '/dev/vg/lv_log']),
                mock.call.sudo_lvm(['lvchange', '-an', '/dev/vg/lv_audit']),
                mock.call.sudo_lvm(['lvchange', '-an', '/dev/vg/lv_home']),
                mock.call.sudo_lvm(['vgchange', '-an', 'vg']),
                mock.call.sudo_lvm(['udevadm', 'settle']),
                # now remove partitions (note has to happen after lvm removal)
                mock.call.sudo_part(['kpartx', '-d', '/dev/fake/image0']),
                # now remove loopback device
                mock.call.sudo_loop(['losetup', '-d', '/dev/fake/image0']),
                # now final LVM cleanup call
                mock.call.sudo_lvm(['pvscan', '--cache']),
            ]

            manager.assert_has_calls(cmd_sequence)
예제 #10
0
 def test_lvm_tree_to_graph(self):
     # equivalence of tree-based to graph-based config
     tree = self.load_config_file('lvm_tree.yaml')
     graph = self.load_config_file('lvm_graph.yaml')
     parsed_graph = config_tree_to_graph(tree)
     self.assertCountEqual(parsed_graph, graph)
예제 #11
0
    def test_lvm_spanned_vg(self):

        # Test when a volume group spans some partitions

        tree = self.load_config_file('lvm_tree_spanned_vg.yaml')
        config = config_tree_to_graph(tree)

        state = BlockDeviceState()

        graph, call_order = create_graph(config, self.fake_default_config,
                                         state)

        # XXX: todo; test call_order.  Make sure PV's come before, VG;
        # VG before LV, and that mounts/etc happen afterwards.

        # Fake state for the two PV's specified by this config
        state['blockdev'] = {}
        state['blockdev']['root'] = {}
        state['blockdev']['root']['device'] = '/dev/fake/root'
        state['blockdev']['data1'] = {}
        state['blockdev']['data1']['device'] = '/dev/fake/data1'
        state['blockdev']['data2'] = {}
        state['blockdev']['data2']['device'] = '/dev/fake/data2'

        # We mock patch this ... it's just a little long!
        exec_sudo = 'diskimage_builder.block_device.level1.lvm.exec_sudo'

        #
        # Creation test
        #
        with mock.patch(exec_sudo) as mock_exec_sudo:

            for node in call_order:
                # XXX: This has not mocked out the "lower" layers of
                # creating the devices, which we're assuming works OK, nor
                # the upper layers.
                if isinstance(node, (LVMNode, PvsNode, VgsNode, LvsNode)):
                    # only the LVMNode actually does anything here...
                    node.create()

            # ensure the sequence of calls correctly setup the devices
            cmd_sequence = [
                # create the pv's on the faked out block devices
                mock.call(['pvcreate', '/dev/fake/root', '--force']),
                mock.call(['pvcreate', '/dev/fake/data1', '--force']),
                mock.call(['pvcreate', '/dev/fake/data2', '--force']),
                # create a root and a data volume, with the data volume
                # spanning data1 & data2
                mock.call(['vgcreate', 'vg_root',
                           '/dev/fake/root', '--force']),
                mock.call(['vgcreate', 'vg_data',
                           '/dev/fake/data1', '/dev/fake/data2', '--force']),
                # create root and data volume
                mock.call(['lvcreate', '--name', 'lv_root',
                           '-L', '1799356416B', 'vg_root']),
                mock.call(['lvcreate', '--name', 'lv_data',
                           '-L', '1996488704B', 'vg_data'])
            ]

            self.assertListEqual(mock_exec_sudo.call_args_list,
                                 cmd_sequence)

        with mock.patch(exec_sudo) as mock_exec_sudo, \
             mock.patch('tempfile.NamedTemporaryFile') as mock_temp, \
             mock.patch('os.unlink'):

            # see above ...
            tempfiles = []

            def new_tempfile(*args, **kwargs):
                n = '/tmp/files%s' % len(tempfiles)
                r = mock.Mock()
                r.configure_mock(name=n)
                tempfiles.append(n)
                return r
            mock_temp.side_effect = new_tempfile

            def run_it(phase):
                reverse_order = reversed(call_order)
                for node in reverse_order:
                    if isinstance(node, (LVMNode, PvsNode, VgsNode, LvsNode)):
                        getattr(node, phase)()
                    else:
                        logger.debug("Skipping node for test: %s", node)

            run_it('umount')
            run_it('cleanup')

            cmd_sequence = [
                # deactivate lv's
                mock.call(['lvchange', '-an', '/dev/vg_root/lv_root']),
                mock.call(['lvchange', '-an', '/dev/vg_data/lv_data']),

                # deactivate vg's
                mock.call(['vgchange', '-an', 'vg_root']),
                mock.call(['vgchange', '-an', 'vg_data']),

                mock.call(['udevadm', 'settle']),
                mock.call(['pvscan', '--cache']),
            ]

            self.assertListEqual(mock_exec_sudo.call_args_list, cmd_sequence)
예제 #12
0
 def test_lvm_tree_to_graph(self):
     # equivalence of tree-based to graph-based config
     tree = self.load_config_file('lvm_tree.yaml')
     graph = self.load_config_file('lvm_graph.yaml')
     parsed_graph = config_tree_to_graph(tree)
     self.assertItemsEqual(parsed_graph, graph)
예제 #13
0
 def test_deep_tree(self):
     tree = self.load_config_file('deep_tree.yaml')
     graph = self.load_config_file('deep_graph.yaml')
     parsed_graph = config_tree_to_graph(tree)
     self.assertItemsEqual(parsed_graph, graph)
예제 #14
0
 def test_multipart_tree(self):
     tree = self.load_config_file('multiple_partitions_tree.yaml')
     graph = self.load_config_file('multiple_partitions_graph.yaml')
     parsed_graph = config_tree_to_graph(tree)
     logger.debug(parsed_graph)
     self.assertItemsEqual(parsed_graph, graph)
예제 #15
0
 def test_deep_tree(self):
     tree = self.load_config_file('deep_tree.yaml')
     graph = self.load_config_file('deep_graph.yaml')
     parsed_graph = config_tree_to_graph(tree)
     self.assertItemsEqual(parsed_graph, graph)
예제 #16
0
 def test_graph(self):
     graph = self.load_config_file('simple_graph.yaml')
     parsed_graph = config_tree_to_graph(graph)
     self.assertItemsEqual(parsed_graph, graph)
예제 #17
0
    def test_lvm_multi_pv(self, mock_exec_sudo):
        # Test the command-sequence for a more complicated LVM setup
        tree = self.load_config_file('lvm_tree_multiple_pv.yaml')
        config = config_tree_to_graph(tree)

        state = BlockDeviceState()

        graph, call_order = create_graph(config, self.fake_default_config,
                                         state)

        # XXX: todo; test call_order.  Make sure PV's come before, VG;
        # VG before LV, and that mounts/etc happen afterwards.

        # Fake state for the two PV's specified by this config
        state['blockdev'] = {}
        state['blockdev']['root'] = {}
        state['blockdev']['root']['device'] = '/dev/fake/root'
        state['blockdev']['data'] = {}
        state['blockdev']['data']['device'] = '/dev/fake/data'

        for node in call_order:
            # XXX: This has not mocked out the "lower" layers of
            # creating the devices, which we're assuming works OK, nor
            # the upper layers.
            if isinstance(node, (LVMNode, PvsNode,
                                 VgsNode, LvsNode)):
                # only the LVMNode actually does anything here...
                node.create()

        # ensure the sequence of calls correctly setup the devices
        cmd_sequence = [
            # create the pv's on the faked out block devices
            mock.call(['pvcreate', '/dev/fake/root', '--force']),
            mock.call(['pvcreate', '/dev/fake/data', '--force']),
            # create a volume called "vg" out of these two pv's
            mock.call(['vgcreate', 'vg',
                       '/dev/fake/root', '/dev/fake/data', '--force']),
            # create a bunch of lv's on vg
            mock.call(['lvcreate', '--name', 'lv_root', '-L', '1800M', 'vg']),
            mock.call(['lvcreate', '--name', 'lv_tmp', '-L', '100M', 'vg']),
            mock.call(['lvcreate', '--name', 'lv_var', '-L', '500M', 'vg']),
            mock.call(['lvcreate', '--name', 'lv_log', '-L', '100M', 'vg']),
            mock.call(['lvcreate', '--name', 'lv_audit', '-L', '100M', 'vg']),
            mock.call(['lvcreate', '--name', 'lv_home', '-L', '200M', 'vg'])]

        self.assertEqual(mock_exec_sudo.call_count, len(cmd_sequence))
        mock_exec_sudo.assert_has_calls(cmd_sequence)

        # Ensure the correct LVM state was preserved
        blockdev_state = {
            'data': {'device': '/dev/fake/data'},
            'root': {'device': '/dev/fake/root'},
            'lv_audit': {
                'device': '/dev/mapper/vg-lv_audit',
                'extents': None,
                'opts': None,
                'size': '100M',
                'vgs': 'vg'
            },
            'lv_home': {
                'device': '/dev/mapper/vg-lv_home',
                'extents': None,
                'opts': None,
                'size': '200M',
                'vgs': 'vg'
            },
            'lv_log': {
                'device': '/dev/mapper/vg-lv_log',
                'extents': None,
                'opts': None,
                'size': '100M',
                'vgs': 'vg'
            },
            'lv_root': {
                'device': '/dev/mapper/vg-lv_root',
                'extents': None,
                'opts': None,
                'size': '1800M',
                'vgs': 'vg'
            },
            'lv_tmp': {
                'device': '/dev/mapper/vg-lv_tmp',
                'extents': None,
                'opts': None,
                'size': '100M',
                'vgs': 'vg'
            },
            'lv_var': {
                'device': '/dev/mapper/vg-lv_var',
                'extents': None,
                'opts': None,
                'size': '500M',
                'vgs': 'vg'
            },
        }

        # state.debug_dump()
        self.assertDictEqual(state['blockdev'], blockdev_state)
예제 #18
0
    def test_lvm_multiple_partitions(self):
        # Test the command-sequence for several partitions, one containing
        # volumes on it
        tree = self.load_config_file('lvm_tree_multiple_partitions.yaml')
        config = config_tree_to_graph(tree)

        state = BlockDeviceState()

        graph, call_order = create_graph(config, self.fake_default_config,
                                         state)

        # Fake state for the partitions on this config
        state['blockdev'] = {}
        state['blockdev']['image0'] = {}
        state['blockdev']['image0']['device'] = '/dev/fake/image0'
        state['blockdev']['image0']['image'] = 'image'
        state['blockdev']['root'] = {}
        state['blockdev']['root']['device'] = '/dev/fake/root'
        state['blockdev']['ESP'] = {}
        state['blockdev']['ESP']['device'] = '/dev/fake/ESP'
        state['blockdev']['BSP'] = {}
        state['blockdev']['BSP']['device'] = '/dev/fake/BSP'

        #
        # Creation test
        #

        # We mock out the following exec_sudo and other related calls
        # calls for the layers we are testing.
        exec_sudo_lvm = 'diskimage_builder.block_device.level1.lvm.exec_sudo'
        exec_sudo_part = ('diskimage_builder.block_device.'
                          'level1.partitioning.exec_sudo')
        exec_sudo_loop = ('diskimage_builder.block_device.'
                          'level0.localloop.exec_sudo')
        image_create = ('diskimage_builder.block_device.level0.'
                        'localloop.LocalLoopNode.create')
        size_of_block = ('diskimage_builder.block_device.level1.'
                         'partitioning.Partitioning._size_of_block_dev')
        create_mbr = ('diskimage_builder.block_device.level1.'
                      'partitioning.Partitioning._create_mbr')

        manager = mock.MagicMock()
        with mock.patch(exec_sudo_lvm) as mock_sudo_lvm, \
             mock.patch(exec_sudo_part) as mock_sudo_part, \
             mock.patch(exec_sudo_loop) as mock_sudo_loop, \
             mock.patch(image_create) as mock_image_create, \
             mock.patch(size_of_block) as mock_size_of_block, \
             mock.patch(create_mbr) as mock_create_mbr:

            manager.attach_mock(mock_sudo_lvm, 'sudo_lvm')
            manager.attach_mock(mock_sudo_part, 'sudo_part')
            manager.attach_mock(mock_sudo_loop, 'sudo_loop')
            manager.attach_mock(mock_image_create, 'image_create')
            manager.attach_mock(mock_size_of_block, 'size_of_block')
            manager.attach_mock(mock_create_mbr, 'create_mbr')

            for node in call_order:
                # We're just keeping this to the partition setup and
                # LVM creation; i.e. skipping mounting, mkfs, etc.
                if isinstance(node, (LVMNode, PvsNode,
                                     VgsNode, LvsNode,
                                     LocalLoopNode, PartitionNode)):
                    node.create()
                else:
                    logger.debug("Skipping node for test: %s", node)

            cmd_sequence = [
                # create the underlying block device
                mock.call.image_create(),
                mock.call.size_of_block('image'),
                # write out partition table
                mock.call.create_mbr(),
                # now mount partitions
                mock.call.sudo_part(['sync']),
                mock.call.sudo_part(['kpartx', '-avs', '/dev/fake/image0']),
                # now create lvm environment
                mock.call.sudo_lvm(['pvcreate', '/dev/fake/root', '--force']),
                mock.call.sudo_lvm(
                    ['vgcreate', 'vg', '/dev/fake/root', '--force']),
                mock.call.sudo_lvm(
                    ['lvcreate', '--name', 'lv_root', '-l', '28%VG', 'vg']),
                mock.call.sudo_lvm(
                    ['lvcreate', '--name', 'lv_tmp', '-l', '4%VG', 'vg']),
                mock.call.sudo_lvm(
                    ['lvcreate', '--name', 'lv_var', '-l', '40%VG', 'vg']),
                mock.call.sudo_lvm(
                    ['lvcreate', '--name', 'lv_log', '-l', '23%VG', 'vg']),
                mock.call.sudo_lvm(
                    ['lvcreate', '--name', 'lv_audit', '-l', '4%VG', 'vg']),
                mock.call.sudo_lvm(
                    ['lvcreate', '--name', 'lv_home', '-l', '1%VG', 'vg']),
            ]
            manager.assert_has_calls(cmd_sequence)

        #
        # Umount/cleanup test
        #
        manager = mock.MagicMock()
        with mock.patch(exec_sudo_lvm) as mock_sudo_lvm, \
             mock.patch(exec_sudo_part) as mock_sudo_part, \
             mock.patch(exec_sudo_loop) as mock_sudo_loop:

            manager.attach_mock(mock_sudo_lvm, 'sudo_lvm')
            manager.attach_mock(mock_sudo_part, 'sudo_part')
            manager.attach_mock(mock_sudo_loop, 'sudo_loop')

            def run_it(phase):
                reverse_order = reversed(call_order)
                for node in reverse_order:
                    if isinstance(node, (LVMNode, PvsNode,
                                         VgsNode, LvsNode,
                                         LocalLoopNode, PartitionNode)):
                        getattr(node, phase)()
                    else:
                        logger.debug("Skipping node for test: %s", node)

            run_it('umount')
            run_it('cleanup')

            cmd_sequence = [
                # deactivate LVM first
                mock.call.sudo_lvm(['lvchange', '-an', '/dev/vg/lv_root']),
                mock.call.sudo_lvm(['lvchange', '-an', '/dev/vg/lv_tmp']),
                mock.call.sudo_lvm(['lvchange', '-an', '/dev/vg/lv_var']),
                mock.call.sudo_lvm(['lvchange', '-an', '/dev/vg/lv_log']),
                mock.call.sudo_lvm(['lvchange', '-an', '/dev/vg/lv_audit']),
                mock.call.sudo_lvm(['lvchange', '-an', '/dev/vg/lv_home']),
                mock.call.sudo_lvm(['vgchange', '-an', 'vg']),
                mock.call.sudo_lvm(['udevadm', 'settle']),
                # now remove partitions (note has to happen after lvm removal)
                mock.call.sudo_part(['kpartx', '-d', '/dev/fake/image0']),
                # now remove loopback device
                mock.call.sudo_loop(['losetup', '-d', '/dev/fake/image0']),
                # now final LVM cleanup call
                mock.call.sudo_lvm(['pvscan', '--cache']),
            ]

            manager.assert_has_calls(cmd_sequence)
예제 #19
0
    def test_lvm_multi_pv(self, mock_exec_sudo):
        # Test the command-sequence for a more complicated LVM setup
        tree = self.load_config_file('lvm_tree_multiple_pv.yaml')
        config = config_tree_to_graph(tree)

        state = BlockDeviceState()

        graph, call_order = create_graph(config, self.fake_default_config,
                                         state)

        # XXX: todo; test call_order.  Make sure PV's come before, VG;
        # VG before LV, and that mounts/etc happen afterwards.

        # Fake state for the two PV's specified by this config
        state['blockdev'] = {}
        state['blockdev']['root'] = {}
        state['blockdev']['root']['device'] = '/dev/fake/root'
        state['blockdev']['data'] = {}
        state['blockdev']['data']['device'] = '/dev/fake/data'

        for node in call_order:
            # XXX: This has not mocked out the "lower" layers of
            # creating the devices, which we're assuming works OK, nor
            # the upper layers.
            if isinstance(node, (LVMNode, PvsNode,
                                 VgsNode, LvsNode)):
                # only the LVMNode actually does anything here...
                node.create()

        # ensure the sequence of calls correctly setup the devices
        cmd_sequence = [
            # create the pv's on the faked out block devices
            mock.call(['pvcreate', '/dev/fake/root', '--force']),
            mock.call(['pvcreate', '/dev/fake/data', '--force']),
            # create a volume called "vg" out of these two pv's
            mock.call(['vgcreate', 'vg',
                       '/dev/fake/root', '/dev/fake/data', '--force']),
            # create a bunch of lv's on vg
            mock.call(['lvcreate', '--name', 'lv_root', '-L', '1799356416B',
                       'vg']),
            mock.call(['lvcreate', '--name', 'lv_tmp', '-L', '96468992B',
                       'vg']),
            mock.call(['lvcreate', '--name', 'lv_var', '-L', '499122176B',
                       'vg']),
            mock.call(['lvcreate', '--name', 'lv_log', '-L', '96468992B',
                       'vg']),
            mock.call(['lvcreate', '--name', 'lv_audit', '-L', '96468992B',
                       'vg']),
            mock.call(['lvcreate', '--name', 'lv_home', '-L', '197132288B',
                       'vg'])]

        self.assertEqual(mock_exec_sudo.call_count, len(cmd_sequence))
        mock_exec_sudo.assert_has_calls(cmd_sequence)

        # Ensure the correct LVM state was preserved
        blockdev_state = {
            'data': {'device': '/dev/fake/data'},
            'root': {'device': '/dev/fake/root'},
            'lv_audit': {
                'device': '/dev/mapper/vg-lv_audit',
                'extents': None,
                'opts': None,
                'size': '100M',
                'vgs': 'vg'
            },
            'lv_home': {
                'device': '/dev/mapper/vg-lv_home',
                'extents': None,
                'opts': None,
                'size': '200M',
                'vgs': 'vg'
            },
            'lv_log': {
                'device': '/dev/mapper/vg-lv_log',
                'extents': None,
                'opts': None,
                'size': '100M',
                'vgs': 'vg'
            },
            'lv_root': {
                'device': '/dev/mapper/vg-lv_root',
                'extents': None,
                'opts': None,
                'size': '1800M',
                'vgs': 'vg'
            },
            'lv_tmp': {
                'device': '/dev/mapper/vg-lv_tmp',
                'extents': None,
                'opts': None,
                'size': '100M',
                'vgs': 'vg'
            },
            'lv_var': {
                'device': '/dev/mapper/vg-lv_var',
                'extents': None,
                'opts': None,
                'size': '500M',
                'vgs': 'vg'
            },
        }

        # state.debug_dump()
        self.assertDictEqual(state['blockdev'], blockdev_state)
예제 #20
0
 def test_simple_tree(self):
     tree = self.load_config_file('simple_tree.yaml')
     graph = self.load_config_file('simple_graph.yaml')
     parsed_graph = config_tree_to_graph(tree)
     self.assertCountEqual(parsed_graph, graph)
예제 #21
0
    def test_lvm_multi_pv_vg(self):
        # Test the command-sequence for a more complicated LVM setup
        tree = self.load_config_file('lvm_tree_multiple_pv_vg.yaml')
        config = config_tree_to_graph(tree)

        state = BlockDeviceState()

        graph, call_order = create_graph(config, self.fake_default_config,
                                         state)

        # XXX: todo; test call_order.  Make sure PV's come before, VG;
        # VG before LV, and that mounts/etc happen afterwards.

        # Fake state for the two PV's specified by this config
        state['blockdev'] = {}
        state['blockdev']['root'] = {}
        state['blockdev']['root']['device'] = '/dev/fake/root'
        state['blockdev']['data'] = {}
        state['blockdev']['data']['device'] = '/dev/fake/data'

        # We mock patch this ... it's just a little long!
        exec_sudo = 'diskimage_builder.block_device.level1.lvm.exec_sudo'

        #
        # Creation test
        #
        with mock.patch(exec_sudo) as mock_exec_sudo:

            for node in call_order:
                # XXX: This has not mocked out the "lower" layers of
                # creating the devices, which we're assuming works OK, nor
                # the upper layers.
                if isinstance(node, (LVMNode, PvsNode,
                                     VgsNode, LvsNode)):
                    # only the PvsNode actually does anything here...
                    node.create()

            # ensure the sequence of calls correctly setup the devices
            cmd_sequence = [
                # create the pv's on the faked out block devices
                mock.call(['pvcreate', '/dev/fake/root', '--force']),
                mock.call(['pvcreate', '/dev/fake/data', '--force']),
                # create a volume called "vg" out of these two pv's
                mock.call(['vgcreate', 'vg1',
                           '/dev/fake/root', '--force']),
                mock.call(['vgcreate', 'vg2',
                           '/dev/fake/data', '--force']),
                # create a bunch of lv's on vg
                mock.call(['lvcreate', '--name', 'lv_root',
                           '-L', '1800M', 'vg1']),
                mock.call(['lvcreate', '--name', 'lv_tmp',
                           '-L', '100M', 'vg1']),
                mock.call(['lvcreate', '--name', 'lv_var',
                           '-L', '500M', 'vg2']),
                mock.call(['lvcreate', '--name', 'lv_log',
                           '-L', '100M', 'vg2']),
                mock.call(['lvcreate', '--name', 'lv_audit',
                           '-L', '100M', 'vg2']),
                mock.call(['lvcreate', '--name', 'lv_home',
                           '-L', '200M', 'vg2'])]

            self.assertListEqual(mock_exec_sudo.call_args_list,
                                 cmd_sequence)

            # Ensure the correct LVM state was preserved
            blockdev_state = {
                'data': {'device': '/dev/fake/data'},
                'root': {'device': '/dev/fake/root'},
                'lv_audit': {
                    'device': '/dev/mapper/vg2-lv_audit',
                    'extents': None,
                    'opts': None,
                    'size': '100M',
                    'vgs': 'vg2'
                },
                'lv_home': {
                    'device': '/dev/mapper/vg2-lv_home',
                    'extents': None,
                    'opts': None,
                    'size': '200M',
                    'vgs': 'vg2'
                },
                'lv_log': {
                    'device': '/dev/mapper/vg2-lv_log',
                    'extents': None,
                    'opts': None,
                    'size': '100M',
                    'vgs': 'vg2'
                },
                'lv_root': {
                    'device': '/dev/mapper/vg1-lv_root',
                    'extents': None,
                    'opts': None,
                    'size': '1800M',
                    'vgs': 'vg1'
                },
                'lv_tmp': {
                    'device': '/dev/mapper/vg1-lv_tmp',
                    'extents': None,
                    'opts': None,
                    'size': '100M',
                    'vgs': 'vg1'
                },
                'lv_var': {
                    'device': '/dev/mapper/vg2-lv_var',
                    'extents': None,
                    'opts': None,
                    'size': '500M',
                    'vgs': 'vg2'
                },
            }

            # state.debug_dump()
            self.assertDictEqual(state['blockdev'], blockdev_state)

        #
        # Umount test
        #
        with mock.patch(exec_sudo) as mock_exec_sudo, \
             mock.patch('tempfile.NamedTemporaryFile') as mock_temp, \
             mock.patch('os.unlink'):

            # each call to tempfile.NamedTemporaryFile will return a
            # new mock with a unique filename, which we store in
            # tempfiles
            tempfiles = []

            def new_tempfile(*args, **kwargs):
                n = '/tmp/files%s' % len(tempfiles)
                # trap! note mock.Mock(name = n) doesn't work like you
                # think it would, since mock has a name attribute.
                # That's why we override it with the configure_mock
                # (this is mentioned in mock documentation if you read
                # it :)
                r = mock.Mock()
                r.configure_mock(name=n)
                tempfiles.append(n)
                return r
            mock_temp.side_effect = new_tempfile

            def run_it(phase):
                reverse_order = reversed(call_order)
                for node in reverse_order:
                    if isinstance(node, (LVMNode, PvsNode, VgsNode, LvsNode)):
                        getattr(node, phase)()
                    else:
                        logger.debug("Skipping node for test: %s", node)

            run_it('umount')
            run_it('cleanup')

            cmd_sequence = [
                # delete the lv's
                mock.call(['lvchange', '-an', '/dev/vg1/lv_root']),
                mock.call(['lvchange', '-an', '/dev/vg1/lv_tmp']),
                mock.call(['lvchange', '-an', '/dev/vg2/lv_var']),
                mock.call(['lvchange', '-an', '/dev/vg2/lv_log']),
                mock.call(['lvchange', '-an', '/dev/vg2/lv_audit']),
                mock.call(['lvchange', '-an', '/dev/vg2/lv_home']),
                # delete the vg's
                mock.call(['vgchange', '-an', 'vg1']),
                mock.call(['vgchange', '-an', 'vg2']),
                mock.call(['udevadm', 'settle']),
                mock.call(['pvscan', '--cache']),
            ]

            self.assertListEqual(mock_exec_sudo.call_args_list, cmd_sequence)
예제 #22
0
 def test_graph(self):
     graph = self.load_config_file('simple_graph.yaml')
     parsed_graph = config_tree_to_graph(graph)
     self.assertItemsEqual(parsed_graph, graph)
예제 #23
0
    def test_lvm_multi_pv_vg(self):
        # Test the command-sequence for a more complicated LVM setup
        tree = self.load_config_file('lvm_tree_multiple_pv_vg.yaml')
        config = config_tree_to_graph(tree)

        state = BlockDeviceState()

        graph, call_order = create_graph(config, self.fake_default_config,
                                         state)

        # XXX: todo; test call_order.  Make sure PV's come before, VG;
        # VG before LV, and that mounts/etc happen afterwards.

        # Fake state for the two PV's specified by this config
        state['blockdev'] = {}
        state['blockdev']['root'] = {}
        state['blockdev']['root']['device'] = '/dev/fake/root'
        state['blockdev']['data'] = {}
        state['blockdev']['data']['device'] = '/dev/fake/data'

        # We mock patch this ... it's just a little long!
        exec_sudo = 'diskimage_builder.block_device.level1.lvm.exec_sudo'

        #
        # Creation test
        #
        with mock.patch(exec_sudo) as mock_exec_sudo:

            for node in call_order:
                # XXX: This has not mocked out the "lower" layers of
                # creating the devices, which we're assuming works OK, nor
                # the upper layers.
                if isinstance(node, (LVMNode, PvsNode,
                                     VgsNode, LvsNode)):
                    # only the PvsNode actually does anything here...
                    node.create()

            # ensure the sequence of calls correctly setup the devices
            cmd_sequence = [
                # create the pv's on the faked out block devices
                mock.call(['pvcreate', '/dev/fake/root', '--force']),
                mock.call(['pvcreate', '/dev/fake/data', '--force']),
                # create a volume called "vg" out of these two pv's
                mock.call(['vgcreate', 'vg1',
                           '/dev/fake/root', '--force']),
                mock.call(['vgcreate', 'vg2',
                           '/dev/fake/data', '--force']),
                # create a bunch of lv's on vg
                mock.call(['lvcreate', '--name', 'lv_root',
                           '-L', '1799356416B', 'vg1']),
                mock.call(['lvcreate', '--name', 'lv_tmp',
                           '-L', '96468992B', 'vg1']),
                mock.call(['lvcreate', '--name', 'lv_var',
                           '-L', '499122176B', 'vg2']),
                mock.call(['lvcreate', '--name', 'lv_log',
                           '-L', '96468992B', 'vg2']),
                mock.call(['lvcreate', '--name', 'lv_audit',
                           '-L', '96468992B', 'vg2']),
                mock.call(['lvcreate', '--name', 'lv_home',
                           '-L', '197132288B', 'vg2'])]

            self.assertListEqual(mock_exec_sudo.call_args_list,
                                 cmd_sequence)

            # Ensure the correct LVM state was preserved
            blockdev_state = {
                'data': {'device': '/dev/fake/data'},
                'root': {'device': '/dev/fake/root'},
                'lv_audit': {
                    'device': '/dev/mapper/vg2-lv_audit',
                    'extents': None,
                    'opts': None,
                    'size': '100M',
                    'vgs': 'vg2'
                },
                'lv_home': {
                    'device': '/dev/mapper/vg2-lv_home',
                    'extents': None,
                    'opts': None,
                    'size': '200M',
                    'vgs': 'vg2'
                },
                'lv_log': {
                    'device': '/dev/mapper/vg2-lv_log',
                    'extents': None,
                    'opts': None,
                    'size': '100M',
                    'vgs': 'vg2'
                },
                'lv_root': {
                    'device': '/dev/mapper/vg1-lv_root',
                    'extents': None,
                    'opts': None,
                    'size': '1800M',
                    'vgs': 'vg1'
                },
                'lv_tmp': {
                    'device': '/dev/mapper/vg1-lv_tmp',
                    'extents': None,
                    'opts': None,
                    'size': '100M',
                    'vgs': 'vg1'
                },
                'lv_var': {
                    'device': '/dev/mapper/vg2-lv_var',
                    'extents': None,
                    'opts': None,
                    'size': '500M',
                    'vgs': 'vg2'
                },
            }

            # state.debug_dump()
            self.assertDictEqual(state['blockdev'], blockdev_state)

        #
        # Umount test
        #
        with mock.patch(exec_sudo) as mock_exec_sudo, \
             mock.patch('tempfile.NamedTemporaryFile') as mock_temp, \
             mock.patch('os.unlink'):

            # each call to tempfile.NamedTemporaryFile will return a
            # new mock with a unique filename, which we store in
            # tempfiles
            tempfiles = []

            def new_tempfile(*args, **kwargs):
                n = '/tmp/files%s' % len(tempfiles)
                # trap! note mock.Mock(name = n) doesn't work like you
                # think it would, since mock has a name attribute.
                # That's why we override it with the configure_mock
                # (this is mentioned in mock documentation if you read
                # it :)
                r = mock.Mock()
                r.configure_mock(name=n)
                tempfiles.append(n)
                return r
            mock_temp.side_effect = new_tempfile

            def run_it(phase):
                reverse_order = reversed(call_order)
                for node in reverse_order:
                    if isinstance(node, (LVMNode, PvsNode, VgsNode, LvsNode)):
                        getattr(node, phase)()
                    else:
                        logger.debug("Skipping node for test: %s", node)

            run_it('umount')
            run_it('cleanup')

            cmd_sequence = [
                # delete the lv's
                mock.call(['lvchange', '-an', '/dev/vg1/lv_root']),
                mock.call(['lvchange', '-an', '/dev/vg1/lv_tmp']),
                mock.call(['lvchange', '-an', '/dev/vg2/lv_var']),
                mock.call(['lvchange', '-an', '/dev/vg2/lv_log']),
                mock.call(['lvchange', '-an', '/dev/vg2/lv_audit']),
                mock.call(['lvchange', '-an', '/dev/vg2/lv_home']),
                # delete the vg's
                mock.call(['vgchange', '-an', 'vg1']),
                mock.call(['vgchange', '-an', 'vg2']),
                mock.call(['udevadm', 'settle']),
                mock.call(['pvscan', '--cache']),
            ]

            self.assertListEqual(mock_exec_sudo.call_args_list, cmd_sequence)
예제 #24
0
 def test_multipart_tree(self):
     tree = self.load_config_file('multiple_partitions_tree.yaml')
     graph = self.load_config_file('multiple_partitions_graph.yaml')
     parsed_graph = config_tree_to_graph(tree)
     logger.debug(parsed_graph)
     self.assertItemsEqual(parsed_graph, graph)
예제 #25
0
    def test_lvm_spanned_vg(self):

        # Test when a volume group spans some partitions

        tree = self.load_config_file('lvm_tree_spanned_vg.yaml')
        config = config_tree_to_graph(tree)

        state = BlockDeviceState()

        graph, call_order = create_graph(config, self.fake_default_config,
                                         state)

        # XXX: todo; test call_order.  Make sure PV's come before, VG;
        # VG before LV, and that mounts/etc happen afterwards.

        # Fake state for the two PV's specified by this config
        state['blockdev'] = {}
        state['blockdev']['root'] = {}
        state['blockdev']['root']['device'] = '/dev/fake/root'
        state['blockdev']['data1'] = {}
        state['blockdev']['data1']['device'] = '/dev/fake/data1'
        state['blockdev']['data2'] = {}
        state['blockdev']['data2']['device'] = '/dev/fake/data2'

        # We mock patch this ... it's just a little long!
        exec_sudo = 'diskimage_builder.block_device.level1.lvm.exec_sudo'

        #
        # Creation test
        #
        with mock.patch(exec_sudo) as mock_exec_sudo:

            for node in call_order:
                # XXX: This has not mocked out the "lower" layers of
                # creating the devices, which we're assuming works OK, nor
                # the upper layers.
                if isinstance(node, (LVMNode, PvsNode, VgsNode, LvsNode)):
                    # only the LVMNode actually does anything here...
                    node.create()

            # ensure the sequence of calls correctly setup the devices
            cmd_sequence = [
                # create the pv's on the faked out block devices
                mock.call(['pvcreate', '/dev/fake/root', '--force']),
                mock.call(['pvcreate', '/dev/fake/data1', '--force']),
                mock.call(['pvcreate', '/dev/fake/data2', '--force']),
                # create a root and a data volume, with the data volume
                # spanning data1 & data2
                mock.call(['vgcreate', 'vg_root',
                           '/dev/fake/root', '--force']),
                mock.call(['vgcreate', 'vg_data',
                           '/dev/fake/data1', '/dev/fake/data2', '--force']),
                # create root and data volume
                mock.call(['lvcreate', '--name', 'lv_root',
                           '-L', '1800M', 'vg_root']),
                mock.call(['lvcreate', '--name', 'lv_data',
                           '-L', '2G', 'vg_data'])
            ]

            self.assertListEqual(mock_exec_sudo.call_args_list,
                                 cmd_sequence)

        with mock.patch(exec_sudo) as mock_exec_sudo, \
             mock.patch('tempfile.NamedTemporaryFile') as mock_temp, \
             mock.patch('os.unlink'):

            # see above ...
            tempfiles = []

            def new_tempfile(*args, **kwargs):
                n = '/tmp/files%s' % len(tempfiles)
                r = mock.Mock()
                r.configure_mock(name=n)
                tempfiles.append(n)
                return r
            mock_temp.side_effect = new_tempfile

            def run_it(phase):
                reverse_order = reversed(call_order)
                for node in reverse_order:
                    if isinstance(node, (LVMNode, PvsNode, VgsNode, LvsNode)):
                        getattr(node, phase)()
                    else:
                        logger.debug("Skipping node for test: %s", node)

            run_it('umount')
            run_it('cleanup')

            cmd_sequence = [
                # deactivate lv's
                mock.call(['lvchange', '-an', '/dev/vg_root/lv_root']),
                mock.call(['lvchange', '-an', '/dev/vg_data/lv_data']),

                # deactivate vg's
                mock.call(['vgchange', '-an', 'vg_root']),
                mock.call(['vgchange', '-an', 'vg_data']),

                mock.call(['udevadm', 'settle']),
                mock.call(['pvscan', '--cache']),
            ]

            self.assertListEqual(mock_exec_sudo.call_args_list, cmd_sequence)