On Thu, 2011-04-07 at 12:33 +0200, Dejan Muhamedagic wrote: > > New syntax: > > ----------- > > > > crm_resource --move-from --resource myresource --node mynode > > -> all resource variants: check whether active on mynode, then create > > standby constraint > > > > crm_resource --move-from --resource myresource > > -> primitive/group: set --node `current_node`, then create standby > > constraint > > -> clone/master: refused > > > > crm_resource --move-to --resource myresource --node mynode > > -> all resource variants: create prefer constraint > > > > crm_resource --move-to --resource myresource --master --node mynode > > -> master: check whether active as slave on mynode, then create prefer > > constraint for master role > > -> others: refused > > > > crm_resource --move-cleanup --resource myresource > > -> zap constraints > > > > As we are already short on meaningful single letter options I vote for long > > options only. > > > > Backwards Compatibility: > > ------------------------ > > > > crm_resource {-M|--move} --resource myresource > > -> output deprecation warning > > -> treat as crm_resource --move-from --resource myresource > > > > crm_resource {-M|--move} --resource myresource --node mynode > > -> output deprecation warning > > -> treat as crm_resource --move-to --resource myresource --node mynode > > > > crm_resource {-U|--unmove} --resource myresource > > -> output deprecation warning > > -> treat as crm_resource --move-cleanup --resource myresource > > All looks fine to me. > > > For the shell: > > Should we go for similar commands or keep "migrate-XXX" > > migrate is a bit of a misnomer, could be confused with the > migrate operation. I'd vote to leave old migrate/unmigrate > as deprecated and introduce just move-from/to/cleanup variants. >
Deajn & Andrew, please find attached the patches that implement these commands for review. The require the patch Low: lib/common/utils.c: Don't try to print unprintable option values in crm_help that I send separately because it is not directly related to the movement stuff. I think that the preceding discussions were very valuable to fully understand issues and implications and I'm confident that the new command set is consistent and behaves with predictable outcome. Regards Holger
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 Fri Apr 08 14:23:59 2011 +0200 @@ -810,28 +810,44 @@ 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. Usage: ............... - migrate <rsc> [<node>] [<lifetime>] [force] + move-from <rsc> [<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]]
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 Fri Apr 08 15:02:39 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; @@ -875,7 +905,7 @@ ID(dont_run), rsc_id, existing_node); CMD_ERR("\tThis will prevent %s from running" " on %s until the constraint is removed using" - " the 'crm_resource -U' command or manually" + " the 'crm_resource --move-cleanup' command or manually" " with cibadmin\n", rsc_id, existing_node); CMD_ERR("\tThis will be the case even if %s is" " the last node in the cluster\n", existing_node); @@ -935,6 +965,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 +1009,83 @@ } 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 on any node\n", rsc_id); + return 0; + } else { + from_uname = current->details->uname; + } + } + + 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 if (move_master) { + CMD_ERR("Resource %s not moved:" + " specifying --master is not supported for --move-from\n", rsc_id); + } else { + rc = make_move_constraint(rsc_id, 0, 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 +1204,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 +1235,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 +1256,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 +1278,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 +1390,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 +1609,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("Deprecation warning: instead of {-U|--un-move} use --move-cleanup in the future\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("Deprecation warning: instead of {-M|--move} use --move-to or --move-from in the future\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 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 Fri Apr 08 15:20:32 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,8 +851,58 @@ 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]""" + """Deprecated: migrate <rsc> [<node>] [<lifetime>] [force]""" + common_warning("Deprecation warning: Instead of migrate use move-to or move-from in the future") + 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> [<node>] [<lifetime>] [force]""" rsc = args[0] if not is_name_sane(rsc): return False @@ -888,12 +943,16 @@ 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>" + 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("Deprecation warning: Instead of unmigrate use move-cleanup in the future") + 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
_______________________________________________ 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