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(),
    )
Beispiel #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)
Beispiel #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(),
     )
Beispiel #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,
     )
Beispiel #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,
     )
Beispiel #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(),
     )
Beispiel #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)
Beispiel #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()
Beispiel #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
         ),
     )
Beispiel #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)
Beispiel #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,
         ))
Beispiel #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)
Beispiel #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),
             }
         ),
     )
Beispiel #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.")
Beispiel #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)
Beispiel #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)
Beispiel #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)
Beispiel #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.")
Beispiel #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.")
Beispiel #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)
Beispiel #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)
Beispiel #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.")