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)
示例#2
0
    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)
示例#3
0
    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
示例#5
0
    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)
示例#6
0
    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)
示例#7
0
    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)
示例#8
0
    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)
示例#10
0
    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)
示例#12
0
    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)
示例#13
0
    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)
示例#16
0
    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)