Hello community,

here is the log from the commit of package crmsh for openSUSE:Factory checked 
in at 2014-06-01 19:40:19
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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      2014-05-23 
07:51:35.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.crmsh.new/crmsh.changes 2014-06-01 
19:40:23.000000000 +0200
@@ -1,0 +2,9 @@
+Tue May 27 18:13:25 UTC 2014 - kgronl...@suse.com
+
+- high: cibconfig: adjust attributes when adding operations (bnc#880052)
+- high: parse: Support id-ref in nvpairs (fate#316118)
+- low: ui_configure: Add --force flag to configure delete
+- low: ui_resource: Allow untrace without explicit interval
+- upstream: 2.0.0-93-g29c4073 
+
+-------------------------------------------------------------------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ crmsh.spec ++++++
--- /var/tmp/diff_new_pack.e9PSHG/_old  2014-06-01 19:40:25.000000000 +0200
+++ /var/tmp/diff_new_pack.e9PSHG/_new  2014-06-01 19:40:25.000000000 +0200
@@ -41,7 +41,7 @@
 Summary:        High Availability cluster command-line interface
 License:        GPL-2.0+
 Group:          %{pkg_group}
-Version:        2.0+git88
+Version:        2.0+git93
 Release:        %{?crmsh_release}%{?dist}
 Url:            http://crmsh.github.io
 Source0:        crmsh.tar.bz2

++++++ crmsh.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh/doc/crm.8.txt new/crmsh/doc/crm.8.txt
--- old/crmsh/doc/crm.8.txt     2014-05-22 19:04:46.000000000 +0200
+++ new/crmsh/doc/crm.8.txt     2014-05-27 20:11:56.000000000 +0200
@@ -2146,6 +2146,79 @@
 true, explicitly set `sequential` in a parenthesis set:
 `A B ( C D sequential=true )`.
 
+==== References in attribute lists
+
+Attribute lists are used to set attributes and parameters for
+resources, constraints and property definitions. For example, to set
+the virtual IP used by an `IPAddr` resource the attribute `ip` can be
+set in an attribute list for that resource.
+
+Attribute lists can have identifiers that name them, and other
+resources can reuse the same attribute list by referring to that name
+using an `$id-ref`. For example, the following statement defines a
+simple dummy resource with an attribute list which sets the parameter
+`state to the value 1 and sets the identifier for the attribute list
+to `on-state`:
+
+..............
+primitive dummy-1 Dummy params $id=on-state state=1
+..............
+
+To refer to this attribute list from a different resource, refer to
+the `on-state` name using an id-ref:
+
+..............
+primitive dummy-2 Dummy params $id-ref=on-state
+..............
+
+The resource `dummy-2` will now also have the parameter `state` set to the 
value 1.
+
+===== Referencing individual attributes
+
+In some cases, referencing complete attribute lists is too
+coarse-grained, for example if two different parameters with different
+names should have the same value set. Instead of having to copy the
+value in multiple places, it is possible to create references to
+individual attributes in attribute lists.
+
+To name an attribute in order to be able to refer to it later, prefix
+the attribute name with a `$` character (as seen above with the
+special names `$id` and `$id-ref`:
+
+............
+primitive dummy-1 Dummy params $state=1
+............
+
+The identifier `state` can now be used to refer to this attribute from other
+primitives, using the `@<id>` syntax:
+
+............
+primitive dummy-2 Dummy params @state
+............
+
+In some cases, using the attribute name as the identifier doesn't work
+due to name clashes. In this case, the syntax `$<id>:<name>=<value>`
+can be used to give the attribute a different identifier:
+
+............
+primitive dummy-1 params $dummy-state-on:state=1
+primitive dummy-2 params @state
+............
+
+There is also the possibility that two resources both use the same
+attribute value but with different names. For example, a web server
+may have a parameter `server_ip` for setting the IP address where it
+listens for incoming requests, and a virtual IP resource may have a
+parameter called `ip` which sets the IP address it creates. To
+configure these two resources with an IP without repeating the value,
+the reference can be given a name using the syntax `@<id>:<name>`.
+
+Example:
+............
+primitive virtual-ip IPaddr2 params $vip:ip=192.168.1.100
+primitive webserver apache params @vip:server_ip
+............
+
 [[cmdhelp_configure_node,define a cluster node]]
 ==== `node`
 
@@ -2861,9 +2934,12 @@
 in that container, then the container is deleted as well. Any
 related constraints are removed as well.
 
+If the object is a started resource, it will not be deleted unless the
+`--force` flag is passed to the command, or the `force` option is set.
+
 Usage:
 ...............
-delete <id> [<id>...]
+delete [--force] <id> [<id>...]
 ...............
 
 [[cmdhelp_configure_default-timeouts,set timeouts for operations to minimums 
from the meta-data]]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh/modules/cibconfig.py 
new/crmsh/modules/cibconfig.py
--- old/crmsh/modules/cibconfig.py      2014-05-22 19:04:46.000000000 +0200
+++ new/crmsh/modules/cibconfig.py      2014-05-27 20:11:56.000000000 +0200
@@ -41,7 +41,7 @@
 from utils import ext_cmd, safe_open_w, pipe_string, safe_close_w, crm_msec
 from utils import ask, lines2cli, olist
 from utils import page_string, cibadmin_can_patch, str2tmp
-from utils import run_ptest, is_id_valid, edit_file, get_boolean, 
filter_string, find_value
+from utils import run_ptest, is_id_valid, edit_file, get_boolean, filter_string
 from ordereddict import odict
 from xmlutil import is_child_rsc, rsc_constraint, sanitize_cib, rename_id, 
get_interesting_nodes
 from xmlutil import is_pref_location, get_topnode, new_cib, 
get_rscop_defaults_meta_node
@@ -56,7 +56,7 @@
 from xmlutil import get_rsc_operations, delete_rscref, xml_equals, 
lookup_node, RscState
 from xmlutil import cibtext2elem
 from cliformat import get_score, nvpairs2list, abs_pos_score, cli_acl_roleref, 
nvpair_format
-from cliformat import cli_acl_rule, rsc_set_constraint, get_kind, 
head_id_format
+from cliformat import cli_nvpair, cli_acl_rule, rsc_set_constraint, get_kind, 
head_id_format
 from cliformat import cli_operations, simple_rsc_constraint, cli_rule, 
cli_format
 
 
@@ -197,21 +197,19 @@
             tonode.append(copy.deepcopy(cnode))
 
     def copy_nvpair(nvp):
+        if 'value' not in nvp:
+            tonode.append(copy.deepcopy(nvp))
+            return
         n = nvp.get('name')
         for nvp2 in tonode:
             if nvp2.get('name') == n:
                 nvp2.set('value', nvp.get('value'))
                 break
         else:
-            m = etree.SubElement(tonode,
-                                 'nvpair',
-                                 name=n,
-                                 value=nvp.get('value'))
-            if 'id' in nvp.attrib:
-                m.set('id', nvp.get('id'))
-            else:
-                m.set('id', idmgmt.new(m, id_hint))
+            m = copy.deepcopy(nvp)
             tonode.append(m)
+            if 'id' not in m.attrib:
+                m.set('id', idmgmt.new(m, id_hint))
 
     def copy_id(node):
         nid = node.get('id')
@@ -469,18 +467,19 @@
             for a in r_node.iterchildren("instance_attributes"):
                 for p in a.iterchildren("nvpair"):
                     name = p.get("name")
+                    value = p.get("value")
                     # don't fail if the meta-data doesn't contain the
                     # expected attributes
-                    try:
-                        if ra_params[name].get("unique") == "1":
-                            value = p.get("value")
-                            k = (ra_class, ra_provider, ra_type, name, value)
-                            try:
-                                clash_dict[k].append(ra_id)
-                            except KeyError:
-                                clash_dict[k] = [ra_id]
-                    except KeyError:
-                        pass
+                    if value is not None:
+                        try:
+                            if ra_params[name].get("unique") == "1":
+                                k = (ra_class, ra_provider, ra_type, name, 
value)
+                                try:
+                                    clash_dict[k].append(ra_id)
+                                except KeyError:
+                                    clash_dict[k] = [ra_id]
+                        except KeyError:
+                            pass
             return
         # we check the whole CIB for clashes as a clash may originate between
         # an object already committed and a new one
@@ -764,12 +763,42 @@
     recurse(node, oldnode, hint_map.get(node.tag, ''))
 
 
+def resolve_idref(node):
+    """
+    resolve id-ref references that refer
+    to object ids, not attribute lists
+    """
+    id_ref = node.get('id-ref')
+    attr_list_type = node.tag
+    obj = cib_factory.find_object(id_ref)
+    if obj:
+        nodes = obj.node.xpath(".//%s" % attr_list_type)
+        if len(nodes) > 1:
+            common_warn("%s contains more than one %s, using first" %
+                        (obj.obj_id, attr_list_type))
+        if len(nodes) > 0:
+            node_id = nodes[0].get("id")
+            if node_id:
+                return node_id
+    target = cib_factory.get_cib().xpath('.//*[@id="%s"]' % (id_ref))
+    if len(target) == 0:
+        common_err("Reference not found: %s" % id_ref)
+    elif len(target) > 1:
+        common_err("Ambiguous reference to %s" % id_ref)
+    return id_ref
+
+
 def resolve_references(node):
     """
     In the output from parse(), there are
     possible references to other nodes in
     the CIB. This resolves those references.
     """
+    idrefnodes = node.xpath('.//*[@id-ref]')
+    if 'id-ref' in node.attrib:
+        idrefnodes += [node]
+    for ref in idrefnodes:
+        ref.set('id-ref', resolve_idref(ref))
     for ref in node.iterchildren('crmsh-ref'):
         child_id = ref.get('id')
         obj = cib_factory.find_object(child_id)
@@ -1002,9 +1031,9 @@
 
         for c in node.iterchildren():
             if c.tag == "rule":
-                ret += "%s %s " % (clidisplay.keyword("rule"), cli_rule(c, 
cib_factory.is_id_refd))
+                ret += "%s %s " % (clidisplay.keyword("rule"), cli_rule(c))
             elif c.tag == "nvpair":
-                ret += "%s " % (nvpair_format(c.get("name"), c.get("value")))
+                ret += "%s " % (cli_nvpair(c))
         if ret[-1] == ' ':
             ret = ret[:-1]
         return ret
@@ -1338,7 +1367,8 @@
         for p in self.node.xpath("instance_attributes/nvpair"):
             n = p.get("name")
             v = p.get("value")
-            self.set_attr(n, v)
+            if n is not None and v is not None:
+                self.set_attr(n, v)
 
     def mkxml(self):
         # create an xml node
@@ -1348,8 +1378,9 @@
             idmgmt.remove_xml(self.node)
         self.node = etree.Element(self.elem_type)
         inst_attr = {}
+        valid_attrs = olist(schema.get('attr', 'op', 'a'))
         for n, v in self.attr_d.iteritems():
-            if n in olist(schema.get('attr', 'op', 'a')):
+            if n in valid_attrs:
                 self.node.set(n, v)
             else:
                 inst_attr[n] = v
@@ -1408,6 +1439,20 @@
         # create an xml node
         if 'id' not in node.attrib:
             idmgmt.set(node, None, self.obj_id)
+        valid_attrs = olist(schema.get('attr', 'op', 'a'))
+        inst_attr = {}
+        for attr in node.attrib.keys():
+            if attr not in valid_attrs:
+                inst_attr[attr] = node.attrib[attr]
+                del node.attrib[attr]
+        if inst_attr:
+            attr_nodes = node.xpath('./instance_attributes')
+            if len(attr_nodes) == 1:
+                fill_nvpairs("instance_attributes", attr_nodes[0], inst_attr, 
node.get("id"))
+            else:
+                nia = mkxmlnvpairs("instance_attributes", inst_attr, 
node.get("id"))
+                node.append(nia)
+
         self._append_op(node)
         comments = find_comment_nodes(node)
         for comment in comments:
@@ -1635,7 +1680,7 @@
     def _repr_cli_child(self, c, format):
         if c.tag == "rule":
             return "%s %s" % \
-                (clidisplay.keyword("rule"), cli_rule(c, 
cib_factory.is_id_refd))
+                (clidisplay.keyword("rule"), cli_rule(c))
 
     def check_sanity(self):
         '''
@@ -1836,9 +1881,9 @@
     def _repr_cli_child(self, c, format):
         if c.tag == "rule":
             return ' '.join((clidisplay.keyword("rule"),
-                             cli_rule(c, cib_factory.is_id_refd)))
+                             cli_rule(c)))
         elif c.tag == "nvpair":
-            return nvpair_format(c.get("name"), c.get("value"))
+            return cli_nvpair(c)
         else:
             return ''
 
@@ -2034,11 +2079,7 @@
 
 
 def can_migrate(node):
-    for c in node.iterchildren("meta_attributes"):
-        pl = nvpairs2list(c)
-        if find_value(pl, "allow-migrate") == "true":
-            return True
-    return False
+    return 'true' in node.xpath('.//nvpair[@name="allow-migrate"]/@value')
 
 
 cib_upgrade = "cibadmin --upgrade --force"
@@ -2648,7 +2689,10 @@
         return rc
 
     def is_id_refd(self, attr_list_type, id):
-        '''Is this ID referenced anywhere?'''
+        '''
+        Is this ID referenced anywhere?
+        Used from cliformat
+        '''
         try:
             return self.id_refs[id] == attr_list_type
         except KeyError:
@@ -2661,36 +2705,32 @@
         one, i.e. if the former is the case to find the right
         id to reference.
         '''
-        obj = self.find_object(id_ref)
         self.id_refs[id_ref] = attr_list_type
+        obj = self.find_object(id_ref)
         if obj:
-            node_l = obj.node.xpath(".//%s" % attr_list_type)
-            if node_l:
-                if len(node_l) > 1:
-                    common_warn("%s contains more than one %s, using first" %
-                                (obj.obj_id, attr_list_type))
-                id = node_l[0].get("id")
-                if not id:
-                    common_err("%s reference not found" % id_ref)
-                    return id_ref  # hope that user will fix that
-                return id
-        # verify if id_ref exists
-        node_l = self.cib_elem.xpath(".//%s" % attr_list_type)
-        for node in node_l:
-            if node.get("id") == id_ref:
-                return id_ref
-        common_err("%s reference not found" % id_ref)
-        return id_ref  # hope that user will fix that
+            nodes = obj.node.xpath(".//%s" % attr_list_type)
+            if len(nodes) > 1:
+                common_warn("%s contains more than one %s, using first" %
+                            (obj.obj_id, attr_list_type))
+            if len(nodes) > 0:
+                node_id = nodes[0].get("id")
+                if node_id:
+                    return node_id
+        target = self.cib_elem.xpath('.//*[@id="%s"]' % (id_ref))
+        if len(target) == 0:
+            common_err("Reference not found: %s" % id_ref)
+        elif len(target) > 1:
+            common_err("Ambiguous reference to %s" % id_ref)
+        return id_ref
 
     def _get_attr_value(self, obj_type, attr):
         if not self.is_cib_sane():
             return None
         for obj in self.cib_objects:
             if obj.obj_type == obj_type and obj.node is not None:
-                pl = nvpairs2list(obj.node)
-                v = find_value(pl, attr)
-                if v:
-                    return v
+                for n in nvpairs2list(obj.node):
+                    if n.get('name') == attr:
+                        return n.get('value')
         return None
 
     def get_property(self, property):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh/modules/cliformat.py 
new/crmsh/modules/cliformat.py
--- old/crmsh/modules/cliformat.py      2014-05-22 19:04:46.000000000 +0200
+++ new/crmsh/modules/cliformat.py      2014-05-27 20:11:56.000000000 +0200
@@ -17,7 +17,6 @@
 
 import constants
 import clidisplay
-from msg import common_err, node_debug
 import utils
 import xmlutil
 
@@ -68,61 +67,74 @@
         return '%s="%s"' % (clidisplay.attr_name(n), clidisplay.attr_value(v))
 
 
-def cli_pairs(pl):
-    'Return a string of name="value" pairs (passed in a list of pairs).'
-    l = []
-    for n, v in pl:
-        l.append(nvpair_format(n, v))
-    return ' '.join(l)
+def cli_nvpair(nvp):
+    'Converts an nvpair tag to CLI syntax'
+    from cibconfig import cib_factory
+    nodeid = nvp.get('id')
+    idref = nvp.get('id-ref')
+    name = nvp.get('name')
+    if idref is not None:
+        if name is not None:
+            return '@%s:%s' % (idref, name)
+        return '@%s' % (idref)
+    elif nodeid is not None and cib_factory.is_id_refd(nvp.tag, nodeid):
+        return '$%s:%s' % (nodeid, nvpair_format(name, nvp.get('value')))
+    return nvpair_format(name, nvp.get('value'))
+
+
+def cli_nvpairs(nvplist):
+    'Return a string of name="value" pairs (passed in a list of nvpairs).'
+    return ' '.join([cli_nvpair(nvp) for nvp in nvplist])
 
 
 def nvpairs2list(node, add_id=False):
     '''
-    Convert nvpairs to a list of pairs.
+    Convert an attribute node to a list of nvpairs.
+    Also converts an id-ref or id into plain nvpairs.
     The id attribute is normally skipped, since they tend to be
     long and therefore obscure the relevant content. For some
     elements, however, they are included (e.g. properties).
     '''
-    pl = []
-    # if there's id-ref, there can be then _only_ id-ref
-    value = node.get("id-ref")
-    if value:
-        pl.append(["$id-ref", value])
-        return pl
-    if add_id or \
-            (not len(node) and len(node.attrib) == 1):
-        value = node.get("id")
-        if value:
-            pl.append(["$id", value])
-    for c in node.iterchildren():
-        if c.tag == "attributes":
-            pl = nvpairs2list(c)
-        elif c.tag == "rule" or xmlutil.is_comment(c):
-            # skip rule expressions and comments
-            continue
-        elif c.tag != "nvpair":
-            node_debug("expected nvpair got", c)
-            continue
-        pl.append([c.get("name"), c.get("value")])
-    return pl
+    import xmlbuilder
+
+    ret = []
+    if 'id-ref' in node:
+        ret.append(xmlbuilder.nvpair('$id-ref', node.get('id-ref')))
+    nvpairs = node.xpath('./nvpair | ./attributes/nvpair')
+    if 'id' in node and (add_id or len(nvpairs) == 0):
+        ret.append(xmlbuilder.nvpair('$id', node.get('id')))
+    ret.extend(nvpairs)
+    return ret
+
+
+def cli_attributes(node, add_id=False):
+    '''
+    Convert an attribute tag to CLI syntax
+    Does not honor possible <rule> tags
+    '''
+    return ' '.join([cli_nvpair(nvp)
+                     for nvp in nvpairs2list(node, add_id=add_id)])
 
 
 def op_instattr(node):
+    """
+    Return nvpairs in <op><instance_attributes>...
+    """
     pl = []
-    for c in node.iterchildren():
-        if c.tag != "instance_attributes":
-            common_err("only instance_attributes are supported in operations")
-        else:
-            pl += nvpairs2list(c)
+    for c in node.xpath('./instance_attributes'):
+        pl.extend(nvpairs2list(c))
     return pl
 
 
 def cli_op(node):
+    "CLI format for an <op> tag"
     action, pl = xmlutil.op2list(node)
     if not action:
         return ""
-    pl += op_instattr(node)
-    return "%s %s %s" % (clidisplay.keyword("op"), action, cli_pairs(pl))
+    ret = ["%s %s" % (clidisplay.keyword("op"), action)]
+    ret += [nvpair_format(n, v) for n, v in pl]
+    ret += [cli_nvpair(v) for v in op_instattr(node)]
+    return ' '.join(ret)
 
 
 def date_exp2cli(node):
@@ -137,16 +149,12 @@
     else:
         if operation == 'in_range':
             for name in constants.in_range_attrs:
-                v = node.get(name)
-                if v:
-                    l.append(nvpair_format(name, v))
+                if name in node.attrib:
+                    l.append(nvpair_format(name, node.attrib[name]))
         for c in node.iterchildren():
             if c.tag in ("duration", "date_spec"):
-                pl = []
-                for name in c.keys():
-                    if name != "id":
-                        pl.append([name, c.get(name)])
-                l.append(cli_pairs(pl))
+                l.extend([nvpair_format(name, c.get(name))
+                          for name in c.keys() if name != 'id'])
     return ' '.join(l)
 
 
@@ -214,10 +222,11 @@
     return (" %s " % clidisplay.keyword(bool_op)).join(exp)
 
 
-def cli_rule(node, is_id_refd):
+def cli_rule(node):
+    from cibconfig import cib_factory
     s = []
     node_id = node.get("id")
-    if node_id and is_id_refd(node.tag, node_id):
+    if node_id and cib_factory.is_id_refd(node.tag, node_id):
         s.append('$id="%s"' % node_id)
     else:
         idref = node.get("id-ref")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh/modules/parse.py new/crmsh/modules/parse.py
--- old/crmsh/modules/parse.py  2014-05-22 19:04:46.000000000 +0200
+++ new/crmsh/modules/parse.py  2014-05-27 20:11:56.000000000 +0200
@@ -37,7 +37,9 @@
 
 
 class BaseParser(object):
-    _NVPAIR_RE = re.compile(r'([^=]+)=(.+)$')
+    _NVPAIR_RE = re.compile(r'([^=@$][^=]*)=(.+)$')
+    _NVPAIR_ID_RE = re.compile(r'\$([^:=]+)(?::(.+))?=(.+)$')
+    _NVPAIR_REF_RE = re.compile(r'@([^:]+)(?::(.+))?$')
     _IDENT_RE = re.compile(r'([a-z0-9_#$-][^=]*)$', re.IGNORECASE)
     _DISPATCH_RE = re.compile(r'[a-z0-9_]+$', re.IGNORECASE)
     _DESC_RE = re.compile(r'description=(.+)$', re.IGNORECASE)
@@ -170,13 +172,13 @@
 
     def match_nvpairs_bykey(self, valid_keys, minpairs=1):
         """
-        matches string of p=v tokens, but only
-        if p is in valid_keys
+        matches string of p=v tokens, but only if p is in valid_keys
+        Returns list of <nvpair> tags
         """
         _KEY_RE = re.compile(r'(%s)=(.+)$' % '|'.join(valid_keys))
         ret = []
         while self.try_match(_KEY_RE):
-            ret.append([self.matched(1), self.matched(2)])
+            ret.append(xmlbuilder.nvpair(self.matched(1), self.matched(2)))
         if len(ret) < minpairs:
             if minpairs == 1:
                 self.err("Expected at least one name-value pair")
@@ -187,10 +189,22 @@
     def match_nvpairs(self, minpairs=1):
         """
         Matches string of p=v tokens
+        Returns list of <nvpair> tags
         """
         ret = []
-        while self.try_match(self._NVPAIR_RE):
-            ret.append([self.matched(1), self.matched(2)])
+        while True:
+            if self.try_match(self._NVPAIR_REF_RE):
+                ret.append(xmlbuilder.nvpair_ref(self.matched(1),
+                                                 self.matched(2)))
+            elif self.try_match(self._NVPAIR_ID_RE):
+                ret.append(xmlbuilder.nvpair_id(self.matched(1),
+                                                self.matched(2),
+                                                self.matched(3)))
+            elif self.try_match(self._NVPAIR_RE):
+                ret.append(xmlbuilder.nvpair(self.matched(1),
+                                             self.matched(2)))
+            else:
+                break
         if len(ret) < minpairs:
             if minpairs == 1:
                 self.err("Expected at least one name-value pair")
@@ -544,19 +558,17 @@
         op_type = self.match(self._OPTYPE_RE, errmsg="Expected operation type")
         all_attrs = self.match_nvpairs(minpairs=0)
         node = xmlbuilder.new('op', name=op_type)
-        if not any(k.lower() == 'interval' for k, _ in all_attrs):
-            all_attrs.append(('interval', '0'))
-        valid_attrs = set(self.validation.op_attributes())
+        if not any(nvp.get('name') == 'interval' for nvp in all_attrs):
+            all_attrs.append(xmlbuilder.nvpair('interval', '0'))
+        valid_attrs = self.validation.op_attributes()
         inst_attrs = None
-        for n, v in all_attrs:
-            if n in valid_attrs:
-                node.set(n, v)
-
-        for n, v in all_attrs:
-            if n not in valid_attrs:
+        for nvp in all_attrs:
+            if nvp.get('name') in valid_attrs:
+                node.set(nvp.get('name'), nvp.get('value'))
+            else:
                 if inst_attrs is None:
                     inst_attrs = xmlbuilder.child(node, 'instance_attributes')
-                inst_attrs.append(xmlbuilder.nvpair(n, v))
+                inst_attrs.append(nvp)
         out.append(node)
 
     def match_operations(self, out, match_id):
@@ -905,8 +917,8 @@
             attrs.set(idkey, idval)
         for rule in self.match_rules():
             attrs.append(rule)
-        for n, v in self.match_nvpairs():
-            attrs.append(xmlbuilder.nvpair(n, v))
+        for nvp in self.match_nvpairs():
+            attrs.append(nvp)
         return root
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh/modules/ra.py new/crmsh/modules/ra.py
--- old/crmsh/modules/ra.py     2014-05-22 19:04:46.000000000 +0200
+++ new/crmsh/modules/ra.py     2014-05-27 20:11:56.000000000 +0200
@@ -557,16 +557,17 @@
                 return True
         return False
 
-    def sanity_check_params(self, id, pl, existence_only=False):
+    def sanity_check_params(self, id, nvpairs, existence_only=False):
         '''
-        pl is a list of (attribute, value) pairs.
+        nvpairs is a list of <nvpair> tags.
         - are all required parameters defined
         - do all parameters exist
         '''
         rc = 0
         d = {}
-        for p, v in pl:
-            d[p] = v
+        for nvp in nvpairs:
+            if 'name' in nvp.attrib and 'value' in nvp.attrib:
+                d[nvp.get('name')] = nvp.get('value')
         if not existence_only:
             for p in self.reqd_params_list():
                 if self.unreq_param(p):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh/modules/ui_configure.py 
new/crmsh/modules/ui_configure.py
--- old/crmsh/modules/ui_configure.py   2014-05-22 19:04:46.000000000 +0200
+++ new/crmsh/modules/ui_configure.py   2014-05-27 20:11:56.000000000 +0200
@@ -446,11 +446,28 @@
             rc = set_obj.graph_img(gtype, outf, ftype)
         return rc
 
+    def _stop_if_running(self, rscs):
+        rscstate = xmlutil.RscState()
+        to_stop = [rsc for rsc in rscs if rscstate.is_running(rsc)]
+        from ui_resource import set_deep_meta_attr
+        if len(to_stop) > 0:
+            ok = all(set_deep_meta_attr(rsc, 'target-role', 'Stopped',
+                                        commit=False) for rsc in to_stop)
+            if not ok or not cib_factory.commit():
+                raise ValueError("Failed to stop one or more running 
resources: %s" %
+                                 (', '.join(to_stop)))
+
     @command.skill_level('administrator')
     @command.completers_repeating(_id_list)
     def do_delete(self, context, *args):
-        "usage: delete <id> [<id>...]"
-        return cib_factory.delete(*args)
+        "usage: delete [-f|--force] <id> [<id>...]"
+        argl = list(args)
+        arg_force = argl and argl[0] == '--force'
+        if arg_force:
+            del argl[0]
+        if arg_force or config.core.force:
+            self._stop_if_running(argl)
+        return cib_factory.delete(*argl)
 
     @command.name('default-timeouts')
     @command.alias('default_timeouts')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh/modules/ui_node.py new/crmsh/modules/ui_node.py
--- old/crmsh/modules/ui_node.py        2014-05-22 19:04:46.000000000 +0200
+++ new/crmsh/modules/ui_node.py        2014-05-27 20:11:56.000000000 +0200
@@ -23,7 +23,7 @@
 import utils
 import xmlutil
 from msg import common_err, syntax_err, no_prog_err, common_info, common_warn
-from cliformat import nvpairs2list
+from cliformat import cli_nvpair, nvpairs2list
 
 
 def _oneline(s):
@@ -50,9 +50,8 @@
             id = v
         else:
             other[attr] = v
-    for elem in node.iterchildren():
-        if elem.tag == "instance_attributes":
-            inst_attr += nvpairs2list(elem)
+    inst_attr = [cli_nvpair(nvpairs2list(elem))
+                 for elem in node.xpath('./instance_attributes')]
     return uname, id, type, other, inst_attr, is_offline(uname)
 
 
@@ -60,8 +59,8 @@
     """
     Try to pretty print a node from the cib. Sth like:
     uname(id): node_type
-        attr1: v1
-        attr2: v2
+        attr1=v1
+        attr2=v2
     """
     s_offline = offline and "(offline)" or ""
     if not node_type:
@@ -72,8 +71,8 @@
         print "%s(%s): %s%s" % (uname, id, node_type, s_offline)
     for a in other:
         print "\t%s: %s" % (a, other[a])
-    for a, v in inst_attr:
-        print "\t%s: %s" % (a, v)
+    for s in inst_attr:
+        print "\t%s" % (s)
 
 
 class NodeMgmt(command.UI):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh/modules/ui_resource.py 
new/crmsh/modules/ui_resource.py
--- old/crmsh/modules/ui_resource.py    2014-05-22 19:04:46.000000000 +0200
+++ new/crmsh/modules/ui_resource.py    2014-05-27 20:11:56.000000000 +0200
@@ -496,11 +496,9 @@
         rsc = self._get_trace_rsc(rsc_id)
         if not rsc:
             return False
-        if not interval:
-            interval = op == "monitor" and "non-0" or "0"
         if op == "probe":
             op = "monitor"
-        op_node = xmlutil.find_operation(rsc.node, op, interval)
+        op_node = xmlutil.find_operation(rsc.node, op, interval=interval)
         if op_node is None:
             common_err("operation %s does not exist in %s" % (op, rsc.obj_id))
             return False
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh/modules/xmlbuilder.py 
new/crmsh/modules/xmlbuilder.py
--- old/crmsh/modules/xmlbuilder.py     2014-05-22 19:04:46.000000000 +0200
+++ new/crmsh/modules/xmlbuilder.py     2014-05-27 20:11:56.000000000 +0200
@@ -52,22 +52,43 @@
     return new("nvpair", name=name, value=value)
 
 
+def nvpair_id(nvpairid, name, value):
+    """
+    <nvpair id="" name="" value="" />
+    """
+    if name is None:
+        name = nvpairid
+    return new("nvpair", id=nvpairid, name=name, value=value)
+
+
+def nvpair_ref(idref, name=None):
+    """
+    <nvpair id-ref=<idref> [name=<name>]/>
+    """
+    print "nvpair_ref:", repr(idref), repr(name)
+    nvp = new("nvpair")
+    nvp.set('id-ref', idref)
+    if name is not None:
+        nvp.set('name', name)
+    return nvp
+
+
 def set_date_expression(expr, tag, values):
     """
     Fill in date_expression tag for date_spec/in_range operations
     expr: <date_expression/>
-    values: [(name, value)...]
+    values: [nvpair...]
     """
-    if set(k for k, _ in values) == set(constants.in_range_attrs):
-        for k, v in values:
-            expr.set(k, v)
+    if set(nvp.get('name') for nvp in values) == set(constants.in_range_attrs):
+        for nvp in values:
+            expr.set(nvp.get('name'), nvp.get('value'))
         return expr
     subtag = child(expr, tag)
-    for k, v in values:
-        if k in constants.in_range_attrs:
-            expr.set(k, v)
+    for nvp in values:
+        if nvp.get('name') in constants.in_range_attrs:
+            expr.set(nvp.get('name'), nvp.get('value'))
         else:
-            subtag.set(k, v)
+            subtag.set(nvp.get('name'), nvp.get('value'))
     return expr
 
 
@@ -91,6 +112,6 @@
         e.set("score", score)
     for rule in rules:
         e.append(rule)
-    for name, value in values:
-        e.append(nvpair(name, value))
+    for nvp in values:
+        e.append(nvp)
     return e
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh/modules/xmlutil.py new/crmsh/modules/xmlutil.py
--- old/crmsh/modules/xmlutil.py        2014-05-22 19:04:46.000000000 +0200
+++ new/crmsh/modules/xmlutil.py        2014-05-27 20:11:56.000000000 +0200
@@ -740,11 +740,12 @@
     return None
 
 
-def find_operation(rsc_node, name, interval="0"):
+def find_operation(rsc_node, name, interval=None):
     '''
     Setting interval to "non-0" means get the first op with interval
     different from 0.
     '''
+    interval = interval or "0"
     op_node_l = rsc_node.findall("operations")
     for ops in op_node_l:
         for c in ops.iterchildren("op"):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh/test/unittests/test_cliformat.py 
new/crmsh/test/unittests/test_cliformat.py
--- old/crmsh/test/unittests/test_cliformat.py  2014-05-22 19:04:46.000000000 
+0200
+++ new/crmsh/test/unittests/test_cliformat.py  2014-05-27 20:11:56.000000000 
+0200
@@ -38,12 +38,9 @@
     print xml
     obj.nocli = False
     s = obj.repr_cli(format=-1)
-    if s != cli:
+    if (s != cli) or debug:
         print "GOT:", s
         print "EXP:", cli
-    if debug:
-        print s
-        print cli
     assert obj.cli_use_validate()
     eq_(cli, s)
     assert not debug
@@ -103,6 +100,16 @@
     roundtrip("# comment 1\n# comment 2\n# comment 3\nprimitive d0 
ocf:pacemaker:Dummy")
 
 
+def test_nvpair_ref1():
+    factory.create_from_cli("primitive dummy-0 Dummy params $fiz:buz=bin")
+    roundtrip('primitive dummy-1 Dummy params @fiz:boz')
+
+
+def test_idresolve():
+    factory.create_from_cli("primitive dummy-5 Dummy params buz=bin")
+    roundtrip('primitive dummy-1 Dummy params 
@dummy-5-instance_attributes-buz')
+
+
 def test_ordering():
     xml = """<primitive id="dummy" class="ocf" provider="pacemaker" 
type="Dummy"> \
   <operations> \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh/test/unittests/test_parse.py 
new/crmsh/test/unittests/test_parse.py
--- old/crmsh/test/unittests/test_parse.py      2014-05-22 19:04:46.000000000 
+0200
+++ new/crmsh/test/unittests/test_parse.py      2014-05-27 20:11:56.000000000 
+0200
@@ -180,6 +180,18 @@
         self.assertEqual(len(out), 1)
         self.assertEqual(['b'], 
out.xpath('/group/instance_attributes/nvpair[@name="a"]/@value'))
 
+    def test_nvpair_ref(self):
+        out = self.parser.parse('primitive dummy-0 Dummy params @foo')
+        self.assertEqual(out.get('id'), 'dummy-0')
+        self.assertEqual(out.get('class'), 'ocf')
+        self.assertEqual(['foo'], out.xpath('.//nvpair/@id-ref'))
+
+        out = self.parser.parse('primitive dummy-0 Dummy params @fiz:buz')
+        self.assertEqual(out.get('id'), 'dummy-0')
+        self.assertEqual(out.get('class'), 'ocf')
+        self.assertEqual(['fiz'], out.xpath('.//nvpair/@id-ref'))
+        self.assertEqual(['buz'], out.xpath('.//nvpair/@name'))
+
     def test_location(self):
         out = self.parser.parse('location loc-1 resource inf: foo')
         self.assertEqual(out.get('id'), 'loc-1')

-- 
To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org
For additional commands, e-mail: opensuse-commit+h...@opensuse.org

Reply via email to