Hello community, here is the log from the commit of package crmsh for openSUSE:Factory checked in at 2016-05-17 17:15:00 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/crmsh (Old) and /work/SRC/openSUSE:Factory/.crmsh.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "crmsh" Changes: -------- --- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes 2016-05-05 12:12:22.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.crmsh.new/crmsh.changes 2016-05-17 17:15:03.000000000 +0200 @@ -1,0 +2,10 @@ +Thu May 12 08:40:54 UTC 2016 - kgronl...@suse.com + +- Update to version 2.2.0+git.1462967444.169c554: + + high: parse: Support for event-driven alerts (fate#320855) (#136) + + high: utils: Avoid deadlock if DC changes during idle wait (bsc#978480) + + medium: ui_resource: Add force argument to resource cleanup (bsc#979420) + + medium: ui_resource: Show utilization in output from crm resource scores + + high: ui_resource: Improved resource move/clear/locate commands + +------------------------------------------------------------------- Old: ---- crmsh-2.2.0+git.1462285059.d79cd0d.tar.bz2 New: ---- crmsh-2.2.0+git.1462967444.169c554.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ crmsh.spec ++++++ --- /var/tmp/diff_new_pack.qvK0Pp/_old 2016-05-17 17:15:04.000000000 +0200 +++ /var/tmp/diff_new_pack.qvK0Pp/_new 2016-05-17 17:15:04.000000000 +0200 @@ -32,13 +32,13 @@ %{!?python_sitelib: %define python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} -%define version_unconverted 2.2.0+git.1462285059.d79cd0d +%define version_unconverted 2.2.0+git.1462967444.169c554 Name: crmsh Summary: High Availability cluster command-line interface License: GPL-2.0+ Group: %{pkg_group} -Version: 2.2.0+git.1462285059.d79cd0d +Version: 2.2.0+git.1462967444.169c554 Release: 0 Url: http://crmsh.github.io Source0: %{name}-%{version}.tar.bz2 ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.qvK0Pp/_old 2016-05-17 17:15:04.000000000 +0200 +++ /var/tmp/diff_new_pack.qvK0Pp/_new 2016-05-17 17:15:04.000000000 +0200 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">git://github.com/ClusterLabs/crmsh.git</param> - <param name="changesrevision">d79cd0db97b99ccb6d4dbbe9797917c18a4982aa</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">169c5549accf42af8b89f6cc4d574c6c219768b1</param></service></servicedata> \ No newline at end of file ++++++ crmsh-2.2.0+git.1462285059.d79cd0d.tar.bz2 -> crmsh-2.2.0+git.1462967444.169c554.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/.gitignore new/crmsh-2.2.0+git.1462967444.169c554/.gitignore --- old/crmsh-2.2.0+git.1462285059.d79cd0d/.gitignore 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/.gitignore 1970-01-01 01:00:00.000000000 +0100 @@ -1,19 +0,0 @@ -*.pyc -*~ -#*.*# -.#* -doc/website-v1/gen -Makefile.in -autom4te.cache -patches/* - -# Tool specific files -.README.md.html -.*.*~ -.project -.settings -.pydevproject - -contrib/build/ -contrib/dist/ -contrib/pygments_crmsh_lexers.egg-info/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/.hgignore new/crmsh-2.2.0+git.1462967444.169c554/.hgignore --- old/crmsh-2.2.0+git.1462285059.d79cd0d/.hgignore 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/.hgignore 1970-01-01 01:00:00.000000000 +0100 @@ -1,7 +0,0 @@ -syntax: glob - -*.pyc -*~ -#*.*# -doc/gen - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/Makefile.am new/crmsh-2.2.0+git.1462967444.169c554/Makefile.am --- old/crmsh-2.2.0+git.1462285059.d79cd0d/Makefile.am 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/Makefile.am 2016-05-12 10:40:53.000000000 +0200 @@ -73,11 +73,11 @@ install-exec-local: -mkdir -p $(DESTDIR)$(pkgpythondir) $(PYTHON) $(srcdir)/setup.py install \ - --root $(DESTDIR) \ + --root $(DESTDIR)/// \ $(python_prefix) \ --record $(DESTDIR)$(pkgpythondir)/install_files.txt \ --verbose - $(INSTALL) -d -m 770 $(DESTDIR)/$(CRM_CACHE_DIR) + $(INSTALL) -d -m 770 $(DESTDIR)$(CRM_CACHE_DIR) uninstall-local: cat $(DESTDIR)$(pkgpythondir)/install_files.txt | xargs rm -rf diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/cibconfig.py new/crmsh-2.2.0+git.1462967444.169c554/crmsh/cibconfig.py --- old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/cibconfig.py 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/crmsh/cibconfig.py 2016-05-12 10:40:53.000000000 +0200 @@ -47,7 +47,7 @@ from .cliformat import get_score, nvpairs2list, abs_pos_score, cli_acl_roleref, nvpair_format from .cliformat import cli_nvpair, cli_acl_rule, rsc_set_constraint, get_kind, head_id_format from .cliformat import cli_operations, simple_rsc_constraint, cli_rule, cli_format -from .cliformat import cli_acl_role, cli_acl_permission +from .cliformat import cli_acl_role, cli_acl_permission, cli_path def show_unrecognized_elems(cib_elem): @@ -657,6 +657,7 @@ 'rsc_location': 'location', 'fencing-topology': 'fencing', 'tags': 'tag', + 'alerts': 'alert', } idless = set(['operations', 'fencing-topology']) @@ -2018,6 +2019,53 @@ for c in self.node.iterchildren() if not is_comment(c)]) +class CibAlert(CibObject): + ''' + Alert objects + + TODO: check_sanity, repr_gv + + FIXME: display instance / meta attributes, description + + ''' + set_names = { + "instance_attributes": "attributes", + "meta_attributes": "meta", + } + + def _repr_cli_head(self, fmt): + ret = [clidisplay.keyword(self.obj_type), + clidisplay.ident(self.obj_id), + cli_path(self.node.get('path'))] + return ' '.join(ret) + + def _repr_cli_child(self, c, format_mode): + if c.tag in self.set_names: + return self._attr_set_str(c) + elif c.tag == "recipient": + r = ["to"] + complex = self._is_complex() + if complex: + r.append('{') + r.append(cli_path(c.get('value'))) + for subset in c.xpath('instance_attributes|meta_attributes'): + r.append(self._attr_set_str(subset)) + if complex: + r.append('}') + return ' '.join(r) + + def _is_complex(self): + ''' + True if this alert is ambiguous wrt meta attributes in recipient tags + ''' + children = [c.tag for c in self.node.xpath('recipient|instance_attributes|meta_attributes')] + ri = children.index('recipient') + if ri < 0: + return False + children = children[ri+1:] + return 'instance_attributes' in children or 'meta_attributes' in children + + # ################################################################ @@ -2062,6 +2110,7 @@ "acl_target": ("acl_target", CibAcl, "acls"), "acl_group": ("acl_group", CibAcl, "acls"), "tag": ("tag", CibTag, "tags"), + "alert": ("alert", CibAlert, "alerts"), } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/cliformat.py new/crmsh-2.2.0+git.1462967444.169c554/crmsh/cliformat.py --- old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/cliformat.py 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/crmsh/cliformat.py 2016-05-12 10:40:53.000000000 +0200 @@ -250,6 +250,10 @@ return rsc +def cli_path(p): + return clidisplay.attr_value(quote_wrap(p)) + + def boolean_maybe(v): "returns True/False or None" if v is None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/cmd_status.py new/crmsh-2.2.0+git.1462967444.169c554/crmsh/cmd_status.py --- old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/cmd_status.py 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/crmsh/cmd_status.py 2016-05-12 10:40:53.000000000 +0200 @@ -3,7 +3,7 @@ # See COPYING for license information. import re -import clidisplay +from . import clidisplay from . import utils _crm_mon = None @@ -125,7 +125,6 @@ Calls crm_verify -LV; ptest -L -VVVV ''' from . import config - from . import clidisplay if "ptest" in config.core.ptest: cmd1 = "crm_verify -LV; %s -L -VVVV" % (config.core.ptest) else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/constants.py new/crmsh-2.2.0+git.1462967444.169c554/crmsh/constants.py --- old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/constants.py 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/crmsh/constants.py 2016-05-12 10:40:53.000000000 +0200 @@ -218,6 +218,9 @@ ms_meta_attributes = ( "master-max", "master-node-max", "description", ) +alert_meta_attributes = ( + "timeout", "timestamp-format" +) trace_ra_attr = "trace_ra" score_types = {'advisory': '0', 'mandatory': 'INFINITY'} boolean_ops = ('or', 'and') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/parse.py new/crmsh-2.2.0+git.1462967444.169c554/crmsh/parse.py --- old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/parse.py 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/crmsh/parse.py 2016-05-12 10:40:53.000000000 +0200 @@ -23,6 +23,7 @@ _DISPATCH_RE = re.compile(r'[a-z0-9_]+$', re.IGNORECASE) _DESC_RE = re.compile(r'description=(.+)$', re.IGNORECASE) _ATTR_RE = re.compile(r'\$?([^=]+)=(.*)$') +_ALERT_PATH_RE = re.compile(r'(.*)$') _RESOURCE_RE = re.compile(r'([a-z_#$][^=]*)$', re.IGNORECASE) _IDSPEC_RE = re.compile(r'(\$id-ref|\$id)=(.*)$', re.IGNORECASE) _ID_RE = re.compile(r'\$id=(.*)$', re.IGNORECASE) @@ -393,7 +394,7 @@ tokens.append(self.match_any()) return tokens - def match_attr_list(self, name, tag, allow_empty=True): + def match_attr_list(self, name, tag, allow_empty=True, terminator=None): """ matches [$id=<id>] [<score>:] <n>=<v> <n>=<v> ... | $id-ref=<id-ref> if matchname is False, matches: @@ -414,12 +415,12 @@ if self.try_match(_SCORE_RE): score = self.matched(1) rules = self.match_rules() - values = self.match_nvpairs(minpairs=0) + values = self.match_nvpairs(minpairs=0, terminator=terminator) if (allow_empty, xmlid, score, len(rules), len(values)) == (False, None, None, 0, 0): return None return xmlutil.attributes(tag, rules, values, xmlid=xmlid, score=score) - def match_attr_lists(self, name_map, implicit_initial=None): + def match_attr_lists(self, name_map, implicit_initial=None, terminator=None): """ generator which matches attr_lists name_map: maps CLI name to XML name @@ -427,16 +428,17 @@ to_match = '|'.join(name_map.keys()) if self.try_match(to_match): name = self.matched(0).lower() - yield self.match_attr_list(name, name_map[name]) + yield self.match_attr_list(name, name_map[name], terminator=terminator) elif implicit_initial is not None: attrs = self.match_attr_list(implicit_initial, name_map[implicit_initial], - allow_empty=False) + allow_empty=False, + terminator=terminator) if attrs is not None: yield attrs while self.try_match(to_match): name = self.matched(0).lower() - yield self.match_attr_list(name, name_map[name]) + yield self.match_attr_list(name, name_map[name], terminator=terminator) def match_rules(self): '''parse rule definitions''' @@ -585,7 +587,7 @@ else: return ['score-attribute', score] - def match_arguments(self, out, name_map, implicit_initial=None): + def match_arguments(self, out, name_map, implicit_initial=None, terminator=None): """ [<name> attr_list] [operations id_spec] @@ -612,12 +614,13 @@ if t in oplist: self.match_operations(out, t == 'operations') else: - for attr_list in self.match_attr_lists(name_map): + for attr_list in self.match_attr_lists(name_map, terminator=terminator): out.append(attr_list) elif initial: initial = False for attr_list in self.match_attr_lists(name_map, - implicit_initial=implicit_initial): + implicit_initial=implicit_initial, + terminator=terminator): out.append(attr_list) else: break @@ -1354,6 +1357,57 @@ return e +@parser_for('alert') +def parse_alert(self, cmd): + """ + <alerts> + <alert id=ID path=PATH> + <recipient id=RID value=VALUE/> + <meta_attributes ..> + <instance_attributes ..> + ... + + meta attributes "timeout", "tstamp_format" + </tag> + + alert ID PATH [attributes ...] [meta ...] [to [{] recipient [}] ...] + recipient :: PATH [attributes ...] [meta ...] + """ + self.begin(cmd, min_args=2) + self.match('alert') + alertid = self.match_identifier() + path = self.match(_ALERT_PATH_RE, errmsg="Expected path") + out = xmlutil.new('alert', id=alertid, path=path) + desc = self.try_match_description() + if desc is not None: + out.attrib['description'] = desc + rcount = 1 + while self.has_tokens(): + if self.current_token() in ('attributes', 'meta'): + self.match_arguments(out, {'attributes': 'instance_attributes', + 'meta': 'meta_attributes'}, + terminator=['attributes', 'meta', 'to']) + continue + self.match('to') + rid = '%s-recipient-%s' % (alertid, rcount) + rcount += 1 + bracer = self.try_match('{') + elem = xmlutil.new('recipient', id=rid, value=self.match_any()) + desc = self.try_match_description() + terminators = ['attributes', 'meta', 'to'] + if bracer: + terminators.append('}') + if desc is not None: + elem.attrib['description'] = desc + self.match_arguments(elem, {'attributes': 'instance_attributes', + 'meta': 'meta_attributes'}, + terminator=terminators) + if bracer: + self.match('}') + out.append(elem) + return out + + class ResourceSet(object): ''' Constraint resource set parser. Parses sth like: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/ui_configure.py new/crmsh-2.2.0+git.1462967444.169c554/crmsh/ui_configure.py --- old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/ui_configure.py 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/crmsh/ui_configure.py 2016-05-12 10:40:53.000000000 +0200 @@ -847,6 +847,10 @@ def do_tag(self, context, *args): return self.__conf_object(context.get_command_name(), *args) + @command.skill_level('administrator') + def do_alert(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): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/ui_resource.py new/crmsh-2.2.0+git.1462967444.169c554/crmsh/ui_resource.py --- old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/ui_resource.py 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/crmsh/ui_resource.py 2016-05-12 10:40:53.000000000 +0200 @@ -150,13 +150,14 @@ return True -def cleanup_resource(rsc, node=''): +def cleanup_resource(rsc, node='', force=False): if not utils.is_name_sane(rsc) or not utils.is_name_sane(node): return False + forces = " -f" if force else "" if not node: - rc = utils.ext_cmd(RscMgmt.rsc_cleanup_all % (rsc)) == 0 + rc = utils.ext_cmd((RscMgmt.rsc_cleanup_all % (rsc)) + forces) == 0 else: - rc = utils.ext_cmd(RscMgmt.rsc_cleanup % (rsc, node)) == 0 + rc = utils.ext_cmd((RscMgmt.rsc_cleanup % (rsc, node)) + forces) == 0 return rc @@ -313,12 +314,20 @@ def do_scores(self, context): "usage: scores" if utils.is_program('crm_simulate'): - utils.ext_cmd('crm_simulate -sL') + utils.ext_cmd('crm_simulate -sUL') elif utils.is_program('ptest'): - utils.ext_cmd('ptest -sL') + utils.ext_cmd('ptest -sUL') else: context.fatal_error("Need crm_simulate or ptest in path to display scores") + @command.completers(compl.resources) + def do_locate(self, context, *resources): + "usage: locate <rsc> [<rsc> ...]" + if len(resources) == 0: + context.error("Expected at least one resource as argument") + for rsc in resources: + utils.ext_cmd("crm_resource --resource '%s' --locate" % (rsc)) + @command.wait @command.completers(compl.resources) def do_demote(self, context, rsc): @@ -340,23 +349,28 @@ "usage: unmanage <rsc>" return self._commit_meta_attr(context, rsc, "is-managed", "false") - @command.alias('move') + @command.alias('migrate') @command.skill_level('administrator') @command.wait @command.completers_repeating(compl.resources, compl.nodes, compl.choice(['reboot', 'forever', 'force'])) - def do_migrate(self, context, rsc, *args): - """usage: migrate <rsc> [<node>] [<lifetime>] [force]""" + def do_move(self, context, rsc, *args): + """usage: move <rsc> [<node>] [<lifetime>] [force]""" if not utils.is_name_sane(rsc): return False node = None argl = list(args) - force = "force" in utils.fetch_opts(argl, ["force"]) + force = "force" in utils.fetch_opts(argl, ["force"]) or config.core.force lifetime = utils.fetch_lifetime_opt(argl) if len(argl) > 0: node = argl[0] if not xmlutil.is_our_node(node): context.fatal_error("Not our node: " + node) + + if context.get_command_name() == 'move': + if not node and not force: + context.fatal_error("No target node: Move requires either a target node or 'force'") + opts = '' if node: opts = "--node='%s'" % node @@ -364,7 +378,13 @@ opts = "%s --lifetime='%s'" % (opts, lifetime) if force or config.core.force: opts = "%s --force" % opts - return utils.ext_cmd(self.rsc_migrate % (rsc, opts)) == 0 + rc = utils.ext_cmd(self.rsc_migrate % (rsc, opts)) + if rc == 0: + if node: + common_info("Move constraint created for %s to %s" % (rsc, node)) + else: + common_info("Move constraint created for %s" % (rsc)) + return rc == 0 @command.skill_level('administrator') @command.wait @@ -375,7 +395,7 @@ return False node = None argl = list(args) - force = "force" in utils.fetch_opts(argl, ["force"]) + force = "force" in utils.fetch_opts(argl, ["force"]) or config.core.force lifetime = utils.fetch_lifetime_opt(argl) if len(argl) > 0: node = argl[0] @@ -386,28 +406,40 @@ opts = "--node='%s'" % node if lifetime: opts = "%s --lifetime='%s'" % (opts, lifetime) - if force or config.core.force: + if force: opts = "%s --force" % opts - return utils.ext_cmd(self.rsc_ban % (rsc, opts)) == 0 + rc = utils.ext_cmd(self.rsc_ban % (rsc, opts)) + if rc == 0: + if node: + common_info("Ban constraint created for %s on %s" % (rsc, node)) + else: + common_info("Ban constraint created for %s" % (rsc)) + return rc == 0 - @command.alias('unmove', 'unban') + @command.alias('unmove', 'unban', 'unmigrate') @command.skill_level('administrator') @command.wait @command.completers(compl.resources) - def do_unmigrate(self, context, rsc): - "usage: unmigrate <rsc>" + def do_clear(self, context, rsc): + "usage: clear <rsc>" if not utils.is_name_sane(rsc): return False - return utils.ext_cmd(self.rsc_unmigrate % rsc) == 0 + rc = utils.ext_cmd(self.rsc_unmigrate % rsc) + if rc == 0: + common_info("Removed migration constraints for %s" % (rsc)) + return rc == 0 @command.skill_level('administrator') @command.wait @command.completers(compl.resources, compl.nodes) - def do_cleanup(self, context, resource, node=''): - "usage: cleanup <rsc> [<node>]" + def do_cleanup(self, context, resource, *args): + "usage: cleanup <rsc> [<node>] [force]" # Cleanup a resource on a node. Omit node to cleanup on # all live nodes. - return cleanup_resource(resource, node) + argl = list(args) + force = "force" in utils.fetch_opts(argl, ["force"]) or config.core.force + node = argl[0] if len(argl) > 0 else '' + return cleanup_resource(resource, node, force=force) @command.wait @command.completers(compl.resources, compl.nodes) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/utils.py new/crmsh-2.2.0+git.1462967444.169c554/crmsh/utils.py --- old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/utils.py 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/crmsh/utils.py 2016-05-12 10:40:53.000000000 +0200 @@ -619,13 +619,17 @@ if 0 < delaymsec: common_info("The crmd-transition-delay is configured. Waiting %d msec before check DC status." % delaymsec) time.sleep(delaymsec / 1000) - cmd = "crmadmin -S %s" % dc cnt = 0 output_started = 0 init_sleep = 0.25 max_sleep = 1.00 sleep_time = init_sleep while True: + dc = get_dc() + if not dc: + common_warn("DC lost during wait") + return False + cmd = "crmadmin -S %s" % dc rc, s = get_stdout(add_sudo(cmd)) if not s.startswith("Status"): common_warn("%s unexpected output: %s (exit code: %d)" % diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/xmlutil.py new/crmsh-2.2.0+git.1462967444.169c554/crmsh/xmlutil.py --- old/crmsh-2.2.0+git.1462285059.d79cd0d/crmsh/xmlutil.py 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/crmsh/xmlutil.py 2016-05-12 10:40:53.000000000 +0200 @@ -687,7 +687,9 @@ "op": ("name", "interval"), "rule": ("score", "score-attribute", "role"), "expression": ("attribute", "operation", "value"), - "fencing-level": ("target", "devices")}) + "fencing-level": ("target", "devices"), + "alert": ("path",), + "recipient": ("value",)}) def add_comment(e, s): @@ -833,7 +835,8 @@ ['rsc_location', 'rsc_colocation', 'rsc_order'], ['rsc_ticket', 'fencing-topology'], 'cluster_property_set', 'rsc_defaults', 'op_defaults', - 'acl_role', ['acl_target', 'acl_group', 'acl_user']) + 'acl_role', ['acl_target', 'acl_group', 'acl_user'], + 'alert') _sort_cli_order = make_sort_map('node', 'rsc_template', 'primitive', 'group', @@ -842,7 +845,8 @@ ['location', 'colocation', 'collocation', 'order'], ['rsc_ticket', 'fencing_topology'], 'property', 'rsc_defaults', 'op_defaults', - 'role', ['acl_target', 'acl_group', 'user']) + 'role', ['acl_target', 'acl_group', 'user'], + 'alert') _SORT_LAST = 1000 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/doc/crm.8.adoc new/crmsh-2.2.0+git.1462967444.169c554/doc/crm.8.adoc --- old/crmsh-2.2.0+git.1462285059.d79cd0d/doc/crm.8.adoc 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/doc/crm.8.adoc 2016-05-12 10:40:53.000000000 +0200 @@ -942,6 +942,43 @@ add <node> ............... +[[cmdhelp_cluster_copy,Copy file to other cluster nodes]] +==== `copy` + +Copy file to other cluster nodes. + +Copies the given file to all other nodes unless given a +list of nodes to copy to as argument. + +Usage: +............... +copy <filename> [nodes ...] +............... + +Example: +............... +copy /etc/motd +............... + +[[cmdhelp_cluster_diff,Diff file across cluster]] +==== `diff` + +Displays the difference, if any, between a given file +on different nodes. If the second argument is `--checksum`, +a checksum of the file will be calculated and displayed for +each node. + +Usage: +............... +diff <file> [--checksum] [nodes...] +............... + +Example: +............... +diff /etc/crm/crm.conf node2 +diff /etc/resolv.conf --checksum +............... + [[cmdhelp_cluster_health,Cluster health check]] ==== `health` @@ -991,24 +1028,6 @@ run "cat /proc/uptime" ............... -[[cmdhelp_cluster_copy,Copy file to other cluster nodes]] -==== `copy` - -Copy file to other cluster nodes. - -Copies the given file to all other nodes unless given a -list of nodes to copy to as argument. - -Usage: -............... -copy <filename> [nodes ...] -............... - -Example: -............... -copy /etc/motd -............... - [[cmdhelp_cluster_start,Start cluster services]] ==== `start` @@ -1054,25 +1073,6 @@ wait_for_startup ........ -[[cmdhelp_cluster_diff,Diff file across cluster]] -==== `diff` - -Displays the difference, if any, between a given file -on different nodes. If the second argument is `--checksum`, -a checksum of the file will be calculated and displayed for -each node. - -Usage: -............... -diff <file> [--checksum] [nodes...] -............... - -Example: -............... -diff /etc/crm/crm.conf node2 -diff /etc/resolv.conf --checksum -............... - [[cmdhelp_script,Cluster script management]] === `script` - Cluster script management @@ -1093,6 +1093,45 @@ function through the usual SSH channels used for system maintenance, requiring no additional software to be installed or maintained. +[[cmdhelp_script_json,JSON API for cluster scripts]] +==== `json` + +This command provides a JSON API for the cluster scripts, intended for +use in user interface tools that want to interact with the cluster via +scripts. + +The command takes a single argument, which should be a JSON array with +the first member identifying the command to perform. + +The output is line-based: Commands that return multiple results will +return them line-by-line, ending with a terminator value: "end". + +When providing parameter values to this command, they should be +provided as nested objects, so +virtual-ip:ip=192.168.0.5+ on the +command line becomes the JSON object ++{"virtual-ip":{"ip":"192.168.0.5"}}+. + +API: +........ +["list"] +=> [{name, shortdesc, category}] + +["show", <name>] +=> [{name, shortdesc, longdesc, category, <<steps>>}] + +<<steps>> := [{name, shortdesc], longdesc, required, parameters, steps}] + +<<params>> := [{name, shortdesc, longdesc, required, unique, advanced, + type, value, example}] + +["verify", <name>, <<values>>] +=> [{shortdesc, longdesc, text, nodes}] + +["run", <name>, <<values>>] +=> [{shortdesc, rc, output|error}] +........ + + [[cmdhelp_script_list,List available scripts]] ==== `list` @@ -1115,6 +1154,32 @@ list all names ............ +[[cmdhelp_script_run,Run the script]] +==== `run` + +Given a list of parameter values, this command will execute the +actions specified by the cluster script. The format for the parameter +values is the same as for the `verify` command. + +Can optionally take at least two parameters: +* `nodes=<nodes>`: List of nodes that the script runs over +* `dry_run=yes|no`: If set, the script will not perform any modifications. + +Additional parameters may be available depending on the script. + +Use the `show` command to see what parameters are available. + +Usage: +............. +run <script> [args...] +............. + +Example: +............. +run apache install=true +run sbd id=sbd-1 node=node1 sbd_device=/dev/disk/by-uuid/F00D-CAFE +............. + [[cmdhelp_script_show,Describe the script]] ==== `show` @@ -1151,71 +1216,6 @@ verify sbd id=sbd-1 node=node1 sbd_device=/dev/disk/by-uuid/F00D-CAFE ............ -[[cmdhelp_script_run,Run the script]] -==== `run` - -Given a list of parameter values, this command will execute the -actions specified by the cluster script. The format for the parameter -values is the same as for the `verify` command. - -Can optionally take at least two parameters: -* `nodes=<nodes>`: List of nodes that the script runs over -* `dry_run=yes|no`: If set, the script will not perform any modifications. - -Additional parameters may be available depending on the script. - -Use the `show` command to see what parameters are available. - -Usage: -............. -run <script> [args...] -............. - -Example: -............. -run apache install=true -run sbd id=sbd-1 node=node1 sbd_device=/dev/disk/by-uuid/F00D-CAFE -............. - -[[cmdhelp_script_json,JSON API for cluster scripts]] -==== `json` - -This command provides a JSON API for the cluster scripts, intended for -use in user interface tools that want to interact with the cluster via -scripts. - -The command takes a single argument, which should be a JSON array with -the first member identifying the command to perform. - -The output is line-based: Commands that return multiple results will -return them line-by-line, ending with a terminator value: "end". - -When providing parameter values to this command, they should be -provided as nested objects, so +virtual-ip:ip=192.168.0.5+ on the -command line becomes the JSON object -+{"virtual-ip":{"ip":"192.168.0.5"}}+. - -API: -........ -["list"] -=> [{name, shortdesc, category}] - -["show", <name>] -=> [{name, shortdesc, longdesc, category, <<steps>>}] - -<<steps>> := [{name, shortdesc], longdesc, required, parameters, steps}] - -<<params>> := [{name, shortdesc, longdesc, required, unique, advanced, - type, value, example}] - -["verify", <name>, <<values>>] -=> [{shortdesc, longdesc, text, nodes}] - -["run", <name>, <<values>>] -=> [{shortdesc, rc, output|error}] -........ - - [[cmdhelp_corosync,Corosync management]] === `corosync` - Corosync management @@ -1609,6 +1609,19 @@ All (or almost all) commands are implemented with the CRM tools such as `crm_resource(8)`. +[[cmdhelp_resource_ban,ban a resource from a node]] +==== `ban` + +Ban a resource from running on a certain node. If no node is given +as argument, the resource is banned from the current location. + +See `move` for details on other arguments. + +Usage: +............... +ban <rsc> [<node>] [<lifetime>] [force] +............... + [[cmdhelp_resource_cleanup,cleanup resource status]] ==== `cleanup` @@ -1616,11 +1629,39 @@ temporarily failed. If a node is omitted, cleanup on all nodes. If there are many nodes, the command may take a while. ++(Pacemaker 1.1.14)+ Pass force to cleanup the resource itself, +otherwise the cleanup command will apply to the parent resource (if +any). + +Usage: +............... +cleanup <rsc> [<node>] [force] +............... + +[[cmdhelp_resource_clear,Clear any relocation constraint]] +==== `clear` (`unmove`, `unmigrate`, `unban`) + +Remove any relocation constraint created by +the `move`, `migrate` or `ban` command. + Usage: ............... -cleanup <rsc> [<node>] +clear <rsc> +unmigrate <rsc> +unban <rsc> ............... +[[cmdhelp_resource_constraints,Show constraints affecting a resource]] +==== `constraints` + +Display the location and colocation constraints affecting the +resource. + +Usage: +................ +constraints <rsc> +................ + [[cmdhelp_resource_demote,demote a master-slave resource]] ==== `demote` @@ -1648,6 +1689,16 @@ failcount fs_0 delete node2 ............... +[[cmdhelp_resource_locate,show the location of resources]] +==== `locate` + +Show the current location of one or more resources. + +Usage: +............... +locate [<rsc> ...] +............... + [[cmdhelp_resource_maintenance,Enable/disable per-resource maintenance mode]] ==== `maintenance` @@ -1698,33 +1749,33 @@ meta ip_0 set target-role stopped ............... -[[cmdhelp_resource_migrate,migrate a resource to another node]] -==== `migrate` (`move`) +[[cmdhelp_resource_move,Move a resource to another node]] +==== `move` (`migrate`) + +Move a resource away from its current location. -Migrate a resource to a different node. If node is left out, the -resource is migrated by creating a constraint which prevents it from -running on the current node. Additionally, you may specify a -lifetime for the constraint---once it expires, the location -constraint will no longer be active. +If the destination node is left out, the resource is migrated by +creating a constraint which prevents it from running on the current +node. For this type of constraint to be created, the +force+ argument +is required. + +A lifetime may be given for the constraint. Once it expires, the +location constraint will no longer be active. Usage: ............... -migrate <rsc> [<node>] [<lifetime>] [force] +move <rsc> [<node>] [<lifetime>] [force] ............... -[[cmdhelp_resource_ban,ban a resource from a node]] -==== `ban` - -Ban a resource from running on a certain node. If no node is given -as argument, the resource is banned from the current location. +[[cmdhelp_resource_operations,Show active resource operations]] +==== `operations` -See `migrate` for details on other arguments. +Show active operations, optionally filtered by resource and node. Usage: -............... -ban <rsc> [<node>] [<lifetime>] [force] -............... - +................ +operations [<rsc>] [<node>] +................ [[cmdhelp_resource_param,manage a parameter of a resource]] ==== `param` @@ -1811,27 +1862,6 @@ # ............... -[[cmdhelp_resource_constraints,Show constraints affecting a resource]] -==== `constraints` - -Display the location and colocation constraints affecting the -resource. - -Usage: -................ -constraints <rsc> -................ - -[[cmdhelp_resource_operations,Show active resource operations]] -==== `operations` - -Show active operations, optionally filtered by resource and node. - -Usage: -................ -operations [<rsc>] [<node>] -................ - [[cmdhelp_resource_scores,Display resource scores]] ==== `scores` @@ -1957,16 +1987,6 @@ unmanage <rsc> ............... -[[cmdhelp_resource_unmigrate,unmigrate a resource to another node]] -==== `unmigrate` (`unmove`) - -Remove the constraint generated by the previous migrate command. - -Usage: -............... -unmigrate <rsc> -............... - [[cmdhelp_resource_untrace,stop RA tracing]] ==== `untrace` @@ -2619,6 +2639,59 @@ acl_target joe resource_admin constraint_editor ................ +[[cmdhelp_configure_alert,Event-driven alerts]] +==== `alert` + +.Version note +**************************** +This feature is only available +in Pacemaker 1.1.15+. +**************************** + +Event-driven alerts enables calling scripts whenever interesting +events occur in the cluster (nodes joining or leaving, resources +starting or stopping, etc.). + +The +path+ is an arbitrary file path to an alert script. Existing +external scripts used with ClusterMon resources can be used as alert +scripts, since the interface is compatible. + +Each alert may have a number of receipients configured. These will be +passed to the script as arguments. The first recipient will also be +passed as the +CRM_alert_recipient+ environment variable, for +compatibility with existing scripts that only support one recipient. + +The available meta attributes are +timeout+ (default 30s) and ++timestamp-format+ (default `"%H:%M:%S.%06N"`). + +Some configurations may require each recipient to be delimited by +brackets, to avoid ambiguity. In the example +alert-2+ below, the meta +attribute for `timeout` is defined after the recipient, so the +brackets are used to ensure that the meta attribute is set for the +alert and not just the recipient. This can be avoided by setting any +alert attributes before defining the recipients. + +Usage: +............... +alert <id> <path> \ + [attributes <nvpair> ...] \ + [meta <nvpair> ...] \ + [to [{] <recipient> + [attributes <nvpair> ...] \ + [meta <nvpair> ...] [}] \ + ...] +............... + +Example: +............... +alert alert-1 /srv/pacemaker/pcmk_alert_sample.sh \ + to /var/log/cluster-alerts.log + +alert alert-2 /srv/pacemaker/example_alert.sh \ + to { /var/log/cluster-alerts.log } \ + meta timeout=60s +............... + [[cmdhelp_configure_cib,CIB shadow management]] ==== `cib` @@ -2902,6 +2975,34 @@ above. ************************** +[[cmdhelp_configure_get_property,Get property value]] +==== `get-property` + +Show the value of the given property. If the value is not set, the +command will print the default value for the property, if known. + +If no property name is passed to the command, the list of known +cluster properties is printed. + +If the property is set multiple times, for example using multiple +property sets with different rule expressions, the output of this +command is undefined. + +Pass the argument +-t+ or +--true+ to `get-property` to translate +the argument value into +true+ or +false+. If the value is not +set, the command will print +false+. + +Usage: +............... +get-property [-t|--true] [<name>] +............... + +Example: +............... +get-property stonith-enabled +get-property -t maintenance-mode +............... + [[cmdhelp_configure_graph,generate a directed graph]] ==== `graph` @@ -3728,34 +3829,6 @@ show related:webapp ............... -[[cmdhelp_configure_get_property,Get property value]] -==== `get-property` - -Show the value of the given property. If the value is not set, the -command will print the default value for the property, if known. - -If no property name is passed to the command, the list of known -cluster properties is printed. - -If the property is set multiple times, for example using multiple -property sets with different rule expressions, the output of this -command is undefined. - -Pass the argument +-t+ or +--true+ to `get-property` to translate -the argument value into +true+ or +false+. If the value is not -set, the command will print +false+. - -Usage: -............... -get-property [-t|--true] [<name>] -............... - -Example: -............... -get-property stonith-enabled -get-property -t maintenance-mode -............... - [[cmdhelp_configure_tag,Define resource tags]] ==== `tag` @@ -3775,7 +3848,6 @@ tag ips server-vip admin-vip ............... - [[cmdhelp_configure_template,edit and import a configuration from a template]] ==== `template` @@ -4283,20 +4355,31 @@ To ensure this, these commands require that maintenance mode is set either for the particular resource, or for the whole cluster. -[[cmdhelp_maintenance_on,Enable maintenance mode]] -==== `on` +[[cmdhelp_maintenance_action,Invoke a resource action]] +==== `action` -Enables maintenances mode, either for the whole cluster -or for the given resource. +Invokes the given action for the resource. This is +done directly via the resource agent, so the command must +be issued while the cluster or the resource is in +maintenance mode. + +Unless the action is `start` or `monitor`, the action must be invoked +on the same node as where the resource is running. If the resource is +running on multiple nodes, the command will fail. + +To use SSH for executing resource actions on multiple nodes, append +`ssh` after the action name. This requires SSH access to be configured +between the nodes and the parallax python package to be installed. Usage: ............... -on -on <rsc> +action <rsc> <action> +action <rsc> <action> ssh ............... Example: ............... -on rsc1 +action webserver reload +action webserver monitor ssh ............... [[cmdhelp_maintenance_off,Disable maintenance mode]] @@ -4315,31 +4398,20 @@ off rsc1 ............... -[[cmdhelp_maintenance_action,Invoke a resource action]] -==== `action` - -Invokes the given action for the resource. This is -done directly via the resource agent, so the command must -be issued while the cluster or the resource is in -maintenance mode. - -Unless the action is `start` or `monitor`, the action must be invoked -on the same node as where the resource is running. If the resource is -running on multiple nodes, the command will fail. +[[cmdhelp_maintenance_on,Enable maintenance mode]] +==== `on` -To use SSH for executing resource actions on multiple nodes, append -`ssh` after the action name. This requires SSH access to be configured -between the nodes and the parallax python package to be installed. +Enables maintenances mode, either for the whole cluster +or for the given resource. Usage: ............... -action <rsc> <action> -action <rsc> <action> ssh +on +on <rsc> ............... Example: ............... -action webserver reload -action webserver monitor ssh +on rsc1 ............... [[cmdhelp_history,Cluster history]] @@ -4437,6 +4509,27 @@ diff pe-input-2080.bz2 live status ............... +[[cmdhelp_history_events,Show events in log]] +==== `events` + +By analysing the log output and looking for particular +patterns, the `events` command helps sifting through +the logs to find when particular events like resources +changing state or node failure may have occurred. + +This can be used to generate a combined list of events +from all nodes. + +Usage: +............... +events +............... + +Example: +............... +events +............... + [[cmdhelp_history_exclude,exclude log messages]] ==== `exclude` @@ -4573,27 +4666,6 @@ log node-a ............... -[[cmdhelp_history_events,Show events in log]] -==== `events` - -By analysing the log output and looking for particular -patterns, the `events` command helps sifting through -the logs to find when particular events like resources -changing state or node failure may have occurred. - -This can be used to generate a combined list of events -from all nodes. - -Usage: -............... -events -............... - -Example: -............... -events -............... - [[cmdhelp_history_node,node events]] ==== `node` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/test/testcases/bugs new/crmsh-2.2.0+git.1462967444.169c554/test/testcases/bugs --- old/crmsh-2.2.0+git.1462285059.d79cd0d/test/testcases/bugs 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/test/testcases/bugs 2016-05-12 10:40:53.000000000 +0200 @@ -57,7 +57,7 @@ property SAPHanaSR_2: \ hana_ha1_site_iss_WDF1=cde \ hana_ha1_site_bss_WDF1=abc -show xml +show commit _test verify diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/test/testcases/bugs.exp new/crmsh-2.2.0+git.1462967444.169c554/test/testcases/bugs.exp --- old/crmsh-2.2.0+git.1462285059.d79cd0d/test/testcases/bugs.exp 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/test/testcases/bugs.exp 2016-05-12 10:40:53.000000000 +0200 @@ -120,40 +120,18 @@ .INP: _test .INP: verify .INP: property SAPHanaSR_2: hana_ha1_site_iss_WDF1=cde hana_ha1_site_bss_WDF1=abc -.INP: show xml -<?xml version="1.0" ?> -<cib> - <configuration> - <crm_config> - <cluster_property_set id="SAPHanaSR_2"> - <nvpair name="hana_ha1_site_iss_WDF1" value="cde" id="SAPHanaSR_2-hana_ha1_site_iss_WDF1"/> - <nvpair name="hana_ha1_site_bss_WDF1" value="abc" id="SAPHanaSR_2-hana_ha1_site_bss_WDF1"/> - </cluster_property_set> - <cluster_property_set id="SAPHanaSR"> - <nvpair name="hana_ha1_site_lss_WDF1" value="4" id="SAPHanaSR-hana_ha1_site_lss_WDF1"/> - </cluster_property_set> - </crm_config> - <nodes> - <node uname="node1" id="node1"/> - </nodes> - <resources> - <primitive id="st" class="stonith" type="null"> - <instance_attributes id="st-instance_attributes"> - <nvpair name="hostlist" value="node1" id="st-instance_attributes-hostlist"/> - </instance_attributes> - <meta_attributes id="st-meta_attributes"> - <nvpair name="description" value="some description here" id="st-meta_attributes-description"/> - </meta_attributes> - <operations> - <op name="start" requires="nothing" interval="0" id="st-start-0"/> - <op name="monitor" interval="60m" id="st-monitor-60m"/> - </operations> - </primitive> - </resources> - <constraints/> - </configuration> -</cib> - +.INP: show +node node1 +primitive st stonith:null \ + params hostlist=node1 \ + meta description="some description here" \ + op start requires=nothing interval=0 \ + op monitor interval=60m +property SAPHanaSR: \ + hana_ha1_site_lss_WDF1=4 +property SAPHanaSR_2: \ + hana_ha1_site_iss_WDF1=cde \ + hana_ha1_site_bss_WDF1=abc .INP: commit .INP: _test .INP: verify diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/test/testcases/resource new/crmsh-2.2.0+git.1462967444.169c554/test/testcases/resource --- old/crmsh-2.2.0+git.1462285059.d79cd0d/test/testcases/resource 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/test/testcases/resource 2016-05-12 10:40:53.000000000 +0200 @@ -43,3 +43,7 @@ configure rename p3 p4 configure primitive p3 Dummy resource stop p3 +%setenv showobj= +configure rm cg +configure ms msg g +resource scores diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/test/testcases/resource.exp new/crmsh-2.2.0+git.1462967444.169c554/test/testcases/resource.exp --- old/crmsh-2.2.0+git.1462285059.d79cd0d/test/testcases/resource.exp 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/test/testcases/resource.exp 2016-05-12 10:40:53.000000000 +0200 @@ -88,6 +88,7 @@ .SETENV showobj=cli-prefer-p3 .TRY resource migrate p3 node1 .EXT crm_resource --quiet --move -r 'p3' --node='node1' +INFO: Move constraint created for p3 to node1 .INP: configure .INP: _regtest on .INP: show xml cli-prefer-p3 @@ -106,9 +107,11 @@ .SETENV showobj= .TRY resource unmigrate p3 .EXT crm_resource --quiet --clear -r 'p3' +INFO: Removed migration constraints for p3 .SETENV showobj=cli-prefer-p3 .TRY resource migrate p3 node1 force .EXT crm_resource --quiet --move -r 'p3' --node='node1' --force +INFO: Move constraint created for p3 to node1 .INP: configure .INP: _regtest on .INP: show xml cli-prefer-p3 @@ -127,6 +130,7 @@ .SETENV showobj= .TRY resource unmigrate p3 .EXT crm_resource --quiet --clear -r 'p3' +INFO: Removed migration constraints for p3 .SETENV showobj=p0 .TRY resource param p0 set a0 "1 2 3" .EXT crm_resource -r 'p0' -p 'a0' -v '1 2 3' @@ -911,3 +915,46 @@ </configuration> </cib> +.SETENV showobj= +.TRY configure rm cg +.TRY configure ms msg g +.TRY resource scores +.EXT crm_simulate -sUL +3 of 6 resources DISABLED and 0 BLOCKED from being started due to failures + +Current cluster status: +Node node1: UNCLEAN (offline) + + st (stonith:null): Stopped + Clone Set: c1 [p1] (unmanaged) + Stopped: [ node1 ] + Master/Slave Set: m1 [p2] + Stopped: [ node1 ] + p3 (ocf::heartbeat:Dummy): Stopped ( disabled ) + Master/Slave Set: msg [g] + Stopped: [ node1 ] + +Allocation scores and utilization information: +Original: node1 capacity: +native_color: st allocation score on node1: 0 +clone_color: c1 allocation score on node1: 0 +clone_color: p1:0 allocation score on node1: 0 +native_color: p1:0 allocation score on node1: -INFINITY +clone_color: m1 allocation score on node1: 0 +clone_color: p2:0 allocation score on node1: 0 +native_color: p2:0 allocation score on node1: -INFINITY +p2:0 promotion score on none: 0 +native_color: p3 allocation score on node1: -INFINITY +clone_color: msg allocation score on node1: 0 +clone_color: g:0 allocation score on node1: 0 +clone_color: p0:0 allocation score on node1: 0 +clone_color: p4:0 allocation score on node1: 0 +group_color: g:0 allocation score on node1: -INFINITY +group_color: p0:0 allocation score on node1: -INFINITY +group_color: p4:0 allocation score on node1: -INFINITY +native_color: p0:0 allocation score on node1: -INFINITY +native_color: p4:0 allocation score on node1: -INFINITY +g:0 promotion score on none: 0 +Remaining: node1 capacity: + +Transition Summary: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/test/unittests/test_cliformat.py new/crmsh-2.2.0+git.1462967444.169c554/test/unittests/test_cliformat.py --- old/crmsh-2.2.0+git.1462285059.d79cd0d/test/unittests/test_cliformat.py 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/test/unittests/test_cliformat.py 2016-05-12 10:40:53.000000000 +0200 @@ -266,3 +266,24 @@ @with_setup(setup_func, teardown_func) def test_is_value_sane_2(): roundtrip('primitive p1 dummy params state="bo\\"o"') + + +@with_setup(setup_func, teardown_func) +def test_alerts_1(): + roundtrip('alert alert1 "/tmp/foo.sh" to "/tmp/bar.log"') + +@with_setup(setup_func, teardown_func) +def test_alerts_2(): + roundtrip('alert alert2 "/tmp/foo.sh" attributes foo=bar to "/tmp/bar.log"') + +@with_setup(setup_func, teardown_func) +def test_alerts_3(): + roundtrip('alert alert3 "a path here" meta baby to "/tmp/bar.log"') + +@with_setup(setup_func, teardown_func) +def test_alerts_4(): + roundtrip('alert alert4 "/also/a/path"') + +@with_setup(setup_func, teardown_func) +def test_alerts_5(): + roundtrip('alert alert5 "/a/path" to { "/another/path" } meta timeout=30s') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0+git.1462285059.d79cd0d/test/unittests/test_parse.py new/crmsh-2.2.0+git.1462967444.169c554/test/unittests/test_parse.py --- old/crmsh-2.2.0+git.1462285059.d79cd0d/test/unittests/test_parse.py 2016-05-03 16:17:39.000000000 +0200 +++ new/crmsh-2.2.0+git.1462967444.169c554/test/unittests/test_parse.py 2016-05-12 10:40:53.000000000 +0200 @@ -474,6 +474,26 @@ self.assertEqual(out.get('id'), 'tag1') self.assertEqual(['foo', 'bar'], out.xpath('/tag/obj_ref/@id')) + def test_alerts(self): + "Test alerts (1.1.15+)" + out = self._parse('alert alert1 /tmp/foo.sh to /tmp/bar.log') + self.assertEqual(out.get('id'), 'alert1') + self.assertEqual(['/tmp/foo.sh'], + out.xpath('/alert/@path')) + self.assertEqual(['/tmp/bar.log'], + out.xpath('/alert/recipient/@value')) + + def test_alerts_brackets(self): + "Test alerts w/ brackets (1.1.15+)" + out = self._parse('alert alert2 /tmp/foo.sh to { /tmp/bar.log meta timeout=10s }') + self.assertEqual(out.get('id'), 'alert2') + self.assertEqual(['/tmp/foo.sh'], + out.xpath('/alert/@path')) + self.assertEqual(['/tmp/bar.log'], + out.xpath('/alert/recipient/@value')) + self.assertEqual(['10s'], + out.xpath('/alert/recipient/meta_attributes/nvpair[@name="timeout"]/@value')) + def _parse_lines(self, lines): out = [] for line in lines2cli(lines):