def parse_create(arg_list): groups = group_by_keywords( arg_list, set(["op", "meta", "clone", "promotable", "bundle"]), implicit_first_group_key="options", group_repeated_keywords=["op"], only_found_keywords=True, ) parts = { "meta": prepare_options(groups.get("meta", [])), "options": prepare_options(groups.get("options", [])), "op": [ prepare_options(op) for op in build_operations(groups.get("op", [])) ], } if "clone" in groups: parts["clone"] = prepare_options(groups["clone"]) if "promotable" in groups: parts["promotable"] = prepare_options(groups["promotable"]) if "bundle" in groups: parts["bundle"] = groups["bundle"] return parts
def test_raises_on_group_repeated_keywords_inconsistency(self): self.assertRaises(AssertionError, lambda: group_by_keywords( [], set(["first", "second"]), group_repeated_keywords=["first", "third"], implicit_first_group_key="third" ))
def parse_create(arg_list): groups = group_by_keywords( arg_list, set(["op", "meta", "clone", "master", "bundle"]), implicit_first_group_key="options", group_repeated_keywords=["op"], only_found_keywords=True, ) parts = { "meta": prepare_options(groups.get("meta", [])), "options": prepare_options(groups.get("options", [])), "op": [ prepare_options(op) for op in build_operations(groups.get("op", [])) ], } if "clone" in groups: parts["clone"] = prepare_options(groups["clone"]) if "master" in groups: parts["master"] = prepare_options(groups["master"]) if "bundle" in groups: parts["bundle"] = groups["bundle"] return parts
def stonith_update_scsi_devices(lib, argv, modifiers): """ Options: * --request-timeout - timeout for HTTP requests * --skip-offline - skip unreachable nodes """ modifiers.ensure_only_supported("--request-timeout", "--skip-offline") if len(argv) < 2: raise CmdLineInputError() stonith_id = argv[0] parsed_args = parse_args.group_by_keywords( argv[1:], ["set"], keyword_repeat_allowed=False, only_found_keywords=True, ) set_args = parsed_args["set"] if "set" in parsed_args else [] if not set_args: raise CmdLineInputError( show_both_usage_and_message=True, hint="You must specify set devices to be updated", ) force_flags = [] if modifiers.get("--skip-offline"): force_flags.append(reports.codes.SKIP_OFFLINE_NODES) lib.stonith.update_scsi_devices(stonith_id, set_args, force_flags=force_flags)
def _parse_bundle_groups(arg_list): """ Commandline options: no options """ repeatable_keyword_list = ["port-map", "storage-map"] keyword_list = ["meta", "container", "network"] + repeatable_keyword_list groups = group_by_keywords( arg_list, set(keyword_list), group_repeated_keywords=repeatable_keyword_list, only_found_keywords=True, ) for keyword in keyword_list: if keyword not in groups: continue if keyword in repeatable_keyword_list: for repeated_section in groups[keyword]: if not repeated_section: raise CmdLineInputError( "No {0} options specified".format(keyword)) else: if not groups[keyword]: raise CmdLineInputError( "No {0} options specified".format(keyword)) return groups
def parse_clone(arg_list, promotable=False): parts = { "clone_id": None, "meta": {}, } allowed_keywords = set(["op", "meta"]) if (arg_list and arg_list[0] not in allowed_keywords and "=" not in arg_list[0]): parts["clone_id"] = arg_list.pop(0) groups = group_by_keywords( arg_list, allowed_keywords, implicit_first_group_key="options", group_repeated_keywords=["op"], only_found_keywords=True, ) if "op" in groups: raise CmdLineInputError( "op settings must be changed on base resource, not the clone", ) parts["meta"] = prepare_options( groups.get("options", []) + groups.get("meta", []), ) if promotable: if "promotable" in parts["meta"]: raise CmdLineInputError( "you cannot specify both promotable option and promotable " "keyword") parts["meta"]["promotable"] = "true" return parts
def _parse_bundle_groups(arg_list): """ Commandline options: no options """ repeatable_keyword_list = ["port-map", "storage-map"] keyword_list = ["meta", "container", "network"] + repeatable_keyword_list groups = group_by_keywords( arg_list, set(keyword_list), group_repeated_keywords=repeatable_keyword_list, only_found_keywords=True, ) for keyword in keyword_list: if keyword not in groups: continue if keyword in repeatable_keyword_list: for repeated_section in groups[keyword]: if not repeated_section: raise CmdLineInputError( "No {0} options specified".format(keyword) ) else: if not groups[keyword]: raise CmdLineInputError( "No {0} options specified".format(keyword) ) return groups
def config_setup(lib, arg_list, modifiers): """ create booth config Options: * --force - overwrite existing * --booth-conf - booth config file * --booth-key - booth authkey file * --name - name of a booth instance """ modifiers.ensure_only_supported( "--force", "--booth-conf", "--booth-key", "--name", ) peers = group_by_keywords(arg_list, set(["sites", "arbitrators"]), keyword_repeat_allowed=False) if "sites" not in peers or not peers["sites"]: raise CmdLineInputError() booth_config = [] for site in peers["sites"]: booth_config.append({"key": "site", "value": site, "details": []}) for arbitrator in peers["arbitrators"]: booth_config.append({ "key": "arbitrator", "value": arbitrator, "details": [], }) lib.booth.config_setup(booth_config, overwrite_existing=modifiers.get("--force"))
def config_setup(lib, arg_list, modifiers): """ create booth config Options: * --force - overwrite existing * --booth-conf - booth config file * --booth-key - booth authkey file * --name - name of a booth instance """ modifiers.ensure_only_supported( "--force", "--booth-conf", "--booth-key", "--name", ) peers = group_by_keywords( arg_list, set(["sites", "arbitrators"]), keyword_repeat_allowed=False ) if "sites" not in peers or not peers["sites"]: raise CmdLineInputError() lib.booth.config_setup( peers["sites"], peers["arbitrators"], instance_name=modifiers.get("--name"), overwrite_existing=modifiers.get("--force"), )
def test_can_disallow_keywords_repeating(self): self.assertRaises( CmdLineInputError, lambda: group_by_keywords( ["first", 1, 2, "second", 3, "first"], set(["first", "second"]), keyword_repeat_allowed=False, ))
def _stonith_level_parse_target_and_stonith(argv): target_type, target_value, devices = None, None, None allowed_keywords = {"target", "stonith"} missing_target_value, missing_stonith_value = False, False groups = parse_args.group_by_keywords( argv, allowed_keywords, only_found_keywords=True, ) if "target" in groups: if len(groups["target"]) > 1: raise CmdLineInputError("At most one target can be specified") if groups["target"]: target_type, target_value = _stonith_level_parse_node( groups["target"][0]) else: missing_target_value = True if "stonith" in groups: if groups["stonith"]: devices = groups["stonith"] else: missing_stonith_value = True if missing_target_value and missing_stonith_value: raise CmdLineInputError("Missing value after 'target' and 'stonith'") if missing_target_value: raise CmdLineInputError("Missing value after 'target'") if missing_stonith_value: raise CmdLineInputError("Missing value after 'stonith'") return target_type, target_value, devices
def test_raises_on_group_repeated_keywords_inconsistency(self): self.assertRaises( AssertionError, lambda: group_by_keywords( [], set(["first", "second"]), group_repeated_keywords=["first", "third"], implicit_first_group_key="third"))
def test_group_repeating_keyword_occurences(self): self.assertEqual( group_by_keywords(["first", 1, 2, "second", 3, "first", 4], set(["first", "second"]), group_repeated_keywords=["first"]), { "first": [[1, 2], [4]], "second": [3], })
def test_raises_when_args_do_not_start_with_keyword_nor_implicit(self): self.assertRaises( CmdLineInputError, lambda: group_by_keywords( [0, "first", 1, 2, "second", 3], set(["first", "second"]), ), )
def test_returns_dict_with_empty_lists_for_no_args(self): self.assertEqual( group_by_keywords([], set(["first", "second"])), { "first": [], "second": [], }, )
def test_implicit_first_kw_applyed_in_the_middle_when_is_in_kwds(self): self.assertEqual( group_by_keywords([1, 2, "first", 3, "zero", 4], set(["first", "zero"]), implicit_first_group_key="zero"), { "zero": [1, 2, 4], "first": [3], })
def test_split_with_implicit_first_keyword(self): self.assertEqual( group_by_keywords([0, "first", 1, 2, "second", 3], set(["first", "second"]), implicit_first_keyword="zero"), { "zero": [0], "first": [1, 2], "second": [3], })
def test_splict_without_implict_keyword(self): self.assertEqual( group_by_keywords( ["first", 1, 2, "second", 3], set(["first", "second"]), ), { "first": [1, 2], "second": [3], })
def test_allow_keywords_repeating(self): self.assertEqual( group_by_keywords( ["first", 1, 2, "second", 3, "first", 4], set(["first", "second"]), ), { "first": [1, 2, 4], "second": [3], })
def test_returns_dict_with_empty_lists_for_no_opts_and_only_found_kws( self): self.assertEqual( group_by_keywords( ["first"], set(["first", "second"]), only_found_keywords=True, ), { "first": [], })
def test_splict_without_implict_keyword(self): self.assertEqual( group_by_keywords( ["first", 1, 2, "second", 3], set(["first", "second"]), ), { "first": [1, 2], "second": [3], } )
def test_returns_dict_with_empty_lists_for_no_args_implicit_case(self): self.assertEqual( group_by_keywords( [], set(["first", "second"]), implicit_first_keyword="zero", ), { "zero": [], "first": [], "second": [], })
def test_allow_keywords_repeating(self): self.assertEqual( group_by_keywords( ["first", 1, 2, "second", 3, "first", 4], set(["first", "second"]), ), { "first": [1, 2, 4], "second": [3], } )
def test_returns_dict_with_empty_lists_for_no_args(self): self.assertEqual( group_by_keywords( [], set(["first", "second"]) ), { "first": [], "second": [], } )
def test_returns_dict_with_empty_lists_for_no_opts_and_only_found_kws(self): self.assertEqual( group_by_keywords( ["first"], set(["first", "second"]), only_found_keywords=True, ), { "first": [], } )
def test_group_repeating_keyword_occurences(self): self.assertEqual( group_by_keywords( ["first", 1, 2, "second", 3, "first", 4], set(["first", "second"]), group_repeated_keywords=["first"] ), { "first": [[1, 2], [4]], "second": [3], } )
def test_implicit_first_kw_applyed_in_the_middle_when_is_in_kwds(self): self.assertEqual( group_by_keywords( [1, 2, "first", 3, "zero", 4], set(["first", "zero"]), implicit_first_group_key="zero" ), { "zero": [1, 2, 4], "first": [3], } )
def test_empty_repeatable(self): self.assertEqual( group_by_keywords( ["second"], set(["first", "second"]), group_repeated_keywords=["second"], only_found_keywords=True, ), { "second": [ [], ], })
def test_implicit_first_kw_not_applyed_in_the_middle(self): self.assertEqual( group_by_keywords( [1, 2, "first", 3, "zero", 4], set(["first"]), implicit_first_group_key="zero", ), { "zero": [1, 2], "first": [3, "zero", 4], }, )
def test_split_with_implicit_first_keyword(self): self.assertEqual( group_by_keywords( [0, "first", 1, 2, "second", 3], set(["first", "second"]), implicit_first_group_key="zero" ), { "zero": [0], "first": [1, 2], "second": [3], } )
def _parse_quorum_device_groups(arg_list): keyword_list = ["model", "heuristics"] groups = parse_args.group_by_keywords(arg_list, set(keyword_list), implicit_first_group_key="generic", keyword_repeat_allowed=False, only_found_keywords=True) for keyword in keyword_list: if keyword not in groups: continue if len(groups[keyword]) == 0: raise CmdLineInputError("No {0} options specified".format(keyword)) return groups
def test_returns_dict_with_empty_lists_for_no_args_implicit_case(self): self.assertEqual( group_by_keywords( [], set(["first", "second"]), implicit_first_group_key="zero", ), { "zero": [], "first": [], "second": [], } )
def test_empty_repeatable(self): self.assertEqual( group_by_keywords( ["second"], set(["first", "second"]), group_repeated_keywords=["second"], only_found_keywords=True, ), { "second": [ [], ], } )
def tag_update( lib: Any, argv: Sequence[str], modifiers: InputModifiers, ) -> None: """ Options: * -f - CIB file * --after - place a reference id in a tag after the specified reference id in the tag * --before - place a reference id in a tag before the specified reference id in the tag """ modifiers.ensure_only_supported("-f", "--after", "--before") if not argv: raise CmdLineInputError() tag_id = argv[0] parsed_args = group_by_keywords( argv[1:], ["add", "remove"], keyword_repeat_allowed=False, only_found_keywords=True, ) no_add_remove_arguments = ("add" not in parsed_args and "remove" not in parsed_args) no_add_id = "add" in parsed_args and not parsed_args["add"] no_remove_id = "remove" in parsed_args and not parsed_args["remove"] if no_add_remove_arguments or no_add_id or no_remove_id: raise CmdLineInputError( show_both_usage_and_message=True, hint=("Specify at least one id for 'add' or 'remove' arguments."), ) adjacent_idref = None after_adjacent = True if modifiers.is_specified("--after") and modifiers.is_specified( "--before"): raise CmdLineInputError("Cannot specify both --before and --after") if modifiers.is_specified("--after"): adjacent_idref = modifiers.get("--after") after_adjacent = True elif modifiers.is_specified("--before"): adjacent_idref = modifiers.get("--before") after_adjacent = False lib.tag.update( tag_id, parsed_args["add"] if "add" in parsed_args else [], parsed_args["remove"] if "remove" in parsed_args else [], adjacent_idref=adjacent_idref, put_after_adjacent=after_adjacent, )
def test_returns_empty_lists_no_opts_and_only_found_kws_with_grouping( self): self.assertEqual( group_by_keywords( ["second", 1, "second", "second", 2, 3], set(["first", "second"]), group_repeated_keywords=["second"], only_found_keywords=True, ), { "second": [ [1], [], [2, 3], ], })
def test_returns_empty_lists_no_opts_and_only_found_kws_with_grouping(self): self.assertEqual( group_by_keywords( ["second", 1, "second", "second", 2, 3], set(["first", "second"]), group_repeated_keywords=["second"], only_found_keywords=True, ), { "second": [ [1], [], [2, 3], ], } )
def _parse_quorum_device_groups(arg_list): keyword_list = ["model", "heuristics"] groups = parse_args.group_by_keywords( arg_list, set(keyword_list), implicit_first_group_key="generic", keyword_repeat_allowed=False, only_found_keywords=True ) for keyword in keyword_list: if keyword not in groups: continue if not groups[keyword]: raise CmdLineInputError( "No {0} options specified".format(keyword) ) return groups
def stonith_update_scsi_devices(lib, argv, modifiers): """ Options: * --request-timeout - timeout for HTTP requests * --skip-offline - skip unreachable nodes """ modifiers.ensure_only_supported("--request-timeout", "--skip-offline") force_flags = [] if modifiers.get("--skip-offline"): force_flags.append(reports.codes.SKIP_OFFLINE_NODES) if len(argv) < 2: raise CmdLineInputError() stonith_id = argv[0] parsed_args = parse_args.group_by_keywords( argv[1:], ["set", "add", "remove", "delete"], keyword_repeat_allowed=False, only_found_keywords=True, ) cmd_exception = CmdLineInputError( show_both_usage_and_message=True, hint=( "You must specify either list of set devices or at least one device" " for add or delete/remove devices"), ) if "set" in parsed_args and {"add", "remove", "delete"} & set( parsed_args.keys()): raise cmd_exception if "set" in parsed_args: if not parsed_args["set"]: raise cmd_exception lib.stonith.update_scsi_devices(stonith_id, parsed_args["set"], force_flags=force_flags) else: for key in ("add", "remove", "delete"): if key in parsed_args and not parsed_args[key]: raise cmd_exception lib.stonith.update_scsi_devices_add_remove( stonith_id, parsed_args.get("add", []), parsed_args.get("delete", []) + parsed_args.get("remove", []), force_flags=force_flags, )
def parse_create(arg_list): groups = group_by_keywords( arg_list, set(["op", "meta", "clone", "promotable", "bundle"]), implicit_first_group_key="options", group_repeated_keywords=["op"], only_found_keywords=True, ) try: parts = { "meta": prepare_options(groups.get("meta", [])), "options": prepare_options(groups.get("options", [])), "op": [ prepare_options(op) for op in build_operations(groups.get("op", [])) ], } if "clone" in groups: if groups["clone"] and "=" not in groups["clone"][0]: parts["clone_id"] = groups["clone"].pop(0) parts["clone"] = prepare_options(groups["clone"]) if "promotable" in groups: if groups["promotable"] and "=" not in groups["promotable"][0]: parts["clone_id"] = groups["promotable"].pop(0) parts["promotable"] = prepare_options(groups["promotable"]) if "bundle" in groups: parts["bundle"] = groups["bundle"] except CmdLineInputError as e: # Print error messages which point users to the changes section in pcs # manpage. # To be removed in the next significant version. if e.message == "missing value of 'master' option": raise CmdLineInputError( message=e.message, hint=("Master/Slave resources have been renamed to promotable " "clones, please use the 'promotable' keyword instead of " "'master'. " + SEE_MAN_CHANGES.format("0.10")), ) from e raise return parts
def parse_create_simple(arg_list): groups = group_by_keywords( arg_list, set(["op", "meta"]), implicit_first_group_key="options", group_repeated_keywords=["op"], ) parts = { "meta": prepare_options(groups.get("meta", [])), "options": prepare_options(groups.get("options", [])), "op": [ prepare_options(op) for op in build_operations(groups.get("op", [])) ], } return parts
def cluster_setup(lib, argv, modifiers): DEFAULT_TRANSPORT_TYPE = KNET_KEYWORD if len(argv) < 2: raise CmdLineInputError() cluster_name, *argv = argv keywords = [TRANSPORT_KEYWORD, "totem", "quorum"] parsed_args = parse_args.group_by_keywords( argv, keywords, implicit_first_group_key="nodes", keyword_repeat_allowed=False, only_found_keywords=True, ) nodes = [ _parse_node_options(node, options) for node, options in parse_args.split_list_by_any_keywords( parsed_args["nodes"], "node name", ).items() ] transport_type = DEFAULT_TRANSPORT_TYPE transport_options = {} if TRANSPORT_KEYWORD in parsed_args: transport_type, transport_options = _parse_transport( parsed_args[TRANSPORT_KEYWORD]) lib.cluster.setup( cluster_name, nodes, transport_type=transport_type, transport_options=transport_options.get(TRANSPORT_DEFAULT_SECTION, {}), link_list=transport_options.get(LINK_KEYWORD, []), compression_options=transport_options.get("compression", {}), crypto_options=transport_options.get("crypto", {}), totem_options=parse_args.prepare_options(parsed_args.get("totem", [])), quorum_options=parse_args.prepare_options(parsed_args.get( "quorum", [])), wait=modifiers["wait"], start=modifiers["start"], enable=modifiers["enable"], force=modifiers["force"], force_unresolvable=modifiers["force"])
def config_setup(lib, arg_list, modifiers): """ create booth config """ peers = group_by_keywords(arg_list, set(["sites", "arbitrators"]), keyword_repeat_allowed=False) if "sites" not in peers or not peers["sites"]: raise CmdLineInputError() booth_config = [] for site in peers["sites"]: booth_config.append({"key": "site", "value": site, "details": []}) for arbitrator in peers["arbitrators"]: booth_config.append({ "key": "arbitrator", "value": arbitrator, "details": [], }) lib.booth.config_setup(booth_config, modifiers["force"])
def config_setup(lib, arg_list, modifiers): """ create booth config """ peers = group_by_keywords( arg_list, set(["sites", "arbitrators"]), keyword_repeat_allowed=False ) if "sites" not in peers or not peers["sites"]: raise CmdLineInputError() booth_config = [] for site in peers["sites"]: booth_config.append({"key": "site", "value": site, "details": []}) for arbitrator in peers["arbitrators"]: booth_config.append({ "key": "arbitrator", "value": arbitrator, "details": [], }) lib.booth.config_setup(booth_config, modifiers["force"])
def _parse_transport(transport_args): if len(transport_args) < 1: raise CmdLineInputError("{} type not defined".format( TRANSPORT_KEYWORD.capitalize())) transport_type, *transport_options = transport_args keywords = {"compression", "crypto", LINK_KEYWORD} parsed_options = parse_args.group_by_keywords( transport_options, keywords, implicit_first_group_key=TRANSPORT_DEFAULT_SECTION, group_repeated_keywords=[LINK_KEYWORD], ) options = { section: parse_args.prepare_options(parsed_options[section]) for section in keywords | {TRANSPORT_DEFAULT_SECTION} if section != LINK_KEYWORD } options[LINK_KEYWORD] = [ parse_args.prepare_options(link_options) for link_options in parsed_options[LINK_KEYWORD] ] return transport_type, options
def parse_create(arg_list): groups = group_by_keywords( arg_list, set(["op", "meta", "clone", "promotable", "bundle"]), implicit_first_group_key="options", group_repeated_keywords=["op"], only_found_keywords=True, ) try: parts = { "meta": prepare_options(groups.get("meta", [])), "options": prepare_options(groups.get("options", [])), "op": [ prepare_options(op) for op in build_operations(groups.get("op", [])) ], } if "clone" in groups: parts["clone"] = prepare_options(groups["clone"]) if "promotable" in groups: parts["promotable"] = prepare_options(groups["promotable"]) if "bundle" in groups: parts["bundle"] = groups["bundle"] except CmdLineInputError as e: # Print error messages which point users to the changes section in pcs # manpage. # To be removed in the next significant version. if e.message == "missing value of 'master' option": raise CmdLineInputError(message=e.message, hint=HINT_SYNTAX_CHANGE) raise e return parts
def test_raises_when_args_do_not_start_with_keyword_nor_implicit(self): self.assertRaises(CmdLineInputError, lambda: group_by_keywords( [0, "first", 1, 2, "second", 3], set(["first", "second"]), ))
def test_can_disallow_keywords_repeating(self): self.assertRaises(CmdLineInputError, lambda: group_by_keywords( ["first", 1, 2, "second", 3, "first"], set(["first", "second"]), keyword_repeat_allowed=False, ))