2 Tests for ctdb_takeover.c
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/>.
22 #include "ctdbd_test.c"
24 /* This is lazy... but it is test code! */
25 #define CTDB_TEST_MAX_NODES 256
27 static void print_ctdb_public_ip_list(struct public_ip_list * ips)
30 printf("%s %d\n", ctdb_addr_to_str(&(ips->addr)), ips->pnn);
35 static uint32_t *get_tunable_values(TALLOC_CTX *tmp_ctx,
38 static enum ctdb_runstate *get_runstate(TALLOC_CTX *tmp_ctx,
41 static void add_ip(TALLOC_CTX *mem_ctx,
42 struct ctdb_public_ip_list *l,
47 l->ip = talloc_realloc(mem_ctx, l->ip,
48 struct ctdb_public_ip, l->num + 1);
49 assert(l->ip != NULL);
51 l->ip[l->num].addr = *addr;
52 l->ip[l->num].pnn = pnn;
56 /* Format of each line is "IP CURRENT_PNN [ALLOWED_PNN,...]".
57 * If multi is true then ALLOWED_PNNs are not allowed. */
58 static void read_ctdb_public_ip_info_node(int numnodes,
60 struct ctdb_public_ip_list **k,
61 struct ctdb_public_ip_list *known)
68 /* Known public IPs */
69 *k = talloc_zero(known, struct ctdb_public_ip_list);
72 while (fgets(line, sizeof(line), stdin) != NULL) {
74 /* Get rid of pesky newline */
75 if ((t = strchr(line, '\n')) != NULL) {
79 /* Exit on an empty line */
80 if (line[0] == '\0') {
84 /* Get the IP address */
85 tok = strtok(line, " \t");
87 DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line ignored :%s\n", line));
91 if (!parse_ip(tok, NULL, 0, &addr)) {
92 DEBUG(DEBUG_ERR, (__location__ " ERROR, bad address :%s\n", tok));
98 tok = strtok(NULL, " \t");
100 pnn = (int) strtol(tok, (char **) NULL, 10);
103 add_ip(*k, *k, &addr, pnn);
105 tok = strtok(NULL, " \t#");
110 /* Handle allowed nodes for addr */
111 assert(multi == false);
112 t = strtok(tok, ",");
114 n = (int) strtol(t, (char **) NULL, 10);
115 add_ip(known, &known[n], &addr, pnn);
116 t = strtok(NULL, ",");
121 static void read_ctdb_public_ip_info(TALLOC_CTX *ctx,
124 struct ctdb_public_ip_list ** known,
125 struct ctdb_public_ip_list ** avail)
128 struct ctdb_public_ip_list * k;
129 enum ctdb_runstate *runstate;
131 *known = talloc_zero_array(ctx, struct ctdb_public_ip_list,
132 CTDB_TEST_MAX_NODES);
133 assert(*known != NULL);
134 *avail = talloc_zero_array(ctx, struct ctdb_public_ip_list,
135 CTDB_TEST_MAX_NODES);
136 assert(*avail != NULL);
139 for (n = 0; n < numnodes; n++) {
140 read_ctdb_public_ip_info_node(numnodes, multi,
146 read_ctdb_public_ip_info_node(numnodes, multi, &k, *known);
148 /* Assign it to any nodes that don't have a list assigned */
149 for (n = 0; n < numnodes; n++) {
150 if ((*known)[n].num == 0) {
156 runstate = get_runstate(ctx, numnodes);
157 for (n = 0; n < numnodes; n++) {
158 if (runstate[n] == CTDB_RUNSTATE_RUNNING) {
159 (*avail)[n] = (*known)[n];
164 static uint32_t *get_tunable_values(TALLOC_CTX *tmp_ctx,
170 uint32_t *tvals = talloc_zero_array(tmp_ctx, uint32_t, numnodes);
171 char *t = getenv(tunable);
174 if (strcmp(t, "1") == 0) {
175 for (i=0; i<numnodes; i++) {
179 tok = strtok(t, ",");
181 while (tok != NULL) {
183 (uint32_t) strtol(tok, NULL, 0);
185 tok = strtok(NULL, ",");
188 fprintf(stderr, "ERROR: Wrong number of values in %s\n", tunable);
197 static enum ctdb_runstate *get_runstate(TALLOC_CTX *tmp_ctx,
202 enum ctdb_runstate *runstate =
203 talloc_zero_array(tmp_ctx, enum ctdb_runstate, numnodes);
204 char *t = getenv("CTDB_TEST_RUNSTATE");
207 for (i=0; i<numnodes; i++) {
208 runstate[i] = CTDB_RUNSTATE_RUNNING;
211 tvals = get_tunable_values(tmp_ctx, numnodes, "CTDB_TEST_RUNSTATE");
212 for (i=0; i<numnodes; i++) {
213 runstate[i] = (enum ctdb_runstate) tvals[i];
221 /* Fake up enough CTDB state to be able to run the IP allocation
222 * algorithm. Usually this sets up some standard state, sets the node
223 * states from the command-line and reads the current IP layout from
226 * However, if read_ips_for_multiple_nodes is true then each node's
227 * idea of the IP layout is read separately from stdin. In this mode
228 * is doesn't make much sense to use read_ctdb_public_ip_info's
229 * optional ALLOWED_PNN,... list in the input, since each node is
230 * being handled separately anyway. IPs for each node are separated
231 * by a blank line. This mode is for testing weird behaviours where
232 * the IP layouts differs across nodes and we want to improve
233 * create_merged_ip_list(), so should only be used in tests of
234 * ipalloc(). Yes, it is a hack... :-)
236 static void ctdb_test_init(const char nodestates[],
237 struct ctdb_context **ctdb,
238 struct ipalloc_state **ipalloc_state,
239 bool read_ips_for_multiple_nodes)
241 struct ctdb_public_ip_list *known;
242 struct ctdb_public_ip_list *avail;
244 uint32_t nodeflags[CTDB_TEST_MAX_NODES];
246 struct ctdb_node_map_old *nodemap;
247 uint32_t *tval_noiptakeover;
248 uint32_t *tval_noiptakeoverondisabled;
250 *ctdb = talloc_zero(NULL, struct ctdb_context);
252 /* Avoid that const */
253 ns = talloc_strdup(*ctdb, nodestates);
256 tok = strtok(ns, ",");
257 while (tok != NULL) {
258 nodeflags[numnodes] = (uint32_t) strtol(tok, NULL, 0);
260 if (numnodes >= CTDB_TEST_MAX_NODES) {
261 DEBUG(DEBUG_ERR, ("ERROR: Exceeding CTDB_TEST_MAX_NODES: %d\n", CTDB_TEST_MAX_NODES));
264 tok = strtok(NULL, ",");
267 /* Fake things up... */
268 (*ctdb)->num_nodes = numnodes;
270 /* Default to LCP2 */
271 (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
272 (*ctdb)->tunable.deterministic_public_ips = 0;
273 (*ctdb)->tunable.disable_ip_failover = 0;
274 (*ctdb)->tunable.no_ip_failback = 0;
276 if ((t = getenv("CTDB_IP_ALGORITHM"))) {
277 if (strcmp(t, "lcp2") == 0) {
278 (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
279 } else if (strcmp(t, "nondet") == 0) {
280 (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
281 } else if (strcmp(t, "det") == 0) {
282 (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
283 (*ctdb)->tunable.deterministic_public_ips = 1;
285 fprintf(stderr, "ERROR: unknown IP algorithm %s\n", t);
290 tval_noiptakeover = get_tunable_values(*ctdb, numnodes,
291 "CTDB_SET_NoIPTakeover");
292 tval_noiptakeoverondisabled =
293 get_tunable_values(*ctdb, numnodes,
294 "CTDB_SET_NoIPHostOnAllDisabled");
296 nodemap = talloc_array(*ctdb, struct ctdb_node_map_old, numnodes);
297 nodemap->num = numnodes;
299 (*ctdb)->nodes = talloc_array(*ctdb, struct ctdb_node *, numnodes); // FIXME: bogus size, overkill
301 *ipalloc_state = ipalloc_state_init(*ctdb, *ctdb);
303 read_ctdb_public_ip_info(*ctdb, numnodes,
304 read_ips_for_multiple_nodes,
307 for (i=0; i < numnodes; i++) {
308 nodemap->nodes[i].pnn = i;
309 nodemap->nodes[i].flags = nodeflags[i];
310 /* nodemap->nodes[i].sockaddr is uninitialised */
312 (*ctdb)->nodes[i] = talloc(*ctdb, struct ctdb_node);
313 (*ctdb)->nodes[i]->pnn = i;
314 (*ctdb)->nodes[i]->flags = nodeflags[i];
316 (*ipalloc_state)->available_public_ips[i] = avail[i];
317 (*ipalloc_state)->known_public_ips[i] = known[i];
320 set_ipflags_internal(*ipalloc_state, nodemap,
322 tval_noiptakeoverondisabled);
324 (*ipalloc_state)->all_ips = create_merged_ip_list(*ctdb,
327 (*ipalloc_state)->force_rebalance_nodes = NULL;
330 /* IP layout is read from stdin. See comment for ctdb_test_init() for
331 * explanation of read_ips_for_multiple_nodes.
333 static void ctdb_test_ipalloc(const char nodestates[],
334 bool read_ips_for_multiple_nodes)
336 struct ctdb_context *ctdb;
337 struct ipalloc_state *ipalloc_state;
339 ctdb_test_init(nodestates, &ctdb, &ipalloc_state,
340 read_ips_for_multiple_nodes);
342 ipalloc(ipalloc_state);
344 print_ctdb_public_ip_list(ipalloc_state->all_ips);
349 static void usage(void)
351 fprintf(stderr, "usage: ctdb_takeover_tests <op>\n");
355 int main(int argc, const char *argv[])
357 DEBUGLEVEL = DEBUG_DEBUG;
358 if (getenv("CTDB_TEST_LOGLEVEL")) {
359 DEBUGLEVEL = atoi(getenv("CTDB_TEST_LOGLEVEL"));
367 strcmp(argv[1], "ipalloc") == 0) {
368 ctdb_test_ipalloc(argv[2], false);
369 } else if (argc == 4 &&
370 strcmp(argv[1], "ipalloc") == 0 &&
371 strcmp(argv[3], "multi") == 0) {
372 ctdb_test_ipalloc(argv[2], true);