varnish-cache/bin/varnishtest/vtc_vsm.c
0
/*-
1
 * Copyright (c) 2023 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Dridi Boukelmoune <dridi.boukelmoune@gmail.com>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
#ifdef VTEST_WITH_VTC_VSM
31
32
#include "config.h"
33
34
#include <sys/types.h>
35
36
#include <stdlib.h>
37
#include <string.h>
38
#include <stdint.h>
39
40
#include "vapi/vsm.h"
41
42
#include "vtc.h"
43
#include "vav.h"
44
45
struct vtc_vsm {
46
        unsigned                        magic;
47
#define VTC_VSM_MAGIC                   0x5ca77a36
48
        VTAILQ_ENTRY(vtc_vsm)           list;
49
50
        char                            *name;
51
        char                            *n_arg;
52
        struct vtclog                   *vl;
53
        struct vsm                      *vsm;
54
};
55
56
static VTAILQ_HEAD(, vtc_vsm) vsms = VTAILQ_HEAD_INITIALIZER(vsms);
57
58
static struct vtc_vsm *
59 40
vsm_new(const char *name)
60
{
61
        struct vtc_vsm *m;
62
63 40
        ALLOC_OBJ(m, VTC_VSM_MAGIC);
64 40
        AN(m);
65 40
        REPLACE(m->name, name);
66 40
        REPLACE(m->n_arg, "${v1_name}");
67 40
        m->vl = vtc_logopen("%s", name);
68
69 40
        VTAILQ_INSERT_TAIL(&vsms, m, list);
70 40
        return (m);
71
}
72
73
static void
74 40
vsm_detach(struct vtc_vsm *m)
75
{
76
77 40
        CHECK_OBJ_NOTNULL(m, VTC_VSM_MAGIC);
78 40
        if (m->vsm == NULL)
79 0
                vtc_fatal(m->vl, "Cannot detach unattached VSM");
80 40
        vtc_log(m->vl, 3, "Detaching from VSM");
81 40
        VSM_Destroy(&m->vsm);
82 40
        AZ(m->vsm);
83 40
}
84
85
static void
86 40
vsm_attach(struct vtc_vsm *m)
87
{
88
        struct vsb *n_arg;
89
90 40
        CHECK_OBJ_NOTNULL(m, VTC_VSM_MAGIC);
91 40
        if (m->vsm != NULL)
92 0
                vsm_detach(m);
93
94 40
        n_arg = macro_expandf(m->vl, "%s", m->n_arg);
95 40
        if (n_arg == NULL)
96 0
                vtc_fatal(m->vl, "Could not expand -n argument");
97 40
        vtc_log(m->vl, 3, "Attaching to VSM: %s", VSB_data(n_arg));
98
99 40
        m->vsm = VSM_New();
100 40
        AN(m->vsm);
101
102 40
        if (VSM_Arg(m->vsm, 'n', VSB_data(n_arg)) <= 0)
103 0
                vtc_fatal(m->vl, "-n argument error: %s", VSM_Error(m->vsm));
104 40
        if (VSM_Attach(m->vsm, -1))
105 0
                vtc_fatal(m->vl, "VSM_Attach: %s", VSM_Error(m->vsm));
106
107 40
        VSB_destroy(&n_arg);
108 40
}
109
110
static void
111 40
vsm_delete(struct vtc_vsm *m)
112
{
113
114 40
        CHECK_OBJ_NOTNULL(m, VTC_VSM_MAGIC);
115 40
        if (m->vsm != NULL)
116 40
                vsm_detach(m);
117 40
        REPLACE(m->name, NULL);
118 40
        REPLACE(m->n_arg, NULL);
119 40
        vtc_logclose(m->vl);
120 40
        FREE_OBJ(m);
121 40
}
122
123
#define STATUS_BITS()                                   \
124
        STATUS_BIT(VSM_MGT_RUNNING,     mgt-running);   \
125
        STATUS_BIT(VSM_MGT_CHANGED,     mgt-changed);   \
126
        STATUS_BIT(VSM_MGT_RESTARTED,   mgt-restarted); \
127
        STATUS_BIT(VSM_WRK_RUNNING,     wrk-running);   \
128
        STATUS_BIT(VSM_WRK_CHANGED,     wrk-changed);   \
129
        STATUS_BIT(VSM_WRK_RESTARTED,   wrk-restarted);
130
131
static void
132 280
vsm_expect_status(struct vtc_vsm *m, const char *exp)
133
{
134
        struct vsb *stat;
135
        const char *sep;
136
        char **av;
137
        unsigned bstat, bexp, bfound;
138
        int argc, i;
139
140 280
        CHECK_OBJ_NOTNULL(m, VTC_VSM_MAGIC);
141 280
        if (exp == NULL)
142 0
                vtc_fatal(m->vl, "Missing expected status");
143
144 280
        if (m->vsm == NULL)
145 40
                vsm_attach(m);
146
147 280
        av = VAV_Parse(exp, &argc, ARGV_COMMA|ARGV_NOESC);
148 280
        AN(av);
149
150 280
        bexp = 0;
151 1080
        for (i = 1; i < argc; i++) {
152
#define STATUS_BIT(b, s)                                \
153
                if (!strcasecmp(#s, av[i])) {           \
154
                        bexp |= b;                      \
155
                        continue;                       \
156
                }
157 800
                STATUS_BITS()
158
#undef STATUS_BIT
159 0
                vtc_fatal(m->vl, "Unknown status bit: %s", av[i]);
160
        }
161 280
        VAV_Free(av);
162
163 280
        bfound = 0;
164 280
        bstat = VSM_Status(m->vsm);
165 280
        stat = VSB_new_auto();
166 280
        AN(stat);
167 280
        sep = "";
168
#define STATUS_BIT(b, s)                                \
169
        if (bstat & b) {                                \
170
                VSB_cat(stat, sep);                     \
171
                VSB_cat(stat, #s);                      \
172
                bfound |= b;                            \
173
                sep = ",";                              \
174
        }
175 280
        STATUS_BITS();
176
#undef STATUS_BIT
177
178 280
        if (bstat != bfound) {
179 0
                vtc_fatal(m->vl, "VSM status bits not handled: %x",
180 0
                    bstat & ~bfound);
181
        }
182
183 280
        if (bstat != bexp) {
184 0
                AZ(VSB_finish(stat));
185 0
                vtc_fatal(m->vl, "Expected VSM status '%s' got '%s'",
186 0
                    exp, VSB_data(stat));
187
        }
188
189 280
        VSB_destroy(&stat);
190 280
        vtc_log(m->vl, 4, "Found expected VSM status");
191 280
}
192
193
/* SECTION: vsm vsm
194
 *
195
 * Interact with the shared memory of a varnish instance.
196
 *
197
 * To define a VSM consumer, use this syntax::
198
 *
199
 *     vsm mNAME [-n STRING]
200
 *
201
 * Arguments:
202
 *
203
 * mNAME
204
 *         Identify the VSM consumer, it must starts with 'm'.
205
 *
206
 * \-n STRING
207
 *         Choose the working directory of the varnish instance. By default
208
 *         a VSM consumer connects to ``${v1_name}``.
209
 *
210
 * \-attach
211
 *         Attach to a new varnish instance. Implicitly detach from the
212
 *         current varnish instance if applicable.
213
 *
214
 * \-detach
215
 *         Detach from the current varnish instance.
216
 *
217
 * \-expect-status STRING
218
 *         Check that the status of VSM matches the list of status flags from
219
 *         STRING. The expected status is represented as a comma-separated
220
 *         list of flags. The list of flags in STRING is not sensitive to the
221
 *         order of flags.
222
 *
223
 *         The available flags are:
224
 *
225
 *         - ``mgt-running``
226
 *         - ``mgt-changed``
227
 *         - ``mgt-restarted``
228
 *         - ``wrk-running``
229
 *         - ``wrk-changed``
230
 *         - ``wrk-restarted``
231
 *
232
 *         Expecting a status automatically attaches to the varnish instance
233
 *         if that was not already the case.
234
 */
235
236
void
237 40400
cmd_vsm(CMD_ARGS)
238
{
239
        struct vtc_vsm *m, *m2;
240
241 40400
        (void)priv;
242
243 40400
        if (av == NULL) {
244
                /* Reset and free */
245 40160
                VTAILQ_FOREACH_SAFE(m, &vsms, list, m2) {
246 40
                        CHECK_OBJ_NOTNULL(m, VTC_VSM_MAGIC);
247 40
                        VTAILQ_REMOVE(&vsms, m, list);
248 40
                        vsm_delete(m);
249 40
                }
250 40120
                return;
251
        }
252
253 280
        AZ(strcmp(av[0], "vsm"));
254 280
        av++;
255
256 280
        VTC_CHECK_NAME(vl, av[0], "VSM", 'm');
257 280
        VTAILQ_FOREACH(m, &vsms, list) {
258 240
                if (!strcmp(m->name, av[0]))
259 240
                        break;
260 0
        }
261
262 280
        if (m == NULL) {
263 40
                m = vsm_new(*av);
264 40
                AN(m);
265 40
        }
266 280
        av++;
267
268 560
        for (; *av != NULL; av++) {
269 280
                if (vtc_error)
270 0
                        break;
271 280
                if (!strcmp(*av, "-attach")) {
272 0
                        vsm_attach(m);
273 0
                        continue;
274
                }
275 280
                if (!strcmp(*av, "-detach")) {
276 0
                        vsm_detach(m);
277 0
                        continue;
278
                }
279 280
                if (!strcmp(*av, "-expect-status")) {
280 280
                        vsm_expect_status(m, av[1]);
281 280
                        av++;
282 280
                        continue;
283
                }
284 0
                if (!strcmp(*av, "-n")) {
285 0
                        if (av[1] == NULL)
286 0
                                vtc_fatal(m->vl, "Missing -n argument");
287 0
                        REPLACE(m->n_arg, av[1]);
288 0
                        av++;
289 0
                        continue;
290
                }
291 0
                vtc_fatal(vl, "Unknown VSM argument: %s", *av);
292
        }
293 40400
}
294
295
#endif /* VTEST_WITH_VTC_VSM */