vinyl-cache/bin/vinyltest/vtest2/src/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 <stdlib.h>
35
#include <string.h>
36
#include <stdint.h>
37
38
#include "vapi/vsm.h"
39
40
#include "vtc.h"
41
#include "vav.h"
42
43
struct vtc_vsm {
44
        unsigned                        magic;
45
#define VTC_VSM_MAGIC                   0x5ca77a36
46
        VTAILQ_ENTRY(vtc_vsm)           list;
47
48
        char                            *name;
49
        char                            *n_arg;
50
        struct vtclog                   *vl;
51
        struct vsm                      *vsm;
52
};
53
54
static VTAILQ_HEAD(, vtc_vsm) vsms = VTAILQ_HEAD_INITIALIZER(vsms);
55
56
static struct vtc_vsm *
57 10
vsm_new(const char *name)
58
{
59
        struct vtc_vsm *m;
60
61 10
        ALLOC_OBJ(m, VTC_VSM_MAGIC);
62 10
        AN(m);
63 10
        REPLACE(m->name, name);
64 10
        REPLACE(m->n_arg, "${v1_name}");
65 10
        m->vl = vtc_logopen("%s", name);
66
67 10
        VTAILQ_INSERT_TAIL(&vsms, m, list);
68 10
        return (m);
69
}
70
71
static void
72 10
vsm_detach(struct vtc_vsm *m)
73
{
74
75 10
        CHECK_OBJ_NOTNULL(m, VTC_VSM_MAGIC);
76 10
        if (m->vsm == NULL)
77 0
                vtc_fatal(m->vl, "Cannot detach unattached VSM");
78 10
        vtc_log(m->vl, 3, "Detaching from VSM");
79 10
        VSM_Destroy(&m->vsm);
80 10
        AZ(m->vsm);
81 10
}
82
83
static void
84 10
vsm_attach(struct vtc_vsm *m)
85
{
86
        struct vsb *n_arg;
87
88 10
        CHECK_OBJ_NOTNULL(m, VTC_VSM_MAGIC);
89 10
        if (m->vsm != NULL)
90 0
                vsm_detach(m);
91
92 10
        n_arg = macro_expandf(m->vl, "%s", m->n_arg);
93 10
        if (n_arg == NULL)
94 0
                vtc_fatal(m->vl, "Could not expand -n argument");
95 10
        vtc_log(m->vl, 3, "Attaching to VSM: %s", VSB_data(n_arg));
96
97 10
        m->vsm = VSM_New();
98 10
        AN(m->vsm);
99
100 10
        if (VSM_Arg(m->vsm, 'n', VSB_data(n_arg)) <= 0)
101 0
                vtc_fatal(m->vl, "-n argument error: %s", VSM_Error(m->vsm));
102 10
        if (VSM_Attach(m->vsm, -1))
103 0
                vtc_fatal(m->vl, "VSM_Attach: %s", VSM_Error(m->vsm));
104
105 10
        VSB_destroy(&n_arg);
106 10
}
107
108
static void
109 10
vsm_delete(struct vtc_vsm *m)
110
{
111
112 10
        CHECK_OBJ_NOTNULL(m, VTC_VSM_MAGIC);
113 10
        if (m->vsm != NULL)
114 10
                vsm_detach(m);
115 10
        REPLACE(m->name, NULL);
116 10
        REPLACE(m->n_arg, NULL);
117 10
        vtc_logclose(m->vl);
118 10
        FREE_OBJ(m);
119 10
}
120
121
#define STATUS_BITS()                                   \
122
        STATUS_BIT(VSM_MGT_RUNNING,     mgt-running);   \
123
        STATUS_BIT(VSM_MGT_CHANGED,     mgt-changed);   \
124
        STATUS_BIT(VSM_MGT_RESTARTED,   mgt-restarted); \
125
        STATUS_BIT(VSM_WRK_RUNNING,     wrk-running);   \
126
        STATUS_BIT(VSM_WRK_CHANGED,     wrk-changed);   \
127
        STATUS_BIT(VSM_WRK_RESTARTED,   wrk-restarted);
128
129
static void
130 70
vsm_expect_status(struct vtc_vsm *m, const char *exp)
131
{
132
        struct vsb *stat;
133
        const char *sep;
134
        char **av;
135
        unsigned bstat, bexp, bfound;
136
        int argc, i;
137
138 70
        CHECK_OBJ_NOTNULL(m, VTC_VSM_MAGIC);
139 70
        if (exp == NULL)
140 0
                vtc_fatal(m->vl, "Missing expected status");
141
142 70
        if (m->vsm == NULL)
143 10
                vsm_attach(m);
144
145 70
        av = VAV_Parse(exp, &argc, ARGV_COMMA|ARGV_NOESC);
146 70
        AN(av);
147
148 70
        bexp = 0;
149 280
        for (i = 1; i < argc; i++) {
150
#define STATUS_BIT(b, s)                                \
151
                if (!strcasecmp(#s, av[i])) {           \
152
                        bexp |= b;                      \
153
                        continue;                       \
154
                }
155 210
                STATUS_BITS()
156
#undef STATUS_BIT
157 0
                vtc_fatal(m->vl, "Unknown status bit: %s", av[i]);
158
        }
159 70
        VAV_Free(av);
160
161 70
        bfound = 0;
162 70
        bstat = VSM_Status(m->vsm);
163 70
        stat = VSB_new_auto();
164 70
        AN(stat);
165 70
        sep = "";
166
#define STATUS_BIT(b, s)                                \
167
        if (bstat & b) {                                \
168
                VSB_cat(stat, sep);                     \
169
                VSB_cat(stat, #s);                      \
170
                bfound |= b;                            \
171
                sep = ",";                              \
172
        }
173 70
        STATUS_BITS();
174
#undef STATUS_BIT
175
176 70
        if (bstat != bfound) {
177 0
                vtc_fatal(m->vl, "VSM status bits not handled: %x",
178 0
                    bstat & ~bfound);
179
        }
180
181 70
        if (bstat != bexp) {
182 0
                AZ(VSB_finish(stat));
183 0
                vtc_fatal(m->vl, "Expected VSM status '%s' got '%s'",
184 0
                    exp, VSB_data(stat));
185
        }
186
187 70
        VSB_destroy(&stat);
188 70
        vtc_log(m->vl, 4, "Found expected VSM status");
189 70
}
190
191
/* SECTION: vsm vsm
192
 *
193
 * Interact with the shared memory of a varnish instance.
194
 *
195
 * To define a VSM consumer, use this syntax::
196
 *
197
 *     vsm mNAME [-n STRING]
198
 *
199
 * Arguments:
200
 *
201
 * mNAME
202
 *         Identify the VSM consumer, it must starts with 'm'.
203
 *
204
 * \-n STRING
205
 *         Choose the working directory of the varnish instance. By default
206
 *         a VSM consumer connects to ``${v1_name}``.
207
 *
208
 * \-attach
209
 *         Attach to a new varnish instance. Implicitly detach from the
210
 *         current varnish instance if applicable.
211
 *
212
 * \-detach
213
 *         Detach from the current varnish instance.
214
 *
215
 * \-expect-status STRING
216
 *         Check that the status of VSM matches the list of status flags from
217
 *         STRING. The expected status is represented as a comma-separated
218
 *         list of flags. The list of flags in STRING is not sensitive to the
219
 *         order of flags.
220
 *
221
 *         The available flags are:
222
 *
223
 *         - ``mgt-running``
224
 *         - ``mgt-changed``
225
 *         - ``mgt-restarted``
226
 *         - ``wrk-running``
227
 *         - ``wrk-changed``
228
 *         - ``wrk-restarted``
229
 *
230
 *         Expecting a status automatically attaches to the varnish instance
231
 *         if that was not already the case.
232
 */
233
234
void
235 5525
cmd_vsm(CMD_ARGS)
236
{
237
        struct vtc_vsm *m, *m2;
238
239 5525
        (void)priv;
240
241 5525
        if (av == NULL) {
242
                /* Reset and free */
243 5465
                VTAILQ_FOREACH_SAFE(m, &vsms, list, m2) {
244 10
                        CHECK_OBJ_NOTNULL(m, VTC_VSM_MAGIC);
245 10
                        VTAILQ_REMOVE(&vsms, m, list);
246 10
                        vsm_delete(m);
247 10
                }
248 5455
                return;
249
        }
250
251 70
        AZ(strcmp(av[0], "vsm"));
252 70
        av++;
253
254 70
        VTC_CHECK_NAME(vl, av[0], "VSM", 'm');
255 70
        VTAILQ_FOREACH(m, &vsms, list) {
256 60
                if (!strcmp(m->name, av[0]))
257 60
                        break;
258 0
        }
259
260 70
        if (m == NULL) {
261 10
                m = vsm_new(*av);
262 10
                AN(m);
263 10
        }
264 70
        av++;
265
266 140
        for (; *av != NULL; av++) {
267 70
                if (vtc_error)
268 0
                        break;
269 70
                if (!strcmp(*av, "-attach")) {
270 0
                        vsm_attach(m);
271 0
                        continue;
272
                }
273 70
                if (!strcmp(*av, "-detach")) {
274 0
                        vsm_detach(m);
275 0
                        continue;
276
                }
277 70
                if (!strcmp(*av, "-expect-status")) {
278 70
                        vsm_expect_status(m, av[1]);
279 70
                        av++;
280 70
                        continue;
281
                }
282 0
                if (!strcmp(*av, "-n")) {
283 0
                        if (av[1] == NULL)
284 0
                                vtc_fatal(m->vl, "Missing -n argument");
285 0
                        REPLACE(m->n_arg, av[1]);
286 0
                        av++;
287 0
                        continue;
288
                }
289 0
                vtc_fatal(vl, "Unknown VSM argument: %s", *av);
290
        }
291 5525
}
292
293
#endif /* VTEST_WITH_VTC_VSM */