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
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
)
41 TALLOC_FREE(ctdb
->nodes
);
47 while ((fgets(line
, sizeof(line
), stdin
) != NULL
) &&
49 uint32_t pnn
, flags
, capabilities
;
54 /* Get rid of pesky newline */
55 if ((t
= strchr(line
, '\n')) != NULL
) {
60 tok
= strtok(line
, " \t");
62 DEBUG(DEBUG_ERR
, (__location__
" WARNING, bad line (PNN) ignored \"%s\"\n", line
));
65 pnn
= (uint32_t)strtoul(tok
, NULL
, 0);
68 tok
= strtok(NULL
, " \t");
70 DEBUG(DEBUG_ERR
, (__location__
" WARNING, bad line (no IP) ignored \"%s\"\n", line
));
73 if (!parse_ip(tok
, NULL
, 0, &saddr
)) {
74 DEBUG(DEBUG_ERR
, (__location__
" WARNING, bad line (IP) ignored \"%s\"\n", line
));
77 ip
= talloc_strdup(ctdb
, tok
);
80 tok
= strtok(NULL
, " \t");
82 DEBUG(DEBUG_ERR
, (__location__
" WARNING, bad line (flags) ignored \"%s\"\n", line
));
85 flags
= (uint32_t)strtoul(tok
, NULL
, 0);
86 capabilities
= CTDB_CAP_RECMASTER
|CTDB_CAP_LMASTER
|CTDB_CAP_NATGW
;
88 tok
= strtok(NULL
, " \t");
90 if (strcmp(tok
, "CURRENT") == 0) {
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"));
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"));
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
;
134 void ctdb_test_stubs_print_nodemap(struct ctdb_context
*ctdb
)
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"
149 * :Name:LinkStatus:References:
155 struct ctdb_iface
*prev
, *next
;
161 void ctdb_test_stubs_read_ifaces(struct ctdb_context
*ctdb
)
164 struct ctdb_iface
*iface
;
166 while ((fgets(line
, sizeof(line
), stdin
) != NULL
) &&
170 char *tok
, *t
, *name
;
172 /* Get rid of pesky newline */
173 if ((t
= strchr(line
, '\n')) != NULL
) {
177 if (strcmp(line
, ":Name:LinkStatus:References:") == 0) {
182 //tok = strtok(line, ":"); /* Leading colon... */
183 tok
= strtok(line
, ":");
185 DEBUG(DEBUG_ERR
, (__location__
" WARNING, bad line ignored \"%s\"\n", line
));
191 tok
= strtok(NULL
, ":");
193 DEBUG(DEBUG_ERR
, (__location__
" WARNING, bad line ignored \"%s\"\n", line
));
196 link_state
= (uint16_t)strtoul(tok
, NULL
, 0);
199 tok
= strtok(NULL
, ":");
201 DEBUG(DEBUG_ERR
, (__location__
" WARNING, bad line ignored \"%s\"\n", line
));
204 references
= (uint32_t)strtoul(tok
, NULL
, 0);
206 iface
= talloc_zero(ctdb
, struct ctdb_iface
);
209 DEBUG(DEBUG_ERR
, ("OOM allocating iface\n"));
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",
243 struct ctdb_vnn_map {
249 void ctdb_test_stubs_read_vnnmap(struct ctdb_context
*ctdb
)
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"));
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
) &&
269 /* Get rid of pesky newline */
270 if ((t
= strchr(line
, '\n')) != NULL
) {
274 n
= (uint32_t) strtol(line
, NULL
, 0);
277 if (ctdb
->vnn_map
->generation
== INVALID_GENERATION
) {
278 ctdb
->vnn_map
->generation
= n
;
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"));
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
)
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
)
307 while (fgets(line
, sizeof(line
), stdin
) != NULL
) {
310 /* Get rid of pesky newline */
311 if ((t
= strchr(line
, '\n')) != NULL
) {
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
);
322 printf("Unknown line %s\n", line
);
329 static bool current_node_is_connected (struct ctdb_context
*ctdb
)
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
)) {
343 /* Shouldn't really happen, so fag an error */
349 struct ctdb_context
*ctdb_cmdline_client_stub(struct tevent_context
*ev
,
350 struct timeval req_timeout
)
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
);
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"));
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
;
407 ctdb_ctrl_getnodemap_stub(struct ctdb_context
*ctdb
,
408 struct timeval timeout
, uint32_t destnode
,
410 struct ctdb_node_map
**nodemap
)
417 if (!current_node_is_connected(ctdb
)) {
424 outdata
= talloc_zero(ctdb
, TDB_DATA
);
426 ret
= ctdb_control_getnodemap(ctdb
, CTDB_CONTROL_GET_NODEMAP
,
430 *nodemap
= (struct ctdb_node_map
*) outdata
->dptr
;
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"));
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
);
456 ctdb_ctrl_getrecmode_stub(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
,
457 struct timeval timeout
, uint32_t destnode
,
460 *recmode
= ctdb
->recovery_mode
;
466 ctdb_ctrl_getrecmaster_stub(struct ctdb_context
*ctdb
, TALLOC_CTX
*mem_ctx
,
467 struct timeval timeout
, uint32_t destnode
,
470 *recmaster
= ctdb
->recovery_master
;
476 ctdb_ctrl_getpnn_stub(struct ctdb_context
*ctdb
, struct timeval timeout
,
479 if (!current_node_is_connected(ctdb
)) {
483 if (destnode
== CTDB_CURRENT_NODE
) {
490 /* From ctdb_takeover.c */
491 int32_t ctdb_control_get_ifaces(struct ctdb_context
*ctdb
,
492 struct ctdb_req_control
*c
,
496 struct ctdb_control_get_ifaces
*ifaces
;
497 struct ctdb_iface
*cur
;
499 /* count how many public ip structures we have */
501 for (cur
=ctdb
->ifaces
;cur
;cur
=cur
->next
) {
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
);
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
;
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
;
528 ctdb_ctrl_get_ifaces_stub(struct ctdb_context
*ctdb
,
529 struct timeval timeout
, uint32_t destnode
,
531 struct ctdb_control_get_ifaces
**ifaces
)
536 if (!current_node_is_connected(ctdb
)) {
540 outdata
= talloc(mem_ctx
, TDB_DATA
);
542 ret
= ctdb_control_get_ifaces(ctdb
, NULL
, outdata
);
545 *ifaces
= (struct ctdb_control_get_ifaces
*)outdata
->dptr
;
551 int ctdb_client_check_message_handlers_stub(struct ctdb_context
*ctdb
,
552 uint64_t *ids
, uint32_t num
,
555 DEBUG(DEBUG_ERR
, (__location__
" NOT IMPLEMENTED\n"));
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__ */
567 ("__LOCATION__ control timed out."
568 " reqid:1234567890 opcode:80 dstnode:%d\n", destnode
));
570 ("__LOCATION__ ctdb_control_recv failed\n"));
572 ("__LOCATION__ ctdb_ctrl_getcapabilities_recv failed\n"));
576 if (ctdb
->nodes
[destnode
]->flags
& NODE_FLAGS_DISCONNECTED
) {
578 ("ctdb_control error: 'ctdb_control to disconnected node\n"));
579 /* Placeholder for line#, instead of __location__ */
581 ("__LOCATION__ ctdb_ctrl_getcapabilities_recv failed\n"));
585 *capabilities
= ctdb
->nodes
[destnode
]->capabilities
;
589 /* This is to support testing ctdb xpnn */
591 bool ctdb_sys_have_ip_stub(ctdb_sock_addr
*addr
)
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,
604 if (ctdb_same_ip(addr
, &node_addr
)) {