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