Hello community, here is the log from the commit of package crmsh for openSUSE:Factory checked in at 2015-12-09 19:52:26 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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 2015-11-22 11:02:40.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.crmsh.new/crmsh.changes 2015-12-09 22:14:37.000000000 +0100 @@ -1,0 +2,15 @@ +Mon Dec 07 08:11:25 UTC 2015 - kgronl...@suse.com + +- Update to version 2.2.0~rc3+git.1449475283.649c9d2: + + high: ui_configure: Move validate-all validation to a separate command (bsc#956442) + + high: scripts: Don't delete steps from upgraded wizards (bnc#957925) + + medium: scripts: Enable setting category in legacy wizards (bnc#957926) + + high: scripts: Don't require scripts to be an array of one element + + high: scripts: Conservatively verify scripts that modify the CIB (bsc#951954) + + high: ui_resource: Enable start/stop/status for multiple resources at once (bsc#952775) + + high: ui_resource: Add constraints and operations commands + + high: ui_ra: Add ra validate command (bsc#956442) + + high: script: Fix issues found in cluster scripts + + low: resource: Fix unban alias for unmigrate + +------------------------------------------------------------------- Old: ---- crmsh-2.2.0~rc3+git.1447774225.24dd944.tar.bz2 New: ---- crmsh-2.2.0~rc3+git.1449475283.649c9d2.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ crmsh.spec ++++++ --- /var/tmp/diff_new_pack.VYeFY0/_old 2015-12-09 22:14:39.000000000 +0100 +++ /var/tmp/diff_new_pack.VYeFY0/_new 2015-12-09 22:14:39.000000000 +0100 @@ -36,7 +36,7 @@ Summary: High Availability cluster command-line interface License: GPL-2.0+ Group: %{pkg_group} -Version: 2.2.0~rc3+git.1447774225.24dd944 +Version: 2.2.0~rc3+git.1449475283.649c9d2 Release: 0 Url: http://crmsh.github.io Source0: %{name}-%{version}.tar.bz2 @@ -92,6 +92,7 @@ Group: %{pkg_group} Requires: crmsh %if 0%{?with_regression_tests} +BuildRequires: mailx BuildRequires: procps BuildRequires: python-dateutil BuildRequires: python-nose ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.VYeFY0/_old 2015-12-09 22:14:39.000000000 +0100 +++ /var/tmp/diff_new_pack.VYeFY0/_new 2015-12-09 22:14:39.000000000 +0100 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">git://github.com/ClusterLabs/crmsh.git</param> - <param name="changesrevision">24dd9445d95803f77eeb0325b1196bf2288d1044</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">649c9d2f0f4a178adadc74f084e565e7f16ee7af</param></service></servicedata> \ No newline at end of file ++++++ crmsh-2.2.0~rc3+git.1447774225.24dd944.tar.bz2 -> crmsh-2.2.0~rc3+git.1449475283.649c9d2.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/.travis.yml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/.travis.yml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/.travis.yml 2015-11-19 14:54:28.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/.travis.yml 2015-12-07 09:11:25.000000000 +0100 @@ -1,4 +1,5 @@ --- +sudo: false language: python python: - "2.6" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/data-manifest new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/data-manifest --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/data-manifest 2015-11-19 14:54:28.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/data-manifest 2015-12-07 09:11:25.000000000 +0100 @@ -162,6 +162,7 @@ test/unittests/test_parse.py test/unittests/test_resource.py test/unittests/test_scripts.py +test/unittests/test_time.py test/unittests/test_utils.py utils/crm_clean.py utils/crm_init.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/doc/crm.8.adoc new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/doc/crm.8.adoc --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/doc/crm.8.adoc 2015-11-19 14:54:28.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/doc/crm.8.adoc 2015-12-07 09:11:25.000000000 +0100 @@ -1564,6 +1564,18 @@ providers apache ............... +[[cmdhelp_ra_validate,validate parameters for RA]] +==== `validate` + +If the resource agent supports the `validate-all` action, this calls +the action with the given parameters, printing any warnings or errors +reported by the agent. + +Usage: +................ +validate <agent> [<key>=<value> ...] +................ + [[cmdhelp_resource,Resource management]] === `resource` - Resource management @@ -1748,21 +1760,22 @@ reprobe [<node>] ............... -[[cmdhelp_resource_restart,restart a resource]] +[[cmdhelp_resource_restart,restart resources]] ==== `restart` -Restart a resource. This is essentially a shortcut for resource -stop followed by a start. The shell is first going to wait for -the stop to finish, that is for all resources to really stop, and +Restart one or more resources. This is essentially a shortcut for +resource stop followed by a start. The shell is first going to wait +for the stop to finish, that is for all resources to really stop, and only then to order the start action. Due to this command entailing a whole set of operations, informational messages are printed to let the user see some progress. -For details on group management see <<cmdhelp_options_manage-children,`options manage-children`>>. +For details on group management see +<<cmdhelp_options_manage-children,`options manage-children`>>. Usage: ............... -restart <rsc> +restart <rsc> [<rsc> ...] ............... Example: ............... @@ -1773,6 +1786,27 @@ # ............... +[[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` @@ -1811,45 +1845,48 @@ secret fence_1 set password secret_value ............... -[[cmdhelp_resource_start,start a resource]] +[[cmdhelp_resource_start,start resources]] ==== `start` -Start a resource by setting the `target-role` attribute. If there -are multiple meta attributes sets, the attribute is set in all of -them. If the resource is a clone, all `target-role` attributes -are removed from the children resources. +Start one or more resources by setting the `target-role` attribute. If +there are multiple meta attributes sets, the attribute is set in all +of them. If the resource is a clone, all `target-role` attributes are +removed from the children resources. -For details on group management see <<cmdhelp_options_manage-children,`options manage-children`>>. +For details on group management see +<<cmdhelp_options_manage-children,`options manage-children`>>. Usage: ............... -start <rsc> +start <rsc> [<rsc> ...] ............... [[cmdhelp_resource_status,show status of resources]] ==== `status` (`show`, `list`) -Print resource status. If the resource parameter is left out -status of all resources is printed. +Print resource status. More than one resource can be shown at once. If +the resource parameter is left out, the status of all resources is +printed. Usage: ............... -status [<rsc>] +status [<rsc> ...] ............... -[[cmdhelp_resource_stop,stop a resource]] +[[cmdhelp_resource_stop,stop resources]] ==== `stop` -Stop a resource using the `target-role` attribute. If there +Stop one or more resources using the `target-role` attribute. If there are multiple meta attributes sets, the attribute is set in all of -them. If the resource is a clone, all `target-role` attributes -are removed from the children resources. +them. If the resource is a clone, all `target-role` attributes are +removed from the children resources. -For details on group management see <<cmdhelp_options_manage-children,`options manage-children`>>. +For details on group management see +<<cmdhelp_options_manage-children,`options manage-children`>>. Usage: ............... -stop <rsc> +stop <rsc> [<rsc> ...] ............... [[cmdhelp_resource_trace,start RA tracing]] @@ -3754,6 +3791,23 @@ role:read_all ............... +[[cmdhelp_configure_validate_all,call agent validate-all for resource]] +==== `validate-all` + +Call the `validate-all` action for the resource, if possible. + +Limitations: + +* The resource agent must implement the `validate-all` action. +* The current user must be root. +* The primitive resource must not use nvpair references. + +Usage: +............... +validate-all <rsc> +............... + + [[cmdhelp_configure_verify,verify the CIB with crm_verify]] ==== `verify` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/doc/website-v1/scripts.adoc new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/doc/website-v1/scripts.adoc --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/doc/website-v1/scripts.adoc 2015-11-19 14:54:28.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/doc/website-v1/scripts.adoc 2015-12-07 09:11:25.000000000 +0100 @@ -333,37 +333,34 @@ [source,yaml] ---- ---- -# The triple-dash indicates that this is a yaml document. -# All yaml documents should begin with this line. # The version must be exactly 2.2, and must always be # specified in the script. If the version is missing or # is less than 2.2, the script is assumed to be a legacy # script (specified in the format used before crmsh 2.2). -- version: 2.2 - shortdesc: Virtual IP - category: Basic - include: - - agent: ocf:heartbeat:IPaddr2 - name: virtual-ip - parameters: - - name: id - type: resource - required: true - - name: ip - type: ip_address - required: true - - name: cidr_netmask - type: integer - required: false - - name: broadcast - type: ip_address - required: false - ops: | - op start timeout="20" op stop timeout="20" - op monitor interval="10" timeout="20" - actions: - - include: virtual-ip +version: 2.2 +shortdesc: Virtual IP +category: Basic +include: + - agent: ocf:heartbeat:IPaddr2 + name: virtual-ip + parameters: + - name: id + type: resource + required: true + - name: ip + type: ip_address + required: true + - name: cidr_netmask + type: integer + required: false + - name: broadcast + type: ip_address + required: false + ops: | + op start timeout="20" op stop timeout="20" + op monitor interval="10" timeout="20" +actions: + - include: virtual-ip ---- For a bigger example, here is the `apache` agent which includes @@ -377,71 +374,70 @@ # Copyright (C) 2015 Kristoffer Gronlund # # License: GNU General Public License (GPL) ---- -- version: 2.2 - category: Server - shortdesc: Apache Webserver - longdesc: | - Configure a resource group containing a virtual IP address and - an instance of the Apache web server. - - You can optionally configure a Filesystem resource which will be - mounted before the web server is started. - - You can also optionally configure a database resource which will - be started before the web server but after mounting the optional - filesystem. - include: - - agent: ocf:heartbeat:apache - name: apache - longdesc: | - The Apache configuration file specified here must be available via the - same path on all cluster nodes, and Apache must be configured with - mod_status enabled. If in doubt, try running Apache manually via - its init script first, and ensure http://localhost:80/server-status is - accessible. - ops: | - op start timeout="40" - op stop timeout="60" - op monitor interval="10" timeout="20" - - script: virtual-ip - shortdesc: The IP address configured here will start before the Apache instance. - parameters: - - name: id - value: "{{id}}-vip" - - script: filesystem - shortdesc: Optional filesystem mounted before the web server is started. - required: false - - script: database - shortdesc: Optional database started before the web server is started. - required: false - parameters: - - name: install - type: boolean - shortdesc: Install and configure apache - value: false - actions: - - install: - - apache2 - shortdesc: Install the apache package - when: install - - service: - - apache: disable - shortdesc: Let cluster manage apache - when: install - - call: a2enmod status; true - shortdesc: Enable status module - when: install - - include: filesystem - - include: database - - include: virtual-ip - - include: apache - - cib: | - group g-{{id}} - {{filesystem:id}} - {{database:id}} - {{virtual-ip:id}} - {{id}} +version: 2.2 +category: Server +shortdesc: Apache Webserver +longdesc: | + Configure a resource group containing a virtual IP address and + an instance of the Apache web server. + + You can optionally configure a Filesystem resource which will be + mounted before the web server is started. + + You can also optionally configure a database resource which will + be started before the web server but after mounting the optional + filesystem. +include: + - agent: ocf:heartbeat:apache + name: apache + longdesc: | + The Apache configuration file specified here must be available via the + same path on all cluster nodes, and Apache must be configured with + mod_status enabled. If in doubt, try running Apache manually via + its init script first, and ensure http://localhost:80/server-status is + accessible. + ops: | + op start timeout="40" + op stop timeout="60" + op monitor interval="10" timeout="20" + - script: virtual-ip + shortdesc: The IP address configured here will start before the Apache instance. + parameters: + - name: id + value: "{{id}}-vip" + - script: filesystem + shortdesc: Optional filesystem mounted before the web server is started. + required: false + - script: database + shortdesc: Optional database started before the web server is started. + required: false +parameters: + - name: install + type: boolean + shortdesc: Install and configure apache + value: false +actions: + - install: + - apache2 + shortdesc: Install the apache package + when: install + - service: + - apache: disable + shortdesc: Let cluster manage apache + when: install + - call: a2enmod status; true + shortdesc: Enable status module + when: install + - include: filesystem + - include: database + - include: virtual-ip + - include: apache + - cib: | + group g-{{id}} + {{filesystem:id}} + {{database:id}} + {{virtual-ip:id}} + {{id}} ---- The language for referring to parameter values in `cib` actions is diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/cibconfig.py new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/cibconfig.py --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/cibconfig.py 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/cibconfig.py 2015-12-07 09:11:25.000000000 +0100 @@ -17,7 +17,7 @@ from . import clidisplay from .cibstatus import cib_status from . import idmgmt -from .ra import get_ra, get_properties_list, get_pe_meta +from .ra import get_ra, get_properties_list, get_pe_meta, can_validate_agent, validate_agent from . import schema from .crm_gv import gv_types from .msg import common_warn, common_err, common_debug, common_info, err_buf diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/ra.py new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/ra.py --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/ra.py 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/ra.py 2015-12-07 09:11:25.000000000 +0100 @@ -828,4 +828,55 @@ pr = pick_provider(ra_providers(tp, cl)) if cl == 'ocf' else '' return cl, pr, tp + +def can_validate_agent(agent): + if utils.getuser() != 'root': + return False + if isinstance(agent, basestring): + c, p, t = disambiguate_ra_type(agent) + if c != "ocf": + return False + agent = RAInfo(c, t, p) + if agent.mk_ra_node() is None: + return False + if len(agent.ra_elem.xpath('.//actions/action[@name="validate-all"]')) < 1: + return False + return True + + +def validate_agent(agentname, params): + """ + Call the validate-all action on the agent, given + the parameter hash params. + agent: either a c:p:t agent name, or an RAInfo instance + params: a hash of agent parameters + Returns: (rc, out) + """ + if not can_validate_agent(agentname): + return (-1, "") + if isinstance(agentname, basestring): + c, p, t = disambiguate_ra_type(agentname) + if c != "ocf": + raise ValueError("Only OCF agents are supported by this command") + agent = RAInfo(c, t, p) + if agent.mk_ra_node() is None: + return (-1, "") + else: + agent = agentname + if len(agent.ra_elem.xpath('.//actions/action[@name="validate-all"]')) < 1: + raise ValueError("validate-all action not supported by agent") + + my_env = os.environ.copy() + my_env["OCF_ROOT"] = config.path.ocf_root + for k, v in params.iteritems(): + my_env["OCF_RESKEY_" + k] = v + cmd = [os.path.join(config.path.ocf_root, "resource.d", agent.ra_provider, agent.ra_type), "validate-all"] + if options.regression_tests: + print ".EXT", " ".join(cmd) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=my_env) + out, _ = p.communicate() + p.wait() + return p.returncode, out + + # vim:ts=4:sw=4:et: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/scripts.py new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/scripts.py --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/scripts.py 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/scripts.py 2015-12-07 09:11:25.000000000 +0100 @@ -399,7 +399,9 @@ try: import yaml with open(scriptfile) as f: - data = yaml.load(f)[0] + data = yaml.load(f) + if isinstance(data, list): + data = data[0] except ImportError as e: raise ValueError("Failed to load yaml module: %s" % (e)) except Exception as e: @@ -413,7 +415,7 @@ if 'parameters' in data: data['steps'] = [{'parameters': data['parameters']}] del data['parameters'] - else: + elif 'steps' not in data: data['steps'] = [] data['name'] = scriptname data['dir'] = os.path.dirname(scriptfile) @@ -537,7 +539,7 @@ 'name': scriptname, 'shortdesc': _strip(''.join(xml.xpath('./shortdesc/text()'))), 'longdesc': ''.join(xml.xpath('./longdesc/text()')), - 'category': 'Wizard', + 'category': ''.join(xml.xpath('./@category')) or 'Wizard', 'dir': None, 'steps': [], 'actions': [], @@ -1001,11 +1003,13 @@ _build_script_cache() import cStringIO import yaml - data = yaml.load(cStringIO.StringIO(yml))[0] + data = yaml.load(cStringIO.StringIO(yml)) + if isinstance(data, list): + data = data[0] if 'parameters' in data: data['steps'] = [{'parameters': data['parameters']}] del data['parameters'] - else: + elif 'steps' not in data: data['steps'] = [] data['name'] = script data['dir'] = None @@ -2120,7 +2124,7 @@ return ret -def verify(script, params): +def verify(script, params, external_check=True): """ Verify the given parameter values, reporting errors where such are detected. @@ -2129,6 +2133,31 @@ """ params = _check_parameters(script, params) actions = _process_actions(script, params) + + if external_check and all(action['name'] == 'cib' for action in actions) and utils.is_program('crm'): + errors = set([]) + cmd = ["cib new"] + for action in actions: + cmd.append(_join_script_lines(action['value'])) + cmd.extend(["verify", "commit", "\n"]) + try: + common_debug("Try executing %s" % ("\n".join(cmd))) + rc, out = utils.filter_string(['crm', '-f', '-', 'configure'], "\n".join(cmd), stderr_on='stdout', shell=False) + errm = re.compile(r"^ERROR: \d+: (.*)$") + outp = [] + for l in (out or "").splitlines(): + m = errm.match(l) + if m: + errors.add(m.group(1)) + else: + outp.append(l) + if rc != 0 and len(errors) == 0: + errors.add("Failed to verify (rc=%s): %s" % (rc, "\n".join(outp))) + except OSError as e: + errors.add(str(e)) + if len(errors): + raise ValueError("\n".join(errors)) + return actions diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/ui_configure.py new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/ui_configure.py --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/ui_configure.py 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/ui_configure.py 2015-12-07 09:11:25.000000000 +0100 @@ -438,6 +438,47 @@ set_obj_all = mkset_obj("xml") return self._verify(set_obj_all, set_obj_all) + @command.name('validate-all') + @command.alias('validate_all') + @command.skill_level('administrator') + @command.completers_repeating(_id_list) + def do_validate_all(self, context, rsc): + "usage: validate-all <rsc>" + from . import ra + from . import cibconfig + from . import cliformat + from . import msg as msglog + obj = cib_factory.find_object(rsc) + if not obj: + context.error("Not found: %s" % (rsc)) + if obj.obj_type != "primitive": + context.error("Not a primitive: %s" % (rsc)) + rnode = cibconfig.reduce_primitive(obj.node) + if rnode is None: + context.error("No resource template %s for %s" % (self.node.get("template"), rsc)) + params = [] + for attrs in rnode.iterchildren("instance_attributes"): + params.extend(cliformat.nvpairs2list(attrs)) + if not all(nvp.get('name') is not None and nvp.get('value') is not None for nvp in params): + context.error("Primitive too complex: %s" % (rsc)) + params = dict([(nvp.get('name'), nvp.get('value')) for nvp in params]) + agentname = xmlutil.mk_rsc_type(rnode) + if not ra.can_validate_agent(agentname): + context.error("%s: Cannot run validate-all for agent: %s" % (rsc, agentname)) + rc, out = ra.validate_agent(agentname, params) + for msg in out.splitlines(): + if msg.startswith("ERROR: "): + msglog.err_buf.error(msg[7:]) + elif msg.startswith("WARNING: "): + msglog.err_buf.warning(msg[9:]) + elif msg.startswith("INFO: "): + msglog.err_buf.info(msg[6:]) + elif msg.startswith("DEBUG: "): + msglog.err_buf.debug(msg[7:]) + else: + msglog.err_buf.writemsg(msg) + return rc == 0 + @command.skill_level('administrator') @command.completers_repeating(_id_show_list) def do_save(self, context, *args): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/ui_ra.py new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/ui_ra.py --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/ui_ra.py 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/ui_ra.py 2015-12-07 09:11:25.000000000 +0100 @@ -8,6 +8,7 @@ from . import ra from . import constants from . import options +from . import msg as msglog def complete_class_provider_type(args): @@ -90,3 +91,20 @@ utils.page_string(agent.meta_pretty()) except Exception, msg: context.fatal_error(msg) + + @command.skill_level('administrator') + def do_validate(self, context, agentname, *params): + "usage: validate [<class>:[<provider>:]]<type> [<key>=<value> ...]" + rc, out = ra.validate_agent(agentname, dict([param.split('=', 1) for param in params])) + for msg in out.splitlines(): + if msg.startswith("ERROR: "): + msglog.err_buf.error(msg[7:]) + elif msg.startswith("WARNING: "): + msglog.err_buf.warning(msg[9:]) + elif msg.startswith("INFO: "): + msglog.err_buf.info(msg[6:]) + elif msg.startswith("DEBUG: "): + msglog.err_buf.debug(msg[7:]) + else: + msglog.err_buf.writemsg(msg) + return rc == 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/ui_resource.py new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/ui_resource.py --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/ui_resource.py 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/ui_resource.py 2015-12-07 09:11:25.000000000 +0100 @@ -222,12 +222,15 @@ @command.alias('show', 'list') @command.completers(compl.resources) - def do_status(self, context, rsc=None): - "usage: status [<rsc>]" - if rsc: - if not utils.is_name_sane(rsc): - return False - return utils.ext_cmd(self.rsc_status % rsc) == 0 + def do_status(self, context, *resources): + "usage: status [<rsc> ...]" + if len(resources) > 0: + rc = True + for rsc in resources: + if not utils.is_name_sane(rsc): + return False + rc = rc and (utils.ext_cmd(self.rsc_status % rsc) == 0) + return rc else: return utils.ext_cmd(self.rsc_status_all) == 0 @@ -242,29 +245,54 @@ context.info("Currently editing the CIB, changes will not be committed") return set_deep_meta_attr(rsc, name, value, commit=commit) + def _commit_meta_attrs(self, context, resources, name, value): + """ + Perform change to list of resources + """ + for rsc in resources: + if not utils.is_name_sane(rsc): + return False + commit = not cib_factory.has_cib_changed() + if not commit: + context.info("Currently editing the CIB, changes will not be committed") + + rc = True + for rsc in resources: + rc = rc and set_deep_meta_attr(rsc, name, value, commit=False) + if commit and rc: + ok = cib_factory.commit() + if not ok: + common_error("Failed to commit updates to %s" % (rsc)) + return ok + return rc + @command.wait @command.completers(compl.resources) - def do_start(self, context, rsc): - "usage: start <rsc>" - return self._commit_meta_attr(context, rsc, "target-role", "Started") + def do_start(self, context, *resources): + "usage: start <rsc> [<rsc> ...]" + if len(resources) == 0: + context.error("Expected at least one resource as argument") + return self._commit_meta_attrs(context, resources, "target-role", "Started") @command.wait @command.completers(compl.resources) - def do_stop(self, context, rsc): - "usage: stop <rsc>" - return self._commit_meta_attr(context, rsc, "target-role", "Stopped") + def do_stop(self, context, *resources): + "usage: stop <rsc> [<rsc> ...]" + if len(resources) == 0: + context.error("Expected at least one resource as argument") + return self._commit_meta_attrs(context, resources, "target-role", "Stopped") @command.wait @command.completers(compl.resources) - def do_restart(self, context, rsc): - "usage: restart <rsc>" - common_info("ordering %s to stop" % rsc) - if not self._commit_meta_attr(context, rsc, "target-role", "Stopped"): + def do_restart(self, context, *resources): + "usage: restart <rsc> [<rsc> ...]" + common_info("ordering %s to stop" % ", ".join(resources)) + if not self._commit_meta_attrs(context, resources, "target-role", "Stopped"): return False if not utils.wait4dc("stop", not options.batch): return False - common_info("ordering %s to start" % rsc) - return self._commit_meta_attr(context, rsc, "target-role", "Started") + common_info("ordering %s to start" % ", ".join(resources)) + return self._commit_meta_attrs(context, resources, "target-role", "Started") @command.wait @command.completers(compl.resources) @@ -357,8 +385,7 @@ opts = "%s --force" % opts return utils.ext_cmd(self.rsc_ban % (rsc, opts)) == 0 - @command.alias('unmove') - @command.alias('unban') + @command.alias('unmove', 'unban') @command.skill_level('administrator') @command.wait @command.completers(compl.resources) @@ -378,6 +405,23 @@ return cleanup_resource(resource, node) @command.wait + @command.completers(compl.resources, compl.nodes) + def do_operations(self, context, resource=None, node=None): + "usage: operations [<rsc>] [<node>]" + cmd = "crm_resource -O" + if resource is None: + return utils.ext_cmd(cmd) + if node is None: + return utils.ext_cmd("%s -r '%s'" % (cmd, resource)) + return utils.ext_cmd("%s -r '%s' -N '%s'" % (cmd, resource, node)) + + @command.wait + @command.completers(compl.resources) + def do_constraints(self, context, resource): + "usage: constraints <rsc>" + return utils.ext_cmd("crm_resource -a -r '%s'" % (resource)) + + @command.wait @command.completers(compl.resources, _attrcmds, compl.nodes) def do_failcount(self, context, rsc, cmd, node, value=None): """usage: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/ui_script.py new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/ui_script.py --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/ui_script.py 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/ui_script.py 2015-12-07 09:11:25.000000000 +0100 @@ -331,36 +331,67 @@ pprint.pprint(ret) @command.name('_convert') - def do_convert(self, context, fromdir, tgtdir): + def do_convert(self, context, workflow, outdir=".", category="basic"): """ Convert hawk wizards to cluster scripts Needs more work to be really useful. - fromdir: hawk wizard directory + workflow: hawk workflow script tgtdir: where the cluster script will be written + category: category set in new wizard """ import yaml import os - import glob - if not os.path.isdir(fromdir): - context.fatal_error("Expected <fromdir> <todir>") + from collections import OrderedDict + + def flatten(script): + if not isinstance(script, dict): + return script + + for k, v in script.iteritems(): + if isinstance(v, scripts.Text): + script[k] = str(v) + elif isinstance(v, dict): + script[k] = flatten(v) + elif isinstance(v, tuple) or isinstance(v, list): + script[k] = [flatten(vv) for vv in v] + elif isinstance(v, basestring): + script[k] = v.strip() + + return script + + def order_rep(dumper, data): + return dumper.represent_mapping(u'tag:yaml.org,2002:map', data.items(), flow_style=False) + + def scriptsorter(item): + order = ["version", "name", "category", "shortdesc", "longdesc", "include", "parameters", "steps", "actions"] + return order.index(item[0]) + + yaml.add_representer(OrderedDict, order_rep) + fromscript = os.path.abspath(workflow) + tgtdir = outdir + scripts._build_script_cache() - if not os.path.isdir(tgtdir): - context.fatal_error("Expected <fromdir> <todir>") - for f in glob.glob(os.path.join(fromdir, 'workflows/*.xml')): - name = os.path.splitext(os.path.basename(f))[0] - script = scripts._load_script_file(name, f) - if script is not None: + name = os.path.splitext(os.path.basename(fromscript))[0] + script = scripts._load_script_file(name, fromscript) + script = flatten(script) + script["category"] = category + del script["name"] + del script["dir"] + script["actions"] = [{"cib": "\n\n".join([action["cib"] for action in script["actions"]])}] + + script = OrderedDict(sorted(script.items(), key=scriptsorter)) + if script is not None: + try: + os.mkdir(os.path.join(tgtdir, name)) + except: + pass + tgtfile = os.path.join(tgtdir, name, "main.yml") + with open(tgtfile, 'w') as tf: try: - os.mkdir(os.path.join(tgtdir, name)) - except: - pass - tgtfile = os.path.join(tgtdir, name, "main.yml") - with open(tgtfile, 'w') as tf: - try: - print("%s -> %s" % (f, tgtfile)) - yaml.dump(script, tf, default_flow_style=False) - except Exception as err: - print(err) + print("%s -> %s" % (fromscript, tgtfile)) + yaml.dump([script], tf, explicit_start=True, default_flow_style=False) + except Exception as err: + print(err) def _json_list(self, context, cmd): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/utils.py new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/utils.py --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/modules/utils.py 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/modules/utils.py 2015-12-07 09:11:25.000000000 +0100 @@ -244,10 +244,10 @@ return rc -def filter_string(cmd, s, stderr_on=True): +def filter_string(cmd, s, stderr_on=True, shell=True): rc = -1 # command failed outp = '' - if stderr_on: + if stderr_on is True: stderr = None else: stderr = subprocess.PIPE @@ -256,12 +256,16 @@ if options.regression_tests: print ".EXT", cmd p = subprocess.Popen(cmd, - shell=True, + shell=shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=stderr) try: - outp = p.communicate(s)[0] + ret = p.communicate(s) + if stderr_on == 'stdout': + outp = "\n".join(ret) + else: + outp = ret[0] p.wait() rc = p.returncode except OSError, (errno, strerror): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/clvm/main.yml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/clvm/main.yml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/clvm/main.yml 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/clvm/main.yml 2015-12-07 09:11:25.000000000 +0100 @@ -13,7 +13,17 @@ To create volume groups after configuring cLVM, the wizard for cLVM volume groups can be used. + parameters: + - name: install + type: boolean + shortdesc: Install packages for cLVM + value: false + actions: + - install: + - lvm2-clvm + shortdesc: Install the clvm package + when: install - cib: | primitive dlm ocf:pacemaker:controld op start timeout=90s @@ -25,6 +35,6 @@ op stop timeout=100s group g-clvm dlm clvm - + clone c-clvm g-clvm meta interleave=true ordered=true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/db2/main.yml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/db2/main.yml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/db2/main.yml 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/db2/main.yml 2015-12-07 09:11:25.000000000 +0100 @@ -40,8 +40,8 @@ - include: db2 - cib: | group g-{{id}} - {{virtual-ip}} - {{filesystem}} + {{virtual-ip:id}} + {{filesystem:id}} {{id}} meta target-role=Stopped diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/db2-hadr/main.yml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/db2-hadr/main.yml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/db2-hadr/main.yml 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/db2-hadr/main.yml 2015-12-07 09:11:25.000000000 +0100 @@ -38,8 +38,7 @@ - include: virtual-ip - include: db2 - cib: | - ms ms-{{id}} {{id}} + ms ms-{{db2:id}} {{db2:id}} meta target-role=Stopped notify=true - - colocation {{virtual-ip:id}}-with-master inf: {{virtual-ip:id}}:Started ms-{{id}}:Master - order {{virtual-ip:id}}-after-master inf: ms-{{id}}:promote {{virtual-ip:id}}:start + colocation {{virtual-ip:id}}-with-master inf: {{virtual-ip:id}}:Started ms-{{db2:id}}:Master + order {{virtual-ip:id}}-after-master inf: ms-{{db2:id}}:promote {{virtual-ip:id}}:start diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/drbd/main.yml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/drbd/main.yml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/drbd/main.yml 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/drbd/main.yml 2015-12-07 09:11:25.000000000 +0100 @@ -20,9 +20,15 @@ type: string - name: drbdconf value: "/etc/drbd.conf" + - name: install + type: boolean + shortdesc: Install packages for DRBD + value: false actions: - install: drbd drbd-kmp-default + shortdesc: Install packages for DRBD + when: install - cib: | primitive {{id}} ocf:linbit:drbd params diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/filesystem/main.yml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/filesystem/main.yml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/filesystem/main.yml 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/filesystem/main.yml 2015-12-07 09:11:25.000000000 +0100 @@ -22,7 +22,7 @@ required: false type: string ops: | - meta target-state=Stopped + meta target-role=Stopped op start timeout=60s op stop timeout=60s op monitor interval=20s timeout=40s diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/sap-simple-stack/main.yml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/sap-simple-stack/main.yml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/sap-simple-stack/main.yml 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/sap-simple-stack/main.yml 2015-12-07 09:11:25.000000000 +0100 @@ -169,8 +169,8 @@ - include: sapinstance-ci - cib: group {{id}} - {{raid1}} - {{lvm}} + {{raid1:id}} + {{lvm:id}} {{virtual-ip-ci:id}} {{virtual-ip-db:id}} {{virtual-ip-as:id}} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/sap-simple-stack-plus/main.yml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/sap-simple-stack-plus/main.yml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/sap-simple-stack-plus/main.yml 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/sap-simple-stack-plus/main.yml 2015-12-07 09:11:25.000000000 +0100 @@ -206,8 +206,8 @@ - include: sapinstance-ci - cib: group {{id}} - {{raid1}} - {{lvm}} + {{raid1:id}} + {{lvm:id}} {{virtual-ip-db:id}} {{filesystem-sapmnt:id}} {{filesystem-db:id}} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/sapdb/main.yml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/sapdb/main.yml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/scripts/sapdb/main.yml 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/scripts/sapdb/main.yml 2015-12-07 09:11:25.000000000 +0100 @@ -26,10 +26,8 @@ actions: - cib: | - primitive {{id}} ocf:heartbeat:SAPdatabase - params - SID="{{SID}}" - DBTYPE="{{DBTYPE}}" + primitive {{id}} ocf:heartbeat:SAPDatabase + params SID="{{SID}}" DBTYPE="{{DBTYPE}}" op monitor interval="120" timeout="60" start_delay="180" op start timeout="1800" op stop timeout="1800" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/cibtests/002.exp.xml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/cibtests/002.exp.xml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/cibtests/002.exp.xml 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/cibtests/002.exp.xml 2015-12-07 09:11:25.000000000 +0100 @@ -12,11 +12,9 @@ <nvpair name="ordered" value="true" id="testfs-clone-meta_attributes-ordered"/> <nvpair name="interleave" value="true" id="testfs-clone-meta_attributes-interleave"/> </meta_attributes> - <primitive id="testfs" class="ocf" provider="heartbeat" type="Filesystem"> + <primitive id="testfs" class="ocf" provider="heartbeat" type="Dummy"> <instance_attributes id="testfs-instance_attributes"> - <nvpair name="directory" value="/mnt" id="testfs-instance_attributes-directory"/> - <nvpair name="fstype" value="ocfs2" id="testfs-instance_attributes-fstype"/> - <nvpair name="device" value="/dev/sda1" id="testfs-instance_attributes-device"/> + <nvpair name="fake" value="1" id="testfs-instance_attributes-fake"/> </instance_attributes> </primitive> </clone> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/cibtests/002.input new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/cibtests/002.input --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/cibtests/002.input 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/cibtests/002.input 2015-12-07 09:11:25.000000000 +0100 @@ -1,7 +1,7 @@ configure property stonith-enabled=false -primitive testfs ocf:heartbeat:Filesystem \ - params directory="/mnt" fstype="ocfs2" device="/dev/sda1" +primitive testfs ocf:heartbeat:Dummy \ + params fake=1 clone testfs-clone testfs \ meta ordered="true" interleave="true" commit diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/cibtests/003.exp.xml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/cibtests/003.exp.xml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/cibtests/003.exp.xml 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/cibtests/003.exp.xml 2015-12-07 09:11:25.000000000 +0100 @@ -13,11 +13,9 @@ <nvpair name="interleave" value="true" id="testfs-clone-meta_attributes-interleave"/> <nvpair id="testfs-clone-meta_attributes-target-role" name="target-role" value="Stopped"/> </meta_attributes> - <primitive id="testfs" class="ocf" provider="heartbeat" type="Filesystem"> + <primitive id="testfs" class="ocf" provider="heartbeat" type="Dummy"> <instance_attributes id="testfs-instance_attributes"> - <nvpair name="directory" value="/mnt" id="testfs-instance_attributes-directory"/> - <nvpair name="fstype" value="ocfs2" id="testfs-instance_attributes-fstype"/> - <nvpair name="device" value="/dev/sda1" id="testfs-instance_attributes-device"/> + <nvpair name="fake" value="2" id="testfs-instance_attributes-fake"/> </instance_attributes> </primitive> </clone> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/cibtests/003.input new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/cibtests/003.input --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/cibtests/003.input 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/cibtests/003.input 2015-12-07 09:11:25.000000000 +0100 @@ -1,7 +1,7 @@ configure property stonith-enabled=false -primitive testfs ocf:heartbeat:Filesystem \ - params directory="/mnt" fstype="ocfs2" device="/dev/sda1" +primitive testfs ocf:heartbeat:Dummy \ + params fake=2 clone testfs-clone testfs \ meta ordered="true" interleave="true" commit diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/cibtests/004.exp.xml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/cibtests/004.exp.xml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/cibtests/004.exp.xml 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/cibtests/004.exp.xml 2015-12-07 09:11:25.000000000 +0100 @@ -13,11 +13,9 @@ <nvpair name="interleave" value="true" id="testfs-clone-meta_attributes-interleave"/> <nvpair id="testfs-clone-meta_attributes-target-role" name="target-role" value="Started"/> </meta_attributes> - <primitive id="testfs" class="ocf" provider="heartbeat" type="Filesystem"> + <primitive id="testfs" class="ocf" provider="heartbeat" type="Dummy"> <instance_attributes id="testfs-instance_attributes"> - <nvpair name="directory" value="/mnt" id="testfs-instance_attributes-directory"/> - <nvpair name="fstype" value="ocfs2" id="testfs-instance_attributes-fstype"/> - <nvpair name="device" value="/dev/sda1" id="testfs-instance_attributes-device"/> + <nvpair name="fake" value="hello" id="testfs-instance_attributes-fake"/> </instance_attributes> </primitive> </clone> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/cibtests/004.input new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/cibtests/004.input --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/cibtests/004.input 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/cibtests/004.input 2015-12-07 09:11:25.000000000 +0100 @@ -1,7 +1,7 @@ configure property stonith-enabled=false -primitive testfs ocf:heartbeat:Filesystem \ - params directory="/mnt" fstype="ocfs2" device="/dev/sda1" +primitive testfs ocf:heartbeat:Dummy \ + params fake=hello clone testfs-clone testfs \ meta ordered="true" interleave="true" commit diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/testcases/common.excl new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/testcases/common.excl --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/testcases/common.excl 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/testcases/common.excl 2015-12-07 09:11:25.000000000 +0100 @@ -18,3 +18,4 @@ ^\.EXT crm_diff \-\-no\-version \-o [^ ]+ \-n \- ^\.EXT sed ['][^']+ ^\.EXT sed ["][^"]+ +^\.EXT [a-zA-Z]+ validate-all diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/testcases/scripts new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/testcases/scripts --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/testcases/scripts 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/testcases/scripts 2015-12-07 09:11:25.000000000 +0100 @@ -6,7 +6,7 @@ list names all list all names list bogus -show virtual-ip -verify virtual-ip id=foo ip=10.0.0.5 -run virtual-ip id=foo ip=10.0.0.5 nodes=node1 dry_run=true +show mailto +verify mailto id=foo email=t...@example.com subject=hello +run mailto id=foo email=t...@example.com subject=hello nodes=node1 dry_run=true . diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/testcases/scripts.exp new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/testcases/scripts.exp --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/testcases/scripts.exp 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/testcases/scripts.exp 2015-12-07 09:11:25.000000000 +0100 @@ -219,45 +219,53 @@ virtual-ip .INP: list bogus ERROR: 7: script.list: Unexpected argument 'bogus': expected [all|names] -.INP: show virtual-ip -virtual-ip (Basic) -Virtual IP - - This Linux-specific resource manages IP alias IP addresses. It can -add an IP alias, or remove one. In addition, it can implement Cluster -Alias IP functionality if invoked as a clone resource. - -If used as a clone, you should explicitly set clone-node-max >= 2, -and/or clone-max < number of nodes. In case of node failure, clone -instances need to be re-allocated on surviving nodes. This would not -be possible if there is already an instance on those nodes, and clone- -node-max=1 (which is the default). +.INP: show mailto +mailto (Basic) +MailTo -1. Manages virtual IPv4 and IPv6 addresses (Linux specific version) + This is a resource agent for MailTo. It sends email to a sysadmin +whenever a takeover occurs. + +1. Notifies recipients by email in the event of resource takeover id (required) (unique) Identifier for the cluster resource - ip (required) (unique) - IPv4 or IPv6 address - cidr_netmask - CIDR netmask - broadcast - Broadcast address - - -.INP: verify virtual-ip id=foo ip=10.0.0.5 -1. Configure cluster resources - - primitive foo ocf:heartbeat:IPaddr2 - ip="10.0.0.5" - op start timeout="20" op stop timeout="20" - op monitor interval="10" timeout="20" + email (required) + Email address + subject + Subject + + +.INP: verify mailto id=foo email=t...@example.com subject=hello +1. Ensure mail package is installed + + mailx + +2. Configure cluster resources + + primitive foo ocf:heartbeat:MailTo + email="t...@example.com" + subject="hello" + op start timeout="10" + op stop timeout="10" + op monitor interval="10" timeout="10" + + clone c-foo foo -.INP: run virtual-ip id=foo ip=10.0.0.5 nodes=node1 dry_run=true -INFO: 10: Virtual IP +.INP: run mailto id=foo email=t...@example.com subject=hello nodes=node1 dry_run=true +INFO: 10: MailTo INFO: 10: Nodes: node1 +** all - #!/usr/bin/env python +import crm_script +import crm_init + +crm_init.install_packages(['mailx']) +crm_script.exit_ok(True) + +OK: 10: Ensure mail package is installed ** localhost - temporary file <<END -primitive foo ocf:heartbeat:IPaddr2 ip="10.0.0.5" op start timeout="20" op stop timeout="20" op monitor interval="10" timeout="20" +primitive foo ocf:heartbeat:MailTo email="t...@example.com" subject="hello" op start timeout="10" op stop timeout="10" op monitor interval="10" timeout="10" +clone c-foo foo END diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/unittests/scripts/inc1/main.yml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/unittests/scripts/inc1/main.yml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/unittests/scripts/inc1/main.yml 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/unittests/scripts/inc1/main.yml 2015-12-07 09:11:25.000000000 +0100 @@ -1,23 +1,22 @@ ---- -- version: 2.2 - shortdesc: Include test script 1 - longdesc: Test if includes work ok - parameters: - - name: foo - type: boolean - shortdesc: An optional feature - - name: bar - type: string - shortdesc: A string of characters - value: the name is the game - - name: is-required - type: int - required: true - actions: - - call: ls /tmp - when: foo - shortdesc: ls - - call: "echo '{{foo}}'" - shortdesc: foo - - call: "echo '{{bar}}'" - shortdesc: bar +version: 2.2 +shortdesc: Include test script 1 +longdesc: Test if includes work ok +parameters: + - name: foo + type: boolean + shortdesc: An optional feature + - name: bar + type: string + shortdesc: A string of characters + value: the name is the game + - name: is-required + type: int + required: true +actions: + - call: ls /tmp + when: foo + shortdesc: ls + - call: "echo '{{foo}}'" + shortdesc: foo + - call: "echo '{{bar}}'" + shortdesc: bar diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/unittests/scripts/unified/main.yml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/unittests/scripts/unified/main.yml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/unittests/scripts/unified/main.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/unittests/scripts/unified/main.yml 2015-12-07 09:11:25.000000000 +0100 @@ -0,0 +1,26 @@ +version: 2.2 +shortdesc: Unified Script +longdesc: > + Test if we can define multiple steps in a single script +category: test +steps: + - parameters: + - name: id + type: resource + required: true + shortdesc: Identifier + - name: vip + shortdesc: Configure the virtual IP + parameters: + - name: id + type: resource + required: true + shortdesc: IP Identifier + - name: ip + type: ip_address + required: true + shortdesc: The IP Address +actions: + - cib: | + primitive {{vip:id}} IPaddr2 ip={{vip:ip}} + group g-{{id}} {{id}} {{vip:id}} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/unittests/scripts/vipinc/main.yml new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/unittests/scripts/vipinc/main.yml --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/unittests/scripts/vipinc/main.yml 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/unittests/scripts/vipinc/main.yml 2015-12-07 09:11:25.000000000 +0100 @@ -1,15 +1,14 @@ ---- -- version: 2.2 - category: Test - shortdesc: Test script include - include: - - script: vip - parameters: - - name: id - value: vip1 - - name: ip - value: 192.168.200.100 - actions: - - include: vip - - cib: | - clone c-{{vip:id}} {{vip:id}} +version: 2.2 +category: Test +shortdesc: Test script include +include: + - script: vip + parameters: + - name: id + value: vip1 + - name: ip + value: 192.168.200.100 +actions: + - include: vip + - cib: | + clone c-{{vip:id}} {{vip:id}} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/unittests/test_scripts.py new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/unittests/test_scripts.py --- old/crmsh-2.2.0~rc3+git.1447774225.24dd944/test/unittests/test_scripts.py 2015-11-19 14:54:29.000000000 +0100 +++ new/crmsh-2.2.0~rc3+git.1449475283.649c9d2/test/unittests/test_scripts.py 2015-12-07 09:11:25.000000000 +0100 @@ -453,7 +453,7 @@ def test_list(): - eq_(set(['v2', 'legacy', '10-webserver', 'inc1', 'inc2', 'vip', 'vipinc']), + eq_(set(['v2', 'legacy', '10-webserver', 'inc1', 'inc2', 'vip', 'vipinc', 'unified']), set(s for s in scripts.list_scripts())) @@ -464,7 +464,7 @@ eq_('legacy', script['name']) assert len(script['shortdesc']) > 0 pprint(script) - actions = scripts.verify(script, {}) + actions = scripts.verify(script, {}, external_check=False) pprint(actions) eq_([{'longdesc': '', 'name': 'apply_local', @@ -522,7 +522,7 @@ {'id': 'www', 'apache': {'id': 'apache'}, 'virtual-ip': {'id': 'www-vip', 'ip': '192.168.1.100'}, - 'install': False}) + 'install': False}, external_check=False) pprint(actions) eq_(len(actions), 1) assert str(actions[0]['text']).find('group www') >= 0 @@ -532,7 +532,7 @@ {'id': 'www', 'apache': {'id': 'apache'}, 'virtual-ip': {'id': 'www-vip', 'ip': '192.168.1.100'}, - 'install': True}) + 'install': True}, external_check=False) pprint(actions) eq_(len(actions), 3) @@ -544,7 +544,7 @@ inc2, {'wiz': 'abc', 'foo': 'cde', - 'included-script': {'foo': True, 'bar': 'bah bah'}}) + 'included-script': {'foo': True, 'bar': 'bah bah'}}, external_check=False) pprint(actions) eq_(len(actions), 6) eq_('33\n\nabc', actions[-1]['text'].strip()) @@ -556,7 +556,7 @@ assert script is not None actions = scripts.verify( script, - {'vip': {'id': 'vop', 'ip': '10.0.0.4'}}) + {'vip': {'id': 'vop', 'ip': '10.0.0.4'}}, external_check=False) eq_(len(actions), 1) pprint(actions) assert actions[0]['text'].find('primitive vop test:virtual-ip\n\tip="10.0.0.4"') >= 0 @@ -592,7 +592,7 @@ assert script_a is not None assert script_b is not None actions = scripts.verify(script_b, - {'wiz': "SARUMAN"}) + {'wiz': "SARUMAN"}, external_check=False) eq_(len(actions), 1) pprint(actions) assert actions[0]['text'] == "SARUMAN+SARUMAN" @@ -632,7 +632,7 @@ assert script_b is not None actions = scripts.verify(script_a, - {"id": "apacho"}) + {"id": "apacho"}, external_check=False) eq_(len(actions), 1) pprint(actions) assert actions[0]['text'] == "primitive apacho test:apache" @@ -640,7 +640,7 @@ #import ipdb #ipdb.set_trace() actions = scripts.verify(script_b, - {'wiz': "SARUMAN", "apache": {"id": "apacho"}}) + {'wiz': "SARUMAN", "apache": {"id": "apacho"}}, external_check=False) eq_(len(actions), 1) pprint(actions) assert actions[0]['text'] == "primitive SARUMAN apacho" @@ -667,13 +667,13 @@ assert script_a is not None actions = scripts.verify(script_a, - {"foo": "one"}) + {"foo": "one"}, external_check=False) eq_(len(actions), 1) pprint(actions) assert actions[0]['text'] == "one" actions = scripts.verify(script_a, - {"foo": "three"}) + {"foo": "three"}, external_check=False) eq_(len(actions), 1) pprint(actions) assert actions[0]['text'] == "three" @@ -699,7 +699,7 @@ assert script_a is not None def ver(): - return scripts.verify(script_a, {"foo": "wrong"}) + return scripts.verify(script_a, {"foo": "wrong"}, external_check=False) assert_raises(ValueError, ver) @@ -719,7 +719,7 @@ assert script_a is not None def ver(): - return scripts.verify(script_a, {"foo": "one"}) + return scripts.verify(script_a, {"foo": "one"}, external_check=False) assert_raises(ValueError, ver) @@ -763,7 +763,7 @@ assert script_b is not None actions = scripts.verify(script_b, - {'wiz': "head", "apache-a": {"id": "one"}, "apache-b": {"id": "two"}}) + {'wiz': "head", "apache-a": {"id": "one"}, "apache-b": {"id": "two"}}, external_check=False) eq_(len(actions), 1) pprint(actions) assert actions[0]['text'] == "primitive one test:apache\n\nprimitive two test:apache\n\nprimitive head one two" @@ -809,6 +809,18 @@ def ver(): actions = scripts.verify(script_b, - {"foofoo": {"foo": "one"}}) + {"foofoo": {"foo": "one"}}, external_check=False) pprint(actions) assert_raises(ValueError, ver) + + +@with_setup(setup_func, teardown_func) +def test_unified(): + unified = scripts.load_script('unified') + actions = scripts.verify( + unified, + {'id': 'foo', + 'vip': {'id': 'bar', 'ip': '192.168.0.15'}}, external_check=False) + pprint(actions) + eq_(len(actions), 1) + eq_('primitive bar IPaddr2 ip=192.168.0.15\ngroup g-foo foo bar', actions[-1]['text'].strip())