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 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 _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 _create_gpt(self): """Create partitions with GPT""" cmd = ['sgdisk', self.image_path] # This padding gives us a little room for rounding so we don't # go over the end of the disk disk_free = self.disk_size - (2048 * 1024) pnum = 1 for p in self.partitions: args = {} args['pnum'] = pnum args['name'] = '%s' % p.get_name() args['type'] = '%s' % p.get_type() # convert from a relative/string size to bytes size = parse_rel_size_spec(p.get_size(), disk_free)[1] # We keep track in bytes, but specify things to sgdisk in # megabytes so it can align on sensible boundaries. And # create partitions right after previous so no need to # calculate start/end - just size. assert size <= disk_free args['size'] = size // (1024 * 1024) new_cmd = ( "-n", "{pnum}:0:+{size}M".format(**args), "-t", "{pnum}:{type}".format(**args), # Careful with this one, as {name} could have spaces "-c", "{pnum}:{name}".format(**args)) cmd.extend(new_cmd) # Fill the state; we 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/" device_name = "/dev/mapper/%sp%d" % (self.device_path[5:], pnum) self.state['blockdev'][p.get_name()] \ = {'device': device_name} disk_free = disk_free - size pnum = pnum + 1 logger.debug("Partition %s added, %s remaining in disk", pnum, disk_free) logger.debug("cmd: %s", ' '.join(cmd)) exec_sudo(cmd)
def _create_gpt(self): """Create partitions with GPT""" cmd = ['sgdisk', self.image_path] # This padding gives us a little room for rounding so we don't # go over the end of the disk disk_free = self.disk_size - (2048 * 1024) pnum = 1 for p in self.partitions: args = {} args['pnum'] = pnum args['name'] = '%s' % p.get_name() args['type'] = '%s' % p.get_type() # convert from a relative/string size to bytes size = parse_rel_size_spec(p.get_size(), disk_free)[1] # We keep track in bytes, but specify things to sgdisk in # megabytes so it can align on sensible boundaries. And # create partitions right after previous so no need to # calculate start/end - just size. assert size <= disk_free args['size'] = size // (1024 * 1024) new_cmd = ("-n", "{pnum}:0:+{size}M".format(**args), "-t", "{pnum}:{type}".format(**args), # Careful with this one, as {name} could have spaces "-c", "{pnum}:{name}".format(**args)) cmd.extend(new_cmd) # Fill the state; we 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/" device_name = "/dev/mapper/%sp%d" % (self.device_path[5:], pnum) self.state['blockdev'][p.get_name()] \ = {'device': device_name} disk_free = disk_free - size pnum = pnum + 1 logger.debug("Partition %s added, %s remaining in disk", pnum, disk_free) logger.debug("cmd: %s", ' '.join(cmd)) exec_sudo(cmd)
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
def test_parse_rel_size_with_abs(self): """Calls parse_rel_size_spec with an absolute number""" is_rel, size = parse_rel_size_spec("154MiB", 0) self.assertFalse(is_rel) self.assertEqual(154 * 1024 * 1024, size)