def update_node_instance_attrs(cib, 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 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 """ node_el = _ensure_node_exists(get_nodes(cib), 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.SubElement( node_el, "instance_attributes", id=find_unique_id(cib, "nodes-{0}".format(node_el.get("id"))) ) update_nvset(attrs_el, attrs)
def test_updates_nvset(self): nvset_element = etree.fromstring(""" <instance_attributes id="iattrs"> <nvpair id="iattrs-a" name="a" value="b"/> <nvpair id="iattrs-c" name="c" value="d"/> <nvpair id="iattrs-e" name="e" value="f"/> </instance_attributes> """) id_provider = IdProvider(nvset_element) nvpair.update_nvset( nvset_element, { "a": "B", "c": "", "g": "h", }, id_provider ) assert_xml_equal( """ <instance_attributes id="iattrs"> <nvpair id="iattrs-a" name="a" value="B"/> <nvpair id="iattrs-e" name="e" value="f"/> <nvpair id="iattrs-g" name="g" value="h"/> </instance_attributes> """, etree_to_str(nvset_element) )
def test_empty_value_has_no_effect(self): xml = """ <instance_attributes id="iattrs"> <nvpair id="1" name="a" value="b"/> <nvpair id="2" name="c" value="d"/> <nvpair id="3" name="e" value="f"/> </instance_attributes> """ nvset_element = etree.fromstring(xml) nvpair.update_nvset(nvset_element, {}) assert_xml_equal(xml, etree.tostring(nvset_element).decode())
def test_empty_value_has_no_effect(self): xml = """ <instance_attributes id="iattrs"> <nvpair id="iattrs-b" name="a" value="b"/> <nvpair id="iattrs-d" name="c" value="d"/> <nvpair id="iattrs-f" name="e" value="f"/> </instance_attributes> """ nvset_element = etree.fromstring(xml) id_provider = IdProvider(nvset_element) nvpair.update_nvset(nvset_element, {}, id_provider) assert_xml_equal(xml, etree_to_str(nvset_element))
def test_remove_empty_nvset(self): xml_pre = """ <resource> <instance_attributes id="iattrs"> <nvpair id="1" name="a" value="b"/> </instance_attributes> </resource> """ xml_post = """ <resource> </resource> """ xml = etree.fromstring(xml_pre) nvset_element = xml.find("instance_attributes") nvpair.update_nvset(nvset_element, {"a": ""}) assert_xml_equal(xml_post, etree_to_str(xml))
def test_new(self): root = etree.Element("root", id="root") assert_xml_equal( """ <nvset id="root-nvset"> <nvpair id="root-nvset-attr" name="attr" value="10"/> <nvpair id="root-nvset-new_one" name="new_one" value="20"/> <nvpair id="root-nvset-test" name="test" value="0"/> </nvset> """, etree.tostring(nvpair.update_nvset("nvset", root, root, { "attr": "10", "new_one": "20", "test": "0", "attr2": "" })).decode() ) assert_xml_equal( """ <root id="root"> <nvset id="root-nvset"> <nvpair id="root-nvset-attr" name="attr" value="10"/> <nvpair id="root-nvset-new_one" name="new_one" value="20"/> <nvpair id="root-nvset-test" name="test" value="0"/> </nvset> </root> """, etree.tostring(root).decode() )
def test_keep_empty_nvset(self): xml_pre = """ <resource> <instance_attributes id="iattrs"> <nvpair id="iattrs-a" name="a" value="b"/> </instance_attributes> </resource> """ xml_post = """ <resource> <instance_attributes id="iattrs" /> </resource> """ xml = etree.fromstring(xml_pre) nvset_element = xml.find("instance_attributes") id_provider = IdProvider(nvset_element) nvpair.update_nvset(nvset_element, {"a": ""}, id_provider) assert_xml_equal(xml_post, etree_to_str(xml))
def update_meta_attributes(tree, element, attribute_dict): """ Updates meta attributes of element. Returns updated meta attributes element. tree -- cib etree node element -- parent element of meta attributes attribute_dict -- dictionary of nvpairs """ return update_nvset("meta_attributes", tree, element, attribute_dict)
def update_instance_attributes(tree, element, attribute_dict): """ Updates instance attributes of element. Returns updated instance attributes element. tree -- cib etree node element -- parent element of instance attributes attribute_dict -- dictionary of nvpairs """ return update_nvset("instance_attributes", tree, element, attribute_dict)
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 test_updates_nvset(self): nvset_element = etree.fromstring( """ <instance_attributes id="iattrs"> <nvpair id="1" name="a" value="b"/> <nvpair id="2" name="c" value="d"/> <nvpair id="3" name="e" value="f"/> </instance_attributes> """ ) nvpair.update_nvset(nvset_element, {"a": "B", "c": "", "g": "h"}) assert_xml_equal( """ <instance_attributes id="iattrs"> <nvpair id="1" name="a" value="B"/> <nvpair id="3" name="e" value="f"/> <nvpair id="4" name="g" value="h"/> </instance_attributes> """, etree.tostring(nvset_element).decode(), )
def test_updates_nvset(self): nvset_element = etree.fromstring(""" <instance_attributes id="iattrs"> <nvpair id="1" name="a" value="b"/> <nvpair id="2" name="c" value="d"/> <nvpair id="3" name="e" value="f"/> </instance_attributes> """) nvpair.update_nvset(nvset_element, { "a": "B", "c": "", "g": "h", }) assert_xml_equal( """ <instance_attributes id="iattrs"> <nvpair id="1" name="a" value="B"/> <nvpair id="3" name="e" value="f"/> <nvpair id="4" name="g" value="h"/> </instance_attributes> """, etree_to_str(nvset_element))
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 test_updates_nvset(self): nvset_element = etree.fromstring(""" <instance_attributes id="iattrs"> <nvpair id="iattrs-a" name="a" value="b"/> <nvpair id="iattrs-c" name="c" value="d"/> <nvpair id="iattrs-e" name="e" value="f"/> </instance_attributes> """) id_provider = IdProvider(nvset_element) nvpair.update_nvset(nvset_element, { "a": "B", "c": "", "g": "h", }, id_provider) assert_xml_equal( """ <instance_attributes id="iattrs"> <nvpair id="iattrs-a" name="a" value="B"/> <nvpair id="iattrs-e" name="e" value="f"/> <nvpair id="iattrs-g" name="g" value="h"/> </instance_attributes> """, etree_to_str(nvset_element))
def test_existing(self): self.assertEqual( self.nvset, nvpair.update_nvset("nvset", self.root, self.root, { "attr": "10", "new_one": "20", "test": "0", "attr2": "" }) ) assert_xml_equal( """ <nvset id="nvset"> <nvpair id="nvset-attr" name="attr" value="10"/> <notnvpair id="nvset-test" name="test" value="0"/> <nvpair id="nvset-new_one" name="new_one" value="20"/> <nvpair id="nvset-test-1" name="test" value="0"/> </nvset> """, etree.tostring(self.nvset).decode() )
def test_None(self): self.assertTrue( nvpair.update_nvset("nvset", self.root, self.root, None) is None )
def test_empty(self): self.assertTrue( nvpair.update_nvset("nvset", self.root, self.root, {}) is None )