2 Tests for ctdb_takeover.c
4 Copyright (C) Martin Schwenke 2011
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "ctdbd_test.c"
22 /* This is lazy... but it is test code! */
23 #define CTDB_TEST_MAX_NODES 256
24 #define CTDB_TEST_MAX_IPS 256
26 /* Format of each line is "IP pnn" - the separator has to be at least
27 * 1 space (not a tab or whatever - a space!).
29 static struct ctdb_public_ip_list *
30 read_ctdb_public_ip_list(TALLOC_CTX *ctx)
36 struct ctdb_public_ip_list *last = NULL;
38 struct ctdb_public_ip_list *ret = NULL;
40 while (fgets(line, sizeof(line), stdin) != NULL) {
42 if ((t = strchr(line, ' ')) != NULL) {
43 /* Make line contain just the address */
45 /* Point to PNN or leading whitespace... */
47 pnn = (int) strtol(t, (char **) NULL, 10);
49 /* Assume just an IP address, default to PNN -1 */
50 if ((t = strchr(line, '\n')) != NULL) {
56 if (parse_ip(line, NULL, 0, &addr)) {
58 last = talloc(ctx, struct ctdb_public_ip_list);
60 last->next = talloc(ctx, struct ctdb_public_ip_list);
65 memcpy(&(last->addr), &addr, sizeof(addr));
70 DEBUG(DEBUG_ERR, (__location__ " ERROR, bad address :%s\n", line));
77 void print_ctdb_public_ip_list(struct ctdb_public_ip_list * ips)
80 printf("%s %d\n", ctdb_addr_to_str(&(ips->addr)), ips->pnn);
85 /* Read some IPs from stdin, 1 per line, parse them and then print
87 void ctdb_test_read_ctdb_public_ip_list(void)
89 struct ctdb_public_ip_list *l;
91 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
93 l = read_ctdb_public_ip_list(tmp_ctx);
95 print_ctdb_public_ip_list(l);
100 /* Format of each line is "IP CURRENT_PNN ALLOWED_PNN,...".
103 read_ctdb_public_ip_info(TALLOC_CTX *ctx,
105 struct ctdb_public_ip_list ** all_ips,
106 struct ctdb_all_public_ips *** avail)
111 struct ctdb_public_ip_list * ta;
112 int pnn, numips, curr, n, i;
113 struct ctdb_all_public_ips * a;
115 struct ctdb_public_ip_list *last = NULL;
117 *avail = talloc_array_size(ctx, sizeof(struct ctdb_all_public_ips *), CTDB_TEST_MAX_NODES);
119 sizeof(struct ctdb_all_public_ips *) * CTDB_TEST_MAX_NODES);
123 while (fgets(line, sizeof(line), stdin) != NULL) {
125 /* Get rid of pesky newline */
126 if ((t = strchr(line, '\n')) != NULL) {
130 /* Get the IP address */
131 tok = strtok(line, " \t");
133 DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line ignored :%s\n", line));
137 if (!parse_ip(tok, NULL, 0, &addr)) {
138 DEBUG(DEBUG_ERR, (__location__ " ERROR, bad address :%s\n", tok));
146 tok = strtok(NULL, " \t");
148 pnn = (int) strtol(tok, (char **) NULL, 10);
151 /* Add address + pnn to all_ips */
153 last = talloc(ctx, struct ctdb_public_ip_list);
155 last->next = talloc(ctx, struct ctdb_public_ip_list);
160 memcpy(&(last->addr), &addr, sizeof(addr));
161 if (*all_ips == NULL) {
165 tok = strtok(NULL, " \t#");
170 /* Handle allowed nodes for addr */
171 t = strtok(tok, ",");
173 n = (int) strtol(t, (char **) NULL, 10);
174 if ((*avail)[n] == NULL) {
175 (*avail)[n] = talloc_array(ctx, struct ctdb_all_public_ips, CTDB_TEST_MAX_IPS);
176 (*avail)[n]->num = 0;
178 curr = (*avail)[n]->num;
179 (*avail)[n]->ips[curr].pnn = pnn;
180 memcpy(&((*avail)[n]->ips[curr].addr),
181 &addr, sizeof(addr));
183 t = strtok(NULL, ",");
188 /* Build list of all allowed IPs */
189 a = talloc_array(ctx, struct ctdb_all_public_ips, CTDB_TEST_MAX_IPS);
191 for (ta = *all_ips, i=0; ta != NULL && i < numips ; ta = ta->next, i++) {
192 a->ips[i].pnn = ta->pnn;
193 memcpy(&(a->ips[i].addr), &(ta->addr), sizeof(ta->addr));
196 /* Assign it to any nodes that don't have a list assigned */
197 for (n = 0; n < numnodes; n++) {
198 if ((*avail)[n] == NULL) {
206 void print_ctdb_available_ips(int numnodes, struct ctdb_all_public_ips **avail)
210 for (n = 0; n < numnodes; n++) {
211 if ((avail[n] != NULL) && (avail[n]->num > 0)) {
213 for (i = 0; i < avail[n]->num; i++) {
215 (i == 0) ? " " : ", ",
216 ctdb_addr_to_str(&(avail[n]->ips[i].addr)));
223 void ctdb_test_read_ctdb_public_ip_info(const char nodestates[])
226 struct ctdb_public_ip_list *l;
227 struct ctdb_all_public_ips **avail;
230 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
232 /* Avoid that const */
233 ns = talloc_strdup(tmp_ctx, nodestates);
236 tok = strtok(ns, ",");
237 while (tok != NULL) {
239 tok = strtok(NULL, ",");
242 read_ctdb_public_ip_info(tmp_ctx, numnodes, &l, &avail);
244 print_ctdb_public_ip_list(l);
245 print_ctdb_available_ips(numnodes, avail);
247 talloc_free(tmp_ctx);
250 /* Read 2 IPs from stdin, calculate the IP distance and print it. */
251 void ctdb_test_ip_distance(void)
253 struct ctdb_public_ip_list *l;
256 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
258 l = read_ctdb_public_ip_list(tmp_ctx);
261 distance = ip_distance(&(l->addr), &(l->next->addr));
262 printf ("%lu\n", (unsigned long) distance);
265 talloc_free(tmp_ctx);
268 /* Read some IPs from stdin, calculate the sum of the squares of the
269 * IP distances between the 1st argument and those read that are on
270 * the given node. The given IP must one of the ones in the list. */
271 void ctdb_test_ip_distance_2_sum(const char ip[], int pnn)
273 struct ctdb_public_ip_list *l;
274 struct ctdb_public_ip_list *t;
278 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
281 l = read_ctdb_public_ip_list(tmp_ctx);
283 if (l && parse_ip(ip, NULL, 0, &addr)) {
284 /* find the entry for the specified IP */
285 for (t=l; t!=NULL; t=t->next) {
286 if (ctdb_same_ip(&(t->addr), &addr)) {
292 fprintf(stderr, "IP NOT PRESENT IN LIST");
296 distance = ip_distance_2_sum(&(t->addr), l, pnn);
297 printf ("%lu\n", (unsigned long) distance);
299 fprintf(stderr, "BAD INPUT");
303 talloc_free(tmp_ctx);
306 /* Read some IPs from stdin, calculate the sume of the squares of the
307 * IP distances between the first and the rest, and print it. */
308 void ctdb_test_lcp2_imbalance(int pnn)
310 struct ctdb_public_ip_list *l;
313 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
315 l = read_ctdb_public_ip_list(tmp_ctx);
317 imbalance = lcp2_imbalance(l, pnn);
318 printf ("%lu\n", (unsigned long) imbalance);
320 talloc_free(tmp_ctx);
323 static uint32_t *get_tunable_values(TALLOC_CTX *tmp_ctx,
329 uint32_t *tvals = talloc_zero_array(tmp_ctx, uint32_t, numnodes);
330 char *t = getenv(tunable);
333 if (strcmp(t, "1") == 0) {
334 for (i=0; i<numnodes; i++) {
338 tok = strtok(t, ",");
340 while (tok != NULL) {
342 (uint32_t) strtol(tok, NULL, 0);
344 tok = strtok(NULL, ",");
347 fprintf(stderr, "ERROR: Wrong number of values in %s\n", tunable);
356 void ctdb_test_init(const char nodestates[],
357 struct ctdb_context **ctdb,
358 struct ctdb_public_ip_list **all_ips,
359 struct ctdb_node_map **nodemap)
361 struct ctdb_all_public_ips **avail;
363 uint32_t nodeflags[CTDB_TEST_MAX_NODES];
365 uint32_t *tval_noiptakeover;
367 *ctdb = talloc_zero(NULL, struct ctdb_context);
369 /* Avoid that const */
370 ns = talloc_strdup(*ctdb, nodestates);
373 tok = strtok(ns, ",");
374 while (tok != NULL) {
375 nodeflags[numnodes] = (uint32_t) strtol(tok, NULL, 0);
377 tok = strtok(NULL, ",");
380 /* Fake things up... */
381 (*ctdb)->num_nodes = numnodes;
383 /* Default to LCP2 */
384 (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
385 (*ctdb)->tunable.deterministic_public_ips = 0;
386 (*ctdb)->tunable.disable_ip_failover = 0;
387 (*ctdb)->tunable.no_ip_failback = 0;
389 if ((t = getenv("CTDB_IP_ALGORITHM"))) {
390 if (strcmp(t, "lcp2") == 0) {
391 (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
392 } else if (strcmp(t, "nondet") == 0) {
393 (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
394 } else if (strcmp(t, "det") == 0) {
395 (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
396 (*ctdb)->tunable.deterministic_public_ips = 1;
398 fprintf(stderr, "ERROR: unknown IP algorithm %s\n", t);
403 (*ctdb)->tunable.no_ip_takeover_on_disabled = 0;
404 if (getenv("CTDB_SET_NoIPTakeoverOnDisabled")) {
405 (*ctdb)->tunable.no_ip_takeover_on_disabled = (uint32_t) strtoul(getenv("CTDB_SET_NoIPTakeoverOnDisabled"), NULL, 0);
408 tval_noiptakeover = get_tunable_values(*ctdb, numnodes,
409 "CTDB_SET_NoIPTakeover");
411 *nodemap = talloc_array(*ctdb, struct ctdb_node_map, numnodes);
412 (*nodemap)->num = numnodes;
414 read_ctdb_public_ip_info(*ctdb, numnodes, all_ips, &avail);
416 (*ctdb)->nodes = talloc_array(*ctdb, struct ctdb_node *, numnodes); // FIXME: bogus size, overkill
418 for (i=0; i < numnodes; i++) {
419 (*nodemap)->nodes[i].pnn = i;
420 (*nodemap)->nodes[i].flags = nodeflags[i];
421 /* nodemap->nodes[i].sockaddr is uninitialised */
423 (*ctdb)->nodes[i] = talloc(*ctdb, struct ctdb_node);
424 (*ctdb)->nodes[i]->pnn = i;
425 (*ctdb)->nodes[i]->flags = nodeflags[i];
426 (*ctdb)->nodes[i]->available_public_ips = avail[i];
427 (*ctdb)->nodes[i]->known_public_ips = avail[i];
430 set_ipflags_internal(*nodemap, tval_noiptakeover);
433 /* IP layout is read from stdin. */
434 void ctdb_test_lcp2_allocate_unassigned(const char nodestates[])
436 struct ctdb_context *ctdb;
437 struct ctdb_public_ip_list *all_ips;
438 struct ctdb_node_map *nodemap;
440 uint32_t *lcp2_imbalances;
443 ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
445 lcp2_init(ctdb, nodemap,
446 NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
447 all_ips, &lcp2_imbalances, &newly_healthy);
449 lcp2_allocate_unassigned(ctdb, nodemap,
450 NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
451 all_ips, lcp2_imbalances);
453 print_ctdb_public_ip_list(all_ips);
458 /* IP layout is read from stdin. */
459 void ctdb_test_lcp2_failback(const char nodestates[])
461 struct ctdb_context *ctdb;
462 struct ctdb_public_ip_list *all_ips;
463 struct ctdb_node_map *nodemap;
465 uint32_t *lcp2_imbalances;
468 ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
470 lcp2_init(ctdb, nodemap,
471 NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
472 all_ips, &lcp2_imbalances, &newly_healthy);
474 lcp2_failback(ctdb, nodemap,
475 NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
476 all_ips, lcp2_imbalances, newly_healthy);
478 print_ctdb_public_ip_list(all_ips);
483 /* IP layout is read from stdin. */
484 void ctdb_test_lcp2_failback_loop(const char nodestates[])
486 struct ctdb_context *ctdb;
487 struct ctdb_public_ip_list *all_ips;
488 struct ctdb_node_map *nodemap;
490 uint32_t *lcp2_imbalances;
493 ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
495 lcp2_init(ctdb, nodemap,
496 NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
497 all_ips, &lcp2_imbalances, &newly_healthy);
499 lcp2_failback(ctdb, nodemap,
500 NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
501 all_ips, lcp2_imbalances, newly_healthy);
503 print_ctdb_public_ip_list(all_ips);
508 /* IP layout is read from stdin. */
509 void ctdb_test_ctdb_takeover_run_core(const char nodestates[])
511 struct ctdb_context *ctdb;
512 struct ctdb_public_ip_list *all_ips;
513 struct ctdb_node_map *nodemap;
515 ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
517 ctdb_takeover_run_core(ctdb, nodemap, &all_ips);
519 print_ctdb_public_ip_list(all_ips);
526 fprintf(stderr, "usage: ctdb_takeover_tests <op>\n");
530 int main(int argc, const char *argv[])
532 LogLevel = DEBUG_DEBUG;
533 if (getenv("CTDB_TEST_LOGLEVEL")) {
534 LogLevel = atoi(getenv("CTDB_TEST_LOGLEVEL"));
541 if (strcmp(argv[1], "ip_list") == 0) {
542 ctdb_test_read_ctdb_public_ip_list();
543 } else if (argc == 3 && strcmp(argv[1], "ip_info") == 0) {
544 ctdb_test_read_ctdb_public_ip_info(argv[2]);
545 } else if (strcmp(argv[1], "ip_distance") == 0) {
546 ctdb_test_ip_distance();
547 } else if (argc == 4 && strcmp(argv[1], "ip_distance_2_sum") == 0) {
548 ctdb_test_ip_distance_2_sum(argv[2], atoi(argv[3]));
549 } else if (argc >= 3 && strcmp(argv[1], "lcp2_imbalance") == 0) {
550 ctdb_test_lcp2_imbalance(atoi(argv[2]));
551 } else if (argc == 3 && strcmp(argv[1], "lcp2_allocate_unassigned") == 0) {
552 ctdb_test_lcp2_allocate_unassigned(argv[2]);
553 } else if (argc == 3 && strcmp(argv[1], "lcp2_failback") == 0) {
554 ctdb_test_lcp2_failback(argv[2]);
555 } else if (argc == 3 && strcmp(argv[1], "lcp2_failback_loop") == 0) {
556 ctdb_test_lcp2_failback_loop(argv[2]);
557 } else if (argc == 3 && strcmp(argv[1], "ctdb_takeover_run_core") == 0) {
558 ctdb_test_ctdb_takeover_run_core(argv[2]);