/* This is lazy... but it is test code! */
#define CTDB_TEST_MAX_NODES 256
-#define CTDB_TEST_MAX_IPS 256
+#define CTDB_TEST_MAX_IPS 1024
/* Format of each line is "IP pnn" - the separator has to be at least
* 1 space (not a tab or whatever - a space!).
*/
-static struct ctdb_public_ip_list *
+static struct public_ip_list *
read_ctdb_public_ip_list(TALLOC_CTX *ctx)
{
char line[1024];
ctdb_sock_addr addr;
char *t;
int pnn;
- struct ctdb_public_ip_list *last = NULL;
+ struct public_ip_list *last = NULL;
- struct ctdb_public_ip_list *ret = NULL;
+ struct public_ip_list *ret = NULL;
while (fgets(line, sizeof(line), stdin) != NULL) {
if (parse_ip(line, NULL, 0, &addr)) {
if (last == NULL) {
- last = talloc(ctx, struct ctdb_public_ip_list);
+ last = talloc(ctx, struct public_ip_list);
} else {
- last->next = talloc(ctx, struct ctdb_public_ip_list);
+ last->next = talloc(ctx, struct public_ip_list);
last = last->next;
}
last->next = NULL;
return ret;
}
-void print_ctdb_public_ip_list(struct ctdb_public_ip_list * ips)
+static void print_ctdb_public_ip_list(struct public_ip_list * ips)
{
while (ips) {
printf("%s %d\n", ctdb_addr_to_str(&(ips->addr)), ips->pnn);
/* Read some IPs from stdin, 1 per line, parse them and then print
* them back out. */
-void ctdb_test_read_ctdb_public_ip_list(void)
+static void ctdb_test_read_ctdb_public_ip_list(void)
{
- struct ctdb_public_ip_list *l;
+ struct public_ip_list *l;
TALLOC_CTX *tmp_ctx = talloc_new(NULL);
talloc_free(tmp_ctx);
}
-/* Format of each line is "IP pnn" - the separator has to be at least
- * 1 space (not a tab or whatever - a space!).
+static uint32_t *get_tunable_values(TALLOC_CTX *tmp_ctx,
+ int numnodes,
+ const char *tunable);
+static enum ctdb_runstate *get_runstate(TALLOC_CTX *tmp_ctx,
+ int numnodes);
+
+/* Format of each line is "IP CURRENT_PNN ALLOWED_PNN,...".
*/
static bool
-read_ctdb_public_ip_info(TALLOC_CTX *ctx,
+read_ctdb_public_ip_info(TALLOC_CTX *ctx ,
int numnodes,
- struct ctdb_public_ip_list ** all_ips,
- struct ctdb_all_public_ips *** avail)
+ struct public_ip_list ** all_ips,
+ struct ctdb_public_ip_list_old *** known,
+ struct ctdb_public_ip_list_old *** avail)
{
char line[1024];
ctdb_sock_addr addr;
char *t, *tok;
- struct ctdb_public_ip_list * ta;
+ struct public_ip_list * ta;
int pnn, numips, curr, n, i;
- struct ctdb_all_public_ips * a;
+ struct ctdb_public_ip_list_old * a;
+
+ struct public_ip_list *last = NULL;
+ enum ctdb_runstate *runstate;
- struct ctdb_public_ip_list *last = NULL;
+ runstate = get_runstate(ctx, numnodes);
- *avail = talloc_array_size(ctx, sizeof(struct ctdb_all_public_ips *), CTDB_TEST_MAX_NODES);
+ *known = talloc_array_size(ctx, sizeof(struct ctdb_public_ip_list_old *), CTDB_TEST_MAX_NODES);
+ memset(*known, 0,
+ sizeof(struct ctdb_public_ip_list_old *) * CTDB_TEST_MAX_NODES);
+
+ *avail = talloc_array_size(ctx, sizeof(struct ctdb_public_ip_list_old *),
+ CTDB_TEST_MAX_NODES);
memset(*avail, 0,
- sizeof(struct ctdb_all_public_ips *) * CTDB_TEST_MAX_NODES);
+ sizeof(struct ctdb_public_ip_list_old *) * CTDB_TEST_MAX_NODES);
numips = 0;
*all_ips = NULL;
*t = '\0';
}
+ /* Exit on an empty line */
+ if (line[0] == '\0') {
+ break;
+ }
+
/* Get the IP address */
tok = strtok(line, " \t");
if (tok == NULL) {
}
numips++;
+ if (numips > CTDB_TEST_MAX_IPS) {
+ DEBUG(DEBUG_ERR, ("ERROR: Exceeding CTDB_TEST_MAX_IPS: %d\n", CTDB_TEST_MAX_IPS));
+ exit(1);
+ }
/* Get the PNN */
pnn = -1;
/* Add address + pnn to all_ips */
if (last == NULL) {
- last = talloc(ctx, struct ctdb_public_ip_list);
+ last = talloc(ctx, struct public_ip_list);
} else {
- last->next = talloc(ctx, struct ctdb_public_ip_list);
+ last->next = talloc(ctx, struct public_ip_list);
last = last->next;
}
last->next = NULL;
t = strtok(tok, ",");
while (t != NULL) {
n = (int) strtol(t, (char **) NULL, 10);
- if ((*avail)[n] == NULL) {
- (*avail)[n] = talloc_array(ctx, struct ctdb_all_public_ips, CTDB_TEST_MAX_IPS);
- (*avail)[n]->num = 0;
+ if ((*known)[n] == NULL) {
+ (*known)[n] = talloc_array(ctx, struct ctdb_public_ip_list_old, CTDB_TEST_MAX_IPS);
+ (*known)[n]->num = 0;
}
- curr = (*avail)[n]->num;
- (*avail)[n]->ips[curr].pnn = pnn;
- memcpy(&((*avail)[n]->ips[curr].addr),
+ curr = (*known)[n]->num;
+ (*known)[n]->ips[curr].pnn = pnn;
+ memcpy(&((*known)[n]->ips[curr].addr),
&addr, sizeof(addr));
- (*avail)[n]->num++;
+ (*known)[n]->num++;
t = strtok(NULL, ",");
}
}
/* Build list of all allowed IPs */
- a = talloc_array(ctx, struct ctdb_all_public_ips, CTDB_TEST_MAX_IPS);
+ a = talloc_array(ctx, struct ctdb_public_ip_list_old, CTDB_TEST_MAX_IPS);
a->num = numips;
for (ta = *all_ips, i=0; ta != NULL && i < numips ; ta = ta->next, i++) {
a->ips[i].pnn = ta->pnn;
/* Assign it to any nodes that don't have a list assigned */
for (n = 0; n < numnodes; n++) {
- if ((*avail)[n] == NULL) {
- (*avail)[n] = a;
+ if ((*known)[n] == NULL) {
+ (*known)[n] = a;
+ }
+ if (runstate[n] == CTDB_RUNSTATE_RUNNING) {
+ (*avail)[n] = (*known)[n];
}
}
return true;
}
-void print_ctdb_available_ips(int numnodes, struct ctdb_all_public_ips **avail)
+static void print_ctdb_available_ips(int numnodes,
+ struct ctdb_public_ip_list_old **avail)
{
int n, i;
}
}
-void ctdb_test_read_ctdb_public_ip_info(const char nodestates[])
+static void ctdb_test_read_ctdb_public_ip_info(const char nodestates[])
{
int numnodes;
- struct ctdb_public_ip_list *l;
- struct ctdb_all_public_ips **avail;
+ struct public_ip_list *l;
+ struct ctdb_public_ip_list_old **known;
+ struct ctdb_public_ip_list_old **avail;
char *tok, *ns;
TALLOC_CTX *tmp_ctx = talloc_new(NULL);
tok = strtok(ns, ",");
while (tok != NULL) {
numnodes++;
+ if (numnodes > CTDB_TEST_MAX_NODES) {
+ DEBUG(DEBUG_ERR, ("ERROR: Exceeding CTDB_TEST_MAX_NODES: %d\n", CTDB_TEST_MAX_NODES));
+ exit(1);
+ }
tok = strtok(NULL, ",");
}
- read_ctdb_public_ip_info(tmp_ctx, numnodes, &l, &avail);
+ read_ctdb_public_ip_info(tmp_ctx, numnodes, &l, &known, &avail);
print_ctdb_public_ip_list(l);
print_ctdb_available_ips(numnodes, avail);
}
/* Read 2 IPs from stdin, calculate the IP distance and print it. */
-void ctdb_test_ip_distance(void)
+static void ctdb_test_ip_distance(void)
{
- struct ctdb_public_ip_list *l;
+ struct public_ip_list *l;
uint32_t distance;
TALLOC_CTX *tmp_ctx = talloc_new(NULL);
/* Read some IPs from stdin, calculate the sum of the squares of the
* IP distances between the 1st argument and those read that are on
* the given node. The given IP must one of the ones in the list. */
-void ctdb_test_ip_distance_2_sum(const char ip[], int pnn)
+static void ctdb_test_ip_distance_2_sum(const char ip[], int pnn)
{
- struct ctdb_public_ip_list *l;
- struct ctdb_public_ip_list *t;
+ struct public_ip_list *l;
+ struct public_ip_list *t;
ctdb_sock_addr addr;
uint32_t distance;
talloc_free(tmp_ctx);
}
-/* Read some IPs from stdin, calculate the sume of the squares of the
+/* Read some IPs from stdin, calculate the sum of the squares of the
* IP distances between the first and the rest, and print it. */
-void ctdb_test_lcp2_imbalance(int pnn)
+static void ctdb_test_lcp2_imbalance(int pnn)
{
- struct ctdb_public_ip_list *l;
+ struct public_ip_list *l;
uint32_t imbalance;
TALLOC_CTX *tmp_ctx = talloc_new(NULL);
talloc_free(tmp_ctx);
}
-void ctdb_test_init(const char nodestates[],
- struct ctdb_context **ctdb,
- struct ctdb_public_ip_list **all_ips,
- struct ctdb_node_map **nodemap)
+static uint32_t *get_tunable_values(TALLOC_CTX *tmp_ctx,
+ int numnodes,
+ const char *tunable)
{
- struct ctdb_all_public_ips **avail;
+ int i;
+ char *tok;
+ uint32_t *tvals = talloc_zero_array(tmp_ctx, uint32_t, numnodes);
+ char *t = getenv(tunable);
+
+ if (t) {
+ if (strcmp(t, "1") == 0) {
+ for (i=0; i<numnodes; i++) {
+ tvals[i] = 1;
+ }
+ } else {
+ tok = strtok(t, ",");
+ i = 0;
+ while (tok != NULL) {
+ tvals[i] =
+ (uint32_t) strtol(tok, NULL, 0);
+ i++;
+ tok = strtok(NULL, ",");
+ }
+ if (i != numnodes) {
+ fprintf(stderr, "ERROR: Wrong number of values in %s\n", tunable);
+ exit(1);
+ }
+ }
+ }
+
+ 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;
+}
+
+/* Fake up enough CTDB state to be able to run the IP allocation
+ * algorithm. Usually this sets up some standard state, sets the node
+ * states from the command-line and reads the current IP layout from
+ * stdin.
+ *
+ * However, if read_ips_for_multiple_nodes is true then each node's
+ * idea of the IP layout is read separately from stdin. In this mode
+ * is doesn't make much sense to use read_ctdb_public_ip_info's
+ * optional ALLOWED_PNN,... list in the input, since each node is
+ * being handled separately anyway. IPs for each node are separated
+ * by a blank line. This mode is for testing weird behaviours where
+ * the IP layouts differs across nodes and we want to improve
+ * create_merged_ip_list(), so should only be used in tests of
+ * ctdb_takeover_run_core(). Yes, it is a hack... :-)
+ */
+static void ctdb_test_init(const char nodestates[],
+ struct ctdb_context **ctdb,
+ struct ipalloc_state **ipalloc_state,
+ bool read_ips_for_multiple_nodes)
+{
+ struct ctdb_public_ip_list_old **known;
+ struct ctdb_public_ip_list_old **avail;
int i, numnodes;
uint32_t nodeflags[CTDB_TEST_MAX_NODES];
- char *tok, *ns;
+ char *tok, *ns, *t;
+ struct ctdb_node_map_old *nodemap;
+ uint32_t *tval_noiptakeover;
+ uint32_t *tval_noiptakeoverondisabled;
+ struct public_ip_list *all_ips;
*ctdb = talloc_zero(NULL, struct ctdb_context);
numnodes = 0;
tok = strtok(ns, ",");
while (tok != NULL) {
- nodeflags[numnodes] = (uint32_t) strtol(tok, NULL, 16);
+ nodeflags[numnodes] = (uint32_t) strtol(tok, NULL, 0);
numnodes++;
+ if (numnodes >= CTDB_TEST_MAX_NODES) {
+ DEBUG(DEBUG_ERR, ("ERROR: Exceeding CTDB_TEST_MAX_NODES: %d\n", CTDB_TEST_MAX_NODES));
+ exit(1);
+ }
tok = strtok(NULL, ",");
}
/* Fake things up... */
(*ctdb)->num_nodes = numnodes;
+ /* Default to LCP2 */
+ (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
(*ctdb)->tunable.deterministic_public_ips = 0;
(*ctdb)->tunable.disable_ip_failover = 0;
(*ctdb)->tunable.no_ip_failback = 0;
- if (getenv("CTDB_LCP2")) {
- if (strcmp(getenv("CTDB_LCP2"), "yes") == 0) {
+ if ((t = getenv("CTDB_IP_ALGORITHM"))) {
+ if (strcmp(t, "lcp2") == 0) {
(*ctdb)->tunable.lcp2_public_ip_assignment = 1;
- } else {
+ } else if (strcmp(t, "nondet") == 0) {
(*ctdb)->tunable.lcp2_public_ip_assignment = 0;
+ } else if (strcmp(t, "det") == 0) {
+ (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
+ (*ctdb)->tunable.deterministic_public_ips = 1;
+ } else {
+ fprintf(stderr, "ERROR: unknown IP algorithm %s\n", t);
+ exit(1);
}
}
- *nodemap = talloc_array(*ctdb, struct ctdb_node_map, numnodes);
- (*nodemap)->num = numnodes;
+ tval_noiptakeover = get_tunable_values(*ctdb, numnodes,
+ "CTDB_SET_NoIPTakeover");
+ tval_noiptakeoverondisabled =
+ get_tunable_values(*ctdb, numnodes,
+ "CTDB_SET_NoIPHostOnAllDisabled");
- read_ctdb_public_ip_info(*ctdb, numnodes, all_ips, &avail);
+ nodemap = talloc_array(*ctdb, struct ctdb_node_map_old, numnodes);
+ nodemap->num = numnodes;
+
+ if (!read_ips_for_multiple_nodes) {
+ read_ctdb_public_ip_info(*ctdb, numnodes,
+ &all_ips, &known, &avail);
+ }
(*ctdb)->nodes = talloc_array(*ctdb, struct ctdb_node *, numnodes); // FIXME: bogus size, overkill
+ *ipalloc_state = ipalloc_state_init(*ctdb, *ctdb);
+
for (i=0; i < numnodes; i++) {
- (*nodemap)->nodes[i].pnn = i;
- (*nodemap)->nodes[i].flags = nodeflags[i];
+ nodemap->nodes[i].pnn = i;
+ nodemap->nodes[i].flags = nodeflags[i];
/* nodemap->nodes[i].sockaddr is uninitialised */
+ if (read_ips_for_multiple_nodes) {
+ read_ctdb_public_ip_info(*ctdb, numnodes,
+ &all_ips, &known, &avail);
+ }
+
(*ctdb)->nodes[i] = talloc(*ctdb, struct ctdb_node);
(*ctdb)->nodes[i]->pnn = i;
(*ctdb)->nodes[i]->flags = nodeflags[i];
- (*ctdb)->nodes[i]->available_public_ips = avail[i];
- (*ctdb)->nodes[i]->known_public_ips = avail[i];
+
+ (*ipalloc_state)->available_public_ips[i] = avail[i];
+ (*ipalloc_state)->known_public_ips[i] = known[i];
}
+
+ set_ipflags_internal(*ipalloc_state, nodemap,
+ tval_noiptakeover,
+ tval_noiptakeoverondisabled);
+
+ (*ipalloc_state)->all_ips = create_merged_ip_list(*ctdb,
+ *ipalloc_state);
+
+ (*ipalloc_state)->force_rebalance_nodes = NULL;
}
/* IP layout is read from stdin. */
-void ctdb_test_lcp2_allocate_unassigned(const char nodestates[])
+static void ctdb_test_lcp2_allocate_unassigned(const char nodestates[])
{
struct ctdb_context *ctdb;
- struct ctdb_public_ip_list *all_ips;
- struct ctdb_node_map *nodemap;
+ struct ipalloc_state *ipalloc_state;
uint32_t *lcp2_imbalances;
bool *newly_healthy;
- ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
+ ctdb_test_init(nodestates, &ctdb, &ipalloc_state, false);
- lcp2_init(ctdb, nodemap,
- NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
- all_ips, &lcp2_imbalances, &newly_healthy);
+ lcp2_init(ipalloc_state, &lcp2_imbalances, &newly_healthy);
- lcp2_allocate_unassigned(ctdb, nodemap,
- NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
- all_ips, lcp2_imbalances);
+ lcp2_allocate_unassigned(ipalloc_state, lcp2_imbalances);
- print_ctdb_public_ip_list(all_ips);
+ print_ctdb_public_ip_list(ipalloc_state->all_ips);
talloc_free(ctdb);
}
/* IP layout is read from stdin. */
-void ctdb_test_lcp2_failback(const char nodestates[])
+static void ctdb_test_lcp2_failback(const char nodestates[])
{
struct ctdb_context *ctdb;
- struct ctdb_public_ip_list *all_ips;
- struct ctdb_node_map *nodemap;
+ struct ipalloc_state *ipalloc_state;
uint32_t *lcp2_imbalances;
bool *newly_healthy;
- ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
+ ctdb_test_init(nodestates, &ctdb, &ipalloc_state, false);
- lcp2_init(ctdb, nodemap,
- NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
- all_ips, &lcp2_imbalances, &newly_healthy);
+ lcp2_init(ipalloc_state, &lcp2_imbalances, &newly_healthy);
- lcp2_failback(ctdb, nodemap,
- NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
- all_ips, lcp2_imbalances, newly_healthy);
+ lcp2_failback(ipalloc_state, lcp2_imbalances, newly_healthy);
- print_ctdb_public_ip_list(all_ips);
+ print_ctdb_public_ip_list(ipalloc_state->all_ips);
talloc_free(ctdb);
}
/* IP layout is read from stdin. */
-void ctdb_test_lcp2_failback_loop(const char nodestates[])
+static void ctdb_test_lcp2_failback_loop(const char nodestates[])
{
struct ctdb_context *ctdb;
- struct ctdb_public_ip_list *all_ips;
- struct ctdb_node_map *nodemap;
+ struct ipalloc_state *ipalloc_state;
uint32_t *lcp2_imbalances;
bool *newly_healthy;
- ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
+ ctdb_test_init(nodestates, &ctdb, &ipalloc_state, false);
- lcp2_init(ctdb, nodemap,
- NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
- all_ips, &lcp2_imbalances, &newly_healthy);
+ lcp2_init(ipalloc_state, &lcp2_imbalances, &newly_healthy);
-try_again:
- if (lcp2_failback(ctdb, nodemap,
- NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
- all_ips, lcp2_imbalances, newly_healthy)) {
- goto try_again;
- }
+ lcp2_failback(ipalloc_state, lcp2_imbalances, newly_healthy);
- print_ctdb_public_ip_list(all_ips);
+ print_ctdb_public_ip_list(ipalloc_state->all_ips);
talloc_free(ctdb);
}
-/* IP layout is read from stdin. */
-void ctdb_test_ctdb_takeover_run_core(const char nodestates[])
+/* IP layout is read from stdin. See comment for ctdb_test_init() for
+ * explanation of read_ips_for_multiple_nodes.
+ */
+static void ctdb_test_ctdb_takeover_run_core(const char nodestates[],
+ bool read_ips_for_multiple_nodes)
{
struct ctdb_context *ctdb;
- struct ctdb_public_ip_list *all_ips;
- struct ctdb_node_map *nodemap;
+ struct ipalloc_state *ipalloc_state;
- ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
+ ctdb_test_init(nodestates, &ctdb, &ipalloc_state,
+ read_ips_for_multiple_nodes);
- ctdb_takeover_run_core(ctdb, nodemap, &all_ips);
+ ctdb_takeover_run_core(ipalloc_state);
- print_ctdb_public_ip_list(all_ips);
+ print_ctdb_public_ip_list(ipalloc_state->all_ips);
talloc_free(ctdb);
}
-void usage(void)
+static void usage(void)
{
fprintf(stderr, "usage: ctdb_takeover_tests <op>\n");
exit(1);
int main(int argc, const char *argv[])
{
- LogLevel = DEBUG_DEBUG;
+ DEBUGLEVEL = DEBUG_DEBUG;
if (getenv("CTDB_TEST_LOGLEVEL")) {
- LogLevel = atoi(getenv("CTDB_TEST_LOGLEVEL"));
+ DEBUGLEVEL = atoi(getenv("CTDB_TEST_LOGLEVEL"));
}
if (argc < 2) {
ctdb_test_lcp2_failback(argv[2]);
} else if (argc == 3 && strcmp(argv[1], "lcp2_failback_loop") == 0) {
ctdb_test_lcp2_failback_loop(argv[2]);
- } else if (argc == 3 && strcmp(argv[1], "ctdb_takeover_run_core") == 0) {
- ctdb_test_ctdb_takeover_run_core(argv[2]);
+ } else if (argc == 3 &&
+ strcmp(argv[1], "ctdb_takeover_run_core") == 0) {
+ ctdb_test_ctdb_takeover_run_core(argv[2], false);
+ } else if (argc == 4 &&
+ strcmp(argv[1], "ctdb_takeover_run_core") == 0 &&
+ strcmp(argv[3], "multi") == 0) {
+ ctdb_test_ctdb_takeover_run_core(argv[2], true);
} else {
usage();
}