r4596 - trunk/varnish-cache/bin/varnishadm

phk at projects.linpro.no phk at projects.linpro.no
Fri Feb 26 20:17:58 CET 2010


Author: phk
Date: 2010-02-26 20:17:57 +0100 (Fri, 26 Feb 2010)
New Revision: 4596

Modified:
   trunk/varnish-cache/bin/varnishadm/varnishadm.1
   trunk/varnish-cache/bin/varnishadm/varnishadm.c
Log:
Add a "pass" mode, where varnishadm just passes your commands,
but does handle the -S authentication for you.

You can now get a secure remote CLI connection by:

	ssh foohost varnisadm -T :8081 -S/etc/varnish_secret

Or you can:

	echo "help" | ssh foohost varnisadm -T :8081 -S/etc/varnish_secret



Modified: trunk/varnish-cache/bin/varnishadm/varnishadm.1
===================================================================
--- trunk/varnish-cache/bin/varnishadm/varnishadm.1	2010-02-26 19:16:39 UTC (rev 4595)
+++ trunk/varnish-cache/bin/varnishadm/varnishadm.1	2010-02-26 19:17:57 UTC (rev 4596)
@@ -39,21 +39,40 @@
 .Op Fl t Ar timeout
 .Op Fl S Ar secret_file
 .Fl T Ar address Ns : Ns Ar port
-.Cm command
-.Op Ar ...
+.Op Cm command Op Ar ...
 .Sh DESCRIPTION
 The
 .Nm
-utility sends the given command and arguments to the
-.Xr varnishd 1
-instance at the specified address and port and prints the results.
+utility establishes a CLI connection using the
+.Fl T
+and
+.Fl S
+arguments.
 .Pp
+If a
+.Cm command
+is given, the command and arguments are sent over the
+CLI connection and the result returned on stdout.
+.Pp
+If no
+.Cm command
+argument is given
+.Nm 
+will pass commands and replies between the CLI socket and
+stdin/stdout.
+.Pp
 The following options are available:
 .Bl -tag -width Fl
 .It Fl t Ar timeout 
 Wait no longer than this many seconds for an operation to finish.
 .It Fl S Ar secret_file
-Specify the authentication secret file
+Specify the authentication secret file.
+.Pp
+This should be the same -S argument as was given to
+.Nm varnishd .
+.Pp
+Only processes which can read the contents of this file, will be able
+to authenticate the CLI connection.
 .It Fl T Ar address Ns : Ns Ar port
 Connect to the management interface at the specified address and port.
 .El
@@ -67,9 +86,20 @@
 .Cm param.show
 command.
 .Sh EXIT STATUS
-The exit status of the
+If a
+.Cm command
+is given,
+the exit status of the
 .Nm
 utility is zero if the command succeeded, and non-zero otherwise.
+.Sh EXAMPLES
+Some ways you can use varnishadm:
+.Pp
+.Dl varnishadm -T localhost:999 -S /var/db/secret vcl.use foo
+.Pp
+.Dl echo vcl.use foo | varnishadm -T localhost:999 -S /var/db/secret 
+.Pp
+.Dl echo vcl.use foo | ssh vhost varnishadm -T localhost:999 -S /var/db/secret 
 .Sh SEE ALSO
 .Xr varnishd 1
 .Sh HISTORY

Modified: trunk/varnish-cache/bin/varnishadm/varnishadm.c
===================================================================
--- trunk/varnish-cache/bin/varnishadm/varnishadm.c	2010-02-26 19:16:39 UTC (rev 4595)
+++ trunk/varnish-cache/bin/varnishadm/varnishadm.c	2010-02-26 19:17:57 UTC (rev 4596)
@@ -33,11 +33,14 @@
 SVNID("$Id$")
 
 #include <fcntl.h>
+#include <poll.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 
+#include <sys/socket.h>
+
 #include "cli.h"
 #include "cli_common.h"
 #include "libvarnish.h"
@@ -45,16 +48,29 @@
 
 static double timeout = 5;
 
+static void
+cli_write(int sock, const char *s)
+{
+	int i, l;
+
+	i = strlen(s);
+	l = write (sock, s, i);
+	if (i == l)
+		return;
+	perror("Write error CLI socket");
+	exit (1);
+}
+
 /*
  * This function establishes a connection to the specified ip and port and
  * sends a command to varnishd. If varnishd returns an OK status, the result
  * is printed and 0 returned. Else, an error message is printed and 1 is
  * returned
  */
-static void
-telnet_mgt(const char *T_arg, const char *S_arg, int argc, char *argv[])
+static int
+cli_sock(const char *T_arg, const char *S_arg)
 {
-	int i, fd;
+	int fd;
 	int sock;
 	unsigned status;
 	char *answer = NULL;
@@ -66,7 +82,7 @@
 		exit(1);
 	}
 
-	cli_readres(sock, &status, &answer, timeout);
+	(void)cli_readres(sock, &status, &answer, timeout);
 	if (status == CLIS_AUTH) {
 		if (S_arg == NULL) {
 			fprintf(stderr, "Authentication required\n");
@@ -80,58 +96,125 @@
 		}
 		CLI_response(fd, answer, buf);
 		AZ(close(fd));
-		write(sock, "auth ", 5);
-		write(sock, buf, strlen(buf));
-		write(sock, "\n", 1);
-		cli_readres(sock, &status, &answer, timeout);
+		free(answer);
+
+		cli_write(sock, "auth ");
+		cli_write(sock, buf);
+		cli_write(sock, "\n");
+		(void)cli_readres(sock, &status, &answer, timeout);
 	}
 	if (status != CLIS_OK) {
 		fprintf(stderr, "Rejected %u\n%s\n", status, answer);
 		exit(1);
 	}
+	free(answer);
 
-	write(sock, "ping\n", 5);
-	cli_readres(sock, &status, &answer, timeout);
+	cli_write(sock, "ping\n");
+	(void)cli_readres(sock, &status, &answer, timeout);
 	if (status != CLIS_OK || strstr(answer, "PONG") == NULL) {
 		fprintf(stderr, "No pong received from server\n");
 		exit(1);
 	}
 	free(answer);
 
+	return (sock);
+}
+
+static void
+do_args(int sock, int argc, char * const *argv)
+{
+	int i;
+	unsigned status;
+	char *answer = NULL;
+
 	for (i=0; i<argc; i++) {
+		/* XXX: We should really CLI-quote these */
 		if (i > 0)
-			write(sock, " ", 1);
-		write(sock, argv[i], strlen(argv[i]));
+			cli_write(sock, " ");
+		cli_write(sock, argv[i]);
 	}
-	write(sock, "\n", 1);
+	cli_write(sock, "\n");
 
-	cli_readres(sock, &status, &answer, 2000);
+	(void)cli_readres(sock, &status, &answer, 2000);
 
-	close(sock);
+	/* XXX: AZ() ? */
+	(void)close(sock);
 
+	printf("%s\n", answer);
 	if (status == CLIS_OK) {
-		printf("%s\n", answer);
 		exit(0);
 	}
 	fprintf(stderr, "Command failed with error code %u\n", status);
 	exit(1);
+}
 
+/*
+ * No arguments given, simply pass bytes on stdin/stdout and CLI socket
+ * Send a "banner" to varnish, to provoke a welcome message.
+ */
+static void
+pass(int sock)
+{
+	struct pollfd fds[2];
+	char buf[1024];
+	int i, n, m;
+
+	cli_write(sock, "banner\n");
+	fds[0].fd = sock;
+	fds[0].events = POLLIN;
+	fds[1].fd = 0;
+	fds[1].events = POLLIN;
+	while (1) {
+		i = poll(fds, 2, -1);
+		assert(i > 0);
+		if (fds[0].revents & POLLIN) {
+			n = read(fds[0].fd, buf, sizeof buf);
+			if (n == 0) 
+				exit (0);
+			if (n < 0) {
+				perror("Read error reading CLI socket");
+				exit (0);
+			}
+			assert(n > 0);
+			m = write(1, buf, n);
+			if (n != m) {
+				perror("Write error writing stdout");
+				exit (1);
+			}
+		}
+		if (fds[1].revents & POLLIN) {
+			n = read(fds[1].fd, buf, sizeof buf);
+			if (n == 0) {
+				AZ(shutdown(sock, SHUT_WR));
+				fds[1].fd = -1;
+			} else if (n < 0) {
+				exit(0);
+			} else {
+				m = write(sock, buf, n);
+				if (n != m) {
+					perror("Write error writing CLI socket");
+					exit (1);
+				}
+			}
+		}
+	}
 }
 
 static void
 usage(void)
 {
 	fprintf(stderr,
-	    "usage: varnishadm [-t timeout] [-S secretfile] -T [address]:port command [...]\n");
+	    "usage: varnishadm [-t timeout] [-S secretfile] "
+	    "-T [address]:port command [...]\n");
 	exit(1);
 }
 
 int
-main(int argc, char *argv[])
+main(int argc, char * const *argv)
 {
 	const char *T_arg = NULL;
 	const char *S_arg = NULL;
-	int opt;
+	int opt, sock;
 
 	while ((opt = getopt(argc, argv, "S:T:t:")) != -1) {
 		switch (opt) {
@@ -152,10 +235,16 @@
 	argc -= optind;
 	argv += optind;
 
-	if (T_arg == NULL || argc < 1)
+	if (T_arg == NULL)
 		usage();
 
-	telnet_mgt(T_arg, S_arg, argc, argv);
+	assert(T_arg != NULL);
+	sock = cli_sock(T_arg, S_arg);
 
+	if (argc > 0) 
+		do_args(sock, argc, argv);
+	else 
+		pass(sock);
+
 	exit(0);
 }



More information about the varnish-commit mailing list