def create_flat_layout(node, boot_disk, PartitionTable, Partition, Filesystem):
    """Create the flat layout for the boot disk."""
    # Create the partition table and root partition.
    now = datetime.now()
    partition_table = PartitionTable.objects.create(
        block_device=boot_disk,
        table_type=PARTITION_TABLE_TYPE.MBR,
        created=now,
        updated=now,
    )
    total_size = 0
    available_size = boot_disk.size - PARTITION_TABLE_EXTRA_SPACE
    partition_size = round_size_to_nearest_block(
        available_size, PARTITION_ALIGNMENT_SIZE, False
    )
    max_mbr_size = round_size_to_nearest_block(
        MAX_PARTITION_SIZE_FOR_MBR, PARTITION_ALIGNMENT_SIZE, False
    )
    if partition_size > max_mbr_size:
        partition_size = max_mbr_size
    available_size -= partition_size
    total_size += partition_size
    root_partition = Partition.objects.create(
        partition_table=partition_table,
        size=partition_size,
        bootable=True,
        created=now,
        updated=now,
        uuid=uuid4(),
    )
    Filesystem.objects.create(
        partition=root_partition,
        fstype=FILESYSTEM_TYPE.EXT4,
        label="root",
        mount_point="/",
        created=now,
        updated=now,
        uuid=uuid4(),
    )
Пример #2
0
 def test_size_rounded_down_and_placed_on_alignment_boundry(self):
     block_size = 4096
     block_device = factory.make_PhysicalBlockDevice(block_size=block_size)
     k_size = (MIN_BLOCK_DEVICE_SIZE // 1000) + 1
     size = "%sk" % k_size
     rounded_size = round_size_to_nearest_block(k_size * 1000,
                                                PARTITION_ALIGNMENT_SIZE,
                                                False)
     data = {"size": size}
     form = AddPartitionForm(block_device, data=data)
     self.assertTrue(form.is_valid(), form.errors)
     partition = form.save()
     self.assertEqual(rounded_size, partition.size)
Пример #3
0
 def test_get_size_returns_block_device_size_minus_ppc64el(self):
     node = factory.make_Node(architecture="ppc64el/generic")
     block_device = factory.make_PhysicalBlockDevice(node=node)
     partition_table = factory.make_PartitionTable(
         block_device=block_device)
     self.assertEqual(
         round_size_to_nearest_block(
             partition_table.block_device.size -
             PARTITION_TABLE_EXTRA_SPACE - PREP_PARTITION_SIZE,
             PARTITION_ALIGNMENT_SIZE,
             False,
         ),
         partition_table.get_size(),
     )
Пример #4
0
 def test_add_partition_no_size_sets_mbr_max(self):
     block_size = 4096
     device = factory.make_BlockDevice(
         size=3 * (1024 ** 4), block_size=block_size
     )
     partition_table = factory.make_PartitionTable(
         table_type=PARTITION_TABLE_TYPE.MBR, block_device=device
     )
     partition = partition_table.add_partition()
     self.assertEqual(
         round_size_to_nearest_block(
             MAX_PARTITION_SIZE_FOR_MBR, PARTITION_ALIGNMENT_SIZE, False
         ),
         partition.size,
     )
Пример #5
0
 def test_add_misaligned_partition(self):
     """Tests whether a partition size are adjusted according to
     partition alignment size (4MiB)."""
     block_size = 4096
     device = factory.make_BlockDevice(
         size=MIN_PARTITION_SIZE * 2 + PARTITION_TABLE_EXTRA_SPACE,
         block_size=block_size,
     )
     partition_table = factory.make_PartitionTable(block_device=device)
     partition = partition_table.add_partition(size=MIN_PARTITION_SIZE + 54)
     self.assertEqual(
         round_size_to_nearest_block(MIN_PARTITION_SIZE + 54,
                                     PARTITION_ALIGNMENT_SIZE, False),
         partition.size,
     )
Пример #6
0
 def test_get_size_returns_block_device_size_minus_amd64_gpt(self):
     node = factory.make_Node(architecture="amd64/generic")
     block_device = factory.make_PhysicalBlockDevice(node=node,
                                                     size=2 * (1024**4))
     partition_table = factory.make_PartitionTable(
         block_device=block_device)
     self.assertEqual(
         round_size_to_nearest_block(
             partition_table.block_device.size -
             PARTITION_TABLE_EXTRA_SPACE - BIOS_GRUB_PARTITION_SIZE,
             PARTITION_ALIGNMENT_SIZE,
             False,
         ),
         partition_table.get_size(),
     )
Пример #7
0
    def add_partition(self, size=None, bootable=False, uuid=None):
        """Adds a partition to this partition table, returns the added
        partition.

        If size is omitted, the partition will extend to the end of the device.

        All partition sizes will be aligned down to PARTITION_ALIGNMENT_SIZE.
        """
        if size is None:
            size = self.get_available_size()
            if self.table_type == PARTITION_TABLE_TYPE.MBR:
                size = min(size, get_max_mbr_partition_size())
        size = round_size_to_nearest_block(
            size, PARTITION_ALIGNMENT_SIZE, False)
        return Partition.objects.create(
            partition_table=self, size=size, uuid=uuid, bootable=bootable)
Пример #8
0
    def clean(self, *args, **kwargs):
        super(VirtualBlockDevice, self).clean(*args, **kwargs)

        # First time called the node might not be set, so we handle the
        # DoesNotExist exception accordingly.
        try:
            node = self.node
        except Node.DoesNotExist:
            # Set the node of this virtual block device, to the same node from
            # the attached filesystem group.
            fsgroup_node = self.filesystem_group.get_node()
            if fsgroup_node is not None:
                self.node = fsgroup_node
        else:
            # The node on the virtual block device must be the same node from
            # the attached filesystem group.
            if node != self.filesystem_group.get_node():
                raise ValidationError(
                    "Node must be the same node as the filesystem_group."
                )

        # Check if the size of this is not larger than the free size of
        # its filesystem group if its lvm.
        if self.filesystem_group.is_lvm():

            # align virtual partition to partition alignment size
            # otherwise on creation it may be rounded up, overfilling group
            self.size = round_size_to_nearest_block(
                self.size, PARTITION_ALIGNMENT_SIZE, False
            )

            if self.size > self.filesystem_group.get_lvm_free_space(
                skip_volumes=[self]
            ):
                raise ValidationError(
                    "There is not enough free space (%s) "
                    "on volume group %s."
                    % (
                        human_readable_bytes(self.size),
                        self.filesystem_group.name,
                    )
                )
        else:
            # If not a volume group the size of the virtual block device
            # must equal the size of the filesystem group.
            assert self.size == self.filesystem_group.get_size()
Пример #9
0
 def test_creates_logical_volume(self):
     volume_group = factory.make_VolumeGroup()
     name = factory.make_name("lv")
     vguuid = "%s" % uuid.uuid4()
     size = random.randint(MIN_BLOCK_DEVICE_SIZE, volume_group.get_size())
     data = {"name": name, "uuid": vguuid, "size": size}
     form = CreateLogicalVolumeForm(volume_group, data=data)
     self.assertTrue(form.is_valid(), form._errors)
     logical_volume = form.save()
     expected_size = round_size_to_nearest_block(
         size, PARTITION_ALIGNMENT_SIZE, False
     )
     self.assertThat(
         logical_volume,
         MatchesStructure.byEquality(
             name=name, uuid=vguuid, size=expected_size
         ),
     )
Пример #10
0
    def test_create_returns_403_if_not_admin(self):
        node = factory.make_Node(status=NODE_STATUS.READY)
        block_size = 1024
        device = factory.make_PhysicalBlockDevice(
            node=node,
            size=(MIN_PARTITION_SIZE * 4) + PARTITION_TABLE_EXTRA_SPACE,
            block_size=block_size,
        )
        factory.make_PartitionTable(block_device=device)
        uri = get_partitions_uri(device)

        # Add a partition to the start of the drive.
        size = round_size_to_nearest_block(
            random.randint(MIN_PARTITION_SIZE, MIN_PARTITION_SIZE * 2),
            block_size,
        )
        response = self.client.post(uri, {"size": size})
        self.assertEqual(http.client.FORBIDDEN, response.status_code,
                         response.content)
Пример #11
0
 def test_updates_virtual_block_device(self):
     block_device = factory.make_VirtualBlockDevice()
     name = factory.make_name("lv")
     vguuid = "%s" % uuid.uuid4()
     size = random.randint(
         MIN_BLOCK_DEVICE_SIZE, block_device.filesystem_group.get_size())
     form = UpdateVirtualBlockDeviceForm(instance=block_device, data={
         'name': name,
         'uuid': vguuid,
         'size': size,
         })
     self.assertTrue(form.is_valid(), form.errors)
     block_device = form.save()
     expected_size = round_size_to_nearest_block(
         size, PARTITION_ALIGNMENT_SIZE, False)
     self.assertThat(block_device, MatchesStructure.byEquality(
         name=name,
         uuid=vguuid,
         size=expected_size,
         ))
Пример #12
0
    def test_create_returns_409_if_not_ready(self):
        self.become_admin()
        node = factory.make_Node(
            status=factory.pick_enum(NODE_STATUS, but_not=[NODE_STATUS.READY]))
        block_size = 1024
        device = factory.make_PhysicalBlockDevice(
            node=node,
            size=(MIN_PARTITION_SIZE * 4) + PARTITION_TABLE_EXTRA_SPACE,
            block_size=block_size)
        factory.make_PartitionTable(block_device=device)
        uri = get_partitions_uri(device)

        # Add a partition to the start of the drive.
        size = round_size_to_nearest_block(
            random.randint(
                MIN_PARTITION_SIZE, MIN_PARTITION_SIZE * 2),
            block_size)
        response = self.client.post(
            uri, {
                'size': size,
            })
        self.assertEqual(
            http.client.CONFLICT, response.status_code, response.content)
Пример #13
0
 def test_create_logical_volume_creates_logical_volume(self):
     self.become_admin()
     node = factory.make_Node(status=NODE_STATUS.READY)
     volume_group = factory.make_VolumeGroup(node=node)
     name = factory.make_name("lv")
     vguuid = "%s" % uuid.uuid4()
     size = random.randint(MIN_BLOCK_DEVICE_SIZE, volume_group.get_size())
     uri = get_volume_group_uri(volume_group)
     response = self.client.post(
         uri,
         {
             "op": "create_logical_volume",
             "name": name,
             "uuid": vguuid,
             "size": size,
         },
     )
     self.assertEqual(
         http.client.OK, response.status_code, response.content
     )
     logical_volume = json.loads(
         response.content.decode(settings.DEFAULT_CHARSET)
     )
     expected_size = round_size_to_nearest_block(
         size, PARTITION_ALIGNMENT_SIZE, False
     )
     self.assertThat(
         logical_volume,
         ContainsDict(
             {
                 "name": Equals("%s-%s" % (volume_group.name, name)),
                 "uuid": Equals(vguuid),
                 "size": Equals(expected_size),
             }
         ),
     )
Пример #14
0
 def test__round_up_doesnt_add_extra_block(self):
     block_size = 4096
     size = block_size
     self.assertEqual(size,
                      round_size_to_nearest_block(size, block_size, True),
                      "Shouldn't add an extra block to the size.")
Пример #15
0
 def get_size(self):
     """Total usable size of partition table."""
     return round_size_to_nearest_block(
         self.block_device.size - self.get_overhead_size(),
         PARTITION_ALIGNMENT_SIZE, False)
Пример #16
0
 def get_available_size(self, ignore_partitions=[]):
     """Return the remaining size available for partitions."""
     used_size = self.get_used_size(ignore_partitions=ignore_partitions)
     # Only report 'alignable' space as available for new partitions
     return round_size_to_nearest_block(self.block_device.size - used_size,
                                        PARTITION_ALIGNMENT_SIZE, False)
Пример #17
0
 def _get_mbr_max_for_block_device(self, block_device):
     """Get the maximum partition size for MBR for this block device."""
     return round_size_to_nearest_block(MAX_PARTITION_SIZE_FOR_MBR,
                                        PARTITION_ALIGNMENT_SIZE, False)
Пример #18
0
 def test__round_down_doesnt_remove_block(self):
     block_size = 4096
     size = block_size * 2
     self.assertEqual(size,
                      round_size_to_nearest_block(size, block_size, False),
                      "Shouldn't remove a block from the size.")
Пример #19
0
 def test__round_up_adds_extra_block(self):
     block_size = 4096
     size = block_size + 1
     self.assertEqual(2 * block_size,
                      round_size_to_nearest_block(size, block_size, True),
                      "Should add an extra block to the size.")
Пример #20
0
 def _round_size(self):
     """Round the size of this partition down for alignment."""
     if self.size is not None and self.partition_table is not None:
         self.size = round_size_to_nearest_block(
             self.size, PARTITION_ALIGNMENT_SIZE, False)
Пример #21
0
def get_max_mbr_partition_size():
    """Get the maximum size for an MBR partition."""
    return round_size_to_nearest_block(
        MAX_PARTITION_SIZE_FOR_MBR, PARTITION_ALIGNMENT_SIZE, False)
Пример #22
0
 def test__round_down_removes_block(self):
     block_size = 4096
     size = block_size + 1
     self.assertEqual(1 * block_size,
                      round_size_to_nearest_block(size, block_size, False),
                      "Should remove block from the size.")