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)
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: l = crm_report.pelist(long=("v" in opt_l))
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: l = crm_report().pelist(long=("v" in opt_l))
class CibShadow(command.UI): ''' CIB shadow management class ''' name = "cib" extcmd = ">/dev/null </dev/null crm_shadow" extcmd_stdout = "</dev/null crm_shadow" def requires(self): if not utils.is_program('crm_shadow'): no_prog_err('crm_shadow') return False return True @command.level(ui_cibstatus.CibStatusUI) def do_cibstatus(self): pass @command.skill_level('administrator') @command.completers_repeating(compl.null, compl.choice(_NEWARGS)) def do_new(self, context, *args): "usage: new [<shadow_cib>] [withstatus] [force] [empty]" argl = list(args) opt_l = utils.fetch_opts(argl, ["force", "--force", "withstatus", "empty"]) if len(argl) > 1: context.fatal_error("Unexpected argument(s): " + ','.join(argl)) name = None if argl: name = argl[0] if not utils.is_filename_sane(name): context.fatal_error("Bad filename: " + name) if name in (vars.tmp_cib_prompt, vars.live_cib_prompt): context.fatal_error("Shadow name '%s' is not allowed" % (name)) del argl[0] vars.tmp_cib = False else: fd, fname = tmpfiles.create(dir=xmlutil.cib_shadow_dir(), prefix="shadow.crmsh_") name = os.path.basename(fname).replace("shadow.", "") vars.tmp_cib = True if "empty" in opt_l: new_cmd = "%s -e '%s'" % (self.extcmd, name) else: new_cmd = "%s -c '%s'" % (self.extcmd, name) if vars.tmp_cib or config.core.force or "force" in opt_l or "--force" in opt_l: new_cmd = "%s --force" % new_cmd if utils.ext_cmd(new_cmd) == 0: context.info("%s shadow CIB created" % name) self.do_use(context, name) if "withstatus" in opt_l: cib_status.load("shadow:%s" % name) def _find_pe(self, context, infile): 'Find a pe input' for p in ("%s/%s", "%s/%s.bz2", "%s/pe-*-%s.bz2"): fl = glob.glob(p % (config.path.pe_state_dir, infile)) if fl: break if not fl: context.fatal_error("no %s pe input file" % infile) if len(fl) > 1: context.fatal_error("more than one %s pe input file: %s" % (infile, ' '.join(fl))) if not fl[0]: context.fatal_error("bad %s pe input file" % infile) return fl[0] @command.skill_level('administrator') @command.completers(compl.null, compl.shadows) def do_import(self, context, infile, name=None): "usage: import {<file>|<number>} [<shadow>]" if name and not utils.is_filename_sane(name): context.fatal_error("Bad filename: " + name) # where's the input? if not os.access(infile, os.F_OK): if "/" in infile: context.fatal_error(str(infile) + ": no such file") infile = self._find_pe(context, infile) if not name: name = os.path.basename(infile).replace(".bz2", "") if not xmlutil.pe2shadow(infile, name): context.fatal_error("Error copying PE file to shadow: %s -> %s" % (infile, name)) # use the shadow and load the status from there return self.do_use(context, name, "withstatus") @command.skill_level('administrator') @command.completers(compl.shadows) def do_delete(self, context, name): "usage: delete <shadow_cib>" if not utils.is_filename_sane(name): context.fatal_error("Bad filename: " + name) if utils.get_cib_in_use() == name: context.fatal_error("%s shadow CIB is in use" % name) if utils.ext_cmd("%s -D '%s' --force" % (self.extcmd, name)) == 0: context.info("%s shadow CIB deleted" % name) else: context.fatal_error("failed to delete %s shadow CIB" % name) @command.skill_level('administrator') @command.completers(compl.shadows) def do_reset(self, context, name): "usage: reset <shadow_cib>" if not utils.is_filename_sane(name): context.fatal_error("Bad filename: " + name) if utils.ext_cmd("%s -r '%s'" % (self.extcmd, name)) == 0: context.info("copied live CIB to %s" % name) else: context.fatal_error("failed to copy live CIB to %s" % name) @command.skill_level('administrator') @command.wait @command.completers(compl.shadows) def do_commit(self, context, name=None): "usage: commit [<shadow_cib>]" if name and not utils.is_filename_sane(name): context.fatal_error("Bad filename: " + name) if not name: name = utils.get_cib_in_use() if not name: context.fatal_error("There is nothing to commit") if utils.ext_cmd("%s -C '%s' --force" % (self.extcmd, name)) == 0: context.info("committed '%s' shadow CIB to the cluster" % name) else: context.fatal_error("failed to commit the %s shadow CIB" % name) if vars.tmp_cib: self._use('', '') @command.skill_level('administrator') def do_diff(self, context): "usage: diff" rc, s = utils.get_stdout(utils.add_sudo("%s -d" % self.extcmd_stdout)) utils.page_string(s) @command.skill_level('administrator') def do_list(self, context): "usage: list" if options.regression_tests: for t in xmlutil.listshadows(): print t else: utils.multicolumn(xmlutil.listshadows()) def _use(self, name, withstatus): # Choose a shadow cib for further changes. If the name # provided is empty, then choose the live (cluster) cib. # Don't allow ' in shadow names if not name or name == "live": if withstatus: cib_status.load("live") if vars.tmp_cib: utils.ext_cmd("%s -D '%s' --force" % (self.extcmd, utils.get_cib_in_use())) vars.tmp_cib = False utils.clear_cib_in_use() else: utils.set_cib_in_use(name) if withstatus: cib_status.load("shadow:%s" % name) return True @command.skill_level('administrator') @command.completers(compl.join(compl.shadows, compl.choice(['live'])), compl.choice(['withstatus'])) def do_use(self, context, name='', withstatus=''): "usage: use [<shadow_cib>] [withstatus]" # check the name argument if name and not utils.is_filename_sane(name): context.fatal_error("Bad filename: " + name) if name and name != "live": if not os.access(xmlutil.shadowfile(name), os.F_OK): context.fatal_error("%s: no such shadow CIB" % name) if withstatus and withstatus != "withstatus": context.fatal_error("Expected 'withstatus', got '%s'" % (withstatus)) # If invoked from configure # take special precautions if not context.previous_level_is("cibconfig"): return self._use(name, withstatus) if not cib_factory.has_cib_changed(): ret = self._use(name, withstatus) # new CIB: refresh the CIB factory cib_factory.refresh() return ret saved_cib = utils.get_cib_in_use() self._use(name, '') # don't load the status yet if not cib_factory.is_current_cib_equal(silent=True): # user made changes and now wants to switch to a # different and unequal CIB; we refuse to cooperate context.error_message( "the requested CIB is different from the current one") if config.core.force: context.info("CIB overwrite forced") elif not utils.ask( "All changes will be dropped. Do you want to proceed?"): self._use(saved_cib, '') # revert to the previous CIB return False return self._use(name, withstatus) # now load the status too