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 static void print_ctdb_public_ip_list(struct public_ip_list * ips)
27 printf("%s %d\n", ctdb_addr_to_str(&(ips->addr)), ips->pnn);
32 static uint32_t *get_tunable_values(TALLOC_CTX *tmp_ctx,
35 static enum ctdb_runstate *get_runstate(TALLOC_CTX *tmp_ctx,
38 static void add_ip(TALLOC_CTX *mem_ctx,
39 struct ctdb_public_ip_list *l,
44 l->ip = talloc_realloc(mem_ctx, l->ip,
45 struct ctdb_public_ip, l->num + 1);
46 assert(l->ip != NULL);
48 l->ip[l->num].addr = *addr;
49 l->ip[l->num].pnn = pnn;
53 /* Format of each line is "IP CURRENT_PNN [ALLOWED_PNN,...]".
54 * If multi is true then ALLOWED_PNNs are not allowed. */
55 static void read_ctdb_public_ip_info_node(int numnodes,
57 struct ctdb_public_ip_list **k,
58 struct ctdb_public_ip_list *known)
65 /* Known public IPs */
66 *k = talloc_zero(known, struct ctdb_public_ip_list);
69 while (fgets(line, sizeof(line), stdin) != NULL) {
71 /* Get rid of pesky newline */
72 if ((t = strchr(line, '\n')) != NULL) {
76 /* Exit on an empty line */
77 if (line[0] == '\0') {
81 /* Get the IP address */
82 tok = strtok(line, " \t");
84 DEBUG(DEBUG_ERR, (__location__ " WARNING, bad line ignored :%s\n", line));
88 if (!parse_ip(tok, NULL, 0, &addr)) {
89 DEBUG(DEBUG_ERR, (__location__ " ERROR, bad address :%s\n", tok));
95 tok = strtok(NULL, " \t");
97 pnn = (int) strtol(tok, (char **) NULL, 10);
100 add_ip(*k, *k, &addr, pnn);
102 tok = strtok(NULL, " \t#");
107 /* Handle allowed nodes for addr */
108 assert(multi == false);
109 t = strtok(tok, ",");
111 n = (int) strtol(t, (char **) NULL, 10);
112 add_ip(known, &known[n], &addr, pnn);
113 t = strtok(NULL, ",");
118 static void read_ctdb_public_ip_info(TALLOC_CTX *ctx,
121 struct ctdb_public_ip_list ** known,
122 struct ctdb_public_ip_list ** avail)
125 struct ctdb_public_ip_list * k;
126 enum ctdb_runstate *runstate;
128 *known = talloc_zero_array(ctx, struct ctdb_public_ip_list,
130 assert(*known != NULL);
131 *avail = talloc_zero_array(ctx, struct ctdb_public_ip_list,
133 assert(*avail != NULL);
136 for (n = 0; n < numnodes; n++) {
137 read_ctdb_public_ip_info_node(numnodes, multi,
143 read_ctdb_public_ip_info_node(numnodes, multi, &k, *known);
145 /* Assign it to any nodes that don't have a list assigned */
146 for (n = 0; n < numnodes; n++) {
147 if ((*known)[n].num == 0) {
153 runstate = get_runstate(ctx, numnodes);
154 for (n = 0; n < numnodes; n++) {
155 if (runstate[n] == CTDB_RUNSTATE_RUNNING) {
156 (*avail)[n] = (*known)[n];
161 static uint32_t *get_tunable_values(TALLOC_CTX *tmp_ctx,
167 uint32_t *tvals = talloc_zero_array(tmp_ctx, uint32_t, numnodes);
168 char *t = getenv(tunable);
171 if (strcmp(t, "1") == 0) {
172 for (i=0; i<numnodes; i++) {
176 tok = strtok(t, ",");
178 while (tok != NULL) {
180 (uint32_t) strtol(tok, NULL, 0);
182 tok = strtok(NULL, ",");
185 fprintf(stderr, "ERROR: Wrong number of values in %s\n", tunable);
194 static enum ctdb_runstate *get_runstate(TALLOC_CTX *tmp_ctx,
199 enum ctdb_runstate *runstate =
200 talloc_zero_array(tmp_ctx, enum ctdb_runstate, numnodes);
201 char *t = getenv("CTDB_TEST_RUNSTATE");
204 for (i=0; i<numnodes; i++) {
205 runstate[i] = CTDB_RUNSTATE_RUNNING;
208 tvals = get_tunable_values(tmp_ctx, numnodes, "CTDB_TEST_RUNSTATE");
209 for (i=0; i<numnodes; i++) {
210 runstate[i] = (enum ctdb_runstate) tvals[i];
218 /* Fake up enough CTDB state to be able to run the IP allocation
219 * algorithm. Usually this sets up some standard state, sets the node
220 * states from the command-line and reads the current IP layout from
223 * However, if read_ips_for_multiple_nodes is true then each node's
224 * idea of the IP layout is read separately from stdin. In this mode
225 * is doesn't make much sense to use read_ctdb_public_ip_info's
226 * optional ALLOWED_PNN,... list in the input, since each node is
227 * being handled separately anyway. IPs for each node are separated
228 * by a blank line. This mode is for testing weird behaviours where
229 * the IP layouts differs across nodes and we want to improve
230 * create_merged_ip_list(), so should only be used in tests of
231 * ipalloc(). Yes, it is a hack... :-)
233 static void ctdb_test_init(const char nodestates[],
234 struct ctdb_context **ctdb,
235 struct ipalloc_state **ipalloc_state,
236 bool read_ips_for_multiple_nodes)
238 struct ctdb_public_ip_list *known;
239 struct ctdb_public_ip_list *avail;
242 struct ctdb_node_map *nodemap;
243 uint32_t *tval_noiptakeover;
244 uint32_t *tval_noiptakeoverondisabled;
245 ctdb_sock_addr sa_zero = { .ip = { 0 } };
247 *ctdb = talloc_zero(NULL, struct ctdb_context);
249 /* Avoid that const */
250 ns = talloc_strdup(*ctdb, nodestates);
252 nodemap = talloc_zero(*ctdb, struct ctdb_node_map);
253 assert(nodemap != NULL);
255 tok = strtok(ns, ",");
256 while (tok != NULL) {
257 uint32_t n = nodemap->num;
258 nodemap->node = talloc_realloc(nodemap, nodemap->node,
259 struct ctdb_node_and_flags, n+1);
260 nodemap->node[n].pnn = n;
261 nodemap->node[n].flags = (uint32_t) strtol(tok, NULL, 0);
262 nodemap->node[n].addr = sa_zero;
264 tok = strtok(NULL, ",");
267 /* Fake things up... */
268 (*ctdb)->num_nodes = nodemap->num;
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;
275 if ((t = getenv("CTDB_IP_ALGORITHM"))) {
276 if (strcmp(t, "lcp2") == 0) {
277 (*ctdb)->tunable.lcp2_public_ip_assignment = 1;
278 } else if (strcmp(t, "nondet") == 0) {
279 (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
280 } else if (strcmp(t, "det") == 0) {
281 (*ctdb)->tunable.lcp2_public_ip_assignment = 0;
282 (*ctdb)->tunable.deterministic_public_ips = 1;
284 fprintf(stderr, "ERROR: unknown IP algorithm %s\n", t);
289 (*ctdb)->nodes = talloc_array(*ctdb, struct ctdb_node *, nodemap->num); // FIXME: bogus size, overkill
291 *ipalloc_state = ipalloc_state_init(*ctdb, nodemap->num,
292 determine_algorithm(&((*ctdb)->tunable)),
295 read_ctdb_public_ip_info(*ctdb, nodemap->num,
296 read_ips_for_multiple_nodes,
299 for (i=0; i < nodemap->num; i++) {
300 (*ctdb)->nodes[i] = talloc(*ctdb, struct ctdb_node);
301 (*ctdb)->nodes[i]->pnn = i;
302 (*ctdb)->nodes[i]->flags = nodemap->node[i].flags;
305 if (! ipalloc_set_public_ips(*ipalloc_state, known, avail)) {
306 DEBUG(DEBUG_ERR, ("Failed to set public IPs\n"));
310 tval_noiptakeover = get_tunable_values(*ctdb, nodemap->num,
311 "CTDB_SET_NoIPTakeover");
312 assert(tval_noiptakeover != NULL);
313 tval_noiptakeoverondisabled =
314 get_tunable_values(*ctdb, nodemap->num,
315 "CTDB_SET_NoIPHostOnAllDisabled");
316 assert(tval_noiptakeoverondisabled != NULL);
318 ipalloc_set_node_flags(*ipalloc_state, nodemap,
320 tval_noiptakeoverondisabled);
323 /* IP layout is read from stdin. See comment for ctdb_test_init() for
324 * explanation of read_ips_for_multiple_nodes.
326 static void ctdb_test_ipalloc(const char nodestates[],
327 bool read_ips_for_multiple_nodes)
329 struct ctdb_context *ctdb;
330 struct ipalloc_state *ipalloc_state;
332 ctdb_test_init(nodestates, &ctdb, &ipalloc_state,
333 read_ips_for_multiple_nodes);
335 print_ctdb_public_ip_list(ipalloc(ipalloc_state));
340 static void usage(void)
342 fprintf(stderr, "usage: ctdb_takeover_tests <op>\n");
346 int main(int argc, const char *argv[])
348 DEBUGLEVEL = DEBUG_DEBUG;
349 if (getenv("CTDB_TEST_LOGLEVEL")) {
350 DEBUGLEVEL = atoi(getenv("CTDB_TEST_LOGLEVEL"));
358 strcmp(argv[1], "ipalloc") == 0) {
359 ctdb_test_ipalloc(argv[2], false);
360 } else if (argc == 4 &&
361 strcmp(argv[1], "ipalloc") == 0 &&
362 strcmp(argv[3], "multi") == 0) {
363 ctdb_test_ipalloc(argv[2], true);