debug: Use debuglevel_(get|set) function
[vlendec/samba-autobuild/.git] / ctdb / tests / src / ctdb_takeover_tests.c
1 /* 
2    Tests for ctdb_takeover.c
3
4    Copyright (C) Martin Schwenke 2011
5
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.
10    
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.
15    
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/>.
18 */
19
20 #include "replace.h"
21 #include "system/network.h"
22
23 #include <assert.h>
24 #include <talloc.h>
25
26 #include "lib/util/debug.h"
27
28 #include "protocol/protocol.h"
29 #include "protocol/protocol_util.h"
30 #include "common/logging.h"
31 #include "common/system.h"
32
33 #include "server/ipalloc.h"
34
35 #include "ipalloc_read_known_ips.h"
36
37 static void print_ctdb_public_ip_list(TALLOC_CTX *mem_ctx,
38                                       struct public_ip_list * ips)
39 {
40         while (ips) {
41                 printf("%s %d\n",
42                        ctdb_sock_addr_to_string(mem_ctx, &(ips->addr), false),
43                        ips->pnn);
44                 ips = ips->next;
45         }
46 }
47
48 static uint32_t *get_tunable_values(TALLOC_CTX *tmp_ctx,
49                                     int numnodes,
50                                     const char *tunable);
51 static enum ctdb_runstate *get_runstate(TALLOC_CTX *tmp_ctx,
52                                         int numnodes);
53
54 static void read_ctdb_public_ip_info(TALLOC_CTX *ctx,
55                                      int numnodes,
56                                      bool multi,
57                                      struct ctdb_public_ip_list ** known,
58                                      struct ctdb_public_ip_list ** avail)
59 {
60         int n;
61         enum ctdb_runstate *runstate;
62
63         *known = ipalloc_read_known_ips(ctx, numnodes, multi);
64         assert(*known != NULL);
65
66         *avail = talloc_zero_array(ctx, struct ctdb_public_ip_list,
67                                    numnodes);
68         assert(*avail != NULL);
69
70         runstate = get_runstate(ctx, numnodes);
71         for (n = 0; n < numnodes; n++) {
72                 if (runstate[n] == CTDB_RUNSTATE_RUNNING) {
73                         (*avail)[n] = (*known)[n];
74                 }
75         }
76 }
77
78 static uint32_t *get_tunable_values(TALLOC_CTX *tmp_ctx,
79                                     int numnodes,
80                                     const char *tunable)
81 {
82         int i;
83         char *tok;
84         uint32_t *tvals = talloc_zero_array(tmp_ctx, uint32_t, numnodes);
85         char *t = getenv(tunable);
86
87         if (t) {
88                 if (strcmp(t, "1") == 0) {
89                         for (i=0; i<numnodes; i++) {
90                                 tvals[i] = 1;
91                         }
92                 } else {
93                         tok = strtok(t, ",");
94                         i = 0;
95                         while (tok != NULL) {
96                                 tvals[i] =
97                                         (uint32_t) strtol(tok, NULL, 0);
98                                 i++;
99                                 tok = strtok(NULL, ",");
100                         }
101                         if (i != numnodes) {
102                                 fprintf(stderr, "ERROR: Wrong number of values in %s\n", tunable);
103                                 exit(1);
104                         }
105                 }
106         }
107
108         return tvals;
109 }
110
111 static enum ctdb_runstate *get_runstate(TALLOC_CTX *tmp_ctx,
112                                         int numnodes)
113 {
114         int i;
115         uint32_t *tvals;
116         enum ctdb_runstate *runstate =
117                 talloc_zero_array(tmp_ctx, enum ctdb_runstate, numnodes);
118         char *t = getenv("CTDB_TEST_RUNSTATE");
119
120         if (t == NULL) {
121                 for (i=0; i<numnodes; i++) {
122                         runstate[i] = CTDB_RUNSTATE_RUNNING;
123                 }
124         } else {
125                 tvals = get_tunable_values(tmp_ctx, numnodes, "CTDB_TEST_RUNSTATE");
126                 for (i=0; i<numnodes; i++) {
127                         runstate[i] = (enum ctdb_runstate) tvals[i];
128                 }
129                 talloc_free(tvals);
130         }
131
132         return runstate;
133 }
134
135 /* Fake up enough CTDB state to be able to run the IP allocation
136  * algorithm.  Usually this sets up some standard state, sets the node
137  * states from the command-line and reads the current IP layout from
138  * stdin.
139  *
140  * However, if read_ips_for_multiple_nodes is true then each node's
141  * idea of the IP layout is read separately from stdin.  In this mode
142  * is doesn't make much sense to use read_ctdb_public_ip_info's
143  * optional ALLOWED_PNN,... list in the input, since each node is
144  * being handled separately anyway.  IPs for each node are separated
145  * by a blank line.  This mode is for testing weird behaviours where
146  * the IP layouts differs across nodes and we want to improve
147  * create_merged_ip_list(), so should only be used in tests of
148  * ipalloc().  Yes, it is a hack...  :-)
149  */
150 static void ctdb_test_init(TALLOC_CTX *mem_ctx,
151                            const char nodestates[],
152                            struct ipalloc_state **ipalloc_state,
153                            bool read_ips_for_multiple_nodes)
154 {
155         struct ctdb_public_ip_list *known;
156         struct ctdb_public_ip_list *avail;
157         char *tok, *ns;
158         const char *t;
159         struct ctdb_node_map *nodemap;
160         uint32_t noiptakeover;
161         ctdb_sock_addr sa_zero = { .ip = { 0 } };
162         enum ipalloc_algorithm algorithm;
163         uint32_t n;
164
165         /* Avoid that const */
166         ns = talloc_strdup(mem_ctx, nodestates);
167
168         nodemap = talloc_zero(mem_ctx, struct ctdb_node_map);
169         assert(nodemap != NULL);
170         nodemap->num = 0;
171         tok = strtok(ns, ",");
172         while (tok != NULL) {
173                 n = nodemap->num;
174                 nodemap->node = talloc_realloc(nodemap, nodemap->node,
175                                                struct ctdb_node_and_flags, n+1);
176                 nodemap->node[n].pnn = n;
177                 nodemap->node[n].flags = (uint32_t) strtol(tok, NULL, 0);
178                 nodemap->node[n].addr = sa_zero;
179                 nodemap->num++;
180                 tok = strtok(NULL, ",");
181         }
182
183         algorithm = IPALLOC_LCP2;
184         if ((t = getenv("CTDB_IP_ALGORITHM"))) {
185                 if (strcmp(t, "lcp2") == 0) {
186                         algorithm = IPALLOC_LCP2;
187                 } else if (strcmp(t, "nondet") == 0) {
188                         algorithm = IPALLOC_NONDETERMINISTIC;
189                 } else if (strcmp(t, "det") == 0) {
190                         algorithm = IPALLOC_DETERMINISTIC;
191                 } else {
192                         DEBUG(DEBUG_ERR,
193                               ("ERROR: unknown IP algorithm %s\n", t));
194                         exit(1);
195                 }
196         }
197
198         t = getenv("CTDB_SET_NoIPTakeover");
199         if (t != NULL) {
200                 noiptakeover = (uint32_t) strtol(t, NULL, 0);
201         } else {
202                 noiptakeover = 0;
203         }
204
205         *ipalloc_state = ipalloc_state_init(mem_ctx, nodemap->num,
206                                             algorithm,
207                                             (noiptakeover != 0),
208                                             false,
209                                             NULL);
210         assert(*ipalloc_state != NULL);
211
212         read_ctdb_public_ip_info(mem_ctx, nodemap->num,
213                                  read_ips_for_multiple_nodes,
214                                  &known, &avail);
215
216         /* Drop available IPs for INACTIVE/DISABLED nodes */
217         for (n = 0; n < nodemap->num; n++) {
218                 uint32_t flags = nodemap->node[n].flags;
219                 if ((flags & (NODE_FLAGS_INACTIVE|NODE_FLAGS_DISABLED)) != 0) {
220                         avail[n].num = 0;
221                 }
222         }
223
224         ipalloc_set_public_ips(*ipalloc_state, known, avail);
225 }
226
227 /* IP layout is read from stdin.  See comment for ctdb_test_init() for
228  * explanation of read_ips_for_multiple_nodes.
229  */
230 static void ctdb_test_ipalloc(const char nodestates[],
231                               bool read_ips_for_multiple_nodes)
232 {
233         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
234         struct ipalloc_state *ipalloc_state;
235
236         ctdb_test_init(tmp_ctx, nodestates, &ipalloc_state,
237                        read_ips_for_multiple_nodes);
238
239         print_ctdb_public_ip_list(tmp_ctx, ipalloc(ipalloc_state));
240
241         talloc_free(tmp_ctx);
242 }
243
244 static void usage(void)
245 {
246         fprintf(stderr, "usage: ctdb_takeover_tests <op>\n");
247         exit(1);
248 }
249
250 int main(int argc, const char *argv[])
251 {
252         int loglevel;
253         const char *debuglevelstr = getenv("CTDB_TEST_LOGLEVEL");
254
255         setup_logging("ctdb_takeover_tests", DEBUG_STDERR);
256
257         if (! debug_level_parse(debuglevelstr, &loglevel)) {
258                 loglevel = DEBUG_DEBUG;
259         }
260         debuglevel_set(loglevel);
261
262         if (argc < 2) {
263                 usage();
264         }
265
266         if (argc == 3 &&
267                    strcmp(argv[1], "ipalloc") == 0) {
268                 ctdb_test_ipalloc(argv[2], false);
269         } else if (argc == 4 &&
270                    strcmp(argv[1], "ipalloc") == 0 &&
271                    strcmp(argv[3], "multi") == 0) {
272                 ctdb_test_ipalloc(argv[2], true);
273         } else {
274                 usage();
275         }
276
277         return 0;
278 }