def process_library_reports(report_item_list): """ report_item_list list of ReportItem """ if not report_item_list: raise error( "Errors have occurred, therefore pcs is unable to continue") critical_error = False for report_item in report_item_list: if report_item.severity == ReportItemSeverity.WARNING: warn(build_report_message(report_item)) continue if report_item.severity != ReportItemSeverity.ERROR: print(build_report_message(report_item)) continue error( build_report_message(report_item, _prepare_force_text(report_item))) critical_error = True if critical_error: sys.exit(1)
def apply(next_in_line, env, *args, **kwargs): if filename: touch_cib_file(filename) try: with open(filename, mode="r") as cib_file: original_content = cib_file.read() except EnvironmentError as e: raise error( "Cannot read cib file '{0}': '{1}'" .format(filename, str(e)) ) env.cib_data = original_content result_of_next = next_in_line(env, *args, **kwargs) if filename and env.cib_data != original_content: try: with open(filename, mode="w") as cib_file: cib_file.write(env.cib_data) except EnvironmentError as e: raise error( "Cannot write cib file '{0}': '{1}'" .format(filename, str(e)) ) return result_of_next
def stonith_create(lib, argv, modifiers): if modifiers["before"] and modifiers["after"]: raise error("you cannot specify both --before and --after{0}".format( "" if modifiers["group"] else " and you have to specify --group" )) if not modifiers["group"]: if modifiers["before"]: raise error("you cannot use --before without --group") elif modifiers["after"]: raise error("you cannot use --after without --group") if len(argv) < 2: usage.stonith(["create"]) sys.exit(1) stonith_id = argv[0] stonith_type = argv[1] parts = parse_create_args(argv[2:]) settings = dict( allow_absent_agent=modifiers["force"], allow_invalid_operation=modifiers["force"], allow_invalid_instance_attributes=modifiers["force"], ensure_disabled=modifiers["disabled"], use_default_operations=not modifiers["no-default-ops"], wait=modifiers["wait"], ) if not modifiers["group"]: lib.stonith.create( stonith_id, stonith_type, parts["op"], parts["meta"], parts["options"], **settings ) else: adjacent_resource_id = None put_after_adjacent = False if modifiers["after"]: adjacent_resource_id = modifiers["after"] put_after_adjacent = True if modifiers["before"]: adjacent_resource_id = modifiers["before"] put_after_adjacent = False lib.stonith.create_in_group( stonith_id, stonith_type, modifiers["group"], parts["op"], parts["meta"], parts["options"], adjacent_resource_id=adjacent_resource_id, put_after_adjacent=put_after_adjacent, **settings )
def middleware_config(name, config_path, key_path): if config_path and not key_path: raise console_report.error( "With --booth-conf must be specified --booth-key as well") if key_path and not config_path: raise console_report.error( "With --booth-key must be specified --booth-conf as well") is_mocked_environment = config_path and key_path def create_booth_env(): if not is_mocked_environment: return {"name": name} return { "name": name, "config_file": env_file.read(config_path), "key_file": env_file.read(key_path, is_binary=True), "key_path": key_path, } def flush(modified_env): if not is_mocked_environment: return if not modified_env: #TODO now this would not happen #for more information see comment in #pcs.cli.common.lib_wrapper.lib_env_to_cli_env raise console_report.error("Error during library communication") env_file.process_no_existing_file_expectation( "booth config file", modified_env["config_file"], config_path) env_file.process_no_existing_file_expectation("booth key file", modified_env["key_file"], key_path) env_file.write(modified_env["key_file"], key_path) env_file.write(modified_env["config_file"], config_path) def apply(next_in_line, env, *args, **kwargs): env.booth = create_booth_env() try: result_of_next = next_in_line(env, *args, **kwargs) except LibraryEnvError as e: missing_file = env_file.MissingFileCandidateInfo env_file.evaluate_for_missing_files(e, [ missing_file(BOOTH_CONFIG, "Booth config file", config_path), missing_file(BOOTH_KEY, "Booth key file", key_path), ]) raise e flush(env.booth["modified_env"]) return result_of_next return apply
def _do_report(self, report_item: ReportItem) -> None: if report_item.severity == ReportItemSeverity.ERROR: error( build_report_message(report_item, _prepare_force_text(report_item))) elif report_item.severity == ReportItemSeverity.WARNING: warn(build_report_message(report_item)) elif self.debug or report_item.severity != ReportItemSeverity.DEBUG: msg = build_report_message(report_item) if msg: print(msg)
def _send(self, report_item_list, print_errors=True): errors = [] for report_item in report_item_list: if report_item.severity == ReportItemSeverity.ERROR: if print_errors: error(build_report_message(report_item)) errors.append(report_item) elif report_item.severity == ReportItemSeverity.WARNING: warn(build_report_message(report_item)) elif self.debug or report_item.severity != ReportItemSeverity.DEBUG: print(build_report_message(report_item)) return errors
def status( lib: Any, argv: Sequence[str], modifiers: InputModifiers, ) -> None: """ Options: * --full - show full details, node attributes and failcount * --hide-inactive - hide inactive resources * --request-timeout - HTTP timeout for node authorization check """ modifiers.ensure_only_supported( "--full", "--hide-inactive", "--request-timeout", ) if argv: raise CmdLineInputError() status_list_raw = lib.dr.status_all_sites_plaintext( hide_inactive_resources=modifiers.get("--hide-inactive"), verbose=modifiers.get("--full"), ) try: status_list = [ dto.from_dict(DrSiteStatusDto, status_raw) for status_raw in status_list_raw ] except (KeyError, TypeError, ValueError): raise error("Unable to communicate with pcsd, received response:\n" f"{status_list_raw}") has_errors = False plaintext_parts = [] for site_status in status_list: plaintext_parts.append( "--- {local_remote} cluster - {role} site ---".format( local_remote=("Local" if site_status.local_site else "Remote"), role=site_status.site_role.capitalize())) if site_status.status_successfully_obtained: plaintext_parts.append(site_status.status_plaintext.strip()) plaintext_parts.extend(["", ""]) else: has_errors = True plaintext_parts.extend([ "Error: Unable to get status of the cluster from any node", "" ]) print("\n".join(plaintext_parts).strip()) if has_errors: raise error("Unable to get status of all sites")
def process_library_reports(report_item_list): """ report_item_list list of ReportItem """ if not report_item_list: raise error("Errors have occurred, therefore pcs is unable to continue") critical_error = False for report_item in report_item_list: if report_item.severity == ReportItemSeverity.WARNING: print("Warning: " + build_report_message(report_item)) continue if report_item.severity != ReportItemSeverity.ERROR: print(build_report_message(report_item)) continue sys.stderr.write('Error: {0}\n'.format(build_report_message( report_item, _prepare_force_text(report_item) ))) critical_error = True if critical_error: sys.exit(1)
def flush(modified_env): if not is_mocked_environment: return if not modified_env: #TODO now this would not happen #for more information see comment in #pcs.cli.common.lib_wrapper.lib_env_to_cli_env raise console_report.error("Error during library communication") try: key_file.write( modified_env["key_file"]["content"], can_overwrite=True ) config_file.write( modified_env["config_file"]["content"], can_overwrite=True ) # TODO write custom error handling, do not use pcs.lib specific code # and LibraryError except pcs_file.RawFileError as e: raise LibraryError( reports.file_io_error( e.metadata.file_type_code, e.action, e.reason, file_path=e.metadata.path, ) )
def process_no_existing_file_expectation(file_role, env_file, file_path): if (env_file["no_existing_file_expected"] and os.path.exists(file_path)): msg = "{0} {1} already exists".format(file_role, file_path) if not env_file["can_overwrite_existing_file"]: raise console_report.error( "{0}, use --force to override".format(msg)) console_report.warn(msg)
def _send(self, report_item_list, print_errors=True): errors = [] for report_item in report_item_list: if report_item.severity == ReportItemSeverity.ERROR: if print_errors: error(build_report_message( report_item, _prepare_force_text(report_item) )) errors.append(report_item) elif report_item.severity == ReportItemSeverity.WARNING: warn(build_report_message(report_item)) elif self.debug or report_item.severity != ReportItemSeverity.DEBUG: msg = build_report_message(report_item) if msg: print(msg) return errors
def apply(next_in_line, env, *args, **kwargs): if local_file_path: try: env.cluster_conf_data = open(local_file_path).read() except EnvironmentError as e: raise console_report.error("Unable to read {0}: {1}".format(local_file_path, e.strerror)) return next_in_line(env, *args, **kwargs)
def write(env_file, file_path): try: f = open(file_path, "wb" if env_file.get("is_binary", False) else "w") f.write(env_file["content"]) f.close() except EnvironmentError as e: raise console_report.error("Unable to write {0}: {1}".format( file_path, e.strerror))
def apply(next_in_line, env, *args, **kwargs): if local_file_path: try: env.corosync_conf_data = open(local_file_path).read() except EnvironmentError as e: raise console_report.error("Unable to read {0}: {1}".format(local_file_path, e.strerror)) result_of_next = next_in_line(env, *args, **kwargs) if local_file_path: try: f = open(local_file_path, "w") f.write(env.corosync_conf_data) f.close() except EnvironmentError as e: raise console_report.error("Unable to write {0}: {1}".format(local_file_path, e.strerror)) return result_of_next
def read_env_file(path): try: return { "content": open(path).read() if os.path.isfile(path) else None } except EnvironmentError as e: raise console_report.error( "Unable to read {0}: {1}".format(path, e.strerror) )
def write_env_file(env_file, file_path): try: f = open(file_path, "wb" if env_file.get("is_binary", False) else "w") f.write(env_file["content"]) f.close() except EnvironmentError as e: raise console_report.error( "Unable to write {0}: {1}".format(file_path, e.strerror) )
def apply(next_in_line, env, *args, **kwargs): if local_file_path: try: env.cluster_conf_data = open(local_file_path).read() except EnvironmentError as e: raise error("Unable to read {0}: {1}".format( local_file_path, e.strerror)) return next_in_line(env, *args, **kwargs)
def apply(next_in_line, env, *args, **kwargs): if local_file_path: try: env.corosync_conf_data = open(local_file_path).read() except EnvironmentError as e: raise error("Unable to read {0}: {1}".format( local_file_path, e.strerror)) result_of_next = next_in_line(env, *args, **kwargs) if local_file_path: try: f = open(local_file_path, "w") f.write(env.corosync_conf_data) f.close() except EnvironmentError as e: raise error("Unable to write {0}: {1}".format( local_file_path, e.strerror)) return result_of_next
def read(path, is_binary=False): try: mode = "rb" if is_binary else "r" return { "content": open(path, mode).read() if os.path.isfile(path) else None } except EnvironmentError as e: raise console_report.error("Unable to read {0}: {1}".format( path, e.strerror))
def read(path, is_binary=False): try: mode = "rb" if is_binary else "r" return { "content": open(path, mode).read() if os.path.isfile(path) else None } except EnvironmentError as e: raise console_report.error( "Unable to read {0}: {1}".format(path, e.strerror) )
def remove(lib, argv, modifiers): """ Options: * -f - CIB file """ modifiers.ensure_only_supported("-f") if len(argv) != 2: raise CmdLineInputError() ticket, resource_id = argv if not lib.constraint_ticket.remove(ticket, resource_id): raise error("no matching ticket constraint found")
def process_no_existing_file_expectation(file_role, env_file, file_path): if( env_file["no_existing_file_expected"] and os.path.exists(file_path) ): msg = "{0} {1} already exists".format(file_role, file_path) if not env_file["can_overwrite_existing_file"]: raise console_report.error( "{0}, use --force to override".format(msg) ) console_report.warn(msg)
def flush(modified_env): if not is_mocked_environment: return if not modified_env: #TODO now this would not happen #for more information see comment in #pcs.cli.common.lib_wrapper.lib_env_to_cli_env raise console_report.error("Error during library communication") env_file.process_no_existing_file_expectation( "booth config file", modified_env["config_file"], config_path) env_file.process_no_existing_file_expectation("booth key file", modified_env["key_file"], key_path) env_file.write(modified_env["key_file"], key_path) env_file.write(modified_env["config_file"], config_path)
def flush(modified_env): if not is_mocked_environment: return if not modified_env: #TODO now this would not happen #for more information see comment in #pcs.cli.common.lib_wrapper.lib_env_to_cli_env raise console_report.error("Error during library communication") process_no_existing_file_expectation( "booth config file", modified_env["config_file"], config_path ) process_no_existing_file_expectation( "booth key file", modified_env["key_file"], key_path ) write_env_file(modified_env["key_file"], key_path) write_env_file(modified_env["config_file"], config_path)
def get_capabilities_definition(): """ Read and parse capabilities file The point is to return all data in python structures for further processing. """ filename = os.path.join(settings.pcsd_exec_location, "capabilities.xml") try: with open(filename, mode="r") as file_: capabilities_xml = xml_fromstring(file_.read()) except (EnvironmentError, etree.XMLSyntaxError, etree.DocumentInvalid) as e: raise error( "Cannot read capabilities definition file '{0}': '{1}'" .format(filename, str(e)) ) capabilities = [] for feat_xml in capabilities_xml.findall(".//capability"): feat = dict(feat_xml.attrib) desc = feat_xml.find("./description") # dedent and strip remove indentation in the XML file feat["description"] = "" if desc is None else dedent(desc.text).strip() capabilities.append(feat) return capabilities
def get_capabilities_definition(): """ Read and parse capabilities file The point is to return all data in python structures for further processing. """ filename = os.path.join(get_pcsd_dir(), "capabilities.xml") try: with open(filename, mode="r") as file_: capabilities_xml = xml_fromstring(file_.read()) except (EnvironmentError, etree.XMLSyntaxError, etree.DocumentInvalid) as e: raise error( "Cannot read capabilities definition file '{0}': '{1}'".format( filename, str(e))) capabilities = [] for feat_xml in capabilities_xml.findall(".//capability"): feat = dict(feat_xml.attrib) desc = feat_xml.find("./description") # dedent and strip remove indentation in the XML file feat["description"] = "" if desc is None else dedent(desc.text).strip() capabilities.append(feat) return capabilities
def config( lib: Any, argv: Sequence[str], modifiers: InputModifiers, ) -> None: """ Options: None """ modifiers.ensure_only_supported() if argv: raise CmdLineInputError() config_raw = lib.dr.get_config() try: config_dto = dto.from_dict(DrConfigDto, config_raw) except (KeyError, TypeError, ValueError): raise error("Unable to communicate with pcsd, received response:\n" f"{config_raw}") lines = ["Local site:"] lines.extend(indent(_config_site_lines(config_dto.local_site))) for site_dto in config_dto.remote_site_list: lines.append("Remote site:") lines.extend(indent(_config_site_lines(site_dto))) print("\n".join(lines))
def cluster_verify(argv): if len(argv) > 1: usage.cluster("verify") raise SystemExit(1) if argv: filename = argv[0] if not utils.usefile: #We must operate on given cib everywhere. utils.usefile = True utils.filename = filename elif os.path.abspath(filename) == os.path.abspath(utils.filename): warn("File '{0}' specified twice".format( os.path.abspath(filename))) else: raise error( "Ambiguous cib filename specification: '{0}' vs -f '{1}'". format(filename, utils.filename)) lib = utils.get_library_wrapper() try: lib.cluster.verify(verbose="-V" in utils.pcs_options) except LibraryError as e: utils.process_library_reports(e.args)
def report_missing_file(file_role, file_path): console_report.error( "{0} '{1}' does not exist".format(file_role, file_path) )
def middleware_config(config_path, key_path): if config_path and not key_path: raise console_report.error( "When --booth-conf is specified, " "--booth-key must be specified as well" ) if key_path and not config_path: raise console_report.error( "When --booth-key is specified, " "--booth-conf must be specified as well" ) is_mocked_environment = config_path and key_path if is_mocked_environment: config_file = pcs_file.RawFile( metadata.for_file_type( file_type_codes.BOOTH_CONFIG, config_path ) ) key_file = pcs_file.RawFile( metadata.for_file_type( file_type_codes.BOOTH_KEY, key_path ) ) def create_booth_env(): try: config_data = config_file.read() if config_file.exists() else None key_data = key_file.read() if key_file.exists() else None # TODO write custom error handling, do not use pcs.lib specific code # and LibraryError except pcs_file.RawFileError as e: raise LibraryError( reports.file_io_error( e.metadata.file_type_code, e.action, e.reason, file_path=e.metadata.path, ) ) return { "config_data": config_data, "key_data": key_data, "key_path": key_path, } def flush(modified_env): if not is_mocked_environment: return if not modified_env: #TODO now this would not happen #for more information see comment in #pcs.cli.common.lib_wrapper.lib_env_to_cli_env raise console_report.error("Error during library communication") try: key_file.write( modified_env["key_file"]["content"], can_overwrite=True ) config_file.write( modified_env["config_file"]["content"], can_overwrite=True ) # TODO write custom error handling, do not use pcs.lib specific code # and LibraryError except pcs_file.RawFileError as e: raise LibraryError( reports.file_io_error( e.metadata.file_type_code, e.action, e.reason, file_path=e.metadata.path, ) ) def apply(next_in_line, env, *args, **kwargs): env.booth = create_booth_env() if is_mocked_environment else {} result_of_next = next_in_line(env, *args, **kwargs) if is_mocked_environment: flush(env.booth["modified_env"]) return result_of_next return apply
def remove(lib, argv, modificators): if len(argv) != 2: raise CmdLineInputError() ticket, resource_id = argv if not lib.constraint_ticket.remove(ticket, resource_id): raise error("no matching ticket constraint found")
def middleware_config(name, config_path, key_path): if config_path and not key_path: raise console_report.error( "With --booth-conf must be specified --booth-key as well" ) if key_path and not config_path: raise console_report.error( "With --booth-key must be specified --booth-conf as well" ) is_mocked_environment = config_path and key_path def create_booth_env(): if not is_mocked_environment: return {"name": name} return { "name": name, "config_file": env_file.read(config_path), "key_file": env_file.read(key_path, is_binary=True), "key_path": key_path, } def flush(modified_env): if not is_mocked_environment: return if not modified_env: #TODO now this would not happen #for more information see comment in #pcs.cli.common.lib_wrapper.lib_env_to_cli_env raise console_report.error("Error during library communication") env_file.process_no_existing_file_expectation( "booth config file", modified_env["config_file"], config_path ) env_file.process_no_existing_file_expectation( "booth key file", modified_env["key_file"], key_path ) env_file.write(modified_env["key_file"], key_path) env_file.write(modified_env["config_file"], config_path) def apply(next_in_line, env, *args, **kwargs): env.booth = create_booth_env() try: result_of_next = next_in_line(env, *args, **kwargs) except LibraryEnvError as err: missing_file = env_file.MissingFileCandidateInfo env_file.evaluate_for_missing_files(err, [ missing_file(BOOTH_CONFIG, "Booth config file", config_path), missing_file(BOOTH_KEY, "Booth key file", key_path), ]) raise err flush(env.booth["modified_env"]) return result_of_next return apply
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 stonith_create(lib, argv, modifiers): """ Options: * --before - specified resource inside a group before which new resource will be placed inside the group * --after - specified resource inside a group after which new resource will be placed inside the group * --group - specifies group in which resource will be created * --force - allow not existing agent, invalid operations or invalid instance attributes * --disabled - created reource will be disabled * --no-default-ops - do not add default operations * --wait * -f - CIB file """ modifiers.ensure_only_supported( "--before", "--after", "--group", "--force", "--disabled", "--no-default-ops", "--wait", "-f", ) if modifiers.is_specified("--before") and modifiers.is_specified( "--after"): raise error("you cannot specify both --before and --after{0}".format( "" if modifiers. is_specified("--group") else " and you have to specify --group")) if not modifiers.is_specified("--group"): if modifiers.is_specified("--before"): raise error("you cannot use --before without --group") elif modifiers.is_specified("--after"): raise error("you cannot use --after without --group") if len(argv) < 2: raise CmdLineInputError() stonith_id = argv[0] stonith_type = argv[1] parts = parse_create_args(argv[2:]) settings = dict( allow_absent_agent=modifiers.get("--force"), allow_invalid_operation=modifiers.get("--force"), allow_invalid_instance_attributes=modifiers.get("--force"), ensure_disabled=modifiers.get("--disabled"), use_default_operations=not modifiers.get("--no-default-ops"), wait=modifiers.get("--wait"), ) if not modifiers.get("--group"): lib.stonith.create(stonith_id, stonith_type, parts["op"], parts["meta"], parts["options"], **settings) else: adjacent_resource_id = None put_after_adjacent = False if modifiers.get("--after"): adjacent_resource_id = modifiers.get("--after") put_after_adjacent = True if modifiers.get("--before"): adjacent_resource_id = modifiers.get("--before") put_after_adjacent = False lib.stonith.create_in_group(stonith_id, stonith_type, modifiers.get("--group"), parts["op"], parts["meta"], parts["options"], adjacent_resource_id=adjacent_resource_id, put_after_adjacent=put_after_adjacent, **settings)
def middleware_config(name, config_path, key_path): if config_path and not key_path: raise console_report.error( "With --booth-conf must be specified --booth-key as well" ) if key_path and not config_path: raise console_report.error( "With --booth-key must be specified --booth-conf as well" ) is_mocked_environment = config_path and key_path def create_booth_env(): if not is_mocked_environment: return {"name": name} return { "name": name, "config_file": read_env_file(config_path), "key_file": read_env_file(key_path), "key_path": key_path, } def flush(modified_env): if not is_mocked_environment: return if not modified_env: #TODO now this would not happen #for more information see comment in #pcs.cli.common.lib_wrapper.lib_env_to_cli_env raise console_report.error("Error during library communication") process_no_existing_file_expectation( "booth config file", modified_env["config_file"], config_path ) process_no_existing_file_expectation( "booth key file", modified_env["key_file"], key_path ) write_env_file(modified_env["key_file"], key_path) write_env_file(modified_env["config_file"], config_path) def apply(next_in_line, env, *args, **kwargs): env.booth = create_booth_env() try: result_of_next = next_in_line(env, *args, **kwargs) except LibraryEnvError as e: for report in e.args: if is_missing_file_report(report, file_role_codes.BOOTH_CONFIG): report_missing_file("Booth config file", config_path) e.sign_processed(report) if is_missing_file_report(report, file_role_codes.BOOTH_KEY): report_missing_file("Booth key file", key_path) e.sign_processed(report) raise e flush(env.booth["modified_env"]) return result_of_next return apply
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 remove(lib, argv, modifiers): if len(argv) != 2: raise CmdLineInputError() ticket, resource_id = argv if not lib.constraint_ticket.remove(ticket, resource_id): raise error("no matching ticket constraint found")
def stonith_create(lib, argv, modifiers): """ Options: * --before - specified resource inside a group before which new resource will be placed inside the group * --after - specified resource inside a group after which new resource will be placed inside the group * --group - specifies group in which resource will be created * --force - allow not existing agent, invalid operations or invalid instance attributes * --disabled - created reource will be disabled * --no-default-ops - do not add default operations * --wait * -f - CIB file """ modifiers.ensure_only_supported( "--before", "--after", "--group", "--force", "--disabled", "--no-default-ops", "--wait", "-f", ) if modifiers.is_specified("--before") and modifiers.is_specified("--after"): raise error("you cannot specify both --before and --after{0}".format( "" if modifiers.is_specified("--group") else " and you have to specify --group" )) if not modifiers.is_specified("--group"): if modifiers.is_specified("--before"): raise error("you cannot use --before without --group") if modifiers.is_specified("--after"): raise error("you cannot use --after without --group") if len(argv) < 2: raise CmdLineInputError() stonith_id = argv[0] stonith_type = argv[1] parts = parse_create_args(argv[2:]) settings = dict( allow_absent_agent=modifiers.get("--force"), allow_invalid_operation=modifiers.get("--force"), allow_invalid_instance_attributes=modifiers.get("--force"), ensure_disabled=modifiers.get("--disabled"), use_default_operations=not modifiers.get("--no-default-ops"), wait=modifiers.get("--wait"), ) if not modifiers.get("--group"): lib.stonith.create( stonith_id, stonith_type, parts["op"], parts["meta"], parts["options"], **settings ) else: adjacent_resource_id = None put_after_adjacent = False if modifiers.get("--after"): adjacent_resource_id = modifiers.get("--after") put_after_adjacent = True if modifiers.get("--before"): adjacent_resource_id = modifiers.get("--before") put_after_adjacent = False lib.stonith.create_in_group( stonith_id, stonith_type, modifiers.get("--group"), parts["op"], parts["meta"], parts["options"], adjacent_resource_id=adjacent_resource_id, put_after_adjacent=put_after_adjacent, **settings )