diff --git a/crmd/crmd_utils.h b/crmd/crmd_utils.h index 351bb6beff0..0e670cd058d 100644 --- a/crmd/crmd_utils.h +++ b/crmd/crmd_utils.h @@ -90,6 +90,7 @@ xmlNode *create_node_state_update(crm_node_t *node, int flags, void populate_cib_nodes(enum node_update_flags flags, const char *source); void crm_update_quorum(gboolean quorum, gboolean force_update); void erase_status_tag(const char *uname, const char *tag, int options); +void init_transient_attrs(const char *uname, const char *start_state, int options); void update_attrd(const char *host, const char *name, const char *value, const char *user_name, gboolean is_remote_node); void update_attrd_remote_node_removed(const char *host, const char *user_name); diff --git a/crmd/join_client.c b/crmd/join_client.c index afd003ad33d..ede9bd103da 100644 --- a/crmd/join_client.c +++ b/crmd/join_client.c @@ -189,6 +189,7 @@ do_cl_join_finalize_respond(long long action, gboolean was_nack = TRUE; static gboolean first_join = TRUE; ha_msg_input_t *input = fsa_typed_data(fsa_dt_ha_msg); + const char *start_state = daemon_option("node_start_state"); int join_id = -1; const char *op = crm_element_value(input->msg, F_CRM_TASK); @@ -250,7 +251,13 @@ do_cl_join_finalize_respond(long long action, */ if (first_join && is_not_set(fsa_input_register, R_SHUTDOWN)) { first_join = FALSE; - erase_status_tag(fsa_our_uname, XML_TAG_TRANSIENT_NODEATTRS, 0); + + if (start_state) { + init_transient_attrs(fsa_our_uname, start_state, 0); + } else { + erase_status_tag(fsa_our_uname, XML_TAG_TRANSIENT_NODEATTRS, 0); + } + update_attrd(fsa_our_uname, "terminate", NULL, NULL, FALSE); update_attrd(fsa_our_uname, XML_CIB_ATTR_SHUTDOWN, "0", NULL, FALSE); } diff --git a/crmd/te_actions.c b/crmd/te_actions.c index 0b881cbbf74..5508234aaab 100644 --- a/crmd/te_actions.c +++ b/crmd/te_actions.c @@ -79,6 +79,8 @@ send_stonith_update(crm_action_t * action, const char *target, const char *uuid) /* zero out the node-status & remove all LRM status info */ xmlNode *node_state = NULL; + const char *start_state = daemon_option("node_start_state"); + CRM_CHECK(target != NULL, return); CRM_CHECK(uuid != NULL, return); @@ -127,7 +129,11 @@ send_stonith_update(crm_action_t * action, const char *target, const char *uuid) /* fsa_cib_conn->cmds->bump_epoch(fsa_cib_conn, cib_quorum_override|cib_scope_local); */ erase_status_tag(peer->uname, XML_CIB_TAG_LRM, cib_scope_local); - erase_status_tag(peer->uname, XML_TAG_TRANSIENT_NODEATTRS, cib_scope_local); + if (start_state) { + init_transient_attrs(peer->uname, start_state, cib_scope_local); + } else { + erase_status_tag(peer->uname, XML_TAG_TRANSIENT_NODEATTRS, cib_scope_local); + } free_xml(node_state); return; diff --git a/crmd/utils.c b/crmd/utils.c index 07c323d2fa2..82b5448691b 100644 --- a/crmd/utils.c +++ b/crmd/utils.c @@ -1008,6 +1008,56 @@ erase_status_tag(const char *uname, const char *tag, int options) } } +static void +crm_set_join_state(const char *uname, const char *start_state) +{ + if (safe_str_eq(start_state, "standby")) { + crm_notice("Forcing node %s to join in %s state per configured environment", uname, start_state); + update_attrd(uname, XML_CIB_ATTR_STANDBY, "on", NULL, FALSE); + } else if (safe_str_eq(start_state, "online")) { + crm_notice("Forcing node %s to join in %s state per configured environment", uname, start_state); + update_attrd(uname, XML_CIB_ATTR_STANDBY, "off", NULL, FALSE); + } else if (safe_str_eq(start_state, "default")) { + crm_debug("Not forcing a starting state on node %s", uname); + } else { + crm_warn("Unrecognized start state '%s', using 'default' (%s)", start_state, uname); + } +} + +static void +init_attrs_callback(xmlNode * msg, int call_id, int rc, xmlNode * output, void *user_data) +{ + char **data = (char**)user_data; + char *uname = data[0]; + char *start_state = data[1]; + char *xpath = data[2]; + + do_crm_log_unlikely(rc == 0 ? LOG_DEBUG : LOG_NOTICE, + "Erasing of \"%s\": %s (rc=%d)", xpath, pcmk_strerror(rc), rc); + crm_set_join_state(uname, start_state); + free(data[0]); + free(data[1]); + free(data[2]); +} + +void +init_transient_attrs(const char *uname, const char *start_state, int options) +{ + if (fsa_cib_conn && uname) { + int rc; + char *xpath = crm_strdup_printf("//node_state[@uname='%s']/%s", uname, XML_TAG_TRANSIENT_NODEATTRS); + int cib_opts = cib_quorum_override | cib_xpath | options; + const char **data = malloc(sizeof(char*)*3); + data[0] = strdup(uname); + data[1] = strdup(start_state); + data[2] = strdup(xpath); + + crm_info("Erasing transient attributes for %s", uname); + rc = fsa_cib_conn->cmds->delete(fsa_cib_conn, xpath, NULL, cib_opts); + fsa_register_cib_callback(rc, FALSE, data, init_attrs_callback); + } +} + void crmd_peer_down(crm_node_t *peer, bool full) { if(full && peer->state == NULL) { diff --git a/include/crm/msg_xml.h b/include/crm/msg_xml.h index 6ec796a9c8e..e0470780b36 100644 --- a/include/crm/msg_xml.h +++ b/include/crm/msg_xml.h @@ -256,6 +256,7 @@ # define XML_CIB_ATTR_SHUTDOWN "shutdown" # define XML_CIB_ATTR_STONITH "stonith" +# define XML_CIB_ATTR_STANDBY "standby" /* LRM is a bit of a misnomer here; the crmd and pengine use these to track * actions, which usually but not always are LRM operations diff --git a/mcp/pacemaker.c b/mcp/pacemaker.c index 95c137010aa..194ed78280d 100644 --- a/mcp/pacemaker.c +++ b/mcp/pacemaker.c @@ -671,6 +671,7 @@ static struct crm_option long_options[] = { {"-spacer-", 1, 0, '-', "\nAdditional Options:"}, {"foreground", 0, 0, 'f', "\t(Ignored) Pacemaker always runs in the foreground"}, {"pid-file", 1, 0, 'p', "\t(Ignored) Daemon pid file location"}, + {"standby", 0, 0, 's', "\tStart node in standby state"}, {NULL, 0, 0, 0} }; @@ -941,6 +942,9 @@ main(int argc, char **argv) case 'p': pid_file = optarg; break; + case 's': + set_daemon_option("node_start_state", "standby"); + break; case '$': case '?': crm_help(flag, EX_OK);