| | varnish-cache/bin/varnishd/cache/cache_director.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2006 Verdens Gang AS |
2 |
|
* Copyright (c) 2006-2015 Varnish Software AS |
3 |
|
* All rights reserved. |
4 |
|
* |
5 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
6 |
|
* |
7 |
|
* SPDX-License-Identifier: BSD-2-Clause |
8 |
|
* |
9 |
|
* Redistribution and use in source and binary forms, with or without |
10 |
|
* modification, are permitted provided that the following conditions |
11 |
|
* are met: |
12 |
|
* 1. Redistributions of source code must retain the above copyright |
13 |
|
* notice, this list of conditions and the following disclaimer. |
14 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
15 |
|
* notice, this list of conditions and the following disclaimer in the |
16 |
|
* documentation and/or other materials provided with the distribution. |
17 |
|
* |
18 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
19 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
20 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
21 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
22 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
24 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
25 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
26 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
27 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
28 |
|
* SUCH DAMAGE. |
29 |
|
* |
30 |
|
* Abstract director API |
31 |
|
* |
32 |
|
* The abstract director API does not know how we talk to the backend or |
33 |
|
* if there even is one in the usual meaning of the word. |
34 |
|
* |
35 |
|
*/ |
36 |
|
|
37 |
|
#include "config.h" |
38 |
|
|
39 |
|
#include "cache_varnishd.h" |
40 |
|
#include "cache_director.h" |
41 |
|
|
42 |
|
#include "vcli_serve.h" |
43 |
|
#include "vte.h" |
44 |
|
#include "vtim.h" |
45 |
|
|
46 |
|
/* -------------------------------------------------------------------*/ |
47 |
|
|
48 |
|
struct vdi_ahealth { |
49 |
|
const char *name; |
50 |
|
int health; |
51 |
|
}; |
52 |
|
|
53 |
|
#define VBE_AHEALTH(l,u,h) \ |
54 |
|
static const struct vdi_ahealth vdi_ah_##l[1] = {{#l,h}}; \ |
55 |
|
const struct vdi_ahealth * const VDI_AH_##u = vdi_ah_##l; |
56 |
|
VBE_AHEALTH_LIST |
57 |
|
#undef VBE_AHEALTH |
58 |
|
|
59 |
|
static const struct vdi_ahealth * |
60 |
1680 |
vdi_str2ahealth(const char *t) |
61 |
|
{ |
62 |
|
#define VBE_AHEALTH(l,u,h) if (!strcasecmp(t, #l)) return (VDI_AH_##u); |
63 |
1680 |
VBE_AHEALTH_LIST |
64 |
|
#undef VBE_AHEALTH |
65 |
160 |
return (NULL); |
66 |
1680 |
} |
67 |
|
|
68 |
|
static const char * |
69 |
50440 |
VDI_Ahealth(const struct director *d) |
70 |
|
{ |
71 |
|
|
72 |
50440 |
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC); |
73 |
50440 |
AN(d->vdir->admin_health); |
74 |
50440 |
if (d->vdir->admin_health != VDI_AH_AUTO) |
75 |
1400 |
return (d->vdir->admin_health->name); |
76 |
49040 |
if (d->vdir->methods->healthy != NULL) |
77 |
5360 |
return ("probe"); |
78 |
43680 |
return ("healthy"); |
79 |
50440 |
} |
80 |
|
|
81 |
|
/* Resolve director --------------------------------------------------*/ |
82 |
|
|
83 |
|
VCL_BACKEND |
84 |
87275 |
VRT_DirectorResolve(VRT_CTX, VCL_BACKEND d) |
85 |
|
{ |
86 |
87275 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
87 |
|
|
88 |
92155 |
while (d != NULL) { |
89 |
92075 |
CHECK_OBJ(d, DIRECTOR_MAGIC); |
90 |
92075 |
AN(d->vdir); |
91 |
92075 |
if (d->vdir->methods->resolve == NULL) |
92 |
87195 |
break; |
93 |
4880 |
d = d->vdir->methods->resolve(ctx, d); |
94 |
|
} |
95 |
87275 |
if (d == NULL) |
96 |
80 |
return (NULL); |
97 |
|
|
98 |
87195 |
CHECK_OBJ(d, DIRECTOR_MAGIC); |
99 |
87195 |
AN(d->vdir); |
100 |
87195 |
return (d); |
101 |
87275 |
} |
102 |
|
|
103 |
|
static VCL_BACKEND |
104 |
89555 |
VDI_Resolve(VRT_CTX) |
105 |
|
{ |
106 |
|
VCL_BACKEND d; |
107 |
|
struct busyobj *bo; |
108 |
|
|
109 |
89555 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
110 |
89555 |
bo = ctx->bo; |
111 |
89555 |
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); |
112 |
|
|
113 |
89555 |
if (bo->director_req == NULL) { |
114 |
2880 |
VSLb(bo->vsl, SLT_FetchError, "No backend"); |
115 |
2880 |
return (NULL); |
116 |
|
} |
117 |
|
|
118 |
86675 |
CHECK_OBJ(bo->director_req, DIRECTOR_MAGIC); |
119 |
86675 |
d = VRT_DirectorResolve(ctx, bo->director_req); |
120 |
86675 |
if (d != NULL) |
121 |
86595 |
return (d); |
122 |
|
|
123 |
160 |
VSLb(bo->vsl, SLT_FetchError, |
124 |
80 |
"Director %s returned no backend", bo->director_req->vcl_name); |
125 |
80 |
return (NULL); |
126 |
89555 |
} |
127 |
|
|
128 |
|
/* Get a set of response headers -------------------------------------*/ |
129 |
|
|
130 |
|
int |
131 |
88559 |
VDI_GetHdr(struct busyobj *bo) |
132 |
|
{ |
133 |
|
const struct director *d; |
134 |
|
struct vrt_ctx ctx[1]; |
135 |
88559 |
int i = -1; |
136 |
|
|
137 |
88559 |
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); |
138 |
88559 |
INIT_OBJ(ctx, VRT_CTX_MAGIC); |
139 |
88559 |
VCL_Bo2Ctx(ctx, bo); |
140 |
|
|
141 |
88559 |
d = VDI_Resolve(ctx); |
142 |
88559 |
if (d != NULL) { |
143 |
85591 |
VRT_Assign_Backend(&bo->director_resp, d); |
144 |
85591 |
AN(d->vdir->methods->gethdrs); |
145 |
85591 |
bo->director_state = DIR_S_HDRS; |
146 |
85591 |
i = d->vdir->methods->gethdrs(ctx, d); |
147 |
85591 |
} |
148 |
88559 |
if (i) |
149 |
10079 |
bo->director_state = DIR_S_NULL; |
150 |
88559 |
return (i); |
151 |
|
} |
152 |
|
|
153 |
|
/* Get IP number (if any ) -------------------------------------------*/ |
154 |
|
|
155 |
|
VCL_IP |
156 |
40 |
VDI_GetIP(struct busyobj *bo) |
157 |
|
{ |
158 |
|
const struct director *d; |
159 |
|
struct vrt_ctx ctx[1]; |
160 |
|
|
161 |
40 |
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); |
162 |
40 |
INIT_OBJ(ctx, VRT_CTX_MAGIC); |
163 |
40 |
VCL_Bo2Ctx(ctx, bo); |
164 |
|
|
165 |
40 |
d = bo->director_resp; |
166 |
40 |
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC); |
167 |
40 |
assert(bo->director_state == DIR_S_HDRS || |
168 |
|
bo->director_state == DIR_S_BODY); |
169 |
40 |
AZ(d->vdir->methods->resolve); |
170 |
40 |
if (d->vdir->methods->getip == NULL) |
171 |
0 |
return (NULL); |
172 |
40 |
return (d->vdir->methods->getip(ctx, d)); |
173 |
40 |
} |
174 |
|
|
175 |
|
/* Finish fetch ------------------------------------------------------*/ |
176 |
|
|
177 |
|
void |
178 |
78439 |
VDI_Finish(struct busyobj *bo) |
179 |
|
{ |
180 |
|
const struct director *d; |
181 |
|
struct vrt_ctx ctx[1]; |
182 |
|
|
183 |
78439 |
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); |
184 |
78439 |
INIT_OBJ(ctx, VRT_CTX_MAGIC); |
185 |
78439 |
VCL_Bo2Ctx(ctx, bo); |
186 |
|
|
187 |
78439 |
d = bo->director_resp; |
188 |
78439 |
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC); |
189 |
|
|
190 |
78439 |
AZ(d->vdir->methods->resolve); |
191 |
78439 |
AN(d->vdir->methods->finish); |
192 |
|
|
193 |
78439 |
assert(bo->director_state != DIR_S_NULL); |
194 |
78439 |
d->vdir->methods->finish(ctx, d); |
195 |
78439 |
bo->director_state = DIR_S_NULL; |
196 |
78439 |
} |
197 |
|
|
198 |
|
/* Get a connection --------------------------------------------------*/ |
199 |
|
|
200 |
|
stream_close_t |
201 |
1000 |
VDI_Http1Pipe(struct req *req, struct busyobj *bo) |
202 |
|
{ |
203 |
|
const struct director *d; |
204 |
|
struct vrt_ctx ctx[1]; |
205 |
|
|
206 |
1000 |
CHECK_OBJ_NOTNULL(req, REQ_MAGIC); |
207 |
1000 |
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); |
208 |
1000 |
INIT_OBJ(ctx, VRT_CTX_MAGIC); |
209 |
1000 |
VCL_Bo2Ctx(ctx, bo); |
210 |
1000 |
VCL_Req2Ctx(ctx, req); |
211 |
|
|
212 |
1000 |
d = VDI_Resolve(ctx); |
213 |
1000 |
if (d == NULL || d->vdir->methods->http1pipe == NULL) { |
214 |
0 |
VSLb(bo->vsl, SLT_VCL_Error, "Backend does not support pipe"); |
215 |
0 |
return (SC_TX_ERROR); |
216 |
|
} |
217 |
1000 |
VRT_Assign_Backend(&bo->director_resp, d); |
218 |
1000 |
return (d->vdir->methods->http1pipe(ctx, d)); |
219 |
1000 |
} |
220 |
|
|
221 |
|
/* Check health -------------------------------------------------------- |
222 |
|
* |
223 |
|
* If director has no healthy method, we just assume it is healthy. |
224 |
|
*/ |
225 |
|
|
226 |
|
/*-------------------------------------------------------------------- |
227 |
|
* Test if backend is healthy and report when that last changed |
228 |
|
*/ |
229 |
|
|
230 |
|
VCL_BOOL |
231 |
118351 |
VRT_Healthy(VRT_CTX, VCL_BACKEND d, VCL_TIME *changed) |
232 |
|
{ |
233 |
|
|
234 |
118351 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
235 |
118351 |
if (d == NULL) |
236 |
0 |
return (0); |
237 |
118351 |
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC); |
238 |
|
|
239 |
118351 |
if (d->vdir->admin_health->health >= 0) { |
240 |
4040 |
if (changed != NULL) |
241 |
2280 |
*changed = d->vdir->health_changed; |
242 |
4040 |
return (d->vdir->admin_health->health); |
243 |
|
} |
244 |
|
|
245 |
114311 |
if (d->vdir->methods->healthy == NULL) { |
246 |
108954 |
if (changed != NULL) |
247 |
21440 |
*changed = d->vdir->health_changed; |
248 |
108954 |
return (1); |
249 |
|
} |
250 |
|
|
251 |
5357 |
return (d->vdir->methods->healthy(ctx, d, changed)); |
252 |
118351 |
} |
253 |
|
|
254 |
|
/*-------------------------------------------------------------------- |
255 |
|
* Update health_changed. |
256 |
|
*/ |
257 |
|
VCL_VOID |
258 |
4480 |
VRT_SetChanged(VCL_BACKEND d, VCL_TIME changed) |
259 |
|
{ |
260 |
|
|
261 |
4480 |
CHECK_OBJ_ORNULL(d, DIRECTOR_MAGIC); |
262 |
|
|
263 |
4480 |
if (d != NULL && changed > d->vdir->health_changed) |
264 |
320 |
d->vdir->health_changed = changed; |
265 |
4480 |
} |
266 |
|
|
267 |
|
/* Send Event ---------------------------------------------------------- |
268 |
|
*/ |
269 |
|
|
270 |
|
void |
271 |
71015 |
VDI_Event(const struct director *d, enum vcl_event_e ev) |
272 |
|
{ |
273 |
|
|
274 |
71015 |
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC); |
275 |
71015 |
if (d->vdir->methods->event != NULL) |
276 |
60778 |
d->vdir->methods->event(d, ev); |
277 |
71015 |
} |
278 |
|
|
279 |
|
/* Dump panic info ----------------------------------------------------- |
280 |
|
*/ |
281 |
|
|
282 |
|
void |
283 |
280 |
VDI_Panic(const struct director *d, struct vsb *vsb, const char *nm) |
284 |
|
{ |
285 |
280 |
if (d == NULL) |
286 |
40 |
return; |
287 |
240 |
VSB_printf(vsb, "%s = %p {\n", nm, d); |
288 |
240 |
VSB_indent(vsb, 2); |
289 |
240 |
VSB_printf(vsb, "cli_name = %s,\n", d->vdir->cli_name); |
290 |
480 |
VSB_printf(vsb, "admin_health = %s, changed = %f,\n", |
291 |
240 |
VDI_Ahealth(d), d->vdir->health_changed); |
292 |
240 |
VSB_printf(vsb, "type = %s {\n", d->vdir->methods->type); |
293 |
240 |
VSB_indent(vsb, 2); |
294 |
240 |
if (d->vdir->methods->panic != NULL) |
295 |
240 |
d->vdir->methods->panic(d, vsb); |
296 |
240 |
VSB_indent(vsb, -2); |
297 |
240 |
VSB_cat(vsb, "},\n"); |
298 |
240 |
VSB_indent(vsb, -2); |
299 |
240 |
VSB_cat(vsb, "},\n"); |
300 |
280 |
} |
301 |
|
|
302 |
|
|
303 |
|
/*---------------------------------------------------------------------*/ |
304 |
|
|
305 |
|
struct list_args { |
306 |
|
unsigned magic; |
307 |
|
#define LIST_ARGS_MAGIC 0x7e7cefeb |
308 |
|
int p; |
309 |
|
int j; |
310 |
|
const char *jsep; |
311 |
|
struct vsb *vsb; |
312 |
|
struct vte *vte; |
313 |
|
}; |
314 |
|
|
315 |
|
static const char * |
316 |
40 |
cli_health(VRT_CTX, const struct director *d) |
317 |
|
{ |
318 |
40 |
VCL_BOOL healthy = VRT_Healthy(ctx, d, NULL); |
319 |
|
|
320 |
40 |
return (healthy ? "healthy" : "sick"); |
321 |
|
} |
322 |
|
|
323 |
|
static int v_matchproto_(vcl_be_func) |
324 |
48960 |
do_list(struct cli *cli, struct director *d, void *priv) |
325 |
|
{ |
326 |
|
char time_str[VTIM_FORMAT_SIZE]; |
327 |
|
struct list_args *la; |
328 |
|
struct vrt_ctx *ctx; |
329 |
|
|
330 |
48960 |
AN(cli); |
331 |
48960 |
CAST_OBJ_NOTNULL(la, priv, LIST_ARGS_MAGIC); |
332 |
48960 |
AN(la->vsb); |
333 |
48960 |
AN(la->vte); |
334 |
48960 |
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC); |
335 |
|
|
336 |
48960 |
if (d->vdir->admin_health == VDI_AH_DELETED) |
337 |
0 |
return (0); |
338 |
|
|
339 |
48960 |
ctx = VCL_Get_CliCtx(0); |
340 |
|
|
341 |
48960 |
VTE_printf(la->vte, "%s\t%s\t", d->vdir->cli_name, VDI_Ahealth(d)); |
342 |
|
|
343 |
48960 |
if (d->vdir->methods->list != NULL) { |
344 |
46520 |
VSB_clear(la->vsb); |
345 |
46520 |
d->vdir->methods->list(ctx, d, la->vsb, 0, 0); |
346 |
46520 |
AZ(VSB_finish(la->vsb)); |
347 |
46520 |
VTE_cat(la->vte, VSB_data(la->vsb)); |
348 |
48960 |
} else if (d->vdir->methods->healthy != NULL) |
349 |
40 |
VTE_printf(la->vte, "0/0\t%s", cli_health(ctx, d)); |
350 |
|
else |
351 |
2400 |
VTE_cat(la->vte, "0/0\thealthy"); |
352 |
|
|
353 |
48960 |
VTIM_format(d->vdir->health_changed, time_str); |
354 |
48960 |
VTE_printf(la->vte, "\t%s", time_str); |
355 |
48960 |
if (la->p && d->vdir->methods->list != NULL) { |
356 |
1120 |
VSB_clear(la->vsb); |
357 |
1120 |
d->vdir->methods->list(ctx, d, la->vsb, la->p, 0); |
358 |
1120 |
AZ(VSB_finish(la->vsb)); |
359 |
1120 |
VTE_cat(la->vte, VSB_data(la->vsb)); |
360 |
1120 |
} |
361 |
|
|
362 |
48960 |
VTE_cat(la->vte, "\n"); |
363 |
48960 |
AZ(VCL_Rel_CliCtx(&ctx)); |
364 |
48960 |
AZ(ctx); |
365 |
|
|
366 |
48960 |
return (0); |
367 |
48960 |
} |
368 |
|
|
369 |
|
static int v_matchproto_(vcl_be_func) |
370 |
1240 |
do_list_json(struct cli *cli, struct director *d, void *priv) |
371 |
|
{ |
372 |
|
struct list_args *la; |
373 |
|
struct vrt_ctx *ctx; |
374 |
|
|
375 |
1240 |
CAST_OBJ_NOTNULL(la, priv, LIST_ARGS_MAGIC); |
376 |
1240 |
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC); |
377 |
|
|
378 |
1240 |
if (d->vdir->admin_health == VDI_AH_DELETED) |
379 |
0 |
return (0); |
380 |
|
|
381 |
1240 |
ctx = VCL_Get_CliCtx(0); |
382 |
|
|
383 |
1240 |
VCLI_Out(cli, "%s", la->jsep); |
384 |
1240 |
la->jsep = ",\n"; |
385 |
1240 |
VCLI_JSON_str(cli, d->vdir->cli_name); |
386 |
1240 |
VCLI_Out(cli, ": {\n"); |
387 |
1240 |
VSB_indent(cli->sb, 2); |
388 |
1240 |
VCLI_Out(cli, "\"type\": \"%s\",\n", d->vdir->methods->type); |
389 |
1240 |
VCLI_Out(cli, "\"admin_health\": \"%s\",\n", VDI_Ahealth(d)); |
390 |
1240 |
VCLI_Out(cli, "\"probe_message\": "); |
391 |
1240 |
if (d->vdir->methods->list != NULL) |
392 |
1160 |
d->vdir->methods->list(ctx, d, cli->sb, 0, 1); |
393 |
80 |
else if (d->vdir->methods->healthy != NULL) |
394 |
0 |
VCLI_Out(cli, "[0, 0, \"%s\"]", cli_health(ctx, d)); |
395 |
|
else |
396 |
80 |
VCLI_Out(cli, "[0, 0, \"healthy\"]"); |
397 |
|
|
398 |
1240 |
VCLI_Out(cli, ",\n"); |
399 |
|
|
400 |
1240 |
if (la->p && d->vdir->methods->list != NULL) { |
401 |
440 |
VCLI_Out(cli, "\"probe_details\": "); |
402 |
440 |
d->vdir->methods->list(ctx, d, cli->sb, la->p, 1); |
403 |
440 |
} |
404 |
1240 |
VCLI_Out(cli, "\"last_change\": %.3f\n", d->vdir->health_changed); |
405 |
1240 |
VSB_indent(cli->sb, -2); |
406 |
1240 |
VCLI_Out(cli, "}"); |
407 |
|
|
408 |
1240 |
AZ(VCL_Rel_CliCtx(&ctx)); |
409 |
1240 |
AZ(ctx); |
410 |
|
|
411 |
1240 |
return (0); |
412 |
1240 |
} |
413 |
|
|
414 |
|
static void v_matchproto_(cli_func_t) |
415 |
36320 |
cli_backend_list(struct cli *cli, const char * const *av, void *priv) |
416 |
|
{ |
417 |
|
const char *p; |
418 |
|
struct list_args la[1]; |
419 |
|
int i; |
420 |
|
|
421 |
36320 |
(void)priv; |
422 |
36320 |
ASSERT_CLI(); |
423 |
36320 |
INIT_OBJ(la, LIST_ARGS_MAGIC); |
424 |
36320 |
la->jsep = ""; |
425 |
37120 |
for (i = 2; av[i] != NULL && av[i][0] == '-'; i++) { |
426 |
1640 |
for(p = av[i] + 1; *p; p++) { |
427 |
840 |
switch(*p) { |
428 |
200 |
case 'j': la->j = 1; break; |
429 |
640 |
case 'p': la->p = !la->p; break; |
430 |
|
default: |
431 |
0 |
VCLI_Out(cli, "Invalid flag %c", *p); |
432 |
0 |
VCLI_SetResult(cli, CLIS_PARAM); |
433 |
0 |
return; |
434 |
|
} |
435 |
840 |
} |
436 |
800 |
} |
437 |
36320 |
if (av[i] != NULL && av[i+1] != NULL) { |
438 |
0 |
VCLI_Out(cli, "Too many arguments"); |
439 |
0 |
VCLI_SetResult(cli, CLIS_PARAM); |
440 |
0 |
return; |
441 |
|
} |
442 |
36320 |
if (la->j) { |
443 |
200 |
VCLI_JSON_begin(cli, 3, av); |
444 |
200 |
VCLI_Out(cli, ",\n"); |
445 |
200 |
VCLI_Out(cli, "{\n"); |
446 |
200 |
VSB_indent(cli->sb, 2); |
447 |
200 |
(void)VCL_IterDirector(cli, av[i], do_list_json, la); |
448 |
200 |
VSB_indent(cli->sb, -2); |
449 |
200 |
VCLI_Out(cli, "\n"); |
450 |
200 |
VCLI_Out(cli, "}"); |
451 |
200 |
VCLI_JSON_end(cli); |
452 |
200 |
} else { |
453 |
36120 |
la->vsb = VSB_new_auto(); |
454 |
36120 |
AN(la->vsb); |
455 |
36120 |
la->vte = VTE_new(5, 80); |
456 |
36120 |
AN(la->vte); |
457 |
36120 |
VTE_printf(la->vte, "%s\t%s\t%s\t%s\t%s\n", |
458 |
|
"Backend name", "Admin", "Probe", "Health", "Last change"); |
459 |
36120 |
(void)VCL_IterDirector(cli, av[i], do_list, la); |
460 |
36120 |
AZ(VTE_finish(la->vte)); |
461 |
36120 |
AZ(VTE_format(la->vte, VCLI_VTE_format, cli)); |
462 |
36120 |
VTE_destroy(&la->vte); |
463 |
36120 |
VSB_destroy(&la->vsb); |
464 |
|
} |
465 |
36320 |
} |
466 |
|
|
467 |
|
/*---------------------------------------------------------------------*/ |
468 |
|
|
469 |
|
struct set_health { |
470 |
|
unsigned magic; |
471 |
|
#define SET_HEALTH_MAGIC 0x0c46b9fb |
472 |
|
const struct vdi_ahealth *ah; |
473 |
|
}; |
474 |
|
|
475 |
|
static int v_matchproto_(vcl_be_func) |
476 |
1400 |
do_set_health(struct cli *cli, struct director *d, void *priv) |
477 |
|
{ |
478 |
|
struct set_health *sh; |
479 |
|
|
480 |
1400 |
(void)cli; |
481 |
1400 |
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC); |
482 |
1400 |
CAST_OBJ_NOTNULL(sh, priv, SET_HEALTH_MAGIC); |
483 |
|
|
484 |
1400 |
if (d->vdir->admin_health == VDI_AH_DELETED) |
485 |
0 |
return (0); |
486 |
1400 |
if (d->vdir->admin_health != sh->ah) { |
487 |
1280 |
d->vdir->health_changed = VTIM_real(); |
488 |
1280 |
d->vdir->admin_health = sh->ah; |
489 |
1280 |
VDI_Event(d, VDI_EVENT_SICK); |
490 |
1280 |
} |
491 |
1400 |
return (0); |
492 |
1400 |
} |
493 |
|
|
494 |
|
static void v_matchproto_() |
495 |
1680 |
cli_backend_set_health(struct cli *cli, const char * const *av, void *priv) |
496 |
|
{ |
497 |
|
int n; |
498 |
|
struct set_health sh[1]; |
499 |
|
|
500 |
1680 |
(void)av; |
501 |
1680 |
(void)priv; |
502 |
1680 |
ASSERT_CLI(); |
503 |
1680 |
AN(av[2]); |
504 |
1680 |
AN(av[3]); |
505 |
1680 |
INIT_OBJ(sh, SET_HEALTH_MAGIC); |
506 |
1680 |
sh->ah = vdi_str2ahealth(av[3]); |
507 |
1680 |
if (sh->ah == NULL || sh->ah == VDI_AH_DELETED) { |
508 |
160 |
VCLI_Out(cli, "Invalid state %s", av[3]); |
509 |
160 |
VCLI_SetResult(cli, CLIS_PARAM); |
510 |
160 |
return; |
511 |
|
} |
512 |
1520 |
n = VCL_IterDirector(cli, av[2], do_set_health, sh); |
513 |
1520 |
if (n == 0) { |
514 |
120 |
VCLI_Out(cli, "No Backends matches"); |
515 |
120 |
VCLI_SetResult(cli, CLIS_PARAM); |
516 |
120 |
} |
517 |
1680 |
} |
518 |
|
|
519 |
|
/*---------------------------------------------------------------------*/ |
520 |
|
|
521 |
|
static struct cli_proto backend_cmds[] = { |
522 |
|
{ CLICMD_BACKEND_LIST, "", |
523 |
|
cli_backend_list, cli_backend_list }, |
524 |
|
{ CLICMD_BACKEND_SET_HEALTH, "", cli_backend_set_health }, |
525 |
|
{ NULL } |
526 |
|
}; |
527 |
|
|
528 |
|
/*---------------------------------------------------------------------*/ |
529 |
|
|
530 |
|
void |
531 |
36676 |
VDI_Init(void) |
532 |
|
{ |
533 |
|
|
534 |
36676 |
CLI_AddFuncs(backend_cmds); |
535 |
36676 |
} |