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