Hello community, here is the log from the commit of package crmsh for openSUSE:Factory checked in at 2016-10-10 16:21:08 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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-09-16 11:02:07.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.crmsh.new/crmsh.changes 2016-10-10 16:21:09.000000000 +0200 @@ -1,0 +2,12 @@ +Wed Oct 05 09:14:50 UTC 2016 - [email protected] + +- Update to version 2.3.1+git.1475245522.4172084: + * high: cibconfig: Ensure temp CIB is readable by crm_diff (bsc#999683) + * high: parse: Support target pattern in fencing topology + * medium: ui_configure: option to obscure passwords + * medium: cibconfig: Remove from tags when removing object + * medium: scripts: Better corosync defaults (bsc#1001164) + * medium: scripts: Drop logrotate check from cluster health + * low: cmd_status: Highlight plural forms (bsc#996806) + +------------------------------------------------------------------- Old: ---- crmsh-2.3.1+git.1473924149.8abc212.tar.bz2 New: ---- crmsh-2.3.1+git.1475245522.4172084.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ crmsh.spec ++++++ --- /var/tmp/diff_new_pack.Vqe7mx/_old 2016-10-10 16:21:11.000000000 +0200 +++ /var/tmp/diff_new_pack.Vqe7mx/_new 2016-10-10 16:21:11.000000000 +0200 @@ -36,7 +36,7 @@ Summary: High Availability cluster command-line interface License: GPL-2.0+ Group: %{pkg_group} -Version: 2.3.1+git.1473924149.8abc212 +Version: 2.3.1+git.1475245522.4172084 Release: 0 Url: http://crmsh.github.io Source0: %{name}-%{version}.tar.bz2 ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.Vqe7mx/_old 2016-10-10 16:21:11.000000000 +0200 +++ /var/tmp/diff_new_pack.Vqe7mx/_new 2016-10-10 16:21:11.000000000 +0200 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">git://github.com/ClusterLabs/crmsh.git</param> - <param name="changesrevision">8abc2127fd1acecdc40ae4e242c1c02eeead75eb</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">41720845429e9a42d4273d70a6be5cc31e324849</param></service></servicedata> \ No newline at end of file ++++++ crmsh-2.3.1+git.1473924149.8abc212.tar.bz2 -> crmsh-2.3.1+git.1475245522.4172084.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.3.1+git.1473924149.8abc212/crmsh/cibconfig.py new/crmsh-2.3.1+git.1475245522.4172084/crmsh/cibconfig.py --- old/crmsh-2.3.1+git.1473924149.8abc212/crmsh/cibconfig.py 2016-09-15 09:26:16.000000000 +0200 +++ new/crmsh-2.3.1+git.1475245522.4172084/crmsh/cibconfig.py 2016-09-30 16:25:22.000000000 +0200 @@ -30,7 +30,7 @@ from .msg import invalid_id_err, cib_ver_unsupported_err from .utils import ext_cmd, safe_open_w, pipe_string, safe_close_w, crm_msec from .utils import ask, lines2cli, olist -from .utils import page_string, cibadmin_can_patch, str2tmp +from .utils import page_string, cibadmin_can_patch, str2tmp, ensure_sudo_readable from .utils import run_ptest, is_id_valid, edit_file, get_boolean, filter_string from .xmlutil import is_child_rsc, rsc_constraint, sanitize_cib, rename_id, get_interesting_nodes from .xmlutil import is_pref_location, get_topnode, new_cib, get_rscop_defaults_meta_node @@ -585,6 +585,12 @@ def repr(self, format_mode="ignored"): "Return a string containing xml of all objects." cib_elem = cib_factory.obj_set2cib(self.obj_set) + + from .utils import obscured + for nvp in cib_elem.xpath('//nvpair'): + if 'value' in nvp.attrib: + nvp.set('value', obscured(nvp.get('name'), nvp.get('value'))) + s = etree.tostring(cib_elem, pretty_print=True) return '<?xml version="1.0" ?>\n' + s @@ -1923,7 +1929,9 @@ s = clidisplay.keyword(self.obj_type) d = ordereddict.odict() for c in self.node.iterchildren("fencing-level"): - if "target-attribute" in c.attrib: + if "target-pattern" in c.attrib: + target = (None, c.get("target-pattern")) + elif "target-attribute" in c.attrib: target = (c.get("target-attribute"), c.get("target-value")) else: target = c.get("target") @@ -1943,9 +1951,10 @@ def fmt_target(tgt): if isinstance(tgt, tuple): + if tgt[0] is None: + return "pattern:%s" % (tgt[1]) return "attr:%s=%s" % tgt - else: - return tgt + ":" + return tgt + ":" return cli_format([s] + ["%s %s" % (fmt_target(x), ' '.join(dd[x])) for x in dd.keys()], break_lines=(format_mode > 0)) @@ -2558,13 +2567,14 @@ self._set_cib_attributes(self.cib_elem) cib_s = etree.tostring(self.cib_orig, pretty_print=True) tmpf = str2tmp(cib_s, suffix=".xml") - if not tmpf: + if not tmpf or not ensure_sudo_readable(tmpf): return False tmpfiles.add(tmpf) cibadmin_opts = force and "-P --force" or "-P" # produce a diff: # dump_new_conf | crm_diff -o self.cib_orig -n - + common_debug("Input: %s" % (etree.tostring(self.cib_elem))) rc, cib_diff = filter_string("%s -o %s -n -" % (self._crm_diff_cmd, tmpf), @@ -3637,6 +3647,16 @@ rmnode(obj.node) self._add_to_remove_queue(obj) self.cib_objects.remove(obj) + for tag in self.related_tags(obj): + # remove self from tag + # remove tag if self is last tagged object in tag + selfies = [x for x in tag.node.iterchildren() if x.get('id') == obj.obj_id] + for c in selfies: + rmnode(c) + if len(tag.node.xpath('./obj_ref')) == 0: + self._remove_obj(tag) + if not self._no_constraint_rm_msg: + err_buf.info("hanging %s deleted" % str(tag)) for c_obj in self.related_constraints(obj): if is_simpleconstraint(c_obj.node) and obj.children: # the first child inherits constraints @@ -3652,6 +3672,16 @@ elif deleted: err_buf.info("constraint %s updated" % str(c_obj)) + def related_tags(self, obj): + def related_tag(tobj): + if tobj.obj_type != 'tag': + return False + for c in tobj.node.iterchildren(): + if c.get('id') == obj.obj_id: + return True + return False + return [x for x in self.cib_objects if related_tag(x)] + def related_constraints(self, obj): def related_constraint(obj2): return is_constraint(obj2.node) and rsc_constraint(obj.obj_id, obj2.node) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.3.1+git.1473924149.8abc212/crmsh/cliformat.py new/crmsh-2.3.1+git.1475245522.4172084/crmsh/cliformat.py --- old/crmsh-2.3.1+git.1473924149.8abc212/crmsh/cliformat.py 2016-09-15 09:26:16.000000000 +0200 +++ new/crmsh-2.3.1+git.1475245522.4172084/crmsh/cliformat.py 2016-09-30 16:25:22.000000000 +0200 @@ -64,10 +64,12 @@ def cli_nvpair(nvp): 'Converts an nvpair tag or a (name, value) pair to CLI syntax' from .cibconfig import cib_factory + from .utils import obscured nodeid = nvp.get('id') idref = nvp.get('id-ref') name = nvp.get('name') value = nvp.get('value') + value = obscured(name, value) if idref is not None: if name is not None: return '@%s:%s' % (idref, name) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.3.1+git.1473924149.8abc212/crmsh/cmd_status.py new/crmsh-2.3.1+git.1475245522.4172084/crmsh/cmd_status.py --- old/crmsh-2.3.1+git.1473924149.8abc212/crmsh/cmd_status.py 2016-09-15 09:26:16.000000000 +0200 +++ new/crmsh-2.3.1+git.1475245522.4172084/crmsh/cmd_status.py 2016-09-30 16:25:22.000000000 +0200 @@ -17,7 +17,7 @@ r'UNKNOWN\!', 'Stopped', 'standby'] -_OKS = ['Online', 'online', 'ok', 'master', 'Started', 'Master', 'Slave'] +_OKS = ['Masters', 'Slaves', 'Started', 'Master', 'Slave', 'Online', 'online', 'ok', 'master'] _ERRORS = ['not running', 'unknown error', 'invalid parameter', @@ -40,14 +40,14 @@ class CrmMonFilter(object): - _OK = re.compile(r'(%s)' % '|'.join(_OKS)) + _OK = re.compile(r'(%s)' % '|'.join(r"(?:\b%s\b)" % (w) for w in _OKS)) _WARNS = re.compile(r'(%s)' % '|'.join(_WARNS)) _ERROR = re.compile(r'(%s)' % ('|'.join(_ERRORS))) _NODES = re.compile(r'(\d+ Nodes configured)') _RESOURCES = re.compile(r'(\d+ Resources configured)') _RESOURCE = re.compile(r'(\S+)(\s+)\((\S+:\S+)\):') - _GROUP = re.compile(r'(Resource Group|Clone Set): (\S+)') + _GROUP = re.compile(r'((?:Resource Group)|(?:Clone Set)|(?:Master/Slave Set)): (\S+)') def _filter(self, line): line = self._RESOURCE.sub("%s%s(%s):" % (clidisplay.help_header(r'\1'), @@ -55,10 +55,11 @@ r'\3'), line) line = self._NODES.sub(clidisplay.help_header(r'\1'), line) line = self._RESOURCES.sub(clidisplay.help_header(r'\1'), line) - line = self._GROUP.sub(r'\1: ' + clidisplay.help_header(r'\2'), line) - line = self._WARNS.sub(clidisplay.warn(r'\1'), line) - line = self._OK.sub(clidisplay.ok(r'\1'), line) - line = self._ERROR.sub(clidisplay.error(r'\1'), line) + line, ngroups = self._GROUP.subn(r'\1: ' + clidisplay.help_header(r'\2'), line) + if ngroups == 0: + line = self._WARNS.sub(clidisplay.warn(r'\1'), line) + line = self._OK.sub(clidisplay.ok(r'\1'), line) + line = self._ERROR.sub(clidisplay.error(r'\1'), line) return line def __call__(self, text): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.3.1+git.1473924149.8abc212/crmsh/parse.py new/crmsh-2.3.1+git.1475245522.4172084/crmsh/parse.py --- old/crmsh-2.3.1+git.1473924149.8abc212/crmsh/parse.py 2016-09-15 09:26:16.000000000 +0200 +++ new/crmsh-2.3.1+git.1475245522.4172084/crmsh/parse.py 2016-09-30 16:25:22.000000000 +0200 @@ -42,6 +42,7 @@ _ROLE2_RE = re.compile(r"role=(.+)$", re.IGNORECASE) _TARGET_RE = re.compile(r'([^:]+):$') _TARGET_ATTR_RE = re.compile(r'attr:([\w-]+)=([\w-]+)$', re.IGNORECASE) +_TARGET_PATTERN_RE = re.compile(r'pattern:(.+)$', re.IGNORECASE) TERMINATORS = ('params', 'meta', 'utilization', 'operations', 'op', 'rule', 'attributes') @@ -1052,6 +1053,19 @@ index=<+int> devices="\w,\w..."/> </fencing-topology> + from 1.1.14 on, target can be a regexp pattern: + + pattern:<pattern> maps to XML: + + <fencing-topology> + <fencing-level id=<id> target-pattern=<pattern> + index=<+int> devices="\w,\w..."/> + </fencing-topology> + + fencing-topology \ + pcmk-1: poison-pill power \ + pcmk-2: disk,network power + """ def parse(self, cmd): self.begin(cmd, min_args=1) @@ -1063,6 +1077,8 @@ while self.has_tokens(): if self.try_match(_TARGET_ATTR_RE): target = (self.matched(1), self.matched(2)) + elif self.try_match(_TARGET_PATTERN_RE): + target = (None, self.matched(1)) elif self.try_match(_TARGET_RE): target = self.matched(1) else: @@ -1090,12 +1106,20 @@ targets = defaultdict(repeat(1).next) for target, devices in lvl_generator(): if isinstance(target, tuple): - c = xmlutil.child(out, 'fencing-level', - index=str(targets[target[0]]), - devices=devices) - c.set('target-attribute', target[0]) - c.set('target-value', target[1]) - targets[target[0]] += 1 + if target[0] is None: + # pattern + c = xmlutil.child(out, 'fencing-level', + index=str(targets[target[1]]), + devices=devices) + c.set('target-pattern', target[1]) + targets[target[1]] += 1 + else: + c = xmlutil.child(out, 'fencing-level', + index=str(targets[target[0]]), + devices=devices) + c.set('target-attribute', target[0]) + c.set('target-value', target[1]) + targets[target[0]] += 1 else: xmlutil.child(out, 'fencing-level', target=target, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.3.1+git.1473924149.8abc212/crmsh/ui_configure.py new/crmsh-2.3.1+git.1475245522.4172084/crmsh/ui_configure.py --- old/crmsh-2.3.1+git.1473924149.8abc212/crmsh/ui_configure.py 2016-09-15 09:26:16.000000000 +0200 +++ new/crmsh-2.3.1+git.1475245522.4172084/crmsh/ui_configure.py 2016-09-30 16:25:22.000000000 +0200 @@ -302,8 +302,12 @@ @command.completers_repeating(_id_show_list) def do_show(self, context, *args): "usage: show [xml] [<id>...]" - set_obj = mkset_obj(*args) - return set_obj.show() + from .utils import obscure + osargs = [arg[8:] for arg in args if arg.startswith('obscure:')] + args = [arg for arg in args if not arg.startswith('obscure:')] + with obscure(osargs): + set_obj = mkset_obj(*args) + return set_obj.show() @command.name("get_property") @command.alias("get-property") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.3.1+git.1473924149.8abc212/crmsh/utils.py new/crmsh-2.3.1+git.1475245522.4172084/crmsh/utils.py --- old/crmsh-2.3.1+git.1473924149.8abc212/crmsh/utils.py 2016-09-15 09:26:16.000000000 +0200 +++ new/crmsh-2.3.1+git.1475245522.4172084/crmsh/utils.py 2016-09-30 16:25:22.000000000 +0200 @@ -245,6 +245,19 @@ return cmd +def ensure_sudo_readable(f): + # make sure the tempfile is readable to crm_diff (bsc#999683) + if config.core.user: + from pwd import getpwnam + uid = getpwnam(config.core.user).pw_uid + try: + os.chown(f, uid, -1) + except os.error as err: + common_err('Failed setting temporary file permissions: %s' % (err)) + return False + return True + + def pipe_string(cmd, s): rc = -1 # command failed cmd = add_sudo(cmd) @@ -1594,5 +1607,27 @@ err_buf.ok(host) return ok +# a set of fnmatch patterns to match attributes whose values +# should be obscured as a sequence of **** when printed +_obscured_nvpairs = [] + +def obscured(key, value): + if key is not None and value is not None: + for o in _obscured_nvpairs: + if fnmatch.fnmatch(key, o): + return '*' * 6 + return value + +@contextmanager +def obscure(obscure_list): + global _obscured_nvpairs + prev = _obscured_nvpairs + _obscured_nvpairs = obscure_list + try: + yield + finally: + _obscured_nvpairs = prev + + # vim:ts=4:sw=4:et: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.3.1+git.1473924149.8abc212/doc/crm.8.adoc new/crmsh-2.3.1+git.1475245522.4172084/doc/crm.8.adoc --- old/crmsh-2.3.1+git.1473924149.8abc212/doc/crm.8.adoc 2016-09-15 09:26:16.000000000 +0200 +++ new/crmsh-2.3.1+git.1475245522.4172084/doc/crm.8.adoc 2016-09-30 16:25:22.000000000 +0200 @@ -2909,6 +2909,10 @@ as the +target+ in a fencing topology. The syntax for this usage is described below. +From Pacemaker version 1.1.14, it is also possible to use regular +expression patterns as the +target+ in a fencing topology. The configured +fencing sequence then applies to all devices matching the pattern. + Usage: ............... fencing_topology <stonith_resources> [<stonith_resources> ...] @@ -2917,7 +2921,7 @@ fencing_order :: <target> <stonith_resources> [<stonith_resources> ...] stonith_resources :: <rsc>[,<rsc>...] -target :: <node>: | attr:<node-attribute>=<value> +target :: <node>: | attr:<node-attribute>=<value> | pattern:<pattern> ............... Example: ............... @@ -2932,6 +2936,13 @@ # Fencing anything on rack 1 requires fencing via both APC 1 and 2, # to defeat the redundancy provided by two separate UPS units. fencing_topology attr:rack=1 apc01,apc02 + +# Fencing for all machines named green.* is done using the pear +# fencing device first, while all machines named red.* are fenced +# using the apple fencing device first. +fencing_topology \ + pattern:green.* pear apple \ + pattern:red.* apple pear ............... [[cmdhelp_configure_filter,filter CIB objects]] @@ -3803,6 +3814,12 @@ +foo+, the following combination can be used: +show type:primitive and tag:foo+. +To hide values when displaying the configuration, use the ++obscure:<glob>+ argument. This can be useful when sending the +configuration over a public channel, to avoid exposing potentially +sensitive information. The +<glob>+ argument is a bash-style pattern +matching attribute keys. + Usage: ............... show [xml] [<id> @@ -3810,6 +3827,7 @@ | type:<type> | tag:<id> | related:<obj> + | obscure:<glob> ...] type :: node | primitive | group | clone | ms | rsc_template @@ -3827,6 +3845,7 @@ show type:primitive show xml tag:db tag:fs show related:webapp +show type:primitive obscure:passwd ............... [[cmdhelp_configure_tag,Define resource tags]] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.3.1+git.1473924149.8abc212/scripts/health/collect.py new/crmsh-2.3.1+git.1475245522.4172084/scripts/health/collect.py --- old/crmsh-2.3.1+git.1473924149.8abc212/scripts/health/collect.py 2016-09-15 09:26:16.000000000 +0200 +++ new/crmsh-2.3.1+git.1475245522.4172084/scripts/health/collect.py 2016-09-30 16:25:22.000000000 +0200 @@ -14,10 +14,7 @@ return crm_script.rpmcheck(PACKAGES) def logrotate_info(): - rc, _, _ = crm_script.call( - 'grep -r corosync.conf /etc/logrotate.d', - shell=True) - return {'corosync.conf': rc == 0} + return {} def sys_info(): sysname, nodename, release, version, machine = os.uname() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.3.1+git.1473924149.8abc212/scripts/init/corosync.conf.template new/crmsh-2.3.1+git.1475245522.4172084/scripts/init/corosync.conf.template --- old/crmsh-2.3.1+git.1473924149.8abc212/scripts/init/corosync.conf.template 2016-09-15 09:26:16.000000000 +0200 +++ new/crmsh-2.3.1+git.1475245522.4172084/scripts/init/corosync.conf.template 2016-09-30 16:25:22.000000000 +0200 @@ -1,9 +1,17 @@ # Please read the corosync.conf.5 manual page totem { version: 2 + secauth: on + crypto_hash: sha1 + crypto_cipher: aes256 + cluster_name: hacluster + clear_node_high_bit: yes - crypto_cipher: none - crypto_hash: none + token: 5000 + token_retransmits_before_loss_const: 10 + join: 60 + consensus: 6000 + max_messages: 20 interface { ringnumber: 0 @@ -17,9 +25,10 @@ logging { fileline: off + to_stderr: no to_logfile: no - to_syslog: yes logfile: /var/log/cluster/corosync.log + to_syslog: yes debug: off timestamp: on logger_subsys { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.3.1+git.1473924149.8abc212/test/unittests/test_cliformat.py new/crmsh-2.3.1+git.1475245522.4172084/test/unittests/test_cliformat.py --- old/crmsh-2.3.1+git.1473924149.8abc212/test/unittests/test_cliformat.py 2016-09-15 09:26:16.000000000 +0200 +++ new/crmsh-2.3.1+git.1475245522.4172084/test/unittests/test_cliformat.py 2016-09-30 16:25:22.000000000 +0200 @@ -187,6 +187,28 @@ @with_setup(setup_func, teardown_func) +def test_fencing2(): + xml = """<fencing-topology> + <fencing-level devices="apple" id="fencing" index="1" +target-pattern="green.*"></fencing-level> + <fencing-level devices="pear" id="fencing" index="2" +target-pattern="green.*"></fencing-level> + <fencing-level devices="pear" id="fencing" index="1" +target-pattern="red.*"></fencing-level> + <fencing-level devices="apple" id="fencing" index="2" +target-pattern="red.*"></fencing-level> + </fencing-topology>""" + data = etree.fromstring(xml) + obj = factory.create_from_node(data) + assert_is_not_none(obj) + data = obj.repr_cli(format_mode=-1) + print data + exp = 'fencing_topology pattern:green.* apple pear pattern:red.* pear apple' + eq_(exp, data) + assert obj.cli_use_validate() + + +@with_setup(setup_func, teardown_func) def test_master(): xml = """<master id="ms-1"> <crmsh-ref id="dummy3" /> @@ -257,6 +279,10 @@ def test_topology_1114(): roundtrip('fencing_topology attr:rack=1 node1,node2') +@with_setup(setup_func, teardown_func) +def test_topology_1114_pattern(): + roundtrip('fencing_topology pattern:.* network disk') + @with_setup(setup_func, teardown_func) def test_locrule():
