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,...".
59 read_ctdb_public_ip_info(TALLOC_CTX *ctx ,
61 struct ctdb_public_ip_list ** known,
62 struct ctdb_public_ip_list ** avail)
68 struct ctdb_public_ip_list * k;
70 enum ctdb_runstate *runstate;
72 runstate = get_runstate(ctx, numnodes);
74 *known = talloc_zero_array(ctx, struct ctdb_public_ip_list,
76 *avail = talloc_zero_array(ctx, struct ctdb_public_ip_list,
79 /* Known public IPs */
80 k = talloc_zero(ctx, struct ctdb_public_ip_list);
83 while (fgets(line, sizeof(line), stdin) != NULL) {
85 /* Get rid of pesky newline */
86 if ((t = strchr(line, '\n')) != NULL) {
90 /* Exit on an empty line */
91 if (line[0] == '\0') {
95 /* Get the IP address */
96 tok = strtok(line, " \t");
98 DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line ignored :%s\n", line));
102 if (!parse_ip(tok, NULL, 0, &addr)) {
103 DEBUG(DEBUG_ERR, (__location__ " ERROR, bad address :%s\n", tok));
109 tok = strtok(NULL, " \t");
111 pnn = (int) strtol(tok, (char **) NULL, 10);
114 add_ip(k, k, &addr, pnn);
116 tok = strtok(NULL, " \t#");
121 /* Handle allowed nodes for addr */
122 t = strtok(tok, ",");
124 n = (int) strtol(t, (char **) NULL, 10);
125 add_ip(*known, &(*known)[n], &addr, pnn);
126 t = strtok(NULL, ",");
131 /* Assign it to any nodes that don't have a list assigned */
132 for (n = 0; n < numnodes; n++) {
133 if ((*known)[n].num == 0) {
136 if (runstate[n] == CTDB_RUNSTATE_RUNNING) {
137 (*avail)[n] = (*known)[n];
144 static uint32_t *get_tunable_values(TALLOC_CTX *tmp_ctx,
150 uint32_t *tvals = talloc_zero_array(tmp_ctx, uint32_t, numnodes);
151 char *t = getenv(tunable);
154 if (strcmp(t, "1") == 0) {
155 for (i=0; i<numnodes; i++) {
159 tok = strtok(t, ",");
161 while (tok != NULL) {
163 (uint32_t) strtol(tok, NULL, 0);
165 tok = strtok(NULL, ",");
168 fprintf(stderr, "ERROR: Wrong number of values in %s\n", tunable);
177 static enum ctdb_runstate *get_runstate(TALLOC_CTX *tmp_ctx,
182 enum ctdb_runstate *runstate =
183 talloc_zero_array(tmp_ctx, enum ctdb_runstate, numnodes);
184 char *t = getenv("CTDB_TEST_RUNSTATE");
187 for (i=0; i<numnodes; i++) {
188 runstate[i] = CTDB_RUNSTATE_RUNNING;
191 tvals = get_tunable_values(tmp_ctx, numnodes, "CTDB_TEST_RUNSTATE");
192 for (i=0; i<numnodes; i++) {
193 runstate[i] = (enum ctdb_runstate) tvals[i];
201 /* Fake up enough CTDB state to be able to run the IP allocation
202 * algorithm. Usually this sets up some standard state, sets the node
203 * states from the command-line and reads the current IP layout from
206 * However, if read_ips_for_multiple_nodes is true then each node's
207 * idea of the IP layout is read separately from stdin. In this mode
208 * is doesn't make much sense to use read_ctdb_public_ip_info's
209 * optional ALLOWED_PNN,... list in the input, since each node is
210 * being handled separately anyway. IPs for each node are separated
211 * by a blank line. This mode is for testing weird behaviours where
212 * the IP layouts differs across nodes and we want to improve
213 * create_merged_ip_list(), so should only be used in tests of
214 * ipalloc(). Yes, it is a hack... :-)
216 static void ctdb_test_init(const char nodestates[],
217 struct ctdb_context **ctdb,
218 struct ipalloc_state **ipalloc_state,
219 bool read_ips_for_multiple_nodes)
221 struct ctdb_public_ip_list *known;
222 struct ctdb_public_ip_list *avail;
224 uint32_t nodeflags[CTDB_TEST_MAX_NODES];
226 struct ctdb_node_map_old *nodemap;
227 uint32_t *tval_noiptakeover;
228 uint32_t *tval_noiptakeoverondisabled;
230 *ctdb = talloc_zero(NULL, struct ctdb_context);
232 /* Avoid that const */
233 ns = talloc_strdup(*ctdb, nodestates);
236 tok = strtok(ns, ",");
237 while (tok != NULL) {
238 nodeflags[numnodes] = (uint32_t) strtol(tok, NULL, 0);
240 if (numnodes >= CTDB_TEST_MAX_NODES) {
241 DEBUG(DEBUG_ERR, ("ERROR: Exceeding CTDB_TEST_MAX_NODES: %d\n", CTDB_TEST_MAX_NODES));
244 tok = strtok(NULL, ",");
247 /* Fake things up... */
248 (*ctdb)->num_nodes = numnodes;
250 /* Default to LCP2 */
251 (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
252 (*ctdb)->tunable.deterministic_public_ips = 0;
253 (*ctdb)->tunable.disable_ip_failover = 0;
254 (*ctdb)->tunable.no_ip_failback = 0;
256 if ((t = getenv("CTDB_IP_ALGORITHM"))) {
257 if (strcmp(t, "lcp2") == 0) {
258 (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
259 } else if (strcmp(t, "nondet") == 0) {
260 (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
261 } else if (strcmp(t, "det") == 0) {
262 (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
263 (*ctdb)->tunable.deterministic_public_ips = 1;
265 fprintf(stderr, "ERROR: unknown IP algorithm %s\n", t);
270 tval_noiptakeover = get_tunable_values(*ctdb, numnodes,
271 "CTDB_SET_NoIPTakeover");
272 tval_noiptakeoverondisabled =
273 get_tunable_values(*ctdb, numnodes,
274 "CTDB_SET_NoIPHostOnAllDisabled");
276 nodemap = talloc_array(*ctdb, struct ctdb_node_map_old, numnodes);
277 nodemap->num = numnodes;
279 if (!read_ips_for_multiple_nodes) {
280 read_ctdb_public_ip_info(*ctdb, numnodes,
284 (*ctdb)->nodes = talloc_array(*ctdb, struct ctdb_node *, numnodes); // FIXME: bogus size, overkill
286 *ipalloc_state = ipalloc_state_init(*ctdb, *ctdb);
288 for (i=0; i < numnodes; i++) {
289 nodemap->nodes[i].pnn = i;
290 nodemap->nodes[i].flags = nodeflags[i];
291 /* nodemap->nodes[i].sockaddr is uninitialised */
293 if (read_ips_for_multiple_nodes) {
294 read_ctdb_public_ip_info(*ctdb, numnodes,
298 (*ctdb)->nodes[i] = talloc(*ctdb, struct ctdb_node);
299 (*ctdb)->nodes[i]->pnn = i;
300 (*ctdb)->nodes[i]->flags = nodeflags[i];
302 (*ipalloc_state)->available_public_ips[i] = avail[i];
303 (*ipalloc_state)->known_public_ips[i] = known[i];
306 set_ipflags_internal(*ipalloc_state, nodemap,
308 tval_noiptakeoverondisabled);
310 (*ipalloc_state)->all_ips = create_merged_ip_list(*ctdb,
313 (*ipalloc_state)->force_rebalance_nodes = NULL;
316 /* IP layout is read from stdin. See comment for ctdb_test_init() for
317 * explanation of read_ips_for_multiple_nodes.
319 static void ctdb_test_ipalloc(const char nodestates[],
320 bool read_ips_for_multiple_nodes)
322 struct ctdb_context *ctdb;
323 struct ipalloc_state *ipalloc_state;
325 ctdb_test_init(nodestates, &ctdb, &ipalloc_state,
326 read_ips_for_multiple_nodes);
328 ipalloc(ipalloc_state);
330 print_ctdb_public_ip_list(ipalloc_state->all_ips);
335 static void usage(void)
337 fprintf(stderr, "usage: ctdb_takeover_tests <op>\n");
341 int main(int argc, const char *argv[])
343 DEBUGLEVEL = DEBUG_DEBUG;
344 if (getenv("CTDB_TEST_LOGLEVEL")) {
345 DEBUGLEVEL = atoi(getenv("CTDB_TEST_LOGLEVEL"));
353 strcmp(argv[1], "ipalloc") == 0) {
354 ctdb_test_ipalloc(argv[2], false);
355 } else if (argc == 4 &&
356 strcmp(argv[1], "ipalloc") == 0 &&
357 strcmp(argv[3], "multi") == 0) {
358 ctdb_test_ipalloc(argv[2], true);