ctdb-ipalloc: ctdb_takeover_run_core() takes ipalloc_state
[obnox/samba/samba-obnox.git] / ctdb / tests / src / ctdb_takeover_tests.c
1 /* 
2    Tests for ctdb_takeover.c
3
4    Copyright (C) Martin Schwenke 2011
5
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.
10    
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.
15    
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/>.
18 */
19
20 #include "ctdbd_test.c"
21
22 /* This is lazy... but it is test code! */
23 #define CTDB_TEST_MAX_NODES 256
24 #define CTDB_TEST_MAX_IPS 1024
25
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!).
28  */
29 static struct public_ip_list *
30 read_ctdb_public_ip_list(TALLOC_CTX *ctx)
31 {
32         char line[1024];
33         ctdb_sock_addr addr;
34         char *t;
35         int pnn;
36         struct public_ip_list *last = NULL;
37
38         struct public_ip_list *ret = NULL;
39
40         while (fgets(line, sizeof(line), stdin) != NULL) {
41                 
42                 if ((t = strchr(line, ' ')) != NULL) {
43                         /* Make line contain just the address */
44                         *t = '\0';
45                         /* Point to PNN or leading whitespace...  */
46                         t++;
47                         pnn = (int) strtol(t, (char **) NULL, 10);
48                 } else {
49                         /* Assume just an IP address, default to PNN -1 */
50                         if ((t = strchr(line, '\n')) != NULL) {
51                                 *t = '\0';
52                         }
53                         pnn = -1;
54                 }
55                
56                 if (parse_ip(line, NULL, 0, &addr)) {
57                         if (last == NULL) {
58                                 last = talloc(ctx, struct public_ip_list);
59                         } else {
60                                 last->next = talloc(ctx, struct public_ip_list);
61                                 last = last->next;
62                         }
63                         last->next = NULL;
64                         last->pnn = pnn;
65                         memcpy(&(last->addr), &addr, sizeof(addr));
66                         if (ret == NULL) {
67                                 ret = last;
68                         }
69                 } else {
70                         DEBUG(DEBUG_ERR, (__location__ " ERROR, bad address :%s\n", line));
71                 }
72         }
73                         
74         return ret;
75 }
76
77 static void print_ctdb_public_ip_list(struct public_ip_list * ips)
78 {
79         while (ips) {
80                 printf("%s %d\n", ctdb_addr_to_str(&(ips->addr)), ips->pnn);
81                 ips = ips->next;
82         }
83 }
84
85 /* Read some IPs from stdin, 1 per line, parse them and then print
86  * them back out. */
87 static void ctdb_test_read_ctdb_public_ip_list(void)
88 {
89         struct public_ip_list *l;
90
91         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
92
93         l = read_ctdb_public_ip_list(tmp_ctx);
94
95         print_ctdb_public_ip_list(l);
96
97         talloc_free(tmp_ctx);
98 }
99
100 static uint32_t *get_tunable_values(TALLOC_CTX *tmp_ctx,
101                                     int numnodes,
102                                     const char *tunable);
103 static enum ctdb_runstate *get_runstate(TALLOC_CTX *tmp_ctx,
104                                         int numnodes);
105
106 /* Format of each line is "IP CURRENT_PNN ALLOWED_PNN,...".
107  */
108 static bool
109 read_ctdb_public_ip_info(TALLOC_CTX *ctx  ,
110                          int numnodes,
111                          struct public_ip_list ** all_ips,
112                          struct ctdb_public_ip_list_old *** known,
113                          struct ctdb_public_ip_list_old *** avail)
114 {
115         char line[1024];
116         ctdb_sock_addr addr;
117         char *t, *tok;
118         struct public_ip_list * ta;
119         int pnn, numips, curr, n, i;
120         struct ctdb_public_ip_list_old * a;
121
122         struct public_ip_list *last = NULL;
123         enum ctdb_runstate *runstate;
124
125         runstate = get_runstate(ctx, numnodes);
126
127         *known = talloc_array_size(ctx, sizeof(struct ctdb_public_ip_list_old *), CTDB_TEST_MAX_NODES);
128         memset(*known, 0,
129                sizeof(struct ctdb_public_ip_list_old *) * CTDB_TEST_MAX_NODES);
130
131         *avail = talloc_array_size(ctx, sizeof(struct ctdb_public_ip_list_old *),
132                                    CTDB_TEST_MAX_NODES);
133         memset(*avail, 0,
134                sizeof(struct ctdb_public_ip_list_old *) * CTDB_TEST_MAX_NODES);
135
136         numips = 0;
137         *all_ips = NULL;
138         while (fgets(line, sizeof(line), stdin) != NULL) {
139
140                 /* Get rid of pesky newline */
141                 if ((t = strchr(line, '\n')) != NULL) {
142                         *t = '\0';
143                 }
144
145                 /* Exit on an empty line */
146                 if (line[0] == '\0') {
147                         break;
148                 }
149
150                 /* Get the IP address */
151                 tok = strtok(line, " \t");
152                 if (tok == NULL) {
153                         DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line ignored :%s\n", line));
154                         continue;
155                 }
156
157                 if (!parse_ip(tok, NULL, 0, &addr)) {
158                         DEBUG(DEBUG_ERR, (__location__ " ERROR, bad address :%s\n", tok));
159                         continue;
160                 }
161
162                 numips++;
163                 if (numips > CTDB_TEST_MAX_IPS) {
164                         DEBUG(DEBUG_ERR, ("ERROR: Exceeding CTDB_TEST_MAX_IPS: %d\n", CTDB_TEST_MAX_IPS));
165                         exit(1);
166                 }
167
168                 /* Get the PNN */
169                 pnn = -1;
170                 tok = strtok(NULL, " \t");
171                 if (tok != NULL) {
172                         pnn = (int) strtol(tok, (char **) NULL, 10);
173                 }
174
175                 /* Add address + pnn to all_ips */
176                 if (last == NULL) {
177                         last = talloc(ctx, struct public_ip_list);
178                 } else {
179                         last->next = talloc(ctx, struct public_ip_list);
180                         last = last->next;
181                 }
182                 last->next = NULL;
183                 last->pnn = pnn;
184                 memcpy(&(last->addr), &addr, sizeof(addr));
185                 if (*all_ips == NULL) {
186                         *all_ips = last;
187                 }
188
189                 tok = strtok(NULL, " \t#");
190                 if (tok == NULL) {
191                         continue;
192                 }
193
194                 /* Handle allowed nodes for addr */
195                 t = strtok(tok, ",");
196                 while (t != NULL) {
197                         n = (int) strtol(t, (char **) NULL, 10);
198                         if ((*known)[n] == NULL) {
199                                 (*known)[n] = talloc_array(ctx, struct ctdb_public_ip_list_old, CTDB_TEST_MAX_IPS);
200                                 (*known)[n]->num = 0;
201                         }
202                         curr = (*known)[n]->num;
203                         (*known)[n]->ips[curr].pnn = pnn;
204                         memcpy(&((*known)[n]->ips[curr].addr),
205                                &addr, sizeof(addr));
206                         (*known)[n]->num++;
207                         t = strtok(NULL, ",");
208                 }
209
210         }
211
212         /* Build list of all allowed IPs */
213         a = talloc_array(ctx, struct ctdb_public_ip_list_old, CTDB_TEST_MAX_IPS);
214         a->num = numips;
215         for (ta = *all_ips, i=0; ta != NULL && i < numips ; ta = ta->next, i++) {
216                 a->ips[i].pnn = ta->pnn;
217                 memcpy(&(a->ips[i].addr), &(ta->addr), sizeof(ta->addr));
218         }
219
220         /* Assign it to any nodes that don't have a list assigned */
221         for (n = 0; n < numnodes; n++) {
222                 if ((*known)[n] == NULL) {
223                         (*known)[n] = a;
224                 }
225                 if (runstate[n] == CTDB_RUNSTATE_RUNNING) {
226                         (*avail)[n] = (*known)[n];
227                 }
228         }
229
230         return true;
231 }
232
233 static void print_ctdb_available_ips(int numnodes,
234                                      struct ctdb_public_ip_list_old **avail)
235 {
236         int n, i;
237
238         for (n = 0; n < numnodes; n++) {
239                 if ((avail[n] != NULL) && (avail[n]->num > 0)) {
240                         printf("%d:", n);
241                         for (i = 0; i < avail[n]->num; i++) {
242                                 printf("%s%s",
243                                        (i == 0) ? " " : ", ",
244                                        ctdb_addr_to_str(&(avail[n]->ips[i].addr)));
245                         }
246                         printf("\n");
247                 }
248         }
249 }
250
251 static void ctdb_test_read_ctdb_public_ip_info(const char nodestates[])
252 {
253         int numnodes;
254         struct public_ip_list *l;
255         struct ctdb_public_ip_list_old **known;
256         struct ctdb_public_ip_list_old **avail;
257         char *tok, *ns;
258
259         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
260
261         /* Avoid that const */
262         ns = talloc_strdup(tmp_ctx, nodestates);
263
264         numnodes = 0;
265         tok = strtok(ns, ",");
266         while (tok != NULL) {
267                 numnodes++;
268                 if (numnodes > CTDB_TEST_MAX_NODES) {
269                         DEBUG(DEBUG_ERR, ("ERROR: Exceeding CTDB_TEST_MAX_NODES: %d\n", CTDB_TEST_MAX_NODES));
270                         exit(1);
271                 }
272                 tok = strtok(NULL, ",");
273         }
274         
275         read_ctdb_public_ip_info(tmp_ctx, numnodes, &l, &known, &avail);
276
277         print_ctdb_public_ip_list(l);
278         print_ctdb_available_ips(numnodes, avail);
279
280         talloc_free(tmp_ctx);
281 }
282
283 /* Read 2 IPs from stdin, calculate the IP distance and print it. */
284 static void ctdb_test_ip_distance(void)
285 {
286         struct public_ip_list *l;
287         uint32_t distance;
288
289         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
290
291         l = read_ctdb_public_ip_list(tmp_ctx);
292
293         if (l && l->next) {
294                 distance = ip_distance(&(l->addr), &(l->next->addr));
295                 printf ("%lu\n", (unsigned long) distance);
296         }
297
298         talloc_free(tmp_ctx);
299 }
300
301 /* Read some IPs from stdin, calculate the sum of the squares of the
302  * IP distances between the 1st argument and those read that are on
303  * the given node. The given IP must one of the ones in the list.  */
304 static void ctdb_test_ip_distance_2_sum(const char ip[], int pnn)
305 {
306         struct public_ip_list *l;
307         struct public_ip_list *t;
308         ctdb_sock_addr addr;
309         uint32_t distance;
310
311         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
312
313         
314         l = read_ctdb_public_ip_list(tmp_ctx);
315
316         if (l && parse_ip(ip, NULL, 0, &addr)) {
317                 /* find the entry for the specified IP */
318                 for (t=l; t!=NULL; t=t->next) {
319                         if (ctdb_same_ip(&(t->addr), &addr)) {
320                                 break;
321                         }
322                 }
323
324                 if (t == NULL) {
325                         fprintf(stderr, "IP NOT PRESENT IN LIST");
326                         exit(1);
327                 }
328
329                 distance = ip_distance_2_sum(&(t->addr), l, pnn);
330                 printf ("%lu\n", (unsigned long) distance);
331         } else {
332                 fprintf(stderr, "BAD INPUT");
333                 exit(1);
334         }
335
336         talloc_free(tmp_ctx);
337 }
338
339 /* Read some IPs from stdin, calculate the sume of the squares of the
340  * IP distances between the first and the rest, and print it. */
341 static void ctdb_test_lcp2_imbalance(int pnn)
342 {
343         struct public_ip_list *l;
344         uint32_t imbalance;
345
346         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
347
348         l = read_ctdb_public_ip_list(tmp_ctx);
349
350         imbalance = lcp2_imbalance(l, pnn);
351         printf ("%lu\n", (unsigned long) imbalance);
352
353         talloc_free(tmp_ctx);
354 }
355
356 static uint32_t *get_tunable_values(TALLOC_CTX *tmp_ctx,
357                                     int numnodes,
358                                     const char *tunable)
359 {
360         int i;
361         char *tok;
362         uint32_t *tvals = talloc_zero_array(tmp_ctx, uint32_t, numnodes);
363         char *t = getenv(tunable);
364
365         if (t) {
366                 if (strcmp(t, "1") == 0) {
367                         for (i=0; i<numnodes; i++) {
368                                 tvals[i] = 1;
369                         }
370                 } else {
371                         tok = strtok(t, ",");
372                         i = 0;
373                         while (tok != NULL) {
374                                 tvals[i] =
375                                         (uint32_t) strtol(tok, NULL, 0);
376                                 i++;
377                                 tok = strtok(NULL, ",");
378                         }
379                         if (i != numnodes) {
380                                 fprintf(stderr, "ERROR: Wrong number of values in %s\n", tunable);
381                                 exit(1);
382                         }
383                 }
384         }
385
386         return tvals;
387 }
388
389 static enum ctdb_runstate *get_runstate(TALLOC_CTX *tmp_ctx,
390                                         int numnodes)
391 {
392         int i;
393         uint32_t *tvals;
394         enum ctdb_runstate *runstate =
395                 talloc_zero_array(tmp_ctx, enum ctdb_runstate, numnodes);
396         char *t = getenv("CTDB_TEST_RUNSTATE");
397
398         if (t == NULL) {
399                 for (i=0; i<numnodes; i++) {
400                         runstate[i] = CTDB_RUNSTATE_RUNNING;
401                 }
402         } else {
403                 tvals = get_tunable_values(tmp_ctx, numnodes, "CTDB_TEST_RUNSTATE");
404                 for (i=0; i<numnodes; i++) {
405                         runstate[i] = (enum ctdb_runstate) tvals[i];
406                 }
407                 talloc_free(tvals);
408         }
409
410         return runstate;
411 }
412
413 /* Fake up enough CTDB state to be able to run the IP allocation
414  * algorithm.  Usually this sets up some standard state, sets the node
415  * states from the command-line and reads the current IP layout from
416  * stdin.
417  *
418  * However, if read_ips_for_multiple_nodes is true then each node's
419  * idea of the IP layout is read separately from stdin.  In this mode
420  * is doesn't make much sense to use read_ctdb_public_ip_info's
421  * optional ALLOWED_PNN,... list in the input, since each node is
422  * being handled separately anyway.  IPs for each node are separated
423  * by a blank line.  This mode is for testing weird behaviours where
424  * the IP layouts differs across nodes and we want to improve
425  * create_merged_ip_list(), so should only be used in tests of
426  * ctdb_takeover_run_core().  Yes, it is a hack...  :-)
427  */
428 static void ctdb_test_init(const char nodestates[],
429                            struct ctdb_context **ctdb,
430                            struct public_ip_list **all_ips,
431                            struct ipalloc_state **ipalloc_state,
432                            struct ctdb_ipflags **ipflags,
433                            bool read_ips_for_multiple_nodes)
434 {
435         struct ctdb_public_ip_list_old **known;
436         struct ctdb_public_ip_list_old **avail;
437         int i, numnodes;
438         uint32_t nodeflags[CTDB_TEST_MAX_NODES];
439         char *tok, *ns, *t;
440         struct ctdb_node_map_old *nodemap;
441         uint32_t *tval_noiptakeover;
442         uint32_t *tval_noiptakeoverondisabled;
443
444         *ctdb = talloc_zero(NULL, struct ctdb_context);
445
446         /* Avoid that const */
447         ns = talloc_strdup(*ctdb, nodestates);
448
449         numnodes = 0;
450         tok = strtok(ns, ",");
451         while (tok != NULL) {
452                 nodeflags[numnodes] = (uint32_t) strtol(tok, NULL, 0);
453                 numnodes++;
454                 if (numnodes >= CTDB_TEST_MAX_NODES) {
455                         DEBUG(DEBUG_ERR, ("ERROR: Exceeding CTDB_TEST_MAX_NODES: %d\n", CTDB_TEST_MAX_NODES));
456                         exit(1);
457                 }
458                 tok = strtok(NULL, ",");
459         }
460         
461         /* Fake things up... */
462         (*ctdb)->num_nodes = numnodes;
463
464         /* Default to LCP2 */
465         (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
466         (*ctdb)->tunable.deterministic_public_ips = 0;
467         (*ctdb)->tunable.disable_ip_failover = 0;
468         (*ctdb)->tunable.no_ip_failback = 0;
469
470         if ((t = getenv("CTDB_IP_ALGORITHM"))) {
471                 if (strcmp(t, "lcp2") == 0) {
472                         (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
473                 } else if (strcmp(t, "nondet") == 0) {
474                         (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
475                 } else if (strcmp(t, "det") == 0) {
476                         (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
477                         (*ctdb)->tunable.deterministic_public_ips = 1;
478                 } else {
479                         fprintf(stderr, "ERROR: unknown IP algorithm %s\n", t);
480                         exit(1);
481                 }
482         }
483
484         tval_noiptakeover = get_tunable_values(*ctdb, numnodes,
485                                                "CTDB_SET_NoIPTakeover");
486         tval_noiptakeoverondisabled =
487                 get_tunable_values(*ctdb, numnodes,
488                                    "CTDB_SET_NoIPHostOnAllDisabled");
489
490         nodemap =  talloc_array(*ctdb, struct ctdb_node_map_old, numnodes);
491         nodemap->num = numnodes;
492
493         if (!read_ips_for_multiple_nodes) {
494                 read_ctdb_public_ip_info(*ctdb, numnodes, all_ips,
495                                          &known, &avail);
496         }
497
498         (*ctdb)->nodes = talloc_array(*ctdb, struct ctdb_node *, numnodes); // FIXME: bogus size, overkill
499
500         *ipalloc_state = ipalloc_state_init(*ctdb, *ctdb);
501
502         for (i=0; i < numnodes; i++) {
503                 nodemap->nodes[i].pnn = i;
504                 nodemap->nodes[i].flags = nodeflags[i];
505                 /* nodemap->nodes[i].sockaddr is uninitialised */
506
507                 if (read_ips_for_multiple_nodes) {
508                         read_ctdb_public_ip_info(*ctdb, numnodes,
509                                                  all_ips, &known, &avail);
510                 }
511
512                 (*ctdb)->nodes[i] = talloc(*ctdb, struct ctdb_node);
513                 (*ctdb)->nodes[i]->pnn = i;
514                 (*ctdb)->nodes[i]->flags = nodeflags[i];
515
516                 (*ipalloc_state)->available_public_ips[i] = avail[i];
517                 (*ipalloc_state)->known_public_ips[i] = known[i];
518         }
519
520         *ipflags = set_ipflags_internal(*ctdb, *ctdb, nodemap,
521                                         tval_noiptakeover,
522                                         tval_noiptakeoverondisabled);
523 }
524
525 /* IP layout is read from stdin. */
526 static void ctdb_test_lcp2_allocate_unassigned(const char nodestates[])
527 {
528         struct ctdb_context *ctdb;
529         struct public_ip_list *all_ips;
530         struct ipalloc_state *ipalloc_state;
531         struct ctdb_ipflags *ipflags;
532
533         uint32_t *lcp2_imbalances;
534         bool *newly_healthy;
535
536         ctdb_test_init(nodestates, &ctdb, &all_ips, &ipalloc_state, &ipflags,
537                        false);
538
539         lcp2_init(ipalloc_state, ipflags, all_ips, NULL,
540                   &lcp2_imbalances, &newly_healthy);
541
542         lcp2_allocate_unassigned(ipalloc_state, ipflags,
543                                  all_ips, lcp2_imbalances);
544
545         print_ctdb_public_ip_list(all_ips);
546
547         talloc_free(ctdb);
548 }
549
550 /* IP layout is read from stdin. */
551 static void ctdb_test_lcp2_failback(const char nodestates[])
552 {
553         struct ctdb_context *ctdb;
554         struct public_ip_list *all_ips;
555         struct ipalloc_state *ipalloc_state;
556         struct ctdb_ipflags *ipflags;
557
558         uint32_t *lcp2_imbalances;
559         bool *newly_healthy;
560
561         ctdb_test_init(nodestates, &ctdb, &all_ips, &ipalloc_state, &ipflags,
562                        false);
563
564         lcp2_init(ipalloc_state, ipflags, all_ips, NULL,
565                   &lcp2_imbalances, &newly_healthy);
566
567         lcp2_failback(ipalloc_state, ipflags,
568                       all_ips, lcp2_imbalances, newly_healthy);
569
570         print_ctdb_public_ip_list(all_ips);
571
572         talloc_free(ctdb);
573 }
574
575 /* IP layout is read from stdin. */
576 static void ctdb_test_lcp2_failback_loop(const char nodestates[])
577 {
578         struct ctdb_context *ctdb;
579         struct public_ip_list *all_ips;
580         struct ipalloc_state *ipalloc_state;
581         struct ctdb_ipflags *ipflags;
582
583         uint32_t *lcp2_imbalances;
584         bool *newly_healthy;
585
586         ctdb_test_init(nodestates, &ctdb, &all_ips, &ipalloc_state, &ipflags,
587                        false);
588
589         lcp2_init(ipalloc_state, ipflags, all_ips, NULL,
590                   &lcp2_imbalances, &newly_healthy);
591
592         lcp2_failback(ipalloc_state, ipflags,
593                       all_ips, lcp2_imbalances, newly_healthy);
594
595         print_ctdb_public_ip_list(all_ips);
596
597         talloc_free(ctdb);
598 }
599
600 /* IP layout is read from stdin.  See comment for ctdb_test_init() for
601  * explanation of read_ips_for_multiple_nodes.
602  */
603 static void ctdb_test_ctdb_takeover_run_core(const char nodestates[],
604                                              bool read_ips_for_multiple_nodes)
605 {
606         struct ctdb_context *ctdb;
607         struct public_ip_list *all_ips;
608         struct ipalloc_state *ipalloc_state;
609         struct ctdb_ipflags *ipflags;
610
611         ctdb_test_init(nodestates, &ctdb, &all_ips, &ipalloc_state, &ipflags,
612                        read_ips_for_multiple_nodes);
613
614         all_ips = create_merged_ip_list(ctdb, ipalloc_state);
615
616         ctdb_takeover_run_core(ipalloc_state, ipflags, all_ips, NULL);
617
618         print_ctdb_public_ip_list(all_ips);
619
620         talloc_free(ctdb);
621 }
622
623 static void usage(void)
624 {
625         fprintf(stderr, "usage: ctdb_takeover_tests <op>\n");
626         exit(1);
627 }
628
629 int main(int argc, const char *argv[])
630 {
631         DEBUGLEVEL = DEBUG_DEBUG;
632         if (getenv("CTDB_TEST_LOGLEVEL")) {
633                 DEBUGLEVEL = atoi(getenv("CTDB_TEST_LOGLEVEL"));
634         }
635
636         if (argc < 2) {
637                 usage();
638         }
639
640         if (strcmp(argv[1], "ip_list") == 0) {
641                 ctdb_test_read_ctdb_public_ip_list();
642         } else if (argc == 3 && strcmp(argv[1], "ip_info") == 0) {
643                 ctdb_test_read_ctdb_public_ip_info(argv[2]);
644         } else if (strcmp(argv[1], "ip_distance") == 0) {
645                 ctdb_test_ip_distance();
646         } else if (argc == 4 && strcmp(argv[1], "ip_distance_2_sum") == 0) {
647                 ctdb_test_ip_distance_2_sum(argv[2], atoi(argv[3]));
648         } else if (argc >= 3 && strcmp(argv[1], "lcp2_imbalance") == 0) {
649                 ctdb_test_lcp2_imbalance(atoi(argv[2]));
650         } else if (argc == 3 && strcmp(argv[1], "lcp2_allocate_unassigned") == 0) {
651                 ctdb_test_lcp2_allocate_unassigned(argv[2]);
652         } else if (argc == 3 && strcmp(argv[1], "lcp2_failback") == 0) {
653                 ctdb_test_lcp2_failback(argv[2]);
654         } else if (argc == 3 && strcmp(argv[1], "lcp2_failback_loop") == 0) {
655                 ctdb_test_lcp2_failback_loop(argv[2]);
656         } else if (argc == 3 &&
657                    strcmp(argv[1], "ctdb_takeover_run_core") == 0) {
658                 ctdb_test_ctdb_takeover_run_core(argv[2], false);
659         } else if (argc == 4 &&
660                    strcmp(argv[1], "ctdb_takeover_run_core") == 0 &&
661                    strcmp(argv[3], "multi") == 0) {
662                 ctdb_test_ctdb_takeover_run_core(argv[2], true);
663         } else {
664                 usage();
665         }
666
667         return 0;
668 }