def location_rule(argv): if len(argv) < 3: usage.constraint(["location", "rule"]) sys.exit(1) res_name = argv.pop(0) resource_valid, resource_error, correct_id \ = utils.validate_constraint_resource(utils.get_cib_dom(), res_name) if "--autocorrect" in utils.pcs_options and correct_id: res_name = correct_id elif not resource_valid: utils.err(resource_error) argv.pop(0) # pop "rule" options, rule_argv = rule_utils.parse_argv(argv, {"constraint-id": None, "resource-discovery": None,}) # If resource-discovery is specified, we use it with the rsc_location # element not the rule if "resource-discovery" in options and options["resource-discovery"]: utils.checkAndUpgradeCIB(2,2,0) cib, constraints = getCurrentConstraints(utils.get_cib_dom()) lc = cib.createElement("rsc_location") lc.setAttribute("resource-discovery", options.pop("resource-discovery")) else: cib, constraints = getCurrentConstraints(utils.get_cib_dom()) lc = cib.createElement("rsc_location") constraints.appendChild(lc) if options.get("constraint-id"): id_valid, id_error = utils.validate_xml_id( options["constraint-id"], 'constraint id' ) if not id_valid: utils.err(id_error) if utils.does_id_exist(cib, options["constraint-id"]): utils.err( "id '%s' is already in use, please specify another one" % options["constraint-id"] ) lc.setAttribute("id", options["constraint-id"]) del options["constraint-id"] else: lc.setAttribute("id", utils.find_unique_id(cib, "location-" + res_name)) lc.setAttribute("rsc", res_name) rule_utils.dom_rule_add(lc, options, rule_argv) location_rule_check_duplicates(constraints, lc) utils.replace_cib_configuration(cib)
def run_role_delete(argv): if len(argv) < 1: usage.acl(["role delete"]) sys.exit(1) role_id = argv.pop(0) dom = utils.get_cib_dom() found = False for elem in dom.getElementsByTagName("acl_role"): if elem.getAttribute("id") == role_id: found = True elem.parentNode.removeChild(elem) break if not found: utils.err("unable to find acl role: %s" % role_id) # Remove any references to this role in acl_target or acl_group for elem in dom.getElementsByTagName("role"): if elem.getAttribute("id") == role_id: user_group = elem.parentNode user_group.removeChild(elem) if "--autodelete" in utils.pcs_options: if not user_group.getElementsByTagName("role"): user_group.parentNode.removeChild(user_group) utils.replace_cib_configuration(dom)
def print_node_utilization(filter_node=None, filter_name=None): cib = utils.get_cib_dom() node_element_list = cib.getElementsByTagName("node") if( filter_node and filter_node not in [ node_element.getAttribute("uname") for node_element in node_element_list ] and ( utils.usefile or filter_node not in [ node_attrs.name for node_attrs in utils.getNodeAttributesFromPacemaker() ] ) ): utils.err("Unable to find a node: {0}".format(filter_node)) utilization = {} for node_el in node_element_list: node = node_el.getAttribute("uname") if filter_node is not None and node != filter_node: continue u = utils.get_utilization_str(node_el, filter_name) if u: utilization[node] = u print("Node Utilization:") for node in sorted(utilization): print(" {0}: {1}".format(node, utilization[node]))
def set_node_utilization(node, argv): cib = utils.get_cib_dom() node_el = utils.dom_get_node(cib, node) if node_el is None: if utils.usefile: utils.err("Unable to find a node: {0}".format(node)) for attrs in utils.getNodeAttributesFromPacemaker(): if attrs.name == node and attrs.type == "remote": node_attrs = attrs break else: utils.err("Unable to find a node: {0}".format(node)) nodes_section_list = cib.getElementsByTagName("nodes") if len(nodes_section_list) == 0: utils.err("Unable to get nodes section of cib") dom = nodes_section_list[0].ownerDocument node_el = dom.createElement("node") node_el.setAttribute("id", node_attrs.id) node_el.setAttribute("type", node_attrs.type) node_el.setAttribute("uname", node_attrs.name) nodes_section_list[0].appendChild(node_el) utils.dom_update_utilization(node_el, prepare_options(argv), "nodes-") utils.replace_cib_configuration(cib)
def stonith_level_add(level, node, devices): dom = utils.get_cib_dom() if not re.search(r'^\d+$', level) or re.search(r'^0+$', level): utils.err("invalid level '{0}', use a positive integer".format(level)) level = level.lstrip('0') if "--force" not in utils.pcs_options: for dev in devices.split(","): if not utils.is_stonith_resource(dev): utils.err("%s is not a stonith id (use --force to override)" % dev) if not utils.is_pacemaker_node(node) and not utils.is_corosync_node(node): utils.err("%s is not currently a node (use --force to override)" % node) ft = dom.getElementsByTagName("fencing-topology") if len(ft) == 0: conf = dom.getElementsByTagName("configuration")[0] ft = dom.createElement("fencing-topology") conf.appendChild(ft) else: ft = ft[0] fls = ft.getElementsByTagName("fencing-level") for fl in fls: if fl.getAttribute("target") == node and fl.getAttribute("index") == level and fl.getAttribute("devices") == devices: utils.err("unable to add fencing level, fencing level for node: %s, at level: %s, with device: %s already exists" % (node,level,devices)) new_fl = dom.createElement("fencing-level") ft.appendChild(new_fl) new_fl.setAttribute("target", node) new_fl.setAttribute("index", level) new_fl.setAttribute("devices", devices) new_fl.setAttribute("id", utils.find_unique_id(dom, "fl-" + node +"-" + level)) utils.replace_cib_configuration(dom)
def print_node_utilization(filter_node=None, filter_name=None): cib = utils.get_cib_dom() node_element_list = cib.getElementsByTagName("node") if (filter_node and filter_node not in [ node_element.getAttribute("uname") for node_element in node_element_list ] and (utils.usefile or filter_node not in [ node_attrs.name for node_attrs in utils.getNodeAttributesFromPacemaker() ])): utils.err("Unable to find a node: {0}".format(filter_node)) utilization = {} for node_el in node_element_list: node = node_el.getAttribute("uname") if filter_node is not None and node != filter_node: continue u = utils.get_utilization_str(node_el, filter_name) if u: utilization[node] = u print("Node Utilization:") for node in sorted(utilization): print(" {0}: {1}".format(node, utilization[node]))
def set_property(lib, argv, modifiers): """ Options: * --force - allow unknown options * -f - CIB file """ del lib modifiers.ensure_only_supported( "--force", "-f", # The hint is defined to print error messages which point users to the # changes section in pcs manpage. # To be removed in the next significant version. hint_syntax_changed=modifiers.is_specified("--node"), ) if not argv: raise CmdLineInputError() prop_def_dict = utils.get_cluster_properties_definition() failed = False forced = modifiers.get("--force") properties = {} for arg in argv: args = arg.split("=") if len(args) != 2: utils.err("invalid property format: '{0}'".format(arg), False) failed = True elif not args[0]: utils.err("empty property name: '{0}'".format(arg), False) failed = True elif forced or args[1].strip() == "": properties[args[0]] = args[1] else: try: if utils.is_valid_cluster_property(prop_def_dict, args[0], args[1]): properties[args[0]] = args[1] else: utils.err( "invalid value of property: '{0}', (use --force to " "override)".format(arg), False, ) failed = True except utils.UnknownPropertyException: utils.err( "unknown cluster property: '{0}', (use --force to " "override)".format(args[0]), False, ) failed = True if failed: sys.exit(1) cib_dom = utils.get_cib_dom() for prop, value in properties.items(): utils.set_cib_property(prop, value, cib_dom) utils.replace_cib_configuration(cib_dom)
def constraint_rule(argv): if len(argv) < 2: usage.constraint("rule") sys.exit(1) found = False command = argv.pop(0) constraint_id = None if command == "add": constraint_id = argv.pop(0) cib = utils.get_cib_dom() constraint = utils.dom_get_element_with_id( cib.getElementsByTagName("constraints")[0], "rsc_location", constraint_id ) if not constraint: utils.err("Unable to find constraint: " + constraint_id) options, rule_argv = rule_utils.parse_argv(argv) rule_utils.dom_rule_add(constraint, options, rule_argv) location_rule_check_duplicates(cib, constraint) utils.replace_cib_configuration(cib) elif command in ["remove","delete"]: cib = utils.get_cib_etree() temp_id = argv.pop(0) constraints = cib.find('.//constraints') loc_cons = cib.findall(str('.//rsc_location')) for loc_con in loc_cons: for rule in loc_con: if rule.get("id") == temp_id: if len(loc_con) > 1: print("Removing Rule: {0}".format(rule.get("id"))) loc_con.remove(rule) found = True break else: print( "Removing Constraint: {0}".format(loc_con.get("id")) ) constraints.remove(loc_con) found = True break if found == True: break if found: utils.replace_cib_configuration(cib) else: utils.err("unable to find rule with id: %s" % temp_id) else: usage.constraint("rule") sys.exit(1)
def status_stonith_check(): # We should read the default value from pacemaker. However that may slow # pcs down as we need to run 'pengine metadata' to get it. stonith_enabled = True stonith_devices = [] stonith_devices_id_action = [] stonith_devices_id_method_cycle = [] sbd_running = False cib = utils.get_cib_dom() for conf in cib.getElementsByTagName("configuration"): for crm_config in conf.getElementsByTagName("crm_config"): for nvpair in crm_config.getElementsByTagName("nvpair"): if (nvpair.getAttribute("name") == "stonith-enabled" and is_false(nvpair.getAttribute("value"))): stonith_enabled = False break if not stonith_enabled: break for resource in conf.getElementsByTagName("primitive"): if resource.getAttribute("class") == "stonith": stonith_devices.append(resource) for attribs in resource.getElementsByTagName( "instance_attributes"): for nvpair in attribs.getElementsByTagName("nvpair"): if (nvpair.getAttribute("name") == "action" and nvpair.getAttribute("value")): stonith_devices_id_action.append( resource.getAttribute("id")) if (nvpair.getAttribute("name") == "method" and nvpair.getAttribute("value") == "cycle"): stonith_devices_id_method_cycle.append( resource.getAttribute("id")) if not utils.usefile: # check if SBD daemon is running try: sbd_running = utils.is_service_running(utils.cmd_runner(), get_sbd_service_name()) except LibraryError: pass if stonith_enabled and not stonith_devices and not sbd_running: print("WARNING: no stonith devices and stonith-enabled is not false") if stonith_devices_id_action: print( "WARNING: following stonith devices have the 'action' option set, " "it is recommended to set {0} instead: {1}".format( ", ".join( ["'{0}'".format(x) for x in _STONITH_ACTION_REPLACED_BY]), ", ".join(sorted(stonith_devices_id_action)))) if stonith_devices_id_method_cycle: print( "WARNING: following stonith devices have the 'method' option set " "to 'cycle' which is potentially dangerous, please consider using " "'onoff': {0}".format(", ".join( sorted(stonith_devices_id_method_cycle))))
def print_node_utilization(node): cib = utils.get_cib_dom() node_el = utils.dom_get_node(cib, node) if node_el is None: utils.err("Unable to find a node: {0}".format(node)) utilization = utils.get_utilization_str(node_el) print("Node Utilization:") print(" {0}: {1}".format(node, utilization))
def print_nodes_utilization(): cib = utils.get_cib_dom() utilization = {} for node_el in cib.getElementsByTagName("node"): u = utils.get_utilization_str(node_el) if u: utilization[node_el.getAttribute("uname")] = u print("Node Utilization:") for node in sorted(utilization): print(" {0}: {1}".format(node, utilization[node]))
def set_node_utilization(node, argv): cib = utils.get_cib_dom() node_el = utils.dom_get_node(cib, node) if node_el is None: utils.err("Unable to find a node: {0}".format(node)) utils.dom_update_utilization( node_el, utils.convert_args_to_tuples(argv), "nodes-" ) utils.replace_cib_configuration(cib)
def stonith_level_rm(level, node, devices): dom = utils.get_cib_dom() if devices != "": node_devices_combo = node + "," + devices else: node_devices_combo = node ft = dom.getElementsByTagName("fencing-topology") if len(ft) == 0: utils.err( "unable to remove fencing level, fencing level for node: %s, at level: %s, with device: %s doesn't exist" % (node, level, devices)) else: ft = ft[0] fls = ft.getElementsByTagName("fencing-level") if node != "": if devices != "": found = False for fl in fls: if fl.getAttribute("target") == node and fl.getAttribute( "index") == level and fl.getAttribute( "devices") == devices: found = True break if fl.getAttribute("index") == level and fl.getAttribute( "devices") == node_devices_combo: found = True break if found == False: utils.err( "unable to remove fencing level, fencing level for node: %s, at level: %s, with device: %s doesn't exist" % (node, level, devices)) fl.parentNode.removeChild(fl) else: for fl in fls: if fl.getAttribute("index") == level and ( fl.getAttribute("target") == node or fl.getAttribute("devices") == node): fl.parentNode.removeChild(fl) else: for fl in fls: if fl.getAttribute("index") == level: parent = fl.parentNode parent.removeChild(fl) if len(parent.getElementsByTagName("fencing-level")) == 0: parent.parentNode.removeChild(parent) break utils.replace_cib_configuration(dom)
def set_property(lib, argv, modifiers): """ Options: * --force - allow unknown options * -f - CIB file """ del lib modifiers.ensure_only_supported( "--force", "-f", ) if not argv: raise CmdLineInputError() prop_def_dict = utils.get_cluster_properties_definition() failed = False forced = modifiers.get("--force") properties = {} for arg in argv: args = arg.split("=") if len(args) != 2: utils.err("invalid property format: '{0}'".format(arg), False) failed = True elif not args[0]: utils.err("empty property name: '{0}'".format(arg), False) failed = True elif forced or args[1].strip() == "": properties[args[0]] = args[1] else: try: if utils.is_valid_cluster_property(prop_def_dict, args[0], args[1]): properties[args[0]] = args[1] else: utils.err( "invalid value of property: '{0}', (use --force to " "override)".format(arg), False, ) failed = True except utils.UnknownPropertyException: utils.err( "unknown cluster property: '{0}', (use --force to " "override)".format(args[0]), False, ) failed = True if failed: sys.exit(1) cib_dom = utils.get_cib_dom() for prop, value in properties.items(): utils.set_cib_property(prop, value, cib_dom) utils.replace_cib_configuration(cib_dom)
def find_constraints_containing(resource_id, passed_dom=None): """ Commandline options: * -f - CIB file, effective only if passed_dom is None """ if passed_dom: dom = passed_dom else: dom = utils.get_cib_dom() constraints_found = [] set_constraints = [] resources = dom.getElementsByTagName("primitive") resource_match = None for res in resources: if res.getAttribute("id") == resource_id: resource_match = res break if resource_match: if ( resource_match.parentNode.tagName == "master" or resource_match.parentNode.tagName == "clone" ): constraints_found, set_constraints = find_constraints_containing( resource_match.parentNode.getAttribute("id"), dom ) constraints = dom.getElementsByTagName("constraints") if not constraints: return [], [] constraints = constraints[0] myConstraints = constraints.getElementsByTagName("rsc_colocation") myConstraints += constraints.getElementsByTagName("rsc_location") myConstraints += constraints.getElementsByTagName("rsc_order") myConstraints += constraints.getElementsByTagName("rsc_ticket") attr_to_match = ["rsc", "first", "then", "with-rsc", "first", "then"] for c in myConstraints: for attr in attr_to_match: if c.getAttribute(attr) == resource_id: constraints_found.append(c.getAttribute("id")) break setConstraints = constraints.getElementsByTagName("resource_ref") for c in setConstraints: if c.getAttribute("id") == resource_id: set_constraints.append(c.parentNode.parentNode.getAttribute("id")) # Remove duplicates set_constraints = list(set(set_constraints)) return constraints_found, set_constraints
def set_property(lib, argv, modifiers): """ Options: * --force - allow unknown options * -f - CIB file """ del lib modifiers.ensure_only_supported("--force", "-f") if not argv: raise CmdLineInputError() prop_def_dict = utils.get_cluster_properties_definition() failed = False forced = modifiers.get("--force") properties = {} for arg in argv: args = arg.split('=') if len(args) != 2: utils.err("invalid property format: '{0}'".format(arg), False) failed = True elif not args[0]: utils.err("empty property name: '{0}'".format(arg), False) failed = True elif forced or args[1].strip() == "": properties[args[0]] = args[1] else: try: if utils.is_valid_cluster_property( prop_def_dict, args[0], args[1] ): properties[args[0]] = args[1] else: utils.err( "invalid value of property: '{0}', (use --force to " "override)".format(arg), False ) failed = True except utils.UnknownPropertyException: utils.err( "unknown cluster property: '{0}', (use --force to " "override)".format(args[0]), False ) failed = True if failed: sys.exit(1) cib_dom = utils.get_cib_dom() for prop, value in properties.items(): utils.set_cib_property(prop, value, cib_dom) utils.replace_cib_configuration(cib_dom)
def stonith_level_verify(): dom = utils.get_cib_dom() fls = dom.getElementsByTagName("fencing-level") for fl in fls: node = fl.getAttribute("target") devices = fl.getAttribute("devices") for dev in devices.split(","): if not utils.is_stonith_resource(dev): utils.err("%s is not a stonith id" % dev) if not utils.is_corosync_node(node) and not utils.is_pacemaker_node(node): utils.err("%s is not currently a node" % node)
def set_property(argv): if not argv: usage.property(['set']) sys.exit(1) prop_def_dict = utils.get_cluster_properties_definition() nodes_attr = "--node" in utils.pcs_options failed = False forced = "--force" in utils.pcs_options properties = {} for arg in argv: args = arg.split('=') if len(args) != 2: utils.err("invalid property format: '{0}'".format(arg), False) failed = True elif not args[0]: utils.err("empty property name: '{0}'".format(arg), False) failed = True elif nodes_attr or forced or args[1].strip() == "": properties[args[0]] = args[1] else: try: if utils.is_valid_cluster_property( prop_def_dict, args[0], args[1] ): properties[args[0]] = args[1] else: utils.err( "invalid value of property: '{0}', (use --force to " "override)".format(arg), False ) failed = True except utils.UnknownPropertyException: utils.err( "unknown cluster property: '{0}', (use --force to " "override)".format(args[0]), False ) failed = True if failed: sys.exit(1) if nodes_attr: for prop, value in properties.items(): utils.set_node_attribute(prop, value, utils.pcs_options["--node"]) else: cib_dom = utils.get_cib_dom() for prop, value in properties.items(): utils.set_cib_property(prop, value, cib_dom) utils.replace_cib_configuration(cib_dom)
def unset_property(argv): if len(argv) < 1: usage.property() sys.exit(1) if "--node" in utils.pcs_options: for arg in argv: utils.set_node_attribute(arg, "",utils.pcs_options["--node"]) else: cib_dom = utils.get_cib_dom() for arg in argv: utils.set_cib_property(arg, "", cib_dom) utils.replace_cib_configuration(cib_dom)
def print_node_utilization(filter_node=None, filter_name=None): cib = utils.get_cib_dom() utilization = {} for node_el in cib.getElementsByTagName("node"): node = node_el.getAttribute("uname") if filter_node is not None and node != filter_node: continue u = utils.get_utilization_str(node_el, filter_name) if u: utilization[node] = u print("Node Utilization:") for node in sorted(utilization): print(" {0}: {1}".format(node, utilization[node]))
def unset_property(lib, argv, modifiers): """ Options: * --force - no error when removing not existing properties * -f - CIB file """ modifiers.ensure_only_supported("--force", "-f") if len(argv) < 1: raise CmdLineInputError() cib_dom = utils.get_cib_dom() for arg in argv: utils.set_cib_property(arg, "", cib_dom) utils.replace_cib_configuration(cib_dom)
def acl_show(argv): dom = utils.get_cib_dom() properties = prop.get_set_properties(defaults=prop.get_default_properties()) acl_enabled = properties.get("enable-acl", "").lower() if is_true(acl_enabled): print("ACLs are enabled") else: print("ACLs are disabled, run 'pcs acl enable' to enable") print() print_targets(dom) print_groups(dom) print_roles(dom)
def unset_property(lib, argv, modifiers): """ Options: * --force - no error when removing not existing properties * -f - CIB file """ del lib modifiers.ensure_only_supported("--force", "-f") if not argv: raise CmdLineInputError() cib_dom = utils.get_cib_dom() for arg in argv: utils.set_cib_property(arg, "", cib_dom) utils.replace_cib_configuration(cib_dom)
def run_permission_delete(argv): dom = utils.get_cib_dom() if len(argv) < 1: usage.acl(["permission delete"]) sys.exit(1) perm_id = argv.pop(0) found = False for elem in dom.getElementsByTagName("acl_permission"): if elem.getAttribute("id") == perm_id: elem.parentNode.removeChild(elem) found = True if not found: utils.err("Unable to find permission with id: %s" % perm_id) utils.replace_cib_configuration(dom)
def stonith_level_verify(): dom = utils.get_cib_dom() corosync_nodes = [] if utils.hasCorosyncConf(): corosync_nodes = utils.getNodesFromCorosyncConf() pacemaker_nodes = utils.getNodesFromPacemaker() fls = dom.getElementsByTagName("fencing-level") for fl in fls: node = fl.getAttribute("target") devices = fl.getAttribute("devices") for dev in devices.split(","): if not utils.is_stonith_resource(dev): utils.err("%s is not a stonith id" % dev) if node not in corosync_nodes and node not in pacemaker_nodes: utils.err("%s is not currently a node" % node)
def stonith_level_rm(level, node, devices): dom = utils.get_cib_dom() if devices != "": node_devices_combo = node + "," + devices else: node_devices_combo = node ft = dom.getElementsByTagName("fencing-topology") if len(ft) == 0: utils.err("unable to remove fencing level, fencing level for node: %s, at level: %s, with device: %s doesn't exist" % (node,level,devices)) else: ft = ft[0] fls = ft.getElementsByTagName("fencing-level") if node != "": if devices != "": found = False for fl in fls: if fl.getAttribute("target") == node and fl.getAttribute("index") == level and fl.getAttribute("devices") == devices: found = True break if fl.getAttribute("index") == level and fl.getAttribute("devices") == node_devices_combo: found = True break if found == False: utils.err("unable to remove fencing level, fencing level for node: %s, at level: %s, with device: %s doesn't exist" % (node,level,devices)) fl.parentNode.removeChild(fl) else: for fl in fls: if fl.getAttribute("index") == level and (fl.getAttribute("target") == node or fl.getAttribute("devices") == node): fl.parentNode.removeChild(fl) else: for fl in fls: if fl.getAttribute("index") == level: parent = fl.parentNode parent.removeChild(fl) if len(parent.getElementsByTagName("fencing-level")) == 0: parent.parentNode.removeChild(parent) break utils.replace_cib_configuration(dom)
def set_node_utilization(node, argv): """ Commandline options: * -f - CIB file """ nvpair_dict = prepare_options(argv) if not nvpair_dict: return only_removing = True for value in nvpair_dict.values(): if value != "": only_removing = False break cib = utils.get_cib_dom() node_el = utils.dom_get_node(cib, node) if node_el is None: if utils.usefile: utils.err("Unable to find a node: {0}".format(node)) for attrs in utils.getNodeAttributesFromPacemaker(): if attrs.name == node and attrs.type == "remote": node_attrs = attrs break else: utils.err("Unable to find a node: {0}".format(node)) nodes_section_list = cib.getElementsByTagName("nodes") if not nodes_section_list: utils.err("Unable to get nodes section of cib") if only_removing: # Do not create new node if we are only removing values from it. return dom = nodes_section_list[0].ownerDocument node_el = dom.createElement("node") node_el.setAttribute("id", node_attrs.id) node_el.setAttribute("type", node_attrs.type) node_el.setAttribute("uname", node_attrs.name) nodes_section_list[0].appendChild(node_el) utils.dom_update_utilization(node_el, nvpair_dict, "nodes-") utils.replace_cib_configuration(cib)
def stonith_level_add(level, node, devices): dom = utils.get_cib_dom() if not re.search(r'^\d+$', level) or re.search(r'^0+$', level): utils.err("invalid level '{0}', use a positive integer".format(level)) level = level.lstrip('0') if "--force" not in utils.pcs_options: for dev in devices.split(","): if not utils.is_stonith_resource(dev): utils.err("%s is not a stonith id (use --force to override)" % dev) corosync_nodes = [] if utils.hasCorosyncConf(): corosync_nodes = utils.getNodesFromCorosyncConf() pacemaker_nodes = utils.getNodesFromPacemaker() if node not in corosync_nodes and node not in pacemaker_nodes: utils.err("%s is not currently a node (use --force to override)" % node) ft = dom.getElementsByTagName("fencing-topology") if len(ft) == 0: conf = dom.getElementsByTagName("configuration")[0] ft = dom.createElement("fencing-topology") conf.appendChild(ft) else: ft = ft[0] fls = ft.getElementsByTagName("fencing-level") for fl in fls: if fl.getAttribute("target") == node and fl.getAttribute( "index") == level and fl.getAttribute("devices") == devices: utils.err( "unable to add fencing level, fencing level for node: %s, at level: %s, with device: %s already exists" % (node, level, devices)) new_fl = dom.createElement("fencing-level") ft.appendChild(new_fl) new_fl.setAttribute("target", node) new_fl.setAttribute("index", level) new_fl.setAttribute("devices", devices) new_fl.setAttribute("id", utils.find_unique_id(dom, "fl-" + node + "-" + level)) utils.replace_cib_configuration(dom)
def find_constraints_containing(resource_id, passed_dom=None): if passed_dom: dom = passed_dom else: dom = utils.get_cib_dom() constraints_found = [] set_constraints = [] resources = dom.getElementsByTagName("primitive") resource_match = None for res in resources: if res.getAttribute("id") == resource_id: resource_match = res break if resource_match: if resource_match.parentNode.tagName == "master" or resource_match.parentNode.tagName == "clone": constraints_found,set_constraints = find_constraints_containing(resource_match.parentNode.getAttribute("id"), dom) constraints = dom.getElementsByTagName("constraints") if len(constraints) == 0: return [],[] else: constraints = constraints[0] myConstraints = constraints.getElementsByTagName("rsc_colocation") myConstraints += constraints.getElementsByTagName("rsc_location") myConstraints += constraints.getElementsByTagName("rsc_order") myConstraints += constraints.getElementsByTagName("rsc_ticket") attr_to_match = ["rsc", "first", "then", "with-rsc", "first", "then"] for c in myConstraints: for attr in attr_to_match: if c.getAttribute(attr) == resource_id: constraints_found.append(c.getAttribute("id")) break setConstraints = constraints.getElementsByTagName("resource_ref") for c in setConstraints: if c.getAttribute("id") == resource_id: set_constraints.append(c.parentNode.parentNode.getAttribute("id")) # Remove duplicates set_constraints = list(set(set_constraints)) return constraints_found,set_constraints
def run_role_assign(argv): if len(argv) < 2: usage.acl(["role assign"]) sys.exit(1) if len(argv) == 2: role_id = argv[0] ug_id = argv[1] elif len(argv) > 2 and argv[1] == "to": role_id = argv[0] ug_id = argv[2] else: usage.acl(["role assign"]) sys.exit(1) dom = utils.get_cib_dom() found = False for role in dom.getElementsByTagName("acl_role"): if role.getAttribute("id") == role_id: found = True break if not found: utils.err("cannot find role: %s" % role_id) found = False for ug in dom.getElementsByTagName("acl_target") + dom.getElementsByTagName("acl_group"): if ug.getAttribute("id") == ug_id: found = True break if not found: utils.err("cannot find user or group: %s" % ug_id) for current_role in ug.getElementsByTagName("role"): if current_role.getAttribute("id") == role_id: utils.err(role_id + " is already assigned to " + ug_id) new_role = dom.createElement("role") new_role.setAttribute("id", role_id) ug.appendChild(new_role) utils.replace_cib_configuration(dom)
def stonith_level_clear(node = None): dom = utils.get_cib_dom() ft = dom.getElementsByTagName("fencing-topology") if len(ft) == 0: return if node == None: ft = ft[0] childNodes = ft.childNodes[:] for node in childNodes: node.parentNode.removeChild(node) else: fls = dom.getElementsByTagName("fencing-level") if len(fls) == 0: return for fl in fls: if fl.getAttribute("target") == node or fl.getAttribute("devices") == node: fl.parentNode.removeChild(fl) utils.replace_cib_configuration(dom)
def unset_property(lib, argv, modifiers): """ Options: * --force - no error when removing not existing properties * -f - CIB file """ del lib modifiers.ensure_only_supported( "--force", "-f", # The hint is defined to print error messages which point users to the # changes section in pcs manpage. # To be removed in the next significant version. hint_syntax_changed=modifiers.is_specified("--node") ) if not argv: raise CmdLineInputError() cib_dom = utils.get_cib_dom() for arg in argv: utils.set_cib_property(arg, "", cib_dom) utils.replace_cib_configuration(cib_dom)
def stonith_level_clear(node=None): dom = utils.get_cib_dom() ft = dom.getElementsByTagName("fencing-topology") if len(ft) == 0: return if node == None: ft = ft[0] childNodes = ft.childNodes[:] for node in childNodes: node.parentNode.removeChild(node) else: fls = dom.getElementsByTagName("fencing-level") if len(fls) == 0: return for fl in fls: if fl.getAttribute("target") == node or fl.getAttribute( "devices") == node: fl.parentNode.removeChild(fl) utils.replace_cib_configuration(dom)
def constraint_resource_update(old_id, passed_dom=None): dom = utils.get_cib_dom() if passed_dom is None else passed_dom new_id = None clone_ms_parent = utils.dom_get_resource_clone_ms_parent(dom, old_id) if clone_ms_parent: new_id = clone_ms_parent.getAttribute("id") if new_id: constraints = dom.getElementsByTagName("rsc_location") constraints += dom.getElementsByTagName("rsc_order") constraints += dom.getElementsByTagName("rsc_colocation") attrs_to_update = ["rsc", "first", "then", "with-rsc"] for constraint in constraints: for attr in attrs_to_update: if constraint.getAttribute(attr) == old_id: constraint.setAttribute(attr, new_id) if passed_dom is None: utils.replace_cib_configuration(dom) if passed_dom: return dom
def constraint_resource_update(old_id, passed_dom=None): dom = utils.get_cib_dom() if passed_dom is None else passed_dom new_id = None clone_ms_parent = utils.dom_get_resource_clone_ms_parent(dom, old_id) if clone_ms_parent: new_id = clone_ms_parent.getAttribute("id") if new_id: constraints = dom.getElementsByTagName("rsc_location") constraints += dom.getElementsByTagName("rsc_order") constraints += dom.getElementsByTagName("rsc_colocation") attrs_to_update=["rsc","first","then", "with-rsc"] for constraint in constraints: for attr in attrs_to_update: if constraint.getAttribute(attr) == old_id: constraint.setAttribute(attr, new_id) if passed_dom is None: utils.replace_cib_configuration(dom) if passed_dom: return dom
def stonith_level_show(): dom = utils.get_cib_dom() node_levels = {} fls = dom.getElementsByTagName("fencing-level") for fl in fls: node = fl.getAttribute("target") level = fl.getAttribute("index") devices = fl.getAttribute("devices") if node in node_levels: node_levels[node].append((level,devices)) else: node_levels[node] = [(level,devices)] if len(node_levels.keys()) == 0: return nodes = sorted(node_levels.keys()) for node in nodes: print(" Node: " + node) for level in sorted(node_levels[node], key=lambda x: int(x[0])): print(" Level " + level[0] + " - " + level[1])
def stonith_level_show(): dom = utils.get_cib_dom() node_levels = {} fls = dom.getElementsByTagName("fencing-level") for fl in fls: node = fl.getAttribute("target") level = fl.getAttribute("index") devices = fl.getAttribute("devices") if node in node_levels: node_levels[node].append((level, devices)) else: node_levels[node] = [(level, devices)] if len(node_levels.keys()) == 0: return nodes = sorted(node_levels.keys()) for node in nodes: print(" Node: " + node) for level in sorted(node_levels[node], key=lambda x: int(x[0])): print(" Level " + level[0] + " - " + level[1])
def run_role_unassign(argv): if len(argv) < 2: usage.acl(["role unassign"]) sys.exit(1) role_id = argv.pop(0) if len(argv) > 1 and argv[0] == "from": ug_id = argv[1] else: ug_id = argv[0] dom = utils.get_cib_dom() found = False for ug in dom.getElementsByTagName("acl_target") + dom.getElementsByTagName("acl_group"): if ug.getAttribute("id") == ug_id: found = True break if not found: utils.err("cannot find user or group: %s" % ug_id) found = False for current_role in ug.getElementsByTagName("role"): if current_role.getAttribute("id") == role_id: found = True current_role.parentNode.removeChild(current_role) break if not found: utils.err("cannot find role: %s, assigned to user/group: %s" % (role_id, ug_id)) if "--autodelete" in utils.pcs_options: if not ug.getElementsByTagName("role"): ug.parentNode.removeChild(ug) utils.replace_cib_configuration(dom)
def location_add(argv,rm=False): if len(argv) < 4 and (rm == False or len(argv) < 1): usage.constraint() sys.exit(1) constraint_id = argv.pop(0) # If we're removing, we only care about the id if (rm == True): resource_name = "" node = "" score = "" else: id_valid, id_error = utils.validate_xml_id(constraint_id, 'constraint id') if not id_valid: utils.err(id_error) resource_name = argv.pop(0) node = argv.pop(0) score = argv.pop(0) options = [] # For now we only allow setting resource-discovery if len(argv) > 0: for arg in argv: if '=' in arg: options.append(arg.split('=',1)) else: print("Error: bad option '%s'" % arg) usage.constraint(["location add"]) sys.exit(1) if options[-1][0] != "resource-discovery" and "--force" not in utils.pcs_options: utils.err("bad option '%s', use --force to override" % options[-1][0]) resource_valid, resource_error, correct_id \ = utils.validate_constraint_resource( utils.get_cib_dom(), resource_name ) if "--autocorrect" in utils.pcs_options and correct_id: resource_name = correct_id elif not resource_valid: utils.err(resource_error) if not utils.is_score(score): utils.err("invalid score '%s', use integer or INFINITY or -INFINITY" % score) # Verify current constraint doesn't already exist # If it does we replace it with the new constraint (dom,constraintsElement) = getCurrentConstraints() elementsToRemove = [] # If the id matches, or the rsc & node match, then we replace/remove for rsc_loc in constraintsElement.getElementsByTagName('rsc_location'): if (constraint_id == rsc_loc.getAttribute("id")) or \ (rsc_loc.getAttribute("rsc") == resource_name and \ rsc_loc.getAttribute("node") == node and not rm): elementsToRemove.append(rsc_loc) for etr in elementsToRemove: constraintsElement.removeChild(etr) if (rm == True and len(elementsToRemove) == 0): utils.err("resource location id: " + constraint_id + " not found.") if (not rm): element = dom.createElement("rsc_location") element.setAttribute("id",constraint_id) element.setAttribute("rsc",resource_name) element.setAttribute("node",node) element.setAttribute("score",score) for option in options: element.setAttribute(option[0], option[1]) constraintsElement.appendChild(element) utils.replace_cib_configuration(dom)
def location_add(argv, rm=False): if rm: location_remove(argv) return if len(argv) < 4: usage.constraint(["location add"]) sys.exit(1) constraint_id = argv.pop(0) rsc_type, rsc_value = parse_args.parse_typed_arg( argv.pop(0), [RESOURCE_TYPE_RESOURCE, RESOURCE_TYPE_REGEXP], RESOURCE_TYPE_RESOURCE) node = argv.pop(0) score = argv.pop(0) options = [] # For now we only allow setting resource-discovery if len(argv) > 0: for arg in argv: if '=' in arg: options.append(arg.split('=', 1)) else: print("Error: bad option '%s'" % arg) usage.constraint(["location add"]) sys.exit(1) if options[-1][ 0] != "resource-discovery" and "--force" not in utils.pcs_options: utils.err("bad option '%s', use --force to override" % options[-1][0]) id_valid, id_error = utils.validate_xml_id(constraint_id, 'constraint id') if not id_valid: utils.err(id_error) if not utils.is_score(score): utils.err("invalid score '%s', use integer or INFINITY or -INFINITY" % score) required_version = None if [x for x in options if x[0] == "resource-discovery"]: required_version = 2, 2, 0 if rsc_type == RESOURCE_TYPE_REGEXP: required_version = 2, 6, 0 if required_version: dom = utils.cluster_upgrade_to_version(required_version) else: dom = utils.get_cib_dom() if rsc_type == RESOURCE_TYPE_RESOURCE: rsc_valid, rsc_error, correct_id = utils.validate_constraint_resource( dom, rsc_value) if "--autocorrect" in utils.pcs_options and correct_id: rsc_value = correct_id elif not rsc_valid: utils.err(rsc_error) # Verify current constraint doesn't already exist # If it does we replace it with the new constraint dummy_dom, constraintsElement = getCurrentConstraints(dom) elementsToRemove = [] # If the id matches, or the rsc & node match, then we replace/remove for rsc_loc in constraintsElement.getElementsByTagName('rsc_location'): if (rsc_loc.getAttribute("id") == constraint_id or (rsc_loc.getAttribute("node") == node and ((RESOURCE_TYPE_RESOURCE == rsc_type and rsc_loc.getAttribute("rsc") == rsc_value) or (RESOURCE_TYPE_REGEXP == rsc_type and rsc_loc.getAttribute("rsc-pattern") == rsc_value)))): elementsToRemove.append(rsc_loc) for etr in elementsToRemove: constraintsElement.removeChild(etr) element = dom.createElement("rsc_location") element.setAttribute("id", constraint_id) if rsc_type == RESOURCE_TYPE_RESOURCE: element.setAttribute("rsc", rsc_value) elif rsc_type == RESOURCE_TYPE_REGEXP: element.setAttribute("rsc-pattern", rsc_value) element.setAttribute("node", node) element.setAttribute("score", score) for option in options: element.setAttribute(option[0], option[1]) constraintsElement.appendChild(element) utils.replace_cib_configuration(dom)
def status_stonith_check(modifiers): """ Commandline options: * -f - CIB file, to get stonith devices and cluster property stonith-enabled from CIB, to determine whenever we are working with files or cluster """ # pylint: disable=too-many-nested-blocks # We should read the default value from pacemaker. However that may slow # pcs down as we need to run 'pacemaker-schedulerd metadata' to get it. warnings = [] stonith_enabled = True stonith_devices = [] stonith_devices_id_action = [] stonith_devices_id_method_cycle = [] sbd_running = False cib = utils.get_cib_dom() for conf in cib.getElementsByTagName("configuration"): for crm_config in conf.getElementsByTagName("crm_config"): for nvpair in crm_config.getElementsByTagName("nvpair"): if (nvpair.getAttribute("name") == "stonith-enabled" and is_false(nvpair.getAttribute("value"))): stonith_enabled = False break if not stonith_enabled: break for resource_el in conf.getElementsByTagName("primitive"): if resource_el.getAttribute("class") == "stonith": stonith_devices.append(resource_el) for attribs in resource_el.getElementsByTagName( "instance_attributes"): for nvpair in attribs.getElementsByTagName("nvpair"): if (nvpair.getAttribute("name") == "action" and nvpair.getAttribute("value")): stonith_devices_id_action.append( resource_el.getAttribute("id")) if (nvpair.getAttribute("name") == "method" and nvpair.getAttribute("value") == "cycle"): stonith_devices_id_method_cycle.append( resource_el.getAttribute("id")) if not modifiers.is_specified("-f"): # check if SBD daemon is running try: sbd_running = utils.is_service_running(utils.cmd_runner(), get_sbd_service_name()) except LibraryError: pass if stonith_enabled and not stonith_devices and not sbd_running: warnings.append("No stonith devices and stonith-enabled is not false") if stonith_devices_id_action: warnings.append( "Following stonith devices have the 'action' option set, " "it is recommended to set {0} instead: {1}".format( ", ".join( ["'{0}'".format(x) for x in _STONITH_ACTION_REPLACED_BY]), ", ".join(sorted(stonith_devices_id_action)))) if stonith_devices_id_method_cycle: warnings.append( "Following stonith devices have the 'method' option set " "to 'cycle' which is potentially dangerous, please consider using " "'onoff': {0}".format(", ".join( sorted(stonith_devices_id_method_cycle)))) return warnings
def _config_show_cib_lines(lib): """ Commandline options: * -f - CIB file """ # update of pcs_options will change output of constraint show utils.pcs_options["--full"] = 1 # get latest modifiers object after updating pcs_options modifiers = utils.get_input_modifiers() cib_xml = utils.get_cib() cib_etree = utils.get_cib_etree(cib_xml=cib_xml) cib_dom = utils.get_cib_dom(cib_xml=cib_xml) resource_lines = [] stonith_lines = [] for resource_el in cib_etree.find(".//resources"): is_stonith = ("class" in resource_el.attrib and resource_el.attrib["class"] == "stonith") resource_el_lines = resource.resource_node_lines(resource_el) if is_stonith: stonith_lines += resource_el_lines else: resource_lines += resource_el_lines all_lines = [] all_lines.append("Resources:") all_lines.extend(indent(resource_lines, indent_step=1)) all_lines.append("") all_lines.append("Stonith Devices:") all_lines.extend(indent(stonith_lines, indent_step=1)) all_lines.append("Fencing Levels:") levels_lines = stonith.stonith_level_config_to_str( lib.fencing_topology.get_config()) if levels_lines: all_lines.extend(indent(levels_lines, indent_step=2)) all_lines.append("") constraints_element = cib_dom.getElementsByTagName("constraints")[0] all_lines.extend( constraint.location_lines( constraints_element, showDetail=True, show_expired=True, verify_expiration=False, )) all_lines.extend( constraint_command.show( "Ordering Constraints:", lib.constraint_order.show, constraints_reports.order_plain, modifiers.get_subset("-f", "--full"), )) all_lines.extend( constraint_command.show( "Colocation Constraints:", lib.constraint_colocation.show, constraints_reports.colocation_plain, modifiers.get_subset("-f", "--full"), )) all_lines.extend( constraint_command.show( "Ticket Constraints:", lib.constraint_ticket.show, constraints_reports.ticket_plain, modifiers.get_subset("-f", "--full"), )) all_lines.append("") all_lines.extend(alert.alert_config_lines(lib)) all_lines.append("") all_lines.append("Resources Defaults:") all_lines.extend( indent(resource.show_defaults(cib_dom, "rsc_defaults"), indent_step=1)) all_lines.append("Operations Defaults:") all_lines.extend( indent(resource.show_defaults(cib_dom, "op_defaults"), indent_step=1)) all_lines.append("") all_lines.append("Cluster Properties:") properties = utils.get_set_properties() all_lines.extend( indent( [ "{0}: {1}".format(prop, val) for prop, val in sorted(properties.items()) ], indent_step=1, )) all_lines.append("") all_lines.append("Tags:") tags = lib.tag.config([]) if not tags: all_lines.append(" No tags defined") tag_lines = [] for tag in tags: tag_lines.append(tag["tag_id"]) tag_lines.extend(indent(tag["idref_list"])) all_lines.extend(indent(tag_lines, indent_step=1)) return all_lines
def cluster_remote_node(argv): usage_add = """\ remote-node add <hostname> <resource id> [options] Enables the specified resource as a remote-node resource on the specified hostname (hostname should be the same as 'uname -n').""" usage_remove = """\ remote-node remove <hostname> Disables any resources configured to be remote-node resource on the specified hostname (hostname should be the same as 'uname -n').""" if len(argv) < 1: print("\nUsage: pcs cluster remote-node...") print(usage_add) print() print(usage_remove) print() sys.exit(1) command = argv.pop(0) if command == "add": if len(argv) < 2: print("\nUsage: pcs cluster remote-node add...") print(usage_add) print() sys.exit(1) if "--force" in utils.pcs_options: warn( "this command is deprecated, use 'pcs cluster node add-guest'") else: raise error( "this command is deprecated, use 'pcs cluster node add-guest'" ", use --force to override") hostname = argv.pop(0) rsc = argv.pop(0) if not utils.dom_get_resource(utils.get_cib_dom(), rsc): utils.err("unable to find resource '%s'" % rsc) resource.resource_update(rsc, ["meta", "remote-node=" + hostname] + argv, deal_with_guest_change=False) elif command in ["remove", "delete"]: if len(argv) < 1: print("\nUsage: pcs cluster remote-node remove...") print(usage_remove) print() sys.exit(1) if "--force" in utils.pcs_options: warn("this command is deprecated, use" " 'pcs cluster node remove-guest'") else: raise error("this command is deprecated, use 'pcs cluster node" " remove-guest', use --force to override") hostname = argv.pop(0) dom = utils.get_cib_dom() nvpairs = dom.getElementsByTagName("nvpair") nvpairs_to_remove = [] for nvpair in nvpairs: if nvpair.getAttribute( "name") == "remote-node" and nvpair.getAttribute( "value") == hostname: for np in nvpair.parentNode.getElementsByTagName("nvpair"): if np.getAttribute("name").startswith("remote-"): nvpairs_to_remove.append(np) if len(nvpairs_to_remove) == 0: utils.err("unable to remove: cannot find remote-node '%s'" % hostname) for nvpair in nvpairs_to_remove[:]: nvpair.parentNode.removeChild(nvpair) dom = constraint.remove_constraints_containing_node(dom, hostname) utils.replace_cib_configuration(dom) if not utils.usefile: output, retval = utils.run( ["crm_node", "--force", "--remove", hostname]) if retval != 0: utils.err("unable to remove: {0}".format(output)) else: print("\nUsage: pcs cluster remote-node...") print(usage_add) print() print(usage_remove) print() sys.exit(1)
def _config_show_cib_lines(lib): """ Commandline options: * -f - CIB file """ # update of pcs_options will change output of constraint show and # displaying resources and operations defaults utils.pcs_options["--full"] = 1 # get latest modifiers object after updating pcs_options modifiers = utils.get_input_modifiers() cib_dom = utils.get_cib_dom() resources_facade = ResourcesConfigurationFacade.from_resources_dto( lib.resource.get_configured_resources()) all_lines = [] all_lines.append("Resources:") all_lines.extend( smart_wrap_text( indent( resources_to_text(resources_facade.filter_stonith(False)), indent_step=INDENT_STEP, ))) all_lines.append("") all_lines.append("Stonith Devices:") all_lines.extend( smart_wrap_text( indent( resources_to_text(resources_facade.filter_stonith(True)), indent_step=INDENT_STEP, ))) all_lines.append("Fencing Levels:") levels_lines = stonith.stonith_level_config_to_str( lib.fencing_topology.get_config()) if levels_lines: all_lines.extend(indent(levels_lines, indent_step=2)) all_lines.append("") constraints_element = cib_dom.getElementsByTagName("constraints")[0] all_lines.extend( constraint.location_lines( constraints_element, showDetail=True, show_expired=True, verify_expiration=False, )) all_lines.extend( constraint_command.config_cmd( "Ordering Constraints:", lib.constraint_order.config, constraints_reports.order_plain, modifiers.get_subset("-f", "--full"), )) all_lines.extend( constraint_command.config_cmd( "Colocation Constraints:", lib.constraint_colocation.config, constraints_reports.colocation_plain, modifiers.get_subset("-f", "--full"), )) all_lines.extend( constraint_command.config_cmd( "Ticket Constraints:", lib.constraint_ticket.config, constraints_reports.ticket_plain, modifiers.get_subset("-f", "--full"), )) all_lines.append("") all_lines.extend(alert.alert_config_lines(lib)) all_lines.append("") all_lines.append("Resources Defaults:") all_lines.extend( indent( nvset_dto_list_to_lines( lib.cib_options.resource_defaults_config( evaluate_expired=False).meta_attributes, nvset_label="Meta Attrs", with_ids=modifiers.get("--full"), text_if_empty="No defaults set", ))) all_lines.append("Operations Defaults:") all_lines.extend( indent( nvset_dto_list_to_lines( lib.cib_options.operation_defaults_config( evaluate_expired=False).meta_attributes, nvset_label="Meta Attrs", with_ids=modifiers.get("--full"), text_if_empty="No defaults set", ))) all_lines.append("") all_lines.append("Cluster Properties:") properties = utils.get_set_properties() all_lines.extend( indent( [ "{0}: {1}".format(prop, val) for prop, val in sorted(properties.items()) ], indent_step=1, )) all_lines.append("") all_lines.append("Tags:") tags = lib.tag.config([]) if not tags: all_lines.append(" No tags defined") tag_lines = [] for tag in tags: tag_lines.append(tag["tag_id"]) tag_lines.extend(indent(tag["idref_list"])) all_lines.extend(indent(tag_lines, indent_step=1)) return all_lines
def location_add(lib, argv, modifiers): """ Options: * --force - allow unknown options, allow constraint for any resource type * -f - CIB file """ del lib modifiers.ensure_only_supported("--force", "-f") if len(argv) < 4: raise CmdLineInputError() constraint_id = argv.pop(0) rsc_type, rsc_value = parse_args.parse_typed_arg( argv.pop(0), [RESOURCE_TYPE_RESOURCE, RESOURCE_TYPE_REGEXP], RESOURCE_TYPE_RESOURCE) node = argv.pop(0) score = argv.pop(0) options = [] # For now we only allow setting resource-discovery if argv: for arg in argv: if '=' in arg: options.append(arg.split('=', 1)) else: raise CmdLineInputError(f"bad option '{arg}'") if (options[-1][0] != "resource-discovery" and not modifiers.get("--force")): utils.err("bad option '%s', use --force to override" % options[-1][0]) id_valid, id_error = utils.validate_xml_id(constraint_id, 'constraint id') if not id_valid: utils.err(id_error) if not utils.is_score(score): utils.err("invalid score '%s', use integer or INFINITY or -INFINITY" % score) required_version = None if [x for x in options if x[0] == "resource-discovery"]: required_version = 2, 2, 0 if rsc_type == RESOURCE_TYPE_REGEXP: required_version = 2, 6, 0 if required_version: dom = utils.cluster_upgrade_to_version(required_version) else: dom = utils.get_cib_dom() if rsc_type == RESOURCE_TYPE_RESOURCE: rsc_valid, rsc_error, dummy_correct_id = ( utils.validate_constraint_resource(dom, rsc_value)) if not rsc_valid: utils.err(rsc_error) # Verify that specified node exists in the cluster if not (modifiers.is_specified("-f") or modifiers.get("--force")): lib_env = utils.get_lib_env() existing_nodes = get_existing_nodes_names( corosync_conf=lib_env.get_corosync_conf(), cib=lib_env.get_cib(), ) if node not in existing_nodes: raise error(f"Node '{node}' does not seem to be in the cluster" ", use --force to override") else: warn(LOCATION_NODE_VALIDATION_SKIP_MSG) # Verify current constraint doesn't already exist # If it does we replace it with the new constraint dummy_dom, constraintsElement = getCurrentConstraints(dom) elementsToRemove = [] # If the id matches, or the rsc & node match, then we replace/remove for rsc_loc in constraintsElement.getElementsByTagName('rsc_location'): # pylint: disable=too-many-boolean-expressions if (rsc_loc.getAttribute("id") == constraint_id or (rsc_loc.getAttribute("node") == node and ((RESOURCE_TYPE_RESOURCE == rsc_type and rsc_loc.getAttribute("rsc") == rsc_value) or (RESOURCE_TYPE_REGEXP == rsc_type and rsc_loc.getAttribute("rsc-pattern") == rsc_value)))): elementsToRemove.append(rsc_loc) for etr in elementsToRemove: constraintsElement.removeChild(etr) element = dom.createElement("rsc_location") element.setAttribute("id", constraint_id) if rsc_type == RESOURCE_TYPE_RESOURCE: element.setAttribute("rsc", rsc_value) elif rsc_type == RESOURCE_TYPE_REGEXP: element.setAttribute("rsc-pattern", rsc_value) element.setAttribute("node", node) element.setAttribute("score", score) for option in options: element.setAttribute(option[0], option[1]) constraintsElement.appendChild(element) utils.replace_cib_configuration(dom)
def location_rule(lib, argv, modifiers): """ Options: * -f - CIB file * --force - allow constraint on any resource type, allow duplicate constraints """ del lib modifiers.ensure_only_supported("-f", "--force") if len(argv) < 3: usage.constraint(["location", "rule"]) sys.exit(1) rsc_type, rsc_value = parse_args.parse_typed_arg( argv.pop(0), [RESOURCE_TYPE_RESOURCE, RESOURCE_TYPE_REGEXP], RESOURCE_TYPE_RESOURCE) argv.pop(0) # pop "rule" options, rule_argv = rule_utils.parse_argv(argv, { "constraint-id": None, "resource-discovery": None, }) resource_discovery = ("resource-discovery" in options and options["resource-discovery"]) required_version = None if resource_discovery: required_version = 2, 2, 0 if rsc_type == RESOURCE_TYPE_REGEXP: required_version = 2, 6, 0 if required_version: dom = utils.cluster_upgrade_to_version(required_version) else: dom = utils.get_cib_dom() if rsc_type == RESOURCE_TYPE_RESOURCE: rsc_valid, rsc_error, dummy_correct_id = ( utils.validate_constraint_resource(dom, rsc_value)) if not rsc_valid: utils.err(rsc_error) cib, constraints = getCurrentConstraints(dom) lc = cib.createElement("rsc_location") # If resource-discovery is specified, we use it with the rsc_location # element not the rule if resource_discovery: lc.setAttribute("resource-discovery", options.pop("resource-discovery")) constraints.appendChild(lc) if options.get("constraint-id"): id_valid, id_error = utils.validate_xml_id(options["constraint-id"], 'constraint id') if not id_valid: utils.err(id_error) if utils.does_id_exist(dom, options["constraint-id"]): utils.err("id '%s' is already in use, please specify another one" % options["constraint-id"]) lc.setAttribute("id", options["constraint-id"]) del options["constraint-id"] else: lc.setAttribute( "id", utils.find_unique_id(dom, sanitize_id("location-" + rsc_value))) if rsc_type == RESOURCE_TYPE_RESOURCE: lc.setAttribute("rsc", rsc_value) elif rsc_type == RESOURCE_TYPE_REGEXP: lc.setAttribute("rsc-pattern", rsc_value) rule_utils.dom_rule_add(lc, options, rule_argv) location_rule_check_duplicates(constraints, lc, modifiers.get("--force")) utils.replace_cib_configuration(cib)
def order_add(argv, modifiers): """ Commandline options: * -f - CIB file * --force - allow constraint for any resource, allow duplicate constraints """ if len(argv) < 2: raise CmdLineInputError() resource1 = argv.pop(0) resource2 = argv.pop(0) cib_dom = utils.get_cib_dom() resource_valid, resource_error, dummy_correct_id \ = utils.validate_constraint_resource(cib_dom, resource1) if not resource_valid: utils.err(resource_error) resource_valid, resource_error, dummy_correct_id \ = utils.validate_constraint_resource(cib_dom, resource2) if not resource_valid: utils.err(resource_error) order_options = [] id_specified = False sym = None for arg in argv: if arg == "symmetrical": sym = "true" elif arg == "nonsymmetrical": sym = "false" elif "=" in arg: name, value = arg.split("=", 1) if name == "id": id_valid, id_error = utils.validate_xml_id( value, 'constraint id') if not id_valid: utils.err(id_error) if utils.does_id_exist(cib_dom, value): utils.err( "id '%s' is already in use, please specify another one" % value) id_specified = True order_options.append((name, value)) elif name == "symmetrical": if value.lower() in OPTIONS_SYMMETRICAL: sym = value.lower() else: utils.err( "invalid symmetrical value '%s', allowed values are: %s" % (value, ", ".join(OPTIONS_SYMMETRICAL))) else: order_options.append((name, value)) if sym: order_options.append(("symmetrical", sym)) options = "" if order_options: options = " (Options: %s)" % " ".join([ "%s=%s" % (name, value) for name, value in order_options if name not in ("kind", "score") ]) scorekind = "kind: Mandatory" id_suffix = "mandatory" for opt in order_options: if opt[0] == "score": scorekind = "score: " + opt[1] id_suffix = opt[1] break if opt[0] == "kind": scorekind = "kind: " + opt[1] id_suffix = opt[1] break if not id_specified: order_id = "order-" + resource1 + "-" + resource2 + "-" + id_suffix order_id = utils.find_unique_id(cib_dom, order_id) order_options.append(("id", order_id)) (dom, constraintsElement) = getCurrentConstraints() element = dom.createElement("rsc_order") element.setAttribute("first", resource1) element.setAttribute("then", resource2) for order_opt in order_options: element.setAttribute(order_opt[0], order_opt[1]) constraintsElement.appendChild(element) if not modifiers.get("--force"): duplicates = order_find_duplicates(constraintsElement, element) if duplicates: utils.err( "duplicate constraint already exists, use --force to override\n" + "\n".join([ " " + constraint_order.console_report.constraint_plain( {"options": dict(dup.attributes.items())}, True) for dup in duplicates ])) print("Adding " + resource1 + " " + resource2 + " (" + scorekind + ")" + options) utils.replace_cib_configuration(dom)
def colocation_add(argv): if len(argv) < 2: usage.constraint() sys.exit(1) role1 = "" role2 = "" if len(argv) > 2: if not utils.is_score_or_opt(argv[2]): if argv[2] == "with": role1 = argv.pop(0).lower().capitalize() resource1 = argv.pop(0) else: resource1 = argv.pop(0) argv.pop(0) # Pop 'with' if len(argv) == 1: resource2 = argv.pop(0) else: if utils.is_score_or_opt(argv[1]): resource2 = argv.pop(0) else: role2 = argv.pop(0).lower().capitalize() resource2 = argv.pop(0) else: resource1 = argv.pop(0) resource2 = argv.pop(0) else: resource1 = argv.pop(0) resource2 = argv.pop(0) cib_dom = utils.get_cib_dom() resource_valid, resource_error, correct_id \ = utils.validate_constraint_resource(cib_dom, resource1) if "--autocorrect" in utils.pcs_options and correct_id: resource1 = correct_id elif not resource_valid: utils.err(resource_error) resource_valid, resource_error, correct_id \ = utils.validate_constraint_resource(cib_dom, resource2) if "--autocorrect" in utils.pcs_options and correct_id: resource2 = correct_id elif not resource_valid: utils.err(resource_error) score,nv_pairs = parse_score_options(argv) id_in_nvpairs = None for name, value in nv_pairs: if name == "id": id_valid, id_error = utils.validate_xml_id(value, 'constraint id') if not id_valid: utils.err(id_error) if utils.does_id_exist(cib_dom, value): utils.err( "id '%s' is already in use, please specify another one" % value ) id_in_nvpairs = True if not id_in_nvpairs: nv_pairs.append(( "id", utils.find_unique_id( cib_dom, "colocation-%s-%s-%s" % (resource1, resource2, score) ) )) (dom,constraintsElement) = getCurrentConstraints(cib_dom) # If one role is specified, the other should default to "started" if role1 != "" and role2 == "": role2 = DEFAULT_ROLE if role2 != "" and role1 == "": role1 = DEFAULT_ROLE element = dom.createElement("rsc_colocation") element.setAttribute("rsc",resource1) element.setAttribute("with-rsc",resource2) element.setAttribute("score",score) if role1 != "": element.setAttribute("rsc-role", role1) if role2 != "": element.setAttribute("with-rsc-role", role2) for nv_pair in nv_pairs: element.setAttribute(nv_pair[0], nv_pair[1]) if "--force" not in utils.pcs_options: duplicates = colocation_find_duplicates(constraintsElement, element) if duplicates: utils.err( "duplicate constraint already exists, use --force to override\n" + "\n".join([ " " + constraint_colocation.console_report.constraint_plain( {"options": dict(dup.attributes.items())}, True ) for dup in duplicates ]) ) constraintsElement.appendChild(element) utils.replace_cib_configuration(dom)
def constraint_rule(lib, argv, modifiers): """ Options: * -f - CIB file * --force - allow duplicate constraints, only for add command NOTE: modifiers check is in subcommand """ del lib if len(argv) < 2: raise CmdLineInputError() found = False command = argv.pop(0) constraint_id = None if command == "add": modifiers.ensure_only_supported("-f", "--force") constraint_id = argv.pop(0) cib = utils.get_cib_dom() constraint = utils.dom_get_element_with_id( cib.getElementsByTagName("constraints")[0], "rsc_location", constraint_id) if not constraint: utils.err("Unable to find constraint: " + constraint_id) options, rule_argv = rule_utils.parse_argv(argv) rule_utils.dom_rule_add(constraint, options, rule_argv) location_rule_check_duplicates(cib, constraint, modifiers.get("--force")) utils.replace_cib_configuration(cib) elif command in ["remove", "delete"]: modifiers.ensure_only_supported("-f") cib = utils.get_cib_etree() temp_id = argv.pop(0) constraints = cib.find('.//constraints') loc_cons = cib.findall(str('.//rsc_location')) for loc_con in loc_cons: for rule in loc_con: if rule.get("id") == temp_id: if len(loc_con) > 1: print("Removing Rule: {0}".format(rule.get("id"))) loc_con.remove(rule) found = True break else: print("Removing Constraint: {0}".format( loc_con.get("id"))) constraints.remove(loc_con) found = True break if found: break if found: utils.replace_cib_configuration(cib) else: utils.err("unable to find rule with id: %s" % temp_id) else: raise CmdLineInputError()
def order_add(argv,returnElementOnly=False): if len(argv) < 2: usage.constraint() sys.exit(1) resource1 = argv.pop(0) resource2 = argv.pop(0) cib_dom = utils.get_cib_dom() resource_valid, resource_error, correct_id \ = utils.validate_constraint_resource(cib_dom, resource1) if "--autocorrect" in utils.pcs_options and correct_id: resource1 = correct_id elif not resource_valid: utils.err(resource_error) resource_valid, resource_error, correct_id \ = utils.validate_constraint_resource(cib_dom, resource2) if "--autocorrect" in utils.pcs_options and correct_id: resource2 = correct_id elif not resource_valid: utils.err(resource_error) order_options = [] id_specified = False sym = None for arg in argv: if arg == "symmetrical": sym = "true" elif arg == "nonsymmetrical": sym = "false" elif "=" in arg: name, value = arg.split("=", 1) if name == "id": id_valid, id_error = utils.validate_xml_id(value, 'constraint id') if not id_valid: utils.err(id_error) if utils.does_id_exist(cib_dom, value): utils.err( "id '%s' is already in use, please specify another one" % value ) id_specified = True order_options.append((name, value)) elif name == "symmetrical": if value.lower() in OPTIONS_SYMMETRICAL: sym = value.lower() else: utils.err( "invalid symmetrical value '%s', allowed values are: %s" % (value, ", ".join(OPTIONS_SYMMETRICAL)) ) else: order_options.append((name, value)) if sym: order_options.append(("symmetrical", sym)) options = "" if order_options: options = " (Options: %s)" % " ".join([ "%s=%s" % (name, value) for name, value in order_options if name not in ("kind", "score") ]) scorekind = "kind: Mandatory" id_suffix = "mandatory" for opt in order_options: if opt[0] == "score": scorekind = "score: " + opt[1] id_suffix = opt[1] break if opt[0] == "kind": scorekind = "kind: " + opt[1] id_suffix = opt[1] break if not id_specified: order_id = "order-" + resource1 + "-" + resource2 + "-" + id_suffix order_id = utils.find_unique_id(cib_dom, order_id) order_options.append(("id", order_id)) (dom,constraintsElement) = getCurrentConstraints() element = dom.createElement("rsc_order") element.setAttribute("first",resource1) element.setAttribute("then",resource2) for order_opt in order_options: element.setAttribute(order_opt[0], order_opt[1]) constraintsElement.appendChild(element) if "--force" not in utils.pcs_options: duplicates = order_find_duplicates(constraintsElement, element) if duplicates: utils.err( "duplicate constraint already exists, use --force to override\n" + "\n".join([ " " + constraint_order.console_report.constraint_plain( {"options": dict(dup.attributes.items())}, True ) for dup in duplicates ]) ) print( "Adding " + resource1 + " " + resource2 + " ("+scorekind+")" + options ) if returnElementOnly == False: utils.replace_cib_configuration(dom) else: return element.toxml()
def acl_target(argv,group=False): if len(argv) < 2: if group: usage.acl(["group"]) sys.exit(1) else: usage.acl(["user"]) sys.exit(1) dom = utils.get_cib_dom() acls = utils.get_acls(dom) command = argv.pop(0) tug_id = argv.pop(0) if command == "create": # pcsd parses the error message in order to determine whether the id is # assigned to user/group or some other cib element if group and utils.dom_get_element_with_id(dom, "acl_group", tug_id): utils.err("group %s already exists" % tug_id) if not group and utils.dom_get_element_with_id(dom, "acl_target", tug_id): utils.err("user %s already exists" % tug_id) if utils.does_id_exist(dom,tug_id): utils.err(tug_id + " already exists") if group: element = dom.createElement("acl_group") else: element = dom.createElement("acl_target") element.setAttribute("id", tug_id) acls.appendChild(element) for role in argv: if not utils.dom_get_element_with_id(acls, "acl_role", role): utils.err("cannot find acl role: %s" % role) r = dom.createElement("role") r.setAttribute("id", role) element.appendChild(r) utils.replace_cib_configuration(dom) elif command == "delete": found = False if group: elist = dom.getElementsByTagName("acl_group") else: elist = dom.getElementsByTagName("acl_target") for elem in elist: if elem.getAttribute("id") == tug_id: found = True elem.parentNode.removeChild(elem) break if not found: if group: utils.err("unable to find acl group: %s" % tug_id) else: utils.err("unable to find acl target/user: %s" % tug_id) utils.replace_cib_configuration(dom) else: if group: usage.acl(["group"]) else: usage.acl(["user"]) sys.exit(1)
def colocation_add(lib, argv, modifiers): """ Options: * -f - CIB file * --force - allow constraint on any resource, allow duplicate constraints """ del lib modifiers.ensure_only_supported("-f", "--force") if len(argv) < 3: raise CmdLineInputError() role1 = "" role2 = "" if argv[2] == "with": role1 = argv.pop(0).lower().capitalize() resource1 = argv.pop(0) elif argv[1] == "with": resource1 = argv.pop(0) else: raise CmdLineInputError() argv.pop(0) # Pop 'with' if not argv: raise CmdLineInputError() elif len(argv) == 1: resource2 = argv.pop(0) else: if utils.is_score_or_opt(argv[1]): resource2 = argv.pop(0) else: role2 = argv.pop(0).lower().capitalize() resource2 = argv.pop(0) score, nv_pairs = parse_score_options(argv) cib_dom = utils.get_cib_dom() resource_valid, resource_error, dummy_correct_id \ = utils.validate_constraint_resource(cib_dom, resource1) if not resource_valid: utils.err(resource_error) resource_valid, resource_error, dummy_correct_id \ = utils.validate_constraint_resource(cib_dom, resource2) if not resource_valid: utils.err(resource_error) id_in_nvpairs = None for name, value in nv_pairs: if name == "id": id_valid, id_error = utils.validate_xml_id(value, 'constraint id') if not id_valid: utils.err(id_error) if utils.does_id_exist(cib_dom, value): utils.err( "id '%s' is already in use, please specify another one" % value) id_in_nvpairs = True if not id_in_nvpairs: nv_pairs.append( ("id", utils.find_unique_id( cib_dom, "colocation-%s-%s-%s" % (resource1, resource2, score)))) (dom, constraintsElement) = getCurrentConstraints(cib_dom) # If one role is specified, the other should default to "started" if role1 != "" and role2 == "": role2 = DEFAULT_ROLE if role2 != "" and role1 == "": role1 = DEFAULT_ROLE element = dom.createElement("rsc_colocation") element.setAttribute("rsc", resource1) element.setAttribute("with-rsc", resource2) element.setAttribute("score", score) if role1 != "": element.setAttribute("rsc-role", role1) if role2 != "": element.setAttribute("with-rsc-role", role2) for nv_pair in nv_pairs: element.setAttribute(nv_pair[0], nv_pair[1]) if not modifiers.get("--force"): duplicates = colocation_find_duplicates(constraintsElement, element) if duplicates: utils.err( "duplicate constraint already exists, use --force to override\n" + "\n".join([ " " + constraint_colocation.console_report.constraint_plain( {"options": dict(dup.attributes.items())}, True) for dup in duplicates ])) constraintsElement.appendChild(element) utils.replace_cib_configuration(dom)
def colocation_add(lib, argv, modifiers): """ Options: * -f - CIB file * --force - allow constraint on any resource, allow duplicate constraints """ def _parse_score_options(argv): # When passed an array of arguments if the first argument doesn't have # an '=' then it's the score, otherwise they're all arguments. Return a # tuple with the score and array of name,value pairs """ Commandline options: no options """ if not argv: return SCORE_INFINITY, [] score = SCORE_INFINITY if "=" in argv[0] else argv.pop(0) # create a list of 2-tuples (name, value) arg_array = [ parse_args.split_option(arg, allow_empty_value=False) for arg in argv ] return score, arg_array def _validate_and_prepare_role(role): role_cleaned = role.lower().capitalize() if role_cleaned not in RESOURCE_ROLES: utils.err( "invalid role value '{0}', allowed values are: '{1}'".format( role, "', '".join(RESOURCE_ROLES))) return role_cleaned del lib modifiers.ensure_only_supported("-f", "--force") if len(argv) < 3: raise CmdLineInputError() role1 = "" role2 = "" if argv[2] == "with": role1 = _validate_and_prepare_role(argv.pop(0)) resource1 = argv.pop(0) elif argv[1] == "with": resource1 = argv.pop(0) else: raise CmdLineInputError() if argv.pop(0) != "with": raise CmdLineInputError() if "with" in argv: raise CmdLineInputError( message="Multiple 'with's cannot be specified.", hint=( "Use the 'pcs constraint colocation set' command if you want " "to create a constraint for more than two resources."), show_both_usage_and_message=True) if not argv: raise CmdLineInputError() if len(argv) == 1: resource2 = argv.pop(0) else: if utils.is_score_or_opt(argv[1]): resource2 = argv.pop(0) else: role2 = _validate_and_prepare_role(argv.pop(0)) resource2 = argv.pop(0) score, nv_pairs = _parse_score_options(argv) cib_dom = utils.get_cib_dom() _validate_constraint_resource(cib_dom, resource1) _validate_constraint_resource(cib_dom, resource2) id_in_nvpairs = None for name, value in nv_pairs: if name == "id": id_valid, id_error = utils.validate_xml_id(value, 'constraint id') if not id_valid: utils.err(id_error) if utils.does_id_exist(cib_dom, value): utils.err( "id '%s' is already in use, please specify another one" % value) id_in_nvpairs = True if not id_in_nvpairs: nv_pairs.append( ("id", utils.find_unique_id( cib_dom, "colocation-%s-%s-%s" % (resource1, resource2, score)))) (dom, constraintsElement) = getCurrentConstraints(cib_dom) # If one role is specified, the other should default to "started" if role1 != "" and role2 == "": role2 = DEFAULT_ROLE if role2 != "" and role1 == "": role1 = DEFAULT_ROLE element = dom.createElement("rsc_colocation") element.setAttribute("rsc", resource1) element.setAttribute("with-rsc", resource2) element.setAttribute("score", score) if role1 != "": element.setAttribute("rsc-role", role1) if role2 != "": element.setAttribute("with-rsc-role", role2) for nv_pair in nv_pairs: element.setAttribute(nv_pair[0], nv_pair[1]) if not modifiers.get("--force"): duplicates = colocation_find_duplicates(constraintsElement, element) if duplicates: utils.err( "duplicate constraint already exists, use --force to override\n" + "\n".join([ " " + constraint_colocation.console_report.constraint_plain( {"options": dict(dup.attributes.items())}, True) for dup in duplicates ])) constraintsElement.appendChild(element) utils.replace_cib_configuration(dom)