[6.0] 6758bc023 Add JSON support for the "param.show" CLI command.

Dridi Boukelmoune dridi.boukelmoune at gmail.com
Wed Oct 31 13:08:28 UTC 2018


commit 6758bc0235f955615a700a294e0ab7ecdd34d89f
Author: Geoff Simmons <geoff at uplex.de>
Date:   Mon Sep 24 17:51:01 2018 +0200

    Add JSON support for the "param.show" CLI command.
    
    * Each param is represented as a JSON object listed in the output
      array.
    * The object's "value" field contains the current value, which can
      have different types -- int, float, string or boolean.
    * There is no -l form with param.show -j, each object contains the
      full description.
    * But "param.show -j the_param" or "param.show -j changed" may be
      used to limit the number of objects in the output.
    * Each object may or may not have any of the fields "minimum",
      "maximum", "default" or "units", depending on the param.
    * Params not implemented on the present platform just have
      "implemented":false along with the param name, and no other fields.
    * The values of the "minimum", "maximum" and "default" fields are
      always strings.

diff --git a/bin/varnishd/mgt/mgt_param.c b/bin/varnishd/mgt/mgt_param.c
index 139814c09..f3faa9cb3 100644
--- a/bin/varnishd/mgt/mgt_param.c
+++ b/bin/varnishd/mgt/mgt_param.c
@@ -335,6 +335,126 @@ mcf_param_show(struct cli *cli, const char * const *av, void *priv)
 	VSB_destroy(&vsb);
 }
 
+static inline void
+mcf_json_key_valstr(struct cli *cli, const char *key, const char *val)
+{
+	VCLI_Out(cli, "\"%s\": ", key);
+	VCLI_JSON_str(cli, val);
+	VCLI_Out(cli, ",\n");
+}
+
+static void v_matchproto_(cli_func_t)
+mcf_param_show_json(struct cli *cli, const char * const *av, void *priv)
+{
+	int n, comma = 0;
+	struct plist *pl;
+	const struct parspec *pp;
+	int chg = 0, flags;
+	struct vsb *vsb, *def;
+	const char *show = NULL;
+
+	vsb = VSB_new_auto();
+	def = VSB_new_auto();
+	(void)priv;
+
+	for (int i = 2; av[i] != NULL; i++) {
+		if (strcmp(av[i], "-l") == 0) {
+			VCLI_SetResult(cli, CLIS_PARAM);
+			VCLI_Out(cli, "-l not permitted with param.show -j");
+			return;
+		}
+		if (strcmp(av[i], "changed") == 0) {
+			chg = 1;
+			continue;
+		}
+		if (strcmp(av[i], "-j") == 0)
+			continue;
+		show = av[i];
+	}
+
+	n = 0;
+	VCLI_JSON_begin(cli, 2, av);
+	VCLI_Out(cli, ",\n");
+	VTAILQ_FOREACH(pl, &phead, list) {
+		pp = pl->spec;
+		if (show != NULL && strcmp(pp->name, show) != 0)
+			continue;
+		n++;
+
+		VSB_clear(vsb);
+		if (pp->func(vsb, pp, JSON_FMT))
+			VCLI_SetResult(cli, CLIS_PARAM);
+		AZ(VSB_finish(vsb));
+		VSB_clear(def);
+		if (pp->func(def, pp, NULL))
+			VCLI_SetResult(cli, CLIS_PARAM);
+		AZ(VSB_finish(def));
+		if (chg && pp->def != NULL && !strcmp(pp->def, VSB_data(def)))
+			continue;
+
+		VCLI_Out(cli, "%s", comma ? ",\n" : "");
+		comma++;
+		VCLI_Out(cli, "{\n");
+		VSB_indent(cli->sb, 2);
+		mcf_json_key_valstr(cli, "name", pp->name);
+		if (pp->flags & NOT_IMPLEMENTED) {
+			VCLI_Out(cli, "\"implemented\": false\n");
+			VSB_indent(cli->sb, -2);
+			VCLI_Out(cli, "}");
+			continue;
+		}
+		VCLI_Out(cli, "\"implemented\": true,\n");
+		VCLI_Out(cli, "\"value\": %s,\n", VSB_data(vsb));
+		if (pp->units != NULL && *pp->units != '\0')
+			mcf_json_key_valstr(cli, "units", pp->units);
+
+		if (pp->def != NULL)
+			mcf_json_key_valstr(cli, "default", pp->def);
+		if (pp->min != NULL)
+			mcf_json_key_valstr(cli, "minimum", pp->min);
+		if (pp->max != NULL)
+			mcf_json_key_valstr(cli, "maximum", pp->max);
+		mcf_json_key_valstr(cli, "description", pp->descr);
+
+		flags = 0;
+		VCLI_Out(cli, "\"flags\": [\n");
+		VSB_indent(cli->sb, 2);
+
+#define flag_out(flag, string) do {					\
+			if (pp->flags & flag) {				\
+				if (flags)				\
+					VCLI_Out(cli, ",\n");		\
+				VCLI_Out(cli, "\"%s\"", #string);	\
+				flags++;				\
+			}						\
+		} while(0)
+
+		flag_out(OBJ_STICKY, obj_sticky);
+		flag_out(DELAYED_EFFECT, delayed_effect);
+		flag_out(EXPERIMENTAL, experimental);
+		flag_out(MUST_RELOAD, must_reload);
+		flag_out(MUST_RESTART, must_restart);
+		flag_out(WIZARD, wizard);
+		flag_out(PROTECTED, protected);
+		flag_out(ONLY_ROOT, only_root);
+
+#undef flag_out
+
+		VSB_indent(cli->sb, -2);
+		VCLI_Out(cli, "\n]");
+		VSB_indent(cli->sb, -2);
+		VCLI_Out(cli, "\n}");
+	}
+	VCLI_JSON_end(cli);
+	if (show != NULL && n == 0) {
+		VSB_clear(cli->sb);
+		VCLI_SetResult(cli, CLIS_PARAM);
+		VCLI_Out(cli, "Unknown parameter \"%s\".", show);
+	}
+	VSB_destroy(&vsb);
+	VSB_destroy(&def);
+}
+
 /*--------------------------------------------------------------------
  * Mark parameters as protected
  */
@@ -471,7 +591,8 @@ mcf_wash_param(struct cli *cli, const struct parspec *pp, const char **val,
 /*--------------------------------------------------------------------*/
 
 static struct cli_proto cli_params[] = {
-	{ CLICMD_PARAM_SHOW,		"", mcf_param_show },
+	{ CLICMD_PARAM_SHOW,		"", mcf_param_show,
+	  mcf_param_show_json },
 	{ CLICMD_PARAM_SET,		"", mcf_param_set },
 	{ NULL }
 };
diff --git a/bin/varnishd/mgt/mgt_param.h b/bin/varnishd/mgt/mgt_param.h
index f4362ca96..7188b64e1 100644
--- a/bin/varnishd/mgt/mgt_param.h
+++ b/bin/varnishd/mgt/mgt_param.h
@@ -32,6 +32,9 @@ struct parspec;
 
 typedef int tweak_t(struct vsb *, const struct parspec *, const char *arg);
 
+/* Sentinel for the arg position of tweak_t to ask for JSON formatting. */
+extern const char * const JSON_FMT;
+
 struct parspec {
 	const char	*name;
 	tweak_t		*func;
diff --git a/bin/varnishd/mgt/mgt_param_bits.c b/bin/varnishd/mgt/mgt_param_bits.c
index a6d7b9216..263d8a34d 100644
--- a/bin/varnishd/mgt/mgt_param_bits.c
+++ b/bin/varnishd/mgt/mgt_param_bits.c
@@ -119,7 +119,7 @@ tweak_vsl_mask(struct vsb *vsb, const struct parspec *par, const char *arg)
 	const char *s;
 	(void)par;
 
-	if (arg != NULL) {
+	if (arg != NULL && arg != JSON_FMT) {
 		if (!strcmp(arg, "default")) {
 			memset(mgt_param.vsl_mask,
 			    0, sizeof mgt_param.vsl_mask);
@@ -141,6 +141,8 @@ tweak_vsl_mask(struct vsb *vsb, const struct parspec *par, const char *arg)
 			    "VSL tag", "-"));
 		}
 	} else {
+		if (arg == JSON_FMT)
+			VSB_putc(vsb, '"');
 		s = "";
 		for (j = 0; j < (unsigned)SLT__Reserved; j++) {
 			if (bit(mgt_param.vsl_mask, j, BTST)) {
@@ -150,6 +152,8 @@ tweak_vsl_mask(struct vsb *vsb, const struct parspec *par, const char *arg)
 		}
 		if (*s == '\0')
 			VSB_printf(vsb, "(all enabled)");
+		if (arg == JSON_FMT)
+			VSB_putc(vsb, '"');
 	}
 	return (0);
 }
@@ -171,7 +175,7 @@ tweak_debug(struct vsb *vsb, const struct parspec *par, const char *arg)
 	unsigned j;
 	(void)par;
 
-	if (arg != NULL) {
+	if (arg != NULL && arg != JSON_FMT) {
 		if (!strcmp(arg, "none")) {
 			memset(mgt_param.debug_bits,
 			    0, sizeof mgt_param.debug_bits);
@@ -180,6 +184,8 @@ tweak_debug(struct vsb *vsb, const struct parspec *par, const char *arg)
 			    DBG_Reserved, arg, debug_tags, "debug bit", "+"));
 		}
 	} else {
+		if (arg == JSON_FMT)
+			VSB_putc(vsb, '"');
 		s = "";
 		for (j = 0; j < (unsigned)DBG_Reserved; j++) {
 			if (bit(mgt_param.debug_bits, j, BTST)) {
@@ -189,6 +195,8 @@ tweak_debug(struct vsb *vsb, const struct parspec *par, const char *arg)
 		}
 		if (*s == '\0')
 			VSB_printf(vsb, "none");
+		if (arg == JSON_FMT)
+			VSB_putc(vsb, '"');
 	}
 	return (0);
 }
@@ -210,7 +218,7 @@ tweak_feature(struct vsb *vsb, const struct parspec *par, const char *arg)
 	unsigned j;
 	(void)par;
 
-	if (arg != NULL) {
+	if (arg != NULL && arg != JSON_FMT) {
 		if (!strcmp(arg, "none")) {
 			memset(mgt_param.feature_bits,
 			    0, sizeof mgt_param.feature_bits);
@@ -220,6 +228,8 @@ tweak_feature(struct vsb *vsb, const struct parspec *par, const char *arg)
 			    "feature bit", "+"));
 		}
 	} else {
+		if (arg == JSON_FMT)
+			VSB_putc(vsb, '"');
 		s = "";
 		for (j = 0; j < (unsigned)FEATURE_Reserved; j++) {
 			if (bit(mgt_param.feature_bits, j, BTST)) {
@@ -229,6 +239,8 @@ tweak_feature(struct vsb *vsb, const struct parspec *par, const char *arg)
 		}
 		if (*s == '\0')
 			VSB_printf(vsb, "none");
+		if (arg == JSON_FMT)
+			VSB_putc(vsb, '"');
 	}
 	return (0);
 }
diff --git a/bin/varnishd/mgt/mgt_param_tweak.c b/bin/varnishd/mgt/mgt_param_tweak.c
index 0f95237c2..01cab5f6b 100644
--- a/bin/varnishd/mgt/mgt_param_tweak.c
+++ b/bin/varnishd/mgt/mgt_param_tweak.c
@@ -43,6 +43,8 @@
 #include "vav.h"
 #include "vnum.h"
 
+const char * const JSON_FMT = (const char *)&JSON_FMT;
+
 /*--------------------------------------------------------------------
  * Generic handling of double typed parameters
  */
@@ -53,7 +55,7 @@ tweak_generic_double(struct vsb *vsb, volatile double *dest,
 {
 	volatile double u, minv = 0, maxv = 0;
 
-	if (arg != NULL) {
+	if (arg != NULL && arg != JSON_FMT) {
 		if (min != NULL) {
 			minv = VNUM(min);
 			if (isnan(minv)) {
@@ -123,7 +125,7 @@ tweak_bool(struct vsb *vsb, const struct parspec *par, const char *arg)
 	volatile unsigned *dest;
 
 	dest = par->priv;
-	if (arg != NULL) {
+	if (arg != NULL && arg != JSON_FMT) {
 		if (!strcasecmp(arg, "off"))
 			*dest = 0;
 		else if (!strcasecmp(arg, "disable"))
@@ -144,6 +146,8 @@ tweak_bool(struct vsb *vsb, const struct parspec *par, const char *arg)
 			VSB_printf(vsb, "use \"on\" or \"off\"\n");
 			return (-1);
 		}
+	} else if (arg == JSON_FMT) {
+		VSB_printf(vsb, "%s", *dest ? "true" : "false");
 	} else {
 		VSB_printf(vsb, "%s", *dest ? "on" : "off");
 	}
@@ -159,7 +163,7 @@ tweak_generic_uint(struct vsb *vsb, volatile unsigned *dest, const char *arg,
 	unsigned u, minv = 0, maxv = 0;
 	char *p;
 
-	if (arg != NULL) {
+	if (arg != NULL && arg != JSON_FMT) {
 		if (min != NULL) {
 			p = NULL;
 			minv = strtoul(min, &p, 0);
@@ -195,7 +199,7 @@ tweak_generic_uint(struct vsb *vsb, volatile unsigned *dest, const char *arg,
 			return (-1);
 		}
 		*dest = u;
-	} else if (*dest == UINT_MAX) {
+	} else if (*dest == UINT_MAX && arg != JSON_FMT) {
 		VSB_printf(vsb, "unlimited");
 	} else {
 		VSB_printf(vsb, "%u", *dest);
@@ -246,7 +250,7 @@ tweak_generic_bytes(struct vsb *vsb, volatile ssize_t *dest, const char *arg,
 	uintmax_t r, rmin = 0, rmax = 0;
 	const char *p;
 
-	if (arg != NULL) {
+	if (arg != NULL && arg != JSON_FMT) {
 		if (min != NULL) {
 			p = VNUM_2bytes(min, &rmin, 0);
 			if (p != NULL) {
@@ -285,6 +289,8 @@ tweak_generic_bytes(struct vsb *vsb, volatile ssize_t *dest, const char *arg,
 			return (-1);
 		}
 		*dest = r;
+	} else if (arg == JSON_FMT) {
+		VSB_printf(vsb, "%zd", *dest);
 	} else {
 		fmt_bytes(vsb, *dest);
 	}
@@ -364,6 +370,8 @@ tweak_string(struct vsb *vsb, const struct parspec *par, const char *arg)
 	/* XXX should have tweak_generic_string */
 	if (arg == NULL) {
 		VSB_quote(vsb, *p, -1, 0);
+	} else if (arg == JSON_FMT) {
+		VSB_quote(vsb, *p, -1, VSB_QUOTE_JSON|VSB_QUOTE_CSTR);
 	} else {
 		REPLACE(*p, arg);
 	}
@@ -380,7 +388,15 @@ tweak_poolparam(struct vsb *vsb, const struct parspec *par, const char *arg)
 	int retval = 0;
 
 	pp = par->priv;
-	if (arg == NULL) {
+	if (arg == JSON_FMT) {
+		VSB_printf(vsb, "{\n");
+		VSB_indent(vsb, 8);
+		VSB_printf(vsb, "\"min_pool\": %u,\n", pp->min_pool);
+		VSB_printf(vsb, "\"max_pool\": %u,\n", pp->max_pool);
+		VSB_printf(vsb, "\"max_age\": %g\n", pp->max_age);
+		VSB_indent(vsb, -4);
+		VSB_printf(vsb, "}");
+	} else if (arg == NULL) {
 		VSB_printf(vsb, "%u,%u,%g",
 		    pp->min_pool, pp->max_pool, pp->max_age);
 	} else {
diff --git a/bin/varnishtest/tests/b00042.vtc b/bin/varnishtest/tests/b00042.vtc
index 9fa143e9a..6470a7260 100644
--- a/bin/varnishtest/tests/b00042.vtc
+++ b/bin/varnishtest/tests/b00042.vtc
@@ -33,3 +33,10 @@ varnish v1 -clierr "106" {param.show fofofofo}
 varnish v1 -cliok "param.show changed"
 varnish v1 -cliok "param.show "
 varnish v1 -cliok "param.show -l"
+
+varnish v1 -clijson "param.show -j pool_req"
+varnish v1 -clijson "param.show -j pool_sess"
+varnish v1 -clijson "param.show -j changed"
+varnish v1 -clijson "param.show -j"
+varnish v1 -clierr "106" "param.show -j -l"
+varnish v1 -clierr "106" "param.show -j fofofofo"


More information about the varnish-commit mailing list