def _export_node_attr(self, parent_el: _Element, expr: NodeAttrExpr) -> _Element: element = etree.SubElement( parent_el, "expression", { "id": create_subelement_id(parent_el, "expr", self.id_provider), "attribute": expr.attr_name, "operation": expr.operator.lower(), }, ) if expr.attr_value: element.attrib["value"] = expr.attr_value if expr.attr_type: # rhbz#1869399 # Pcs was always accepting 'integer', while CIB was only supporting # 'number' (and 'string' and 'version'). Pacemaker was documenting # it as 'integer' and was treating it as integer (not float). With # CIB schema 3.5.0, both 'integer' and 'number' are accepted by # CIB. For older schemas, we turn 'integer' to 'number'. if (self.cib_schema_version < Version(3, 5, 0) and expr.attr_type == NODE_ATTR_TYPE_INTEGER): element.attrib["type"] = "number" else: element.attrib["type"] = expr.attr_type.lower() return element
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 _export_datespec(self, parent_el: _Element, expr: DatespecExpr) -> _Element: element = etree.SubElement( parent_el, "date_expression", { "id": create_subelement_id(parent_el, "expr", self.id_provider), "operation": "date_spec", }, ) datespec_attrs = dict(expr.date_parts) datespec_attrs["id"] = create_subelement_id(element, "datespec", self.id_provider) etree.SubElement(element, "date_spec", datespec_attrs) return element
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 test_parent_has_no_id(self): context = etree.fromstring("<cib><a/></cib>") self.assertEqual( "a-name", lib.create_subelement_id(context.find(".//a"), "name", lib.IdProvider(context)), )
def test_create_decorated_id_when_conflicting_id_there(self): context = etree.fromstring('<cib><a id="b"><c id="b-name"/></a></cib>') self.assertEqual( "b-name-1", lib.create_subelement_id(context.find(".//a"), "name", lib.IdProvider(context)), )
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 arrange_first_nvset(tag_name, context_element, nvpair_dict): """ 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 """ if not nvpair_dict: return nvset_element = get_sub_element(context_element, tag_name, create_subelement_id( context_element, tag_name), new_index=0) update_nvset(nvset_element, nvpair_dict)
def arrange_first_nvset(tag_name, context_element, nvpair_dict): """ Arrange to context_element contains some nvset (with tag_name) with nvpairs corresponing to nvpair_dict. WARNING: does not solve multiple nvset (with tag_name) under context_element! Consider carefully if this is your case. Probably not. There could be more than one nvset. This function is DEPRECATED. Try to use update_nvset etc. This method updates nvset specified by tag_name. If specified nvset doesn't exist it will be created. Returns updated nvset element or None if nvpair_dict is empty. tag_name -- tag name of nvset element context_element -- parent element of nvset nvpair_dict -- dictionary of nvpairs """ if not nvpair_dict: return nvset_element = get_sub_element( context_element, tag_name, create_subelement_id(context_element, tag_name), new_index=0 ) update_nvset(nvset_element, nvpair_dict)
def nvset_append_new( parent_element: _Element, id_provider: IdProvider, nvset_tag: NvsetTag, nvpair_dict: Mapping[str, str], nvset_options: Mapping[str, str], nvset_rule: Optional[RuleRoot] = None, ) -> _Element: """ Create new nvset and append it to CIB parent_element -- the created nvset will be appended into this element id_provider -- elements' ids generator nvset_tag -- type and actual tag of the nvset nvpair_dict -- nvpairs to be put into the new nvset nvset_options -- additional attributes of the created nvset nvset_rule -- optional rule describing when the created nvset applies """ nvset_options = dict(nvset_options) # make a copy which we can modify if "id" not in nvset_options or not nvset_options["id"]: nvset_options["id"] = create_subelement_id(parent_element, nvset_tag, id_provider) nvset_el = etree.SubElement(parent_element, nvset_tag) for name, value in nvset_options.items(): if value != "": nvset_el.attrib[name] = value if nvset_rule: rule_to_cib(nvset_el, id_provider, nvset_rule) for name, value in nvpair_dict.items(): _set_nvpair(nvset_el, id_provider, name, value) return nvset_el
def arrange_first_nvset(tag_name, context_element, attribute_dict): """ Arrange to context_element contains some nvset (with tag_name) with nvpairs corresponing to attribute_dict. WARNING: does not solve multiple nvset (with tag_name) under context_element! Consider carefully if this is your case. Probably not. There could be more than one nvset. This function is DEPRECATED. Try to use update_nvset etc. This method updates nvset specified by tag_name. If specified nvset doesn't exist it will be created. Returns updated nvset element or None if attribute_dict is empty. tag_name -- tag name of nvset element context_element -- parent element of nvset attribute_dict -- dictionary of nvpairs """ if not attribute_dict: return nvset_element = get_sub_element( context_element, tag_name, create_subelement_id(context_element, tag_name), new_index=0 ) update_nvset(nvset_element, attribute_dict)
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_create_plain_id_when_no_confilicting_id_there(self): context = etree.fromstring('<cib><a id="b"/></cib>') self.assertEqual( "b-name", lib.create_subelement_id( context.find(".//a"), "name", lib.IdProvider(context) ) )
def test_create_decorated_id_when_conflicting_id_there(self): context = etree.fromstring( '<cib><a id="b"><c id="b-name"/></a></cib>' ) self.assertEqual( "b-name-1", lib.create_subelement_id(context.find(".//a"), "name") )
def create_id(context_element, name, interval): """ Create id for op element. etree context_element is used for the name building string name is the name of the operation mixed interval is the interval attribute of operation """ return create_subelement_id(context_element, "{0}-interval-{1}".format(name, interval))
def create_id(context_element, name, interval): """ Create id for op element. etree context_element is used for the name building string name is the name of the operation mixed interval is the interval attribute of operation """ return create_subelement_id( context_element, "{0}-interval-{1}".format(name, interval) )
def _export_date_inrange(self, parent_el: _Element, expr: DateInRangeExpr) -> _Element: element = etree.SubElement( parent_el, "date_expression", { "id": create_subelement_id(parent_el, "expr", self.id_provider), "operation": "in_range", }, ) if expr.date_start: element.attrib["start"] = expr.date_start if expr.duration_parts: duration_attrs = dict(expr.duration_parts) duration_attrs["id"] = create_subelement_id( element, "duration", self.id_provider) etree.SubElement(element, "duration", duration_attrs) elif expr.date_end: element.attrib["end"] = expr.date_end return element
def __export_bool(parent_el: _Element, boolean: BoolExpr, id_provider: IdProvider) -> _Element: element = etree.SubElement( parent_el, "rule", { "id": create_subelement_id(parent_el, "rule", id_provider), "boolean-op": boolean.operator.lower(), }, ) for child in boolean.children: __export_part(element, child, id_provider) return element
def _append_new_nvpair(nvset_element, name, value): """ Create nvpair with name and value as subelement of nvset_element. etree.Element nvset_element is context of new nvpair string name is name attribute of new nvpair string value is value attribute of new nvpair """ etree.SubElement(nvset_element, "nvpair", id=create_subelement_id(nvset_element, name), name=name, value=value)
def __export_op(parent_el: _Element, op: OpExpr, id_provider: IdProvider) -> _Element: element = etree.SubElement( parent_el, "op_expression", { "id": create_subelement_id(parent_el, f"op-{op.name}", id_provider), "name": op.name, }, ) if op.interval: element.attrib["interval"] = op.interval return element
def append_new_nvset(tag_name, context_element, nvpair_dict): """ 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 """ nvset_element = etree.SubElement(context_element, tag_name, { "id": create_subelement_id(context_element, tag_name) }) for name, value in sorted(nvpair_dict.items()): _append_new_nvpair(nvset_element, name, value)
def _append_new_nvpair(nvset_element, name, value, id_provider=None): """ Create nvpair with name and value as subelement of nvset_element. etree.Element nvset_element is context of new nvpair string name is name attribute of new nvpair string value is value attribute of new nvpair IdProvider id_provider -- elements' ids generator """ etree.SubElement(nvset_element, "nvpair", id=create_subelement_id(nvset_element, name, id_provider), name=name, value=value)
def append_new_nvset(tag_name, context_element, nvpair_dict): """ 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 """ nvset_element = etree.SubElement( context_element, tag_name, {"id": create_subelement_id(context_element, tag_name)}) for name, value in sorted(nvpair_dict.items()): _append_new_nvpair(nvset_element, name, value)
def __export_rsc(parent_el: _Element, rsc: RscExpr, id_provider: IdProvider) -> _Element: id_part = "-".join(filter(None, [rsc.standard, rsc.provider, rsc.type])) element = etree.SubElement( parent_el, "rsc_expression", {"id": create_subelement_id(parent_el, f"rsc-{id_part}", id_provider)}, ) if rsc.standard: element.attrib["class"] = rsc.standard if rsc.provider: element.attrib["provider"] = rsc.provider if rsc.type: element.attrib["type"] = rsc.type return element
def _append_new_nvpair(nvset_element, name, value): """ Create nvpair with name and value as subelement of nvset_element. etree.Element nvset_element is context of new nvpair string name is name attribute of new nvpair string value is value attribute of new nvpair """ etree.SubElement( nvset_element, "nvpair", id=create_subelement_id(nvset_element, name), name=name, value=value )
def _append_new_nvpair(nvset_element, name, value, id_provider): """ Create nvpair with name and value as subelement of nvset_element. etree.Element nvset_element is context of new nvpair string name is name attribute of new nvpair string value is value attribute of new nvpair IdProvider id_provider -- elements' ids generator """ etree.SubElement( nvset_element, "nvpair", id=create_subelement_id(nvset_element, name, id_provider), name=name, value=value )
def _export_date_unary(self, parent_el: _Element, expr: DateUnaryExpr) -> _Element: element = etree.SubElement( parent_el, "date_expression", { "id": create_subelement_id(parent_el, "expr", self.id_provider), "operation": expr.operator.lower(), }, ) if expr.operator == DATE_OP_GT: element.attrib["start"] = expr.date elif expr.operator == DATE_OP_LT: element.attrib["end"] = expr.date return element
def _set_nvpair(nvset_element: Element, id_provider: IdProvider, name: str, value: str) -> None: """ Ensure name-value pair is set / removed in specified nvset nvset_element -- container for nvpair elements to update id_provider -- elements' ids generator name -- name of the nvpair to be set value -- value of the nvpair to be set, if "" the nvpair will be removed """ nvpair_el_list = cast( # The xpath method has a complicated return value, but we know our xpath # expression returns only elements. List[Element], cast(_Element, nvset_element).xpath("./nvpair[@name=$name]", name=name), ) if not nvpair_el_list: if value != "": etree.SubElement( cast(_Element, nvset_element), "nvpair", { "id": create_subelement_id( nvset_element, # limit id length to prevent excessively long ids name[:20], id_provider, ), "name": name, "value": value, }, ) return if value != "": nvpair_el_list[0].set("value", value) else: nvset_element.remove(nvpair_el_list[0]) for nvpair_el in nvpair_el_list[1:]: nvset_element.remove(nvpair_el)
def __export_bool(parent_el: _Element, boolean: BoolExpr, id_provider: IdProvider) -> _Element: element = etree.SubElement( parent_el, "rule", { "id": create_subelement_id(parent_el, "rule", id_provider), "boolean-op": boolean.operator.lower(), # Score or score-attribute is required for nested rules, otherwise # the CIB is not valid. Pacemaker doesn't use the score of nested # rules. Score for the top rule, which is used by pacemaker, is # supposed to be set in the export function above. "score": "0", }, ) for child in boolean.children: __export_part(element, child, id_provider) return element
def set_nvpair_in_nvset(nvset_element, name, value): """ Update nvpair, create new if it doesn't yet exist or remove existing nvpair if value is empty. nvset_element -- element in which nvpair should be added/updated/removed name -- name of nvpair value -- value of nvpair """ nvpair = nvset_element.find("./nvpair[@name='{0}']".format(name)) if nvpair is None: if value: etree.SubElement( nvset_element, "nvpair", id=create_subelement_id(nvset_element, name), name=name, value=value ) else: if value: nvpair.set("value", value) else: nvset_element.remove(nvpair)