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/>.
21 #include "../include/ctdb_private.h"
23 /* This is lazy... but it is test code! */
24 #define CTDB_TEST_MAX_NODES 256
25 #define CTDB_TEST_MAX_IPS 256
28 * Need these, since they're defined in ctdbd.c but we can't link
33 void ctdb_load_nodes_file(struct ctdb_context *ctdb) {}
35 /* Format of each line is "IP pnn" - the separator has to be at least
36 * 1 space (not a tab or whatever - a space!).
38 static struct ctdb_public_ip_list *
39 read_ctdb_public_ip_list(TALLOC_CTX *ctx)
45 struct ctdb_public_ip_list *last = NULL;
47 struct ctdb_public_ip_list *ret = NULL;
49 while (fgets(line, sizeof(line), stdin) != NULL) {
51 if ((t = strchr(line, ' ')) != NULL) {
52 /* Make line contain just the address */
54 /* Point to PNN or leading whitespace... */
56 pnn = (int) strtol(t, (char **) NULL, 10);
58 /* Assume just an IP address, default to PNN -1 */
59 if ((t = strchr(line, '\n')) != NULL) {
65 if (parse_ip(line, NULL, 0, &addr)) {
67 last = talloc(ctx, struct ctdb_public_ip_list);
69 last->next = talloc(ctx, struct ctdb_public_ip_list);
74 memcpy(&(last->addr), &addr, sizeof(addr));
79 DEBUG(DEBUG_ERR, (__location__ " ERROR, bad address :%s\n", line));
86 void print_ctdb_public_ip_list(struct ctdb_public_ip_list * ips)
89 printf("%s %d\n", ctdb_addr_to_str(&(ips->addr)), ips->pnn);
94 /* Read some IPs from stdin, 1 per line, parse them and then print
96 void ctdb_test_read_ctdb_public_ip_list(void)
98 struct ctdb_public_ip_list *l;
100 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
102 l = read_ctdb_public_ip_list(tmp_ctx);
104 print_ctdb_public_ip_list(l);
106 talloc_free(tmp_ctx);
109 /* Format of each line is "IP pnn" - the separator has to be at least
110 * 1 space (not a tab or whatever - a space!).
113 read_ctdb_public_ip_info(TALLOC_CTX *ctx,
115 struct ctdb_public_ip_list ** all_ips,
116 struct ctdb_all_public_ips *** avail)
121 struct ctdb_public_ip_list * ta;
122 int pnn, numips, curr, n, i;
123 struct ctdb_all_public_ips * a;
125 struct ctdb_public_ip_list *last = NULL;
127 *avail = talloc_array_size(ctx, sizeof(struct ctdb_all_public_ips *), CTDB_TEST_MAX_NODES);
129 sizeof(struct ctdb_all_public_ips *) * CTDB_TEST_MAX_NODES);
133 while (fgets(line, sizeof(line), stdin) != NULL) {
135 /* Get rid of pesky newline */
136 if ((t = strchr(line, '\n')) != NULL) {
140 /* Get the IP address */
141 tok = strtok(line, " \t");
143 DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line ignored :%s\n", line));
147 if (!parse_ip(tok, NULL, 0, &addr)) {
148 DEBUG(DEBUG_ERR, (__location__ " ERROR, bad address :%s\n", tok));
156 tok = strtok(NULL, " \t");
158 pnn = (int) strtol(tok, (char **) NULL, 10);
161 /* Add address + pnn to all_ips */
163 last = talloc(ctx, struct ctdb_public_ip_list);
165 last->next = talloc(ctx, struct ctdb_public_ip_list);
170 memcpy(&(last->addr), &addr, sizeof(addr));
171 if (*all_ips == NULL) {
175 tok = strtok(NULL, " \t#");
180 /* Handle allowed nodes for addr */
181 t = strtok(tok, ",");
183 n = (int) strtol(t, (char **) NULL, 10);
184 if ((*avail)[n] == NULL) {
185 (*avail)[n] = talloc_array(ctx, struct ctdb_all_public_ips, CTDB_TEST_MAX_IPS);
186 (*avail)[n]->num = 0;
188 curr = (*avail)[n]->num;
189 (*avail)[n]->ips[curr].pnn = pnn;
190 memcpy(&((*avail)[n]->ips[curr].addr),
191 &addr, sizeof(addr));
193 t = strtok(NULL, ",");
198 /* Build list of all allowed IPs */
199 a = talloc_array(ctx, struct ctdb_all_public_ips, CTDB_TEST_MAX_IPS);
201 for (ta = *all_ips, i=0; ta != NULL && i < numips ; ta = ta->next, i++) {
202 a->ips[i].pnn = ta->pnn;
203 memcpy(&(a->ips[i].addr), &(ta->addr), sizeof(ta->addr));
206 /* Assign it to any nodes that don't have a list assigned */
207 for (n = 0; n < numnodes; n++) {
208 if ((*avail)[n] == NULL) {
216 void print_ctdb_available_ips(int numnodes, struct ctdb_all_public_ips **avail)
220 for (n = 0; n < numnodes; n++) {
221 if ((avail[n] != NULL) && (avail[n]->num > 0)) {
223 for (i = 0; i < avail[n]->num; i++) {
225 (i == 0) ? " " : ", ",
226 ctdb_addr_to_str(&(avail[n]->ips[i].addr)));
233 void ctdb_test_read_ctdb_public_ip_info(const char nodestates[])
236 struct ctdb_public_ip_list *l;
237 struct ctdb_all_public_ips **avail;
240 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
242 /* Avoid that const */
243 ns = talloc_strdup(tmp_ctx, nodestates);
246 tok = strtok(ns, ",");
247 while (tok != NULL) {
249 tok = strtok(NULL, ",");
252 read_ctdb_public_ip_info(tmp_ctx, numnodes, &l, &avail);
254 print_ctdb_public_ip_list(l);
255 print_ctdb_available_ips(numnodes, avail);
257 talloc_free(tmp_ctx);
260 /* Read 2 IPs from stdin, calculate the IP distance and print it. */
261 void ctdb_test_ip_distance(void)
263 struct ctdb_public_ip_list *l;
266 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
268 l = read_ctdb_public_ip_list(tmp_ctx);
271 distance = ip_distance(&(l->addr), &(l->next->addr));
272 printf ("%lu\n", (unsigned long) distance);
275 talloc_free(tmp_ctx);
278 /* Read some IPs from stdin, calculate the sum of the squares of the
279 * IP distances between the 1st argument and those read that are on
280 * the given node. The given IP must one of the ones in the list. */
281 void ctdb_test_ip_distance_2_sum(const char ip[], int pnn)
283 struct ctdb_public_ip_list *l;
284 struct ctdb_public_ip_list *t;
288 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
291 l = read_ctdb_public_ip_list(tmp_ctx);
293 if (l && parse_ip(ip, NULL, 0, &addr)) {
294 /* find the entry for the specified IP */
295 for (t=l; t!=NULL; t=t->next) {
296 if (ctdb_same_ip(&(t->addr), &addr)) {
302 fprintf(stderr, "IP NOT PRESENT IN LIST");
306 distance = ip_distance_2_sum(&(t->addr), l, pnn);
307 printf ("%lu\n", (unsigned long) distance);
309 fprintf(stderr, "BAD INPUT");
313 talloc_free(tmp_ctx);
316 /* Read some IPs from stdin, calculate the sume of the squares of the
317 * IP distances between the first and the rest, and print it. */
318 void ctdb_test_lcp2_imbalance(int pnn)
320 struct ctdb_public_ip_list *l;
323 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
325 l = read_ctdb_public_ip_list(tmp_ctx);
327 imbalance = lcp2_imbalance(l, pnn);
328 printf ("%lu\n", (unsigned long) imbalance);
330 talloc_free(tmp_ctx);
333 void ctdb_test_init(const char nodestates[],
334 struct ctdb_context **ctdb,
335 struct ctdb_public_ip_list **all_ips,
336 struct ctdb_node_map **nodemap)
338 struct ctdb_all_public_ips **avail;
340 uint32_t nodeflags[CTDB_TEST_MAX_NODES];
343 *ctdb = talloc_zero(NULL, struct ctdb_context);
345 /* Avoid that const */
346 ns = talloc_strdup(*ctdb, nodestates);
349 tok = strtok(ns, ",");
350 while (tok != NULL) {
351 nodeflags[numnodes] = (uint32_t) strtol(tok, NULL, 16);
353 tok = strtok(NULL, ",");
356 /* Fake things up... */
357 (*ctdb)->num_nodes = numnodes;
359 (*ctdb)->tunable.deterministic_public_ips = 0;
360 (*ctdb)->tunable.disable_ip_failover = 0;
361 (*ctdb)->tunable.no_ip_failback = 0;
363 if (getenv("CTDB_LCP2")) {
364 if (strcmp(getenv("CTDB_LCP2"), "yes") == 0) {
365 (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
367 (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
371 *nodemap = talloc_array(*ctdb, struct ctdb_node_map, numnodes);
372 (*nodemap)->num = numnodes;
374 read_ctdb_public_ip_info(*ctdb, numnodes, all_ips, &avail);
376 (*ctdb)->nodes = talloc_array(*ctdb, struct ctdb_node *, numnodes); // FIXME: bogus size, overkill
378 for (i=0; i < numnodes; i++) {
379 (*nodemap)->nodes[i].pnn = i;
380 (*nodemap)->nodes[i].flags = nodeflags[i];
381 /* nodemap->nodes[i].sockaddr is uninitialised */
383 (*ctdb)->nodes[i] = talloc(*ctdb, struct ctdb_node);
384 (*ctdb)->nodes[i]->pnn = i;
385 (*ctdb)->nodes[i]->flags = nodeflags[i];
386 (*ctdb)->nodes[i]->available_public_ips = avail[i];
387 (*ctdb)->nodes[i]->known_public_ips = avail[i];
391 /* IP layout is read from stdin. */
392 void ctdb_test_lcp2_allocate_unassigned(const char nodestates[])
394 struct ctdb_context *ctdb;
395 struct ctdb_public_ip_list *all_ips;
396 struct ctdb_node_map *nodemap;
398 uint32_t *lcp2_imbalances;
401 ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
403 lcp2_init(ctdb, nodemap,
404 NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
405 all_ips, &lcp2_imbalances, &newly_healthy);
407 lcp2_allocate_unassigned(ctdb, nodemap,
408 NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
409 all_ips, lcp2_imbalances);
411 print_ctdb_public_ip_list(all_ips);
416 /* IP layout is read from stdin. */
417 void ctdb_test_lcp2_failback(const char nodestates[])
419 struct ctdb_context *ctdb;
420 struct ctdb_public_ip_list *all_ips;
421 struct ctdb_node_map *nodemap;
423 uint32_t *lcp2_imbalances;
426 ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
428 lcp2_init(ctdb, nodemap,
429 NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
430 all_ips, &lcp2_imbalances, &newly_healthy);
432 lcp2_failback(ctdb, nodemap,
433 NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
434 all_ips, lcp2_imbalances, newly_healthy);
436 print_ctdb_public_ip_list(all_ips);
441 /* IP layout is read from stdin. */
442 void ctdb_test_lcp2_failback_loop(const char nodestates[])
444 struct ctdb_context *ctdb;
445 struct ctdb_public_ip_list *all_ips;
446 struct ctdb_node_map *nodemap;
448 uint32_t *lcp2_imbalances;
451 ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
453 lcp2_init(ctdb, nodemap,
454 NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
455 all_ips, &lcp2_imbalances, &newly_healthy);
458 if (lcp2_failback(ctdb, nodemap,
459 NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
460 all_ips, lcp2_imbalances, newly_healthy)) {
464 print_ctdb_public_ip_list(all_ips);
469 /* IP layout is read from stdin. */
470 void ctdb_test_ctdb_takeover_run_core(const char nodestates[])
472 struct ctdb_context *ctdb;
473 struct ctdb_public_ip_list *all_ips;
474 struct ctdb_node_map *nodemap;
476 ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
478 ctdb_takeover_run_core(ctdb, nodemap, &all_ips);
480 print_ctdb_public_ip_list(all_ips);
487 fprintf(stderr, "usage: ctdb_takeover_tests <op>\n");
491 int main(int argc, const char *argv[])
493 LogLevel = DEBUG_DEBUG;
494 if (getenv("CTDB_TEST_LOGLEVEL")) {
495 LogLevel = atoi(getenv("CTDB_TEST_LOGLEVEL"));
502 if (strcmp(argv[1], "ip_list") == 0) {
503 ctdb_test_read_ctdb_public_ip_list();
504 } else if (argc == 3 && strcmp(argv[1], "ip_info") == 0) {
505 ctdb_test_read_ctdb_public_ip_info(argv[2]);
506 } else if (strcmp(argv[1], "ip_distance") == 0) {
507 ctdb_test_ip_distance();
508 } else if (argc == 4 && strcmp(argv[1], "ip_distance_2_sum") == 0) {
509 ctdb_test_ip_distance_2_sum(argv[2], atoi(argv[3]));
510 } else if (argc >= 3 && strcmp(argv[1], "lcp2_imbalance") == 0) {
511 ctdb_test_lcp2_imbalance(atoi(argv[2]));
512 } else if (argc == 3 && strcmp(argv[1], "lcp2_allocate_unassigned") == 0) {
513 ctdb_test_lcp2_allocate_unassigned(argv[2]);
514 } else if (argc == 3 && strcmp(argv[1], "lcp2_failback") == 0) {
515 ctdb_test_lcp2_failback(argv[2]);
516 } else if (argc == 3 && strcmp(argv[1], "lcp2_failback_loop") == 0) {
517 ctdb_test_lcp2_failback_loop(argv[2]);
518 } else if (argc == 3 && strcmp(argv[1], "ctdb_takeover_run_core") == 0) {
519 ctdb_test_ctdb_takeover_run_core(argv[2]);