ctdb-tests: Support fake capabilities in CTDB tool stub
[nivanova/samba-autobuild/.git] / ctdb / tests / src / ctdb_test_stubs.c
1 /*
2    Test stubs and support functions for some CTDB client functions
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 /* Read a nodemap from stdin.  Each line looks like:
21  *  <PNN> <FLAGS> [RECMASTER] [CURRENT] [CAPABILITIES]
22  * EOF or a blank line terminates input.
23  *
24  * By default, capablities for each node are
25  * CTDB_CAP_RECMASTER|CTDB_CAP_LMASTER|CTDB_CAP_NATGW.  These 3
26  * capabilities can be faked off by adding, for example,
27  * -CTDB_CAP_RECMASTER.  LVS can be faked on by adding
28  * CTDB_CAP_LVS.
29  */
30 void ctdb_test_stubs_read_nodemap(struct ctdb_context *ctdb)
31 {
32         char line[1024];
33
34         TALLOC_FREE(ctdb->nodes);
35         ctdb->pnn = -1;
36         ctdb->num_nodes = 0;
37
38         ctdb->nodes = NULL;
39
40         while ((fgets(line, sizeof(line), stdin) != NULL) &&
41                (line[0] != '\n')) {
42                 uint32_t pnn, flags, capabilities;
43                 char *tok, *t;
44                 const char *ip;
45                 ctdb_sock_addr saddr;
46
47                 /* Get rid of pesky newline */
48                 if ((t = strchr(line, '\n')) != NULL) {
49                         *t = '\0';
50                 }
51
52                 /* Get PNN */
53                 tok = strtok(line, " \t");
54                 if (tok == NULL) {
55                         DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line (PNN) ignored \"%s\"\n", line));
56                         continue;
57                 }
58                 pnn = (uint32_t)strtoul(tok, NULL, 0);
59
60                 /* Get IP */
61                 tok = strtok(NULL, " \t");
62                 if (tok == NULL) {
63                         DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line (no IP) ignored \"%s\"\n", line));
64                         continue;
65                 }
66                 if (!parse_ip(tok, NULL, 0, &saddr)) {
67                         DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line (IP) ignored \"%s\"\n", line));
68                         continue;
69                 }
70                 ip = talloc_strdup(ctdb, tok);
71
72                 /* Get flags */
73                 tok = strtok(NULL, " \t");
74                 if (tok == NULL) {
75                         DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line (flags) ignored \"%s\"\n", line));
76                         continue;
77                 }
78                 flags = (uint32_t)strtoul(tok, NULL, 0);
79                 capabilities = CTDB_CAP_RECMASTER|CTDB_CAP_LMASTER|CTDB_CAP_NATGW;
80
81                 tok = strtok(NULL, " \t");
82                 while (tok != NULL) {
83                         if (strcmp(tok, "CURRENT") == 0) {
84                                 ctdb->pnn = pnn;
85                         } else if (strcmp(tok, "RECMASTER") == 0) {
86                                 ctdb->recovery_master = pnn;
87                         } else if (strcmp(tok, "-CTDB_CAP_RECMASTER") == 0) {
88                                 capabilities &= ~CTDB_CAP_RECMASTER;
89                         } else if (strcmp(tok, "-CTDB_CAP_LMASTER") == 0) {
90                                 capabilities &= ~CTDB_CAP_LMASTER;
91                         } else if (strcmp(tok, "-CTDB_CAP_NATGW") == 0) {
92                                 capabilities &= ~CTDB_CAP_NATGW;
93                         } else if (strcmp(tok, "CTDB_CAP_LVS") == 0) {
94                                 capabilities |= CTDB_CAP_LVS;
95                         }
96                         tok = strtok(NULL, " \t");
97                 }
98
99                 ctdb->nodes = talloc_realloc(ctdb, ctdb->nodes, struct ctdb_node *, ctdb->num_nodes + 1);
100                 if (ctdb->nodes == NULL) {
101                         DEBUG(DEBUG_ERR, ("OOM allocating nodes array\n"));
102                         exit (1);
103                 }
104                 ctdb->nodes[ctdb->num_nodes] = talloc_zero(ctdb, struct ctdb_node);
105                 if (ctdb->nodes[ctdb->num_nodes] == NULL) {
106                         DEBUG(DEBUG_ERR, ("OOM allocating node structure\n"));
107                         exit (1);
108                 }
109
110                 ctdb->nodes[ctdb->num_nodes]->ctdb = ctdb;
111                 ctdb->nodes[ctdb->num_nodes]->name = "fakectdb";
112                 ctdb->nodes[ctdb->num_nodes]->pnn = pnn;
113                 ctdb->nodes[ctdb->num_nodes]->address.address = ip;
114                 ctdb->nodes[ctdb->num_nodes]->address.port = 0;
115                 ctdb->nodes[ctdb->num_nodes]->flags = flags;
116                 ctdb->nodes[ctdb->num_nodes]->capabilities = capabilities;
117                 ctdb->num_nodes++;
118         }
119 }
120
121 void ctdb_test_stubs_print_nodemap(struct ctdb_context *ctdb)
122 {
123         int i;
124
125         for (i = 0; i < ctdb->num_nodes; i++) {
126                 printf("%ld\t0x%lx%s%s\n",
127                        (unsigned long) ctdb->nodes[i]->pnn,
128                        (unsigned long) ctdb->nodes[i]->flags,
129                        ctdb->nodes[i]->pnn == ctdb->pnn ? "\tCURRENT" : "",
130                        ctdb->nodes[i]->pnn == ctdb->recovery_master ? "\tRECMASTER" : "");
131         }
132 }
133
134 /* Read interfaces information.  Same format as "ctdb ifaces -Y"
135  * output:
136  *   :Name:LinkStatus:References:
137  *   :eth2:1:4294967294
138  *   :eth1:1:4294967292
139  */
140
141 struct ctdb_iface {
142         struct ctdb_iface *prev, *next;
143         const char *name;
144         bool link_up;
145         uint32_t references;
146 };
147
148 void ctdb_test_stubs_read_ifaces(struct ctdb_context *ctdb)
149 {
150         char line[1024];
151         struct ctdb_iface *iface;
152
153         while ((fgets(line, sizeof(line), stdin) != NULL) &&
154                (line[0] != '\n')) {
155                 uint16_t link_state;
156                 uint32_t references;
157                 char *tok, *t, *name;
158
159                 /* Get rid of pesky newline */
160                 if ((t = strchr(line, '\n')) != NULL) {
161                         *t = '\0';
162                 }
163
164                 if (strcmp(line, ":Name:LinkStatus:References:") == 0) {
165                         continue;
166                 }
167
168                 /* name */
169                 //tok = strtok(line, ":"); /* Leading colon... */
170                 tok = strtok(line, ":");
171                 if (tok == NULL) {
172                         DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line ignored \"%s\"\n", line));
173                         continue;
174                 }
175                 name = tok;
176
177                 /* link_state */
178                 tok = strtok(NULL, ":");
179                 if (tok == NULL) {
180                         DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line ignored \"%s\"\n", line));
181                         continue;
182                 }
183                 link_state = (uint16_t)strtoul(tok, NULL, 0);
184
185                 /* references... */
186                 tok = strtok(NULL, ":");
187                 if (tok == NULL) {
188                         DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line ignored \"%s\"\n", line));
189                         continue;
190                 }
191                 references = (uint32_t)strtoul(tok, NULL, 0);
192
193                 iface = talloc_zero(ctdb, struct ctdb_iface);
194
195                 if (iface == NULL) {
196                         DEBUG(DEBUG_ERR, ("OOM allocating iface\n"));
197                         exit (1);
198                 }
199
200                 iface->name = talloc_strdup(iface, name);
201                 iface->link_up = link_state;
202                 iface->references = references;
203
204                 DLIST_ADD(ctdb->ifaces, iface);
205         }
206 }
207
208 void ctdb_test_stubs_print_ifaces(struct ctdb_context *ctdb)
209 {
210         struct ctdb_iface *iface;
211
212         printf(":Name:LinkStatus:References:\n");
213         for (iface = ctdb->ifaces; iface != NULL; iface = iface->next) {
214                 printf(":%s:%u:%u:\n",
215                        iface->name,
216                        iface->link_up,
217                        iface->references);
218         }
219 }
220
221 /* Read vnn map.
222  * output:
223  *   <GENERATION>
224  *   <LMASTER0>
225  *   <LMASTER1>
226  *   ...
227  */
228
229 /*
230 struct ctdb_vnn_map {
231         uint32_t generation;
232         uint32_t size;
233         uint32_t *map;
234 };
235 */
236 void ctdb_test_stubs_read_vnnmap(struct ctdb_context *ctdb)
237 {
238         char line[1024];
239
240         TALLOC_FREE(ctdb->vnn_map);
241
242         ctdb->vnn_map = talloc_zero(ctdb, struct ctdb_vnn_map);
243         if (ctdb->vnn_map == NULL) {
244                 DEBUG(DEBUG_ERR, ("OOM allocating vnnmap\n"));
245                 exit (1);
246         }
247         ctdb->vnn_map->generation = INVALID_GENERATION;
248         ctdb->vnn_map->size = 0;
249         ctdb->vnn_map->map = NULL;
250
251         while ((fgets(line, sizeof(line), stdin) != NULL) &&
252                (line[0] != '\n')) {
253                 uint32_t n;
254                 char *t;
255
256                 /* Get rid of pesky newline */
257                 if ((t = strchr(line, '\n')) != NULL) {
258                         *t = '\0';
259                 }
260
261                 n = (uint32_t) strtol(line, NULL, 0);
262
263                 /* generation */
264                 if (ctdb->vnn_map->generation == INVALID_GENERATION) {
265                         ctdb->vnn_map->generation = n;
266                         continue;
267                 }
268
269                 ctdb->vnn_map->map = talloc_realloc(ctdb, ctdb->vnn_map->map, uint32_t, ctdb->vnn_map->size + 1);
270                 if (ctdb->vnn_map->map == NULL) {
271                         DEBUG(DEBUG_ERR, ("OOM allocating vnn_map->map\n"));
272                         exit (1);
273                 }
274
275                 ctdb->vnn_map->map[ctdb->vnn_map->size] = n;
276                 ctdb->vnn_map->size++;
277         }
278 }
279
280 void ctdb_test_stubs_print_vnnmap(struct ctdb_context *ctdb)
281 {
282         int i;
283
284         printf("%d\n", ctdb->vnn_map->generation);
285         for (i = 0; i < ctdb->vnn_map->size; i++) {
286                 printf("%d\n", ctdb->vnn_map->map[i]);
287         }
288 }
289
290 void ctdb_test_stubs_fake_setup(struct ctdb_context *ctdb)
291 {
292         char line[1024];
293
294         while (fgets(line, sizeof(line), stdin) != NULL) {
295                 char *t;
296
297                 /* Get rid of pesky newline */
298                 if ((t = strchr(line, '\n')) != NULL) {
299                         *t = '\0';
300                 }
301
302                 if (strcmp(line, "NODEMAP") == 0) {
303                         ctdb_test_stubs_read_nodemap(ctdb);
304                 } else if (strcmp(line, "IFACES") == 0) {
305                         ctdb_test_stubs_read_ifaces(ctdb);
306                 } else if (strcmp(line, "VNNMAP") == 0) {
307                         ctdb_test_stubs_read_vnnmap(ctdb);
308                 } else {
309                         printf("Unknown line %s\n", line);
310                         exit(1);
311                 }
312         }
313 }
314
315 /* Support... */
316 static bool current_node_is_connected (struct ctdb_context *ctdb)
317 {
318         int i;
319         for (i = 0; i < ctdb->num_nodes; i++) {
320                 if (ctdb->nodes[i]->pnn == ctdb->pnn) {
321                         if (ctdb->nodes[i]->flags &
322                             (NODE_FLAGS_DISCONNECTED | NODE_FLAGS_DELETED)) {
323                                 return false;
324                         } else {
325                                 return true;
326                         }
327                 }
328         }
329
330         /* Shouldn't really happen, so fag an error */
331         return false;
332 }
333
334 /* Stubs... */
335
336 struct ctdb_context *ctdb_cmdline_client_stub(struct tevent_context *ev,
337                                               struct timeval req_timeout)
338 {
339         struct ctdb_context *ctdb;
340
341         ctdb = talloc_zero(NULL, struct ctdb_context);
342
343         ctdb_set_socketname(ctdb, "fake");
344
345         ctdb_test_stubs_fake_setup(ctdb);
346
347         return ctdb;
348 }
349
350 /* Copied from ctdb_recover.c */
351 int
352 ctdb_control_getnodemap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata)
353 {
354         uint32_t i, num_nodes;
355         struct ctdb_node_map *node_map;
356
357         CHECK_CONTROL_DATA_SIZE(0);
358
359         num_nodes = ctdb->num_nodes;
360
361         outdata->dsize = offsetof(struct ctdb_node_map, nodes) + num_nodes*sizeof(struct ctdb_node_and_flags);
362         outdata->dptr  = (unsigned char *)talloc_zero_size(outdata, outdata->dsize);
363         if (!outdata->dptr) {
364                 DEBUG(DEBUG_ALERT, (__location__ " Failed to allocate nodemap array\n"));
365                 exit(1);
366         }
367
368         node_map = (struct ctdb_node_map *)outdata->dptr;
369         node_map->num = num_nodes;
370         for (i=0; i<num_nodes; i++) {
371                 if (parse_ip(ctdb->nodes[i]->address.address,
372                              NULL, /* TODO: pass in the correct interface here*/
373                              0,
374                              &node_map->nodes[i].addr) == 0)
375                 {
376                         DEBUG(DEBUG_ERR, (__location__ " Failed to parse %s into a sockaddr\n", ctdb->nodes[i]->address.address));
377                 }
378
379                 node_map->nodes[i].pnn   = ctdb->nodes[i]->pnn;
380                 node_map->nodes[i].flags = ctdb->nodes[i]->flags;
381         }
382
383         return 0;
384 }
385
386 int
387 ctdb_ctrl_getnodemap_stub(struct ctdb_context *ctdb,
388                           struct timeval timeout, uint32_t destnode,
389                           TALLOC_CTX *mem_ctx,
390                           struct ctdb_node_map **nodemap)
391 {
392         int ret;
393
394         TDB_DATA indata;
395         TDB_DATA *outdata;
396
397         if (!current_node_is_connected(ctdb)) {
398                 return -1;
399         }
400
401         indata.dsize = 0;
402         indata.dptr = NULL;
403
404         outdata = talloc_zero(ctdb, TDB_DATA);
405
406         ret = ctdb_control_getnodemap(ctdb, CTDB_CONTROL_GET_NODEMAP,
407                                       indata, outdata);
408
409         if (ret == 0) {
410                 *nodemap = (struct ctdb_node_map *) outdata->dptr;
411         }
412
413         return ret;
414 }
415
416 int
417 ctdb_ctrl_getvnnmap_stub(struct ctdb_context *ctdb,
418                          struct timeval timeout, uint32_t destnode,
419                          TALLOC_CTX *mem_ctx, struct ctdb_vnn_map **vnnmap)
420 {
421         *vnnmap = talloc(ctdb, struct ctdb_vnn_map);
422         if (*vnnmap == NULL) {
423                 DEBUG(DEBUG_ERR, (__location__ "OOM\n"));
424                 exit (1);
425         }
426         (*vnnmap)->map = talloc_array(*vnnmap, uint32_t, ctdb->vnn_map->size);
427
428         (*vnnmap)->generation = ctdb->vnn_map->generation;
429         (*vnnmap)->size = ctdb->vnn_map->size;
430         memcpy((*vnnmap)->map, ctdb->vnn_map->map, sizeof(uint32_t) * (*vnnmap)->size);
431
432         return 0;
433 }
434
435 int
436 ctdb_ctrl_getrecmode_stub(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
437                           struct timeval timeout, uint32_t destnode,
438                           uint32_t *recmode)
439 {
440         *recmode = ctdb->recovery_mode;
441
442         return 0;
443 }
444
445 int
446 ctdb_ctrl_getrecmaster_stub(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
447                             struct timeval timeout, uint32_t destnode,
448                             uint32_t *recmaster)
449 {
450         *recmaster = ctdb->recovery_master;
451
452         return 0;
453 }
454
455 int
456 ctdb_ctrl_getpnn_stub(struct ctdb_context *ctdb, struct timeval timeout,
457                       uint32_t destnode)
458 {
459         if (!current_node_is_connected(ctdb)) {
460                 return -1;
461         }
462
463         if (destnode == CTDB_CURRENT_NODE) {
464                 return ctdb->pnn;
465         } else {
466                 return destnode;
467         }
468 }
469
470 /* From ctdb_takeover.c */
471 int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb,
472                                 struct ctdb_req_control *c,
473                                 TDB_DATA *outdata)
474 {
475         int i, num, len;
476         struct ctdb_control_get_ifaces *ifaces;
477         struct ctdb_iface *cur;
478
479         /* count how many public ip structures we have */
480         num = 0;
481         for (cur=ctdb->ifaces;cur;cur=cur->next) {
482                 num++;
483         }
484
485         len = offsetof(struct ctdb_control_get_ifaces, ifaces) +
486                 num*sizeof(struct ctdb_control_iface_info);
487         ifaces = talloc_zero_size(outdata, len);
488         CTDB_NO_MEMORY(ctdb, ifaces);
489
490         i = 0;
491         for (cur=ctdb->ifaces;cur;cur=cur->next) {
492                 strcpy(ifaces->ifaces[i].name, cur->name);
493                 ifaces->ifaces[i].link_state = cur->link_up;
494                 ifaces->ifaces[i].references = cur->references;
495                 i++;
496         }
497         ifaces->num = i;
498         len = offsetof(struct ctdb_control_get_ifaces, ifaces) +
499                 i*sizeof(struct ctdb_control_iface_info);
500
501         outdata->dsize = len;
502         outdata->dptr  = (uint8_t *)ifaces;
503
504         return 0;
505 }
506
507 int
508 ctdb_ctrl_get_ifaces_stub(struct ctdb_context *ctdb,
509                           struct timeval timeout, uint32_t destnode,
510                           TALLOC_CTX *mem_ctx,
511                           struct ctdb_control_get_ifaces **ifaces)
512 {
513         TDB_DATA *outdata;
514         int ret;
515
516         if (!current_node_is_connected(ctdb)) {
517                 return -1;
518         }
519
520         outdata = talloc(mem_ctx, TDB_DATA);
521
522         ret = ctdb_control_get_ifaces(ctdb, NULL, outdata);
523
524         if (ret == 0) {
525                 *ifaces = (struct ctdb_control_get_ifaces *)outdata->dptr;
526         }
527
528         return ret;
529 }
530
531 int ctdb_client_check_message_handlers_stub(struct ctdb_context *ctdb,
532                                             uint64_t *ids, uint32_t num,
533                                             uint8_t *result)
534 {
535         DEBUG(DEBUG_ERR, (__location__ " NOT IMPLEMENTED\n"));
536         return -1;
537 }
538
539 int ctdb_ctrl_getcapabilities_stub(struct ctdb_context *ctdb,
540                                    struct timeval timeout, uint32_t destnode,
541                                    uint32_t *capabilities)
542 {
543         *capabilities = ctdb->nodes[destnode]->capabilities;
544         return 0;
545 }