def test_is_vmfs_partition_false_different_block_device(self): node = factory.make_Node(with_boot_disk=False) factory.make_PhysicalBlockDevice(node=node, size=LARGE_BLOCK_DEVICE) layout = VMFS6StorageLayout(node) layout.configure() other_bd_part = factory.make_Partition(node=node) self.assertFalse(other_bd_part.is_vmfs_partition())
def make_Node_with_VMFS6_layout(*args, **kwargs): """Create a node with the VMFS6 storage layout applied.""" kwargs['with_boot_disk'] = False node = factory.make_Node(*args, **kwargs) factory.make_PhysicalBlockDevice(node=node, size=LARGE_BLOCK_DEVICE) layout = VMFS6StorageLayout(node) layout.configure() return node
def test_delete_not_allowed_if_part_of_vmfs_layout(self): node = factory.make_Node(with_boot_disk=False) bd = factory.make_PhysicalBlockDevice(node=node, size=LARGE_BLOCK_DEVICE) layout = VMFS6StorageLayout(node) layout.configure() pt = bd.get_partitiontable() partition = random.choice(list(pt.partitions.all())) self.assertRaises(ValidationError, partition.delete)
def test_is_vmfs_partition_false_extra_partition(self): node = factory.make_Node(with_boot_disk=False) bd = factory.make_PhysicalBlockDevice(node=node, size=LARGE_BLOCK_DEVICE) layout = VMFS6StorageLayout(node, {"root_size": 10 * 1024**3}) layout.configure() pt = bd.get_partitiontable() extra_partition = pt.add_partition() self.assertFalse(extra_partition.is_vmfs_partition())
def test_is_vmfs_partition(self): node = factory.make_Node(with_boot_disk=False) bd = factory.make_PhysicalBlockDevice(node=node, size=LARGE_BLOCK_DEVICE) layout = VMFS6StorageLayout(node) layout.configure() pt = bd.get_partitiontable() for partition in pt.partitions.all(): self.assertTrue(partition.is_vmfs_partition())
def test_get_partition_number_returns_vmfs_order(self): node = factory.make_Node(with_boot_disk=False) bd = factory.make_PhysicalBlockDevice( node=node, size=LARGE_BLOCK_DEVICE) layout = VMFS6StorageLayout(node) layout.configure() pt = bd.get_partitiontable() self.assertItemsEqual( [1, 2, 3, 5, 6, 7, 8, 9], [part.get_partition_number() for part in pt.partitions.all()])
def test_is_not_valid_if_vmfs_partition(self): node = factory.make_Node(with_boot_disk=False) bd = factory.make_PhysicalBlockDevice(node=node, size=LARGE_BLOCK_DEVICE) layout = VMFS6StorageLayout(node) layout.configure() pt = bd.get_partitiontable() partition = random.choice(list(pt.partitions.all())) form = FormatPartitionForm(partition, {"fstype": FILESYSTEM_TYPE.EXT4}) self.assertFalse(form.is_valid())
def get_partition_number(self): """Return the partition number in the table.""" # Avoid circular imports. from maasserver.storage_layouts import VMFS6StorageLayout # Sort manually instead of with `order_by`, this will prevent django # from making a query if the partitions are already cached. partitions_in_table = self.partition_table.partitions.all() partitions_in_table = sorted(partitions_in_table, key=attrgetter('id')) idx = partitions_in_table.index(self) if self.partition_table.table_type == PARTITION_TABLE_TYPE.GPT: # In some instances the first partition is skipped because it # is used by the machine architecture for a specific reason. # * ppc64el - reserved for prep partition # * amd64 (not UEFI) - reserved for bios_grub partition node = self.get_node() arch, _ = node.split_arch() boot_disk = node.get_boot_disk() bios_boot_method = node.get_bios_boot_method() block_device = self.partition_table.block_device vmfs_layout = VMFS6StorageLayout(self.get_node()) vmfs_bd = vmfs_layout.is_layout() if vmfs_bd is not None: # VMware ESXi is a DD image but MAAS allows partitions to # be added to the end of the disk as well as resize the # datastore partition. The EFI partition is already in the # image so there is no reason to account for it. if vmfs_bd.id == block_device.id and idx >= 3: # VMware ESXi skips the 4th partition. return idx + 2 else: return idx + 1 elif (arch == "ppc64el" and block_device.id == boot_disk.id): return idx + 2 elif arch == "amd64" and bios_boot_method != "uefi": if block_device.type == 'physical': # Delay the `type` check because it can cause a query. Only # physical block devices get the bios_grub partition. return idx + 2 else: return idx + 1 else: return idx + 1 elif self.partition_table.table_type == PARTITION_TABLE_TYPE.MBR: # If more than 4 partitions then the 4th partition number is # skipped because that is used for the extended partition. if len(partitions_in_table) > 4 and idx > 2: return idx + 2 else: return idx + 1 else: raise ValueError("Unknown partition table type.")
def is_vmfs_partition(self): # Avoid circular imports. from maasserver.storage_layouts import VMFS6StorageLayout vmfs_layout = VMFS6StorageLayout(self.get_node()) vmfs_bd = vmfs_layout.is_layout() if vmfs_bd is None: return False if vmfs_bd.id != self.partition_table.block_device_id: return False if self.get_partition_number() >= len(vmfs_layout.base_partitions) + 2: # A user may apply the VMFS6 layout and leave space at the end of # the disk for additional VMFS datastores. Those partitions may be # deleted, the base partitions may not as they are part of the DD. # The + 2 is to account for partition 4 being skipped. return False return True
def test_POST_creates_with_block_devices_and_partitions(self): self.become_admin() node = factory.make_Machine(status=NODE_STATUS.READY, with_boot_disk=False) node.boot_disk = factory.make_PhysicalBlockDevice( node=node, size=LARGE_BLOCK_DEVICE) layout = VMFS6StorageLayout(node) layout.configure() block_devices = [ factory.make_PhysicalBlockDevice(node=node) for _ in range(3) ] block_device = factory.make_PhysicalBlockDevice( node=node, size=MIN_PARTITION_SIZE * 3 + PARTITION_TABLE_EXTRA_SPACE, ) partition_table = factory.make_PartitionTable( block_device=block_device) partitions = [ partition_table.add_partition(size=MIN_PARTITION_SIZE) for _ in range(2) ] name = factory.make_name("name") vmfs_uuid = uuid.uuid4() response = self.client.post( self.get_vmfs_uri(node), { "name": name, "uuid": vmfs_uuid, "block_devices": [bd.id for bd in block_devices], "partitions": [part.id for part in partitions], }, ) self.assertThat(response, HasStatusCode(http.client.OK)) parsed_results = json_load_bytes(response.content) self.assertEquals(node.system_id, parsed_results["system_id"]) # VMFS should be using the 5 devices we listed above. self.assertEquals(5, len(parsed_results["devices"])) # VMFS should be using all the block devices we created. self.assertItemsEqual( [bd.id for bd in block_devices] + [block_device.id], set([result["device_id"] for result in parsed_results["devices"]]), )