コード例 #1
0
def find_resources_to_delete(resource_el: _Element) -> List[_Element]:
    """
    Get resources to delete, children and parents of the given resource if
    necessary.

    If element is a primitive which is in a clone and you specify one of them,
    you will get elements for both of them. If you specify group element which
    is in a clone then will you get clone, group, and all primitive elements in
    a group and etc.

    resource_el - resource element (bundle, clone, group, primitive)
    """
    result = [resource_el]
    # childrens of bundle, clone, group, clone-with-group
    inner_resource_list = get_inner_resources(resource_el)
    if inner_resource_list:
        result.extend(inner_resource_list)
        inner_resource = inner_resource_list[0]
        if is_group(inner_resource):
            result.extend(get_inner_resources(inner_resource))
    # parents of primitive if needed (group, clone)
    parent_el = get_parent_resource(resource_el)
    if parent_el is None or is_bundle(parent_el):
        return result
    if is_any_clone(parent_el):
        result.insert(0, parent_el)
    if is_group(parent_el):
        group_inner_resources = get_group_inner_resources(parent_el)
        if len(group_inner_resources) <= 1:
            result = [parent_el] + group_inner_resources
            clone_el = get_parent_resource(parent_el)
            if clone_el is not None:
                result.insert(0, clone_el)
    return result
コード例 #2
0
ファイル: hierarchy.py プロジェクト: ldming/pcs
 def _validate_adjacent_resource_element(self):
     report_list = []
     if self._adjacent_resource_element is not None:
         if self._group_element is not None:
             adjacent_parent = self._adjacent_resource_element.getparent()
             if not (adjacent_parent is not None
                     and group.is_group(adjacent_parent) and
                     (adjacent_parent.attrib.get("id")
                      == self._group_element.attrib.get("id"))):
                 # pylint: disable=line-too-long
                 report_list.append(
                     ReportItem.error(
                         reports.messages.
                         CannotGroupResourceAdjacentResourceNotInGroup(
                             self._adjacent_resource_element.attrib.get(
                                 "id"),
                             self._group_element.attrib.get("id"),
                         )))
         for resource in self._resource_element_list:
             if self._adjacent_resource_element.attrib.get(
                     "id") == resource.attrib.get("id"):
                 report_list.append(
                     ReportItem.error(
                         reports.messages.CannotGroupResourceNextToItself(
                             self._adjacent_resource_element.attrib.get(
                                 "id"))))
                 break
     return report_list
コード例 #3
0
def is_wrapper_resource(resource_el: Element) -> bool:
    """
    Return True for resource_el of types that can contain other resource(s)
    (these are: group, bundle, clone) and False otherwise.

    resource_el -- resource element to check
    """
    return (is_group(resource_el) or is_bundle(resource_el)
            or is_any_clone(resource_el))
コード例 #4
0
ファイル: relation.py プロジェクト: tomjelinek/pcs
def move_resources_to_group(
    group_element, primitives_to_place, adjacent_resource=None,
    put_after_adjacent=True
):
    """
    Put resources into a group or move them within their group

    etree.Element group_element -- the group to put resources into
    iterable primitives_to_place -- resource elements to put into the group
    etree.Element adjacent_resource -- put resources beside this one if set
    bool put_after_adjacent -- put resources after or before the adjacent one
    """
    for resource in primitives_to_place:
        old_parent = resource.getparent()

        # Move a resource to the group.
        if (
            adjacent_resource is not None
            and
            adjacent_resource.getnext() is not None
            and
            put_after_adjacent
        ):
            adjacent_resource.getnext().addprevious(resource)
            adjacent_resource = resource
        elif (
            adjacent_resource is not None
            and
            not put_after_adjacent
        ):
            adjacent_resource.addprevious(resource)
        else:
            group_element.append(resource)
            adjacent_resource = resource

        # If the resource was the last resource in another group, that group is
        # now empty and must be deleted. If the group is in a clone element,
        # delete that as well.
        if (
            old_parent is not None
            and
            group.is_group(old_parent)
            and
            not group.get_inner_resources(old_parent)
            and
            old_parent.getparent() is not None
        ):
            old_grandparent = old_parent.getparent()
            if (
                clone.is_any_clone(old_grandparent)
                and
                old_grandparent.getparent() is not None
            ):
                old_grandparent.getparent().remove(old_grandparent)
            else:
                old_grandparent.remove(old_parent)
コード例 #5
0
def move_resources_to_group(
    group_element: _Element,
    primitives_to_place: Iterable[_Element],
    adjacent_resource: Optional[_Element] = None,
    put_after_adjacent: bool = True,
) -> None:
    """
    Put resources into a group or move them within their group

    There is a corner case which is not covered in this function. If the CIB
    contains references to a group or clone which this function deletes,
    they are not deleted and an invalid CIB is generated. These references
    can be constraints, fencing levels etc. - anything that contains group id of
    the deleted group. It is on the caller to detect this corner case and handle
    it appropriately (see group_add in lib/commands/resource.py). For future
    rewrites of this function, it would be better to ask for --force before
    deleting anything that user didn't explicitly ask for - like deleting the
    clone and its associated constraints.

    etree.Element group_element -- the group to put resources into
    iterable primitives_to_place -- resource elements to put into the group
    etree.Element adjacent_resource -- put resources beside this one if set
    bool put_after_adjacent -- put resources after or before the adjacent one
    """
    for resource in primitives_to_place:
        old_parent = resource.getparent()

        # Move a resource to the group.
        if (adjacent_resource is not None
                and adjacent_resource.getnext() is not None
                and put_after_adjacent):
            adjacent_resource.getnext().addprevious(resource)  # type: ignore
            adjacent_resource = resource
        elif adjacent_resource is not None and not put_after_adjacent:
            adjacent_resource.addprevious(resource)
        else:
            group_element.append(resource)
            adjacent_resource = resource

        # If the resource was the last resource in another group, that group is
        # now empty and must be deleted. If the group is in a clone element,
        # delete that as well.
        if (old_parent is not None and group.is_group(
                old_parent)  # do not delete resources element
                and not group.get_inner_resources(old_parent)):
            old_grandparent = old_parent.getparent()
            if old_grandparent is not None:
                old_great_grandparent = old_grandparent.getparent()
                if (clone.is_any_clone(old_grandparent)
                        and old_great_grandparent is not None):
                    old_great_grandparent.remove(old_grandparent)
                else:
                    old_grandparent.remove(old_parent)
コード例 #6
0
ファイル: common.py プロジェクト: wuyeliang/pcs
def find_resources_to_unmanage(resource_el):
    """
    Get resources to unmanage to unmanage the specified resource succesfully
    etree resource_el -- resource element
    """
    # resource hierarchy - specified resource - what to return
    # a primitive - the primitive - the primitive
    #
    # a cloned primitive - the primitive - the primitive
    # a cloned primitive - the clone - the primitive
    #   The resource will run on all nodes after unclone. However that doesn't
    #   seem to be bad behavior. Moreover, if monitor operations were disabled,
    #   they wouldn't enable on unclone, but the resource would become managed,
    #   which is definitely bad.
    #
    # a primitive in a group - the primitive - the primitive
    #   Otherwise all primitives in the group would become unmanaged.
    # a primitive in a group - the group - all primitives in the group
    #   If only the group was set to unmanaged, setting any primitive in the
    #   group to managed would set all the primitives in the group to managed.
    #   If the group as well as all its primitives were set to unmanaged, any
    #   primitive added to the group would become unmanaged. This new primitive
    #   would become managed if any original group primitive becomes managed.
    #   Therefore changing one primitive influences another one, which we do
    #   not want to happen.
    #
    # a primitive in a cloned group - the primitive - the primitive
    # a primitive in a cloned group - the group - all primitives in the group
    #   See group notes above
    # a primitive in a cloned group - the clone - all primitives in the group
    #   See clone notes above
    #
    # a bundled primitive - the primitive - the primitive
    # a bundled primitive - the bundle - the bundle and the primitive
    #  We need to unmanage implicit resources create by pacemaker and there is
    #  no other way to do it than unmanage the bundle itself.
    #  Since it is not possible to unbundle a resource, the concers described
    #  at unclone don't apply here. However to prevent future bugs, in case
    #  unbundling becomes possible, we unmanage the primitive as well.
    # an empty bundle - the bundle - the bundle
    #  There is nothing else to unmanage.
    if is_bundle(resource_el):
        in_bundle = get_bundle_inner_resource(resource_el)
        return (
            [resource_el, in_bundle] if in_bundle is not None else [resource_el]
        )
    if is_any_clone(resource_el):
        resource_el = get_clone_inner_resource(resource_el)
    if is_group(resource_el):
        return get_group_inner_resources(resource_el)
    if is_primitive(resource_el):
        return [resource_el]
    return []
コード例 #7
0
ファイル: common.py プロジェクト: wuyeliang/pcs
def find_primitives(resource_el):
    """
    Get list of primitives contained in a given resource
    etree resource_el -- resource element
    """
    if is_bundle(resource_el):
        in_bundle = get_bundle_inner_resource(resource_el)
        return [in_bundle] if in_bundle is not None else []
    if is_any_clone(resource_el):
        resource_el = get_clone_inner_resource(resource_el)
    if is_group(resource_el):
        return get_group_inner_resources(resource_el)
    if is_primitive(resource_el):
        return [resource_el]
    return []
コード例 #8
0
ファイル: resource_set.py プロジェクト: CtrlZmaster/pcs
def is_resource_in_same_group(cib, resource_id_list):
    # We don't care about not found elements here, that is a job of another
    # validator. We do not care if the id doesn't belong to a resource either
    # for the same reason.
    element_list, _ = get_elements_by_ids(cib, set(resource_id_list))

    parent_list = []
    for element in element_list:
        parent = get_parent_resource(element)
        if parent is not None and group.is_group(parent):
            parent_list.append(parent)

    if len(set(parent_list)) != len(parent_list):
        raise LibraryError(
            ReportItem.error(
                reports.messages.
                CannotSetOrderConstraintsForResourcesInTheSameGroup()))
コード例 #9
0
def get_inner_resources(resource_el: _Element) -> List[_Element]:
    """
    Return list of inner resources (direct descendants) of a resource
    specified as resource_el.
    Example: for clone containing a group, this function will return only
    group and not resource inside the group

    resource_el -- resource element to get its inner resources
    """
    if is_bundle(resource_el):
        in_bundle = get_bundle_inner_resource(resource_el)
        return [in_bundle] if in_bundle is not None else []
    if is_any_clone(resource_el):
        return [get_clone_inner_resource(resource_el)]
    if is_group(resource_el):
        return get_group_inner_resources(resource_el)
    return []
コード例 #10
0
ファイル: common.py プロジェクト: cwjenkins/pcs
def find_resources_to_unmanage(resource_el):
    """
    Get resources to unmanage to unmanage the specified resource succesfully
    etree resource_el -- resource element
    """
    # resource hierarchy - specified resource - what to return
    # a primitive - the primitive - the primitive
    #
    # a cloned primitive - the primitive - the primitive
    # a cloned primitive - the clone - the primitive
    #   The resource will run on all nodes after unclone. However that doesn't
    #   seem to be bad behavior. Moreover, if monitor operations were disabled,
    #   they wouldn't enable on unclone, but the resource would become managed,
    #   which is definitely bad.
    #
    # a primitive in a group - the primitive - the primitive
    #   Otherwise all primitives in the group would become unmanaged.
    # a primitive in a group - the group - all primitives in the group
    #   If only the group was set to unmanaged, setting any primitive in the
    #   group to managed would set all the primitives in the group to managed.
    #   If the group as well as all its primitives were set to unmanaged, any
    #   primitive added to the group would become unmanaged. This new primitive
    #   would become managed if any original group primitive becomes managed.
    #   Therefore changing one primitive influences another one, which we do
    #   not want to happen.
    #
    # a primitive in a cloned group - the primitive - the primitive
    # a primitive in a cloned group - the group - all primitives in the group
    #   See group notes above
    # a primitive in a cloned group - the clone - all primitives in the group
    #   See clone notes above
    #
    # a bundled primitive - the primitive - the primitive
    # a bundled primitive - the bundle - nothing
    #  bundles currently cannot be set as unmanaged - pcmk does not support that
    # an empty bundle - the bundle - nothing
    #  bundles currently cannot be set as unmanaged - pcmk does not support that
    if is_any_clone(resource_el):
        resource_el = get_clone_inner_resource(resource_el)
    if is_group(resource_el):
        return get_group_inner_resources(resource_el)
    if is_primitive(resource_el):
        return [resource_el]
    return []
コード例 #11
0
ファイル: hierarchy.py プロジェクト: ldming/pcs
def move_resources_to_group(
    group_element,
    primitives_to_place,
    adjacent_resource=None,
    put_after_adjacent=True,
):
    """
    Put resources into a group or move them within their group

    etree.Element group_element -- the group to put resources into
    iterable primitives_to_place -- resource elements to put into the group
    etree.Element adjacent_resource -- put resources beside this one if set
    bool put_after_adjacent -- put resources after or before the adjacent one
    """
    for resource in primitives_to_place:
        old_parent = resource.getparent()

        # Move a resource to the group.
        if (adjacent_resource is not None
                and adjacent_resource.getnext() is not None
                and put_after_adjacent):
            adjacent_resource.getnext().addprevious(resource)
            adjacent_resource = resource
        elif adjacent_resource is not None and not put_after_adjacent:
            adjacent_resource.addprevious(resource)
        else:
            group_element.append(resource)
            adjacent_resource = resource

        # If the resource was the last resource in another group, that group is
        # now empty and must be deleted. If the group is in a clone element,
        # delete that as well.
        if (old_parent is not None and group.is_group(old_parent)
                and not group.get_inner_resources(old_parent)
                and old_parent.getparent() is not None):
            old_grandparent = old_parent.getparent()
            if (clone.is_any_clone(old_grandparent)
                    and old_grandparent.getparent() is not None):
                old_grandparent.getparent().remove(old_grandparent)
            else:
                old_grandparent.remove(old_parent)
コード例 #12
0
 def _validate_adjacent_resource_element(self):
     report_list = []
     if self._adjacent_resource_element is not None:
         if self._group_element is not None:
             adjacent_parent = self._adjacent_resource_element.getparent()
             if not (adjacent_parent is not None
                     and group.is_group(adjacent_parent) and
                     (adjacent_parent.attrib.get("id")
                      == self._group_element.attrib.get("id"))):
                 report_list.append(
                     reports.
                     cannot_group_resource_adjacent_resource_not_in_group(
                         self._adjacent_resource_element.attrib.get("id"),
                         self._group_element.attrib.get("id")))
         for resource in self._resource_element_list:
             if (self._adjacent_resource_element.attrib.get("id") ==
                     resource.attrib.get("id")):
                 report_list.append(
                     reports.cannot_group_resource_next_to_itself(
                         self._adjacent_resource_element.attrib.get("id")))
                 break
     return report_list
コード例 #13
0
ファイル: relation.py プロジェクト: tomjelinek/pcs
 def _validate_adjacent_resource_element(self):
     report_list = []
     if self._adjacent_resource_element is not None:
         if self._group_element is not None:
             adjacent_parent = self._adjacent_resource_element.getparent()
             if not (
                 adjacent_parent is not None
                 and
                 group.is_group(adjacent_parent)
                 and
                 (
                     adjacent_parent.attrib.get("id")
                     ==
                     self._group_element.attrib.get("id")
                 )
             ):
                 report_list.append(
                     reports
                     .cannot_group_resource_adjacent_resource_not_in_group(
                         self._adjacent_resource_element.attrib.get("id"),
                         self._group_element.attrib.get("id")
                     )
                 )
         for resource in self._resource_element_list:
             if (
                 self._adjacent_resource_element.attrib.get("id")
                 ==
                 resource.attrib.get("id")
             ):
                 report_list.append(
                     reports.cannot_group_resource_next_to_itself(
                         self._adjacent_resource_element.attrib.get("id")
                     )
                 )
                 break
     return report_list
コード例 #14
0
ファイル: relation.py プロジェクト: tomjelinek/pcs
    def _validate_resource_elements(
        self, bad_or_missing_group_specified, bad_resources_specified,
        bad_adjacent_specified
    ):
        report_list = []

        # Check if the group element is really a group unless it has been
        # checked before.
        if (
            not bad_or_missing_group_specified
            and
            not group.is_group(self._group_element)
        ):
            bad_or_missing_group_specified = True
            report_list.append(
                reports.id_belongs_to_unexpected_type(
                    self._group_element.attrib.get("id"),
                    expected_types=[group.TAG],
                    current_type=self._group_element.tag
                )
            )

        # Report an error if no resources were specified. If resource ids have
        # been specified but they are not valid resource ids, then some
        # resources were specified, even though not valid ones.
        if not bad_resources_specified and not self._resource_element_list:
            report_list.append(reports.cannot_group_resource_no_resources())

        resources_already_in_the_group = set()
        resources_count = defaultdict(int)
        for resource in self._resource_element_list:
            resource_id = resource.attrib.get("id")
            if not primitive.is_primitive(resource):
                report_list.append(
                    reports.cannot_group_resource_wrong_type(
                        resource_id,
                        resource.tag
                    )
                )
                continue
            resources_count[resource_id] = resources_count[resource_id] + 1
            parent = resource.getparent()
            if parent is not None:
                if group.is_group(parent):
                    # If no adjacent resource has been specified (either valid
                    # or invalid), the resources must not already be in the
                    # group, if the group already exists.
                    if (
                        not bad_or_missing_group_specified
                        and
                        not bad_adjacent_specified
                        and
                        self._adjacent_resource_element is None
                        and
                        (
                            parent.attrib.get("id")
                            ==
                            self._group_element.attrib.get("id")
                        )
                    ):
                        resources_already_in_the_group.add(resource_id)
                elif parent.tag != "resources":
                    # If the primitive is not in a 'group' or 'resources' tag,
                    # it is either in a clone, master, bundle or similar tag
                    # and cannot be put into a group.
                    report_list.append(
                        reports.cannot_group_resource_wrong_type(
                            resource_id,
                            parent.tag
                        )
                    )
        if resources_already_in_the_group:
            report_list.append(
                reports.cannot_group_resource_already_in_the_group(
                    resources_already_in_the_group,
                    self._group_element.attrib.get("id")
                )
            )
        more_than_once_resources = [
            resource for resource, count in resources_count.items()
            if count > 1
        ]
        if more_than_once_resources:
            report_list.append(
                reports.cannot_group_resource_more_than_once(
                    more_than_once_resources
                )
            )
        return report_list
コード例 #15
0
ファイル: test_resource_group.py プロジェクト: zht750808/pcs
 def test_is_group(self):
     self.assertTrue(group.is_group(etree.fromstring("<group/>")))
     self.assertFalse(group.is_group(etree.fromstring("<clone/>")))
     self.assertFalse(group.is_group(etree.fromstring("<master/>")))
コード例 #16
0
ファイル: hierarchy.py プロジェクト: ldming/pcs
    def _validate_resource_elements(
        self,
        bad_or_missing_group_specified,
        bad_resources_specified,
        bad_adjacent_specified,
    ):
        report_list = []

        # Check if the group element is really a group unless it has been
        # checked before.
        if not bad_or_missing_group_specified and not group.is_group(
                self._group_element):
            bad_or_missing_group_specified = True
            report_list.append(
                ReportItem.error(
                    reports.messages.IdBelongsToUnexpectedType(
                        self._group_element.attrib.get("id"),
                        expected_types=[group.TAG],
                        current_type=self._group_element.tag,
                    )))

        # Report an error if no resources were specified. If resource ids have
        # been specified but they are not valid resource ids, then some
        # resources were specified, even though not valid ones.
        if not bad_resources_specified and not self._resource_element_list:
            report_list.append(
                ReportItem.error(
                    reports.messages.CannotGroupResourceNoResources()))

        resources_already_in_the_group = set()
        resources_count = defaultdict(int)
        for resource in self._resource_element_list:
            resource_id = resource.attrib.get("id")
            if not primitive.is_primitive(resource):
                report_list.append(
                    ReportItem.error(
                        reports.messages.CannotGroupResourceWrongType(
                            resource_id, resource.tag)))
                continue
            resources_count[resource_id] = resources_count[resource_id] + 1
            parent = resource.getparent()
            if parent is not None:
                if group.is_group(parent):
                    # If no adjacent resource has been specified (either valid
                    # or invalid), the resources must not already be in the
                    # group, if the group already exists.
                    if (not bad_or_missing_group_specified
                            and not bad_adjacent_specified
                            and self._adjacent_resource_element is None
                            and (parent.attrib.get("id")
                                 == self._group_element.attrib.get("id"))):
                        resources_already_in_the_group.add(resource_id)
                elif parent.tag != "resources":
                    # If the primitive is not in a 'group' or 'resources' tag,
                    # it is either in a clone, master, bundle or similar tag
                    # and cannot be put into a group.
                    report_list.append(
                        ReportItem.error(
                            reports.messages.CannotGroupResourceWrongType(
                                resource_id, parent.tag)))
        if resources_already_in_the_group:
            report_list.append(
                ReportItem.error(
                    reports.messages.CannotGroupResourceAlreadyInTheGroup(
                        sorted(resources_already_in_the_group),
                        self._group_element.attrib.get("id"),
                    )))
        more_than_once_resources = [
            resource for resource, count in resources_count.items()
            if count > 1
        ]
        if more_than_once_resources:
            report_list.append(
                ReportItem.error(
                    reports.messages.CannotGroupResourceMoreThanOnce(
                        sorted(more_than_once_resources))))
        return report_list
コード例 #17
0
def validate_move_resources_to_group(
    group_element: _Element,
    resource_element_list: List[_Element],
    adjacent_resource_element: Optional[_Element],
) -> ReportItemList:
    """
    Validates that existing resources can be moved into a group,
    optionally beside an adjacent_resource_element

    group_element -- the group to put resources into
    resource_element_list -- resources that are being moved into the group
    adjacent_resource_element -- put resources beside this one
    """
    report_list: ReportItemList = []

    # Validate types of resources and their parents
    for resource_element in resource_element_list:
        # Only primitive resources can be moved
        if not is_resource(resource_element):
            report_list.append(
                ReportItem.error(
                    reports.messages.IdBelongsToUnexpectedType(
                        str(resource_element.attrib["id"]),
                        ["primitive"],
                        resource_element.tag,
                    )))
        elif is_wrapper_resource(resource_element):
            report_list.append(
                ReportItem.error(
                    reports.messages.CannotGroupResourceWrongType(
                        str(resource_element.attrib["id"]),
                        resource_element.tag,
                        parent_id=None,
                        parent_type=None,
                    )))
        else:
            parent = get_parent_resource(resource_element)
            if parent is not None and not group.is_group(parent):
                # At the moment, moving resources out of bundles and clones
                # (or masters) is not possible
                report_list.append(
                    ReportItem.error(
                        reports.messages.CannotGroupResourceWrongType(
                            str(resource_element.attrib["id"]),
                            resource_element.tag,
                            parent_id=str(parent.attrib["id"]),
                            parent_type=parent.tag,
                        )))

    # Validate that elements can be added
    # Check if the group element is a group
    if group.is_group(group_element):
        report_list += validate_add_remove_items(
            [str(resource.attrib["id"]) for resource in resource_element_list],
            [],
            [
                str(resource.attrib["id"])
                for resource in get_inner_resources(group_element)
            ],
            ADD_REMOVE_CONTAINER_TYPE_GROUP,
            ADD_REMOVE_ITEM_TYPE_RESOURCE,
            str(group_element.attrib["id"]),
            str(adjacent_resource_element.attrib["id"])
            if adjacent_resource_element is not None else None,
            True,
        )
    else:
        report_list.append(
            ReportItem.error(
                reports.messages.IdBelongsToUnexpectedType(
                    str(group_element.attrib["id"]),
                    expected_types=[group.TAG],
                    current_type=group_element.tag,
                )))

    # Elements can always be removed from their old groups, except when the last
    # resource is removed but that is handled in resource.group_add for now, no
    # need to run the validation for removing elements
    return report_list
コード例 #18
0
ファイル: test_resource_group.py プロジェクト: tomjelinek/pcs
 def test_is_group(self):
     self.assertTrue(group.is_group(etree.fromstring("<group/>")))
     self.assertFalse(group.is_group(etree.fromstring("<clone/>")))
     self.assertFalse(group.is_group(etree.fromstring("<master/>")))