File crm_tickets_825cb3e79d7b.patch of Package pacemaker

# HG changeset patch
# User Dejan Muhamedagic <dejan@hello-penguin.com>
# Date 1314783705 -7200
# Node ID 825cb3e79d7bc1c4ac30468f8c028c9129d00541
# Parent  f77e52725f2d98c219d8b22208da0b89b3d42112
High: Shell: support for rsc_ticket

diff --git a/doc/crm.8.txt b/doc/crm.8.txt
--- a/doc/crm.8.txt
+++ b/doc/crm.8.txt
@@ -1639,6 +1639,34 @@ Example:
         order o1 inf: A ( B C )
 ...............
 
+[[cmdhelp_configure_rsc_ticket,resources ticket dependency]]
+==== `rsc_ticket`
+
+This constraint expresses dependency of resources on cluster-wide
+attributes, also known as tickets. Tickets are mainly used in
+geo-clusters, which consist of multiple sites. A ticket may be
+granted to a site, thus allowing resources to run there.
+
+The `loss-policy` attribute specifies what happens to the
+resource (or resources) if the ticket is revoked. The default is
+either `stop` or `demote` depending on whether a resource is
+multi-state.
+
+Usage:
+...............
+        rsc_ticket <id> <ticket_id>: <rsc>[:<role>] [<rsc>[:<role>] ...]
+          [loss-policy=<loss_policy_action>]
+
+        loss_policy_action :: stop | demote | fence | freeze
+...............
+Example:
+...............
+        rsc_ticket ticket-A_public-ip ticket-A: public-ip
+        rsc_ticket ticket-A_bigdb ticket-A: bigdb loss-policy=fence
+        rsc_ticket ticket-B_storage ticket-B: drbd-a:Master drbd-b:Master
+...............
+
+
 [[cmdhelp_configure_property,set a cluster property]]
 ==== `property`
 
diff --git a/shell/modules/cibconfig.py b/shell/modules/cibconfig.py
--- a/shell/modules/cibconfig.py
+++ b/shell/modules/cibconfig.py
@@ -1243,7 +1243,7 @@ class CibSimpleConstraint(CibObject):
         if node.getElementsByTagName("resource_set"):
             col = rsc_set_constraint(node,obj_type)
         else:
-            col = two_rsc_constraint(node,obj_type)
+            col = simple_rsc_constraint(node,obj_type)
         if not col:
             return None
         symm = node.getAttribute("symmetrical")
@@ -1264,6 +1264,27 @@ class CibSimpleConstraint(CibObject):
         remove_id_used_attributes(oldnode)
         return headnode
 
+class CibRscTicket(CibSimpleConstraint):
+    '''
+    rsc_ticket constraint.
+    '''
+    def repr_cli_head(self,node):
+        obj_type = vars.cib_cli_map[node.tagName]
+        node_id = node.getAttribute("id")
+        s = cli_display.keyword(obj_type)
+        id = cli_display.id(node_id)
+        ticket = cli_display.ticket(node.getAttribute("ticket"))
+        if node.getElementsByTagName("resource_set"):
+            col = rsc_set_constraint(node,obj_type)
+        else:
+            col = simple_rsc_constraint(node,obj_type)
+        if not col:
+            return None
+        a = node.getAttribute("loss-policy")
+        if a:
+            col.append("loss-policy=%s" % a)
+        return "%s %s %s: %s" % (s,id,ticket,' '.join(col))
+
 class CibProperty(CibObject):
     '''
     Cluster properties.
@@ -1371,6 +1392,7 @@ cib_object_map = {
     "rsc_location": ( "location", CibLocation, "constraints" ),
     "rsc_colocation": ( "colocation", CibSimpleConstraint, "constraints" ),
     "rsc_order": ( "order", CibSimpleConstraint, "constraints" ),
+    "rsc_ticket": ( "rsc_ticket", CibRscTicket, "constraints" ),
     "cluster_property_set": ( "property", CibProperty, "crm_config", "cib-bootstrap-options" ),
     "rsc_defaults": ( "rsc_defaults", CibProperty, "rsc_defaults", "rsc-options" ),
     "op_defaults": ( "op_defaults", CibProperty, "op_defaults", "op-options" ),
diff --git a/shell/modules/clidisplay.py b/shell/modules/clidisplay.py
--- a/shell/modules/clidisplay.py
+++ b/shell/modules/clidisplay.py
@@ -62,6 +62,8 @@ class CliDisplay(Singleton):
         return self.otherword(4, s)
     def score(self, s):
         return self.otherword(5, s)
+    def ticket(self, s):
+        return self.otherword(5, s)
 
 user_prefs = UserPrefs.getInstance()
 vars = Vars.getInstance()
diff --git a/shell/modules/cliformat.py b/shell/modules/cliformat.py
--- a/shell/modules/cliformat.py
+++ b/shell/modules/cliformat.py
@@ -226,22 +226,25 @@ def rsc_set_constraint(node,obj_type):
         action = n.getAttribute("action")
         for r in n.getElementsByTagName("resource_ref"):
             rsc = cli_display.rscref(r.getAttribute("id"))
-            q = (obj_type == "colocation") and role or action
+            q = (obj_type == "order") and action or role
             col.append(q and "%s:%s"%(rsc,q) or rsc)
             cnt += 1
         if not sequential:
             col.append(")")
-    if cnt <= 2: # a degenerate thingie
+    if (obj_type != "rsc_ticket" and cnt <= 2) or \
+            (obj_type == "rsc_ticket" and cnt <= 1): # a degenerate thingie
         col.insert(0,"_rsc_set_")
     return col
-def two_rsc_constraint(node,obj_type):
+def simple_rsc_constraint(node,obj_type):
     col = []
     if obj_type == "colocation":
         col.append(mkrscrole(node,"rsc"))
         col.append(mkrscrole(node,"with-rsc"))
-    else:
+    elif obj_type == "order":
         col.append(mkrscaction(node,"first"))
         col.append(mkrscaction(node,"then"))
+    else: # rsc_ticket
+        col.append(mkrscrole(node,"rsc"))
     return col
 
 # this pre (or post)-processing is oversimplified
diff --git a/shell/modules/completion.py b/shell/modules/completion.py
--- a/shell/modules/completion.py
+++ b/shell/modules/completion.py
@@ -467,6 +467,7 @@ completer_lists = {
         "location" : (null_list,rsc_id_list),
         "colocation" : (null_list,null_list,rsc_id_list,loop),
         "order" : (null_list,null_list,rsc_id_list,loop),
+        "rsc_ticket" : (null_list,null_list,rsc_id_list,loop),
         "property" : (property_complete,loop),
         "rsc_defaults" : (prim_complete_meta,loop),
         "op_defaults" : (op_attr_list,loop),
diff --git a/shell/modules/parse.py b/shell/modules/parse.py
--- a/shell/modules/parse.py
+++ b/shell/modules/parse.py
@@ -178,6 +178,15 @@ def parse_op(s):
     head_pl.append(["name",s[0]])
     return cli_list
 
+def cli_parse_ticket(ticket,pl):
+    if ticket.endswith(':'):
+        ticket = ticket.rstrip(':')
+    else:
+        syntax_err(ticket, context = 'rsc_ticket')
+        return False
+    pl.append(["ticket",ticket])
+    return True
+
 def cli_parse_score(score,pl,noattr = False):
     if score.endswith(':'):
         score = score.rstrip(':')
@@ -197,6 +206,7 @@ def cli_parse_score(score,pl,noattr = Fa
         else:
             pl.append(["score-attribute",score])
     return True
+
 def is_binary_op(s):
     l = s.split(':')
     if len(l) == 2:
@@ -302,13 +312,13 @@ def parse_location(s):
         return False
     return cli_list
 
-def cli_opt_symmetrical(p,pl):
+def cli_opt_attribute(type, p, pl, attr):
     if not p:
         return True
     pl1 = []
     cli_parse_attr([p],pl1)
-    if len(pl1) != 1 or not find_value(pl1,"symmetrical"):
-        syntax_err(p,context = "order")
+    if len(pl1) != 1 or not find_value(pl1, attr):
+        syntax_err(p,context = type)
         return False
     pl += pl1
     return True
@@ -490,7 +500,33 @@ def parse_order(s):
         resource_set_obj = ResourceSet(type,s[3:],cli_list)
         if not resource_set_obj.parse():
             return False
-    if not cli_opt_symmetrical(symm,head_pl):
+    if not cli_opt_attribute(type, symm, head_pl, "symmetrical"):
+        return False
+    return cli_list
+
+def parse_rsc_ticket(s):
+    cli_list = []
+    head_pl = []
+    type = "rsc_ticket"
+    cli_list.append([s[0],head_pl])
+    if len(s) < 4:
+        syntax_err(s,context = "rsc_ticket")
+        return False
+    head_pl.append(["id",s[1]])
+    if not cli_parse_ticket(s[2],head_pl):
+        return False
+    # save loss-policy for later (if it exists)
+    loss_policy = ""
+    if is_attribute(s[len(s)-1],"loss-policy"):
+        loss_policy = s.pop()
+    if len(s) == 4:
+        if not cli_parse_rsc_role(s[3], head_pl):
+            return False
+    else:
+        resource_set_obj = ResourceSet(type, s[3:], cli_list)
+        if not resource_set_obj.parse():
+            return False
+    if not cli_opt_attribute(type, loss_policy, head_pl, attr = "loss-policy"):
         return False
     return cli_list
 
@@ -501,6 +537,8 @@ def parse_constraint(s):
         return parse_colocation(s)
     elif keyword_cmp(s[0], "order"):
         return parse_order(s)
+    elif keyword_cmp(s[0], "rsc_ticket"):
+        return parse_rsc_ticket(s)
 def parse_property(s):
     cli_list = []
     head_pl = []
@@ -708,6 +746,7 @@ class CliParser(object):
         "colocation": (3,parse_constraint),
         "collocation": (3,parse_constraint),
         "order": (3,parse_constraint),
+        "rsc_ticket": (3,parse_constraint),
         "monitor": (3,parse_op),
         "node": (2,parse_node),
         "property": (2,parse_property),
diff --git a/shell/modules/ui.py.in b/shell/modules/ui.py.in
--- a/shell/modules/ui.py.in
+++ b/shell/modules/ui.py.in
@@ -1400,6 +1400,7 @@ cluster.
         self.cmd_table["location"] = (self.conf_location,(2,),1,0)
         self.cmd_table["colocation"] = (self.conf_colocation,(2,),1,0)
         self.cmd_table["order"] = (self.conf_order,(2,),1,0)
+        self.cmd_table["rsc_ticket"] = (self.conf_rsc_ticket,(2,),1,0)
         self.cmd_table["property"] = (self.conf_property,(1,),1,0)
         self.cmd_table["rsc_defaults"] = (self.conf_rsc_defaults,(1,),1,0)
         self.cmd_table["op_defaults"] = (self.conf_op_defaults,(1,),1,0)
@@ -1632,6 +1633,10 @@ cluster.
         """usage: order <id> score-type: <first-rsc>[:<action>] <then-rsc>[:<action>]
         [symmetrical=<bool>]"""
         return self.__conf_object(cmd,*args)
+    def conf_rsc_ticket(self,cmd,*args):
+        """usage: rsc_ticket <id> <ticket_id>: <rsc>[:<role>] [<rsc>[:<role>] ...]
+        [loss-policy=<loss_policy_action>]"""
+        return self.__conf_object(cmd,*args)
     def conf_property(self,cmd,*args):
         "usage: property [$id=<set_id>] <option>=<value>"
         return self.__conf_object(cmd,*args)
diff --git a/shell/modules/vars.py.in b/shell/modules/vars.py.in
--- a/shell/modules/vars.py.in
+++ b/shell/modules/vars.py.in
@@ -53,6 +53,7 @@ class Vars(Singleton):
     "rsc_location": "location",
     "rsc_colocation": "colocation",
     "rsc_order": "order",
+    "rsc_ticket": "rsc_ticket",
     "cluster_property_set": "property",
     "rsc_defaults": "rsc_defaults",
     "op_defaults": "op_defaults",
@@ -62,13 +63,13 @@ class Vars(Singleton):
     container_tags = ("group", "clone", "ms", "master")
     clonems_tags = ("clone", "ms", "master")
     resource_tags = ("primitive","group","clone","ms","master")
-    constraint_tags = ("rsc_location","rsc_colocation","rsc_order")
+    constraint_tags = ("rsc_location","rsc_colocation","rsc_order","rsc_ticket")
     constraint_rsc_refs = ("rsc","with-rsc","first","then")
     children_tags = ("group", "primitive")
     nvpairs_tags = ("meta_attributes", "instance_attributes", "utilization")
     defaults_tags = ("rsc_defaults","op_defaults")
     resource_cli_names = ("primitive","group","clone","ms","master")
-    constraint_cli_names = ("location","colocation","collocation","order")
+    constraint_cli_names = ("location","colocation","collocation","order","rsc_ticket")
     nvset_cli_names = ("property","rsc_defaults","op_defaults")
     op_cli_names = ("monitor", "start", "stop", "migrate_to", "migrate_from","promote","demote","notify")
     ra_operations = ("probe", "monitor", "start", "stop",
diff --git a/shell/modules/xmlutil.py b/shell/modules/xmlutil.py
--- a/shell/modules/xmlutil.py
+++ b/shell/modules/xmlutil.py
@@ -520,7 +520,8 @@ def mss(node_list):
 def constraints(node_list):
     return filter_on_tag(node_list,"rsc_location") \
         + filter_on_tag(node_list,"rsc_colocation") \
-        + filter_on_tag(node_list,"rsc_order")
+        + filter_on_tag(node_list,"rsc_order") \
+        + filter_on_tag(node_list,"rsc_ticket")
 def properties(node_list):
     return filter_on_tag(node_list,"cluster_property_set") \
         + filter_on_tag(node_list,"rsc_defaults") \
@@ -562,7 +563,8 @@ def constraints_cli(node_list):
     return filter_on_type(node_list,"location") \
         + filter_on_type(node_list,"colocation") \
         + filter_on_type(node_list,"collocation") \
-        + filter_on_type(node_list,"order")
+        + filter_on_type(node_list,"order") \
+        + filter_on_type(node_list,"rsc_ticket")
 def properties_cli(cl):
     return filter_on_type(cl,"property") \
         + filter_on_type(cl,"rsc_defaults") \
@@ -601,6 +603,8 @@ def referenced_resources(node):
     elif xml_obj_type == "rsc_order":
         node_list = node.getElementsByTagName("first") + \
             node.getElementsByTagName("then")
+    elif xml_obj_type == "rsc_ticket":
+        node_list = node.getElementsByTagName("rsc")
     return [x.getAttribute("id") for x in node_list]
 
 def rename_id(node,old_id,new_id):
openSUSE Build Service is sponsored by