class RA(command.UI): ''' CIB shadow management class ''' name = "ra" provider_classes = ["ocf"] def do_classes(self, context): "usage: classes" for c in ra.ra_classes(): if c in self.provider_classes: providers = ra.ra_providers_all(c) if providers: print "%s / %s" % (c, ' '.join(providers)) else: print "%s" % c @command.skill_level('administrator') def do_providers(self, context, ra_type, ra_class="ocf"): "usage: providers <ra> [<class>]" print ' '.join(ra.ra_providers(ra_type, ra_class)) @command.skill_level('administrator') @command.completers(compl.call(ra.ra_classes), lambda args: ra.ra_providers_all(args[1])) def do_list(self, context, class_, provider_=None): "usage: list <class> [<provider>]" if not class_ in ra.ra_classes(): context.fatal_error("class %s does not exist" % class_) if provider_ and not provider_ in ra.ra_providers_all(class_): context.fatal_error("there is no provider %s for class %s" % (provider_, class_)) types = ra.ra_types(class_, provider_) if options.regression_tests: for t in types: print t else: utils.multicolumn(types) @command.skill_level('administrator') @command.alias('meta') @command.completers(complete_class_provider_type) def do_info(self, context, *args): "usage: info [<class>:[<provider>:]]<type>" if len(args) == 0: context.fatal_error("Expected [<class>:[<provider>:]]<type>") elif len(args) > 1: # obsolete syntax if len(args) < 3: ra_type, ra_class, ra_provider = args[0], args[1], "heartbeat" else: ra_type, ra_class, ra_provider = args[0], args[1], args[2] elif args[0] in constants.meta_progs: ra_class, ra_provider, ra_type = args[0], None, None else: ra_class, ra_provider, ra_type = ra.disambiguate_ra_type(args[0]) agent = ra.RAInfo(ra_class, ra_type, ra_provider) if agent.mk_ra_node() is None: return False try: utils.page_string(agent.meta_pretty()) except Exception, msg: context.fatal_error(msg)
class CibConfig(command.UI): ''' The configuration class ''' name = "configure" def __init__(self): command.UI.__init__(self) # for interactive use, we want to populate the CIB # immediately so that tab completion works if options.interactive or options.shell_completion: cib_factory.initialize() def requires(self): # see the configure ptest/simulate command has_ptest = utils.is_program('ptest') has_simulate = utils.is_program('crm_simulate') if not has_ptest: vars.simulate_programs["ptest"] = "crm_simulate" if not has_simulate: vars.simulate_programs["simulate"] = "ptest" if not (has_ptest or has_simulate): common_warn("neither ptest nor crm_simulate exist, check your installation") vars.simulate_programs["ptest"] = "" vars.simulate_programs["simulate"] = "" return True @command.name('_test') @command.skill_level('administrator') def do_check_structure(self, context): return cib_factory.check_structure() @command.name('_regtest') @command.skill_level('administrator') def do_regression_testing(self, context, param): return cib_factory.regression_testing(param) @command.name('_objects') @command.skill_level('administrator') def do_showobjects(self, context): cib_factory.showobjects() @command.level(ui_ra.RA) def do_ra(self): pass @command.level(ui_cib.CibShadow) def do_cib(self): pass @command.level(ui_cibstatus.CibStatusUI) def do_cibstatus(self): pass @command.level(ui_template.Template) def do_template(self): pass @command.level(ui_history.History) def do_history(self): pass @command.level(ui_assist.Assist) def do_assist(self): pass @command.skill_level('administrator') @command.completers_repeating(_id_show_list) def do_show(self, context, *args): "usage: show [xml] [<id>...]" if not cib_factory.is_cib_sane(): context.fatal_error("CIB is not valid") set_obj = mkset_obj(*args) return set_obj.show() @command.skill_level('administrator') @command.completers_repeating(compl.null, _id_xml_list, _id_list) def do_filter(self, context, filterprog, *args): "usage: filter <prog> [xml] [<id>...]" if not cib_factory.is_cib_sane(): context.fatal_error("CIB is not valid") set_obj = mkset_obj(*args) return set_obj.filter(filterprog) @command.skill_level('administrator') @command.completers(_f_group_id_list, compl.choice(['add', 'remove']), _prim_id_list, compl.choice(['after', 'before']), _prim_id_list) def do_modgroup(self, context, group_id, subcmd, prim_id, *args): """usage: modgroup <id> add <id> [after <id>|before <id>] modgroup <id> remove <id>""" if not cib_factory.is_cib_sane(): context.fatal_error("CIB is not valid") if subcmd not in ("add", "remove"): common_err("modgroup subcommand %s unknown" % subcmd) return False after_before = None if args: if subcmd != 'add': context.fatal_error("Expected add (found %s)" % subcmd) if args[0] not in ("after", "before"): context.fatal_error("Expected after|before (found %s)" % args[0]) if len(args) != 2: context.fatal_error("Expected 'after|before <id>' (%d arguments given)" % len(args)) after_before = args[0] ref_member_id = args[1] g = cib_factory.find_object(group_id) if not g: context.fatal_error("group %s does not exist" % group_id) if not xmlutil.is_group(g.node): context.fatal_error("element %s is not a group" % group_id) children = xmlutil.get_rsc_children_ids(g.node) if after_before and ref_member_id not in children: context.fatal_error("%s is not member of %s" % (ref_member_id, group_id)) if subcmd == "remove" and prim_id not in children: context.fatal_error("%s is not member of %s" % (prim_id, group_id)) # done checking arguments # have a group and children if not after_before: after_before = "after" ref_member_id = children[-1] # just do the filter # (i wonder if this is a feature abuse?) if subcmd == "add": if after_before == "after": sed_s = r's/ %s( |$)/& %s /' % (ref_member_id, prim_id) else: sed_s = r's/ %s( |$)/ %s& /' % (ref_member_id, prim_id) else: sed_s = r's/ %s( |$)/ /' % prim_id l = (group_id,) set_obj = mkset_obj(*l) return set_obj.filter("sed -r '%s'" % sed_s) @command.skill_level('administrator') @command.completers_repeating(_id_xml_list, _id_list) def do_edit(self, context, *args): "usage: edit [xml] [<id>...]" if not cib_factory.is_cib_sane(): context.fatal_error("CIB is not valid") err_buf.buffer() # keep error messages set_obj = mkset_obj(*args) err_buf.release() # show them, but get an ack from the user return set_obj.edit() def _verify(self, set_obj_semantic, set_obj_all): rc1 = set_obj_all.verify() if config.core.check_frequency != "never": rc2 = set_obj_semantic.semantic_check(set_obj_all) else: rc2 = 0 return rc1 and rc2 <= 1 @command.skill_level('administrator') def do_verify(self, context): "usage: verify" if not cib_factory.is_cib_sane(): context.fatal_error("CIB is not valid") set_obj_all = mkset_obj("xml") return self._verify(set_obj_all, set_obj_all) @command.skill_level('administrator') def do_save(self, context, *args): "usage: save [xml] <filename>" if not cib_factory.is_cib_sane(): context.fatal_error("CIB is not valid") if not args: context.fatal_error("Expected 1 argument (0 given)") if args[0] == "xml": if len(args) != 2: context.fatal_error("Expected 2 arguments (%d given)" % (len(args))) filename = args[1] set_obj = mkset_obj("xml") else: filename = args[0] set_obj = mkset_obj() return set_obj.save_to_file(filename) @command.skill_level('administrator') @command.completers(compl.choice(['xml', 'replace', 'update']), _load_2nd_completer) def do_load(self, context, *args): "usage: load [xml] {replace|update} {<url>|<path>}" if not cib_factory.is_cib_sane(): context.fatal_error("CIB is not valid") if len(args) < 2: context.fatal_error("Expected 2 arguments (0 given)") if args[0] == "xml": if len(args) != 3: context.fatal_error("Expected 3 arguments (%d given)" % len(args)) url = args[2] method = args[1] xml = True else: if len(args) != 2: context.fatal_error("Expected 2 arguments (%d given)" % len(args)) url = args[1] method = args[0] xml = False if method not in ("replace", "update"): context.fatal_error("Unknown method %s" % method) if method == "replace": if options.interactive and cib_factory.has_cib_changed(): if not utils.ask("This operation will erase all changes. Do you want to proceed?"): return False cib_factory.erase() if xml: set_obj = mkset_obj("xml") else: set_obj = mkset_obj() return set_obj.import_file(method, url) @command.skill_level('administrator') @command.completers(compl.choice(gv_types.keys() + ['exportsettings'])) def do_graph(self, context, *args): "usage: graph [<gtype> [<file> [<img_format>]]]" if args and args[0] == "exportsettings": return utils.save_graphviz_file(userdir.GRAPHVIZ_USER_FILE, vars.graph) if not cib_factory.is_cib_sane(): context.fatal_error("CIB is not valid") rc, gtype, outf, ftype = ui_utils.graph_args(args) if not rc: context.fatal_error("Failed to create graph") rc, d = utils.load_graphviz_file(userdir.GRAPHVIZ_USER_FILE) if rc and d: vars.graph = d set_obj = mkset_obj() if not outf: rc = set_obj.show_graph(gtype) elif gtype == ftype: rc = set_obj.save_graph(gtype, outf) else: rc = set_obj.graph_img(gtype, outf, ftype) return rc @command.skill_level('administrator') @command.completers_repeating(_id_list) def do_delete(self, context, *args): "usage: delete <id> [<id>...]" if not cib_factory.is_cib_sane(): context.fatal_error("CIB is not valid") return cib_factory.delete(*args) @command.name('default-timeouts') @command.alias('default_timeouts') @command.completers_repeating(_id_list) def do_default_timeouts(self, context, *args): "usage: default-timeouts <id> [<id>...]" if not cib_factory.is_cib_sane(): context.fatal_error("CIB is not valid") return cib_factory.default_timeouts(*args) @command.skill_level('administrator') @command.completers(_id_list, _id_list) def do_rename(self, context, old_id, new_id): "usage: rename <old_id> <new_id>" if not cib_factory.is_cib_sane(): context.fatal_error("CIB is not valid") return cib_factory.rename(old_id, new_id) @command.skill_level('administrator') @command.completers(compl.choice(['nodes'])) def do_erase(self, context, nodes=None): "usage: erase [nodes]" if not cib_factory.is_cib_sane(): context.fatal_error("CIB is not valid") if nodes is None: return cib_factory.erase() if nodes != 'nodes': context.fatal_error("Expected 'nodes' (found '%s')" % (nodes)) return cib_factory.erase_nodes() @command.skill_level('administrator') def do_refresh(self, context): "usage: refresh" if options.interactive and cib_factory.has_cib_changed(): if not utils.ask("All changes will be dropped. Do you want to proceed?"): return cib_factory.refresh() @command.alias('simulate') @command.completers(compl.choice(['nograph'])) def do_ptest(self, context, *args): "usage: ptest [nograph] [v...] [scores] [utilization] [actions]" if not cib_factory.is_cib_sane(): return False # use ptest/crm_simulate depending on which command was # used config.core.ptest = vars.simulate_programs[context.get_command_name()] if not config.core.ptest: return False set_obj = mkset_obj("xml") return ui_utils.ptestlike(set_obj.ptest, 'vv', context.get_command_name(), args) def _commit(self, force=None): if force and force != "force": syntax_err(('configure.commit', force)) return False if not cib_factory.is_cib_sane(): return False if not cib_factory.has_cib_changed(): common_info("apparently there is nothing to commit") common_info("try changing something first") return True rc1 = True if not (force or utils.cibadmin_can_patch()): rc1 = cib_factory.is_current_cib_equal() rc2 = cib_factory.is_cib_empty() or \ self._verify(mkset_obj("xml", "changed"), mkset_obj("xml")) if rc1 and rc2: return cib_factory.commit() if force or config.core.force: common_info("commit forced") return cib_factory.commit(force=True) if utils.ask("Do you still want to commit?"): return cib_factory.commit(force=True) return False @command.skill_level('administrator') @command.wait @command.completers(compl.choice(['force'])) def do_commit(self, context, force=None): "usage: commit [force]" return self._commit(force=force) @command.skill_level('administrator') @command.completers(compl.choice(['force'])) def do_upgrade(self, context, force=None): "usage: upgrade [force]" if not cib_factory.is_cib_sane(): return False if force and force != "force": syntax_err((context.get_command_name(), force)) return False if config.core.force or force: return cib_factory.upgrade_cib_06to10(True) else: return cib_factory.upgrade_cib_06to10() @command.skill_level('administrator') def do_schema(self, context, schema_st=None): "usage: schema [<schema>]" if not cib_factory.is_cib_sane(): return False if not schema_st: print cib_factory.get_schema() return True return cib_factory.change_schema(schema_st) def __conf_object(self, cmd, *args): "The configure object command." if not cib_factory.is_cib_sane(): return False if cmd in vars.cib_cli_map.values() and \ not cib_factory.is_elem_supported(cmd): common_err("%s not supported by the RNG schema" % cmd) return False f = lambda: cib_factory.create_object(cmd, *args) return f() @command.skill_level('administrator') @command.completers(_node_id_list, compl.choice(vars.node_attributes_keyw)) def do_node(self, context, *args): """usage: node <uname>[:<type>] [attributes <param>=<value> [<param>=<value>...]] [utilization <param>=<value> [<param>=<value>...]]""" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') @command.completers_repeating(compl.null, ra_classes_or_tmpl, primitive_complete_complex) def do_primitive(self, context, *args): """usage: primitive <rsc> {[<class>:[<provider>:]]<type>|@<template>} [params <param>=<value> [<param>=<value>...]] [meta <attribute>=<value> [<attribute>=<value>...]] [utilization <attribute>=<value> [<attribute>=<value>...]] [operations id_spec [op op_type [<attribute>=<value>...] ...]]""" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') @command.completers_repeating(compl.null, _group_completer) def do_group(self, context, *args): """usage: group <name> <rsc> [<rsc>...] [params <param>=<value> [<param>=<value>...]] [meta <attribute>=<value> [<attribute>=<value>...]]""" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') @command.completers_repeating(compl.null, _f_children_id_list, _clone_completer) def do_clone(self, context, *args): """usage: clone <name> <rsc> [params <param>=<value> [<param>=<value>...]] [meta <attribute>=<value> [<attribute>=<value>...]]""" return self.__conf_object(context.get_command_name(), *args) @command.alias('master') @command.skill_level('administrator') @command.completers_repeating(compl.null, _f_children_id_list, _ms_completer) def do_ms(self, context, *args): """usage: ms <name> <rsc> [params <param>=<value> [<param>=<value>...]] [meta <attribute>=<value> [<attribute>=<value>...]]""" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') @command.completers_repeating(compl.null, ui_ra.complete_class_provider_type, primitive_complete_complex) def do_rsc_template(self, context, *args): """usage: rsc_template <name> [<class>:[<provider>:]]<type> [params <param>=<value> [<param>=<value>...]] [meta <attribute>=<value> [<attribute>=<value>...]] [utilization <attribute>=<value> [<attribute>=<value>...]] [operations id_spec [op op_type [<attribute>=<value>...] ...]]""" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') @command.completers(compl.null, _top_rsc_id_list) def do_location(self, context, *args): """usage: location <id> <rsc> {node_pref|rules} node_pref :: <score>: <node> rules :: rule [id_spec] [$role=<role>] <score>: <expression> [rule [id_spec] [$role=<role>] <score>: <expression> ...] id_spec :: $id=<id> | $id-ref=<id> score :: <number> | <attribute> | [-]inf expression :: <simple_exp> [bool_op <simple_exp> ...] bool_op :: or | and simple_exp :: <attribute> [type:]<binary_op> <value> | <unary_op> <attribute> | date <date_expr> type :: string | version | number binary_op :: lt | gt | lte | gte | eq | ne unary_op :: defined | not_defined""" return self.__conf_object(context.get_command_name(), *args) @command.alias('collocation') @command.skill_level('administrator') @command.completers_repeating(compl.null, compl.null, top_rsc_tmpl_id_list) def do_colocation(self, context, *args): """usage: colocation <id> <score>: <rsc>[:<role>] <rsc>[:<role>] ... [node-attribute=<node_attr>]""" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') @command.completers_repeating(compl.null, compl.call(schema.rng_attr_values, 'rsc_order', 'kind'), top_rsc_tmpl_id_list) def do_order(self, context, *args): """usage: order <id> {kind|<score>}: <rsc>[:<action>] <rsc>[:<action>] ... [symmetrical=<bool>]""" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') @command.completers_repeating(compl.null, compl.null, top_rsc_tmpl_id_list) def do_rsc_ticket(self, context, *args): """usage: rsc_ticket <id> <ticket_id>: <rsc>[:<role>] [<rsc>[:<role>] ...] [loss-policy=<loss_policy_action>]""" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') @command.completers_repeating(_property_completer) def do_property(self, context, *args): "usage: property [$id=<set_id>] <option>=<value>" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') @command.completers_repeating(_prim_meta_completer) def do_rsc_defaults(self, context, *args): "usage: rsc_defaults [$id=<set_id>] <option>=<value>" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') @command.completers_repeating(op_attr_list) def do_op_defaults(self, context, *args): "usage: op_defaults [$id=<set_id>] <option>=<value>" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') @command.completers_repeating(node_id_colon_list, stonith_resource_list) def do_fencing_topology(self, context, *args): "usage: fencing_topology [<node>:] stonith_resources [stonith_resources ...]" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') def do_xml(self, context, *args): "usage: xml <xml>" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') @command.completers(_f_children_id_list) def do_monitor(self, context, *args): "usage: monitor <rsc>[:<role>] <interval>[:<timeout>]" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('expert') @command.completers_repeating(compl.null, compl.choice(["role:", "read", "write", "deny"])) def do_user(self, context, *args): """user <uid> {roles|rules} roles :: role:<role-ref> [role:<role-ref> ...] rules :: rule [rule ...] (See the role command for details on rules.)""" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('expert') @command.completers_repeating(compl.null, compl.choice(["read", "write", "deny"])) def do_role(self, context, *args): """role <role-id> rule [rule ...] rule :: acl-right cib-spec [attribute:<attribute>] acl-right :: read | write | deny cib-spec :: xpath-spec | tag-ref-spec xpath-spec :: xpath:<xpath> | shortcut tag-ref-spec :: tag:<tag> | ref:<id> | tag:<tag> ref:<id> shortcut :: meta:<rsc>[:<attr>] params:<rsc>[:<attr>] utilization:<rsc> location:<rsc> property[:<attr>] node[:<node>] nodeattr[:<attr>] nodeutil[:<node>] status""" return self.__conf_object(context.get_command_name(), *args) @command.skill_level('administrator') @command.completers_repeating(compl.null, top_rsc_tmpl_id_list) def do_tag(self, context, *args): return self.__conf_object(context.get_command_name(), *args) @command.skill_level('expert') @command.completers_repeating(_rsc_id_list) def do_rsctest(self, context, *args): "usage: rsctest <rsc_id> [<rsc_id> ...] [<node_id> ...]" if not cib_factory.is_cib_sane(): return False rc = True rsc_l = [] node_l = [] current = "r" for ident in args: el = cib_factory.find_object(ident) if not el: common_err("element %s does not exist" % ident) rc = False elif current == "r" and xmlutil.is_resource(el.node): if xmlutil.is_container(el.node): rsc_l += el.node.findall("primitive") else: rsc_l.append(el.node) elif xmlutil.is_normal_node(el.node): current = "n" node_l.append(el.node.get("uname")) else: syntax_err((context.get_command_name(), ident), context='rsctest') return False if not rc: return False if not rsc_l: common_err("specify at least one resource") return False all_nodes = cib_factory.node_id_list() if not node_l: node_l = all_nodes return rsctest.test_resources(rsc_l, node_l, all_nodes) def should_wait(self): return cib_factory.has_cib_changed() def end_game(self, no_questions_asked=False): ok = True if cib_factory.has_cib_changed(): if no_questions_asked or not options.interactive: ok = self._commit() elif utils.ask("There are changes pending. Do you want to commit them?"): ok = self._commit() cib_factory.reset() return ok
import ui_utils import ui_assist from crm_gv import gv_types err_buf = ErrorBuffer.getInstance() cib_factory = CibFactory.getInstance() def _type_completions(): "completer for type: use in show" typelist = cib_factory.type_list() return ['type:%s' % (t) for t in typelist] # Tab completion helpers _id_list = compl.call(cib_factory.id_list) _id_xml_list = compl.join(_id_list, compl.choice(['xml'])) _id_show_list = compl.join(_id_list, compl.choice(['xml', 'changed']), compl.call(_type_completions)) _prim_id_list = compl.call(cib_factory.prim_id_list) _f_prim_free_id_list = compl.call(cib_factory.f_prim_free_id_list) _f_group_id_list = compl.call(cib_factory.f_group_id_list) _f_children_id_list = compl.call(cib_factory.f_children_id_list) _rsc_id_list = compl.call(cib_factory.rsc_id_list) _top_rsc_id_list = compl.call(cib_factory.top_rsc_id_list) _node_id_list = compl.call(cib_factory.node_id_list) _rsc_template_list = compl.call(cib_factory.rsc_template_list) _group_completer = compl.join(_f_prim_free_id_list, compl.choice(['params', 'meta'])) _clone_completer = compl.choice(['params', 'meta']) _ms_completer = compl.choice(['params', 'meta'])
class Template(command.UI): ''' Configuration templates. ''' name = "template" def __init__(self): command.UI.__init__(self) self.curr_conf = '' self.init_dir() @command.skill_level('administrator') @command.completers_repeating(compl.null, compl.call(utils.listtemplates)) def do_new(self, context, name, *args): "usage: new <config> <template> [<template> ...] [params name=value ...]" if not utils.is_filename_sane(name): return False if os.path.isfile("%s/%s" % (userdir.CRMCONF_DIR, name)): common_err("config %s exists; delete it first" % name) return False lt = LoadTemplate(name) rc = True mode = 0 params = {} for s in args: if mode == 0 and s == "params": params["id"] = name mode = 1 elif mode == 1: a = s.split('=') if len(a) != 2: syntax_err(args, context='new') rc = False else: params[a[0]] = a[1] elif not lt.load_template(s): rc = False if rc: lt.post_process(params) if not rc or not lt.write_config(name): return False self.curr_conf = name @command.skill_level('administrator') @command.completers(compl.call(utils.listconfigs)) def do_delete(self, context, name, force=''): "usage: delete <config> [force]" if force: if force != "force" and force != "--force": syntax_err((context.get_command_name(), force), context='delete') return False if not self.config_exists(name): return False if name == self.curr_conf: if not force and not config.core.force and \ not utils.ask("Do you really want to remove config %s which is in use?" % self.curr_conf): return False else: self.curr_conf = '' os.remove("%s/%s" % (userdir.CRMCONF_DIR, name)) @command.skill_level('administrator') @command.completers(compl.call(utils.listconfigs)) def do_load(self, context, name=''): "usage: load [<config>]" if not name: self.curr_conf = '' return True if not self.config_exists(name): return False self.curr_conf = name @command.skill_level('administrator') @command.completers(compl.call(utils.listconfigs)) def do_edit(self, context, name=''): "usage: edit [<config>]" if not name and not self.curr_conf: common_err("please load a config first") return False if name: if not self.config_exists(name): return False utils.edit_file("%s/%s" % (userdir.CRMCONF_DIR, name)) else: utils.edit_file("%s/%s" % (userdir.CRMCONF_DIR, self.curr_conf)) @command.completers(compl.call(utils.listconfigs)) def do_show(self, context, name=''): "usage: show [<config>]" if not name and not self.curr_conf: common_err("please load a config first") return False if name: if not self.config_exists(name): return False print self.process(name) else: print self.process() @command.skill_level('administrator') @command.completers( compl.join(compl.call(utils.listconfigs), compl.choice(['replace', 'update'])), compl.call(utils.listconfigs)) def do_apply(self, context, *args): "usage: apply [<method>] [<config>]" method = "replace" name = '' if len(args) > 0: i = 0 if args[0] in ("replace", "update"): method = args[0] i += 1 if len(args) > i: name = args[i] if not name and not self.curr_conf: common_err("please load a config first") return False if name: if not self.config_exists(name): return False s = self.process(name) else: s = self.process() if not s: return False tmp = utils.str2tmp(s) if not tmp: return False if method == "replace": if options.interactive and cib_factory.has_cib_changed(): if not utils.ask( "This operation will erase all changes. Do you want to proceed?" ): return False cib_factory.erase() set_obj = mkset_obj() rc = set_obj.import_file(method, tmp) try: os.unlink(tmp) except: pass return rc @command.completers(compl.choice(['templates'])) def do_list(self, context, templates=''): "usage: list [templates]" if templates == "templates": utils.multicolumn(utils.listtemplates()) else: utils.multicolumn(utils.listconfigs()) def init_dir(self): '''Create the conf directory, link to templates''' if not os.path.isdir(userdir.CRMCONF_DIR): try: os.makedirs(userdir.CRMCONF_DIR) except os.error, msg: common_err("makedirs: %s" % msg)
class History(command.UI): ''' The history class ''' name = "history" def __init__(self): command.UI.__init__(self) self.current_session = None self._source_inited = False def _init_source(self): if self._source_inited: return True self._source_inited = True return self._set_source(options.history) def _set_period(self, from_time='', to_time=''): ''' parse time specs and set period ''' from_dt = to_dt = None if from_time: from_dt = utils.parse_time(from_time) if not from_dt: return False if to_time: to_dt = utils.parse_time(to_time) if not to_dt: return False if to_dt and to_dt <= from_dt: common_err("%s - %s: bad period" % (from_time, to_time)) return False return crm_report().set_period(from_dt, to_dt) def _check_source(self, src): 'a (very) quick source check' if src == "live" or os.path.isfile(src) or os.path.isdir(src): return True else: common_err("source %s doesn't exist" % src) return False def _set_source(self, src, live_from_time=None): ''' Have the last history source survive the History and Report instances ''' common_debug("setting source to %s" % src) if not self._check_source(src): return False crm_report().set_source(src) options.history = src self.current_session = None to_time = '' if src == "live": from_time = time.ctime(live_from_time and live_from_time or (time.time() - 60 * 60)) else: from_time = '' return self._set_period(from_time, to_time) @command.skill_level('administrator') def do_source(self, context, src=None): "usage: source {<dir>|<file>|live}" if src is None: print "Current source: %s" % (options.history) return True self._init_source() if src != options.history: return self._set_source(src) @command.skill_level('administrator') @command.alias('timeframe') def do_limit(self, context, from_time='', to_time=''): "usage: limit [<from_time> [<to_time>]]" self._init_source() if options.history == "live" and not from_time: from_time = time.ctime(time.time() - 60 * 60) return self._set_period(from_time, to_time) @command.skill_level('administrator') def do_refresh(self, context, force=''): "usage: refresh" self._init_source() if options.history != "live": common_info("nothing to refresh if source isn't live") return False if force: if force != "force" and force != "--force": context.fatal_error( "Expected 'force' or '--force' (was '%s')" % (force)) force = True return crm_report().refresh_source(force) @command.skill_level('administrator') def do_detail(self, context, detail_lvl): "usage: detail <detail_level>" self._init_source() detail_num = utils.convert2ints(detail_lvl) if not (isinstance(detail_num, int) and int(detail_num) >= 0): bad_usage(context.get_command_name(), detail_lvl) return False return crm_report().set_detail(detail_lvl) @command.skill_level('administrator') @command.completers_repeating(compl.call(lambda: crm_report().node_list())) def do_setnodes(self, context, *args): "usage: setnodes <node> [<node> ...]" self._init_source() if options.history != "live": common_info( "setting nodes not necessary for existing reports, proceeding anyway" ) return crm_report().set_nodes(*args) @command.skill_level('administrator') def do_info(self, context): "usage: info" self._init_source() return crm_report().info() @command.skill_level('administrator') def do_latest(self, context): "usage: latest" self._init_source() if not utils.wait4dc("transition", not options.batch): return False self._set_source("live") crm_report().refresh_source() f = self._get_pe_byidx(-1) if not f: return False crm_report().show_transition_log(f) @command.skill_level('administrator') @command.completers_repeating(compl.call(lambda: crm_report().rsc_list())) def do_resource(self, context, *args): "usage: resource <rsc> [<rsc> ...]" self._init_source() return crm_report().resource(*args) @command.skill_level('administrator') @command.wait @command.completers_repeating(compl.call(lambda: crm_report().node_list())) def do_node(self, context, *args): "usage: node <node> [<node> ...]" self._init_source() return crm_report().node(*args) @command.skill_level('administrator') @command.completers_repeating(compl.call(lambda: crm_report().node_list())) def do_log(self, context, *args): "usage: log [<node> ...]" self._init_source() return crm_report().log(*args) def ptest(self, nograph, scores, utilization, actions, verbosity): 'Send a decompressed self.pe_file to ptest' try: s = bz2.decompress(open(self.pe_file).read()) except IOError, msg: common_err("open: %s" % msg) return False return utils.run_ptest(s, nograph, scores, utilization, actions, verbosity)
self._init_source() return crm_report().log(*args) def ptest(self, nograph, scores, utilization, actions, verbosity): 'Send a decompressed self.pe_file to ptest' try: s = bz2.decompress(open(self.pe_file).read()) except IOError, msg: common_err("open: %s" % msg) return False return utils.run_ptest(s, nograph, scores, utilization, actions, verbosity) @command.skill_level('administrator') @command.completers_repeating( compl.join(compl.call(lambda: crm_report().peinputs_list()), compl.choice(['v']))) def do_peinputs(self, context, *args): """usage: peinputs [{<range>|<number>} ...] [v]""" self._init_source() argl = list(args) opt_l = utils.fetch_opts(argl, ["v"]) if argl: l = [] for s in argl: a = utils.convert2ints(s.split(':')) if a and len(a) == 2 and not utils.check_range(a): common_err("%s: invalid peinputs range" % a) return False l += crm_report().pelist(a, long=("v" in opt_l)) else:
# General Public License for more details. # # You should have received a copy of the GNU General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # import command import completers as compl import utils import ui_utils import constants from cibstatus import cib_status _status_node_list = compl.call(cib_status.status_node_list) class CibStatusUI(command.UI): ''' The CIB status section management user interface class ''' name = "cibstatus" @command.skill_level('expert') def do_load(self, context, org): "usage: load {<file>|shadow:<cib>|live}" return cib_status.load(org) @command.skill_level('expert') def do_save(self, context, dest=None):
# # You should have received a copy of the GNU General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # import command import completers as compl import utils import ui_utils import vars from cibstatus import CibStatus cib_status = CibStatus.getInstance() _status_node_list = compl.call(cib_status.status_node_list) class CibStatusUI(command.UI): ''' The CIB status section management user interface class ''' name = "cibstatus" @command.skill_level('expert') def do_load(self, context, org): "usage: load {<file>|shadow:<cib>|live}" return cib_status.load(org) @command.skill_level('expert') def do_save(self, context, dest=None):
def do_log(self, context, *args): "usage: log [<node> ...]" self._init_source() return crm_report().log(*args) def ptest(self, nograph, scores, utilization, actions, verbosity): 'Send a decompressed self.pe_file to ptest' try: s = bz2.decompress(open(self.pe_file).read()) except IOError, msg: common_err("open: %s" % msg) return False return utils.run_ptest(s, nograph, scores, utilization, actions, verbosity) @command.skill_level('administrator') @command.completers_repeating(compl.join(compl.call(lambda: crm_report().peinputs_list()), compl.choice(['v']))) def do_peinputs(self, context, *args): """usage: peinputs [{<range>|<number>} ...] [v]""" self._init_source() argl = list(args) opt_l = utils.fetch_opts(argl, ["v"]) if argl: l = [] for s in argl: a = utils.convert2ints(s.split(':')) if a and len(a) == 2 and not utils.check_range(a): common_err("%s: invalid peinputs range" % a) return False l += crm_report().pelist(a, long=("v" in opt_l)) else:
class Assist(command.UI): ''' The assist UI collects what could be called configuration macros. Things like merging multiple resources into a template, or building a colocated set with a relation to a dummy resource. ''' name = "assist" def __init__(self): command.UI.__init__(self) def requires(self): return cib_factory.initialize() @command.skill_level('administrator') @command.completers_repeating(compl.call(cib_factory.prim_id_list)) def do_template(self, context, *primitives): ''' Create a shared template for the given primitives ''' if len(primitives) < 1: context.fatal_error("Expected at least one primitive argument") objs = [cib_factory.find_object(p) for p in primitives] for prim, obj in zip(primitives, objs): if obj is None: context.fatal_error("Primitive %s not found" % (prim)) if objs and all(obj.obj_type == 'primitive' for obj in objs): return self._template_primitives(context, objs) context.fatal_error("Cannot create a template for the given resources") def _template_primitives(self, context, primitives): """ Try to template the given primitives: Templating means creating a rsc_template and moving shared attributes and other commonalities into that template (this second step is currently not available) """ shared_template = None if all('template' in obj.node.attrib for obj in primitives): return True if len(set(xmlutil.mk_rsc_type(obj.node) for obj in primitives)) != 1: context.fatal_error("Cannot template the given primitives") node = primitives[0].node template_name = self.make_unique_name('template-%s-' % (node.get('type').lower())) shared_template = cib_factory.create_object('rsc_template', template_name, xmlutil.mk_rsc_type(node)) if not shared_template: context.fatal_error("Error creating template") for obj in primitives: obj.node.set('template', template_name) rmattrs(obj.node, 'class', 'provider', 'type') obj.set_updated() if not self._pull_attributes(context, shared_template, primitives): context.fatal_error("Error when copying attributes into template") context.info("Template created: %s" % (template_name)) return True def _pull_attributes(self, context, template, primitives): ''' TODO: take any attributes shared by all primitives and move them into the shared template ''' return True @command.skill_level('administrator') @command.completers_repeating(compl.call(cib_factory.prim_id_list)) @command.name('weak-bond') @command.alias('weak_bond') def do_weak_bond(self, context, *nodes): ''' Create a 'weak' colocation: Colocating a non-sequential resource set with a dummy resource which is not monitored creates, in effect, a colocation which does not imply any internal relationship between resources. ''' if len(nodes) < 2: context.fatal_error("Need at least two arguments") for node in nodes: obj = cib_factory.find_object(node) if not obj: context.fatal_error("Object not found: %s" % (node)) if not xmlutil.is_primitive(obj.node): context.fatal_error("Object not primitive: %s" % (node)) constraint_name = self.make_unique_name('place-constraint-') dummy_name = self.make_unique_name('place-dummy-') print "Create weak bond / independent colocation" print "The following elements will be created:" print " * Colocation constraint, ID: %s" % (constraint_name) print " * Dummy resource, ID: %s" % (dummy_name) if not utils.can_ask() or utils.ask("Create resources?"): cib_factory.create_object('primitive', dummy_name, 'ocf:heartbeat:Dummy') colo = ['colocation', constraint_name, 'inf:', '('] colo.extend(nodes) colo.append(')') colo.append(dummy_name) cib_factory.create_object(*colo) def make_unique_name(self, prefix): n = 0 while n < 1000: n += 1 name = "%s%s" % (prefix, n) for _id in cib_factory.id_list(): if name == _id.lower(): continue return name raise ValueError( "Failed to generate unique resource ID with prefix '%s'" % (prefix))
class Maintenance(command.UI): ''' Commands that should only be run while in maintenance mode. ''' name = "maintenance" rsc_maintenance = "crm_resource -r '%s' --meta -p maintenance -v '%s'" def __init__(self): command.UI.__init__(self) def requires(self): return cib_factory.initialize() def _onoff(self, resource, onoff): if resource is not None: return utils.ext_cmd(self.rsc_maintenance % (resource, onoff)) == 0 else: return cib_factory.create_object('property', 'maintenance-mode=%s' % (onoff)) @command.skill_level('administrator') @command.completers_repeating(compl.call(cib_factory.rsc_id_list)) def do_on(self, context, resource=None): ''' Enable maintenance mode (for the optional resource or for everything) ''' return self._onoff(resource, 'true') @command.skill_level('administrator') @command.completers_repeating(compl.call(cib_factory.rsc_id_list)) def do_off(self, context, resource=None): ''' Disable maintenance mode (for the optional resource or for everything) ''' return self._onoff(resource, 'false') def _in_maintenance_mode(self, obj): if cib_factory.get_property("maintenance-mode") == "true": return True v = obj.meta_attributes("maintenance") return v and all(x == 'true' for x in v) def _runs_on_this_node(self, resource): nodes = utils.running_on(resource) return set(nodes) == set([utils.this_node()]) @command.skill_level('administrator') @command.completers(compl.call(cib_factory.rsc_id_list), _compl_actions, compl.choice(["ssh"])) def do_action(self, context, resource, action, ssh=None): ''' Issue action out-of-band to the given resource, making sure that the resource is in maintenance mode first ''' obj = cib_factory.find_object(resource) if not obj: context.fatal_error("Resource not found: %s" % (resource)) if not xmlutil.is_resource(obj.node): context.fatal_error("Not a resource: %s" % (resource)) if not self._in_maintenance_mode(obj): context.fatal_error("Not in maintenance mode.") if ssh is None: if action not in ('start', 'monitor'): if not self._runs_on_this_node(resource): context.fatal_error( "Resource %s must be running on this node (%s)" % (resource, utils.this_node())) import rsctest return rsctest.call_resource(obj.node, action, [utils.this_node()], local_only=True) elif ssh == "ssh": import rsctest if action in ('start', 'promote', 'demote', 'recover', 'meta-data'): return rsctest.call_resource(obj.node, action, [utils.this_node()], local_only=True) else: all_nodes = cib_factory.node_id_list() return rsctest.call_resource(obj.node, action, all_nodes, local_only=False) else: context.fatal_error("Unknown argument: %s" % (ssh))
def ptest(self, nograph, scores, utilization, actions, verbosity): 'Send a decompressed self.pe_file to ptest' try: f = open(self.pe_file) except IOError, msg: common_err("open: %s" % msg) return False s = bz2.decompress(''.join(f)) f.close() return utils.run_ptest(s, nograph, scores, utilization, actions, verbosity) @command.skill_level('administrator') @command.completers_repeating( compl.join(compl.call(crm_report.peinputs_list), compl.choice(['v']))) def do_peinputs(self, context, *args): """usage: peinputs [{<range>|<number>} ...] [v]""" argl = list(args) opt_l = utils.fetch_opts(argl, ["v"]) if argl: l = [] for s in argl: a = utils.convert2ints(s.split(':')) if a and len(a) == 2 and not utils.check_range(a): common_err("%s: invalid peinputs range" % a) return False l += crm_report.pelist(a, long=("v" in opt_l)) else: l = crm_report.pelist(long=("v" in opt_l)) if not l:
class CibStatusUI(command.UI): ''' The CIB status section management user interface class ''' name = "cibstatus" @command.skill_level('expert') def do_load(self, context, org): "usage: load {<file>|shadow:<cib>|live}" return cib_status.load(org) @command.skill_level('expert') def do_save(self, context, dest=None): "usage: save [<file>|shadow:<cib>]" return cib_status.save(dest) @command.skill_level('administrator') def do_origin(self, context): "usage: origin" state = cib_status.modified and " (modified)" or "" print "%s%s" % (cib_status.origin, state) @command.skill_level('administrator') @command.completers(compl.choice(['changed'])) def do_show(self, context, changed=""): "usage: show [changed]" if changed: if changed != "changed": context.fatal_error("Expected 'changed', got '%s'" % (changed)) return cib_status.list_changes() return cib_status.show() @command.skill_level('administrator') @command.completers(compl.booleans) def do_quorum(self, context, opt): "usage: quorum <bool>" if not utils.verify_boolean(opt): context.fatal_error("%s: bad boolean option" % opt) return cib_status.set_quorum(utils.is_boolean_true(opt)) @command.skill_level('expert') @command.completers(_status_node_list, compl.choice(vars.node_states)) def do_node(self, context, node, state): "usage: node <node> {online|offline|unclean}" return cib_status.edit_node(node, state) @command.skill_level('expert') @command.completers(compl.null, compl.choice(cib_status.ticket_ops.keys())) def do_ticket(self, context, ticket, subcmd): "usage: ticket <ticket> {grant|revoke|activate|standby}" return cib_status.edit_ticket(ticket, subcmd) @command.skill_level('expert') @command.completers(compl.choice(vars.ra_operations), compl.call(cib_status.status_rsc_list), compl.choice(vars.lrm_exit_codes.keys()), compl.choice(vars.lrm_status_codes.keys()), compl.choice(vars.node_states)) def do_op(self, context, op, rsc, rc, op_status=None, node=''): "usage: op <operation> <resource> <exit_code> [<op_status>] [<node>]" if rc in vars.lrm_exit_codes: num_rc = vars.lrm_exit_codes[rc] else: num_rc = rc if not num_rc.isdigit(): context.fatal_error("Invalid exit code '%s'" % num_rc) num_op_status = op_status if op_status: if op_status in vars.lrm_status_codes: num_op_status = vars.lrm_status_codes[op_status] if not num_op_status.isdigit(): context.fatal_error("Invalid operation status '%s'" % num_op_status) return cib_status.edit_op(op, rsc, num_rc, num_op_status, node) @command.skill_level('administrator') @command.completers(compl.choice(['nograph'])) def do_run(self, context, *args): "usage: run [nograph] [v...] [scores] [utilization]" return ui_utils.ptestlike(cib_status.run, '', context.get_command_name(), args) @command.skill_level('administrator') @command.completers(compl.choice(['nograph'])) def do_simulate(self, context, *args): "usage: simulate [nograph] [v...] [scores] [utilization]" return ui_utils.ptestlike(cib_status.simulate, '', context.get_command_name(), args)
logfile = corosync.get_value('logging.logfile') if not logfile: context.fatal_error("No corosync log file configured") utils.page_file(logfile) @command.name('add-node') @command.alias('add_node') @command.skill_level('administrator') def do_addnode(self, context, name): "Add a node to the corosync nodelist" corosync.add_node(name) @command.name('del-node') @command.alias('del_node') @command.skill_level('administrator') def do_delnode(self, context, name): "Remove a node from the corosync nodelist" corosync.del_node(name) @command.skill_level('administrator') @command.completers(completers.call(corosync.get_all_paths)) def do_get(self, context, path): "Get a corosync configuration value" for v in corosync.get_values(path): print v @command.skill_level('administrator') def do_set(self, context, path, value): "Set a corosync configuration value" corosync.set_value(path, value)
def do_log(self, context, *args): "usage: log [<node> ...]" self._init_source() return crm_report.log(*args) def ptest(self, nograph, scores, utilization, actions, verbosity): 'Send a decompressed self.pe_file to ptest' try: s = bz2.decompress(open(self.pe_file).read()) except IOError, msg: common_err("open: %s" % msg) return False return utils.run_ptest(s, nograph, scores, utilization, actions, verbosity) @command.skill_level('administrator') @command.completers_repeating(compl.join(compl.call(crm_report.peinputs_list), compl.choice(['v']))) def do_peinputs(self, context, *args): """usage: peinputs [{<range>|<number>} ...] [v]""" self._init_source() argl = list(args) opt_l = utils.fetch_opts(argl, ["v"]) if argl: l = [] for s in argl: a = utils.convert2ints(s.split(':')) if a and len(a) == 2 and not utils.check_range(a): common_err("%s: invalid peinputs range" % a) return False l += crm_report.pelist(a, long=("v" in opt_l)) else:
class Assist(command.UI): ''' The assist UI collects what could be called configuration macros. Things like merging multiple resources into a template, or building a colocated set with a relation to a dummy resource. ''' name = "assist" def __init__(self): command.UI.__init__(self) # for interactive use, we want to populate the CIB # immediately so that tab completion works if options.interactive: cib_factory.initialize() #def do_distill(self, context): # ''' # Detect and merge resources if the # resulting template makes for a smaller # configuration. # ''' # # TODO # return True @command.skill_level('administrator') @command.completers_repeating(compl.call(cib_factory.prim_id_list)) @command.name('weak-bond') @command.alias('weak_bond') def do_weak_bond(self, context, *nodes): ''' Create a 'weak' colocation: Colocating a non-sequential resource set with a dummy resource which is not monitored creates, in effect, a colocation which does not imply any internal relationship between resources. ''' if not cib_factory.is_cib_sane(): return False if len(nodes) < 2: context.fatal_error("Need at least two arguments") for node in nodes: obj = cib_factory.find_object(node) if not obj: context.fatal_error("Object not found: %s" % (node)) if not xmlutil.is_primitive(obj.node): context.fatal_error("Object not primitive: %s" % (node)) constraint_name = self.make_unique_name('place-constraint-') dummy_name = self.make_unique_name('place-dummy-') print "Create weak bond / independent colocation" print "The following elements will be created:" print " * Colocation constraint, ID: %s" % (constraint_name) print " * Dummy resource, ID: %s" % (dummy_name) if not utils.can_ask() or utils.ask("Create resources?"): cib_factory.create_object('primitive', dummy_name, 'ocf:heartbeat:Dummy') colo = ['colocation', constraint_name, 'inf:', '('] colo.extend(nodes) colo.append(')') colo.append(dummy_name) cib_factory.create_object(*colo) def make_unique_name(self, prefix): n = 0 while n < 1000: n += 1 name = "%s%s" % (prefix, n) for _id in cib_factory.id_list(): if name == _id.lower(): continue return name raise ValueError("Failed to generate unique resource ID with prefix '%s'" % (prefix))