varnish-cache/vmod/vmod_directors_fall_back.c
1
/*-
2
 * Copyright (c) 2013-2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@FreeBSD.org>
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
31
#include "config.h"
32
33
#include <stdlib.h>
34
#include <string.h>
35
36
#include "cache/cache.h"
37
38
#include "vcc_directors_if.h"
39
40
#include "vmod_directors.h"
41
#include "vsb.h"
42
#include "vbm.h"
43
44
struct vmod_directors_fallback {
45
        unsigned                                magic;
46
#define VMOD_DIRECTORS_FALLBACK_MAGIC           0xad4e26ba
47
        struct vdir                             *vd;
48
        VCL_BOOL                                st;
49
        unsigned                                cur;
50
};
51
52
static VCL_BOOL v_matchproto_(vdi_healthy)
53 40
vmod_fallback_healthy(VRT_CTX, VCL_BACKEND dir, VCL_TIME *changed)
54
{
55
        struct vmod_directors_fallback *fb;
56
57 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
58 40
        CHECK_OBJ_NOTNULL(dir, DIRECTOR_MAGIC);
59 40
        CAST_OBJ_NOTNULL(fb, dir->priv, VMOD_DIRECTORS_FALLBACK_MAGIC);
60 40
        return (vdir_any_healthy(ctx, fb->vd, changed));
61
}
62
63
static void v_matchproto_(vdi_list_f)
64 130
vmod_fallback_list(VRT_CTX, VCL_BACKEND dir, struct vsb *vsb, int pflag,
65
    int jflag)
66
{
67
        struct vmod_directors_fallback *fb;
68
        struct vdir *vd;
69
        VCL_BACKEND be;
70
        VCL_BOOL h;
71
        unsigned u, nh;
72
73 130
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
74 130
        CHECK_OBJ_NOTNULL(dir, DIRECTOR_MAGIC);
75 130
        CAST_OBJ_NOTNULL(fb, dir->priv, VMOD_DIRECTORS_FALLBACK_MAGIC);
76 130
        CAST_OBJ_NOTNULL(vd, fb->vd, VDIR_MAGIC);
77
78 130
        if (pflag) {
79 20
                if (jflag) {
80 10
                        VSB_cat(vsb, "{\n");
81 10
                        VSB_indent(vsb, 2);
82 20
                        VSB_printf(vsb, "\"sticky\": %s,\n",
83 10
                            fb->st ? "true" : "false");
84 10
                        VSB_cat(vsb, "\"backends\": {\n");
85 10
                        VSB_indent(vsb, 2);
86 10
                } else {
87 10
                        VSB_cat(vsb, "\n\n\tBackend\tCurrent\tHealth\n");
88
                }
89 20
        }
90
91 130
        vdir_rdlock(vd);
92 130
        vdir_update_health(ctx, vd);
93 210
        for (u = 0; pflag && u < vd->n_backend; u++) {
94 80
                be = vd->backend[u];
95 80
                CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
96
97 80
                h = vbit_test(vd->healthy, u);
98
99 80
                if (jflag) {
100 40
                        if (u)
101 30
                                VSB_cat(vsb, ",\n");
102 40
                        VSB_printf(vsb, "\"%s\": {\n", be->vcl_name);
103 40
                        VSB_indent(vsb, 2);
104
105 40
                        if (fb->cur == u)
106 10
                                VSB_cat(vsb, "\"current\": true,\n");
107
                        else
108 30
                                VSB_cat(vsb, "\"current\": false,\n");
109
110 40
                        if (h)
111 30
                                VSB_cat(vsb, "\"health\": \"healthy\"\n");
112
                        else
113 10
                                VSB_cat(vsb, "\"health\": \"sick\"\n");
114
115 40
                        VSB_indent(vsb, -2);
116 40
                        VSB_cat(vsb, "}");
117 40
                } else {
118 40
                        VSB_cat(vsb, "\t");
119 40
                        VSB_cat(vsb, be->vcl_name);
120 40
                        if (fb->cur == u)
121 10
                                VSB_cat(vsb, "\t*\t");
122
                        else
123 30
                                VSB_cat(vsb, "\t\t");
124 40
                        VSB_cat(vsb, h ? "healthy" : "sick");
125 40
                        VSB_cat(vsb, "\n");
126
                }
127 80
        }
128 130
        nh = vd->n_healthy;
129 130
        u = vd->n_backend;
130 130
        vdir_unlock(vd);
131
132 130
        if (jflag && (pflag)) {
133 10
                VSB_cat(vsb, "\n");
134 10
                VSB_indent(vsb, -2);
135 10
                VSB_cat(vsb, "}\n");
136 10
                VSB_indent(vsb, -2);
137 10
                VSB_cat(vsb, "},\n");
138 10
        }
139
140 130
        if (pflag)
141 20
                return;
142
143 110
        if (jflag)
144 60
                VSB_printf(vsb, "[%u, %u, \"%s\"]", nh, u,
145 30
                    nh ? "healthy" : "sick");
146
        else
147 80
                VSB_printf(vsb, "%u/%u\t%s", nh, u, nh ? "healthy" : "sick");
148 130
}
149
150
static VCL_BACKEND v_matchproto_(vdi_resolve_f)
151 230
vmod_fallback_resolve(VRT_CTX, VCL_BACKEND dir)
152
{
153
        struct vmod_directors_fallback *fb;
154
        unsigned u;
155 230
        VCL_BACKEND be = NULL;
156
157 230
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
158 230
        CHECK_OBJ_NOTNULL(dir, DIRECTOR_MAGIC);
159 230
        CAST_OBJ_NOTNULL(fb, dir->priv, VMOD_DIRECTORS_FALLBACK_MAGIC);
160
161 230
        vdir_wrlock(fb->vd);
162 230
        if (!fb->st)
163 140
                fb->cur = 0;
164 370
        for (u = 0; u < fb->vd->n_backend; u++) {
165 360
                be = fb->vd->backend[fb->cur];
166 360
                CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
167 360
                if (VRT_Healthy(ctx, be, NULL))
168 220
                        break;
169 140
                if (++fb->cur == fb->vd->n_backend)
170 20
                        fb->cur = 0;
171 140
        }
172 230
        vdir_unlock(fb->vd);
173 230
        if (u == fb->vd->n_backend)
174 10
                be = NULL;
175 230
        return (be);
176
}
177
178
static void v_matchproto_(vdi_destroy_f)
179 10
vmod_fallback_destroy(VCL_BACKEND dir)
180
{
181
        struct vmod_directors_fallback *fallback;
182
183 10
        CHECK_OBJ_NOTNULL(dir, DIRECTOR_MAGIC);
184 10
        CAST_OBJ_NOTNULL(fallback, dir->priv, VMOD_DIRECTORS_FALLBACK_MAGIC);
185 10
        vdir_delete(&fallback->vd);
186 10
        FREE_OBJ(fallback);
187 10
}
188
189
static const struct vdi_methods vmod_fallback_methods[1] = {{
190
        .magic =                VDI_METHODS_MAGIC,
191
        .type =                 "fallback",
192
        .healthy =              vmod_fallback_healthy,
193
        .resolve =              vmod_fallback_resolve,
194
        .destroy =              vmod_fallback_destroy,
195
        .list =                 vmod_fallback_list
196
}};
197
198
199
VCL_VOID v_matchproto_()
200 50
vmod_fallback__init(VRT_CTX,
201
    struct vmod_directors_fallback **fbp, const char *vcl_name, VCL_BOOL sticky)
202
{
203
        struct vmod_directors_fallback *fb;
204
205 50
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
206 50
        AN(fbp);
207 50
        AZ(*fbp);
208 50
        ALLOC_OBJ(fb, VMOD_DIRECTORS_FALLBACK_MAGIC);
209 50
        AN(fb);
210 50
        *fbp = fb;
211 50
        vdir_new(ctx, &fb->vd, vcl_name, vmod_fallback_methods, fb);
212 50
        fb->st = sticky;
213 50
}
214
215
VCL_VOID v_matchproto_()
216 10
vmod_fallback__fini(struct vmod_directors_fallback **fbp)
217
{
218
        struct vmod_directors_fallback *fb;
219
220 10
        TAKE_OBJ_NOTNULL(fb, fbp, VMOD_DIRECTORS_FALLBACK_MAGIC);
221 10
        VRT_DelDirector(&fb->vd->dir);
222 10
}
223
224
VCL_VOID v_matchproto_()
225 160
vmod_fallback_add_backend(VRT_CTX,
226
    struct vmod_directors_fallback *fb, VCL_BACKEND be)
227
{
228
229 160
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
230 160
        CHECK_OBJ_NOTNULL(fb, VMOD_DIRECTORS_FALLBACK_MAGIC);
231 160
        vdir_add_backend(ctx, fb->vd, be, 0.0);
232 160
}
233
234
VCL_VOID v_matchproto_()
235 40
vmod_fallback_remove_backend(VRT_CTX,
236
    struct vmod_directors_fallback *fb, VCL_BACKEND be)
237
{
238 40
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
239 40
        CHECK_OBJ_NOTNULL(fb, VMOD_DIRECTORS_FALLBACK_MAGIC);
240 40
        vdir_remove_backend(ctx, fb->vd, be, &fb->cur);
241 40
}
242
243
VCL_BACKEND v_matchproto_()
244 270
vmod_fallback_backend(VRT_CTX,
245
    struct vmod_directors_fallback *fb)
246
{
247 270
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
248 270
        CHECK_OBJ_NOTNULL(fb, VMOD_DIRECTORS_FALLBACK_MAGIC);
249 270
        return (fb->vd->dir);
250
}