5fd23320a3d6742629c964cccfb4d0370fd47bfe
[sahlberg/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 "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
187         numnodes = strlen(nodestates);
188
189         *ctdb = talloc_zero(NULL, struct ctdb_context);
190
191         /* Fake things up... */
192         (*ctdb)->num_nodes = numnodes;
193
194         (*ctdb)->tunable.deterministic_public_ips = 0;
195         (*ctdb)->tunable.disable_ip_failover = 0;
196         (*ctdb)->tunable.no_ip_failback = 0;
197
198         if (getenv("CTDB_LCP2")) {
199                 if (strcmp(getenv("CTDB_LCP2"), "yes") == 0) {
200                         (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
201                 } else {
202                         (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
203                 }
204         }
205
206         *nodemap =  talloc_array(*ctdb, struct ctdb_node_map, numnodes);
207         (*nodemap)->num = numnodes;
208
209         for (i=0; i < numnodes; i++) {
210                 (*nodemap)->nodes[i].pnn = i;
211                 (*nodemap)->nodes[i].flags = nodestates[i] - '0';
212                 /* *nodemap->nodes[i].sockaddr is uninitialised */
213         }
214
215         *all_ips = read_ctdb_public_ip_list(*ctdb);
216         numips = 0;
217         for (t = *all_ips; t != NULL; t = t->next) {
218                 numips++;
219         }
220
221         available_public_ips = talloc_array(*ctdb, struct ctdb_all_public_ips, numips); // FIXME: bogus size, overkill
222         available_public_ips->num = numips;
223         for (t = *all_ips, i=0; t != NULL && i < numips ; t = t->next, i++) {
224                 available_public_ips->ips[i].pnn = t->pnn;
225                 memcpy(&(available_public_ips->ips[i].addr), &(t->addr), sizeof(t->addr));
226         }
227
228         (*ctdb)->nodes = talloc_array(*ctdb, struct ctdb_node *, numnodes); // FIXME: bogus size, overkill
229
230         /* Setup both nodemap and ctdb->nodes.  Mark all nodes as
231          * healthy - change this later. */
232         for (i=0; i < numnodes; i++) {
233                 uint32_t flags = nodestates[i] - '0' ? NODE_FLAGS_UNHEALTHY : 0;
234                 (*nodemap)->nodes[i].pnn = i;
235                 (*nodemap)->nodes[i].flags = flags;
236                 /* nodemap->nodes[i].sockaddr is uninitialised */
237
238                 (*ctdb)->nodes[i] = talloc(*ctdb, struct ctdb_node);
239                 (*ctdb)->nodes[i]->pnn = i;
240                 (*ctdb)->nodes[i]->flags = flags;
241                 (*ctdb)->nodes[i]->available_public_ips = available_public_ips;
242                 (*ctdb)->nodes[i]->known_public_ips = available_public_ips;
243         }
244 }
245
246 /* IP layout is read from stdin. */
247 void ctdb_test_lcp2_allocate_unassigned(const char nodestates[])
248 {
249         struct ctdb_context *ctdb;
250         struct ctdb_public_ip_list *all_ips;
251         struct ctdb_node_map *nodemap;
252
253         uint32_t *lcp2_imbalances;
254         bool *newly_healthy;
255
256         ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
257
258         lcp2_init(ctdb, nodemap,
259                   NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
260                   all_ips, &lcp2_imbalances, &newly_healthy);
261
262         lcp2_allocate_unassigned(ctdb, nodemap,
263                                  NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
264                                  all_ips, lcp2_imbalances);
265
266         print_ctdb_public_ip_list(all_ips);
267
268         talloc_free(ctdb);
269 }
270
271 /* IP layout is read from stdin. */
272 void ctdb_test_lcp2_failback(const char nodestates[])
273 {
274         struct ctdb_context *ctdb;
275         struct ctdb_public_ip_list *all_ips;
276         struct ctdb_node_map *nodemap;
277
278         uint32_t *lcp2_imbalances;
279         bool *newly_healthy;
280
281         ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
282
283         lcp2_init(ctdb, nodemap,
284                   NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
285                   all_ips, &lcp2_imbalances, &newly_healthy);
286
287         lcp2_failback(ctdb, nodemap,
288                                  NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
289                       all_ips, lcp2_imbalances, newly_healthy);
290
291         print_ctdb_public_ip_list(all_ips);
292
293         talloc_free(ctdb);
294 }
295
296 /* IP layout is read from stdin. */
297 void ctdb_test_lcp2_failback_loop(const char nodestates[])
298 {
299         struct ctdb_context *ctdb;
300         struct ctdb_public_ip_list *all_ips;
301         struct ctdb_node_map *nodemap;
302
303         uint32_t *lcp2_imbalances;
304         bool *newly_healthy;
305
306         ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
307
308         lcp2_init(ctdb, nodemap,
309                   NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
310                   all_ips, &lcp2_imbalances, &newly_healthy);
311
312 try_again:
313         if (lcp2_failback(ctdb, nodemap,
314                           NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED,
315                           all_ips, lcp2_imbalances, newly_healthy)) {
316                 goto try_again;
317         }
318
319         print_ctdb_public_ip_list(all_ips);
320
321         talloc_free(ctdb);
322 }
323
324 /* IP layout is read from stdin. */
325 void ctdb_test_ctdb_takeover_run_core(const char nodestates[])
326 {
327         struct ctdb_context *ctdb;
328         struct ctdb_public_ip_list *all_ips;
329         struct ctdb_node_map *nodemap;
330
331         ctdb_test_init(nodestates, &ctdb, &all_ips, &nodemap);
332
333         ctdb_takeover_run_core(ctdb, nodemap, &all_ips);
334
335         print_ctdb_public_ip_list(all_ips);
336
337         talloc_free(ctdb);
338 }
339
340 void usage(void)
341 {
342         fprintf(stderr, "usage: ctdb_takeover_tests <op>\n");
343         exit(1);
344 }
345
346 int main(int argc, const char *argv[])
347 {
348         LogLevel = DEBUG_DEBUG;
349         if (getenv("CTDB_TEST_LOGLEVEL")) {
350                 LogLevel = atoi(getenv("CTDB_TEST_LOGLEVEL"));
351         }
352
353         if (argc < 2) {
354                 usage();
355         }
356
357         if (strcmp(argv[1], "ip_list") == 0) {
358                 ctdb_test_read_ctdb_public_ip_list();
359         } else if (strcmp(argv[1], "ip_distance") == 0) {
360                 ctdb_test_ip_distance();
361         } else if (argc == 4 && strcmp(argv[1], "ip_distance_2_sum") == 0) {
362                 ctdb_test_ip_distance_2_sum(argv[2], atoi(argv[3]));
363         } else if (argc >= 3 && strcmp(argv[1], "lcp2_imbalance") == 0) {
364                 ctdb_test_lcp2_imbalance(atoi(argv[2]));
365         } else if (argc == 3 && strcmp(argv[1], "lcp2_allocate_unassigned") == 0) {
366                 ctdb_test_lcp2_allocate_unassigned(argv[2]);
367         } else if (argc == 3 && strcmp(argv[1], "lcp2_failback") == 0) {
368                 ctdb_test_lcp2_failback(argv[2]);
369         } else if (argc == 3 && strcmp(argv[1], "lcp2_failback_loop") == 0) {
370                 ctdb_test_lcp2_failback_loop(argv[2]);
371         } else if (argc == 3 && strcmp(argv[1], "ctdb_takeover_run_core") == 0) {
372                 ctdb_test_ctdb_takeover_run_core(argv[2]);
373         } else {
374                 usage();
375         }
376
377         return 0;
378 }