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())


Reply via email to