Merge branch 'master' of 10.1.1.27:/shared/ctdb/ctdb-master
[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 "includes.h"
21 #include "../include/ctdb_private.h"
22
23 /*
24  * Need these, since they're defined in ctdbd.c but we can't link
25  * that.
26  */
27 int script_log_level;
28 bool fast_start;
29 void ctdb_load_nodes_file(struct ctdb_context *ctdb) {}
30
31 /* Format of each line is "IP pnn" - the separator has to be at least
32  * 1 space (not a tab or whatever - a space!).
33  */
34 static struct ctdb_public_ip_list *
35 read_ctdb_public_ip_list(TALLOC_CTX *ctx)
36 {
37         char line[1024];
38         ctdb_sock_addr addr;
39         char *t;
40         int pnn;
41         struct ctdb_public_ip_list *last = NULL;
42
43         struct ctdb_public_ip_list *ret = NULL;
44
45         while (fgets(line, sizeof(line), stdin) != NULL) {
46                 
47                 if ((t = strchr(line, ' ')) != NULL) {
48                         /* Make line contain just the address */
49                         *t = '\0';
50                         /* Point to PNN or leading whitespace...  */
51                         t++;
52                         pnn = (int) strtol(t, (char **) NULL, 10);
53                 } else {
54                         /* Assume just an IP address, default to PNN -1 */
55                         if ((t = strchr(line, '\n')) != NULL) {
56                                 *t = '\0';
57                         }
58                         pnn = -1;
59                 }
60                
61                 if (parse_ip(line, NULL, 0, &addr)) {
62                         if (last == NULL) {
63                                 last = talloc(ctx, struct ctdb_public_ip_list);
64                         } else {
65                                 last->next = talloc(ctx, struct ctdb_public_ip_list);
66                                 last = last->next;
67                         }
68                         last->next = NULL;
69                         last->pnn = pnn;
70                         memcpy(&(last->addr), &addr, sizeof(addr));
71                         if (ret == NULL) {
72                                 ret = last;
73                         }
74                 } else {
75                         DEBUG(DEBUG_ERR, (__location__ " ERROR, bad address :%s\n", line));
76                 }
77         }
78                         
79         return ret;
80 }
81
82 void print_ctdb_public_ip_list(struct ctdb_public_ip_list * ips)
83 {
84         while (ips) {
85                 printf("%s %d\n", ctdb_addr_to_str(&(ips->addr)), ips->pnn);
86                 ips = ips->next;
87         }
88 }
89
90 /* Read some IPs from stdin, 1 per line, parse them and then print
91  * them back out. */
92 void ctdb_test_read_ctdb_public_ip_list(void)
93 {
94         struct ctdb_public_ip_list *l;
95
96         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
97
98         l = read_ctdb_public_ip_list(tmp_ctx);
99
100         print_ctdb_public_ip_list(l);
101
102         talloc_free(tmp_ctx);
103 }
104
105 /* Read 2 IPs from stdin, calculate the IP distance and print it. */
106 void ctdb_test_ip_distance(void)
107 {
108         struct ctdb_public_ip_list *l;
109         uint32_t distance;
110
111         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
112
113         l = read_ctdb_public_ip_list(tmp_ctx);
114
115         if (l && l->next) {
116                 distance = ip_distance(&(l->addr), &(l->next->addr));
117                 printf ("%lu\n", (unsigned long) distance);
118         }
119
120         talloc_free(tmp_ctx);
121 }
122
123 /* Read some IPs from stdin, calculate the sum of the squares of the
124  * IP distances between the 1st argument and those read that are on
125  * the given node. The given IP must one of the ones in the list.  */
126 void ctdb_test_ip_distance_2_sum(const char ip[], int pnn)
127 {
128         struct ctdb_public_ip_list *l;
129         struct ctdb_public_ip_list *t;
130         ctdb_sock_addr addr;
131         uint32_t distance;
132
133         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
134
135         
136         l = read_ctdb_public_ip_list(tmp_ctx);
137
138         if (l && parse_ip(ip, NULL, 0, &addr)) {
139                 /* find the entry for the specified IP */
140                 for (t=l; t!=NULL; t=t->next) {
141                         if (ctdb_same_ip(&(t->addr), &addr)) {
142                                 break;
143                         }
144                 }
145
146                 if (t == NULL) {
147                         fprintf(stderr, "IP NOT PRESENT IN LIST");
148                         exit(1);
149                 }
150
151                 distance = ip_distance_2_sum(&(t->addr), l, pnn);
152                 printf ("%lu\n", (unsigned long) distance);
153         } else {
154                 fprintf(stderr, "BAD INPUT");
155                 exit(1);
156         }
157
158         talloc_free(tmp_ctx);
159 }
160
161 /* Read some IPs from stdin, calculate the sume of the squares of the
162  * IP distances between the first and the rest, and print it. */
163 void ctdb_test_lcp2_imbalance(int pnn)
164 {
165         struct ctdb_public_ip_list *l;
166         uint32_t imbalance;
167
168         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
169
170         l = read_ctdb_public_ip_list(tmp_ctx);
171
172         imbalance = lcp2_imbalance(l, pnn);
173         printf ("%lu\n", (unsigned long) imbalance);
174
175         talloc_free(tmp_ctx);
176 }
177
178 void ctdb_test_init(const char nodestates[],
179                     struct ctdb_context **ctdb,
180                     struct ctdb_public_ip_list **all_ips,
181                     struct ctdb_node_map **nodemap)
182 {
183         struct ctdb_public_ip_list *t;
184         struct ctdb_all_public_ips *available_public_ips;
185         int i, numips, numnodes;
186         /* This is test code and this is unreasonably big... :-) */
187         uint32_t nodeflags[256];
188         char *tok, *ns;
189
190         *ctdb = talloc_zero(NULL, struct ctdb_context);
191
192         /* Avoid that const */
193         ns = talloc_strdup(*ctdb, nodestates);
194
195         numnodes = 0;
196         tok = strtok(ns, ",");
197         while (tok != NULL) {
198                 nodeflags[numnodes] = (uint32_t) strtol(tok, NULL, 16);
199                 numnodes++;
200                 tok = strtok(NULL, ",");
201         }
202         
203         /* Fake things up... */
204         (*ctdb)->num_nodes = numnodes;
205
206         (*ctdb)->tunable.deterministic_public_ips = 0;
207         (*ctdb)->tunable.disable_ip_failover = 0;
208         (*ctdb)->tunable.no_ip_failback = 0;
209
210         if (getenv("CTDB_LCP2")) {
211                 if (strcmp(getenv("CTDB_LCP2"), "yes") == 0) {
212                         (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
213                 } else {
214                         (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
215                 }
216         }
217
218         *nodemap =  talloc_array(*ctdb, struct ctdb_node_map, numnodes);
219         (*nodemap)->num = numnodes;
220
221         *all_ips = read_ctdb_public_ip_list(*ctdb);
222         numips = 0;
223         for (t = *all_ips; t != NULL; t = t->next) {
224                 numips++;
225         }
226
227         available_public_ips = talloc_array(*ctdb, struct ctdb_all_public_ips, numips); // FIXME: bogus size, overkill
228         available_public_ips->num = numips;
229         for (t = *all_ips, i=0; t != NULL && i < numips ; t = t->next, i++) {
230                 available_public_ips->ips[i].pnn = t->pnn;
231                 memcpy(&(available_public_ips->ips[i].addr), &(t->addr), sizeof(t->addr));
232         }
233
234         (*ctdb)->nodes = talloc_array(*ctdb, struct ctdb_node *, numnodes); // FIXME: bogus size, overkill
235
236         /* Setup both nodemap and ctdb->nodes.  Mark all nodes as
237          * healthy - change this later. */
238         for (i=0; i < numnodes; i++) {
239                 (*nodemap)->nodes[i].pnn = i;
240                 (*nodemap)->nodes[i].flags = nodeflags[i];
241                 /* nodemap->nodes[i].sockaddr is uninitialised */
242
243                 (*ctdb)->nodes[i] = talloc(*ctdb, struct ctdb_node);
244                 (*ctdb)->nodes[i]->pnn = i;
245                 (*ctdb)->nodes[i]->flags = nodeflags[i];
246                 (*ctdb)->nodes[i]->available_public_ips = available_public_ips;
247                 (*ctdb)->nodes[i]->known_public_ips = available_public_ips;
248         }
249 }
250
251 /* IP layout is read from stdin. */
252 void ctdb_test_lcp2_allocate_unassigned(const char nodestates[])
253 {
254         struct ctdb_context *ctdb;
255         struct ctdb_public_ip_list *all_ips;
256         struct ctdb_node_map *nodemap;
257
258         uint32_t *lcp2_imbalances;
259         bool *newly_healthy;
260
261         ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
262
263         lcp2_init(ctdb, nodemap,
264                   NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
265                   all_ips, &lcp2_imbalances, &newly_healthy);
266
267         lcp2_allocate_unassigned(ctdb, nodemap,
268                                  NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
269                                  all_ips, lcp2_imbalances);
270
271         print_ctdb_public_ip_list(all_ips);
272
273         talloc_free(ctdb);
274 }
275
276 /* IP layout is read from stdin. */
277 void ctdb_test_lcp2_failback(const char nodestates[])
278 {
279         struct ctdb_context *ctdb;
280         struct ctdb_public_ip_list *all_ips;
281         struct ctdb_node_map *nodemap;
282
283         uint32_t *lcp2_imbalances;
284         bool *newly_healthy;
285
286         ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
287
288         lcp2_init(ctdb, nodemap,
289                   NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
290                   all_ips, &lcp2_imbalances, &newly_healthy);
291
292         lcp2_failback(ctdb, nodemap,
293                                  NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
294                       all_ips, lcp2_imbalances, newly_healthy);
295
296         print_ctdb_public_ip_list(all_ips);
297
298         talloc_free(ctdb);
299 }
300
301 /* IP layout is read from stdin. */
302 void ctdb_test_lcp2_failback_loop(const char nodestates[])
303 {
304         struct ctdb_context *ctdb;
305         struct ctdb_public_ip_list *all_ips;
306         struct ctdb_node_map *nodemap;
307
308         uint32_t *lcp2_imbalances;
309         bool *newly_healthy;
310
311         ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
312
313         lcp2_init(ctdb, nodemap,
314                   NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
315                   all_ips, &lcp2_imbalances, &newly_healthy);
316
317 try_again:
318         if (lcp2_failback(ctdb, nodemap,
319                           NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
320                           all_ips, lcp2_imbalances, newly_healthy)) {
321                 goto try_again;
322         }
323
324         print_ctdb_public_ip_list(all_ips);
325
326         talloc_free(ctdb);
327 }
328
329 /* IP layout is read from stdin. */
330 void ctdb_test_ctdb_takeover_run_core(const char nodestates[])
331 {
332         struct ctdb_context *ctdb;
333         struct ctdb_public_ip_list *all_ips;
334         struct ctdb_node_map *nodemap;
335
336         ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
337
338         ctdb_takeover_run_core(ctdb, nodemap, &all_ips);
339
340         print_ctdb_public_ip_list(all_ips);
341
342         talloc_free(ctdb);
343 }
344
345 void usage(void)
346 {
347         fprintf(stderr, "usage: ctdb_takeover_tests <op>\n");
348         exit(1);
349 }
350
351 int main(int argc, const char *argv[])
352 {
353         LogLevel = DEBUG_DEBUG;
354         if (getenv("CTDB_TEST_LOGLEVEL")) {
355                 LogLevel = atoi(getenv("CTDB_TEST_LOGLEVEL"));
356         }
357
358         if (argc < 2) {
359                 usage();
360         }
361
362         if (strcmp(argv[1], "ip_list") == 0) {
363                 ctdb_test_read_ctdb_public_ip_list();
364         } else if (strcmp(argv[1], "ip_distance") == 0) {
365                 ctdb_test_ip_distance();
366         } else if (argc == 4 && strcmp(argv[1], "ip_distance_2_sum") == 0) {
367                 ctdb_test_ip_distance_2_sum(argv[2], atoi(argv[3]));
368         } else if (argc >= 3 && strcmp(argv[1], "lcp2_imbalance") == 0) {
369                 ctdb_test_lcp2_imbalance(atoi(argv[2]));
370         } else if (argc == 3 && strcmp(argv[1], "lcp2_allocate_unassigned") == 0) {
371                 ctdb_test_lcp2_allocate_unassigned(argv[2]);
372         } else if (argc == 3 && strcmp(argv[1], "lcp2_failback") == 0) {
373                 ctdb_test_lcp2_failback(argv[2]);
374         } else if (argc == 3 && strcmp(argv[1], "lcp2_failback_loop") == 0) {
375                 ctdb_test_lcp2_failback_loop(argv[2]);
376         } else if (argc == 3 && strcmp(argv[1], "ctdb_takeover_run_core") == 0) {
377                 ctdb_test_ctdb_takeover_run_core(argv[2]);
378         } else {
379                 usage();
380         }
381
382         return 0;
383 }