ctdb-tools-ctdb: Make natgwlist and lvsmaster more resilient
[Samba.git] / ctdb / tests / src / ctdb_test_stubs.c
blobd36fe815678c73efd5295103d01e98e817c56928
1 /*
2 Test stubs and support functions for some CTDB client functions
4 Copyright (C) Martin Schwenke 2011
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.
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.
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/>.
20 /* Useful for functions that don't get struct ctdb_context passed */
21 static struct ctdb_context *ctdb_global;
23 /* Read a nodemap from stdin. Each line looks like:
24 * <PNN> <FLAGS> [RECMASTER] [CURRENT] [CAPABILITIES]
25 * EOF or a blank line terminates input.
27 * By default, capablities for each node are
28 * CTDB_CAP_RECMASTER|CTDB_CAP_LMASTER|CTDB_CAP_NATGW. These 3
29 * capabilities can be faked off by adding, for example,
30 * -CTDB_CAP_RECMASTER. LVS can be faked on by adding
31 * CTDB_CAP_LVS.
34 /* A fake flag that is only supported by some functions */
35 #define NODE_FLAGS_FAKE_TIMEOUT 0x80000000
37 void ctdb_test_stubs_read_nodemap(struct ctdb_context *ctdb)
39 char line[1024];
41 TALLOC_FREE(ctdb->nodes);
42 ctdb->pnn = -1;
43 ctdb->num_nodes = 0;
45 ctdb->nodes = NULL;
47 while ((fgets(line, sizeof(line), stdin) != NULL) &&
48 (line[0] != '\n')) {
49 uint32_t pnn, flags, capabilities;
50 char *tok, *t;
51 const char *ip;
52 ctdb_sock_addr saddr;
54 /* Get rid of pesky newline */
55 if ((t = strchr(line, '\n')) != NULL) {
56 *t = '\0';
59 /* Get PNN */
60 tok = strtok(line, " \t");
61 if (tok == NULL) {
62 DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line (PNN) ignored \"%s\"\n", line));
63 continue;
65 pnn = (uint32_t)strtoul(tok, NULL, 0);
67 /* Get IP */
68 tok = strtok(NULL, " \t");
69 if (tok == NULL) {
70 DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line (no IP) ignored \"%s\"\n", line));
71 continue;
73 if (!parse_ip(tok, NULL, 0, &saddr)) {
74 DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line (IP) ignored \"%s\"\n", line));
75 continue;
77 ip = talloc_strdup(ctdb, tok);
79 /* Get flags */
80 tok = strtok(NULL, " \t");
81 if (tok == NULL) {
82 DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line (flags) ignored \"%s\"\n", line));
83 continue;
85 flags = (uint32_t)strtoul(tok, NULL, 0);
86 capabilities = CTDB_CAP_RECMASTER|CTDB_CAP_LMASTER|CTDB_CAP_NATGW;
88 tok = strtok(NULL, " \t");
89 while (tok != NULL) {
90 if (strcmp(tok, "CURRENT") == 0) {
91 ctdb->pnn = pnn;
92 } else if (strcmp(tok, "RECMASTER") == 0) {
93 ctdb->recovery_master = pnn;
94 } else if (strcmp(tok, "-CTDB_CAP_RECMASTER") == 0) {
95 capabilities &= ~CTDB_CAP_RECMASTER;
96 } else if (strcmp(tok, "-CTDB_CAP_LMASTER") == 0) {
97 capabilities &= ~CTDB_CAP_LMASTER;
98 } else if (strcmp(tok, "-CTDB_CAP_NATGW") == 0) {
99 capabilities &= ~CTDB_CAP_NATGW;
100 } else if (strcmp(tok, "CTDB_CAP_LVS") == 0) {
101 capabilities |= CTDB_CAP_LVS;
102 } else if (strcmp(tok, "TIMEOUT") == 0) {
103 /* This can be done with just a flag
104 * value but it is probably clearer
105 * and less error-prone to fake this
106 * with an explicit token */
107 flags |= NODE_FLAGS_FAKE_TIMEOUT;
109 tok = strtok(NULL, " \t");
112 ctdb->nodes = talloc_realloc(ctdb, ctdb->nodes, struct ctdb_node *, ctdb->num_nodes + 1);
113 if (ctdb->nodes == NULL) {
114 DEBUG(DEBUG_ERR, ("OOM allocating nodes array\n"));
115 exit (1);
117 ctdb->nodes[ctdb->num_nodes] = talloc_zero(ctdb, struct ctdb_node);
118 if (ctdb->nodes[ctdb->num_nodes] == NULL) {
119 DEBUG(DEBUG_ERR, ("OOM allocating node structure\n"));
120 exit (1);
123 ctdb->nodes[ctdb->num_nodes]->ctdb = ctdb;
124 ctdb->nodes[ctdb->num_nodes]->name = "fakectdb";
125 ctdb->nodes[ctdb->num_nodes]->pnn = pnn;
126 ctdb->nodes[ctdb->num_nodes]->address.address = ip;
127 ctdb->nodes[ctdb->num_nodes]->address.port = 0;
128 ctdb->nodes[ctdb->num_nodes]->flags = flags;
129 ctdb->nodes[ctdb->num_nodes]->capabilities = capabilities;
130 ctdb->num_nodes++;
134 void ctdb_test_stubs_print_nodemap(struct ctdb_context *ctdb)
136 int i;
138 for (i = 0; i < ctdb->num_nodes; i++) {
139 printf("%ld\t0x%lx%s%s\n",
140 (unsigned long) ctdb->nodes[i]->pnn,
141 (unsigned long) ctdb->nodes[i]->flags,
142 ctdb->nodes[i]->pnn == ctdb->pnn ? "\tCURRENT" : "",
143 ctdb->nodes[i]->pnn == ctdb->recovery_master ? "\tRECMASTER" : "");
147 /* Read interfaces information. Same format as "ctdb ifaces -Y"
148 * output:
149 * :Name:LinkStatus:References:
150 * :eth2:1:4294967294
151 * :eth1:1:4294967292
154 struct ctdb_iface {
155 struct ctdb_iface *prev, *next;
156 const char *name;
157 bool link_up;
158 uint32_t references;
161 void ctdb_test_stubs_read_ifaces(struct ctdb_context *ctdb)
163 char line[1024];
164 struct ctdb_iface *iface;
166 while ((fgets(line, sizeof(line), stdin) != NULL) &&
167 (line[0] != '\n')) {
168 uint16_t link_state;
169 uint32_t references;
170 char *tok, *t, *name;
172 /* Get rid of pesky newline */
173 if ((t = strchr(line, '\n')) != NULL) {
174 *t = '\0';
177 if (strcmp(line, ":Name:LinkStatus:References:") == 0) {
178 continue;
181 /* name */
182 //tok = strtok(line, ":"); /* Leading colon... */
183 tok = strtok(line, ":");
184 if (tok == NULL) {
185 DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line ignored \"%s\"\n", line));
186 continue;
188 name = tok;
190 /* link_state */
191 tok = strtok(NULL, ":");
192 if (tok == NULL) {
193 DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line ignored \"%s\"\n", line));
194 continue;
196 link_state = (uint16_t)strtoul(tok, NULL, 0);
198 /* references... */
199 tok = strtok(NULL, ":");
200 if (tok == NULL) {
201 DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line ignored \"%s\"\n", line));
202 continue;
204 references = (uint32_t)strtoul(tok, NULL, 0);
206 iface = talloc_zero(ctdb, struct ctdb_iface);
208 if (iface == NULL) {
209 DEBUG(DEBUG_ERR, ("OOM allocating iface\n"));
210 exit (1);
213 iface->name = talloc_strdup(iface, name);
214 iface->link_up = link_state;
215 iface->references = references;
217 DLIST_ADD(ctdb->ifaces, iface);
221 void ctdb_test_stubs_print_ifaces(struct ctdb_context *ctdb)
223 struct ctdb_iface *iface;
225 printf(":Name:LinkStatus:References:\n");
226 for (iface = ctdb->ifaces; iface != NULL; iface = iface->next) {
227 printf(":%s:%u:%u:\n",
228 iface->name,
229 iface->link_up,
230 iface->references);
234 /* Read vnn map.
235 * output:
236 * <GENERATION>
237 * <LMASTER0>
238 * <LMASTER1>
239 * ...
243 struct ctdb_vnn_map {
244 uint32_t generation;
245 uint32_t size;
246 uint32_t *map;
249 void ctdb_test_stubs_read_vnnmap(struct ctdb_context *ctdb)
251 char line[1024];
253 TALLOC_FREE(ctdb->vnn_map);
255 ctdb->vnn_map = talloc_zero(ctdb, struct ctdb_vnn_map);
256 if (ctdb->vnn_map == NULL) {
257 DEBUG(DEBUG_ERR, ("OOM allocating vnnmap\n"));
258 exit (1);
260 ctdb->vnn_map->generation = INVALID_GENERATION;
261 ctdb->vnn_map->size = 0;
262 ctdb->vnn_map->map = NULL;
264 while ((fgets(line, sizeof(line), stdin) != NULL) &&
265 (line[0] != '\n')) {
266 uint32_t n;
267 char *t;
269 /* Get rid of pesky newline */
270 if ((t = strchr(line, '\n')) != NULL) {
271 *t = '\0';
274 n = (uint32_t) strtol(line, NULL, 0);
276 /* generation */
277 if (ctdb->vnn_map->generation == INVALID_GENERATION) {
278 ctdb->vnn_map->generation = n;
279 continue;
282 ctdb->vnn_map->map = talloc_realloc(ctdb, ctdb->vnn_map->map, uint32_t, ctdb->vnn_map->size + 1);
283 if (ctdb->vnn_map->map == NULL) {
284 DEBUG(DEBUG_ERR, ("OOM allocating vnn_map->map\n"));
285 exit (1);
288 ctdb->vnn_map->map[ctdb->vnn_map->size] = n;
289 ctdb->vnn_map->size++;
293 void ctdb_test_stubs_print_vnnmap(struct ctdb_context *ctdb)
295 int i;
297 printf("%d\n", ctdb->vnn_map->generation);
298 for (i = 0; i < ctdb->vnn_map->size; i++) {
299 printf("%d\n", ctdb->vnn_map->map[i]);
303 void ctdb_test_stubs_fake_setup(struct ctdb_context *ctdb)
305 char line[1024];
307 while (fgets(line, sizeof(line), stdin) != NULL) {
308 char *t;
310 /* Get rid of pesky newline */
311 if ((t = strchr(line, '\n')) != NULL) {
312 *t = '\0';
315 if (strcmp(line, "NODEMAP") == 0) {
316 ctdb_test_stubs_read_nodemap(ctdb);
317 } else if (strcmp(line, "IFACES") == 0) {
318 ctdb_test_stubs_read_ifaces(ctdb);
319 } else if (strcmp(line, "VNNMAP") == 0) {
320 ctdb_test_stubs_read_vnnmap(ctdb);
321 } else {
322 printf("Unknown line %s\n", line);
323 exit(1);
328 /* Support... */
329 static bool current_node_is_connected (struct ctdb_context *ctdb)
331 int i;
332 for (i = 0; i < ctdb->num_nodes; i++) {
333 if (ctdb->nodes[i]->pnn == ctdb->pnn) {
334 if (ctdb->nodes[i]->flags &
335 (NODE_FLAGS_DISCONNECTED | NODE_FLAGS_DELETED)) {
336 return false;
337 } else {
338 return true;
343 /* Shouldn't really happen, so fag an error */
344 return false;
347 /* Stubs... */
349 struct ctdb_context *ctdb_cmdline_client_stub(struct tevent_context *ev,
350 struct timeval req_timeout)
352 return ctdb_global;
355 struct tevent_context *tevent_context_init_stub(TALLOC_CTX *mem_ctx)
357 struct ctdb_context *ctdb;
359 ctdb = talloc_zero(NULL, struct ctdb_context);
361 ctdb_set_socketname(ctdb, "fake");
363 ctdb_test_stubs_fake_setup(ctdb);
365 ctdb_global = ctdb;
367 return tevent_context_init_byname(mem_ctx, NULL);
370 /* Copied from ctdb_recover.c */
372 ctdb_control_getnodemap(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata, TDB_DATA *outdata)
374 uint32_t i, num_nodes;
375 struct ctdb_node_map *node_map;
377 CHECK_CONTROL_DATA_SIZE(0);
379 num_nodes = ctdb->num_nodes;
381 outdata->dsize = offsetof(struct ctdb_node_map, nodes) + num_nodes*sizeof(struct ctdb_node_and_flags);
382 outdata->dptr = (unsigned char *)talloc_zero_size(outdata, outdata->dsize);
383 if (!outdata->dptr) {
384 DEBUG(DEBUG_ALERT, (__location__ " Failed to allocate nodemap array\n"));
385 exit(1);
388 node_map = (struct ctdb_node_map *)outdata->dptr;
389 node_map->num = num_nodes;
390 for (i=0; i<num_nodes; i++) {
391 if (parse_ip(ctdb->nodes[i]->address.address,
392 NULL, /* TODO: pass in the correct interface here*/
394 &node_map->nodes[i].addr) == 0)
396 DEBUG(DEBUG_ERR, (__location__ " Failed to parse %s into a sockaddr\n", ctdb->nodes[i]->address.address));
399 node_map->nodes[i].pnn = ctdb->nodes[i]->pnn;
400 node_map->nodes[i].flags = ctdb->nodes[i]->flags;
403 return 0;
407 ctdb_ctrl_getnodemap_stub(struct ctdb_context *ctdb,
408 struct timeval timeout, uint32_t destnode,
409 TALLOC_CTX *mem_ctx,
410 struct ctdb_node_map **nodemap)
412 int ret;
414 TDB_DATA indata;
415 TDB_DATA *outdata;
417 if (!current_node_is_connected(ctdb)) {
418 return -1;
421 indata.dsize = 0;
422 indata.dptr = NULL;
424 outdata = talloc_zero(ctdb, TDB_DATA);
426 ret = ctdb_control_getnodemap(ctdb, CTDB_CONTROL_GET_NODEMAP,
427 indata, outdata);
429 if (ret == 0) {
430 *nodemap = (struct ctdb_node_map *) outdata->dptr;
433 return ret;
437 ctdb_ctrl_getvnnmap_stub(struct ctdb_context *ctdb,
438 struct timeval timeout, uint32_t destnode,
439 TALLOC_CTX *mem_ctx, struct ctdb_vnn_map **vnnmap)
441 *vnnmap = talloc(ctdb, struct ctdb_vnn_map);
442 if (*vnnmap == NULL) {
443 DEBUG(DEBUG_ERR, (__location__ "OOM\n"));
444 exit (1);
446 (*vnnmap)->map = talloc_array(*vnnmap, uint32_t, ctdb->vnn_map->size);
448 (*vnnmap)->generation = ctdb->vnn_map->generation;
449 (*vnnmap)->size = ctdb->vnn_map->size;
450 memcpy((*vnnmap)->map, ctdb->vnn_map->map, sizeof(uint32_t) * (*vnnmap)->size);
452 return 0;
456 ctdb_ctrl_getrecmode_stub(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
457 struct timeval timeout, uint32_t destnode,
458 uint32_t *recmode)
460 *recmode = ctdb->recovery_mode;
462 return 0;
466 ctdb_ctrl_getrecmaster_stub(struct ctdb_context *ctdb, TALLOC_CTX *mem_ctx,
467 struct timeval timeout, uint32_t destnode,
468 uint32_t *recmaster)
470 *recmaster = ctdb->recovery_master;
472 return 0;
476 ctdb_ctrl_getpnn_stub(struct ctdb_context *ctdb, struct timeval timeout,
477 uint32_t destnode)
479 if (!current_node_is_connected(ctdb)) {
480 return -1;
483 if (destnode == CTDB_CURRENT_NODE) {
484 return ctdb->pnn;
485 } else {
486 return destnode;
490 /* From ctdb_takeover.c */
491 int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb,
492 struct ctdb_req_control *c,
493 TDB_DATA *outdata)
495 int i, num, len;
496 struct ctdb_control_get_ifaces *ifaces;
497 struct ctdb_iface *cur;
499 /* count how many public ip structures we have */
500 num = 0;
501 for (cur=ctdb->ifaces;cur;cur=cur->next) {
502 num++;
505 len = offsetof(struct ctdb_control_get_ifaces, ifaces) +
506 num*sizeof(struct ctdb_control_iface_info);
507 ifaces = talloc_zero_size(outdata, len);
508 CTDB_NO_MEMORY(ctdb, ifaces);
510 i = 0;
511 for (cur=ctdb->ifaces;cur;cur=cur->next) {
512 strcpy(ifaces->ifaces[i].name, cur->name);
513 ifaces->ifaces[i].link_state = cur->link_up;
514 ifaces->ifaces[i].references = cur->references;
515 i++;
517 ifaces->num = i;
518 len = offsetof(struct ctdb_control_get_ifaces, ifaces) +
519 i*sizeof(struct ctdb_control_iface_info);
521 outdata->dsize = len;
522 outdata->dptr = (uint8_t *)ifaces;
524 return 0;
528 ctdb_ctrl_get_ifaces_stub(struct ctdb_context *ctdb,
529 struct timeval timeout, uint32_t destnode,
530 TALLOC_CTX *mem_ctx,
531 struct ctdb_control_get_ifaces **ifaces)
533 TDB_DATA *outdata;
534 int ret;
536 if (!current_node_is_connected(ctdb)) {
537 return -1;
540 outdata = talloc(mem_ctx, TDB_DATA);
542 ret = ctdb_control_get_ifaces(ctdb, NULL, outdata);
544 if (ret == 0) {
545 *ifaces = (struct ctdb_control_get_ifaces *)outdata->dptr;
548 return ret;
551 int ctdb_client_check_message_handlers_stub(struct ctdb_context *ctdb,
552 uint64_t *ids, uint32_t num,
553 uint8_t *result)
555 DEBUG(DEBUG_ERR, (__location__ " NOT IMPLEMENTED\n"));
556 return -1;
559 int ctdb_ctrl_getcapabilities_stub(struct ctdb_context *ctdb,
560 struct timeval timeout, uint32_t destnode,
561 uint32_t *capabilities)
564 if (ctdb->nodes[destnode]->flags & NODE_FLAGS_FAKE_TIMEOUT) {
565 /* Placeholder for line#, instead of __location__ */
566 DEBUG(DEBUG_ERR,
567 ("__LOCATION__ control timed out."
568 " reqid:1234567890 opcode:80 dstnode:%d\n", destnode));
569 DEBUG(DEBUG_ERR,
570 ("__LOCATION__ ctdb_control_recv failed\n"));
571 DEBUG(DEBUG_ERR,
572 ("__LOCATION__ ctdb_ctrl_getcapabilities_recv failed\n"));
573 return -1;
576 if (ctdb->nodes[destnode]->flags & NODE_FLAGS_DISCONNECTED) {
577 DEBUG(DEBUG_ERR,
578 ("ctdb_control error: 'ctdb_control to disconnected node\n"));
579 /* Placeholder for line#, instead of __location__ */
580 DEBUG(DEBUG_ERR,
581 ("__LOCATION__ ctdb_ctrl_getcapabilities_recv failed\n"));
582 return -1;
585 *capabilities = ctdb->nodes[destnode]->capabilities;
586 return 0;
589 /* This is to support testing ctdb xpnn */
591 bool ctdb_sys_have_ip_stub(ctdb_sock_addr *addr)
593 int i;
594 struct ctdb_context *ctdb = ctdb_global;
596 for (i = 0; i < ctdb->num_nodes; i++) {
597 ctdb_sock_addr node_addr;
599 if (ctdb->pnn == ctdb->nodes[i]->pnn) {
600 if (!parse_ip(ctdb->nodes[i]->address.address, NULL, 0,
601 &node_addr)) {
602 continue;
604 if (ctdb_same_ip(addr, &node_addr)) {
605 return true;
610 return false;