recoverd: Remove unused mask argument and initial mask calculation
[obnox/ctdb.git] / 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 256
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 ctdb_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 ctdb_public_ip_list *last = NULL;
37
38         struct ctdb_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 ctdb_public_ip_list);
59                         } else {
60                                 last->next = talloc(ctx, struct ctdb_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 void print_ctdb_public_ip_list(struct ctdb_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 void ctdb_test_read_ctdb_public_ip_list(void)
88 {
89         struct ctdb_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 /* Format of each line is "IP CURRENT_PNN ALLOWED_PNN,...".
101  */
102 static bool
103 read_ctdb_public_ip_info(TALLOC_CTX *ctx,
104                          int numnodes,
105                          struct ctdb_public_ip_list ** all_ips,
106                          struct ctdb_all_public_ips *** avail)
107 {
108         char line[1024];
109         ctdb_sock_addr addr;
110         char *t, *tok;
111         struct ctdb_public_ip_list * ta;
112         int pnn, numips, curr, n, i;
113         struct ctdb_all_public_ips * a;
114
115         struct ctdb_public_ip_list *last = NULL;
116
117         *avail = talloc_array_size(ctx, sizeof(struct ctdb_all_public_ips *), CTDB_TEST_MAX_NODES);
118         memset(*avail, 0,
119                sizeof(struct ctdb_all_public_ips *) * CTDB_TEST_MAX_NODES);
120
121         numips = 0;
122         *all_ips = NULL;
123         while (fgets(line, sizeof(line), stdin) != NULL) {
124
125                 /* Get rid of pesky newline */
126                 if ((t = strchr(line, '\n')) != NULL) {
127                         *t = '\0';
128                 }
129
130                 /* Get the IP address */
131                 tok = strtok(line, " \t");
132                 if (tok == NULL) {
133                         DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line ignored :%s\n", line));
134                         continue;
135                 }
136
137                 if (!parse_ip(tok, NULL, 0, &addr)) {
138                         DEBUG(DEBUG_ERR, (__location__ " ERROR, bad address :%s\n", tok));
139                         continue;
140                 }
141
142                 numips++;
143
144                 /* Get the PNN */
145                 pnn = -1;
146                 tok = strtok(NULL, " \t");
147                 if (tok != NULL) {
148                         pnn = (int) strtol(tok, (char **) NULL, 10);
149                 }
150
151                 /* Add address + pnn to all_ips */
152                 if (last == NULL) {
153                         last = talloc(ctx, struct ctdb_public_ip_list);
154                 } else {
155                         last->next = talloc(ctx, struct ctdb_public_ip_list);
156                         last = last->next;
157                 }
158                 last->next = NULL;
159                 last->pnn = pnn;
160                 memcpy(&(last->addr), &addr, sizeof(addr));
161                 if (*all_ips == NULL) {
162                         *all_ips = last;
163                 }
164
165                 tok = strtok(NULL, " \t#");
166                 if (tok == NULL) {
167                         continue;
168                 }
169
170                 /* Handle allowed nodes for addr */
171                 t = strtok(tok, ",");
172                 while (t != NULL) {
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;
177                         }
178                         curr = (*avail)[n]->num;
179                         (*avail)[n]->ips[curr].pnn = pnn;
180                         memcpy(&((*avail)[n]->ips[curr].addr),
181                                &addr, sizeof(addr));
182                         (*avail)[n]->num++;
183                         t = strtok(NULL, ",");
184                 }
185
186         }
187
188         /* Build list of all allowed IPs */
189         a = talloc_array(ctx, struct ctdb_all_public_ips, CTDB_TEST_MAX_IPS);
190         a->num = numips;
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));
194         }
195
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) {
199                         (*avail)[n] = a;
200                 }
201         }
202
203         return true;
204 }
205
206 void print_ctdb_available_ips(int numnodes, struct ctdb_all_public_ips **avail)
207 {
208         int n, i;
209
210         for (n = 0; n < numnodes; n++) {
211                 if ((avail[n] != NULL) && (avail[n]->num > 0)) {
212                         printf("%d:", n);
213                         for (i = 0; i < avail[n]->num; i++) {
214                                 printf("%s%s",
215                                        (i == 0) ? " " : ", ",
216                                        ctdb_addr_to_str(&(avail[n]->ips[i].addr)));
217                         }
218                         printf("\n");
219                 }
220         }
221 }
222
223 void ctdb_test_read_ctdb_public_ip_info(const char nodestates[])
224 {
225         int numnodes;
226         struct ctdb_public_ip_list *l;
227         struct ctdb_all_public_ips **avail;
228         char *tok, *ns;
229
230         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
231
232         /* Avoid that const */
233         ns = talloc_strdup(tmp_ctx, nodestates);
234
235         numnodes = 0;
236         tok = strtok(ns, ",");
237         while (tok != NULL) {
238                 numnodes++;
239                 tok = strtok(NULL, ",");
240         }
241         
242         read_ctdb_public_ip_info(tmp_ctx, numnodes, &l, &avail);
243
244         print_ctdb_public_ip_list(l);
245         print_ctdb_available_ips(numnodes, avail);
246
247         talloc_free(tmp_ctx);
248 }
249
250 /* Read 2 IPs from stdin, calculate the IP distance and print it. */
251 void ctdb_test_ip_distance(void)
252 {
253         struct ctdb_public_ip_list *l;
254         uint32_t distance;
255
256         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
257
258         l = read_ctdb_public_ip_list(tmp_ctx);
259
260         if (l && l->next) {
261                 distance = ip_distance(&(l->addr), &(l->next->addr));
262                 printf ("%lu\n", (unsigned long) distance);
263         }
264
265         talloc_free(tmp_ctx);
266 }
267
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)
272 {
273         struct ctdb_public_ip_list *l;
274         struct ctdb_public_ip_list *t;
275         ctdb_sock_addr addr;
276         uint32_t distance;
277
278         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
279
280         
281         l = read_ctdb_public_ip_list(tmp_ctx);
282
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)) {
287                                 break;
288                         }
289                 }
290
291                 if (t == NULL) {
292                         fprintf(stderr, "IP NOT PRESENT IN LIST");
293                         exit(1);
294                 }
295
296                 distance = ip_distance_2_sum(&(t->addr), l, pnn);
297                 printf ("%lu\n", (unsigned long) distance);
298         } else {
299                 fprintf(stderr, "BAD INPUT");
300                 exit(1);
301         }
302
303         talloc_free(tmp_ctx);
304 }
305
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)
309 {
310         struct ctdb_public_ip_list *l;
311         uint32_t imbalance;
312
313         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
314
315         l = read_ctdb_public_ip_list(tmp_ctx);
316
317         imbalance = lcp2_imbalance(l, pnn);
318         printf ("%lu\n", (unsigned long) imbalance);
319
320         talloc_free(tmp_ctx);
321 }
322
323 static uint32_t *get_tunable_values(TALLOC_CTX *tmp_ctx,
324                                     int numnodes,
325                                     const char *tunable)
326 {
327         int i;
328         char *tok;
329         uint32_t *tvals = talloc_zero_array(tmp_ctx, uint32_t, numnodes);
330         char *t = getenv(tunable);
331
332         if (t) {
333                 if (strcmp(t, "1") == 0) {
334                         for (i=0; i<numnodes; i++) {
335                                 tvals[i] = 1;
336                         }
337                 } else {
338                         tok = strtok(t, ",");
339                         i = 0;
340                         while (tok != NULL) {
341                                 tvals[i] =
342                                         (uint32_t) strtol(tok, NULL, 0);
343                                 i++;
344                                 tok = strtok(NULL, ",");
345                         }
346                         if (i != numnodes) {
347                                 fprintf(stderr, "ERROR: Wrong number of values in %s\n", tunable);
348                                 exit(1);
349                         }
350                 }
351         }
352
353         return tvals;
354 }
355
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)
360 {
361         struct ctdb_all_public_ips **avail;
362         int i, numnodes;
363         uint32_t nodeflags[CTDB_TEST_MAX_NODES];
364         char *tok, *ns, *t;
365         uint32_t *tval_noiptakeover;
366         uint32_t *tval_noiptakeoverondisabled;
367
368         *ctdb = talloc_zero(NULL, struct ctdb_context);
369
370         /* Avoid that const */
371         ns = talloc_strdup(*ctdb, nodestates);
372
373         numnodes = 0;
374         tok = strtok(ns, ",");
375         while (tok != NULL) {
376                 nodeflags[numnodes] = (uint32_t) strtol(tok, NULL, 0);
377                 numnodes++;
378                 tok = strtok(NULL, ",");
379         }
380         
381         /* Fake things up... */
382         (*ctdb)->num_nodes = numnodes;
383
384         /* Default to LCP2 */
385         (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
386         (*ctdb)->tunable.deterministic_public_ips = 0;
387         (*ctdb)->tunable.disable_ip_failover = 0;
388         (*ctdb)->tunable.no_ip_failback = 0;
389
390         if ((t = getenv("CTDB_IP_ALGORITHM"))) {
391                 if (strcmp(t, "lcp2") == 0) {
392                         (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
393                 } else if (strcmp(t, "nondet") == 0) {
394                         (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
395                 } else if (strcmp(t, "det") == 0) {
396                         (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
397                         (*ctdb)->tunable.deterministic_public_ips = 1;
398                 } else {
399                         fprintf(stderr, "ERROR: unknown IP algorithm %s\n", t);
400                         exit(1);
401                 }
402         }
403
404         tval_noiptakeover = get_tunable_values(*ctdb, numnodes,
405                                                "CTDB_SET_NoIPTakeover");
406         tval_noiptakeoverondisabled =
407                 get_tunable_values(*ctdb, numnodes,
408                                    "CTDB_SET_NoIPHostOnAllDisabled");
409
410         *nodemap =  talloc_array(*ctdb, struct ctdb_node_map, numnodes);
411         (*nodemap)->num = numnodes;
412
413         read_ctdb_public_ip_info(*ctdb, numnodes, all_ips, &avail);
414
415         (*ctdb)->nodes = talloc_array(*ctdb, struct ctdb_node *, numnodes); // FIXME: bogus size, overkill
416
417         for (i=0; i < numnodes; i++) {
418                 (*nodemap)->nodes[i].pnn = i;
419                 (*nodemap)->nodes[i].flags = nodeflags[i];
420                 /* nodemap->nodes[i].sockaddr is uninitialised */
421
422                 (*ctdb)->nodes[i] = talloc(*ctdb, struct ctdb_node);
423                 (*ctdb)->nodes[i]->pnn = i;
424                 (*ctdb)->nodes[i]->flags = nodeflags[i];
425                 (*ctdb)->nodes[i]->available_public_ips = avail[i];
426                 (*ctdb)->nodes[i]->known_public_ips = avail[i];
427         }
428
429         set_ipflags_internal(*nodemap, tval_noiptakeover, tval_noiptakeoverondisabled);
430 }
431
432 /* IP layout is read from stdin. */
433 void ctdb_test_lcp2_allocate_unassigned(const char nodestates[])
434 {
435         struct ctdb_context *ctdb;
436         struct ctdb_public_ip_list *all_ips;
437         struct ctdb_node_map *nodemap;
438
439         uint32_t *lcp2_imbalances;
440         bool *newly_healthy;
441
442         ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
443
444         lcp2_init(ctdb, nodemap, all_ips, &lcp2_imbalances, &newly_healthy);
445
446         lcp2_allocate_unassigned(ctdb, nodemap,
447                                  all_ips, lcp2_imbalances);
448
449         print_ctdb_public_ip_list(all_ips);
450
451         talloc_free(ctdb);
452 }
453
454 /* IP layout is read from stdin. */
455 void ctdb_test_lcp2_failback(const char nodestates[])
456 {
457         struct ctdb_context *ctdb;
458         struct ctdb_public_ip_list *all_ips;
459         struct ctdb_node_map *nodemap;
460
461         uint32_t *lcp2_imbalances;
462         bool *newly_healthy;
463
464         ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
465
466         lcp2_init(ctdb, nodemap, all_ips, &lcp2_imbalances, &newly_healthy);
467
468         lcp2_failback(ctdb, nodemap,
469                       all_ips, lcp2_imbalances, newly_healthy);
470
471         print_ctdb_public_ip_list(all_ips);
472
473         talloc_free(ctdb);
474 }
475
476 /* IP layout is read from stdin. */
477 void ctdb_test_lcp2_failback_loop(const char nodestates[])
478 {
479         struct ctdb_context *ctdb;
480         struct ctdb_public_ip_list *all_ips;
481         struct ctdb_node_map *nodemap;
482
483         uint32_t *lcp2_imbalances;
484         bool *newly_healthy;
485
486         ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
487
488         lcp2_init(ctdb, nodemap, all_ips, &lcp2_imbalances, &newly_healthy);
489
490         lcp2_failback(ctdb, nodemap,
491                       all_ips, lcp2_imbalances, newly_healthy);
492
493         print_ctdb_public_ip_list(all_ips);
494
495         talloc_free(ctdb);
496 }
497
498 /* IP layout is read from stdin. */
499 void ctdb_test_ctdb_takeover_run_core(const char nodestates[])
500 {
501         struct ctdb_context *ctdb;
502         struct ctdb_public_ip_list *all_ips;
503         struct ctdb_node_map *nodemap;
504
505         ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
506
507         ctdb_takeover_run_core(ctdb, nodemap, &all_ips);
508
509         print_ctdb_public_ip_list(all_ips);
510
511         talloc_free(ctdb);
512 }
513
514 void usage(void)
515 {
516         fprintf(stderr, "usage: ctdb_takeover_tests <op>\n");
517         exit(1);
518 }
519
520 int main(int argc, const char *argv[])
521 {
522         LogLevel = DEBUG_DEBUG;
523         if (getenv("CTDB_TEST_LOGLEVEL")) {
524                 LogLevel = atoi(getenv("CTDB_TEST_LOGLEVEL"));
525         }
526
527         if (argc < 2) {
528                 usage();
529         }
530
531         if (strcmp(argv[1], "ip_list") == 0) {
532                 ctdb_test_read_ctdb_public_ip_list();
533         } else if (argc == 3 && strcmp(argv[1], "ip_info") == 0) {
534                 ctdb_test_read_ctdb_public_ip_info(argv[2]);
535         } else if (strcmp(argv[1], "ip_distance") == 0) {
536                 ctdb_test_ip_distance();
537         } else if (argc == 4 && strcmp(argv[1], "ip_distance_2_sum") == 0) {
538                 ctdb_test_ip_distance_2_sum(argv[2], atoi(argv[3]));
539         } else if (argc >= 3 && strcmp(argv[1], "lcp2_imbalance") == 0) {
540                 ctdb_test_lcp2_imbalance(atoi(argv[2]));
541         } else if (argc == 3 && strcmp(argv[1], "lcp2_allocate_unassigned") == 0) {
542                 ctdb_test_lcp2_allocate_unassigned(argv[2]);
543         } else if (argc == 3 && strcmp(argv[1], "lcp2_failback") == 0) {
544                 ctdb_test_lcp2_failback(argv[2]);
545         } else if (argc == 3 && strcmp(argv[1], "lcp2_failback_loop") == 0) {
546                 ctdb_test_lcp2_failback_loop(argv[2]);
547         } else if (argc == 3 && strcmp(argv[1], "ctdb_takeover_run_core") == 0) {
548                 ctdb_test_ctdb_takeover_run_core(argv[2]);
549         } else {
550                 usage();
551         }
552
553         return 0;
554 }