vinyl-cache/bin/vinyltest/vtc_vinyl.c
0
/*-
1
 * Copyright (c) 2008-2015 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
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_VINYL
31
32
#include "config.h"
33
34
#include <sys/socket.h>
35
36
#include <errno.h>
37
#include <fcntl.h>
38
#include <fnmatch.h>
39
#include <inttypes.h>
40
#include <poll.h>
41
#include <stdio.h>
42
#include <stdlib.h>
43
#include <string.h>
44
#include <unistd.h>
45
46
#include "vtc.h"
47
48
#include "vapi/vsc.h"
49
#include "vapi/vsl.h"
50
#include "vapi/vsm.h"
51
#include "vcli.h"
52
#include "vjsn.h"
53
#include "vre.h"
54
#include "vsub.h"
55
#include "vtcp.h"
56
#include "vtim.h"
57
58
struct vinyl {
59
        unsigned                magic;
60
#define VINYL_MAGIC             0x208cd8e4
61
        char                    *me;
62
        char                    *name;
63
        struct vtclog           *vl;
64
        VTAILQ_ENTRY(vinyl)     list;
65
66
        struct vsb              *args;
67
        int                     fds[4];
68
        pid_t                   pid;
69
70
        double                  syntax;
71
72
        pthread_t               tp;
73
        pthread_t               tp_vsl;
74
        int                     tp_started;
75
76
        int                     expect_exit;
77
78
        int                     cli_fd;
79
        int                     vcl_nbr;
80
        char                    *workdir;
81
        char                    *jail;
82
        char                    *proto;
83
84
        struct vsm              *vsm_vsl;
85
        struct vsm              *vsm_vsc;
86
        struct vsc              *vsc;
87
        int                     has_a_arg;
88
89
        unsigned                vsl_tag_count[256];
90
91
        volatile int            vsl_rec;
92
        volatile int            vsl_idle;
93
};
94
95
#define NONSENSE        "%XJEIFLH|)Xspa8P"
96
97
static VTAILQ_HEAD(, vinyl)     vinyles =
98
    VTAILQ_HEAD_INITIALIZER(vinyles);
99
100
/**********************************************************************
101
 * Fatal condition cleanup
102
 * Invalid to call in any code path not followed by vtc_fatal().
103
 */
104
105
static void
106 4
vinyl_fatal_cleanup(const struct vinyl *v)
107
{
108
        struct pollfd fd[1];
109
        int n;
110
111 4
        if (!pthread_equal(pthread_self(), vtc_thread))
112 0
                return;
113
114 4
        if (!v->tp_started)
115 4
                return;
116
117 0
        memset(fd, 0, sizeof(fd));
118 0
        fd[0].fd = v->fds[0];
119 0
        fd[0].events = POLLIN;
120
121 0
        do {
122 0
                n = poll(fd, sizeof(fd)/sizeof(fd[0]), 10);
123 0
                if (n == 1 && (fd[0].revents & (POLLHUP|POLLERR)) != 0) {
124 0
                        PTOK(pthread_join(v->tp, NULL));
125 0
                        break;
126
                }
127
128 0
                if (n == 1)
129 0
                        VTIM_sleep(0.01);
130 0
        } while (n > 0);
131 4
}
132
133
#define vinyl_fatal(v, ...)                                             \
134
    do {                                                                \
135
            vinyl_fatal_cleanup((v));                                   \
136
            vtc_fatal((v)->vl, __VA_ARGS__);                            \
137
    } while (0)
138
139
/**********************************************************************
140
 * Ask a question over CLI
141
 */
142
143
static enum VCLI_status_e
144 60512
vinyl_ask_cli(const struct vinyl *v, const char *cmd, char **repl)
145
{
146
        int i;
147
        unsigned retval;
148
        char *r;
149
150 60512
        if (cmd != NULL) {
151 56520
                vtc_dump(v->vl, 4, "CLI TX", cmd, -1);
152 56520
                i = write(v->cli_fd, cmd, vstrlen(cmd));
153 56520
                if (i != vstrlen(cmd) && !vtc_stop)
154 0
                        vinyl_fatal(v, "CLI write failed (%s) = %u %s",
155
                            cmd, errno, strerror(errno));
156 0
                i = write(v->cli_fd, "\n", 1);
157 0
                if (i != 1 && !vtc_stop)
158 0
                        vinyl_fatal(v, "CLI write failed (%s) = %u %s",
159
                            cmd, errno, strerror(errno));
160 56520
        }
161 113040
        i = VCLI_ReadResult(v->cli_fd, &retval, &r, vtc_maxdur);
162 113040
        if (i != 0 && !vtc_stop)
163 0
                vinyl_fatal(v, "CLI failed (%s) = %d %u %s",
164
                    cmd != NULL ? cmd : "NULL", i, retval, r);
165 60512
        vtc_log(v->vl, 3, "CLI RX  %u", retval);
166 60512
        vtc_dump(v->vl, 4, "CLI RX", r, -1);
167 60512
        if (repl != NULL)
168 38660
                *repl = r;
169
        else
170 21852
                free(r);
171 60512
        return ((enum VCLI_status_e)retval);
172
}
173
174
/**********************************************************************
175
 *
176
 */
177
178
static void
179 4224
wait_stopped(const struct vinyl *v)
180
{
181 4224
        char *r = NULL;
182
        enum VCLI_status_e st;
183
184 4224
        vtc_log(v->vl, 3, "wait-stopped");
185 4224
        while (1) {
186 4224
                st = vinyl_ask_cli(v, "status", &r);
187 4224
                if (st != CLIS_OK)
188 0
                        vinyl_fatal(v,
189
                            "CLI status command failed: %u %s", st, r);
190 4224
                if (!vstrcmp(r, "Child in state stopped")) {
191 4224
                        free(r);
192 4224
                        break;
193
                }
194 0
                free(r);
195 0
                r = NULL;
196 0
                VTIM_sleep(0.2);
197
        }
198 4224
}
199
/**********************************************************************
200
 *
201
 */
202
203
static void
204 3948
wait_running(const struct vinyl *v)
205
{
206 3948
        char *r = NULL;
207
        enum VCLI_status_e st;
208
209 3948
        while (1) {
210 3948
                vtc_log(v->vl, 3, "wait-running");
211 3948
                st = vinyl_ask_cli(v, "status", &r);
212 3948
                if (st != CLIS_OK)
213 0
                        vinyl_fatal(v,
214
                            "CLI status command failed: %u %s", st, r);
215 0
                if (!vstrcmp(r, "Child in state stopped"))
216 0
                        vinyl_fatal(v,
217
                            "Child stopped before running: %u %s", st, r);
218 3948
                if (!vstrcmp(r, "Child in state running")) {
219 3948
                        free(r);
220 3948
                        r = NULL;
221 3948
                        st = vinyl_ask_cli(v, "debug.listen_address", &r);
222 3948
                        if (st != CLIS_OK)
223 0
                                vinyl_fatal(v,
224
                                    "CLI status command failed: %u %s", st, r);
225 3948
                        free(r);
226 3948
                        break;
227
                }
228 0
                free(r);
229 0
                r = NULL;
230 0
                VTIM_sleep(0.2);
231
        }
232 3948
}
233
234
/**********************************************************************
235
 * Vinyllog gatherer thread
236
 */
237
238
static void *
239 3992
vinyllog_thread(void *priv)
240
{
241
        struct vinyl *v;
242
        struct VSL_data *vsl;
243
        struct vsm *vsm;
244
        struct VSL_cursor *c;
245
        enum VSL_tag_e tag;
246
        uint64_t vxid;
247
        unsigned len, vs;
248
        const char *tagname, *data;
249
        int type, i, opt;
250 3992
        struct vsb *vsb = NULL;
251
252 3992
        CAST_OBJ_NOTNULL(v, priv, VINYL_MAGIC);
253
254 3992
        vsl = VSL_New();
255 3992
        AN(vsl);
256 3992
        vsm = v->vsm_vsl;
257
258 3992
        c = NULL;
259 3992
        opt = 0;
260 127263
        while (v->fds[1] > 0 || c != NULL) {    //lint !e845 bug in flint
261 123271
                if (c == NULL) {
262 36451
                        if (vtc_error)
263 0
                                break;
264 36451
                        VTIM_sleep(0.1);
265 36451
                        (void)VSM_Status(vsm);
266 36451
                        c = VSL_CursorVSM(vsl, vsm, opt);
267 36451
                        if (c == NULL) {
268 25902
                                vtc_log(v->vl, 3, "vsl|%s", VSL_Error(vsl));
269 25902
                                VSL_ResetError(vsl);
270 25902
                                continue;
271
                        }
272 10549
                }
273 97369
                AN(c);
274
275 97369
                opt = VSL_COPT_TAIL;
276
277 1342273
                while (1) {
278 1342273
                        i = VSL_Next(c);
279 1342273
                        if (i != 1)
280 97369
                                break;
281
282 1244904
                        v->vsl_rec = 1;
283
284 1244904
                        tag = VSL_TAG(c->rec.ptr);
285 1244904
                        vxid = VSL_ID(c->rec.ptr);
286 1244904
                        if (tag == SLT__Batch)
287 0
                                continue;
288 1244904
                        tagname = VSL_tags[tag];
289 1244904
                        len = VSL_LEN(c->rec.ptr);
290 1244904
                        type = VSL_CLIENT(c->rec.ptr) ?
291 491860
                            'c' : VSL_BACKEND(c->rec.ptr) ?
292
                            'b' : '-';
293 1244904
                        data = VSL_CDATA(c->rec.ptr);
294 1244904
                        v->vsl_tag_count[tag]++;
295 1244904
                        if (VSL_tagflags[tag] & SLT_F_BINARY) {
296 5996
                                if (vsb == NULL)
297 220
                                        vsb = VSB_new_auto();
298 5996
                                VSB_clear(vsb);
299 5996
                                VSB_quote(vsb, data, len, VSB_QUOTE_HEX);
300 5996
                                AZ(VSB_finish(vsb));
301
                                /* +2 to skip "0x" */
302 11992
                                vtc_log(v->vl, 4, "vsl| %10ju %-15s %c [%s]",
303 5996
                                    (uintmax_t)vxid, tagname, type,
304 5996
                                    VSB_data(vsb) + 2);
305 5996
                        } else {
306 2477816
                                vtc_log(v->vl, 4, "vsl| %10ju %-15s %c %.*s",
307 1238908
                                    (uintmax_t)vxid, tagname, type, (int)len,
308 1238908
                                    data);
309
                        }
310
                }
311 97369
                if (i == 0) {
312
                        /* Nothing to do but wait */
313 97369
                        v->vsl_idle++;
314 97369
                        vs = VSM_Status(vsm) & VSM_WRK_MASK;
315 97369
                        if ((vs & ~VSM_WRK_CHANGED) != VSM_WRK_RUNNING) {
316
                                /* Abandoned - try reconnect */
317 10549
                                VSL_DeleteCursor(c);
318 10549
                                c = NULL;
319 10549
                        } else {
320 86820
                                VTIM_sleep(0.1);
321
                        }
322 97369
                } else if (i == -2) {
323
                        /* Abandoned - try reconnect */
324 0
                        VSL_DeleteCursor(c);
325 0
                        c = NULL;
326 0
                } else
327 0
                        break;
328
        }
329
330 0
        if (c)
331 0
                VSL_DeleteCursor(c);
332 220
        VSL_Delete(vsl);
333 220
        if (vsb != NULL)
334 220
                VSB_destroy(&vsb);
335
336 3992
        return (NULL);
337
}
338
339
/**********************************************************************
340
 * Allocate and initialize a vinyl
341
 */
342
343
static struct vinyl *
344 3996
vinyl_new(const char *name)
345
{
346
        struct vinyl *v;
347
        struct vsb *vsb;
348
        char buf[1024];
349
350 3996
        ALLOC_OBJ(v, VINYL_MAGIC);
351 3996
        AN(v);
352 3996
        REPLACE(v->name, name);
353
354 3996
        REPLACE(v->jail, "");
355
356 3996
        v->vl = vtc_logopen("%s", name);
357 3996
        AN(v->vl);
358
359 3996
        vsb = macro_expandf(v->vl, "${tmpdir}/%s", name);
360 3996
        AN(vsb);
361 3996
        v->workdir = strdup(VSB_data(vsb));
362 3996
        AN(v->workdir);
363 3996
        VSB_destroy(&vsb);
364
365 3996
        bprintf(buf, "rm -rf %s ; mkdir -p %s", v->workdir, v->workdir);
366 3996
        AZ(system(buf));
367
368 3996
        v->args = VSB_new_auto();
369
370 3996
        v->cli_fd = -1;
371 3996
        VTAILQ_INSERT_TAIL(&vinyles, v, list);
372
373 3996
        return (v);
374
}
375
376
/**********************************************************************
377
 * Delete a vinyl instance
378
 */
379
380
static void
381 3996
vinyl_delete(struct vinyl *v)
382
{
383
384 3996
        CHECK_OBJ_NOTNULL(v, VINYL_MAGIC);
385 3996
        vtc_logclose(v->vl);
386 3996
        free(v->name);
387 3996
        free(v->jail);
388 3996
        free(v->workdir);
389 3996
        VSB_destroy(&v->args);
390 3996
        if (v->vsc != NULL)
391 3992
                VSC_Destroy(&v->vsc, v->vsm_vsc);
392 3992
        if (v->vsm_vsc != NULL)
393 3992
                VSM_Destroy(&v->vsm_vsc);
394 3992
        if (v->vsm_vsl != NULL)
395 3992
                VSM_Destroy(&v->vsm_vsl);
396
397
        /*
398
         * We do not delete the workdir, it may contain stuff people
399
         * want (coredumps, shmlog/stats etc), and trying to divine
400
         * "may want" is just too much trouble.  Leave it around and
401
         * nuke it at the start of the next test-run.
402
         */
403
404
        /* XXX: MEMLEAK (?) */
405 3996
        FREE_OBJ(v);
406 3996
}
407
408
/**********************************************************************
409
 * Vinyl listener
410
 */
411
412
static void *
413 3992
vinyl_thread(void *priv)
414
{
415
        struct vinyl *v;
416
417 3992
        CAST_OBJ_NOTNULL(v, priv, VINYL_MAGIC);
418 3992
        return (vtc_record(v->vl, v->fds[0], NULL));
419
}
420
421
/**********************************************************************
422
 * Launch a Vinyl
423
 */
424
425
static void
426 3992
vinyl_launch(struct vinyl *v)
427
{
428
        struct vsb *vsb, *vsb1;
429
        int i, nfd, asock;
430
        char abuf[VTCP_ADDRBUFSIZE];
431
        char pbuf[VTCP_PORTBUFSIZE];
432
        char lbuf[PATH_MAX];
433
        struct pollfd fd[3];
434
        enum VCLI_status_e u;
435
        const char *err;
436 3992
        char *r = NULL;
437
438
        /* Create listener socket */
439 3992
        asock = VTCP_listen_on(default_listen_addr, NULL, 1, &err);
440 3992
        if (err != NULL)
441 0
                vinyl_fatal(v, "Create CLI listen socket failed: %s", err);
442 3992
        assert(asock > 0);
443 3992
        VTCP_myname(asock, abuf, sizeof abuf, pbuf, sizeof pbuf);
444
445 3992
        AZ(VSB_finish(v->args));
446 3992
        vtc_log(v->vl, 2, "Launch");
447 3992
        vsb = VSB_new_auto();
448 3992
        AN(vsb);
449 3992
        VSB_cat(vsb, "cd ${pwd} &&");
450 7984
        VSB_printf(vsb, " exec %sd %s -d -n %s -i %s",
451 3992
            v->me, v->jail, v->workdir, v->name);
452 3992
        if (macro_isdef(NULL, "vinyld_args_prepend")) {
453 0
                VSB_putc(vsb, ' ');
454 0
                macro_cat(v->vl, vsb, "vinyld_args_prepend", NULL);
455 0
        }
456 0
        VSB_cat(vsb, VSB_data(params_vsb));
457 0
        if (leave_temp) {
458 0
                VSB_cat(vsb, " -p debug=+vcl_keep");
459 0
                VSB_cat(vsb, " -p debug=+vmod_so_keep");
460 0
                VSB_cat(vsb, " -p debug=+vsm_keep");
461 0
        }
462 3852
        VSB_cat(vsb, " -l 2m");
463 3852
        VSB_cat(vsb, " -p auto_restart=off");
464 3852
        VSB_cat(vsb, " -p syslog_cli_traffic=off");
465 3852
        VSB_cat(vsb, " -p thread_pool_min=10");
466 3852
        VSB_cat(vsb, " -p debug=+vtc_mode");
467 3852
        VSB_cat(vsb, " -p vsl_mask=+Debug,+H2RxHdr,+H2RxBody");
468 3852
        VSB_cat(vsb, " -p h2_initial_window_size=1m");
469 3852
        VSB_cat(vsb, " -p h2_rx_window_low_water=64k");
470 3852
        if (!v->has_a_arg) {
471 3852
                VSB_printf(vsb, " -a '%s'", default_listen_addr);
472 3852
                if (v->proto != NULL)
473 64
                        VSB_printf(vsb, ",%s", v->proto);
474 3852
        }
475 3988
        VSB_printf(vsb, " -M '%s %s'", abuf, pbuf);
476 3988
        VSB_printf(vsb, " -P %s/%sd.pid", v->workdir, v->me);
477 3988
        if (vmod_path != NULL)
478 3988
                VSB_printf(vsb, " -p vmod_path=%s", vmod_path);
479 7976
        VSB_printf(vsb, " %s", VSB_data(v->args));
480 7976
        if (macro_isdef(NULL, "vinyld_args_append")) {
481 0
                VSB_putc(vsb, ' ');
482 0
                macro_cat(v->vl, vsb, "vinyld_args_append", NULL);
483 0
        }
484 3992
        AZ(VSB_finish(vsb));
485 3992
        vtc_log(v->vl, 3, "CMD: %s", VSB_data(vsb));
486 3992
        vsb1 = macro_expand(v->vl, VSB_data(vsb));
487 3992
        AN(vsb1);
488 3992
        VSB_destroy(&vsb);
489 3992
        vsb = vsb1;
490 3992
        vtc_log(v->vl, 3, "CMD: %s", VSB_data(vsb));
491 3992
        AZ(pipe(&v->fds[0]));
492 3992
        AZ(pipe(&v->fds[2]));
493 3992
        v->pid = fork();
494 3992
        assert(v->pid >= 0);
495 7984
        if (v->pid == 0) {
496 3992
                AZ(dup2(v->fds[0], 0));
497 3992
                assert(dup2(v->fds[3], 1) == 1);
498 3992
                assert(dup2(1, 2) == 2);
499 3992
                closefd(&v->fds[0]);
500 3992
                closefd(&v->fds[1]);
501 3992
                closefd(&v->fds[2]);
502 3992
                closefd(&v->fds[3]);
503 3992
                VSUB_closefrom(STDERR_FILENO + 1);
504 3992
                AZ(execl("/bin/sh", "/bin/sh", "-c", VSB_data(vsb), (char*)0));
505 0
                exit(1);
506
        } else {
507 3992
                vtc_log(v->vl, 3, "PID: %ld", (long)v->pid);
508 3992
                macro_def(v->vl, v->name, "pid", "%ld", (long)v->pid);
509 3992
                macro_def(v->vl, v->name, "name", "%s", v->workdir);
510
        }
511 3992
        closefd(&v->fds[0]);
512 3992
        closefd(&v->fds[3]);
513 3992
        v->fds[0] = v->fds[2];
514 3992
        v->fds[2] = v->fds[3] = -1;
515 3992
        VSB_destroy(&vsb);
516 3992
        AZ(v->tp_started);
517 3992
        v->tp_started = 1;
518 3992
        PTOK(pthread_create(&v->tp, NULL, vinyl_thread, v));
519
520
        /* Wait for the vinyl to call home */
521 3992
        memset(fd, 0, sizeof fd);
522 3992
        fd[0].fd = asock;
523 3992
        fd[0].events = POLLIN;
524 3992
        fd[1].fd = v->fds[1];
525 3992
        fd[1].events = POLLIN;
526 3992
        fd[2].fd = v->fds[2];
527 3992
        fd[2].events = POLLIN;
528 3992
        i = poll(fd, 2, (int)(vtc_maxdur * 1000 / 3));
529 7984
        vtc_log(v->vl, 4, "CLIPOLL %d 0x%x 0x%x 0x%x",
530 3992
            i, fd[0].revents, fd[1].revents, fd[2].revents);
531 3992
        if (i == 0)
532 0
                vinyl_fatal(v, "FAIL timeout waiting for CLI connection");
533 0
        if (fd[1].revents & POLLHUP)
534 0
                vinyl_fatal(v, "FAIL debug pipe closed");
535 0
        if (!(fd[0].revents & POLLIN))
536 0
                vinyl_fatal(v, "FAIL CLI connection wait failure");
537 3992
        nfd = accept(asock, NULL, NULL);
538 3992
        closefd(&asock);
539 3992
        if (nfd < 0)
540 0
                vinyl_fatal(v, "FAIL no CLI connection accepted");
541
542 3992
        v->cli_fd = nfd;
543
544 3992
        vtc_log(v->vl, 3, "CLI connection fd = %d", v->cli_fd);
545 3992
        assert(v->cli_fd >= 0);
546
547
        /* Receive the banner or auth response */
548 3992
        u = vinyl_ask_cli(v, NULL, &r);
549 3992
        if (vtc_error)
550 0
                return;
551 3992
        if (u != CLIS_AUTH)
552 0
                vinyl_fatal(v, "CLI auth demand expected: %u %s", u, r);
553
554 3992
        bprintf(lbuf, "%s/_.secret", v->workdir);
555 3992
        nfd = open(lbuf, O_RDONLY);
556 3992
        assert(nfd >= 0);
557
558 3992
        assert(sizeof lbuf >= CLI_AUTH_RESPONSE_LEN + 7);
559 3992
        bstrcpy(lbuf, "auth ");
560 3992
        VCLI_AuthResponse(nfd, r, lbuf + 5);
561 3992
        closefd(&nfd);
562 3992
        free(r);
563 3992
        r = NULL;
564 3992
        strcat(lbuf, "\n");
565
566 3992
        u = vinyl_ask_cli(v, lbuf, &r);
567 3992
        if (vtc_error)
568 0
                return;
569 3992
        if (u != CLIS_OK)
570 0
                vinyl_fatal(v, "CLI auth command failed: %u %s", u, r);
571 3992
        free(r);
572
573 3992
        v->vsm_vsc = VSM_New();
574 3992
        AN(v->vsm_vsc);
575 3992
        v->vsc = VSC_New();
576 3992
        AN(v->vsc);
577 3992
        assert(VSM_Arg(v->vsm_vsc, 'n', v->workdir) > 0);
578 3992
        AZ(VSM_Attach(v->vsm_vsc, -1));
579
580 3992
        v->vsm_vsl = VSM_New();
581 3992
        assert(VSM_Arg(v->vsm_vsl, 'n', v->workdir) > 0);
582 3992
        AZ(VSM_Attach(v->vsm_vsl, -1));
583
584 3992
        PTOK(pthread_create(&v->tp_vsl, NULL, vinyllog_thread, v));
585 3992
}
586
587
#define VINYL_LAUNCH(v)                         \
588
        do {                                            \
589
                CHECK_OBJ_NOTNULL(v, VINYL_MAGIC);      \
590
                if (v->cli_fd < 0)                      \
591
                        vinyl_launch(v);                \
592
                if (vtc_error)                          \
593
                        return;                         \
594
        } while (0)
595
596
/**********************************************************************
597
 * Start a Vinyl
598
 */
599
600
static void
601 3936
vinyl_listen(const struct vinyl *v, char *la)
602
{
603
        const char *a, *p, *n, *n2;
604
        char m[64], s[256];
605
        unsigned first;
606
607 3936
        n2 = "";
608 3936
        first = 1;
609
610 7892
        while (*la != '\0') {
611 3956
                n = la;
612 3956
                la = strchr(la, ' ');
613 3956
                AN(la);
614 3956
                *la = '\0';
615 3956
                a = ++la;
616 3956
                la = strchr(la, ' ');
617 3956
                AN(la);
618 3956
                *la = '\0';
619 3956
                p = ++la;
620 3956
                la = strchr(la, '\n');
621 3956
                AN(la);
622 3956
                *la = '\0';
623 3956
                la++;
624
625 3956
                AN(*n);
626 3956
                AN(*a);
627 3956
                AN(*p);
628
629 3956
                if (*p == '-') {
630 112
                        bprintf(s, "%s", a);
631 112
                        a = "0.0.0.0";
632 112
                        p = "0";
633 3956
                } else if (strchr(a, ':')) {
634 0
                        bprintf(s, "[%s]:%s", a, p);
635 0
                } else {
636 3844
                        bprintf(s, "%s:%s", a, p);
637
                }
638
639 3956
                if (first) {
640 3936
                        vtc_log(v->vl, 2, "Listen on %s %s", a, p);
641 3936
                        macro_def(v->vl, v->name, "addr", "%s", a);
642 3936
                        macro_def(v->vl, v->name, "port", "%s", p);
643 3936
                        macro_def(v->vl, v->name, "sock", "%s", s);
644 3936
                        first = 0;
645 3936
                }
646
647 3956
                if (!vstrcmp(n, n2))
648 0
                        continue;
649
650 3956
                bprintf(m, "%s_addr", n);
651 3956
                macro_def(v->vl, v->name, m, "%s", a);
652 3956
                bprintf(m, "%s_port", n);
653 3956
                macro_def(v->vl, v->name, m, "%s", p);
654 3956
                bprintf(m, "%s_sock", n);
655 3956
                macro_def(v->vl, v->name, m, "%s", s);
656 3956
                n2 = n;
657
        }
658 3936
}
659
660
static void
661 3936
vinyl_start(struct vinyl *v)
662
{
663
        enum VCLI_status_e u;
664 3936
        char *resp = NULL;
665
666 3936
        VINYL_LAUNCH(v);
667 3936
        vtc_log(v->vl, 2, "Start");
668 3936
        u = vinyl_ask_cli(v, "start", &resp);
669 3936
        if (vtc_error)
670 0
                return;
671 3936
        if (u != CLIS_OK)
672 0
                vinyl_fatal(v, "CLI start command failed: %u %s", u, resp);
673 3936
        wait_running(v);
674 3936
        free(resp);
675 3936
        resp = NULL;
676 3936
        u = vinyl_ask_cli(v, "debug.xid 1000", &resp);
677 3936
        if (vtc_error)
678 0
                return;
679 3936
        if (u != CLIS_OK)
680 0
                vinyl_fatal(v, "CLI debug.xid command failed: %u %s",
681
                    u, resp);
682 3936
        free(resp);
683 3936
        resp = NULL;
684 3936
        u = vinyl_ask_cli(v, "debug.listen_address", &resp);
685 3936
        if (vtc_error)
686 0
                return;
687 3936
        if (u != CLIS_OK)
688 0
                vinyl_fatal(v,
689
                    "CLI debug.listen_address command failed: %u %s", u, resp);
690 3936
        vinyl_listen(v, resp);
691 3936
        free(resp);
692
        /* Wait for vsl logging to get underway */
693 3936
        while (v->vsl_rec == 0)
694 0
                VTIM_sleep(.1);
695 3936
}
696
697
/**********************************************************************
698
 * Stop a Vinyl
699
 */
700
701
static void
702 4212
vinyl_stop(struct vinyl *v)
703
{
704
705 4212
        VINYL_LAUNCH(v);
706 4212
        vtc_log(v->vl, 2, "Stop");
707 4212
        (void)vinyl_ask_cli(v, "stop", NULL);
708 4212
        wait_stopped(v);
709 4212
}
710
711
/**********************************************************************
712
 * Cleanup
713
 */
714
715
static void
716 3992
vinyl_cleanup(struct vinyl *v)
717
{
718
        void *p;
719
720
        /* Close the CLI connection */
721 3992
        closefd(&v->cli_fd);
722
723
        /* Close the STDIN connection. */
724 3992
        closefd(&v->fds[1]);
725
726
        /* Wait until STDOUT+STDERR closes */
727 3992
        AN(v->tp_started);
728 3992
        PTOK(pthread_join(v->tp, &p));
729 3992
        closefd(&v->fds[0]);
730 3992
        v->tp_started = 0;
731
732
        /* Pick up the VSL thread */
733 3992
        PTOK(pthread_join(v->tp_vsl, &p));
734
735 3992
        vtc_wait4(v->vl, v->pid, v->expect_exit, 0, 0);
736 3992
        v->pid = 0;
737 3992
}
738
739
/**********************************************************************
740
 * Wait for a Vinyl
741
 */
742
743
static void
744 3980
vinyl_wait(struct vinyl *v)
745
{
746 3980
        if (v->cli_fd < 0)
747 0
                return;
748
749 3980
        vtc_log(v->vl, 2, "Wait");
750
751 3980
        if (!vtc_error) {
752
                /* Do a backend.list to log if child is still running */
753 3980
                (void)vinyl_ask_cli(v, "backend.list", NULL);
754 3980
        }
755
756
        /* Then stop it */
757 7960
        vinyl_stop(v);
758
759 7960
        if (vinyl_ask_cli(v, "panic.show", NULL) != CLIS_CANT)
760 0
                vinyl_fatal(v, "Unexpected panic");
761
762 3980
        vinyl_cleanup(v);
763 3980
}
764
765
766
/**********************************************************************
767
 * Ask a CLI JSON question
768
 */
769
770
static void
771 152
vinyl_cli_json(struct vinyl *v, const char *cli)
772
{
773
        enum VCLI_status_e u;
774 152
        char *resp = NULL;
775
        const char *errptr;
776
        struct vjsn *vj;
777
778 152
        VINYL_LAUNCH(v);
779 152
        u = vinyl_ask_cli(v, cli, &resp);
780 152
        vtc_log(v->vl, 2, "CLI %03u <%s>", u, cli);
781 152
        if (u != CLIS_OK)
782 0
                vinyl_fatal(v,
783
                    "FAIL CLI response %u expected %u", u, CLIS_OK);
784 0
        vj = vjsn_parse(resp, &errptr);
785 0
        if (vj == NULL)
786 0
                vinyl_fatal(v, "FAIL CLI, not good JSON: %s", errptr);
787 152
        vjsn_delete(&vj);
788 152
        free(resp);
789 152
}
790
791
/**********************************************************************
792
 * Ask a CLI question
793
 */
794
795
static void
796 5240
vinyl_cli(struct vinyl *v, const char *cli, unsigned exp, const char *re,
797
    int neg)
798
{
799
        enum VCLI_status_e u;
800
        struct vsb vsb[1];
801 5240
        vre_t *vre = NULL;
802 5240
        char *resp = NULL, errbuf[VRE_ERROR_LEN];
803
        int err, erroff;
804
805 5240
        VINYL_LAUNCH(v);
806 5240
        if (re != NULL) {
807 424
                vre = VRE_compile(re, 0, &err, &erroff, 1);
808 424
                if (vre == NULL) {
809 0
                        AN(VSB_init(vsb, errbuf, sizeof errbuf));
810 0
                        AZ(VRE_error(vsb, err));
811 0
                        AZ(VSB_finish(vsb));
812 0
                        VSB_fini(vsb);
813 0
                        vinyl_fatal(v, "Illegal regexp: %s (@%d)",
814
                            errbuf, erroff);
815 0
                }
816 424
        }
817 4624
        u = vinyl_ask_cli(v, cli, &resp);
818 4624
        vtc_log(v->vl, 2, "CLI %03u <%s>", u, cli);
819 4624
        if (exp != 0 && exp != (unsigned)u)
820 0
                vinyl_fatal(v, "FAIL CLI response %u expected %u", u, exp);
821 424
        if (vre != NULL) {
822 424
                err = VRE_match(vre, resp, 0, 0, NULL);
823 424
                if (err < VRE_ERROR_NOMATCH) {
824 0
                        AN(VSB_init(vsb, errbuf, sizeof errbuf));
825 0
                        AZ(VRE_error(vsb, err));
826 0
                        AZ(VSB_finish(vsb));
827 0
                        VSB_fini(vsb);
828 0
                        vinyl_fatal(v, "Regexp failed: %s with %s (%d)",
829
                            re, errbuf, err);
830 424
                } else if ((err == VRE_ERROR_NOMATCH) == (neg == 0)) { /*lint !e731 */
831 0
                        vinyl_fatal(v, "Expect failed: regexp \"%s\" did%s "
832
                            "match response \"%s\"", re, neg ? "" : " not",
833
                            resp);
834 0
                }
835 424
                VRE_free(&vre);
836 424
        }
837 5240
        free(resp);
838 5240
}
839
840
static const char *
841 6196
vcl_prepend(void)
842
{
843
        const char *vcl_pfx;
844
845 6196
        vcl_pfx = getenv("VTEST_VINYL_VCL_PREPEND");
846 6196
        return vcl_pfx ? vcl_pfx : "";
847
}
848
849
/**********************************************************************
850
 * Load a VCL program
851
 */
852
853
static void
854 2548
vinyl_vcl(struct vinyl *v, const char *vcl, int fail, char **resp)
855
{
856
        struct vsb *vsb;
857
        enum VCLI_status_e u;
858
859 2548
        VINYL_LAUNCH(v);
860 2548
        vsb = VSB_new_auto();
861 2548
        AN(vsb);
862
863 5096
        VSB_printf(vsb, "vcl.inline vcl%d << %s\nvcl %.1f;\n%s%s\n%s\n",
864 2548
            ++v->vcl_nbr, NONSENSE, v->syntax,
865 2548
            vcl_prepend(), vcl, NONSENSE);
866 2548
        AZ(VSB_finish(vsb));
867
868 2548
        u = vinyl_ask_cli(v, VSB_data(vsb), resp);
869 2548
        if (u == CLIS_OK) {
870 1192
                VSB_clear(vsb);
871 1192
                VSB_printf(vsb, "vcl.use vcl%d", v->vcl_nbr);
872 1192
                AZ(VSB_finish(vsb));
873 1192
                u = vinyl_ask_cli(v, VSB_data(vsb), NULL);
874 1192
        }
875 1192
        if (u == CLIS_OK && fail) {
876 0
                VSB_destroy(&vsb);
877 0
                vinyl_fatal(v, "VCL compilation succeeded expected failure");
878 1356
        } else if (u != CLIS_OK && !fail) {
879 0
                VSB_destroy(&vsb);
880 0
                vinyl_fatal(v, "VCL compilation failed expected success");
881 1356
        } else if (fail)
882 1356
                vtc_log(v->vl, 2, "VCL compilation failed (as expected)");
883 2548
        VSB_destroy(&vsb);
884 2548
}
885
886
/**********************************************************************
887
 * Load a VCL program prefixed by backend decls for our servers
888
 */
889
890
static void
891 3648
vinyl_vclbackend(struct vinyl *v, const char *vcl)
892
{
893
        struct vsb *vsb, *vsb2;
894
        enum VCLI_status_e u;
895
896 3648
        VINYL_LAUNCH(v);
897 3648
        vsb = VSB_new_auto();
898 3648
        AN(vsb);
899
900 3648
        vsb2 = VSB_new_auto();
901 3648
        AN(vsb2);
902
903 3648
        VSB_printf(vsb2, "vcl %.1f;\n", v->syntax);
904
905 3648
        cmd_server_gen_vcl(vsb2);
906
907 3648
        AZ(VSB_finish(vsb2));
908
909 7296
        VSB_printf(vsb, "vcl.inline vcl%d << %s\n%s\n%s%s\n%s\n",
910 3648
            ++v->vcl_nbr, NONSENSE, VSB_data(vsb2), vcl_prepend(),
911 3648
            vcl, NONSENSE);
912 3648
        AZ(VSB_finish(vsb));
913
914 3648
        u = vinyl_ask_cli(v, VSB_data(vsb), NULL);
915 3648
        if (u != CLIS_OK) {
916 0
                VSB_destroy(&vsb);
917 0
                VSB_destroy(&vsb2);
918 0
                vinyl_fatal(v, "FAIL VCL does not compile");
919 0
        }
920 3648
        VSB_clear(vsb);
921 3648
        VSB_printf(vsb, "vcl.use vcl%d", v->vcl_nbr);
922 3648
        AZ(VSB_finish(vsb));
923 3648
        u = vinyl_ask_cli(v, VSB_data(vsb), NULL);
924 3648
        assert(u == CLIS_OK);
925 3648
        VSB_destroy(&vsb);
926 3648
        VSB_destroy(&vsb2);
927 3648
}
928
929
/**********************************************************************
930
 */
931
932
struct dump_priv {
933
        const char *arg;
934
        const struct vinyl *v;
935
};
936
937
static int
938 16660
do_stat_dump_cb(void *priv, const struct VSC_point * const pt)
939
{
940
        const struct vinyl *v;
941
        struct dump_priv *dp;
942
        uint64_t u;
943
944 16660
        if (pt == NULL)
945 0
                return (0);
946 16660
        dp = priv;
947 16660
        v = dp->v;
948
949 16660
        if (vstrcmp(pt->ctype, "uint64_t"))
950 0
                return (0);
951 16660
        u = VSC_Value(pt);
952
953 16660
        if (vstrcmp(dp->arg, "*")) {
954 16660
                if (fnmatch(dp->arg, pt->name, 0))
955 16102
                        return (0);
956 558
        }
957
958 558
        vtc_log(v->vl, 4, "VSC %s %ju",  pt->name, (uintmax_t)u);
959 558
        return (0);
960 16660
}
961
962
static void
963 40
vinyl_vsc(struct vinyl *v, const char *arg)
964
{
965
        struct dump_priv dp;
966
967 40
        VINYL_LAUNCH(v);
968 40
        memset(&dp, 0, sizeof dp);
969 40
        dp.v = v;
970 40
        dp.arg = arg;
971 40
        (void)VSM_Status(v->vsm_vsc);
972 40
        (void)VSC_Iter(v->vsc, v->vsm_vsc, do_stat_dump_cb, &dp);
973 40
}
974
975
/**********************************************************************
976
 * Check statistics
977
 */
978
979
struct stat_arg {
980
        const char      *pattern;
981
        uintmax_t       val;
982
        unsigned        good;
983
};
984
985
struct stat_priv {
986
        struct stat_arg lhs;
987
        struct stat_arg rhs;
988
};
989
990
static int
991 1212391
stat_match(const char *pattern, const char *name)
992
{
993
994 1212391
        if (strchr(pattern, '.') == NULL) {
995 262944
                if (fnmatch("MAIN.*", name, 0))
996 17899
                        return (FNM_NOMATCH);
997 245045
                name += 5;
998 245045
        }
999 1194492
        return (fnmatch(pattern, name, 0));
1000 1212391
}
1001
1002
static int
1003 1211747
do_expect_cb(void *priv, const struct VSC_point * const pt)
1004
{
1005 1211747
        struct stat_priv *sp = priv;
1006
1007 1211747
        if (pt == NULL)
1008 0
                return (0);
1009
1010 1211747
        if (!sp->lhs.good && stat_match(sp->lhs.pattern, pt->name) == 0) {
1011 4372
                AZ(vstrcmp(pt->ctype, "uint64_t"));
1012 4372
                AN(pt->ptr);
1013 4372
                sp->lhs.val = VSC_Value(pt);
1014 4372
                sp->lhs.good = 1;
1015 4372
        }
1016
1017 1211747
        if (sp->rhs.pattern == NULL) {
1018 1211087
                sp->rhs.good = 1;
1019 1211747
        } else if (!sp->rhs.good &&
1020 660
            stat_match(sp->rhs.pattern, pt->name) == 0) {
1021 16
                AZ(vstrcmp(pt->ctype, "uint64_t"));
1022 16
                AN(pt->ptr);
1023 16
                sp->rhs.val = VSC_Value(pt);
1024 16
                sp->rhs.good = 1;
1025 16
        }
1026
1027 1211747
        return (sp->lhs.good && sp->rhs.good);
1028 1211747
}
1029
1030
/**********************************************************************
1031
 */
1032
1033
static void
1034 3852
vinyl_expect(struct vinyl *v, char * const *av)
1035
{
1036
        struct stat_priv sp;
1037
        int good, i, not;
1038
        uintmax_t u;
1039
        char *l, *p;
1040
1041 3852
        VINYL_LAUNCH(v);
1042 3852
        ZERO_OBJ(&sp, sizeof sp);
1043 3852
        l = av[0];
1044 3852
        not = (*l == '!');
1045 3852
        if (not) {
1046 20
                l++;
1047 20
                AZ(av[1]);
1048 20
        } else {
1049 3832
                AN(av[1]);
1050 3832
                AN(av[2]);
1051 3832
                errno = 0;
1052 3832
                u = strtoumax(av[2], &p, 0);
1053 3832
                if (errno != ERANGE && *p == '\0')
1054 3816
                        sp.rhs.val = u;
1055
                else
1056 16
                        sp.rhs.pattern = av[2];
1057
        }
1058
1059 3852
        sp.lhs.pattern = l;
1060
1061 5392
        for (i = 0; i < 50; i++, (void)usleep(100000)) {
1062 5372
                (void)VSM_Status(v->vsm_vsc);
1063 5372
                sp.lhs.good = sp.rhs.good = 0;
1064 5372
                good = VSC_Iter(v->vsc, v->vsm_vsc, do_expect_cb, &sp);
1065 5372
                if (!good)
1066 1000
                        good = -2;
1067 5372
                if (good < 0)
1068 1000
                        continue;
1069
1070 4372
                if (not)
1071 0
                        vinyl_fatal(v, "Found (not expected): %s", l);
1072
1073 3880
                good = -1;
1074 3880
                if (!strcmp(av[1], "==")) good = (sp.lhs.val == sp.rhs.val);
1075 7752
                if (!strcmp(av[1], "!=")) good = (sp.lhs.val != sp.rhs.val);
1076 216
                if (!strcmp(av[1], ">" )) good = (sp.lhs.val >  sp.rhs.val);
1077 300
                if (!strcmp(av[1], "<" )) good = (sp.lhs.val <  sp.rhs.val);
1078 144
                if (!strcmp(av[1], ">=")) good = (sp.lhs.val >= sp.rhs.val);
1079 224
                if (!strcmp(av[1], "<=")) good = (sp.lhs.val <= sp.rhs.val);
1080 32
                if (good == -1)
1081 0
                        vinyl_fatal(v, "comparison %s unknown", av[1]);
1082 4372
                if (good)
1083 3832
                        break;
1084 540
        }
1085 7664
        if (good == -1) {
1086 0
                vinyl_fatal(v, "VSM error: %s", VSM_Error(v->vsm_vsc));
1087 0
        }
1088 20
        if (good == -2) {
1089 20
                if (not) {
1090 20
                        vtc_log(v->vl, 2, "not found (as expected): %s", l);
1091 20
                        return;
1092
                }
1093 0
                vinyl_fatal(v, "stats field %s unknown",
1094
                    sp.lhs.good ? sp.rhs.pattern : sp.lhs.pattern);
1095 0
        }
1096
1097 3832
        if (good == 1) {
1098 7664
                vtc_log(v->vl, 2, "as expected: %s (%ju) %s %s (%ju)",
1099 3832
                    av[0], sp.lhs.val, av[1], av[2], sp.rhs.val);
1100 3832
        } else {
1101 0
                vinyl_fatal(v, "Not true: %s (%ju) %s %s (%ju)",
1102
                    av[0], sp.lhs.val, av[1], av[2], sp.rhs.val);
1103
        }
1104 3852
}
1105
1106
static void
1107 572
vsl_catchup(struct vinyl *v)
1108
{
1109
        int vsl_idle;
1110
1111 572
        VINYL_LAUNCH(v);
1112 572
        vsl_idle = v->vsl_idle;
1113 1144
        while (!vtc_error && vsl_idle == v->vsl_idle)
1114 572
                VTIM_sleep(0.1);
1115 572
}
1116
1117
/* SECTION: vinyl vinyl
1118
 *
1119
 * Define and interact with vinyl instances.
1120
 *
1121
 * To define a ``vinyld``, you'll use this syntax::
1122
 *
1123
 *      vinyl vNAME [-arg STRING] [-vcl STRING] [-vcl+backend STRING]
1124
 *              [-errvcl STRING STRING] [-jail STRING] [-proto PROXY]
1125
 *
1126
 * The first ``vinyl vNAME`` invocation will start the vinyld master
1127
 * process in the background, waiting for the ``-start`` switch to actually
1128
 * start the child.
1129
 *
1130
 * Types used in the description below:
1131
 *
1132
 * PATTERN
1133
 *         is a 'glob' style pattern (ie: fnmatch(3)) as used in shell filename
1134
 *         expansion.
1135
 *
1136
 * Arguments:
1137
 *
1138
 * vNAME
1139
 *         Identify the ``vinyld`` server with a string, it must starts with 'v'.
1140
 *
1141
 * \-arg STRING
1142
 *         Pass an argument to vinyld, for example "-h simple_list".
1143
 *
1144
 *         If the ${vinyld_args_prepend} or ${vinyld_args_append} macros are
1145
 *         defined, they are expanded and inserted before / appended to the
1146
 *         vinyld command line as constructed by vinyltest, before the
1147
 *         command line itself is expanded. This enables tweaks to the vinyld
1148
 *         command line without editing test cases. This macros can be defined
1149
 *         using the ``-D`` option for vinyltest.
1150
 *
1151
 * \-vcl STRING
1152
 *         Specify the VCL to load on this ``vinyld`` instance. You'll probably
1153
 *         want to use multi-lines strings for this ({...}).
1154
 *
1155
 * \-vcl+backend STRING
1156
 *         Do the exact same thing as -vcl, but adds the definition block of
1157
 *         known backends (ie. already defined).
1158
 *
1159
 * \-errvcl STRING1 STRING2
1160
 *         Load STRING2 as VCL, expecting it to fail, and ``vinyld`` to send an
1161
 *         error string matching STRING1
1162
 *
1163
 * \-jail STRING
1164
 *         Look at ``man vinyld`` (-j) for more information.
1165
 *
1166
 * \-proto PROXY
1167
 *         Have ``vinyld`` use the proxy protocol. Note that PROXY here is the
1168
 *         actual string.
1169
 *
1170
 * You can decide to start the ``vinyld`` instance and/or wait for several events::
1171
 *
1172
 *         vinyl vNAME [-start] [-wait] [-wait-running] [-wait-stopped]
1173
 *
1174
 * \-start
1175
 *         Start the child process.
1176
 *
1177
 *         Once successfully started, the following macros are available for
1178
 *         the default listen address: ``${vNAME_addr}``, ``${vNAME_port}``
1179
 *         and ``${vNAME_sock}``. Additional macros are available, including
1180
 *         the listen address name for each address vNAME listens to, like for
1181
 *         example: ``${vNAME_a0_addr}``.
1182
 *
1183
 * \-stop
1184
 *         Stop the child process.
1185
 *
1186
 * \-syntax
1187
 *         Set the VCL syntax level for this command (default: 4.1)
1188
 *
1189
 * \-wait
1190
 *         Wait for that instance to terminate.
1191
 *
1192
 * \-wait-running
1193
 *         Wait for the ``vinyld`` child process to be started.
1194
 *
1195
 * \-wait-stopped
1196
 *         Wait for the ``vinyld`` child process to stop.
1197
 *
1198
 * \-cleanup
1199
 *         Once ``vinyld`` is stopped, clean everything after it. This is only used
1200
 *         in very few tests and you should never need it.
1201
 *
1202
 * \-expectexit NUMBER
1203
 *         Expect vinyld to exit(3) with this value
1204
 *
1205
 * Once ``vinyld`` is started, you can talk to it (as you would through
1206
 * ``vinyladm``) with these additional switches::
1207
 *
1208
 *         vinyl vNAME [-cli STRING] [-cliok STRING] [-clierr STRING]
1209
 *                       [-clijson STRING]
1210
 *
1211
 * \-cli STRING|-cliok STRING|-clierr STATUS STRING|-cliexpect [!] REGEXP STRING
1212
 *         All four of these will send STRING to the CLI, the only difference
1213
 *         is what they expect the result to be. -cli doesn't expect
1214
 *         anything, -cliok expects 200, -clierr expects STATUS, and
1215
 *         -cliexpect expects the REGEXP to match the returned response.
1216
 *         -cliexpect ! ... negates the match
1217
 *
1218
 * \-clijson STRING
1219
 *         Send STRING to the CLI, expect success (CLIS_OK/200) and check
1220
 *         that the response is parsable JSON.
1221
 *
1222
 * It is also possible to interact with its shared memory (as you would
1223
 * through tools like ``vinylstat``) with additional switches:
1224
 *
1225
 * \-expect \!PATTERN|PATTERN OP NUMBER|PATTERN OP PATTERN
1226
 *         Look into the VSM and make sure the first VSC counter identified by
1227
 *         PATTERN has a correct value. OP can be ==, >, >=, <, <=. For
1228
 *         example::
1229
 *
1230
 *                 vinyl v1 -expect SM?.s1.g_space > 1000000
1231
 *                 vinyl v1 -expect cache_hit >= cache_hit_grace
1232
 *
1233
 *         In the \! form the test fails if a counter matches PATTERN.
1234
 *
1235
 *         The ``MAIN.`` namespace can be omitted from PATTERN.
1236
 *
1237
 *         The test takes up to 5 seconds before timing out.
1238
 *
1239
 * \-vsc PATTERN
1240
 *         Dump VSC counters matching PATTERN.
1241
 *
1242
 * \-vsl_catchup
1243
 *         Wait until the logging thread has idled to make sure that all
1244
 *         the generated log is flushed
1245
 *
1246
 * Environment variables:
1247
 *
1248
 * VTEST_VINYL_VCL_PREPEND can be used to inject VCL code into all VCL created
1249
 * by the vinyl command before VCL provided by the caller using the -vcl or
1250
 * -vcl+backend argument. That is, VTEST_VINYL_VCL_PREPEND is injected after the
1251
 * implicit "vcl x.y;" statement and backend definitions generated by the vinyl
1252
 * command.
1253
 */
1254
1255
void
1256 20876
cmd_vinyl(CMD_ARGS)
1257
{
1258
        struct vinyl *v, *v2;
1259
        const char *me;
1260
1261 20876
        (void)priv;
1262
1263 20876
        if (av == NULL) {
1264
                /* Reset and free */
1265 8376
                VTAILQ_FOREACH_SAFE(v, &vinyles, list, v2) {
1266 3996
                        if (v->cli_fd >= 0)
1267 3952
                                vinyl_wait(v);
1268 3996
                        VTAILQ_REMOVE(&vinyles, v, list);
1269 3996
                        vinyl_delete(v);
1270 3996
                }
1271 4380
                return;
1272
        }
1273
1274 16496
        me = av[0];
1275
        // AZ(strcmp(av[0], "vinyl"));
1276 16496
        av++;
1277
1278 16496
        VTC_CHECK_NAME(vl, av[0], "Vinyl", 'v');
1279 16948
        VTAILQ_FOREACH(v, &vinyles, list)
1280 12952
                if (!vstrcmp(v->name, av[0]))
1281 12500
                        break;
1282 21004
        if (v == NULL) {
1283 3996
                v = vinyl_new(av[0]);
1284 3996
                v->me =strdup(me);
1285 3996
                AN(v->me);
1286 3996
        }
1287 16496
        av++;
1288 16496
        v->syntax = 4.1;
1289
1290 38388
        for (; *av != NULL; av++) {
1291 21896
                if (vtc_error)
1292 0
                        break;
1293 21896
                if (!vstrcmp(*av, "-arg")) {
1294 1268
                        AN(av[1]);
1295 1268
                        AZ(v->pid);
1296 1268
                        VSB_cat(v->args, " ");
1297 1268
                        VSB_cat(v->args, av[1]);
1298 1268
                        if (av[1][0] == '-' && av[1][1] == 'a')
1299 148
                                v->has_a_arg = 1;
1300 1268
                        av++;
1301 1268
                        continue;
1302
                }
1303 20628
                if (!vstrcmp(*av, "-cleanup")) {
1304 12
                        AZ(av[1]);
1305 12
                        vinyl_cleanup(v);
1306 12
                        continue;
1307
                }
1308 20616
                if (!vstrcmp(*av, "-cli")) {
1309 192
                        AN(av[1]);
1310 192
                        vinyl_cli(v, av[1], 0, NULL, 0);
1311 192
                        av++;
1312 192
                        continue;
1313
                }
1314 20424
                if (!vstrcmp(*av, "-clierr")) {
1315 536
                        AN(av[1]);
1316 536
                        AN(av[2]);
1317 536
                        vinyl_cli(v, av[2], atoi(av[1]), NULL, 0);
1318 536
                        av += 2;
1319 536
                        continue;
1320
                }
1321 19888
                if (!vstrcmp(*av, "-cliexpect")) {
1322 424
                        int neg = 0;
1323
1324 424
                        AN(av[1]);
1325 424
                        AN(av[2]);
1326 424
                        if (*av[1] == '!') {
1327 4
                                neg = 1;
1328 4
                                av++;
1329 4
                                AN(av[2]);
1330 4
                        }
1331 424
                        vinyl_cli(v, av[2], 0, av[1], neg);
1332 424
                        av += 2;
1333 424
                        continue;
1334
                }
1335 19464
                if (!vstrcmp(*av, "-clijson")) {
1336 152
                        AN(av[1]);
1337 152
                        vinyl_cli_json(v, av[1]);
1338 152
                        av++;
1339 152
                        continue;
1340
                }
1341 19312
                if (!vstrcmp(*av, "-cliok")) {
1342 4088
                        AN(av[1]);
1343 4088
                        vinyl_cli(v, av[1], (unsigned)CLIS_OK, NULL, 0);
1344 4088
                        av++;
1345 4088
                        continue;
1346
                }
1347 15224
                if (!vstrcmp(*av, "-errvcl")) {
1348 1356
                        char *r = NULL;
1349 1356
                        AN(av[1]);
1350 1356
                        AN(av[2]);
1351 1356
                        vinyl_vcl(v, av[2], 1, &r);
1352 1356
                        if (strstr(r, av[1]) == NULL)
1353 0
                                vinyl_fatal(v,
1354
                                    "Did not find expected string: (\"%s\")",
1355
                                    av[1]);
1356
                        else
1357 2712
                                vtc_log(v->vl, 3,
1358
                                    "Found expected string: (\"%s\")",
1359 1356
                                    av[1]);
1360 1356
                        free(r);
1361 1356
                        av += 2;
1362 1356
                        continue;
1363
                }
1364 13868
                if (!vstrcmp(*av, "-expect")) {
1365 3852
                        av++;
1366 3852
                        vinyl_expect(v, av);
1367 3852
                        av += 2;
1368 3852
                        continue;
1369
                }
1370 10016
                if (!vstrcmp(*av, "-expectexit")) {
1371 40
                        v->expect_exit = strtoul(av[1], NULL, 0);
1372 40
                        av++;
1373 40
                        continue;
1374
                }
1375 9976
                if (!vstrcmp(*av, "-jail")) {
1376 20
                        AN(av[1]);
1377 20
                        AZ(v->pid);
1378 20
                        REPLACE(v->jail, av[1]);
1379 20
                        av++;
1380 20
                        continue;
1381
                }
1382 9956
                if (!vstrcmp(*av, "-proto")) {
1383 64
                        AN(av[1]);
1384 64
                        AZ(v->pid);
1385 64
                        REPLACE(v->proto, av[1]);
1386 64
                        av++;
1387 64
                        continue;
1388
                }
1389 9892
                if (!vstrcmp(*av, "-start")) {
1390 3936
                        vinyl_start(v);
1391 3936
                        continue;
1392
                }
1393 5956
                if (!vstrcmp(*av, "-stop")) {
1394 232
                        vinyl_stop(v);
1395 232
                        continue;
1396
                }
1397 5724
                if (!vstrcmp(*av, "-syntax")) {
1398 216
                        AN(av[1]);
1399 216
                        v->syntax = strtod(av[1], NULL);
1400 216
                        av++;
1401 216
                        continue;
1402
                }
1403 5508
                if (!vstrcmp(*av, "-vcl")) {
1404 1192
                        AN(av[1]);
1405 1192
                        vinyl_vcl(v, av[1], 0, NULL);
1406 1192
                        av++;
1407 1192
                        continue;
1408
                }
1409 4316
                if (!vstrcmp(*av, "-vcl+backend")) {
1410 3648
                        AN(av[1]);
1411 3648
                        vinyl_vclbackend(v, av[1]);
1412 3648
                        av++;
1413 3648
                        continue;
1414
                }
1415 668
                if (!vstrcmp(*av, "-vsc")) {
1416 40
                        AN(av[1]);
1417 40
                        vinyl_vsc(v, av[1]);
1418 40
                        av++;
1419 40
                        continue;
1420
                }
1421 628
                if (!vstrcmp(*av, "-wait-stopped")) {
1422 12
                        wait_stopped(v);
1423 12
                        continue;
1424
                }
1425 616
                if (!vstrcmp(*av, "-wait-running")) {
1426 12
                        wait_running(v);
1427 12
                        continue;
1428
                }
1429 604
                if (!vstrcmp(*av, "-wait")) {
1430 28
                        vinyl_wait(v);
1431 28
                        continue;
1432
                }
1433 576
                if (!vstrcmp(*av, "-vsl_catchup")) {
1434 572
                        vsl_catchup(v);
1435 572
                        continue;
1436
                }
1437 4
                vinyl_fatal(v, "Unknown %s argument: %s", me, *av);
1438 0
        }
1439 20872
}
1440
1441
#endif /* VTEST_WITH_VTC_VINYL */