Hello community, here is the log from the commit of package crmsh for openSUSE:Factory checked in at 2018-01-10 23:36:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/crmsh (Old) and /work/SRC/openSUSE:Factory/.crmsh.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "crmsh" Wed Jan 10 23:36:04 2018 rev:136 rq:563058 version:4.0.0+git.1515511613.5ee0eb23 Changes: -------- --- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes 2017-12-14 11:03:29.958189541 +0100 +++ /work/SRC/openSUSE:Factory/.crmsh.new/crmsh.changes 2018-01-10 23:36:06.349383198 +0100 @@ -1,0 +2,10 @@ +Tue Jan 09 15:31:11 UTC 2018 - [email protected] + +- Update to version 4.0.0+git.1515511613.5ee0eb23: + * high: scripts: Enable complex expressions in when: (bsc#1074835) + * medium: hb_report: Support new pacemaker.log location (fate#324508) + * low: ui_configure: Complete rsc template correctly + * fix: ra: Convert bytes to str + * fix: ui_resource: Using crm_failcount instead of crm_attribute(bsc#1074127) + +------------------------------------------------------------------- Old: ---- crmsh-4.0.0+git.1513179435.e1d17d7b.tar.bz2 New: ---- crmsh-4.0.0+git.1515511613.5ee0eb23.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ crmsh.spec ++++++ --- /var/tmp/diff_new_pack.hIQEt8/_old 2018-01-10 23:36:06.909356924 +0100 +++ /var/tmp/diff_new_pack.hIQEt8/_new 2018-01-10 23:36:06.913356736 +0100 @@ -1,7 +1,7 @@ # # spec file for package crmsh # -# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -36,7 +36,7 @@ Summary: High Availability cluster command-line interface License: GPL-2.0+ Group: %{pkg_group} -Version: 4.0.0+git.1513179435.e1d17d7b +Version: 4.0.0+git.1515511613.5ee0eb23 Release: 0 Url: http://crmsh.github.io Source0: %{name}-%{version}.tar.bz2 ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.hIQEt8/_old 2018-01-10 23:36:06.949355047 +0100 +++ /var/tmp/diff_new_pack.hIQEt8/_new 2018-01-10 23:36:06.953354859 +0100 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">git://github.com/ClusterLabs/crmsh.git</param> - <param name="changesrevision">e1d17d7b1a3b6b4a3ca0211d72d8102b150c0c65</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">5ee0eb231d19e543bcba9a5dd9f43327096ff1b3</param></service></servicedata> \ No newline at end of file ++++++ crmsh-4.0.0+git.1513179435.e1d17d7b.tar.bz2 -> crmsh-4.0.0+git.1515511613.5ee0eb23.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.0.0+git.1513179435.e1d17d7b/crmsh/config.py new/crmsh-4.0.0+git.1515511613.5ee0eb23/crmsh/config.py --- old/crmsh-4.0.0+git.1513179435.e1d17d7b/crmsh/config.py 2017-12-13 16:37:15.000000000 +0100 +++ new/crmsh-4.0.0+git.1515511613.5ee0eb23/crmsh/config.py 2018-01-09 16:26:53.000000000 +0100 @@ -260,7 +260,7 @@ 'from_time': opt_string('-12H'), 'compress': opt_boolean('yes'), 'speed_up': opt_boolean('no'), - 'collect_extra_logs': opt_string('/var/log/messages /var/log/pacemaker.log /var/log/ha-cluster-bootstrap.log'), + 'collect_extra_logs': opt_string('/var/log/messages /var/log/pacemaker/pacemaker.log /var/log/pacemaker.log /var/log/ha-cluster-bootstrap.log'), 'remove_exist_dest': opt_boolean('no'), 'single_node': opt_boolean('no') } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.0.0+git.1513179435.e1d17d7b/crmsh/minieval.py new/crmsh-4.0.0+git.1515511613.5ee0eb23/crmsh/minieval.py --- old/crmsh-4.0.0+git.1513179435.e1d17d7b/crmsh/minieval.py 1970-01-01 01:00:00.000000000 +0100 +++ new/crmsh-4.0.0+git.1515511613.5ee0eb23/crmsh/minieval.py 2018-01-09 16:26:53.000000000 +0100 @@ -0,0 +1,360 @@ +# Copyright (C) 2013-2017 Daniel Fairhead +# Copyright (C) 2017 Kristoffer Gronlund <[email protected]> +# See COPYING for license information. + +""" +Based on simpleeval: + +SimpleEval - (C) 2013-2017 Daniel Fairhead +------------------------------------- + +An short, easy to use, safe and reasonably extensible expression evaluator. +Designed for things like in a website where you want to allow the user to +generate a string, or a number from some other input, without allowing full +eval() or other unsafe or needlessly complex linguistics. + +------------------------------------- + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +------------------------------------- + +Initial idea copied from J.F. Sebastian on Stack Overflow +( http://stackoverflow.com/a/9558001/1973500 ) with +modifications and many improvments. + +------------------------------------- +Contributors: +- corro (Robin Baumgartner) (py3k) +- dratchkov (David R) (nested dicts) +- marky1991 (Mark Young) (slicing) +- T045T (Nils Berg) (!=, py3kstr, obj. +- perkinslr (Logan Perkins) (.__globals__ or .func_ breakouts) +- impala2 (Kirill Stepanov) (massive _eval refactor) +- gk (ugik) (Other iterables than str can DOS too, and can be made) +- daveisfera (Dave Johansen) 'not' Boolean op, Pycharm and pep8 fixes. + +------------------------------------- +Usage: + +>>> s = SimpleEval() +>>> s.eval("20 + 30") +50 + +You can add your own functions easily too: + +if file.txt contents is "11" + +>>> def get_file(): + with open("file.txt",'r') as f: + return f.read() + + s.functions["get_file"] = get_file + s.eval("int(get_file()) + 31") +42 + +For more information, see the full package documentation on pypi, or the github +repo. + +----------- + +If you don't need to re-use the evaluator (with it's names, functions, etc), +then you can use the simple_eval() function: + +>>> simple_eval("21 + 19") +40 + +You can pass names, operators and functions to the simple_eval function as +well: + +>>> simple_eval("40 + two", names={"two": 2}) +42 + +""" + +import ast +import sys +import operator as op + +######################################## +# Module wide 'globals' + +MAX_STRING_LENGTH = 100000 +DISALLOW_PREFIXES = ['_', 'func_'] +DISALLOW_METHODS = ['format'] + +PYTHON3 = sys.version_info[0] == 3 + +######################################## +# Exceptions: + + +class InvalidExpression(Exception): + """ Generic Exception """ + pass + + +class NameNotDefined(InvalidExpression): + """ a name isn't defined. """ + def __init__(self, name, expression): + self.name = name + self.message = "'{0}' is not defined for expression '{1}'".format( + name, expression) + self.expression = expression + + # pylint: disable=bad-super-call + super(InvalidExpression, self).__init__(self.message) + + +class AttributeDoesNotExist(InvalidExpression): + """attribute does not exist""" + def __init__(self, attr, expression): + self.message = \ + "Attribute '{0}' does not exist in expression '{1}'".format( + attr, expression) + self.attr = attr + self.expression = expression + + +class FeatureNotAvailable(InvalidExpression): + """ What you're trying to do is not allowed. """ + pass + + +class IterableTooLong(InvalidExpression): + """ That iterable is **way** too long, baby. """ + pass + + +######################################## +# Defaults for the evaluator: + +DEFAULT_OPERATORS = {ast.Eq: op.eq, ast.NotEq: op.ne, + ast.Gt: op.gt, ast.Lt: op.lt, + ast.GtE: op.ge, ast.LtE: op.le, + ast.Not: op.not_, + ast.USub: op.neg, ast.UAdd: op.pos, + ast.In: lambda x, y: op.contains(y, x), + ast.NotIn: lambda x, y: not op.contains(y, x), + ast.Is: lambda x, y: x is y, + ast.IsNot: lambda x, y: x is not y, + } + +DEFAULT_NAMES = {"True": True, "False": False} + +######################################## +# And the actual evaluator: + + +class SimpleEval(object): # pylint: disable=too-few-public-methods + """ A very simple expression parser. + >>> s = SimpleEval() + >>> s.eval("20 + 30 - ( 10 * 5)") + 0 + """ + expr = "" + + def __init__(self, names): + """ + Create the evaluator instance. Set up valid operators (+,-, etc) + functions (add, random, get_val, whatever) and names. """ + + operators = DEFAULT_OPERATORS + names = names.copy() + names.update(DEFAULT_NAMES) + + self.operators = operators + self.names = names + + self.nodes = { + ast.Num: self._eval_num, + ast.Str: self._eval_str, + ast.Name: self._eval_name, + ast.UnaryOp: self._eval_unaryop, + ast.BinOp: self._eval_binop, + ast.BoolOp: self._eval_boolop, + ast.Compare: self._eval_compare, + ast.IfExp: self._eval_ifexp, + ast.keyword: self._eval_keyword, + ast.Subscript: self._eval_subscript, + ast.Attribute: self._eval_attribute, + ast.Index: self._eval_index, + ast.Slice: self._eval_slice, + } + + # py3k stuff: + if hasattr(ast, 'NameConstant'): + self.nodes[ast.NameConstant] = self._eval_nameconstant + elif isinstance(self.names, dict) and "None" not in self.names: + self.names["None"] = None + + def evaluate(self, expr): + """ evaluate an expresssion, using the operators, functions and + names previously set up. """ + + # set a copy of the expression aside, so we can give nice errors... + + self.expr = expr + + # and evaluate: + return self._eval(ast.parse(expr.strip()).body[0].value) + + def _eval(self, node): + """ The internal evaluator used on each node in the parsed tree. """ + + try: + handler = self.nodes[type(node)] + except KeyError: + raise FeatureNotAvailable("Sorry, {0} is not available in this " + "evaluator".format(type(node).__name__)) + + return handler(node) + + @staticmethod + def _eval_num(node): + return node.n + + @staticmethod + def _eval_str(node): + if len(node.s) > MAX_STRING_LENGTH: + raise IterableTooLong("String Literal in statement is too long!" + " ({0}, when {1} is max)".format( + len(node.s), MAX_STRING_LENGTH)) + return node.s + + @staticmethod + def _eval_nameconstant(node): + return node.value + + def _eval_unaryop(self, node): + return self.operators[type(node.op)](self._eval(node.operand)) + + def _eval_binop(self, node): + return self.operators[type(node.op)](self._eval(node.left), + self._eval(node.right)) + + def _eval_boolop(self, node): + if isinstance(node.op, ast.And): + vout = False + for value in node.values: + vout = self._eval(value) + if not vout: + return False + return vout + elif isinstance(node.op, ast.Or): + for value in node.values: + vout = self._eval(value) + if vout: + return vout + return False + + def _eval_compare(self, node): + left = self._eval(node.left) + for operation, comp in zip(node.ops, node.comparators): + right = self._eval(comp) + if self.operators[type(operation)](left, right): + left = right # Hi Dr. Seuss... + else: + return False + return True + + def _eval_ifexp(self, node): + return self._eval(node.body) if self._eval(node.test) \ + else self._eval(node.orelse) + + def _eval_keyword(self, node): + return node.arg, self._eval(node.value) + + def _eval_name(self, node): + try: + # This happens at least for slicing + # This is a safe thing to do because it is impossible + # that there is a true exression assigning to none + # (the compiler rejects it, so you can't even + # pass that to ast.parse) + if isinstance(self.names, dict): + return self.names[node.id] + elif callable(self.names): + return self.names(node) + else: + raise InvalidExpression('Trying to use name (variable) "{0}"' + ' when no "names" defined for' + ' evaluator'.format(node.id)) + + except KeyError: + if node.id in self.functions: + return self.functions[node.id] + + raise NameNotDefined(node.id, self.expr) + + def _eval_subscript(self, node): + + container = self._eval(node.value) + key = self._eval(node.slice) + try: + return container[key] + except KeyError: + raise + + def _eval_attribute(self, node): + for prefix in DISALLOW_PREFIXES: + if node.attr.startswith(prefix): + raise FeatureNotAvailable( + "Sorry, access to __attributes " + " or func_ attributes is not available. " + "({0})".format(node.attr)) + if node.attr in DISALLOW_METHODS: + raise FeatureNotAvailable( + "Sorry, this method is not available. " + "({0})".format(node.attr)) + + try: + return self._eval(node.value)[node.attr] + except (KeyError, TypeError): + pass + + # Maybe the base object is an actual object, not just a dict + try: + return getattr(self._eval(node.value), node.attr) + except (AttributeError, TypeError): + pass + + # If it is neither, raise an exception + raise AttributeDoesNotExist(node.attr, self.expr) + + def _eval_index(self, node): + return self._eval(node.value) + + def _eval_slice(self, node): + lower = upper = step = None + if node.lower is not None: + lower = self._eval(node.lower) + if node.upper is not None: + upper = self._eval(node.upper) + if node.step is not None: + step = self._eval(node.step) + return slice(lower, upper, step) + + +def minieval(expr, env): + """ + Given a dict of variable -> value mapping in env, + parse and evaluate the expression in expr + """ + return SimpleEval(env).evaluate(expr) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.0.0+git.1513179435.e1d17d7b/crmsh/ra.py new/crmsh-4.0.0+git.1515511613.5ee0eb23/crmsh/ra.py --- old/crmsh-4.0.0+git.1513179435.e1d17d7b/crmsh/ra.py 2017-12-13 16:37:15.000000000 +0100 +++ new/crmsh-4.0.0+git.1515511613.5ee0eb23/crmsh/ra.py 2018-01-09 16:26:53.000000000 +0100 @@ -13,7 +13,7 @@ from . import options from . import userdir from . import utils -from .utils import stdout2list, is_program, is_process +from .utils import stdout2list, is_program, is_process, to_ascii from .utils import os_types_list, get_stdout, find_value from .utils import crm_msec, crm_time_cmp from .msg import common_debug, common_err, common_warn, common_info @@ -836,7 +836,8 @@ if options.regression_tests: print(".EXT", " ".join(cmd)) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=my_env) - out, _ = p.communicate() + _out, _ = p.communicate() + out = to_ascii(_out) p.wait() if log is True: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.0.0+git.1513179435.e1d17d7b/crmsh/scripts.py new/crmsh-4.0.0+git.1515511613.5ee0eb23/crmsh/scripts.py --- old/crmsh-4.0.0+git.1513179435.e1d17d7b/crmsh/scripts.py 2017-12-13 16:37:15.000000000 +0100 +++ new/crmsh-4.0.0+git.1515511613.5ee0eb23/crmsh/scripts.py 2018-01-09 16:26:53.000000000 +0100 @@ -118,6 +118,24 @@ return str(self) == str(obj) +class WhenExpr(object): + def __init__(self, script, prog): + self.script = script + self.prog = prog + + def __repr__(self): + return repr(self.prog) + + def __str__(self): + lenv = self.script.get('__values__', {}) + inp = handles.parse(self.prog, lenv).strip() + try: + from .minieval import minieval, InvalidExpression + return str(minieval(inp, lenv)).lower() + except InvalidExpression as err: + raise ValueError(str(err)) + + def _strip(desc): if desc is None: return None @@ -206,13 +224,14 @@ action['longdesc'] = Text.desc(script, action['longdesc']) hre = handles.headmatcher + ident_re = re.compile(r'([a-z_-][a-z0-9_-]*)$', re.IGNORECASE) if 'when' in action: when = action['when'] - if hre.search(when): - action['when'] = Text(script, when) - elif when: + if ident_re.match(when): action['when'] = Text(script, '{{%s}}' % (when)) + elif when: + action['when'] = WhenExpr(script, when) else: del action['when'] for k, v in action.items(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.0.0+git.1513179435.e1d17d7b/crmsh/ui_configure.py new/crmsh-4.0.0+git.1515511613.5ee0eb23/crmsh/ui_configure.py --- old/crmsh-4.0.0+git.1513179435.e1d17d7b/crmsh/ui_configure.py 2017-12-13 16:37:15.000000000 +0100 +++ new/crmsh-4.0.0+git.1515511613.5ee0eb23/crmsh/ui_configure.py 2018-01-09 16:26:53.000000000 +0100 @@ -109,9 +109,8 @@ def ra_classes_or_tmpl(args): - if args[-1].startswith('@'): - return cib_factory.rsc_template_list() - return ui_ra.complete_class_provider_type(args) + return ui_ra.complete_class_provider_type(args) + \ + ['@'+x for x in cib_factory.rsc_template_list()] def op_attr_list(args): @@ -142,7 +141,8 @@ def get_prim_token(words, n): for key in ("primitive", "rsc_template"): try: - return words[words.index(key) + n - 1] + if key in words: + return words[words.index(key) + n - 1] except IndexError: pass return '' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.0.0+git.1513179435.e1d17d7b/crmsh/ui_resource.py new/crmsh-4.0.0+git.1515511613.5ee0eb23/crmsh/ui_resource.py --- old/crmsh-4.0.0+git.1513179435.e1d17d7b/crmsh/ui_resource.py 2017-12-13 16:37:15.000000000 +0100 +++ new/crmsh-4.0.0+git.1515511613.5ee0eb23/crmsh/ui_resource.py 2018-01-09 16:26:53.000000000 +0100 @@ -195,9 +195,9 @@ } rsc_failcount = { 'set': "crm_attribute -t status -n 'fail-count-%s' -N '%s' -v '%s' -d 0", - 'delete': "crm_attribute -t status -n 'fail-count-%s' -N '%s' -D -d 0", - 'show': "crm_attribute -t status -n 'fail-count-%s' -N '%s' -G -d 0", - 'get': "crm_attribute -t status -n 'fail-count-%s' -N '%s' -G -d 0", + 'delete': "crm_failcount -D -r %s -N %s", + 'show': "crm_failcount -G -r %s -N %s", + 'get': "crm_failcount -G -r %s -N %s", } rsc_utilization = { 'set': "crm_resource -z -r '%s' -p '%s' -v '%s'", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.0.0+git.1513179435.e1d17d7b/doc/website-v1/scripts.adoc new/crmsh-4.0.0+git.1515511613.5ee0eb23/doc/website-v1/scripts.adoc --- old/crmsh-4.0.0+git.1513179435.e1d17d7b/doc/website-v1/scripts.adoc 2017-12-13 16:37:15.000000000 +0100 +++ new/crmsh-4.0.0+git.1515511613.5ee0eb23/doc/website-v1/scripts.adoc 2018-01-09 16:26:53.000000000 +0100 @@ -301,6 +301,22 @@ to be passed to the next action. Instead, the output is printed to the screen. +==== When expressions ==== + +Actions can be made conditional on the value of script parameters using +the +when:+ expression. This expression has two basic forms. + +The first form is in the form of the name of a script parameter. For +example, given a boolean script parameter named +install+, an action +can be made conditional on that parameter being true using the syntax ++when: install+. + +The second form is a more complex expression. All parameters are +interpreted as either a string value or None if no value was provided. +These can be compared to string literals using python-style +comparators. For example, an action can be conditional on the string +parameter +mode+ having the value +"advanced"+ using the following +syntax: +when: mode == "advanced"+. === Basic structure === @@ -641,3 +657,4 @@ {{^name}} ... {{/name}} = Inserts the text between the mustasches when name is falsy. ............ + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.0.0+git.1513179435.e1d17d7b/hb_report/constants.py new/crmsh-4.0.0+git.1515511613.5ee0eb23/hb_report/constants.py --- old/crmsh-4.0.0+git.1513179435.e1d17d7b/hb_report/constants.py 2017-12-13 16:37:15.000000000 +0100 +++ new/crmsh-4.0.0+git.1515511613.5ee0eb23/hb_report/constants.py 2018-01-09 16:26:53.000000000 +0100 @@ -36,7 +36,7 @@ OCF_DIR = None PACKAGES = None PCMK_LIB = None -PCMK_LOG = "/var/log/pacemaker.log" +PCMK_LOG = "/var/log/pacemaker/pacemaker.log /var/log/pacemaker.log" PE_STATE_DIR = None PTEST = "crm_simulate" SANITIZE = "passw.*" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.0.0+git.1513179435.e1d17d7b/hb_report/utillib.py new/crmsh-4.0.0+git.1515511613.5ee0eb23/hb_report/utillib.py --- old/crmsh-4.0.0+git.1513179435.e1d17d7b/hb_report/utillib.py 2017-12-13 16:37:15.000000000 +0100 +++ new/crmsh-4.0.0+git.1515511613.5ee0eb23/hb_report/utillib.py 2018-01-09 16:26:53.000000000 +0100 @@ -638,15 +638,16 @@ """ if constants.EXTRA_LOGS: for l in constants.EXTRA_LOGS.split(): - if os.path.isfile(l) and l != constants.PCMK_LOG: + if os.path.isfile(l) and l not in constants.PCMK_LOG.split(): return l tmp_f = os.path.join(constants.WORKDIR, constants.JOURNAL_F) if os.path.isfile(tmp_f): return tmp_f - if os.path.isfile(constants.PCMK_LOG): - return constants.PCMK_LOG + for l in constants.PCMK_LOG.split(): + if os.path.isfile(l): + return l if constants.HA_DEBUGFILE: log_debug("will try with %s" % constants.HA_DEBUGFILE) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-4.0.0+git.1513179435.e1d17d7b/test/unittests/test_scripts.py new/crmsh-4.0.0+git.1515511613.5ee0eb23/test/unittests/test_scripts.py --- old/crmsh-4.0.0+git.1513179435.e1d17d7b/test/unittests/test_scripts.py 2017-12-13 16:37:15.000000000 +0100 +++ new/crmsh-4.0.0+git.1515511613.5ee0eb23/test/unittests/test_scripts.py 2018-01-09 16:26:53.000000000 +0100 @@ -879,3 +879,48 @@ print(action, args) if action == 'finish': assert args[0]['value'] == '#!/bin/sh\necho "hello world"' + + +@with_setup(setup_func, teardown_func) +def test_when_expression(): + """ + Test when expressions + """ + def runtest(when, val): + the_script = '''version: 2.2 +shortdesc: Test when expressions +longdesc: See if more complicated expressions work +parameters: + - name: stringtest + type: string + shortdesc: A test string +actions: + - call: "echo '{{stringtest}}'" + when: %s +''' + scrpt = scripts.load_script_string('{}_{}'.format(when, val), the_script % when) + assert scrpt is not None + + a1 = scripts.verify(scrpt, + {"stringtest": val}, + external_check=False) + pprint(a1) + return a1 + + a1 = runtest('stringtest == "balloon"', "balloon") + assert len(a1) == 1 and a1[0]['value'] == "echo 'balloon'" + + a1 = runtest('stringtest == "balloon"', "not a balloon") + assert len(a1) == 0 + + a1 = runtest('stringtest != "balloon"', "not a balloon") + assert len(a1) == 1 + + a1 = runtest('stringtest != "balloon"', "balloon") + assert len(a1) == 0 + + a1 = runtest('stringtest == "{{dry_run}}"', "no") + assert len(a1) == 1 + + a1 = runtest('stringtest == "yes" or stringtest == "no"', "yes") + assert len(a1) == 1
