def insert(self, index, value): # check that the name of the zpool is not already in the list if value.name in [zpool.name for zpool in self._shadow]: self.set_error(self.DuplicateZpoolNameError(value.name)) # if is_root is set to True, verify there are no other zpools with # is_root set to True if value.is_root: for zpool in self._shadow: if zpool.is_root: self.set_error(self.TooManyRootPoolsError(zpool.name)) # verify the mountpoint (if specified) doesn't overlap with any other # zpool mountpoints if value.mountpoint is not None: for zpool in self._shadow: if zpool.mountpoint is not None: common = os.path.commonprefix([value.mountpoint, zpool.mountpoint]) # the only character in common should be "/". If it's # anything else, the mountpoints overlap if common != ("/"): self.set_error(self.DuplicateMountpointError( value.mountpoint)) # insert the zpool ShadowList.insert(self, index, value)
def insert(self, index, value): # check that the name of the zpool is not already in the list if value.name in [zpool.name for zpool in self._shadow]: self.set_error(self.DuplicateZpoolNameError(value.name)) # if is_root is set to True, verify there are no other zpools with # is_root set to True if value.is_root: for zpool in self._shadow: if zpool.is_root: self.set_error(self.TooManyRootPoolsError(zpool.name)) # verify the mountpoint (if specified) doesn't overlap with any other # zpool mountpoints if value.mountpoint is not None: for zpool in self._shadow: if zpool.mountpoint is not None: common = os.path.commonprefix( [value.mountpoint, zpool.mountpoint]) # the only character in common should be "/". If it's # anything else, the mountpoints overlap if common != ("/"): self.set_error( self.DuplicateMountpointError(value.mountpoint)) # insert the zpool ShadowList.insert(self, index, value)
def __init__(self, container, *args): ShadowList.__init__(self, *args) self.mod_id = "zfs dataset validation" self.container = container for entry in args: self.append(entry) # will call self.insert
def __init__(self, container, *args): ShadowList.__init__(self, *args) self.mod_id = "zpool validation" self.container = container for entry in args: self.append(entry) # will call self.insert
def insert(self, index, value): """ insert() - overridden method for validation of logical DOC objects the following checks are done as part of validation: - duplicate dataset name (zfs filesystems and zvolss) - duplicate dataset mountpoint (zfs filesystems) - verifies the <logical> tag's noswap and nodump values do not conflict with the use attribute of a Zvol object - more than 1 zvol with maximum size per pool """ # reset the errsvc for Logical errors errsvc.clear_error_list_by_mod_id(self.mod_id) # check the existing datasets for name and mountpoint overlap for dataset in self._shadow: # look for name duplication if not an Options object if not hasattr(value, "OPTIONS_PARAM_STR") and \ value.name == dataset.name: self.set_error(self.DuplicateDatasetNameError(dataset.name)) # check the mountpoint if this is a Filesystem object if hasattr(value, "mountpoint") and hasattr(dataset, "mountpoint"): if value.mountpoint is not None and \ value.mountpoint.lower() not in ["none", "legacy"] and \ value.mountpoint == dataset.mountpoint: self.set_error( self.DuplicateMountpointError(dataset.name, dataset.mountpoint)) # check for multiple zvol with max size in same pool if hasattr(value, "use") and hasattr(dataset, "use"): if isinstance(value.size, str) and \ isinstance(dataset.size, str) and value.size == "max" and \ dataset.size == "max" and \ self.container.name == dataset.parent.name: self.set_error( self.MaxSizeZvolError(value.name, dataset.name)) # check the 'use' attribute for Zvol objects. The grandparent of the # entry is the <logical> element if hasattr(value, "use") and value.use is not "none": if value.use == "swap" and self.container.parent.noswap: self.set_error(self.NoswapMismatchError()) if value.use == "dump" and self.container.parent.nodump: self.set_error(self.NodumpMismatchError()) # insert the filesystem ShadowList.insert(self, index, value)
def remove(self, value): # reset the errsvc for Physical errors errsvc.clear_error_list_by_mod_id(self.mod_id) # Check slices or GPT partitions for in use conclicts if hasattr(value, "force"): # check for in_use conflicts. stats = self.in_use_check(value) if stats and not value.force: self.set_error(self.SliceInUseError(stats)) # remove the object ShadowList.remove(self, value)
def insert(self, index, value): # check the container object's adjust_boundaries attribute. If False, # simply insert the object into the shadow list if hasattr(self.container, "validate_children") and \ not self.container.validate_children: ShadowList.insert(self, index, value) else: # reset the errsvc for Physical errors errsvc.clear_error_list_by_mod_id(self.mod_id) # Check the value to see what kind of DOC object we're trying to # insert. We can't import the classes from target.physical because # it results in a circular import, so look at class name instead. insert_map = {"GPTPartition": self.insert_gptpartition, "Slice": self.insert_slice, "Partition": self.insert_partition} insert_map[value.__class__.__name__](index, value)
def insert(self, index, value): # check the container object's adjust_boundaries attribute. If False, # simply insert the object into the shadow list if hasattr(self.container, "validate_children") and \ not self.container.validate_children: ShadowList.insert(self, index, value) else: # reset the errsvc for Physical errors errsvc.clear_error_list_by_mod_id(self.mod_id) # check the value to see what kind of DOC object we're trying to # insert. if hasattr(value, "force"): # this is a Slice object, so call insert_slice self.insert_slice(index, value) elif hasattr(value, "part_type"): # this is a Partition object, so call insert_partition self.insert_partition(index, value)
def insert(self, index, value): # check the container object's adjust_boundaries attribute. If False, # simply insert the object into the shadow list if hasattr(self.container, "validate_children") and \ not self.container.validate_children: ShadowList.insert(self, index, value) else: # reset the errsvc for Physical errors errsvc.clear_error_list_by_mod_id(self.mod_id) # check the value to see what kind of DOC object we're trying to # insert. if hasattr(value, "force"): # this is a Slice object, so call insert_slice self.insert_slice(index, value) elif hasattr(value, "part_type"): # this is a Partition object, so call insert_partition self.insert_partition(index, value)
def remove(self, value): # reset the errsvc for Physical errors errsvc.clear_error_list_by_mod_id(self.mod_id) # look for slices only if hasattr(value, "force"): # set the ctds of the slice if hasattr(self.container, "geometry"): # container is a Disk object ctds = self.container.ctd + "s%s" % value.name elif hasattr(self.container, "part_type"): # container is a Partition object ctds = self.container.parent.ctd + "s%s" % value.name # check for in_use conflicts. Re-query libdiskmgt due to circular # import issues with trying to navigate the DOC stats = self.in_use_check(ctds) if stats and not value.force: self.set_error(self.SliceInUseError(stats)) # remove the object ShadowList.remove(self, value)
def remove(self, value): # reset the errsvc for Physical errors errsvc.clear_error_list_by_mod_id(self.mod_id) # look for slices only if hasattr(value, "force"): # set the ctds of the slice if hasattr(self.container, "geometry"): # container is a Disk object ctds = self.container.ctd + "s%s" % value.name elif hasattr(self.container, "part_type"): # container is a Partition object ctds = self.container.parent.ctd + "s%s" % value.name # check for in_use conflicts. Re-query libdiskmgt due to circular # import issues with trying to navigate the DOC stats = self.in_use_check(ctds) if stats and not value.force: self.set_error(self.SliceInUseError(stats)) # remove the object ShadowList.remove(self, value)
def insert_partition(self, index, value): """ insert_partition() - override method for validation of Partition DOC objects. the following checks are done as part of validation: - Partition objects *must* have a part_type. - the parent Disk object does not have whole_disk attribute set - the start_sector of the slice is an int or long and is between 0 and the container's maximum size - if a partition is a logical partition, ensure there is an extended partition somewhere in indexes 1-4 - no more than MAX_EXT_PARTS logical partitions - logical partitions fall within the boundaries of the extended partition - Only one active primary partition - primary partitions are not larger than the Disk - no overlapping boundaries of the partition with any other partitions already inserted - no duplicate indexes - the extended partition is at least 63 sectors in size and there is only one extended partition specified - none of the parent objects have an in_zpool or in_vdev attribute set """ # verify part_type is not None if value.part_type is None: self.set_error(self.PartitionTypeMissingError()) # verify the name of the partition is valid if not (1 <= int(value.name) <= (FD_NUMPART + MAX_EXT_PARTS)): self.set_error( self.InvalidPartitionNameError(str(value.name), self.container.ctd)) # fix the start_sector and size to align to cylinder boundaries for # primary partitions if value.is_primary: value = self.cylinder_boundary_adjustment(value) # check the bounds of the partition to be added. if not (isinstance(value.start_sector, int) or \ isinstance(value.start_sector, long)): self.set_error(self.InvalidPartitionStartSectorError()) if hasattr(self.container.disk_prop, "dev_size") and \ getattr(self.container.disk_prop, "dev_size") is not None: if not (0 <= value.start_sector <= \ self.container.disk_prop.dev_size.sectors): self.set_error(self.InvalidPartitionStartSectorError()) # verify that the Disk does not have 'whole_disk' set to 'true' if self.container.whole_disk: self.set_error(self.WholeDiskIsTrueError()) # if the partition is a logical partition, ensure there is a partition # with part_type in Partition.EXTENDED_ID_LIST has already been # inserted. if value.is_logical: extended_part = None for partition in self._shadow: if partition.is_extended: if partition.part_type in partition.EXTENDED_ID_LIST: extended_part = partition if extended_part is None: self.set_error(self.NoExtPartitionsError()) else: # verify there are not more than MAX_EXT_PARTS logical_list = [p for p in self._shadow if p.is_logical and \ p.action != "delete"] if len(logical_list) >= MAX_EXT_PARTS: self.set_error(self.TooManyLogicalPartitionsError()) # ensure this logical partition does not start too close to any # previously inserted logical partitions. # sort the logical list by start sector slist = sorted( logical_list, lambda x, y: cmp(x.start_sector, y.start_sector)) # find the closest logical partition within the extended # partition closest_endpoint = 0 for logical in slist: end_point = logical.start_sector + logical.size.sectors if end_point < value.start_sector and \ end_point > closest_endpoint: closest_endpoint = end_point if closest_endpoint == 0: # no logical partitions were found, so use the start of the # extended partition, if the difference is smaller than the # needed offset diff = value.start_sector - extended_part.start_sector if diff < LOGICAL_ADJUSTMENT and value.action == "create": value.start_sector = extended_part.start_sector + \ LOGICAL_ADJUSTMENT new_size = value.size.sectors - LOGICAL_ADJUSTMENT value.size = Size(str(new_size) + Size.sector_units) else: diff = value.start_sector - closest_endpoint # make sure there's at least 63 sectors between logical # partitions if diff < LOGICAL_ADJUSTMENT and value.action == "create": value.start_sector += LOGICAL_ADJUSTMENT - diff new_size = value.size.sectors - LOGICAL_ADJUSTMENT value.size = Size(str(new_size) + Size.sector_units) # check the bootid attibute on primary partitions for multiple active # partitions if value.is_primary and value.bootid == value.ACTIVE: for partition in self._shadow: # skip logical partitions if partition.is_logical: continue # check the bootid attribute if partition.bootid == value.ACTIVE: self.set_error( self.MultipleActivePartitionsError(partition.name)) p_start = value.start_sector p_end = p_start + value.size.sectors - 1 # walk each inserted partition already in the shadow list to ensure the # partition we're trying to insert doesn't cross boundaries. for partition in self._shadow: # start and end points of the partition to check if partition.is_primary: start = partition.start_sector end = start + partition.size.sectors - 1 else: # for logical partitions, there needs to be a buffer of # LOGICAL_ADJUSTMENT on each end start = partition.start_sector - LOGICAL_ADJUSTMENT end = start + partition.size.sectors - 1 + LOGICAL_ADJUSTMENT if value.is_primary: # do not test logical partition boundaries for primary # partitions if partition.is_logical: continue else: # verify the logical partition we're trying to insert fits # within the extended partition "parent" if partition.is_extended and partition.action != "delete": if p_start < start or p_end > end: self.set_error(self.LogicalPartitionOverlapError()) # do not test primary partition boundaries for logical # partitions if partition.is_primary: continue # check that the start sector of the partition we're trying to # insert is not within another partition and the existing partition # isn't inside the partition we're inserting. Primary partitions # are only checked against other primary partitions and logical # partitions are only checked aginst other logical partitions. # Partitions marked for deletion should not be checked at all if value.action != "delete" and partition.action != "delete": if ((start <= p_start <= end) or (start <= p_end <= end)) or \ ((p_start <= start <= p_end) or (p_start <= end <= p_end)): self.set_error( self.OverlappingPartitionError(partition.name, value.name)) # check that a primary partition doesn't exceed the size of the Disk, # if the dev_size is specified if hasattr(self.container.disk_prop, "dev_size") and \ self.container.disk_prop.dev_size is not None and \ value.is_primary: disk_size = self.container.disk_prop.dev_size.sectors p_size = value.start_sector + value.size.sectors # check that the name of the partition is not already in the list if value.name in [p.name for p in self._shadow \ if p.action != "delete"]: self.set_error(self.DuplicatePartitionNameError(value.name)) # if this is an extended partition, verify there are no other # partitions of the same type. Also verify it's at least # LOGICAL_ADJUSTMENT sectors in size if value.is_extended: for partition in self._shadow: if partition.is_extended and partition.action != "delete": self.set_error(self.TooManyExtPartitionsError()) if value.size.sectors < LOGICAL_ADJUSTMENT: self.set_error(self.ExtPartitionTooSmallError()) # if the partition type is FAT16, make sure it's not larger than 4GB fat16_list = [ value.name_to_num("FAT16 (Upto 32M)"), value.name_to_num("FAT16 (>32M, HUGEDOS)"), value.name_to_num("WIN95 FAT16(LBA)") ] if value.part_type in fat16_list and value.action == "create": if value.size.byte_value > Size.units["gb"] * 4: self.set_error(self.FAT16PartitionTooLargeError()) # check to see if the container object has the same in_zpool attribute if value.in_zpool is not None: if getattr(self.container, "in_zpool") == value.in_zpool: self.set_error(self.OverlappingPartitionZpoolError()) # check to see if the container object has the same in_vdev attribute if value.in_vdev is not None: if getattr(self.container, "in_vdev") == value.in_vdev: self.set_error(self.OverlappingPartitionVdevError()) # insert the partition ShadowList.insert(self, index, value)
def insert_slice(self, index, value): """ insert_slice() - override method for validation of Slice DOC objects. the following checks are done as part of validation: - the parent Disk object does not have whole_disk attribute set - the start_sector of the slice is an int or long and is between 0 and the container's maximum size - no overlapping boundaries of the slice with any other slices already inserted - no more than V_NUMPAR slices - no duplicate indexes (ie. no duplicate slice numbers) - none of the parent objects have an in_zpool or in_vdev attribute set """ # set the proper cylinder boundry, parent_size and ctds string based on # the container type if hasattr(self.container, "geometry"): # container is a Disk object parent_size = self.container.disk_prop.dev_size.sectors ctds = self.container.ctd + "s%s" % value.name label = self.container.label # verify that the Disk does not have 'whole_disk' set to 'true' if self.container.whole_disk: self.set_error(self.WholeDiskIsTrueError()) elif hasattr(self.container, "part_type"): # container is a Partition object parent_size = self.container.size.sectors ctds = self.container.parent.ctd + "s%s" % value.name label = self.container.parent.label # check the bounds of the slice to be added. if not (isinstance(value.start_sector, int) or \ isinstance(value.start_sector, long)): self.set_error(self.InvalidSliceStartSectorError()) if not (0 <= value.start_sector <= parent_size): self.set_error(self.InvalidSliceStartSectorError()) # find the cylinder boundary of the disk and adjust the Slice's start # and size to fall on a cylinder boundary. start and end will be on # the boundaries and in blocks. # only adjust the start sector for VTOC slices that are do not have the # V_BOOT or V_BACKUP tag. if label == "VTOC" and value.tag not in [V_BACKUP, V_BOOT]: # fix the start_sector and size to align to cylinder boundaries value = self.cylinder_boundary_adjustment(value) cb_start = value.start_sector cb_end = value.start_sector + value.size.sectors - 1 # verify each slice does not overlap with any other slice for slc in self._shadow: # if slice 2 is being inserted into a VTOC labeled disk, do not # check for overlap if label == "VTOC" and int(value.name) == 2: break # skip VTOC overlap slice if it is already inserted into the # shadow list if label == "VTOC" and int(slc.name) == 2: continue # calculate the range of each slice already inserted start = slc.start_sector end = slc.start_sector + slc.size.sectors - 1 # check that the start sector is not within another slice and # the existing slice isn't inside the new slice but only for slices # not marked for deletion if value.action != "delete" and slc.action != "delete": if (start <= cb_start <= end or start <= cb_end <= end) or \ (cb_start <= start <= cb_end or cb_start <= end <= cb_end): self.set_error( self.OverlappingSliceError(value.name, slc.name)) if len(self._shadow) >= V_NUMPAR: self.set_error(self.TooManySlicesError()) # check for duplicate slice.name values if value.name in [slc.name for slc in self._shadow \ if slc.action != "delete"]: self.set_error(self.DuplicateSliceNameError(value.name)) # check for in_zpool overlap if value.in_zpool is not None: # check the container if getattr(self.container, "in_zpool") == value.in_zpool: self.set_error(self.OverlappingSliceZpoolError()) # check the container's parent if it's a partition if hasattr(self.container, "part_type"): if getattr(self.container.parent, "in_zpool") == \ value.in_zpool: self.set_error(self.OverlappingSliceZpoolError()) # check for in_vdev overlap if value.in_vdev is not None: # check the container if getattr(self.container, "in_vdev") == value.in_vdev: self.set_error(self.OverlappingSliceVdevError()) # check the container's parent if it's a partition if hasattr(self.container, "part_type"): if getattr(self.container.parent, "in_vdev") == \ value.in_vdev: self.set_error(self.OverlappingSliceVdevError()) # check for in_use conflicts. Re-query libdiskmgt due to circular # import issues with trying to navigate the DOC stats = self.in_use_check(ctds) if stats and value.action != "preserve" and not value.force: self.set_error(self.SliceInUseError(stats)) # insert the corrected Slice object ShadowList.insert(self, index, value)
def insert_partition(self, index, value): """ insert_partition() - override method for validation of Partition DOC objects. the following checks are done as part of validation: - Partition objects *must* have a part_type. - the parent Disk object does not have whole_disk attribute set - the start_sector of the slice is an int or long and is between 0 and the container's maximum size - if a partition is a logical partition, ensure there is an extended partition somewhere in indexes 1-4 - no more than MAX_EXT_PARTS logical partitions - logical partitions fall within the boundaries of the extended partition - Only one active primary partition - primary partitions are not larger than the Disk - no overlapping boundaries of the partition with any other partitions already inserted - no duplicate indexes - the extended partition is at least 63 sectors in size and there is only one extended partition specified - none of the parent objects have an in_zpool or in_vdev attribute set """ # verify part_type is not None if value.part_type is None: self.set_error(self.PartitionTypeMissingError()) # verify the name of the partition is valid if not (1 <= int(value.name) <= (FD_NUMPART + MAX_EXT_PARTS)): self.set_error(self.InvalidPartitionNameError( str(value.name), self.container.ctd)) # fix the start_sector and size to align to cylinder boundaries for # primary partitions if value.is_primary: value = self.cylinder_boundary_adjustment(value) # check the bounds of the partition to be added. if not (isinstance(value.start_sector, int) or \ isinstance(value.start_sector, long)): self.set_error(self.InvalidPartitionStartSectorError()) if hasattr(self.container.disk_prop, "dev_size") and \ getattr(self.container.disk_prop, "dev_size") is not None: if not (0 <= value.start_sector <= \ self.container.disk_prop.dev_size.sectors): self.set_error(self.InvalidPartitionStartSectorError()) # verify that the Disk does not have 'whole_disk' set to 'true' if self.container.whole_disk: self.set_error(self.WholeDiskIsTrueError()) # if the partition is a logical partition, ensure there is a partition # with part_type in Partition.EXTENDED_ID_LIST has already been # inserted. if value.is_logical: extended_part = None for partition in self._shadow: if partition.is_extended: if partition.part_type in partition.EXTENDED_ID_LIST: extended_part = partition if extended_part is None: self.set_error(self.NoExtPartitionsError()) else: # verify there are not more than MAX_EXT_PARTS logical_list = [p for p in self._shadow if p.is_logical and \ p.action != "delete"] if len(logical_list) >= MAX_EXT_PARTS: self.set_error(self.TooManyLogicalPartitionsError()) # ensure this logical partition does not start too close to any # previously inserted logical partitions. # sort the logical list by start sector slist = sorted(logical_list, lambda x, y: cmp(x.start_sector, y.start_sector)) # find the closest logical partition within the extended # partition closest_endpoint = 0 for logical in slist: end_point = logical.start_sector + logical.size.sectors if end_point < value.start_sector and \ end_point > closest_endpoint: closest_endpoint = end_point if closest_endpoint == 0: # no logical partitions were found, so use the start of the # extended partition, if the difference is smaller than the # needed offset diff = value.start_sector - extended_part.start_sector if diff < LOGICAL_ADJUSTMENT and value.action == "create": value.start_sector = extended_part.start_sector + \ LOGICAL_ADJUSTMENT new_size = value.size.sectors - LOGICAL_ADJUSTMENT value.size = Size(str(new_size) + Size.sector_units) else: diff = value.start_sector - closest_endpoint # make sure there's at least 63 sectors between logical # partitions if diff < LOGICAL_ADJUSTMENT and value.action == "create": value.start_sector += LOGICAL_ADJUSTMENT - diff new_size = value.size.sectors - LOGICAL_ADJUSTMENT value.size = Size(str(new_size) + Size.sector_units) # check the bootid attibute on primary partitions for multiple active # partitions if value.is_primary and value.bootid == value.ACTIVE: for partition in self._shadow: # skip logical partitions if partition.is_logical: continue # check the bootid attribute if partition.bootid == value.ACTIVE: self.set_error(self.MultipleActivePartitionsError( partition.name)) p_start = value.start_sector p_end = p_start + value.size.sectors - 1 # walk each inserted partition already in the shadow list to ensure the # partition we're trying to insert doesn't cross boundaries. for partition in self._shadow: # start and end points of the partition to check if partition.is_primary: start = partition.start_sector end = start + partition.size.sectors - 1 else: # for logical partitions, there needs to be a buffer of # LOGICAL_ADJUSTMENT on each end start = partition.start_sector - LOGICAL_ADJUSTMENT end = start + partition.size.sectors - 1 + LOGICAL_ADJUSTMENT if value.is_primary: # do not test logical partition boundaries for primary # partitions if partition.is_logical: continue else: # verify the logical partition we're trying to insert fits # within the extended partition "parent" if partition.is_extended and partition.action != "delete": if p_start < start or p_end > end: self.set_error(self.LogicalPartitionOverlapError()) # do not test primary partition boundaries for logical # partitions if partition.is_primary: continue # check that the start sector of the partition we're trying to # insert is not within another partition and the existing partition # isn't inside the partition we're inserting. Primary partitions # are only checked against other primary partitions and logical # partitions are only checked aginst other logical partitions. # Partitions marked for deletion should not be checked at all if value.action != "delete" and partition.action != "delete": if ((start <= p_start <= end) or (start <= p_end <= end)) or \ ((p_start <= start <= p_end) or (p_start <= end <= p_end)): self.set_error(self.OverlappingPartitionError( partition.name, value.name)) # check that a primary partition doesn't exceed the size of the Disk, # if the dev_size is specified if hasattr(self.container.disk_prop, "dev_size") and \ self.container.disk_prop.dev_size is not None and \ value.is_primary: disk_size = self.container.disk_prop.dev_size.sectors p_size = value.start_sector + value.size.sectors # check that the name of the partition is not already in the list if value.name in [p.name for p in self._shadow \ if p.action != "delete"]: self.set_error(self.DuplicatePartitionNameError(value.name)) # if this is an extended partition, verify there are no other # partitions of the same type. Also verify it's at least # LOGICAL_ADJUSTMENT sectors in size if value.is_extended: for partition in self._shadow: if partition.is_extended and partition.action != "delete": self.set_error(self.TooManyExtPartitionsError()) if value.size.sectors < LOGICAL_ADJUSTMENT: self.set_error(self.ExtPartitionTooSmallError()) # if the partition type is FAT16, make sure it's not larger than 4GB fat16_list = [ value.name_to_num("FAT16 (Upto 32M)"), value.name_to_num("FAT16 (>32M, HUGEDOS)"), value.name_to_num("WIN95 FAT16(LBA)") ] if value.part_type in fat16_list and value.action == "create": if value.size.byte_value > Size.units["gb"] * 4: self.set_error(self.FAT16PartitionTooLargeError()) # check to see if the container object has the same in_zpool attribute if value.in_zpool is not None: if getattr(self.container, "in_zpool") == value.in_zpool: self.set_error(self.OverlappingPartitionZpoolError()) # check to see if the container object has the same in_vdev attribute if value.in_vdev is not None: if getattr(self.container, "in_vdev") == value.in_vdev: self.set_error(self.OverlappingPartitionVdevError()) # insert the partition ShadowList.insert(self, index, value)
def insert_slice(self, index, value): """ insert_slice() - override method for validation of Slice DOC objects. the following checks are done as part of validation: - the parent Disk object does not have whole_disk attribute set - the start_sector of the slice is an int or long and is between 0 and the container's maximum size - no overlapping boundaries of the slice with any other slices already inserted - no more than V_NUMPAR slices - no duplicate indexes (ie. no duplicate slice numbers) - none of the parent objects have an in_zpool or in_vdev attribute set """ # set the proper cylinder boundry, parent_size and ctds string based on # the container type if hasattr(self.container, "geometry"): # container is a Disk object parent_size = self.container.disk_prop.dev_size.sectors ctds = self.container.ctd + "s%s" % value.name label = self.container.label # verify that the Disk does not have 'whole_disk' set to 'true' if self.container.whole_disk: self.set_error(self.WholeDiskIsTrueError()) elif hasattr(self.container, "part_type"): # container is a Partition object parent_size = self.container.size.sectors ctds = self.container.parent.ctd + "s%s" % value.name label = self.container.parent.label # check the bounds of the slice to be added. if not (isinstance(value.start_sector, int) or \ isinstance(value.start_sector, long)): self.set_error(self.InvalidSliceStartSectorError()) if not (0 <= value.start_sector <= parent_size): self.set_error(self.InvalidSliceStartSectorError()) # find the cylinder boundary of the disk and adjust the Slice's start # and size to fall on a cylinder boundary. start and end will be on # the boundaries and in blocks. # only adjust the start sector for VTOC slices that are do not have the # V_BOOT or V_BACKUP tag. if label == "VTOC" and value.tag not in [V_BACKUP, V_BOOT]: # fix the start_sector and size to align to cylinder boundaries value = self.cylinder_boundary_adjustment(value) cb_start = value.start_sector cb_end = value.start_sector + value.size.sectors - 1 # verify each slice does not overlap with any other slice for slc in self._shadow: # if slice 2 is being inserted into a VTOC labeled disk, do not # check for overlap if label == "VTOC" and int(value.name) == 2: break # skip VTOC overlap slice if it is already inserted into the # shadow list if label == "VTOC" and int(slc.name) == 2: continue # calculate the range of each slice already inserted start = slc.start_sector end = slc.start_sector + slc.size.sectors - 1 # check that the start sector is not within another slice and # the existing slice isn't inside the new slice but only for slices # not marked for deletion if value.action != "delete" and slc.action != "delete": if (start <= cb_start <= end or start <= cb_end <= end) or \ (cb_start <= start <= cb_end or cb_start <= end <= cb_end): self.set_error( self.OverlappingSliceError(value.name, slc.name)) if len(self._shadow) >= V_NUMPAR: self.set_error(self.TooManySlicesError()) # check for duplicate slice.name values if value.name in [slc.name for slc in self._shadow \ if slc.action != "delete"]: self.set_error(self.DuplicateSliceNameError(value.name)) # check for in_zpool overlap if value.in_zpool is not None: # check the container if getattr(self.container, "in_zpool") == value.in_zpool: self.set_error(self.OverlappingSliceZpoolError()) # check the container's parent if it's a partition if hasattr(self.container, "part_type"): if getattr(self.container.parent, "in_zpool") == \ value.in_zpool: self.set_error(self.OverlappingSliceZpoolError()) # check for in_vdev overlap if value.in_vdev is not None: # check the container if getattr(self.container, "in_vdev") == value.in_vdev: self.set_error(self.OverlappingSliceVdevError()) # check the container's parent if it's a partition if hasattr(self.container, "part_type"): if getattr(self.container.parent, "in_vdev") == \ value.in_vdev: self.set_error(self.OverlappingSliceVdevError()) # check for in_use conflicts. Re-query libdiskmgt due to circular # import issues with trying to navigate the DOC stats = self.in_use_check(ctds) if stats and value.action != "preserve" and not value.force: self.set_error(self.SliceInUseError(stats)) # insert the corrected Slice object ShadowList.insert(self, index, value)
def insert_gptpartition(self, index, value): """ insert_gptpartition() - override method for validation of GPTPartition DOC objects. the following checks are done as part of validation: - the parent Disk object does not have whole_disk attribute set - the start_sector of the slice is an int or long and is between 0 and the container's maximum size - no overlapping boundaries of the GPT partition with any other GPT partitions already inserted - no more than EFI_NUMUSERPAR for non-reserved or non-preserved partitions - no duplicate indexes (ie. no duplicate GPT partition numbers) - none of the parent objects have an in_zpool or in_vdev attribute set """ # set the parent_size based on the parent Disk object parent_size = self.container.disk_prop.dev_size.sectors label = self.container.label # verify part_type is not None if value.part_type is None: self.set_error(self.GPTPartitionTypeMissingError()) # verify the name of the partition is valid # User partitions must be between s0 - s6 unless preserving existing # ones # Reserved partitions can and should be s8+ if not value.is_reserved and \ not 0 <= int(value.name) < EFI_NUMUSERPAR: if value.action != "preserve": self.set_error(self.InvalidGPTPartitionNameError( str(value.name), self.container.ctd)) if int(value.name) == EFI_NUMUSERPAR: if value.action != "preserve": self.set_error(self.InvalidGPTPartitionNameError( str(value.name), self.container.ctd)) # check the bounds of the GPT partition to be added. if not (isinstance(value.start_sector, int) or \ isinstance(value.start_sector, long)): self.set_error(self.InvalidGPTPartitionStartSectorError()) if hasattr(self.container.disk_prop, "dev_size") and \ getattr(self.container.disk_prop, "dev_size") is not None: if not (0 <= value.start_sector <= \ self.container.disk_prop.dev_size.sectors): self.set_error(self.InvalidGPTPartitionStartSectorError()) # fix the start_sector and size to align against a lowest common # multiple disk block size. Helps to prevent partition mis-alignment. value = self.sector_boundary_adjustment(value) # verify that the Disk does not have 'whole_disk' set to 'true' if self.container.whole_disk: self.set_error(self.WholeDiskIsTrueError()) new_start = value.start_sector new_end = value.start_sector + value.size.sectors - 1 # verify each GPT partition does not overlap with any other for gpart in self._shadow: # calculate the range of each GPT partition already inserted start = gpart.start_sector end = gpart.start_sector + gpart.size.sectors - 1 # check that the start sector is not within another GPT partition # and the existing GPT partition isn't inside the new GPT # partition but only for GPT partitions not marked for deletion if value.action != "delete" and gpart.action != "delete": if (start <= new_start <= end or start <= new_end <= end) or \ (new_start <= start <= new_end or \ new_start <= end <= new_end): self.set_error( self.OverlappingGPTPartitionError(value.name, gpart.name)) if len(self._shadow) >= EFI_MAXPAR: self.set_error(self.TooManyGPTPartitionsError()) # check for duplicate gptpartition.name values if value.name in [gpart.name for gpart in self._shadow \ if gpart.action != "delete"]: self.set_error(self.DuplicateGPTPartitionNameError(value.name)) # check for in_zpool overlap if value.in_zpool is not None: # check the container if getattr(self.container, "in_zpool") == value.in_zpool: self.set_error(self.OverlappingGPTPartitionZpoolError()) # check for in_vdev overlap if value.in_vdev is not None: # check the container if getattr(self.container, "in_vdev") == value.in_vdev: self.set_error(self.OverlappingGPTPartitionVdevError()) # check for in_use conflicts. stats = self.in_use_check(value) if stats and value.action != "preserve" and not value.force: self.set_error(self.GPTPartitionInUseError(stats)) # insert the corrected GPTPartition object ShadowList.insert(self, index, value)