return tvals;
}
+struct get_runstate_callback_data {
+ enum ctdb_runstate *out;
+ bool fatal;
+};
+
+static void get_runstate_callback(struct ctdb_context *ctdb, uint32_t pnn,
+ int32_t res, TDB_DATA outdata,
+ void *callback_data)
+{
+ struct get_runstate_callback_data *cd =
+ (struct get_runstate_callback_data *)callback_data;
+ int size;
+
+ if (res != 0) {
+ /* Already handled in fail callback */
+ return;
+ }
+
+ if (outdata.dsize != sizeof(uint32_t)) {
+ DEBUG(DEBUG_ERR,("Wrong size of returned data when getting runstate from node %d. Expected %d bytes but received %d bytes\n",
+ pnn, (int)sizeof(uint32_t),
+ (int)outdata.dsize));
+ cd->fatal = true;
+ return;
+ }
+
+ size = talloc_array_length(cd->out);
+ if (pnn >= size) {
+ DEBUG(DEBUG_ERR,("Got reply from node %d but nodemap only has %d entries\n",
+ pnn, size));
+ return;
+ }
+
+ cd->out[pnn] = (enum ctdb_runstate)*(uint32_t *)outdata.dptr;
+}
+
+static void get_runstate_fail_callback(struct ctdb_context *ctdb, uint32_t pnn,
+ int32_t res, TDB_DATA outdata,
+ void *callback)
+{
+ struct get_runstate_callback_data *cd =
+ (struct get_runstate_callback_data *)callback;
+
+ switch (res) {
+ case -ETIME:
+ DEBUG(DEBUG_ERR,
+ ("Timed out getting runstate from node %d\n", pnn));
+ cd->fatal = true;
+ break;
+ default:
+ DEBUG(DEBUG_WARNING,
+ ("Error getting runstate from node %d - assuming runstates not supported\n",
+ pnn));
+ }
+}
+
+static enum ctdb_runstate * get_runstate_from_nodes(struct ctdb_context *ctdb,
+ TALLOC_CTX *tmp_ctx,
+ struct ctdb_node_map *nodemap,
+ enum ctdb_runstate default_value)
+{
+ uint32_t *nodes;
+ enum ctdb_runstate *rs;
+ struct get_runstate_callback_data callback_data;
+ int i;
+
+ rs = talloc_array(tmp_ctx, enum ctdb_runstate, nodemap->num);
+ CTDB_NO_MEMORY_NULL(ctdb, rs);
+ for (i=0; i<nodemap->num; i++) {
+ rs[i] = default_value;
+ }
+
+ callback_data.out = rs;
+ callback_data.fatal = false;
+
+ nodes = list_of_connected_nodes(ctdb, nodemap, tmp_ctx, true);
+ if (ctdb_client_async_control(ctdb, CTDB_CONTROL_GET_RUNSTATE,
+ nodes, 0, TAKEOVER_TIMEOUT(),
+ true, tdb_null,
+ get_runstate_callback,
+ get_runstate_fail_callback,
+ &callback_data) != 0) {
+ if (callback_data.fatal) {
+ free(rs);
+ rs = NULL;
+ }
+ }
+ talloc_free(nodes);
+
+ return rs;
+}
+
/* Set internal flags for IP allocation:
* Clear ip flags
* Set NOIPTAKOVER ip flags from per-node NoIPTakeover tunable
TALLOC_CTX *tmp_ctx,
struct ctdb_node_map *nodemap,
uint32_t *tval_noiptakeover,
- uint32_t *tval_noiphostonalldisabled)
+ uint32_t *tval_noiphostonalldisabled,
+ enum ctdb_runstate *runstate)
{
int i;
struct ctdb_ipflags *ipflags;
ipflags[i].noiptakeover = true;
}
+ /* Can not host IPs on node not in RUNNING state */
+ if (runstate[i] != CTDB_RUNSTATE_RUNNING) {
+ ipflags[i].noiphost = true;
+ continue;
+ }
/* Can not host IPs on INACTIVE node */
if (nodemap->nodes[i].flags & NODE_FLAGS_INACTIVE) {
ipflags[i].noiphost = true;
uint32_t *tval_noiptakeover;
uint32_t *tval_noiphostonalldisabled;
struct ctdb_ipflags *ipflags;
+ enum ctdb_runstate *runstate;
+
tval_noiptakeover = get_tunable_from_nodes(ctdb, tmp_ctx, nodemap,
"NoIPTakeover", 0);
return NULL;
}
+ /* Any nodes where CTDB_CONTROL_GET_RUNSTATE is not supported
+ * will default to CTDB_RUNSTATE_RUNNING. This ensures
+ * reasonable behaviour on a mixed cluster during upgrade.
+ */
+ runstate = get_runstate_from_nodes(ctdb, tmp_ctx, nodemap,
+ CTDB_RUNSTATE_RUNNING);
+ if (runstate == NULL) {
+ /* Caller frees tmp_ctx */
+ return NULL;
+ }
+
ipflags = set_ipflags_internal(ctdb, tmp_ctx, nodemap,
tval_noiptakeover,
- tval_noiphostonalldisabled);
+ tval_noiphostonalldisabled,
+ runstate);
talloc_free(tval_noiptakeover);
talloc_free(tval_noiphostonalldisabled);
+ talloc_free(runstate);
return ipflags;
}
return tvals;
}
+static enum ctdb_runstate *get_runstate(TALLOC_CTX *tmp_ctx,
+ int numnodes)
+{
+ int i;
+ uint32_t *tvals;
+ enum ctdb_runstate *runstate =
+ talloc_zero_array(tmp_ctx, enum ctdb_runstate, numnodes);
+ char *t = getenv("CTDB_TEST_RUNSTATE");
+
+ if (t == NULL) {
+ for (i=0; i<numnodes; i++) {
+ runstate[i] = CTDB_RUNSTATE_RUNNING;
+ }
+ } else {
+ tvals = get_tunable_values(tmp_ctx, numnodes, "CTDB_TEST_RUNSTATE");
+ for (i=0; i<numnodes; i++) {
+ runstate[i] = (enum ctdb_runstate) tvals[i];
+ }
+ talloc_free(tvals);
+ }
+
+ return runstate;
+}
+
void ctdb_test_init(const char nodestates[],
struct ctdb_context **ctdb,
struct ctdb_public_ip_list **all_ips,
struct ctdb_node_map *nodemap;
uint32_t *tval_noiptakeover;
uint32_t *tval_noiptakeoverondisabled;
+ enum ctdb_runstate *runstate;
*ctdb = talloc_zero(NULL, struct ctdb_context);
get_tunable_values(*ctdb, numnodes,
"CTDB_SET_NoIPHostOnAllDisabled");
+ runstate = get_runstate(*ctdb, numnodes);
+
nodemap = talloc_array(*ctdb, struct ctdb_node_map, numnodes);
nodemap->num = numnodes;
*ipflags = set_ipflags_internal(*ctdb, *ctdb, nodemap,
tval_noiptakeover,
- tval_noiptakeoverondisabled);
+ tval_noiptakeoverondisabled,
+ runstate);
}
/* IP layout is read from stdin. */