Exemplo n.º 1
0
    def parse_schemes(self):
        self.image_scheme = objects.ImageScheme()
        self.partition_scheme = objects.PartitionScheme()

        for mount, image in six.iteritems(self.data['image_data']):
            filename = os.path.basename(urlsplit(image['uri']).path)
            # Loop does not allocate any loop device
            # during initialization.
            device = objects.Loop()

            self.image_scheme.add_image(
                uri='file://' + os.path.join(self.data['output'], filename),
                format=image['format'],
                container=image['container'],
                target_device=device)

            self.partition_scheme.add_fs(
                device=device,
                mount=mount,
                fs_type=image['format'])

            if mount == '/':
                metadata_filename = filename.split('.', 1)[0] + '.yaml'
                self.metadata_uri = 'file://' + os.path.join(
                    self.data['output'], metadata_filename)
Exemplo n.º 2
0
    def __init__(self, data):
        super(NailgunBuildImage, self).__init__(data)
        self._image_scheme = objects.ImageScheme()
        self._partition_scheme = objects.PartitionScheme()

        self.parse_schemes()
        self._operating_system = self.parse_operating_system()
Exemplo n.º 3
0
    def parse_partition_scheme(self):
        partition_scheme = objects.PartitionScheme()

        for obj in ('lv', 'pv', 'fs', 'vg', 'md', 'parted'):
            attr = '{0}s'.format(obj)
            parse_method = getattr(self, 'parse_{0}_data'.format(obj))
            raw = self.partition_data.get(attr, {})
            setattr(partition_scheme, attr, parse_method(raw))

        return partition_scheme
Exemplo n.º 4
0
    def parse_partition_scheme(self):
        LOG.debug('--- Preparing partition scheme ---')
        data = self.partition_data()
        ks_spaces_validator.validate(data)
        partition_scheme = objects.PartitionScheme()

        ceph_osds = self._num_ceph_osds()
        journals_left = ceph_osds
        ceph_journals = self._num_ceph_journals()

        LOG.debug('Looping over all disks in provision data')
        for disk in self.ks_disks:
            # skipping disk if there are no volumes with size >0
            # to be allocated on it which are not boot partitions
            if all((
                v["size"] <= 0
                for v in disk["volumes"]
                if v["type"] != "boot" and v.get("mount") != "/boot"
            )):
                continue
            LOG.debug('Processing disk %s' % disk['name'])
            LOG.debug('Adding gpt table on disk %s' % disk['name'])
            parted = partition_scheme.add_parted(
                name=self._disk_dev(disk), label='gpt')
            if disk in self.boot_disks:
                # we install bootloader only on every suitable disk
                LOG.debug('Adding bootloader stage0 on disk %s' % disk['name'])
                parted.install_bootloader = True

                # legacy boot partition
                LOG.debug('Adding bios_grub partition on disk %s: size=24' %
                          disk['name'])
                parted.add_partition(size=24, flags=['bios_grub'])
                # uefi partition (for future use)
                LOG.debug('Adding UEFI partition on disk %s: size=200' %
                          disk['name'])
                parted.add_partition(size=200)

            LOG.debug('Looping over all volumes on disk %s' % disk['name'])
            for volume in disk['volumes']:
                LOG.debug('Processing volume: '
                          'name=%s type=%s size=%s mount=%s vg=%s' %
                          (volume.get('name'), volume.get('type'),
                           volume.get('size'), volume.get('mount'),
                           volume.get('vg')))
                if volume['size'] <= 0:
                    LOG.debug('Volume size is zero. Skipping.')
                    continue

                if volume.get('name') == 'cephjournal':
                    LOG.debug('Volume seems to be a CEPH journal volume. '
                              'Special procedure is supposed to be applied.')
                    # We need to allocate a journal partition for each ceph OSD
                    # Determine the number of journal partitions we need on
                    # each device
                    ratio = int(math.ceil(float(ceph_osds) / ceph_journals))

                    # No more than 10GB will be allocated to a single journal
                    # partition
                    size = volume["size"] / ratio
                    if size > 10240:
                        size = 10240

                    # This will attempt to evenly spread partitions across
                    # multiple devices e.g. 5 osds with 2 journal devices will
                    # create 3 partitions on the first device and 2 on the
                    # second
                    if ratio < journals_left:
                        end = ratio
                    else:
                        end = journals_left

                    for i in range(0, end):
                        journals_left -= 1
                        if volume['type'] == 'partition':
                            LOG.debug('Adding CEPH journal partition on '
                                      'disk %s: size=%s' %
                                      (disk['name'], size))
                            prt = parted.add_partition(size=size)
                            LOG.debug('Partition name: %s' % prt.name)
                            if 'partition_guid' in volume:
                                LOG.debug('Setting partition GUID: %s' %
                                          volume['partition_guid'])
                                prt.set_guid(volume['partition_guid'])
                    continue

                if volume['type'] in ('partition', 'pv', 'raid'):
                    if volume.get('mount') != '/boot':
                        LOG.debug('Adding partition on disk %s: size=%s' %
                                  (disk['name'], volume['size']))
                        prt = parted.add_partition(
                            size=volume['size'],
                            keep_data=volume.get('keep_data', False))
                        LOG.debug('Partition name: %s' % prt.name)

                    elif volume.get('mount') == '/boot' \
                            and not self._boot_partition_done \
                            and disk in self.boot_disks:
                        LOG.debug('Adding /boot partition on disk %s: '
                                  'size=%s', disk['name'], volume['size'])
                        prt = parted.add_partition(
                            size=volume['size'],
                            keep_data=volume.get('keep_data', False))
                        LOG.debug('Partition name: %s', prt.name)
                        self._boot_partition_done = True
                    else:
                        LOG.debug('No need to create partition on disk %s. '
                                  'Skipping.', disk['name'])
                        continue

                if volume['type'] == 'partition':
                    if 'partition_guid' in volume:
                        LOG.debug('Setting partition GUID: %s' %
                                  volume['partition_guid'])
                        prt.set_guid(volume['partition_guid'])

                    if 'mount' in volume and volume['mount'] != 'none':
                        LOG.debug('Adding file system on partition: '
                                  'mount=%s type=%s' %
                                  (volume['mount'],
                                   volume.get('file_system', 'xfs')))
                        partition_scheme.add_fs(
                            device=prt.name, mount=volume['mount'],
                            fs_type=volume.get('file_system', 'xfs'),
                            fs_label=volume.get('disk_label'))
                        if volume['mount'] == '/boot' and not self._boot_done:
                            self._boot_done = True

                if volume['type'] == 'pv':
                    LOG.debug('Creating pv on partition: pv=%s vg=%s' %
                              (prt.name, volume['vg']))
                    lvm_meta_size = volume.get('lvm_meta_size', 64)
                    # The reason for that is to make sure that
                    # there will be enough space for creating logical volumes.
                    # Default lvm extension size is 4M. Nailgun volume
                    # manager does not care of it and if physical volume size
                    # is 4M * N + 3M and lvm metadata size is 4M * L then only
                    # 4M * (N-L) + 3M of space will be available for
                    # creating logical extensions. So only 4M * (N-L) of space
                    # will be available for logical volumes, while nailgun
                    # volume manager might reguire 4M * (N-L) + 3M
                    # logical volume. Besides, parted aligns partitions
                    # according to its own algorithm and actual partition might
                    # be a bit smaller than integer number of mebibytes.
                    if lvm_meta_size < 10:
                        raise errors.WrongPartitionSchemeError(
                            'Error while creating physical volume: '
                            'lvm metadata size is too small')
                    metadatasize = int(math.floor((lvm_meta_size - 8) / 2))
                    metadatacopies = 2
                    partition_scheme.vg_attach_by_name(
                        pvname=prt.name, vgname=volume['vg'],
                        metadatasize=metadatasize,
                        metadatacopies=metadatacopies)

                if volume['type'] == 'raid':
                    if 'mount' in volume and \
                            volume['mount'] not in ('none', '/boot'):
                        LOG.debug('Attaching partition to RAID '
                                  'by its mount point %s' % volume['mount'])
                        metadata = 'default'
                        if self.have_grub1_by_default:
                            metadata = '0.90'
                        LOG.debug('Going to use MD metadata version {0}. '
                                  'The version was guessed at the data has '
                                  'been given about the operating system.'
                                  .format(metadata))
                        partition_scheme.md_attach_by_mount(
                            device=prt.name, mount=volume['mount'],
                            fs_type=volume.get('file_system', 'xfs'),
                            fs_label=volume.get('disk_label'),
                            metadata=metadata)

                    if 'mount' in volume and volume['mount'] == '/boot' and \
                            not self._boot_done:
                        LOG.debug('Adding file system on partition: '
                                  'mount=%s type=%s' %
                                  (volume['mount'],
                                   volume.get('file_system', 'ext2')))
                        partition_scheme.add_fs(
                            device=prt.name, mount=volume['mount'],
                            fs_type=volume.get('file_system', 'ext2'),
                            fs_label=volume.get('disk_label'))
                        self._boot_done = True

            # this partition will be used to put there configdrive image
            if (partition_scheme.configdrive_device() is None and
                    self._needs_configdrive() and
                    (self._is_root_disk(disk) or self._is_os_disk(disk))):
                LOG.debug('Adding configdrive partition on disk %s: size=20' %
                          disk['name'])
                parted.add_partition(size=20, configdrive=True)

        # checking if /boot is expected to be created
        if self._have_boot_partition(self.ks_disks) and \
                (not self._boot_partition_done or not self._boot_done):
            raise errors.WrongPartitionSchemeError(
                '/boot partition has not been created for some reasons')

        # checking if configdrive partition is created
        if (not partition_scheme.configdrive_device() and
                self._needs_configdrive()):
            raise errors.WrongPartitionSchemeError(
                'configdrive partition has not been created for some reasons')

        LOG.debug('Looping over all volume groups in provision data')
        for vg in self.ks_vgs:
            LOG.debug('Processing vg %s' % vg['id'])
            LOG.debug('Looping over all logical volumes in vg %s' % vg['id'])
            for volume in vg['volumes']:
                LOG.debug('Processing lv %s' % volume['name'])
                if volume['size'] <= 0:
                    LOG.debug('LogicalVolume size is zero. Skipping.')
                    continue

                if volume['type'] == 'lv':
                    LOG.debug('Adding lv to vg %s: name=%s, size=%s' %
                              (vg['id'], volume['name'], volume['size']))
                    lv = partition_scheme.add_lv(name=volume['name'],
                                                 vgname=vg['id'],
                                                 size=volume['size'])

                    if 'mount' in volume and volume['mount'] != 'none':
                        LOG.debug('Adding file system on lv: '
                                  'mount=%s type=%s' %
                                  (volume['mount'],
                                   volume.get('file_system', 'xfs')))
                        partition_scheme.add_fs(
                            device=lv.device_name, mount=volume['mount'],
                            fs_type=volume.get('file_system', 'xfs'),
                            fs_label=volume.get('disk_label'))

        partition_scheme.elevate_keep_data()
        return partition_scheme
Exemplo n.º 5
0
    def test_do_build_image(self, mock_umount_target, mock_mount_target,
                            mock_yaml_dump, mock_mkdtemp, mock_open,
                            mock_shutil_move, mock_os, mock_utils, mock_fu,
                            mock_bu):

        loops = [objects.Loop(), objects.Loop()]

        self.mgr.driver.image_scheme = objects.ImageScheme([
            objects.Image('file:///fake/img.img.gz', loops[0], 'ext4', 'gzip'),
            objects.Image('file:///fake/img-boot.img.gz', loops[1], 'ext2',
                          'gzip')
        ])
        self.mgr.driver.partition_scheme = objects.PartitionScheme()
        self.mgr.driver.partition_scheme.add_fs(device=loops[0],
                                                mount='/',
                                                fs_type='ext4')
        self.mgr.driver.partition_scheme.add_fs(device=loops[1],
                                                mount='/boot',
                                                fs_type='ext2')
        self.mgr.driver.metadata_uri = 'file:///fake/img.yaml'
        self.mgr.driver.operating_system = objects.Ubuntu(
            repos=[
                objects.DEBRepo('ubuntu',
                                'http://fakeubuntu',
                                'trusty',
                                'fakesection',
                                priority=900),
                objects.DEBRepo('ubuntu_zero',
                                'http://fakeubuntu_zero',
                                'trusty',
                                'fakesection',
                                priority=None),
                objects.DEBRepo('mos',
                                'http://fakemos',
                                'mosX.Y',
                                'fakesection',
                                priority=1000)
            ],
            packages=['fakepackage1', 'fakepackage2'])

        mock_os.path.exists.return_value = False
        mock_os.path.join.return_value = '/tmp/imgdir/proc'
        mock_os.path.basename.side_effect = ['img.img.gz', 'img-boot.img.gz']
        mock_bu.create_sparse_tmp_file.side_effect = \
            ['/tmp/img', '/tmp/img-boot']
        mock_bu.get_free_loop_device.side_effect = ['/dev/loop0', '/dev/loop1']
        mock_mkdtemp.return_value = '/tmp/imgdir'
        getsize_side = [20, 2, 10, 1]
        mock_os.path.getsize.side_effect = getsize_side
        md5_side = [
            'fakemd5_raw', 'fakemd5_gzip', 'fakemd5_raw_boot',
            'fakemd5_gzip_boot'
        ]
        mock_utils.calculate_md5.side_effect = md5_side
        mock_bu.containerize.side_effect = ['/tmp/img.gz', '/tmp/img-boot.gz']
        mock_bu.stop_chrooted_processes.side_effect = [
            False, True, False, True
        ]

        self.mgr.do_build_image()
        self.assertEqual([
            mock.call('/fake/img.img.gz'),
            mock.call('/fake/img-boot.img.gz')
        ], mock_os.path.exists.call_args_list)
        self.assertEqual([
            mock.call(dir=CONF.image_build_dir, suffix=CONF.image_build_suffix)
        ] * 2, mock_bu.create_sparse_tmp_file.call_args_list)
        self.assertEqual([mock.call()] * 2,
                         mock_bu.get_free_loop_device.call_args_list)
        self.assertEqual([
            mock.call('/tmp/img', '/dev/loop0'),
            mock.call('/tmp/img-boot', '/dev/loop1')
        ], mock_bu.attach_file_to_loop.call_args_list)
        self.assertEqual([
            mock.call(
                fs_type='ext4', fs_options='', fs_label='', dev='/dev/loop0'),
            mock.call(
                fs_type='ext2', fs_options='', fs_label='', dev='/dev/loop1')
        ], mock_fu.make_fs.call_args_list)
        mock_mkdtemp.assert_called_once_with(dir=CONF.image_build_dir,
                                             suffix=CONF.image_build_suffix)
        mock_mount_target.assert_called_once_with('/tmp/imgdir',
                                                  treat_mtab=False,
                                                  pseudo=False)
        self.assertEqual([mock.call('/tmp/imgdir')] * 2,
                         mock_bu.suppress_services_start.call_args_list)
        mock_bu.run_debootstrap.assert_called_once_with(
            uri='http://fakeubuntu', suite='trusty', chroot='/tmp/imgdir')
        mock_bu.set_apt_get_env.assert_called_once_with()
        mock_bu.pre_apt_get.assert_called_once_with('/tmp/imgdir')
        self.assertEqual([
            mock.call(name='ubuntu',
                      uri='http://fakeubuntu',
                      suite='trusty',
                      section='fakesection',
                      chroot='/tmp/imgdir'),
            mock.call(name='ubuntu_zero',
                      uri='http://fakeubuntu_zero',
                      suite='trusty',
                      section='fakesection',
                      chroot='/tmp/imgdir'),
            mock.call(name='mos',
                      uri='http://fakemos',
                      suite='mosX.Y',
                      section='fakesection',
                      chroot='/tmp/imgdir')
        ], mock_bu.add_apt_source.call_args_list)

        # we don't call add_apt_preference for ubuntu_zero
        # because it has priority == None
        self.assertEqual([
            mock.call(name='ubuntu',
                      priority=900,
                      suite='trusty',
                      section='fakesection',
                      chroot='/tmp/imgdir',
                      uri='http://fakeubuntu'),
            mock.call(name='mos',
                      priority=1000,
                      suite='mosX.Y',
                      section='fakesection',
                      chroot='/tmp/imgdir',
                      uri='http://fakemos')
        ], mock_bu.add_apt_preference.call_args_list)
        mock_utils.makedirs_if_not_exists.assert_called_once_with(
            '/tmp/imgdir/proc')
        self.assertEqual([
            mock.call('tune2fs', '-O', '^has_journal', '/dev/loop0'),
            mock.call('tune2fs', '-O', 'has_journal', '/dev/loop0')
        ], mock_utils.execute.call_args_list)
        mock_fu.mount_bind.assert_called_once_with('/tmp/imgdir', '/proc')
        mock_bu.run_apt_get.assert_called_once_with(
            '/tmp/imgdir', packages=['fakepackage1', 'fakepackage2'])
        mock_bu.do_post_inst.assert_called_once_with('/tmp/imgdir')
        signal_calls = mock_bu.stop_chrooted_processes.call_args_list
        self.assertEqual(
            2 * [
                mock.call('/tmp/imgdir', signal=signal.SIGTERM),
                mock.call('/tmp/imgdir', signal=signal.SIGKILL)
            ], signal_calls)
        self.assertEqual([mock.call('/tmp/imgdir/proc')] * 2,
                         mock_fu.umount_fs.call_args_list)
        self.assertEqual(
            [mock.call('/tmp/imgdir', try_lazy_umount=False, pseudo=False)] *
            2, mock_umount_target.call_args_list)
        self.assertEqual([mock.call('/dev/loop0'),
                          mock.call('/dev/loop1')] * 2,
                         mock_bu.deattach_loop.call_args_list)
        self.assertEqual([mock.call('/tmp/img'),
                          mock.call('/tmp/img-boot')],
                         mock_bu.shrink_sparse_file.call_args_list)
        self.assertEqual([
            mock.call('/tmp/img'),
            mock.call('/fake/img.img.gz'),
            mock.call('/tmp/img-boot'),
            mock.call('/fake/img-boot.img.gz')
        ], mock_os.path.getsize.call_args_list)
        self.assertEqual([
            mock.call('/tmp/img', 20),
            mock.call('/fake/img.img.gz', 2),
            mock.call('/tmp/img-boot', 10),
            mock.call('/fake/img-boot.img.gz', 1)
        ], mock_utils.calculate_md5.call_args_list)
        self.assertEqual([
            mock.call('/tmp/img', 'gzip'),
            mock.call('/tmp/img-boot', 'gzip')
        ], mock_bu.containerize.call_args_list)
        mock_open.assert_called_once_with('/fake/img.yaml', 'w')
        self.assertEqual([
            mock.call('/tmp/img.gz', '/fake/img.img.gz'),
            mock.call('/tmp/img-boot.gz', '/fake/img-boot.img.gz')
        ], mock_shutil_move.call_args_list)

        metadata = {}
        for repo in self.mgr.driver.operating_system.repos:
            metadata.setdefault('repos', []).append({
                'type': 'deb',
                'name': repo.name,
                'uri': repo.uri,
                'suite': repo.suite,
                'section': repo.section,
                'priority': repo.priority,
                'meta': repo.meta
            })
        metadata['packages'] = self.mgr.driver.operating_system.packages
        metadata['images'] = [{
            'raw_md5':
            md5_side[0],
            'raw_size':
            getsize_side[0],
            'raw_name':
            None,
            'container_name':
            os.path.basename(self.mgr.driver.image_scheme.images[0].uri.split(
                'file://', 1)[1]),
            'container_md5':
            md5_side[1],
            'container_size':
            getsize_side[1],
            'container':
            self.mgr.driver.image_scheme.images[0].container,
            'format':
            self.mgr.driver.image_scheme.images[0].format
        }, {
            'raw_md5':
            md5_side[2],
            'raw_size':
            getsize_side[2],
            'raw_name':
            None,
            'container_name':
            os.path.basename(self.mgr.driver.image_scheme.images[1].uri.split(
                'file://', 1)[1]),
            'container_md5':
            md5_side[3],
            'container_size':
            getsize_side[3],
            'container':
            self.mgr.driver.image_scheme.images[1].container,
            'format':
            self.mgr.driver.image_scheme.images[1].format
        }]
        mock_yaml_dump.assert_called_once_with(metadata, stream=mock_open())
Exemplo n.º 6
0
 def setUp(self):
     super(TestPartitionScheme, self).setUp()
     self.p_scheme = objects.PartitionScheme()
Exemplo n.º 7
0
    def partition_scheme(self):
        data = self.partition_data()
        ks_spaces_validator.validate(data)
        partition_scheme = objects.PartitionScheme()

        ceph_osds = self._num_ceph_osds()
        journals_left = ceph_osds
        ceph_journals = self._num_ceph_journals()

        for disk in self.ks_disks:
            parted = partition_scheme.add_parted(
                name=self._disk_dev(disk), label='gpt')
            # we install bootloader on every disk
            parted.install_bootloader = True
            # legacy boot partition
            parted.add_partition(size=24, flags=['bios_grub'])
            # uefi partition (for future use)
            parted.add_partition(size=200)

            for volume in disk['volumes']:
                if volume['size'] <= 0:
                    continue

                if volume.get('name') == 'cephjournal':
                    # We need to allocate a journal partition for each ceph OSD
                    # Determine the number of journal partitions we need on
                    # each device
                    ratio = math.ceil(float(ceph_osds) / ceph_journals)

                    # No more than 10GB will be allocated to a single journal
                    # partition
                    size = volume["size"] / ratio
                    if size > 10240:
                        size = 10240

                    # This will attempt to evenly spread partitions across
                    # multiple devices e.g. 5 osds with 2 journal devices will
                    # create 3 partitions on the first device and 2 on the
                    # second
                    if ratio < journals_left:
                        end = ratio
                    else:
                        end = journals_left

                    for i in range(0, end):
                        journals_left -= 1
                        if volume['type'] == 'partition':
                            prt = parted.add_partition(size=size)
                            if 'partition_guid' in volume:
                                prt.set_guid(volume['partition_guid'])
                    continue

                if volume['type'] in ('partition', 'pv', 'raid'):
                    prt = parted.add_partition(size=volume['size'])

                if volume['type'] == 'partition':
                    if 'partition_guid' in volume:
                        prt.set_guid(volume['partition_guid'])

                    if 'mount' in volume and volume['mount'] != 'none':
                        partition_scheme.add_fs(
                            device=prt.name, mount=volume['mount'],
                            fs_type=volume.get('file_system', 'xfs'),
                            fs_label=self._getlabel(volume.get('disk_label')))

                if volume['type'] == 'pv':
                    partition_scheme.vg_attach_by_name(
                        pvname=prt.name, vgname=volume['vg'])

                if volume['type'] == 'raid':
                    if 'mount' in volume and volume['mount'] != 'none':
                        partition_scheme.md_attach_by_mount(
                            device=prt.name, mount=volume['mount'],
                            fs_type=volume.get('file_system', 'xfs'),
                            fs_label=self._getlabel(volume.get('disk_label')))

            # this partition will be used to put there configdrive image
            if partition_scheme.configdrive_device() is None:
                parted.add_partition(size=20, configdrive=True)

        for vg in self.ks_vgs:
            for volume in vg['volumes']:
                if volume['size'] <= 0:
                    continue

                if volume['type'] == 'lv':
                    lv = partition_scheme.add_lv(name=volume['name'],
                                                 vgname=vg['id'],
                                                 size=volume['size'])

                    if 'mount' in volume and volume['mount'] != 'none':
                        partition_scheme.add_fs(
                            device=lv.device_name, mount=volume['mount'],
                            fs_type=volume.get('file_system', 'xfs'),
                            fs_label=self._getlabel(volume.get('disk_label')))

        partition_scheme.append_kernel_params(
            self.data['ks_meta']['pm_data']['kernel_params'])
        return partition_scheme
Exemplo n.º 8
0
    def partition_scheme(self):
        LOG.debug('--- Preparing partition scheme ---')
        data = self.partition_data()
        ks_spaces_validator.validate(data)
        partition_scheme = objects.PartitionScheme()

        ceph_osds = self._num_ceph_osds()
        journals_left = ceph_osds
        ceph_journals = self._num_ceph_journals()

        LOG.debug('Looping over all disks in provision data')
        for disk in self.ks_disks:
            LOG.debug('Processing disk %s' % disk['name'])
            LOG.debug('Adding gpt table on disk %s' % disk['name'])
            parted = partition_scheme.add_parted(name=self._disk_dev(disk),
                                                 label='gpt')
            # we install bootloader on every disk
            LOG.debug('Adding bootloader stage0 on disk %s' % disk['name'])
            parted.install_bootloader = True
            # legacy boot partition
            LOG.debug('Adding bios_grub partition on disk %s: size=24' %
                      disk['name'])
            parted.add_partition(size=24, flags=['bios_grub'])
            # uefi partition (for future use)
            LOG.debug('Adding UEFI partition on disk %s: size=200' %
                      disk['name'])
            parted.add_partition(size=200)

            LOG.debug('Looping over all volumes on disk %s' % disk['name'])
            for volume in disk['volumes']:
                LOG.debug('Processing volume: '
                          'name=%s type=%s size=%s mount=%s vg=%s' %
                          (volume.get('name'), volume.get('type'),
                           volume.get('size'), volume.get('mount'),
                           volume.get('vg')))
                if volume['size'] <= 0:
                    LOG.debug('Volume size is zero. Skipping.')
                    continue

                if volume.get('name') == 'cephjournal':
                    LOG.debug('Volume seems to be a CEPH journal volume. '
                              'Special procedure is supposed to be applied.')
                    # We need to allocate a journal partition for each ceph OSD
                    # Determine the number of journal partitions we need on
                    # each device
                    ratio = math.ceil(float(ceph_osds) / ceph_journals)

                    # No more than 10GB will be allocated to a single journal
                    # partition
                    size = volume["size"] / ratio
                    if size > 10240:
                        size = 10240

                    # This will attempt to evenly spread partitions across
                    # multiple devices e.g. 5 osds with 2 journal devices will
                    # create 3 partitions on the first device and 2 on the
                    # second
                    if ratio < journals_left:
                        end = ratio
                    else:
                        end = journals_left

                    for i in range(0, end):
                        journals_left -= 1
                        if volume['type'] == 'partition':
                            LOG.debug('Adding CEPH journal partition on '
                                      'disk %s: size=%s' %
                                      (disk['name'], size))
                            prt = parted.add_partition(size=size)
                            LOG.debug('Partition name: %s' % prt.name)
                            if 'partition_guid' in volume:
                                LOG.debug('Setting partition GUID: %s' %
                                          volume['partition_guid'])
                                prt.set_guid(volume['partition_guid'])
                    continue

                if volume['type'] in ('partition', 'pv', 'raid'):
                    LOG.debug('Adding partition on disk %s: size=%s' %
                              (disk['name'], volume['size']))
                    prt = parted.add_partition(size=volume['size'])
                    LOG.debug('Partition name: %s' % prt.name)

                if volume['type'] == 'partition':
                    if 'partition_guid' in volume:
                        LOG.debug('Setting partition GUID: %s' %
                                  volume['partition_guid'])
                        prt.set_guid(volume['partition_guid'])

                    if 'mount' in volume and volume['mount'] != 'none':
                        LOG.debug('Adding file system on partition: '
                                  'mount=%s type=%s' %
                                  (volume['mount'],
                                   volume.get('file_system', 'xfs')))
                        partition_scheme.add_fs(
                            device=prt.name,
                            mount=volume['mount'],
                            fs_type=volume.get('file_system', 'xfs'),
                            fs_label=self._getlabel(volume.get('disk_label')))

                if volume['type'] == 'pv':
                    LOG.debug('Creating pv on partition: pv=%s vg=%s' %
                              (prt.name, volume['vg']))
                    lvm_meta_size = volume.get('lvm_meta_size', 64)
                    # The reason for that is to make sure that
                    # there will be enough space for creating logical volumes.
                    # Default lvm extension size is 4M. Nailgun volume
                    # manager does not care of it and if physical volume size
                    # is 4M * N + 3M and lvm metadata size is 4M * L then only
                    # 4M * (N-L) + 3M of space will be available for
                    # creating logical extensions. So only 4M * (N-L) of space
                    # will be available for logical volumes, while nailgun
                    # volume manager might reguire 4M * (N-L) + 3M
                    # logical volume. Besides, parted aligns partitions
                    # according to its own algorithm and actual partition might
                    # be a bit smaller than integer number of mebibytes.
                    if lvm_meta_size < 10:
                        raise errors.WrongPartitionSchemeError(
                            'Error while creating physical volume: '
                            'lvm metadata size is too small')
                    metadatasize = int(math.floor((lvm_meta_size - 8) / 2))
                    metadatacopies = 2
                    partition_scheme.vg_attach_by_name(
                        pvname=prt.name,
                        vgname=volume['vg'],
                        metadatasize=metadatasize,
                        metadatacopies=metadatacopies)

                if volume['type'] == 'raid':
                    if 'mount' in volume and volume['mount'] != 'none':
                        LOG.debug('Attaching partition to RAID '
                                  'by its mount point %s' % volume['mount'])
                        partition_scheme.md_attach_by_mount(
                            device=prt.name,
                            mount=volume['mount'],
                            fs_type=volume.get('file_system', 'xfs'),
                            fs_label=self._getlabel(volume.get('disk_label')))

            # this partition will be used to put there configdrive image
            if partition_scheme.configdrive_device() is None:
                LOG.debug('Adding configdrive partition on disk %s: size=20' %
                          disk['name'])
                parted.add_partition(size=20, configdrive=True)

        LOG.debug('Looping over all volume groups in provision data')
        for vg in self.ks_vgs:
            LOG.debug('Processing vg %s' % vg['id'])
            LOG.debug('Looping over all logical volumes in vg %s' % vg['id'])
            for volume in vg['volumes']:
                LOG.debug('Processing lv %s' % volume['name'])
                if volume['size'] <= 0:
                    LOG.debug('Lv size is zero. Skipping.')
                    continue

                if volume['type'] == 'lv':
                    LOG.debug('Adding lv to vg %s: name=%s, size=%s' %
                              (vg['id'], volume['name'], volume['size']))
                    lv = partition_scheme.add_lv(name=volume['name'],
                                                 vgname=vg['id'],
                                                 size=volume['size'])

                    if 'mount' in volume and volume['mount'] != 'none':
                        LOG.debug('Adding file system on lv: '
                                  'mount=%s type=%s' %
                                  (volume['mount'],
                                   volume.get('file_system', 'xfs')))
                        partition_scheme.add_fs(
                            device=lv.device_name,
                            mount=volume['mount'],
                            fs_type=volume.get('file_system', 'xfs'),
                            fs_label=self._getlabel(volume.get('disk_label')))

        LOG.debug('Appending kernel parameters: %s' %
                  self.data['ks_meta']['pm_data']['kernel_params'])
        partition_scheme.append_kernel_params(
            self.data['ks_meta']['pm_data']['kernel_params'])
        return partition_scheme
Exemplo n.º 9
0
    def partition_scheme(self):
        data = self.partition_data()
        ks_spaces_validator.validate(data)
        partition_scheme = objects.PartitionScheme()

        for disk in self.ks_disks:
            parted = partition_scheme.add_parted(name=self._disk_dev(disk),
                                                 label='gpt')
            # legacy boot partition
            parted.add_partition(size=24, flags=['bios_grub'])
            # uefi partition (for future use)
            parted.add_partition(size=200)

            for volume in disk['volumes']:
                if volume['size'] <= 0:
                    continue

                if volume['type'] in ('partition', 'pv', 'raid'):
                    prt = parted.add_partition(size=volume['size'])

                if volume['type'] == 'partition':
                    if 'partition_guid' in volume:
                        prt.set_guid(volume['partition_guid'])

                    if 'mount' in volume and volume['mount'] != 'none':
                        partition_scheme.add_fs(
                            device=prt.name,
                            mount=volume['mount'],
                            fs_type=volume.get('file_system', 'xfs'),
                            fs_label=self._getlabel(volume.get('disk_label')))

                if volume['type'] == 'pv':
                    partition_scheme.vg_attach_by_name(pvname=prt.name,
                                                       vgname=volume['vg'])

                if volume['type'] == 'raid':
                    if 'mount' in volume and volume['mount'] != 'none':
                        partition_scheme.md_attach_by_mount(
                            device=prt.name,
                            mount=volume['mount'],
                            fs_type=volume.get('file_system', 'xfs'),
                            fs_label=self._getlabel(volume.get('disk_label')))

            # this partition will be used to put there configdrive image
            if partition_scheme.configdrive_device() is None:
                parted.add_partition(size=20, configdrive=True)

        for vg in self.ks_vgs:
            for volume in vg['volumes']:
                if volume['size'] <= 0:
                    continue

                if volume['type'] == 'lv':
                    lv = partition_scheme.add_lv(name=volume['name'],
                                                 vgname=vg['id'],
                                                 size=volume['size'])

                    if 'mount' in volume and volume['mount'] != 'none':
                        partition_scheme.add_fs(
                            device=lv.device_name,
                            mount=volume['mount'],
                            fs_type=volume.get('file_system', 'xfs'),
                            fs_label=self._getlabel(volume.get('disk_label')))

        return partition_scheme