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 50360
VDI_Ahealth(const struct director *d)
70
{
71
72 50360
        CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
73 50360
        AN(d->vdir->admin_health);
74 50360
        if (d->vdir->admin_health != VDI_AH_AUTO)
75 1400
                return (d->vdir->admin_health->name);
76 48960
        if (d->vdir->methods->healthy != NULL)
77 5360
                return ("probe");
78 43600
        return ("healthy");
79 50360
}
80
81
/* Resolve director --------------------------------------------------*/
82
83
VCL_BACKEND
84 87232
VRT_DirectorResolve(VRT_CTX, VCL_BACKEND d)
85
{
86 87232
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
87
88 92112
        while (d != NULL) {
89 92032
                CHECK_OBJ(d, DIRECTOR_MAGIC);
90 92032
                AN(d->vdir);
91 92032
                if (d->vdir->methods->resolve == NULL)
92 87152
                        break;
93 4880
                d = d->vdir->methods->resolve(ctx, d);
94
        }
95 87232
        if (d == NULL)
96 80
                return (NULL);
97
98 87152
        CHECK_OBJ(d, DIRECTOR_MAGIC);
99 87152
        AN(d->vdir);
100 87152
        return (d);
101 87232
}
102
103
static VCL_BACKEND
104 89516
VDI_Resolve(VRT_CTX)
105
{
106
        VCL_BACKEND d;
107
        struct busyobj *bo;
108
109 89516
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
110 89516
        bo = ctx->bo;
111 89516
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
112
113 89516
        if (bo->director_req == NULL) {
114 2880
                VSLb(bo->vsl, SLT_FetchError, "No backend");
115 2880
                return (NULL);
116
        }
117
118 86636
        CHECK_OBJ(bo->director_req, DIRECTOR_MAGIC);
119 86636
        d = VRT_DirectorResolve(ctx, bo->director_req);
120 86636
        if (d != NULL)
121 86556
                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 89516
}
127
128
/* Get a set of response headers -------------------------------------*/
129
130
int
131 88519
VDI_GetHdr(struct busyobj *bo)
132
{
133
        const struct director *d;
134
        struct vrt_ctx ctx[1];
135 88519
        int i = -1;
136
137 88519
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
138 88519
        INIT_OBJ(ctx, VRT_CTX_MAGIC);
139 88519
        VCL_Bo2Ctx(ctx, bo);
140
141 88519
        d = VDI_Resolve(ctx);
142 88519
        if (d != NULL) {
143 85556
                VRT_Assign_Backend(&bo->director_resp, d);
144 85556
                AN(d->vdir->methods->gethdrs);
145 85556
                bo->director_state = DIR_S_HDRS;
146 85556
                i = d->vdir->methods->gethdrs(ctx, d);
147 85556
        }
148 88519
        if (i)
149 10077
                bo->director_state = DIR_S_NULL;
150 88519
        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 78394
VDI_Finish(struct busyobj *bo)
179
{
180
        const struct director *d;
181
        struct vrt_ctx ctx[1];
182
183 78394
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
184 78394
        INIT_OBJ(ctx, VRT_CTX_MAGIC);
185 78394
        VCL_Bo2Ctx(ctx, bo);
186
187 78394
        d = bo->director_resp;
188 78394
        CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
189
190 78394
        AZ(d->vdir->methods->resolve);
191 78394
        AN(d->vdir->methods->finish);
192
193 78394
        assert(bo->director_state != DIR_S_NULL);
194 78394
        d->vdir->methods->finish(ctx, d);
195 78394
        bo->director_state = DIR_S_NULL;
196 78394
}
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 118312
VRT_Healthy(VRT_CTX, VCL_BACKEND d, VCL_TIME *changed)
232
{
233
234 118312
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
235 118312
        if (d == NULL)
236 0
                return (0);
237 118312
        CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
238
239 118312
        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 114272
        if (d->vdir->methods->healthy == NULL) {
246 108912
                if (changed != NULL)
247 21440
                        *changed = d->vdir->health_changed;
248 108912
                return (1);
249
        }
250
251 5360
        return (d->vdir->methods->healthy(ctx, d, changed));
252 118312
}
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 70904
VDI_Event(const struct director *d, enum vcl_event_e ev)
272
{
273
274 70904
        CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
275 70904
        if (d->vdir->methods->event != NULL)
276 60747
                d->vdir->methods->event(d, ev);
277 70904
}
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 48880
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 48880
        AN(cli);
331 48880
        CAST_OBJ_NOTNULL(la, priv, LIST_ARGS_MAGIC);
332 48880
        AN(la->vsb);
333 48880
        AN(la->vte);
334 48880
        CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
335
336 48880
        if (d->vdir->admin_health == VDI_AH_DELETED)
337 0
                return (0);
338
339 48880
        ctx = VCL_Get_CliCtx(0);
340
341 48880
        VTE_printf(la->vte, "%s\t%s\t", d->vdir->cli_name, VDI_Ahealth(d));
342
343 48880
        if (d->vdir->methods->list != NULL) {
344 46480
                VSB_clear(la->vsb);
345 46480
                d->vdir->methods->list(ctx, d, la->vsb, 0, 0);
346 46480
                AZ(VSB_finish(la->vsb));
347 46480
                VTE_cat(la->vte, VSB_data(la->vsb));
348 48880
        } else if (d->vdir->methods->healthy != NULL)
349 40
                VTE_printf(la->vte, "0/0\t%s", cli_health(ctx, d));
350
        else
351 2360
                VTE_cat(la->vte, "0/0\thealthy");
352
353 48880
        VTIM_format(d->vdir->health_changed, time_str);
354 48880
        VTE_printf(la->vte, "\t%s", time_str);
355 48880
        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 48880
        VTE_cat(la->vte, "\n");
363 48880
        AZ(VCL_Rel_CliCtx(&ctx));
364 48880
        AZ(ctx);
365
366 48880
        return (0);
367 48880
}
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 36280
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 36280
        (void)priv;
422 36280
        ASSERT_CLI();
423 36280
        INIT_OBJ(la, LIST_ARGS_MAGIC);
424 36280
        la->jsep = "";
425 37080
        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 36280
        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 36280
        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 36080
                la->vsb = VSB_new_auto();
454 36080
                AN(la->vsb);
455 36080
                la->vte = VTE_new(5, 80);
456 36080
                AN(la->vte);
457 36080
                VTE_printf(la->vte, "%s\t%s\t%s\t%s\t%s\n",
458
                    "Backend name", "Admin", "Probe", "Health", "Last change");
459 36080
                (void)VCL_IterDirector(cli, av[i], do_list, la);
460 36080
                AZ(VTE_finish(la->vte));
461 36080
                AZ(VTE_format(la->vte, VCLI_VTE_format, cli));
462 36080
                VTE_destroy(&la->vte);
463 36080
                VSB_destroy(&la->vsb);
464
        }
465 36280
}
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 36629
VDI_Init(void)
532
{
533
534 36629
        CLI_AddFuncs(backend_cmds);
535 36629
}