On Mon, 2011-04-11 at 20:50 +0200, Andrew Beekhof wrote: > why? > CMD_ERR("Resource %s not moved:" > " specifying --master is not supported for > --move-from\n", rsc_id); > it did not look sensible to me but I can't recall the exact reasons 8-) It's now implemented. > also the legacy handling is a little off - do a make install and run > tools/regression.sh and you'll see what i mean.
Remaining diffs seem to be not related to my changes. > other than that the crm_resource part looks pretty good. > can you add some regression testcases in tools/ too please? > Will add them once the code is in the repo. Latest diffs are attached. -holger
diff -r b4f456380f60 shell/modules/ui.py.in --- a/shell/modules/ui.py.in Thu Mar 17 09:41:25 2011 +0100 +++ b/shell/modules/ui.py.in Sun Apr 24 16:18:59 2011 +0200 @@ -738,8 +738,9 @@ rsc_status = "crm_resource -W -r '%s'" rsc_showxml = "crm_resource -q -r '%s'" rsc_setrole = "crm_resource --meta -r '%s' -p target-role -v '%s'" - rsc_migrate = "crm_resource -M -r '%s' %s" - rsc_unmigrate = "crm_resource -U -r '%s'" + rsc_move_to = "crm_resource --move-to -r '%s' %s" + rsc_move_from = "crm_resource --move-from -r '%s' %s" + rsc_move_cleanup = "crm_resource --move-cleanup -r '%s'" rsc_cleanup = "crm_resource -C -r '%s' -H '%s'" rsc_cleanup_all = "crm_resource -C -r '%s'" rsc_param = { @@ -776,8 +777,12 @@ self.cmd_table["demote"] = (self.demote,(1,1),0) self.cmd_table["manage"] = (self.manage,(1,1),0) self.cmd_table["unmanage"] = (self.unmanage,(1,1),0) + # the next two commands are deprecated self.cmd_table["migrate"] = (self.migrate,(1,4),0) self.cmd_table["unmigrate"] = (self.unmigrate,(1,1),0) + self.cmd_table["move-to"] = (self.move_to,(2,4),0) + self.cmd_table["move-from"] = (self.move_from,(1,4),0) + self.cmd_table["move-cleanup"] = (self.move_cleanup,(1,1),0) self.cmd_table["param"] = (self.param,(3,4),1) self.cmd_table["meta"] = (self.meta,(3,4),1) self.cmd_table["utilization"] = (self.utilization,(3,4),1) @@ -846,9 +851,67 @@ if not is_name_sane(rsc): return False return set_deep_meta_attr("is-managed","false",rsc) + def move_to(self,cmd,*args): + """usage: move-to <rsc>[:master] <node> [<lifetime>] [force]""" + elem = args[0].split(':') + rsc = elem[0] + master = False + if len(elem) > 1: + master = elem[1] + if master != "master": + common_error("%s is invalid, specify 'master'" % master) + return False + master = True + if not is_name_sane(rsc): + return False + node = args[1] + lifetime = None + force = False + if len(args) == 3: + if args[2] == "force": + force = True + else: + lifetime = args[2] + elif len(args) == 4: + if args[2] == "force": + force = True + lifetime = args[3] + elif args[3] == "force": + force = True + lifetime = args[2] + else: + syntax_err((cmd,force)) + return False + + opts = '' + if node: + opts = "--node='%s'" % node + if lifetime: + opts = "%s --lifetime='%s'" % (opts,lifetime) + if force or user_prefs.get_force(): + opts = "%s --force" % opts + if master: + opts = "%s --master" % opts + return ext_cmd(self.rsc_move_to % (rsc,opts)) == 0 + def migrate(self,cmd,*args): - """usage: migrate <rsc> [<node>] [<lifetime>] [force]""" - rsc = args[0] + """Deprecated: migrate <rsc> [<node>] [<lifetime>] [force]""" + common_warning("migrate is deprecated, use move-to or move-from") + if len(args) >= 2 and args[1] in listnodes(): + return self.move_to(cmd, *args) + return self.move_from(cmd, *args) + + def move_from(self,cmd,*args): + """usage: move-from <rsc>[:master] [<node>] [<lifetime>] [force]""" + elem = args[0].split(':') + rsc = elem[0] + master = False + if len(elem) > 1: + master = elem[1] + if master != "master": + common_error("%s is invalid, specify 'master'" % master) + return False + master = True if not is_name_sane(rsc): return False node = None @@ -888,12 +951,18 @@ opts = "%s --lifetime='%s'" % (opts,lifetime) if force or user_prefs.get_force(): opts = "%s --force" % opts - return ext_cmd(self.rsc_migrate % (rsc,opts)) == 0 - def unmigrate(self,cmd,rsc): - "usage: unmigrate <rsc>" + if master: + opts = "%s --master" % opts + return ext_cmd(self.rsc_move_from % (rsc,opts)) == 0 + def move_cleanup(self,cmd,rsc): + "usage: move_cleanup <rsc>" if not is_name_sane(rsc): return False - return ext_cmd(self.rsc_unmigrate%rsc) == 0 + return ext_cmd(self.rsc_move_cleanup%rsc) == 0 + def unmigrate(self,cmd,rsc): + "Deprecated: usage: unmigrate <rsc>" + common_warning("unmigrate is deprecated, use move-cleanup") + return self.move_cleanup(cmd, rsc) def cleanup(self,cmd,*args): "usage: cleanup <rsc> [<node>]" # Cleanup a resource on a node. Omit node to cleanup on
diff -r b4f456380f60 tools/crm_resource.c --- a/tools/crm_resource.c Thu Mar 17 09:41:25 2011 +0100 +++ b/tools/crm_resource.c Sun Apr 24 16:17:40 2011 +0200 @@ -52,7 +52,8 @@ const char *prop_id = NULL; const char *prop_set = NULL; char *move_lifetime = NULL; -char rsc_cmd = 'L'; +int move_master = 0; +int rsc_cmd = 'L'; char *our_pid = NULL; IPC_Channel *crmd_channel = NULL; char *xml_file = NULL; @@ -192,6 +193,33 @@ return 0; } +/* return role of resource on node */ +static int +role_on_node(resource_t *rsc, const char *node_uname) +{ + GListPtr lpc = NULL; + + if(rsc->variant > pe_native) { + /* recursively call down */ + GListPtr gIter = rsc->children; + for(; gIter != NULL; gIter = gIter->next) { + int role; + if((role = role_on_node(gIter->data, node_uname)) != RSC_ROLE_UNKNOWN) + return role; + } + return RSC_ROLE_UNKNOWN; + } + + for(lpc = rsc->running_on; lpc != NULL; lpc = lpc->next) { + node_t *node = (node_t*)lpc->data; + if(rsc->variant == pe_native + && safe_str_eq(node->details->uname, node_uname)) { + return rsc->role; + } + } + return RSC_ROLE_UNKNOWN; +} + #define cons_string(x) x?x:"NA" static void print_cts_constraints(pe_working_set_t *data_set) @@ -795,8 +823,9 @@ } static int -move_resource( +make_move_constraint( const char *rsc_id, + int move_master, const char *existing_node, const char *preferred_node, cib_t * cib_conn) { @@ -824,7 +853,8 @@ crm_xml_add(dont_run, XML_ATTR_ID, id); crm_free(id); - if(move_lifetime) { + /* don't compute lifetime on a delete operation */ + if(move_lifetime && (existing_node != NULL || preferred_node != NULL)) { char *life = crm_strdup(move_lifetime); char *life_mutable = life; @@ -868,15 +898,17 @@ } else { if(BE_QUIET == FALSE) { + const char *ms_text = move_master ? " as master": ""; + fprintf(stderr, "WARNING: Creating rsc_location constraint '%s'" - " with a score of -INFINITY for resource %s" + " with a score of -INFINITY for resource %s%s" " on %s.\n", - ID(dont_run), rsc_id, existing_node); - CMD_ERR("\tThis will prevent %s from running" + ID(dont_run), rsc_id, ms_text, existing_node); + CMD_ERR("\tThis will prevent %s%s from running" " on %s until the constraint is removed using" - " the 'crm_resource -U' command or manually" - " with cibadmin\n", rsc_id, existing_node); + " the 'crm_resource --move-cleanup' command or manually" + " with cibadmin\n", rsc_id, ms_text, existing_node); CMD_ERR("\tThis will be the case even if %s is" " the last node in the cluster\n", existing_node); CMD_ERR("\tThis message can be disabled with -Q\n"); @@ -890,6 +922,10 @@ crm_xml_add(rule, XML_ATTR_ID, id); crm_free(id); + if(move_master) { + crm_xml_add(rule, XML_RULE_ATTR_ROLE, "Master"); + } + crm_xml_add(rule, XML_RULE_ATTR_SCORE, MINUS_INFINITY_S); crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and"); @@ -935,6 +971,10 @@ crm_xml_add(rule, XML_ATTR_ID, id); crm_free(id); + if(move_master) { + crm_xml_add(rule, XML_RULE_ATTR_ROLE, "Master"); + } + crm_xml_add(rule, XML_RULE_ATTR_SCORE, INFINITY_S); crm_xml_add(rule, XML_RULE_ATTR_BOOLEAN_OP, "and"); @@ -975,6 +1015,85 @@ } static int +move_resource_from(resource_t *rsc, const char *from_uname, cib_t *cib_conn) +{ + int rc = 0; + + /* if from_uname is empty figure out the current node */ + if(from_uname == NULL) { + node_t *current = NULL; + if (rsc->variant > pe_group) { + CMD_ERR("Resource %s not moved:" + " move without hostname not supported for clones and masters\n", rsc_id); + return rc; + } + + if(rsc->running_on != NULL) + current = rsc->running_on->data; + + if(current == NULL) { + CMD_ERR("Resource %s not moved:" + " not-active and no preferred location specified.\n", rsc_id); + return cib_missing; + } else { + from_uname = current->details->uname; + } + } + + if(rsc->variant < pe_master && move_master) { + CMD_ERR("Error performing operation: " + "--master is only supported for m/s resources\n"); + } else if (!do_force && role_on_node(rsc, from_uname) < RSC_ROLE_STARTED) { + CMD_ERR("Resource %s not moved:" + " not active on %s\n", rsc_id, from_uname); + } else { + /* zap a possibly existing stale master rule */ + make_move_constraint(rsc_id, 0, NULL, NULL, cib_conn); + rc = make_move_constraint(rsc_id, move_master, from_uname, NULL, cib_conn); + } + + return rc; +} + +static int +move_resource_to(resource_t *rsc, const char *to_uname, cib_t *cib_conn) +{ + int rc = 0; + int role = role_on_node(rsc, to_uname); + + if(rsc->variant < pe_master) { + if(move_master) { + CMD_ERR("Error performing operation: " + "--master is only supported for m/s resources\n"); + } else if(!do_force && role >= RSC_ROLE_STARTED) { + CMD_ERR("Error performing operation: " + "%s is already active on %s\n", + rsc_id, to_uname); + } else { + rc = make_move_constraint(rsc_id, 0, NULL, to_uname, cib_conn); + } + + } else { /* pe_master */ + if(!do_force && move_master && role == RSC_ROLE_MASTER) { + CMD_ERR("Error performing operation: " + "%s is already active on %s with role Master\n", + rsc_id, to_uname); + } else if(!do_force && move_master && role != RSC_ROLE_SLAVE) { + CMD_ERR("Error performing operation: " + "%s is not active on %s as Slave, can't move Master role\n", + rsc_id, to_uname); + + } else { + /* zap a possibly existing master rule */ + make_move_constraint(rsc_id, 0, NULL, NULL, cib_conn); + rc = make_move_constraint(rsc_id, move_master, NULL, to_uname, cib_conn); + } + } + + return rc; +} + +static int list_resource_operations( const char *rsc_id, const char *host_uname, gboolean active, pe_working_set_t *data_set) { @@ -1093,6 +1212,11 @@ crm_free(prefix); } +/* (partially) out of single letter options */ +#define CMD_MOVE_TO (1001) +#define CMD_MOVE_FROM (1002) +#define CMD_MOVE_CLEANUP (1003) +#define OPT_MASTER (1101) static struct crm_option long_options[] = { /* Top-level Options */ {"help", 0, 0, '?', "\t\tThis text"}, @@ -1119,11 +1243,14 @@ {"delete-parameter",1, 0, 'd', "Delete the named parameter for a resource. See also -m, --meta"}, {"get-property", 1, 0, 'G', "Display the 'class', 'type' or 'provider' of a resource", 1}, {"set-property", 1, 0, 'S', "(Advanced) Set the class, type or provider of a resource", 1}, - {"move", 0, 0, 'M', - "\t\tMove a resource from its current location, optionally specifying a destination (-N) and/or a period for which it should take effect (-u)" + {"move-to", 0, 0, CMD_MOVE_TO, + "\t\tMove a resource from its current location, optionally specifying a role (--master), a destination (-N) and/or a period for which it should take effect (-u)"}, + {"move-from", 0, 0, CMD_MOVE_FROM, "\tMove a resource away from the node specified by -N" "\n\t\t\t\tIf -N is not specified, the cluster will force the resource to move by creating a rule for the current location and a score of -INFINITY" "\n\t\t\t\tNOTE: This will prevent the resource from running on this node until the constraint is removed with -U"}, - {"un-move", 0, 0, 'U', "\tRemove all constraints created by a move command"}, + {"move-cleanup", 0, 0, CMD_MOVE_CLEANUP, "\tRemove all constraints created by a move command"}, + {"move", 0, 0, 'M', "Deprecated: Use --move-to or --move-from"}, + {"un-move", 0, 0, 'U', "Deprecated: Use --move-cleanup"}, {"-spacer-", 1, 0, '-', "\nAdvanced Commands:"}, {"delete", 0, 0, 'D', "\t\tDelete a resource from the CIB"}, @@ -1137,6 +1264,7 @@ {"resource-type", 1, 0, 't', "Resource type (primitive, clone, group, ...)"}, {"parameter-value", 1, 0, 'v', "Value to use with -p, -g or -d"}, {"lifetime", 1, 0, 'u', "\tLifespan of migration constraints\n"}, + {"master", 0, 0, OPT_MASTER, "\t\tMaster role for migration constraints\n"}, {"meta", 0, 0, 'm', "\t\tModify a resource's configuration option rather than one which is passed to the resource agent script. For use with -p, -g, -d"}, {"utilization", 0, 0, 'z', "\tModify a resource's utilization attribute. For use with -p, -g, -d"}, {"set-name", 1, 0, 's', "\t(Advanced) ID of the instance_attributes object to change"}, @@ -1158,12 +1286,19 @@ {"-spacer-", 1, 0, '-', " crm_resource --list", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Display the current location of 'myResource':", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --locate", pcmk_option_example}, - {"-spacer-", 1, 0, '-', "Move 'myResource' to another machine:", pcmk_option_paragraph}, + {"-spacer-", 1, 0, '-', "Move primitive or group 'myResource' off the active node:", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --move", pcmk_option_example}, + {"-spacer-", 1, 0, '-', "Move 'myResource' off the specified node:", pcmk_option_paragraph}, + {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --move-off --node actNode", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Move 'myResource' to a specific machine:", pcmk_option_paragraph}, - {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --move --node altNode", pcmk_option_example}, + {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --move-to --node altNode", pcmk_option_example}, + {"-spacer-", 1, 0, '-', " crm_resource --resource myMsResource --master --move-to --node altNode", pcmk_option_example}, + {"-spacer-", 1, 0, '-', "Move 'myResource' away from a specific machine:", pcmk_option_paragraph}, + {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --move-from --node actNode", pcmk_option_example}, + {"-spacer-", 1, 0, '-', "Move a primitive/group 'myResource' away from the current machine:", pcmk_option_paragraph}, + {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --move-from", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Allow (but not force) 'myResource' to move back to its original location:", pcmk_option_paragraph}, - {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --un-move", pcmk_option_example}, + {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --move-cleanup", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Tell the cluster that 'myResource' failed:", pcmk_option_paragraph}, {"-spacer-", 1, 0, '-', " crm_resource --resource myResource --fail", pcmk_option_example}, {"-spacer-", 1, 0, '-', "Stop a 'myResource' (and anything that depends on it):", pcmk_option_paragraph}, @@ -1263,13 +1398,19 @@ case 'C': case 'W': case 'M': + case CMD_MOVE_TO: + case CMD_MOVE_FROM: + case CMD_MOVE_CLEANUP: case 'U': case 'O': case 'o': case 'A': case 'a': rsc_cmd = flag; - break; + break; + case OPT_MASTER: + move_master = 1; + break; case 'p': case 'g': case 'd': @@ -1476,67 +1617,55 @@ } rc = dump_resource(rsc_id, &data_set); - } else if(rsc_cmd == 'U') { + } else if(rsc_cmd == 'U' || rsc_cmd == CMD_MOVE_CLEANUP) { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n"); rc = cib_NOTEXISTS; goto bail; - } - rc = move_resource(rsc_id, NULL, NULL, cib_conn); + } + if (rsc_cmd == 'U') + CMD_ERR("{-U|--un-move} is deprecated, use --move-cleanup\n"); + rc = make_move_constraint(rsc_id, 0, NULL, NULL, cib_conn); - } else if(rsc_cmd == 'M') { - node_t *dest = NULL; - node_t *current = NULL; - const char *current_uname = NULL; + } else if(rsc_cmd == CMD_MOVE_TO || rsc_cmd == CMD_MOVE_FROM || rsc_cmd == 'M') { resource_t *rsc = pe_find_resource(data_set.resources, rsc_id); - if(rsc != NULL && rsc->running_on != NULL) { - current = rsc->running_on->data; - if(current != NULL) { - current_uname = current->details->uname; - } - } - if(host_uname != NULL) { - dest = pe_find_node(data_set.nodes, host_uname); - } - + /* some common error checking */ if(rsc == NULL) { CMD_ERR("Resource %s not moved:" " not found\n", rsc_id); + goto bail; + } - } else if(rsc->variant == pe_native - && g_list_length(rsc->running_on) > 1) { - CMD_ERR("Resource %s not moved:" - " active on multiple nodes\n", rsc_id); - - } else if(host_uname != NULL && dest == NULL) { - CMD_ERR("Error performing operation: " - "%s is not a known node\n", host_uname); - rc = cib_NOTEXISTS; + if(host_uname != NULL) { + if(pe_find_node(data_set.nodes, host_uname) == NULL) { + CMD_ERR("Error performing operation: " + "%s is not a known node\n", host_uname); + rc = cib_NOTEXISTS; + goto bail; + } + } - } else if(host_uname != NULL - && safe_str_eq(current_uname, host_uname)) { - CMD_ERR("Error performing operation: " - "%s is already active on %s\n", - rsc_id, host_uname); + if (rsc_cmd == 'M') { + CMD_ERR("{-M|--move} is deprecated, use --move-to or --move-from\n"); + if (host_uname == NULL) { + rsc_cmd = CMD_MOVE_FROM; + } else { + rsc_cmd = CMD_MOVE_TO; + } + } - } else if(current_uname != NULL - && (do_force || host_uname == NULL)) { - rc = move_resource(rsc_id, current_uname, - host_uname, cib_conn); + switch(rsc_cmd) { + case CMD_MOVE_TO: + rc = move_resource_to(rsc, host_uname, cib_conn); + break; - - } else if(host_uname != NULL) { - rc = move_resource( - rsc_id, NULL, host_uname, cib_conn); + case CMD_MOVE_FROM: + rc = move_resource_from(rsc, host_uname, cib_conn); + break; - } else { - CMD_ERR("Resource %s not moved: " - "not-active and no preferred location" - " specified.\n", rsc_id); - rc = cib_missing; - } - + } + } else if(rsc_cmd == 'G') { if(rsc_id == NULL) { CMD_ERR("Must supply a resource id with -r\n");
diff -r b4f456380f60 doc/crm_cli.txt --- a/doc/crm_cli.txt Thu Mar 17 09:41:25 2011 +0100 +++ b/doc/crm_cli.txt Sun Apr 24 16:30:01 2011 +0200 @@ -810,28 +810,45 @@ unmanage <rsc> ............... -[[cmdhelp_resource_migrate,migrate a resource to another node]] -==== `migrate` (`move`) - -Migrate a resource to a different node. If node is left out, the -resource is migrated by creating a constraint which prevents it from -running on the current node. Additionally, you may specify a +[[cmdhelp_resource_move-to,move a resource to another node]] +==== `move-to` + +Move a resource to a different node. The resource is moved by creating +a constraint which forces it to run on the specified node. +Additionally, you may specify a lifetime for the constraint---once it +expires, the location constraint will no longer be active. +For a master resource specify <rsc>:master to move the master role. + +Usage: +............... + move-to <rsc>[:master] <node> [<lifetime>] [force] +............... + +[[cmdhelp_resource_move-from,move a resource away from the specified node]] +==== `move-from` + +Move a resource away from the specified node. +If node is left out, the the node where the resource is currently active +is used. +The resource is moved by creating a constraint which prevents it from +running on the specified node. Additionally, you may specify a lifetime for the constraint---once it expires, the location constraint will no longer be active. +For a master resource specify <rsc>:master to move the master role. Usage: ............... - migrate <rsc> [<node>] [<lifetime>] [force] + move-from <rsc>[:master] [<node>] [<lifetime>] [force] ............... -[[cmdhelp_resource_unmigrate,unmigrate a resource to another node]] -==== `unmigrate` (`unmove`) - -Remove the constraint generated by the previous migrate command. +[[cmdhelp_resource_move-cleanup,Cleanup previously created move constraint]] +==== `move-cleanup` + +Remove the constraint generated by the previous move-to/move-from command. Usage: ............... - unmigrate <rsc> + move-cleanup <rsc> ............... [[cmdhelp_resource_param,manage a parameter of a resource]]
_______________________________________________ Pacemaker mailing list: Pacemaker@oss.clusterlabs.org http://oss.clusterlabs.org/mailman/listinfo/pacemaker Project Home: http://www.clusterlabs.org Getting started: http://www.clusterlabs.org/doc/Cluster_from_Scratch.pdf Bugs: http://developerbugs.linux-foundation.org/enter_bug.cgi?product=Pacemaker