Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 943699 Details for
Bug 1110166
[RFE] allow user to specify constraint id on its creation
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
proposed fix
0001-Improved-constraint-commands-options.patch (text/plain), 32.97 KB, created by
Tomas Jelinek
on 2014-10-03 10:50:58 UTC
(
hide
)
Description:
proposed fix
Filename:
MIME Type:
Creator:
Tomas Jelinek
Created:
2014-10-03 10:50:58 UTC
Size:
32.97 KB
patch
obsolete
>From e84b62c5057842cf0e05fcc71c450607df73854e Mon Sep 17 00:00:00 2001 >From: Tomas Jelinek <tojeline@redhat.com> >Date: Fri, 3 Oct 2014 11:12:57 +0200 >Subject: [PATCH] Improved constraint commands options > >* added possibility to specify constraint id when creating a constraint >* fixed score options in 'constraint collocation set' command >* added setoptions to 'constraint order set' command >* fixed 'symmetrical' options parsing in 'constraint order add' command >--- > pcs/constraint.py | 226 ++++++++++++++++++++++++++++++--------- > pcs/pcs.8 | 12 +-- > pcs/rule.py | 28 ++--- > pcs/test/test_constraints.py | 244 ++++++++++++++++++++++++++++++++++++++++++- > pcs/test/test_rule.py | 3 +- > pcs/usage.py | 16 +-- > 6 files changed, 454 insertions(+), 75 deletions(-) > >diff --git a/pcs/constraint.py b/pcs/constraint.py >index 2ef05fd..403429b 100644 >--- a/pcs/constraint.py >+++ b/pcs/constraint.py >@@ -13,6 +13,8 @@ OPTIONS_ACTION = ("start", "promote", "demote", "stop") > DEFAULT_ACTION = "start" > OPTIONS_ROLE = ("Stopped", "Started", "Master", "Slave") > DEFAULT_ROLE = "Started" >+OPTIONS_KIND = ("Optional", "Mandatory", "Serialize") >+OPTIONS_SYMMETRICAL = ("true", "false") > > def constraint_cmd(argv): > if len(argv) == 0: >@@ -216,10 +218,28 @@ def colocation_add(argv): > utils.err(resource_error) > > score,nv_pairs = parse_score_options(argv) >+ id_in_nvpairs = None >+ for name, value in nv_pairs: >+ if name == "id": >+ id_valid, id_error = utils.validate_xml_id(value, 'constraint id') >+ if not id_valid: >+ utils.err(id_error) >+ if utils.does_id_exist(cib_dom, value): >+ utils.err( >+ "id '%s' is already in use, please specify another one" >+ % value >+ ) >+ id_in_nvpairs = True >+ if not id_in_nvpairs: >+ nv_pairs.append(( >+ "id", >+ utils.find_unique_id( >+ cib_dom, >+ "colocation-%s-%s-%s" % (resource1, resource2, score) >+ ) >+ )) > > (dom,constraintsElement) = getCurrentConstraints(cib_dom) >- cl_id = utils.find_unique_id(dom, "colocation-" + resource1 + "-" + >- resource2 + "-" + score) > > # If one role is specified, the other should default to "started" > if role1 != "" and role2 == "": >@@ -228,7 +248,6 @@ def colocation_add(argv): > role1 = DEFAULT_ROLE > > element = dom.createElement("rsc_colocation") >- element.setAttribute("id",cl_id) > element.setAttribute("rsc",resource1) > element.setAttribute("with-rsc",resource2) > element.setAttribute("score",score) >@@ -278,34 +297,55 @@ def colocation_set(argv): > break > > current_set = set_args_into_array(argv) >- colocation_id = "pcs_rsc_colocation" >- for a in argv: >- if a.find('=') == -1: >- colocation_id = colocation_id + "_" + a >- > cib, constraints = getCurrentConstraints(utils.get_cib_dom()) >- rsc_colocation = cib.createElement("rsc_colocation") >- rsc_colocation.setAttribute("id", utils.find_unique_id(cib, colocation_id)) >- rsc_colocation.setAttribute("score", "INFINITY") >+ >+ attributes = [] > score_options = ("score", "score-attribute", "score-attribute-mangle") > score_specified = False >+ id_specified = False > for opt in setoptions: >- if opt.find("=") != -1: >- name,value = opt.split("=") >- if name not in score_options: >+ if "=" not in opt: >+ utils.err("missing value of '%s' option" % opt) >+ name, value = opt.split("=", 1) >+ if name == "id": >+ id_valid, id_error = utils.validate_xml_id(value, 'constraint id') >+ if not id_valid: >+ utils.err(id_error) >+ if utils.does_id_exist(cib, value): > utils.err( >- "invalid option '%s', allowed options are: %s" >- % (name, ", ".join(score_options)) >+ "id '%s' is already in use, please specify another one" >+ % value > ) >+ id_specified = True >+ attributes.append((name, value)) >+ elif name in score_options: > if score_specified: > utils.err("you cannot specify multiple score options") >- score_specified = True > if name == "score" and not utils.is_score(value): > utils.err( > "invalid score '%s', use integer or INFINITY or -INFINITY" > % value > ) >- rsc_colocation.setAttribute(name, value) >+ score_specified = True >+ attributes.append((name, value)) >+ else: >+ utils.err( >+ "invalid option '%s', allowed options are: %s" >+ % (name, ", ".join(score_options + ("id",))) >+ ) >+ >+ if not score_specified: >+ attributes.append(("score", "INFINITY")) >+ if not id_specified: >+ colocation_id = "pcs_rsc_colocation" >+ for a in argv: >+ if "=" not in a: >+ colocation_id += "_" + a >+ attributes.append(("id", utils.find_unique_id(cib, colocation_id))) >+ >+ rsc_colocation = cib.createElement("rsc_colocation") >+ for name, value in attributes: >+ rsc_colocation.setAttribute(name, value) > set_add_resource_sets(rsc_colocation, current_set, cib) > constraints.appendChild(rsc_colocation) > utils.replace_cib_configuration(cib) >@@ -457,16 +497,64 @@ def set_constraint_find_duplicates(dom, constraint_el): > ] > > def order_set(argv): >+ setoptions = [] >+ for i in range(len(argv)): >+ if argv[i] == "setoptions": >+ setoptions = argv[i+1:] >+ argv[i:] = [] >+ break >+ > current_set = set_args_into_array(argv) >+ cib, constraints = getCurrentConstraints(utils.get_cib_dom()) >+ >+ attributes = [] >+ id_specified = False >+ for opt in setoptions: >+ if "=" not in opt: >+ utils.err("missing value of '%s' option" % opt) >+ name, value = opt.split("=", 1) >+ if name == "id": >+ id_valid, id_error = utils.validate_xml_id(value, 'constraint id') >+ if not id_valid: >+ utils.err(id_error) >+ if utils.does_id_exist(cib, value): >+ utils.err( >+ "id '%s' is already in use, please specify another one" >+ % value >+ ) >+ id_specified = True >+ attributes.append((name, value)) >+ elif name == "kind": >+ normalized_value = value.lower().capitalize() >+ if normalized_value not in OPTIONS_KIND: >+ utils.err( >+ "invalid kind value '%s', allowed values are: %s" >+ % (value, ", ".join(OPTIONS_KIND)) >+ ) >+ attributes.append((name, normalized_value)) >+ elif name == "symmetrical": >+ if value.lower() not in OPTIONS_SYMMETRICAL: >+ utils.err( >+ "invalid symmetrical value '%s', allowed values are: %s" >+ % (value, ", ".join(OPTIONS_SYMMETRICAL)) >+ ) >+ attributes.append((name, value.lower())) >+ else: >+ utils.err( >+ "invalid option '%s', allowed options are: %s" >+ % (name, "kind, symmetrical, id") >+ ) > >- order_id = "pcs_rsc_order" >- for a in argv: >- if a.find('=') == -1: >- order_id = order_id + "_" + a >+ if not id_specified: >+ order_id = "pcs_rsc_order" >+ for a in argv: >+ if "=" not in a: >+ order_id += "_" + a >+ attributes.append(("id", utils.find_unique_id(cib, order_id))) > >- cib, constraints = getCurrentConstraints(utils.get_cib_dom()) > rsc_order = cib.createElement("rsc_order") >- rsc_order.setAttribute("id", utils.find_unique_id(cib, order_id)) >+ for name, value in attributes: >+ rsc_order.setAttribute(name, value) > set_add_resource_sets(rsc_order, current_set, cib) > constraints.appendChild(rsc_order) > utils.replace_cib_configuration(cib) >@@ -567,21 +655,47 @@ def order_add(argv,returnElementOnly=False): > elif not resource_valid: > utils.err(resource_error) > >- sym = "true" if (len(argv) == 0 or argv[0] != "nonsymmetrical") else "false" >- > order_options = [] >- if len(argv) != 0: >- if argv[0] == "nonsymmetrical" or argv[0] == "symmetrical": >- argv.pop(0) >- for arg in argv: >- if arg.count("=") == 1: >- mysplit = arg.split("=") >- order_options.append((mysplit[0],mysplit[1])) >- >- if len(argv) != 0: >- options = " (Options: " + " ".join(argv)+")" >- else: >- options = "" >+ id_specified = False >+ sym = None >+ for arg in argv: >+ if arg == "symmetrical": >+ sym = "true" >+ elif arg == "nonsymmetrical": >+ sym = "false" >+ elif "=" in arg: >+ name, value = arg.split("=", 1) >+ if name == "id": >+ id_valid, id_error = utils.validate_xml_id(value, 'constraint id') >+ if not id_valid: >+ utils.err(id_error) >+ if utils.does_id_exist(cib_dom, value): >+ utils.err( >+ "id '%s' is already in use, please specify another one" >+ % value >+ ) >+ id_specified = True >+ order_options.append((name, value)) >+ elif name == "symmetrical": >+ if value.lower() in OPTIONS_SYMMETRICAL: >+ sym = value.lower() >+ else: >+ utils.err( >+ "invalid symmetrical value '%s', allowed values are: %s" >+ % (value, ", ".join(OPTIONS_SYMMETRICAL)) >+ ) >+ else: >+ order_options.append((name, value)) >+ if sym: >+ order_options.append(("symmetrical", sym)) >+ >+ options = "" >+ if order_options: >+ options = " (Options: %s)" % " ".join([ >+ "%s=%s" % (name, value) >+ for name, value in order_options >+ if name not in ("kind", "score") >+ ]) > > scorekind = "kind: Mandatory" > id_suffix = "mandatory" >@@ -595,18 +709,17 @@ def order_add(argv,returnElementOnly=False): > id_suffix = opt[1] > break > >- order_id = "order-" + resource1 + "-" + resource2 + "-" + id_suffix >- order_id = utils.find_unique_id(cib_dom, order_id) >+ if not id_specified: >+ order_id = "order-" + resource1 + "-" + resource2 + "-" + id_suffix >+ order_id = utils.find_unique_id(cib_dom, order_id) >+ order_options.append(("id", order_id)) > > (dom,constraintsElement) = getCurrentConstraints() > element = dom.createElement("rsc_order") >- element.setAttribute("id",order_id) > element.setAttribute("first",resource1) > element.setAttribute("then",resource2) > for order_opt in order_options: > element.setAttribute(order_opt[0], order_opt[1]) >- if (sym == "false"): >- element.setAttribute("symmetrical", "false") > constraintsElement.appendChild(element) > if "--force" not in utils.pcs_options: > duplicates = order_find_duplicates(constraintsElement, element) >@@ -880,7 +993,7 @@ def location_add(argv,rm=False): > > def location_rule(argv): > if len(argv) < 3: >- usage.constraint("location rule") >+ usage.constraint(["location", "rule"]) > sys.exit(1) > > res_name = argv.pop(0) >@@ -891,16 +1004,30 @@ def location_rule(argv): > elif not resource_valid: > utils.err(resource_error) > >- argv.pop(0) >+ argv.pop(0) # pop "rule" > >+ options, rule_argv = rule_utils.parse_argv(argv, {"constraint-id": None,}) > cib, constraints = getCurrentConstraints(utils.get_cib_dom()) > lc = cib.createElement("rsc_location") > constraints.appendChild(lc) >- lc_id = utils.find_unique_id(cib, "location-" + res_name) >- lc.setAttribute("id", lc_id) >+ if options.get("constraint-id"): >+ id_valid, id_error = utils.validate_xml_id( >+ options["constraint-id"], 'constraint id' >+ ) >+ if not id_valid: >+ utils.err(id_error) >+ if utils.does_id_exist(cib, options["constraint-id"]): >+ utils.err( >+ "id '%s' is already in use, please specify another one" >+ % options["constraint-id"] >+ ) >+ lc.setAttribute("id", options["constraint-id"]) >+ del options["constraint-id"] >+ else: >+ lc.setAttribute("id", utils.find_unique_id(cib, "location-" + res_name)) > lc.setAttribute("rsc", res_name) > >- rule_utils.dom_rule_add(lc, argv) >+ rule_utils.dom_rule_add(lc, options, rule_argv) > location_rule_check_duplicates(constraints, lc) > utils.replace_cib_configuration(cib) > >@@ -1164,7 +1291,8 @@ def constraint_rule(argv): > ) > if not constraint: > utils.err("Unable to find constraint: " + constraint_id) >- rule_utils.dom_rule_add(constraint, argv) >+ options, rule_argv = rule_utils.parse_argv(argv) >+ rule_utils.dom_rule_add(constraint, options, rule_argv) > location_rule_check_duplicates(cib, constraint) > utils.replace_cib_configuration(cib) > >diff --git a/pcs/pcs.8 b/pcs/pcs.8 >index 5390350..cad0897 100644 >--- a/pcs/pcs.8 >+++ b/pcs/pcs.8 >@@ -364,7 +364,7 @@ Create a location constraint on a resource to prefer the specified node and scor > location <resource id> avoids <node[=score]>... > Create a location constraint on a resource to avoid the specified node and score (default score: INFINITY) > .TP >-location <resource id> rule [id=<rule id>] [role=master|slave] [score=<score>|score-attribute=<attribute>] <expression> >+location <resource id> rule [id=<rule id>] [role=master|slave] [constraint-id=<id>] [score=<score>|score-attribute=<attribute>] <expression> > Creates a location rule on the specified resource where the expression looks like one of the following: > .br > defined|not_defined <attribute> >@@ -398,10 +398,10 @@ order show [\fB\-\-full\fR] > List all current ordering constraints (if \fB\-\-full\fR is specified show the internal constraint id's as well). > .TP > order [action] <resource id> then [action] <resource id> [options] >-Add an ordering constraint specifying actions (start, stop, promote, demote) and if no action is specified the default action will be start. Available options are kind=Optional/Mandatory/Serialize and symmetrical=true/false >+Add an ordering constraint specifying actions (start, stop, promote, demote) and if no action is specified the default action will be start. Available options are kind=Optional/Mandatory/Serialize, symmetrical=true/false and id=<constraint-id>. > .TP >-order set <resource1> <resource2> [resourceN]... [options] [set <resourceX> <resourceY> ... [options]] >-Create an ordered set of resources. Available options are sequential=true/false, require-all=true/false, action=start/promote/demote/stop and role=Stopped/Started/Master/Slave. >+order set <resource1> <resource2> [resourceN]... [options] [set <resourceX> <resourceY> ... [options]] [setoptions [constraint_options]] >+Create an ordered set of resources. Available options are sequential=true/false, require-all=true/false, action=start/promote/demote/stop and role=Stopped/Started/Master/Slave. Available constraint_options are id=<constraint-id>, kind=Optional/Mandatory/Serialize and symmetrical=true/false. > .TP > order remove <resource1> [resourceN]... > Remove resource from any ordering constraint >@@ -409,11 +409,11 @@ Remove resource from any ordering constraint > colocation show [\fB\-\-full\fR] > List all current colocation constraints (if \fB\-\-full\fR is specified show the internal constraint id's as well). > .TP >-colocation add [master|slave] <source resource id> with [master|slave] <target resource id> [score] [options] >+colocation add [master|slave] <source resource id> with [master|slave] <target resource id> [score] [options] [id=constraint-id] > Request <source resource> to run on the same node where pacemaker has determined <target resource> should run. Positive values of score mean the resources should be run on the same node, negative values mean the resources should not be run on the same node. Specifying 'INFINITY' (or '\-INFINITY') for the score force <source resource> to run (or not run) with <target resource>. (score defaults to "INFINITY") A role can be master or slave (if no role is specified, it defaults to 'started'). > .TP > colocation set <resource1> <resource2> [resourceN]... [options] [set <resourceX> <resourceY> ... [options]] [setoptions [constraint_options]] >-Create a colocation constraint with a resource set. Available options are sequential=true/false, require-all=true/false, action=start/promote/demote/stop and role=Stopped/Started/Master/Slave. Available constraint_options are score, score-attribute and score-attribute-mangle. >+Create a colocation constraint with a resource set. Available options are sequential=true/false, require-all=true/false, action=start/promote/demote/stop and role=Stopped/Started/Master/Slave. Available constraint_options are id, score, score-attribute and score-attribute-mangle. > .TP > colocation remove <source resource id> <target resource id> > Remove colocation constraints with <source resource> >diff --git a/pcs/rule.py b/pcs/rule.py >index 7805b6f..e5606db 100644 >--- a/pcs/rule.py >+++ b/pcs/rule.py >@@ -4,13 +4,15 @@ import utils > > # main functions > >-def dom_rule_add(dom_element, argv): >+def parse_argv(argv, extra_options=None): > options = { > "id": None, > "role": None, > "score": None, > "score-attribute": None > } >+ if extra_options: >+ options.update(dict(extra_options)) > > # parse options > while argv: >@@ -24,11 +26,13 @@ def dom_rule_add(dom_element, argv): > if not found: > argv.insert(0, option) > break >+ return options, argv > >+def dom_rule_add(dom_element, options, rule_argv): > # validate options >- if options["score"] and options["score-attribute"]: >+ if options.get("score") and options.get("score-attribute"): > utils.err("can not specify both score and score-attribute") >- if options["score"] and not utils.is_score(options["score"]): >+ if options.get("score") and not utils.is_score(options["score"]): > # preserving legacy behaviour > print ( > "Warning: invalid score '%s', setting score-attribute=pingd instead" >@@ -36,11 +40,11 @@ def dom_rule_add(dom_element, argv): > ) > options["score-attribute"] = "pingd" > options["score"] = None >- if options["role"] and options["role"] not in ["master", "slave"]: >+ if options.get("role") and options["role"] not in ["master", "slave"]: > utils.err( > "invalid role '%s', use 'master' or 'slave'" % options["role"] > ) >- if options["id"]: >+ if options.get("id"): > id_valid, id_error = utils.validate_xml_id(options["id"], 'rule id') > if not id_valid: > utils.err(id_error) >@@ -51,29 +55,29 @@ def dom_rule_add(dom_element, argv): > ) > > # parse rule >- if not argv: >+ if not rule_argv: > utils.err("no rule expression was specified") > try: > dom_rule = CibBuilder().build( > dom_element, >- RuleParser().parse(TokenPreprocessor().run(argv)), >- options["id"] >+ RuleParser().parse(TokenPreprocessor().run(rule_argv)), >+ options.get("id") > ) > except SyntaxError as e: > utils.err( > "'%s' is not a valid rule expression: %s" >- % (" ".join(argv), e) >+ % (" ".join(rule_argv), e) > ) > except UnexpectedEndOfInput as e: > utils.err( > "'%s' is not a valid rule expression: unexpected end of rule" >- % " ".join(argv) >+ % " ".join(rule_argv) > ) > except (ParserException, CibBuilderException) as e: >- utils.err("'%s' is not a valid rule expression" % " ".join(argv)) >+ utils.err("'%s' is not a valid rule expression" % " ".join(rule_argv)) > > # add options into rule xml >- if not options["score"] and not options["score-attribute"]: >+ if not options.get("score") and not options.get("score-attribute"): > options["score"] = "INFINITY" > for name, value in options.iteritems(): > if name != "id" and value is not None: >diff --git a/pcs/test/test_constraints.py b/pcs/test/test_constraints.py >index c2769e3..df57ac8 100644 >--- a/pcs/test/test_constraints.py >+++ b/pcs/test/test_constraints.py >@@ -433,7 +433,7 @@ Colocation Constraints: > self.assertEquals(1, retValue) > > output, retValue = pcs(temp_cib, "constraint colocation set D1 D2 setoptions foo=bar") >- ac(output, "Error: invalid option 'foo', allowed options are: score, score-attribute, score-attribute-mangle\n") >+ ac(output, "Error: invalid option 'foo', allowed options are: score, score-attribute, score-attribute-mangle, id\n") > self.assertEquals(1, retValue) > > output, retValue = pcs(temp_cib, "constraint colocation set D1 D2 setoptions score=foo") >@@ -444,6 +444,10 @@ Colocation Constraints: > ac(output, "Error: you cannot specify multiple score options\n") > self.assertEquals(1, retValue) > >+ output, retValue = pcs(temp_cib, "constraint colocation set D1 D2 setoptions score-attribute=foo") >+ ac(output, "") >+ self.assertEquals(0, retValue) >+ > def testOrderSetsRemoval(self): > o,r = pcs("resource create T0 Dummy") > ac(o,"") >@@ -591,6 +595,52 @@ Ordering Constraints: > ac(output, "Error: invalid option 'foo', allowed options are: action, role, sequential, require-all\n") > self.assertEquals(1, retValue) > >+ output, retValue = pcs( >+ temp_cib, >+ "constraint order set D1 D2 setoptions foo=bar" >+ ) >+ ac(output, """\ >+Error: invalid option 'foo', allowed options are: kind, symmetrical, id >+""") >+ self.assertEquals(1, retValue) >+ >+ output, retValue = pcs( >+ temp_cib, >+ "constraint order set D1 D2 setoptions kind=foo" >+ ) >+ ac(output, """\ >+Error: invalid kind value 'foo', allowed values are: Optional, Mandatory, Serialize >+""") >+ self.assertEquals(1, retValue) >+ >+ output, retValue = pcs( >+ temp_cib, >+ "constraint order set D1 D2 setoptions symmetrical=foo" >+ ) >+ ac(output, """\ >+Error: invalid symmetrical value 'foo', allowed values are: true, false >+""") >+ self.assertEquals(1, retValue) >+ >+ output, retValue = pcs( >+ temp_cib, >+ "constraint order set D1 D2 setoptions symmetrical=false kind=mandatory" >+ ) >+ ac(output, "") >+ self.assertEquals(0, retValue) >+ >+ output, retValue = pcs(temp_cib, "constraint --full") >+ ac(output, """\ >+Location Constraints: >+Ordering Constraints: >+ Resource Sets: >+ set D7 sequential=false require-all=true (id:pcs_rsc_set_D5_D6_D7) set D8 D9 action=start role=Stopped sequential=true require-all=false (id:pcs_rsc_set_D8_D9) (id:pcs_rsc_order_D5_D6_D7_set_D8_D9) >+ set D7 D8 action=promote role=Slave (id:pcs_rsc_set_D7_D8) set D8 D9 action=demote role=Master (id:pcs_rsc_set_D8_D9-1) (id:pcs_rsc_order_D5_D6_set_D7_D8_set_D8_D9) >+ set D1 D2 (id:pcs_rsc_set_D1_D2) setoptions symmetrical=false kind=Mandatory (id:pcs_rsc_order_D1_D2) >+Colocation Constraints: >+""") >+ self.assertEquals(0, retValue) >+ > def testLocationConstraintRule(self): > o, r = pcs(temp_cib, "constraint location D1 prefers rh7-1") > assert r == 0 and o == "", o >@@ -2123,6 +2173,198 @@ Location Constraints: > Ordering Constraints: > Colocation Constraints: > """) >+ self.assertEquals(0, returnVal) >+ >+ def testConstraintsCustomId(self): >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint colocation add D1 with D2 id=1id" >+ ) >+ ac(output, """\ >+Error: invalid constraint id '1id', '1' is not a valid first character for a constraint id >+""") >+ self.assertEquals(1, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint colocation add D1 with D2 id=id1" >+ ) >+ ac(output, "") >+ self.assertEquals(0, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint colocation add D1 with D2 id=id1" >+ ) >+ ac(output, """\ >+Error: id 'id1' is already in use, please specify another one >+""") >+ self.assertEquals(1, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint colocation add D2 with D1 100 id=id2" >+ ) >+ ac(output, "") >+ self.assertEquals(0, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint colocation set D1 D2 setoptions id=3id" >+ ) >+ ac(output, """\ >+Error: invalid constraint id '3id', '3' is not a valid first character for a constraint id >+""") >+ self.assertEquals(1, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint colocation set D1 D2 setoptions id=id3" >+ ) >+ ac(output, "") >+ self.assertEquals(0, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint colocation set D1 D2 setoptions id=id3" >+ ) >+ ac(output, """\ >+Error: id 'id3' is already in use, please specify another one >+""") >+ self.assertEquals(1, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint colocation set D2 D1 setoptions score=100 id=id4" >+ ) >+ ac(output, "") >+ self.assertEquals(0, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint order set D1 D2 setoptions id=5id" >+ ) >+ ac(output, """\ >+Error: invalid constraint id '5id', '5' is not a valid first character for a constraint id >+""") >+ self.assertEquals(1, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint order set D1 D2 setoptions id=id5" >+ ) >+ ac(output, "") >+ self.assertEquals(0, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint order set D1 D2 setoptions id=id5" >+ ) >+ ac(output, """\ >+Error: id 'id5' is already in use, please specify another one >+""") >+ self.assertEquals(1, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint order set D2 D1 setoptions kind=Mandatory id=id6" >+ ) >+ ac(output, "") >+ self.assertEquals(0, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint order D1 then D2 id=7id" >+ ) >+ ac(output, """\ >+Error: invalid constraint id '7id', '7' is not a valid first character for a constraint id >+""") >+ self.assertEquals(1, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint order D1 then D2 id=id7" >+ ) >+ ac(output, """\ >+Adding D1 D2 (kind: Mandatory) (Options: id=id7 first-action=start then-action=start) >+""") >+ self.assertEquals(0, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint order D1 then D2 id=id7" >+ ) >+ ac(output, """\ >+Error: id 'id7' is already in use, please specify another one >+""") >+ self.assertEquals(1, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint order D2 then D1 kind=Optional id=id8" >+ ) >+ ac(output, """\ >+Adding D2 D1 (kind: Optional) (Options: id=id8 first-action=start then-action=start) >+""") >+ self.assertEquals(0, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint location D1 rule constraint-id=9id defined pingd" >+ ) >+ ac(output, """\ >+Error: invalid constraint id '9id', '9' is not a valid first character for a constraint id >+""") >+ self.assertEquals(1, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint location D1 rule constraint-id=id9 defined pingd" >+ ) >+ ac(output, "") >+ self.assertEquals(0, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint location D1 rule constraint-id=id9 defined pingd" >+ ) >+ ac(output, """\ >+Error: id 'id9' is already in use, please specify another one >+""") >+ self.assertEquals(1, returnVal) >+ >+ output, returnVal = pcs( >+ temp_cib, >+ "constraint location D2 rule score=100 constraint-id=id10 id=rule1 defined pingd" >+ ) >+ ac(output, "") >+ self.assertEquals(0, returnVal) >+ >+ output, returnVal = pcs(temp_cib, "constraint --full") >+ ac(output, """\ >+Location Constraints: >+ Resource: D1 >+ Constraint: id9 >+ Rule: score=INFINITY (id:id9-rule) >+ Expression: defined pingd (id:id9-rule-expr) >+ Resource: D2 >+ Constraint: id10 >+ Rule: score=100 (id:rule1) >+ Expression: defined pingd (id:rule1-expr) >+Ordering Constraints: >+ start D1 then start D2 (kind:Mandatory) (id:id7) >+ start D2 then start D1 (kind:Optional) (id:id8) >+ Resource Sets: >+ set D1 D2 (id:pcs_rsc_set_D1_D2-1) (id:id5) >+ set D2 D1 (id:pcs_rsc_set_D2_D1-1) setoptions kind=Mandatory (id:id6) >+Colocation Constraints: >+ D1 with D2 (score:INFINITY) (id:id1) >+ D2 with D1 (score:100) (id:id2) >+ Resource Sets: >+ set D1 D2 (id:pcs_rsc_set_D1_D2) setoptions score=INFINITY (id:id3) >+ set D2 D1 (id:pcs_rsc_set_D2_D1) setoptions score=100 (id:id4) >+""") >+ self.assertEquals(0, returnVal) > > if __name__ == "__main__": > unittest.main() >diff --git a/pcs/test/test_rule.py b/pcs/test/test_rule.py >index 051956a..b23632a 100644 >--- a/pcs/test/test_rule.py >+++ b/pcs/test/test_rule.py >@@ -1926,7 +1926,8 @@ Location Constraints: > cib_dom.createElement("rsc_location") > ) > constraint_el.setAttribute("id", "location-dummy") >- rule.dom_rule_add(constraint_el, rule_expression) >+ options, rule_argv = rule.parse_argv(rule_expression) >+ rule.dom_rule_add(constraint_el, options, rule_argv) > ac( > constraint_el.toprettyxml(indent=" "), > rule_xml.lstrip().rstrip(" ") >diff --git a/pcs/usage.py b/pcs/usage.py >index bb15a23..72fa748 100644 >--- a/pcs/usage.py >+++ b/pcs/usage.py >@@ -775,7 +775,8 @@ Commands: > node and score (default score: INFINITY) > > location <resource id> rule [id=<rule id>] [role=master|slave] >- [score=<score>|score-attribute=<attribute>] <expression> >+ [constraint-id=<id>] [score=<score>|score-attribute=<attribute>] >+ <expression> > Creates a location rule on the specified resource where the expression > looks like one of the following: > defined|not_defined <attribute> >@@ -811,17 +812,20 @@ Commands: > the internal constraint id's as well). > > order [action] <resource id> then [action] <resource id> [options] >- Add an ordering constraint specifying actions (start,stop,promote, >+ Add an ordering constraint specifying actions (start, stop, promote, > demote) and if no action is specified the default action will be > start. >- Available options are kind=Optional/Mandatory/Serialize and >- symmetrical=true/false >+ Available options are kind=Optional/Mandatory/Serialize, >+ symmetrical=true/false and id=<constraint-id>. > > order set <resource1> <resource2> [resourceN]... [options] [set > <resourceX> <resourceY> ... [options]] >+ [setoptions [constraint_options]] > Create an ordered set of resources. > Available options are sequential=true/false, require-all=true/false, > action=start/promote/demote/stop and role=Stopped/Started/Master/Slave. >+ Available constraint_options are id=<constraint-id>, >+ kind=Optional/Mandatory/Serialize and symmetrical=true/false. > > order remove <resource1> [resourceN]... > Remove resource from any ordering constraint >@@ -831,7 +835,7 @@ Commands: > the internal constraint id's as well). > > colocation add [master|slave] <source resource id> with [master|slave] >- <target resource id> [score] [options] >+ <target resource id> [score] [options] [id=constraint-id] > Request <source resource> to run on the same node where pacemaker has > determined <target resource> should run. Positive values of score > mean the resources should be run on the same node, negative values >@@ -847,7 +851,7 @@ Commands: > Create a colocation constraint with a resource set. > Available options are sequential=true/false, require-all=true/false, > action=start/promote/demote/stop and role=Stopped/Started/Master/Slave. >- Available constraint_options are score, score-attribute and >+ Available constraint_options are id, score, score-attribute and > score-attribute-mangle. > > colocation remove <source resource id> <target resource id> >-- >1.9.1 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 1110166
: 943699