def _append_container(bundle_element, container_type, container_options): # Do not add options with empty values. When updating, an empty value means # remove the option. update_attributes_remove_empty( etree.SubElement(bundle_element, container_type), container_options, )
def append_new(parent_element, id_provider, bundle_id, container_type, container_options, network_options, port_map, storage_map): """ Create new bundle and add it to the CIB etree parent_element -- the bundle will be appended to this element IdProvider id_provider -- elements' ids generator string bundle_id -- id of the bundle string container_type -- bundle container type dict container_options -- container options dict network_options -- network options list of dict port_map -- list of port mapping options list of dict storage_map -- list of storage mapping options """ bundle_element = etree.SubElement(parent_element, TAG, {"id": bundle_id}) # TODO create the proper element once more container_types are supported # by pacemaker docker_element = etree.SubElement(bundle_element, "docker") # Do not add options with empty values. When updating, an empty value means # remove the option. update_attributes_remove_empty(docker_element, container_options) if network_options or port_map: network_element = etree.SubElement(bundle_element, "network") # Do not add options with empty values. When updating, an empty value # means remove the option. update_attributes_remove_empty(network_element, network_options) for port_map_options in port_map: _append_port_map(network_element, id_provider, bundle_id, port_map_options) if storage_map: storage_element = etree.SubElement(bundle_element, "storage") for storage_map_options in storage_map: _append_storage_map(storage_element, id_provider, bundle_id, storage_map_options) return bundle_element
def test_more(self): lib.update_attributes_remove_empty(self.el, { "a": "X", "b": "", "c": "C", "d": "", }) self.assert_xml_equal('<test_element a="X" c="C" />')
def _append_network(bundle_element, id_provider, id_base, network_options, port_map): network_element = etree.SubElement(bundle_element, "network") # Do not add options with empty values. When updating, an empty value means # remove the option. update_attributes_remove_empty(network_element, network_options) for port_map_options in port_map: _append_port_map(network_element, id_provider, id_base, port_map_options)
def _append_storage_map(parent_element, id_provider, id_base, storage_map_options): if "id" not in storage_map_options: storage_map_options["id"] = id_provider.allocate_id( # use just numbers to keep the ids reasonably short "{0}-storage-map".format(id_base)) storage_map_element = etree.SubElement(parent_element, "storage-mapping") # Do not add options with empty values. When updating, an empty value means # remove the option. update_attributes_remove_empty(storage_map_element, storage_map_options) return storage_map_element
def update(id_provider, bundle_el, container_options, network_options, port_map_add, port_map_remove, storage_map_add, storage_map_remove, meta_attributes): """ 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 """ 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") 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) for port_map_options in port_map_add: _append_port_map(network_element, id_provider, bundle_id, port_map_options) storage_element = get_sub_element(bundle_el, "storage") # 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) for storage_map_options in storage_map_add: _append_storage_map(storage_element, id_provider, bundle_id, storage_map_options) if meta_attributes: arrange_first_meta_attributes(bundle_el, meta_attributes) # remove empty elements with no attributes # meta attributes are handled in their own function remove_when_pointless(network_element) remove_when_pointless(storage_element)
def _append_port_map(parent_element, id_provider, id_base, port_map_options): if "id" not in port_map_options: id_suffix = None if "port" in port_map_options: id_suffix = port_map_options["port"] elif "range" in port_map_options: id_suffix = port_map_options["range"] if id_suffix: port_map_options["id"] = id_provider.allocate_id( sanitize_id("{0}-port-map-{1}".format(id_base, id_suffix))) port_map_element = etree.SubElement(parent_element, "port-mapping") # Do not add options with empty values. When updating, an empty value means # remove the option. update_attributes_remove_empty(port_map_element, port_map_options) return port_map_element
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)