def test_different_parent_not_useful(self): element = self.tree.find(".//element-B2") lib.append_when_useful(self.parent, element) assert_xml_equal( self.tree_str, etree_to_str(self.tree) )
def arrange_first_nvset( tag_name, context_element, nvpair_dict, id_provider, new_id=None ): """ Put nvpairs to the first tag_name nvset in the context_element. If the nvset does not exist, it will be created. WARNING: does not solve multiple nvsets (with the same tag_name) in the context_element! Consider carefully if this is your use case. Probably not. There could be more than one nvset. This function is DEPRECATED. Try to use update_nvset etc. string tag_name -- tag name of nvset element etree context_element -- parent element of nvset dict nvpair_dict -- dictionary of nvpairs IdProvider id_provider -- elements' ids generator """ if not nvpair_dict: return nvset_element = get_sub_element( context_element, tag_name, new_id=( new_id if new_id else create_subelement_id(context_element, tag_name, id_provider) ), append_if_missing=False, ) update_nvset(nvset_element, nvpair_dict, id_provider) append_when_useful(context_element, nvset_element, index=0)
def append_new_nvset(tag_name, context_element, nvpair_dict, id_provider, enforce_append=False): """ Append new nvset_element comprising nvpairs children (corresponding nvpair_dict) to the context_element string tag_name should be "instance_attributes" or "meta_attributes" etree.Element context_element is element where new nvset will be appended dict nvpair_dict contains source for nvpair children IdProvider id_provider -- elements' ids generator bool enforce_append -- append element wo usefulness check if flag is True """ nvset_element = etree.Element( tag_name, {"id": create_subelement_id(context_element, tag_name, id_provider)}, ) for name, value in sorted(nvpair_dict.items()): _append_new_nvpair(nvset_element, name, value, id_provider) if enforce_append: context_element.append(nvset_element) else: append_when_useful(context_element, nvset_element)
def test_not_useful(self): element = etree.Element("new") lib.append_when_useful(self.parent, element) assert_xml_equal( self.tree_str, etree_to_str(self.tree) )
def arrange_first_nvset( tag_name, context_element, nvpair_dict, id_provider, new_id=None ): """ Put nvpairs to the first tag_name nvset in the context_element. If the nvset does not exist, it will be created. WARNING: does not solve multiple nvsets (with the same tag_name) in the context_element! Consider carefully if this is your use case. Probably not. There could be more than one nvset. This function is DEPRECATED. Try to use update_nvset etc. string tag_name -- tag name of nvset element etree context_element -- parent element of nvset dict nvpair_dict -- dictionary of nvpairs IdProvider id_provider -- elements' ids generator """ if not nvpair_dict: return nvset_element = get_sub_element( context_element, tag_name, new_id=(new_id if new_id else create_subelement_id( context_element, tag_name, id_provider )), append_if_missing=False ) update_nvset(nvset_element, nvpair_dict, id_provider) append_when_useful(context_element, nvset_element, index=0)
def append_new_nvset( tag_name, context_element, nvpair_dict, id_provider, enforce_append=False ): """ Append new nvset_element comprising nvpairs children (corresponding nvpair_dict) to the context_element string tag_name should be "instance_attributes" or "meta_attributes" etree.Element context_element is element where new nvset will be appended dict nvpair_dict contains source for nvpair children IdProvider id_provider -- elements' ids generator bool enforce_append -- append element wo usefulness check if flag is True """ nvset_element = etree.Element( tag_name, { "id": create_subelement_id(context_element, tag_name, id_provider) } ) for name, value in sorted(nvpair_dict.items()): _append_new_nvpair(nvset_element, name, value, id_provider) if enforce_append: context_element.append(nvset_element) else: append_when_useful(context_element, nvset_element)
def test_already_appended(self): element = self.tree.find(".//element-A2") lib.append_when_useful(self.parent, element) assert_xml_equal( self.tree_str, etree_to_str(self.tree) )
def test_not_useful_with_attributes(self): element = etree.Element("new", attr="test") lib.append_when_useful(self.parent, element, attribs_important=False) assert_xml_equal( self.tree_str, etree_to_str(self.tree) )
def test_already_appended(self): element = self.tree.find(".//element-A2") lib.append_when_useful(self.parent, element) assert_xml_equal( self.tree_str, etree_to_str(self.tree) )
def test_not_useful_with_attributes(self): element = etree.Element("new", attr="test") lib.append_when_useful(self.parent, element, attribs_important=False) assert_xml_equal( self.tree_str, etree_to_str(self.tree) )
def test_not_useful(self): element = etree.Element("new") lib.append_when_useful(self.parent, element) assert_xml_equal( self.tree_str, etree_to_str(self.tree) )
def test_different_parent_not_useful(self): element = self.tree.find(".//element-B2") lib.append_when_useful(self.parent, element) assert_xml_equal( self.tree_str, etree_to_str(self.tree) )
def test_different_parent_useful(self): element = self.tree.find(".//element-B1") lib.append_when_useful(self.parent, element) assert_xml_equal( """ <root> <parent-A> <element-A1 /> <element-A2 attr="test" /> <element-B1 attr="test"/> </parent-A> <parent-B> <element-B2 /> </parent-B> </root> """, etree_to_str(self.tree))
def test_index(self): element = etree.Element("new", attr="test") lib.append_when_useful(self.parent, element, index=1) assert_xml_equal( """ <root> <parent-A> <element-A1 /> <new attr="test" /> <element-A2 attr="test" /> </parent-A> <parent-B> <element-B1 attr="test"/> <element-B2 /> </parent-B> </root> """, etree_to_str(self.tree))
def test_different_parent_useful(self): element = self.tree.find(".//element-B1") lib.append_when_useful(self.parent, element) assert_xml_equal( """ <root> <parent-A> <element-A1 /> <element-A2 attr="test" /> <element-B1 attr="test"/> </parent-A> <parent-B> <element-B2 /> </parent-B> </root> """, etree_to_str(self.tree) )
def test_index(self): element = etree.Element("new", attr="test") lib.append_when_useful(self.parent, element, index=1) assert_xml_equal( """ <root> <parent-A> <element-A1 /> <new attr="test" /> <element-A2 attr="test" /> </parent-A> <parent-B> <element-B1 attr="test"/> <element-B2 /> </parent-B> </root> """, etree_to_str(self.tree) )
def update_node_instance_attrs(cib, id_provider, node_name, attrs, state_nodes=None): """ Update nvpairs in instance_attributes for a node specified by its name. Automatically creates instance_attributes element if needed. If the node has more than one instance_attributes element, the first one is modified. If the node is missing in the CIB, it is automatically created if its state is provided in state_nodes. etree cib -- cib IdProvider id_provider -- elements' ids generator string node_name -- name of the node to be updated dict attrs -- attrs to update, e.g. {'A': 'a', 'B': ''} iterable state_nodes -- optional list of node state objects """ # Do not ever remove the nvset element or the node element, even if they # are empty. There may be ACLs set in pacemaker which allow "write" for # nvpairs (adding, changing and removing) but not nvsets. In such a case, # removing the nvset would cause the whole change to be rejected by # pacemaker with a "permission denied" message. # https://bugzilla.redhat.com/show_bug.cgi?id=1642514 if not attrs: return cib_nodes = get_nodes(cib) node_el = _ensure_node_exists(cib_nodes, node_name, state_nodes) # If no instance_attributes id is specified, crm_attribute modifies the # first one found. So we just mimic this behavior here. attrs_el = node_el.find("./instance_attributes") if attrs_el is None: attrs_el = etree.Element( "instance_attributes", id=id_provider.allocate_id("nodes-{0}".format(node_el.get("id"))), ) update_nvset(attrs_el, attrs, id_provider) append_when_useful(node_el, attrs_el) append_when_useful(cib_nodes, node_el)
def update_node_instance_attrs( cib, id_provider, node_name, attrs, state_nodes=None ): """ Update nvpairs in instance_attributes for a node specified by its name. Automatically creates instance_attributes element if needed. If the node has more than one instance_attributes element, the first one is modified. If the node is missing in the CIB, it is automatically created if its state is provided in state_nodes. etree cib -- cib IdProvider id_provider -- elements' ids generator string node_name -- name of the node to be updated dict attrs -- attrs to update, e.g. {'A': 'a', 'B': ''} iterable state_nodes -- optional list of node state objects """ # Do not ever remove the nvset element or the node element, even if they # are empty. There may be ACLs set in pacemaker which allow "write" for # nvpairs (adding, changing and removing) but not nvsets. In such a case, # removing the nvset would cause the whole change to be rejected by # pacemaker with a "permission denied" message. # https://bugzilla.redhat.com/show_bug.cgi?id=1642514 if not attrs: return cib_nodes = get_nodes(cib) node_el = _ensure_node_exists(cib_nodes, node_name, state_nodes) # If no instance_attributes id is specified, crm_attribute modifies the # first one found. So we just mimic this behavior here. attrs_el = node_el.find("./instance_attributes") if attrs_el is None: attrs_el = etree.Element( "instance_attributes", id=id_provider.allocate_id("nodes-{0}".format(node_el.get("id"))), ) update_nvset(attrs_el, attrs, id_provider) append_when_useful(node_el, attrs_el) append_when_useful(cib_nodes, node_el)
def update( id_provider, bundle_el, container_options, network_options, port_map_add, port_map_remove, storage_map_add, storage_map_remove, meta_attributes, ): # pylint: disable=too-many-arguments, too-many-locals """ Modify an existing bundle (does not touch encapsulated resources) IdProvider id_provider -- elements' ids generator and uniqueness checker etree bundle_el -- the bundle to be updated dict container_options -- container options to modify dict network_options -- network options to modify list of dict port_map_add -- list of port mapping options to add list of string port_map_remove -- list of port mapping ids to remove list of dict storage_map_add -- list of storage mapping options to add list of string storage_map_remove -- list of storage mapping ids to remove dict meta_attributes -- meta attributes to update """ # Do not ever remove meta_attributes, network and storage elements, even if # they are empty. There may be ACLs set in pacemaker which allow "write" # for their children (adding, changing and removing) but not themselves. In # such a case, removing those elements would cause the whole change to be # rejected by pacemaker with a "permission denied" message. # https://bugzilla.redhat.com/show_bug.cgi?id=1642514 bundle_id = bundle_el.get("id") update_attributes_remove_empty(_get_container_element(bundle_el), container_options) network_element = get_sub_element(bundle_el, "network", append_if_missing=False) if network_options: update_attributes_remove_empty(network_element, network_options) # It's crucial to remove port maps prior to appending new ones: If we are # adding a port map which in any way conflicts with another one and that # another one is being removed in the very same command, the removal must # be done first, otherwise the conflict would manifest itself (and then # possibly the old mapping would be removed) if port_map_remove: _remove_map_elements(network_element.findall("port-mapping"), port_map_remove) if port_map_add: for port_map_options in port_map_add: _append_port_map(network_element, id_provider, bundle_id, port_map_options) append_when_useful(bundle_el, network_element) storage_element = get_sub_element(bundle_el, "storage", append_if_missing=False) # See the comment above about removing port maps prior to adding new ones. if storage_map_remove: _remove_map_elements(storage_element.findall("storage-mapping"), storage_map_remove) if storage_map_add: for storage_map_options in storage_map_add: _append_storage_map(storage_element, id_provider, bundle_id, storage_map_options) append_when_useful(bundle_el, storage_element) if meta_attributes: arrange_first_meta_attributes(bundle_el, meta_attributes, id_provider)