def create(self): # This is a bit of a hack. Each of the partitions is actually # in the graph, so for every partition we get a create() call # as the walk happens. But we only need to create the # partition table once... if self.already_created: logger.info("Not creating the partitions a second time.") return self.already_created = True # the raw file on disk image_path = self.state['blockdev'][self.base]['image'] # the /dev/loopX device of the parent device_path = self.state['blockdev'][self.base]['device'] logger.info("Creating partition on [%s] [%s]", self.base, image_path) assert self.label == 'mbr' disk_size = self._size_of_block_dev(image_path) with MBR(image_path, disk_size, self.align) as part_impl: for part_cfg in self.partitions: part_name = part_cfg.get_name() part_bootflag = PartitionNode.flag_boot \ in part_cfg.get_flags() part_primary = PartitionNode.flag_primary \ in part_cfg.get_flags() part_size = part_cfg.get_size() part_free = part_impl.free() part_type = part_cfg.get_type() logger.debug("Not partitioned space [%d]", part_free) part_size = parse_rel_size_spec(part_size, part_free)[1] part_no \ = part_impl.add_partition(part_primary, part_bootflag, part_size, part_type) logger.debug("Create partition [%s] [%d]", part_name, part_no) # We're going to mount all partitions with kpartx # below once we're done. So the device this partition # will be seen at becomes "/dev/mapper/loop0pX" assert device_path[:5] == "/dev/" partition_device_name = "/dev/mapper/%sp%d" % \ (device_path[5:], part_no) self.state['blockdev'][part_name] \ = {'device': partition_device_name} # "saftey sync" to make sure the partitions are written exec_sudo(["sync"]) # now all the partitions are created, get device-mapper to # mount them if not os.path.exists("/.dockerenv"): exec_sudo(["kpartx", "-avs", device_path]) else: # If running inside Docker, make our nodes manually, # because udev will not be working. kpartx cannot run in # sync mode in docker. exec_sudo(["kpartx", "-av", device_path]) exec_sudo(["dmsetup", "--noudevsync", "mknodes"]) return
def test_many_ext_partitions(self): """Creates many partition and check correctness with partx.""" tmp_dir, image_path = self._create_image() with MBR(image_path, TestMBR.disk_size_1G, 1024 * 1024) as mbr: for nr in range(0, 64): mbr.add_partition(False, False, TestMBR.disk_size_10M, 0x83) output = self._run_partx(image_path) shutil.rmtree(tmp_dir) lines = output.split("\n") self.assertEqual(66, len(lines)) self.assertEqual("1 2048 2097151 0xf 0x0 dos", lines[0]) start_block = 4096 end_block = start_block + TestMBR.disk_size_10M / 512 - 1 for nr in range(1, 65): fields = lines[nr].split(" ") self.assertEqual(6, len(fields)) self.assertEqual(nr + 4, int(fields[0])) self.assertEqual(start_block, int(fields[1])) self.assertEqual(end_block, int(fields[2])) self.assertEqual("0x83", fields[3]) self.assertEqual("0x0", fields[4]) self.assertEqual("dos", fields[5]) start_block += 22528 end_block = start_block + TestMBR.disk_size_10M / 512 - 1
def test_many_pri_and_ext_partition(self): """Creates many primary and extended partitions.""" tmp_dir, image_path = self._create_image() with MBR(image_path, TestMBR.disk_size_1G, 1024 * 1024) as mbr: # Create three primary partitions for _ in range(3): mbr.add_partition(True, False, TestMBR.disk_size_10M, 0x83) for _ in range(7): mbr.add_partition(False, False, TestMBR.disk_size_10M, 0x83) output = self._run_partx(image_path) shutil.rmtree(tmp_dir) self.assertEqual( "1 2048 22527 0x83 0x0 dos\n" # Primary 1 "2 22528 43007 0x83 0x0 dos\n" # Primary 2 "3 43008 63487 0x83 0x0 dos\n" # Primary 3 "4 63488 2097151 0xf 0x0 dos\n" # Extended "5 65536 86015 0x83 0x0 dos\n" # Extended Partition 1 "6 88064 108543 0x83 0x0 dos\n" # Extended Partition 2 "7 110592 131071 0x83 0x0 dos\n" # ... "8 133120 153599 0x83 0x0 dos\n" "9 155648 176127 0x83 0x0 dos\n" "10 178176 198655 0x83 0x0 dos\n" "11 200704 221183 0x83 0x0 dos\n", output)
def test_zero_partitions(self): """Creates no partition and check correctness with partx.""" with MBR(self.image_path, TestMBR.disk_size_1G, 1024 * 1024): pass output = self._run_partx(self.image_path) self.assertEqual("", output)
def _create_mbr(self): """Create partitions with MBR""" with MBR(self.image_path, self.disk_size, self.align) as part_impl: for part_cfg in self.partitions: part_name = part_cfg.get_name() part_bootflag = PartitionNode.flag_boot \ in part_cfg.get_flags() part_primary = PartitionNode.flag_primary \ in part_cfg.get_flags() part_size = part_cfg.get_size() part_free = part_impl.free() part_type = part_cfg.get_type() logger.debug("Not partitioned space [%d]", part_free) part_size = parse_rel_size_spec(part_size, part_free)[1] part_no \ = part_impl.add_partition(part_primary, part_bootflag, part_size, part_type) logger.debug("Create partition [%s] [%d]", part_name, part_no) # We're going to mount all partitions with kpartx # below once we're done. So the device this partition # will be seen at becomes "/dev/mapper/loop0pX" assert self.device_path[:5] == "/dev/" partition_device_name = "/dev/mapper/%sp%d" % \ (self.device_path[5:], part_no) self.state['blockdev'][part_name] \ = {'device': partition_device_name}
def test_one_pri_partition(self): """Creates one primary partition and check correctness with partx.""" with MBR(self.image_path, TestMBR.disk_size_1G, 1024 * 1024) as mbr: mbr.add_partition(True, False, TestMBR.disk_size_10M, 0x83) output = self._run_partx(self.image_path) self.assertEqual("1 2048 22527 0x83 0x0 dos\n", output)
def test_pri_fat32_lba_partition(self): """Creates a partition with a non-default 'type' and verifies.""" with MBR(self.image_path, TestMBR.disk_size_1G, 1024 * 1024) as mbr: mbr.add_partition(True, False, TestMBR.disk_size_10M, 0x0c) output = self._run_partx(self.image_path) self.assertEqual( "1 2048 22527 0xc 0x0 dos\n", output)
def test_one_ext_partition(self): """Creates one partition and check correctness with partx.""" with MBR(self.image_path, TestMBR.disk_size_1G, 1024 * 1024) as mbr: mbr.add_partition(False, False, TestMBR.disk_size_10M, 0x83) output = self._run_partx(self.image_path) self.assertEqual( "1 2048 2097151 0xf 0x0 dos\n" "5 4096 24575 0x83 0x0 dos\n", output)
def test_zero_partitions(self): """Creates no partition and check correctness with partx.""" tmp_dir, image_path = self._create_image() with MBR(image_path, TestMBR.disk_size_1G, 1024 * 1024): pass output = self._run_partx(image_path) shutil.rmtree(tmp_dir) self.assertEqual("", output)
def test_three_pri_partition(self): """Creates three primary partition and check correctness with partx.""" with MBR(self.image_path, TestMBR.disk_size_1G, 1024 * 1024) as mbr: for _ in range(3): mbr.add_partition(True, False, TestMBR.disk_size_10M, 0x83) output = self._run_partx(self.image_path) self.assertEqual( "1 2048 22527 0x83 0x0 dos\n" "2 22528 43007 0x83 0x0 dos\n" "3 43008 63487 0x83 0x0 dos\n", output)
def test_one_ext_partition(self, mock_os_fsync): """Creates one partition and check correctness with partx.""" with MBR(self.image_path, TestMBR.disk_size_1G, 1024 * 1024) as mbr: mbr.add_partition(False, False, TestMBR.disk_size_10M, 0x83) # the exit handler of MBR should have synced the raw device # before exit mock_os_fsync.assert_called() output = self._run_partx(self.image_path) self.assertEqual( "1 2048 2097151 0xf 0x0 dos\n" "5 4096 24575 0x83 0x0 dos\n", output)
def create(self, state, rollback): # not this is NOT a node and this is not called directly! The # create() calls in the partition nodes this plugin has # created are calling back into this. image_path = state['blockdev'][self.base]['image'] device_path = state['blockdev'][self.base]['device'] logger.info("Creating partition on [%s] [%s]", self.base, image_path) # This is a bit of a hack. Each of the partitions is actually # in the graph, so for every partition we get a create() call # as the walk happens. But we only need to create the # partition table once... if self.already_created: logger.info("Not creating the partitions a second time.") return assert self.label == 'mbr' partition_devices = set() disk_size = self._size_of_block_dev(image_path) with MBR(image_path, disk_size, self.align) as part_impl: for part_cfg in self.partitions: part_name = part_cfg.get_name() part_bootflag = PartitionNode.flag_boot \ in part_cfg.get_flags() part_primary = PartitionNode.flag_primary \ in part_cfg.get_flags() part_size = part_cfg.get_size() part_free = part_impl.free() part_type = part_cfg.get_type() logger.debug("Not partitioned space [%d]", part_free) part_size = parse_rel_size_spec(part_size, part_free)[1] part_no \ = part_impl.add_partition(part_primary, part_bootflag, part_size, part_type) logger.debug("Create partition [%s] [%d]", part_name, part_no) partition_device_name = device_path + "p%d" % part_no state['blockdev'][part_name] \ = {'device': partition_device_name} partition_devices.add(partition_device_name) self.already_created = True self._notify_os_of_partition_changes(device_path, partition_devices) return
def create(self, result, rollback): image_path = result['blockdev'][self.base]['image'] device_path = result['blockdev'][self.base]['device'] logger.info("Creating partition on [%s] [%s]" % (self.base, image_path)) if self.already_created: logger.info("Not creating the partitions a second time.") return assert self.label == 'mbr' partition_devices = set() disk_size = self._size_of_block_dev(image_path) with MBR(image_path, disk_size, self.align) as part_impl: for part_cfg in self.partitions: part_name = part_cfg.get_name() part_bootflag = Partitioning.flag_boot \ in part_cfg.get_flags() part_primary = Partitioning.flag_primary \ in part_cfg.get_flags() part_size = part_cfg.get_size() part_free = part_impl.free() part_type = part_cfg.get_type() logger.debug("Not partitioned space [%d]" % part_free) part_size = parse_rel_size_spec(part_size, part_free)[1] part_no \ = part_impl.add_partition(part_primary, part_bootflag, part_size, part_type) logger.debug("Create partition [%s] [%d]" % (part_name, part_no)) partition_device_name = device_path + "p%d" % part_no result['blockdev'][part_name] \ = {'device': partition_device_name} partition_devices.add(partition_device_name) self.already_created = True self._notify_os_of_partition_changes(device_path, partition_devices) return