monotone-commits-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Monotone-commits-diffs] net.venge.monotone.contrib.usher: cc30eea18819


From: code
Subject: [Monotone-commits-diffs] net.venge.monotone.contrib.usher: cc30eea18819ad3237d718fa62475d7632fbbe6e
Date: Sun, 23 Jan 2011 21:06:00 GMT

revision:            cc30eea18819ad3237d718fa62475d7632fbbe6e
date:                2011-01-23T21:02:49
author:              Timothy Brownawell  <address@hidden>
branch:              net.venge.monotone.contrib.usher
changelog:
Allow STOP, KILL_NOW, and SHUTDOWN to take a reason, which is given to
clients that try to connect (see issue 35 in the monotone tracker).

Also process quotes/escapes on all administrative commands, not just some.

manifest:
format_version "1"

new_manifest [561acaadcc7ac073ed70cec4f9d527338181ddb2]

old_revision [6c2c0d14604e12e3096cdb96ab5090190e970dad]

patch "doc/documentation.html"
 from [428368437a2f078716e183d140dd58c2532cf147]
   to [0a65a84724775cabd40c8439a1ee11bf97664dc6]

patch "src/administrator.cc"
 from [362b1109b89aa9d16be22abced7eefaba1b58daa]
   to [e81924a2d5c53fd38a0656ebb078356e8588095d]

patch "src/server.cc"
 from [507f6c7aef780079d9a8651f5e06e60af34d9731]
   to [b17d1a2e095a09e8b3de119695220e0dcebd327c]

patch "src/server.hh"
 from [6a57214c24d5c35c705276dcae8415dfcabf6c6e]
   to [28e6eab321dee672e5e2af16b97243aa45d7d842]

patch "src/server_manager.cc"
 from [f4a5b6fe2d917f24ce56c133ee347b9b3e91e50b]
   to [887d163110cb77d5e62b51979d86cade131de7ce]

patch "src/server_manager.hh"
 from [1d1f3a16329bdf11b69fb7593d048d95c65edc8d]
   to [1d0b57afbfb50fb00370a09603616091ed666dbb]

patch "src/usher.cc"
 from [24ed73f0e9d84bfbf9db808c1006e9c9ffe2e90e]
   to [c3c382dae77d855df18f9a3d4ae7b512df304ebc]

patch "test/run-tests.sh"
 from [09b15b7cc7258cd670214c487462e5a1103f31f9]
   to [0773db5606bbdaab16b1708ad9210c6f4f5d48d4]

patch "test/test1/script.txt"
 from [e6183a6c77560578e045ea578669c788f088d771]
   to [396d4ff0effe51b79acfe0c016030a9d2848e8b0]
============================================================
--- src/administrator.cc	362b1109b89aa9d16be22abced7eefaba1b58daa
+++ src/administrator.cc	e81924a2d5c53fd38a0656ebb078356e8588095d
@@ -140,6 +140,14 @@ namespace {
 
     return args;
   }
+  string _empty;
+  string const & cmdline_item(vector<string> const & cmdline, unsigned int idx)
+  {
+    if (cmdline.size() > idx)
+      return cmdline.at(idx);
+    else
+      return _empty;
+  }
 }
 
 bool
@@ -150,13 +158,16 @@ administrator::process(connection & cs)
     return true;
   if (cs.authenticated)
     cs.read_done = true;
-  std::istringstream iss(l);
-  string cmd;
-  iss>>cmd;
+  vector<string> cmdline = parse_cmd_line(l);
+  string const & cmd = cmdline_item(cmdline, 0);
   bool set_response = true;
   if (cmd == "USERPASS") {
-    string user, pass;
-    iss>>user>>pass;
+    if (cmdline.size() != 3) {
+      cerr<<"Invalid admin login.\n";
+      return false;
+    }
+    string const & user = cmdline_item(cmdline, 1);
+    string const & pass = cmdline_item(cmdline, 2);
     map<string, string>::iterator i = admins.find(user);
     if (i == admins.end() || i->second != pass) {
       cerr<<"Failed admin login.\n";
@@ -170,10 +181,8 @@ administrator::process(connection & cs)
   } else if (!cs.authenticated) {
     cs.outbound.put_string("You must log in first.\n");
   } else if (cmd == "MATCH") {
-    string host;
-    iss>>host;
-    string pattern;
-    iss>>pattern;
+    string const &host = cmdline_item(cmdline, 1);
+    string const &pattern = cmdline_item(cmdline, 2);
     try {
       string const &name = manager.lookup_server_name(host, pattern);
       cs.outbound.put_string("OK: " + name + "\n");
@@ -181,8 +190,7 @@ administrator::process(connection & cs)
       cs.outbound.put_string(string("ERROR: ") + e.what() + "\n");
     }
   } else if (cmd == "STATUS") {
-    string srv;
-    iss>>srv;
+    string const &srv = cmdline_item(cmdline, 1);
     std::ostringstream oss;
     if (srv.empty()) {
       serverstate ss;
@@ -211,8 +219,7 @@ administrator::process(connection & cs)
     }
     cs.outbound.put_string(oss.str());
   } else if (cmd == "LISTCONNECTIONS") {
-    string srv;
-    iss>>srv;
+    string const &srv = cmdline_item(cmdline, 1);
     std::ostringstream oss;
     if (srv.empty())
       {
@@ -220,15 +227,15 @@ administrator::process(connection & cs)
         for (set<string>::iterator s = servers.begin();
              s != servers.end(); ++s)
           {
-            srv = *s;
+            string const & xsrv = *s;
 
-            set<string> clients = manager.list_connections(srv);
+            set<string> clients = manager.list_connections(xsrv);
             for (set<string>::iterator c = clients.begin();
                  c != clients.end(); ++c)
               {
                 if (!oss.str().empty())
                   oss<<" ";
-                oss<<"("<<srv<<")"<<*c;
+                oss<<"("<<xsrv<<")"<<*c;
               }
           }
       }
@@ -248,12 +255,11 @@ administrator::process(connection & cs)
     oss<<"\n";
     cs.outbound.put_string(oss.str());
   } else if (cmd == "START") {
-    string srv;
-    iss>>srv;
+    string const &srv = cmdline_item(cmdline, 1);
     std::ostringstream oss;
     try
       {
-        manager.start_stop_server(srv, true);
+        manager.start_server(srv);
       }
     catch (std::exception &e)
       {
@@ -261,12 +267,12 @@ administrator::process(connection & cs)
       }
     cs.outbound.put_string(oss.str());
   } else if (cmd == "STOP") {
-    string srv;
-    iss>>srv;
+    string const &srv = cmdline_item(cmdline, 1);
+    string const &reason = cmdline_item(cmdline, 2);
     std::ostringstream oss;
     try
       {
-        manager.start_stop_server(srv, false);
+        manager.stop_server(srv, reason);
       }
     catch (std::exception &e)
       {
@@ -274,11 +280,11 @@ administrator::process(connection & cs)
       }
     cs.outbound.put_string(oss.str());
   } else if (cmd == "KILL_NOW") {
-    string srv;
-    iss>>srv;
+    string const &srv = cmdline_item(cmdline, 1);
+    string const &reason = cmdline_item(cmdline, 2);
     try
       {
-        manager.kill_server_now(srv);
+        manager.kill_server_now(srv, reason);
         cs.outbound.put_string("ok\n");
       }
     catch (std::exception &e)
@@ -286,8 +292,7 @@ administrator::process(connection & cs)
         cs.outbound.put_string(e.what() + string("\n"));
       }
   } else if (cmd == "LIST") {
-    string state;
-    iss>>state;
+    string const & state = cmdline_item(cmdline, 1);
     set<string> servers = manager.list_servers(state);
     bool first = true;
     for (set<string>::iterator i = servers.begin();
@@ -298,7 +303,7 @@ administrator::process(connection & cs)
       }
     cs.outbound.put_string("\n");
   } else if (cmd == "SHUTDOWN") {
-    manager.allow_connections(false);
+    manager.allow_connections(false, cmdline_item(cmdline, 1));
     manager.kill_old_servers();
     cs.outbound.put_string("ok\n");
   } else if (cmd == "CONNECTIONS") {
@@ -307,15 +312,13 @@ administrator::process(connection & cs)
     reload_conffile();
     cs.outbound.put_string("ok\n");
   } else if (cmd == "STARTUP") {
-    manager.allow_connections(true);
+    manager.allow_connections(true, "");
     cs.outbound.put_string("ok\n");
   } else if (cmd == "ADD_SERVER") {
-    string name, type;
-    iss >> name >> type;
+    string const & name = cmdline_item(cmdline, 1);
+    string const & type = cmdline_item(cmdline, 2);
     if (type == "local") {
-      string local_args;
-      std::getline(iss, local_args);
-      vector<string> const arguments = parse_cmd_line(local_args);
+      vector<string> const arguments(cmdline.begin() + 3, cmdline.end());
       if (arguments.empty())
 	cs.outbound.put_string("you need at least one argument for a local server\n");
       else {
@@ -326,10 +329,9 @@ administrator::process(connection & cs)
 	  cs.outbound.put_string("failed to create server\n");
       }
     } else if (type == "remote") {
-      string addr;
-      int port;
-      iss >> addr >> port;
-      if (!iss)
+      string const & addr = cmdline_item(cmdline, 3);
+      int port = boost::lexical_cast<int>(cmdline_item(cmdline, 4));
+      if (addr.empty() || port == 0)
 	cs.outbound.put_string("could not read address or port\n");
       else {
 	bool ok = manager.create_remote_server(name, addr, port);
@@ -342,17 +344,15 @@ administrator::process(connection & cs)
       cs.outbound.put_string("invalid server type\n");
     }
   } else if (cmd == "REMOVE_SERVER") {
-    string name;
-    iss >> name;
+    string const & name = cmdline_item(cmdline, 1);
     if (manager.remove_server(name)) {
       cs.outbound.put_string("ok\n");
     } else {
       cs.outbound.put_string("not found\n");
     }
   } else if (cmd == "SCRIPT") {
-    do {
-      string name;
-      iss >> name;
+    do { // do {...} while (false);
+      string const & name = cmdline_item(cmdline, 1);
       map<string, vector<string> >::iterator script_iter = scripts.find(name);
       if (script_iter == scripts.end()) {
 	cs.outbound.put_string("\n127 script '" + name + "' not found\n");
@@ -381,9 +381,7 @@ administrator::process(connection & cs)
 	
 	vector<string> args = script_iter->second;
 
-	string cmd_line;
-	std::getline(iss, cmd_line);
-	vector<string> extra_args = parse_cmd_line(cmd_line);
+	vector<string> extra_args(cmdline.begin() + 2, cmdline.end());
 	std::copy(extra_args.begin(), extra_args.end(), back_inserter(args));
 
 	char ** argv = new char*[args.size() + 1];
============================================================
--- src/server.cc	507f6c7aef780079d9a8651f5e06e60af34d9731
+++ src/server.cc	b17d1a2e095a09e8b3de119695220e0dcebd327c
@@ -171,11 +171,42 @@ find_addr(string & addr, int & port)
   } while (!sock::is_address_empty(addr, port));
 }
 
+serverstate
+server::disable(string const & reason)
+{
+  enabled = false;
+  if (reason.empty())
+    disabled_reason = "server shutdown";
+  else
+    disabled_reason = reason;
+  maybekill();
+  return get_state();
+}
+
+serverstate
+server::enable()
+{
+  disabled_reason = "";
+  enabled = true;
+  return get_state();
+}
+
+void
+server::disable_kill(string const & reason)
+{
+  enabled = false;
+  if (reason.empty())
+    disabled_reason = "server shutdown";
+  else
+    disabled_reason = reason;
+  yeskill();
+}
+
 sock
 server::connect(string const &name)
 {
   if (!enabled)
-    throw std::runtime_error("This server is disabled.");
+    throw std::runtime_error("This server is disabled: " + disabled_reason);
   map<shared_ptr<server>, server_manager::serverdata>::iterator
     i = manager.servers.find(self());
   map<string, vector<string> > opts = manager.get_opts();
============================================================
--- src/server.hh	6a57214c24d5c35c705276dcae8415dfcabf6c6e
+++ src/server.hh	28e6eab321dee672e5e2af16b97243aa45d7d842
@@ -42,6 +42,7 @@ class server
 {
   friend class server_manager;
   bool enabled;
+  string disabled_reason;
   bool local;
   int pid;
   vector<string> arguments;
@@ -61,6 +62,9 @@ public:
   void maybekill();
   void yeskill();
   shared_ptr<server> self();
+  serverstate disable(string const & reason);
+  serverstate enable();
+  void disable_kill(string const & reason);
 };
 
 #endif
============================================================
--- src/server_manager.cc	f4a5b6fe2d917f24ce56c133ee347b9b3e91e50b
+++ src/server_manager.cc	887d163110cb77d5e62b51979d86cade131de7ce
@@ -303,7 +303,7 @@ server_manager::connect_to_server(string
                                   string const &name)
 {
   if (!connections_allowed)
-    throw rejected_request("All servers are disabled.");
+    throw rejected_request("All servers are disabled: " + disabled_reason);
 
   shared_ptr<server> srv = find_server(peername, pattern);
 
@@ -368,31 +368,41 @@ void
 }
 
 void
-server_manager::allow_connections(bool allow)
+server_manager::allow_connections(bool allow, string const & reason)
 {
   connections_allowed = allow;
+  if (reason.empty())
+    disabled_reason = " Usher is being shutdown";
+  else
+    disabled_reason = " " + reason;
 }
 
 string
-server_manager::start_stop_server(string const &srv, bool start)
+server_manager::stop_server(string const &srv, string const & reason)
 {
   map<string, shared_ptr<server> >::iterator i = by_name.find(srv);
   if (i != by_name.end()) {
-    i->second->enabled = start;
-    if (!start)
-      i->second->maybekill();
-    return boost::lexical_cast<string>(i->second->get_state());
+    return boost::lexical_cast<string>(i->second->disable(reason));
   } else
     throw rejected_request("No such server.");
 }
 
+string
+server_manager::start_server(string const &srv)
+{
+  map<string, shared_ptr<server> >::iterator i = by_name.find(srv);
+  if (i != by_name.end()) {
+    return boost::lexical_cast<string>(i->second->enable());
+  } else
+    throw rejected_request("No such server.");
+}
+
 void
-server_manager::kill_server_now(string const &srv)
+server_manager::kill_server_now(string const &srv, string const & reason)
 {
   map<string, shared_ptr<server> >::iterator i = by_name.find(srv);
   if (i != by_name.end()) {
-    i->second->enabled = false;
-    i->second->yeskill();
+    i->second->disable_kill(reason);
   } else
     throw rejected_request("No such server.");
 }
============================================================
--- src/server_manager.hh	1d1f3a16329bdf11b69fb7593d048d95c65edc8d
+++ src/server_manager.hh	1d0b57afbfb50fb00370a09603616091ed666dbb
@@ -54,6 +54,7 @@ private:
   set<shared_ptr<server> > live;
   map<shared_ptr<server>, serverdata> servers;
   bool connections_allowed;
+  string disabled_reason;
   int total_connections;
   serverlist_reader &reader;
   map<string, vector<string> > opts;
@@ -65,14 +66,16 @@ public:
 
 public:
   server_manager(serverlist_reader &r);
-  bool get_connections_allowed() {return connections_allowed;}
-  int get_total_connections() {return total_connections;}
-  map<string, vector<string> > get_opts() {return opts;}
+  bool get_connections_allowed() const { return connections_allowed; }
+  string get_disabled_reason() const { return disabled_reason; }
+  int get_total_connections() const { return total_connections; }
+  map<string, vector<string> > get_opts() const { return opts; }
   
   void set_opts(map<string, vector<string> > const & o);
-  void allow_connections(bool allow=true);
-  string start_stop_server(string const &srv, bool start);
-  void kill_server_now(string const &srv);
+  void allow_connections(bool allow, string const & reason);
+  string stop_server(string const & srv, string const & reason = string());
+  string start_server(string const & srv);
+  void kill_server_now(string const & srv, string const & reason = string());
 
   void reload_servers();
   bool remove_server(string const & name);
============================================================
--- src/usher.cc	24ed73f0e9d84bfbf9db808c1006e9c9ffe2e90e
+++ src/usher.cc	c3c382dae77d855df18f9a3d4ae7b512df304ebc
@@ -173,7 +173,7 @@ int main (int argc, char **argv)
         else {
           char * dat;
           int size;
-          make_packet(disabled, dat, size);
+          make_packet(disabled + manager.get_disabled_reason(), dat, size);
           write(cli, dat, size);
           delete[] dat;
         }
============================================================
--- test/run-tests.sh	09b15b7cc7258cd670214c487462e5a1103f31f9
+++ test/run-tests.sh	0773db5606bbdaab16b1708ad9210c6f4f5d48d4
@@ -55,6 +55,16 @@ client() {
     eval CLIENT_${mypid}='"$uri"'
 }
 
+client_fg() {
+    local what=$1
+    local database=$2
+    local uri="$3"
+    uri="$(echo $uri | sed 's/HOST/127.0.0.1:8691/')"
+    [ -e $database.mtn ] || $mtn db init -d $database.mtn
+    # see usher.conf.head for address
+    $mtn --root=. -d $database.mtn $what "$uri"
+}
+
 sync() {
     client sync "$@"
 }
@@ -103,6 +113,17 @@ script() {
     fi
 }
 
+wait_for_clients() {
+    for c in $CLIENTS; do
+	echo "Waiting for $c..."
+	if ! wait $c; then
+            echo "Client died horribly: " "$(eval echo '$'CLIENT_$c)"
+            OK=false
+	fi
+    done
+    CLIENTS=
+}
+
 EXIT_STATUS=0
 
 for test_name in $(ls $SRCDIR/test/); do
@@ -164,13 +185,7 @@ for test_name in $(ls $SRCDIR/test/); do
 		esac
             done
             echo "Reached end of script, waiting for clients to die..."
-            for c in $CLIENTS; do
-		echo "Waiting for $c..."
-		if ! wait $c; then
-                    echo "Client died horribly: " "$(eval echo '$'CLIENT_$c)"
-                    OK=false
-		fi
-            done
+	    wait_for_clients
             if $OK; then
 		echo "PASS $test_name" >>$TESTDIR/status
             else
============================================================
--- test/test1/script.txt	e6183a6c77560578e045ea578669c788f088d771
+++ test/test1/script.txt	396d4ff0effe51b79acfe0c016030a9d2848e8b0
@@ -58,3 +58,16 @@
 sync user1 mtn://HOST/someserver?'*'
 check_cmd ADD_SERVER otherserver local "-d" "user1.mtn" "--confdir=../confdir"
 multipull 2 mtn://HOST/otherserver?'*'
+
+
+wait_for_clients
+
+# stop/start/shutdown/startup
+check_cmd SHUTDOWN foobar
+client_fg sync user2 mtn://HOST/prjek?net.prjek'*' 2>&1 | grep -q foobar
+check_cmd STARTUP
+client_fg sync user2 mtn://HOST/prjek?net.prjek'*'
+msg_usher STOP prjek baz
+client_fg sync user2 mtn://HOST/prjek?net.prjek'*' 2>&1 | grep -q baz
+msg_usher START prjek
+client_fg sync user2 mtn://HOST/prjek?net.prjek'*'
============================================================
--- doc/documentation.html	428368437a2f078716e183d140dd58c2532cf147
+++ doc/documentation.html	0a65a84724775cabd40c8439a1ee11bf97664dc6
@@ -6,6 +6,7 @@
 
 
 
+
   
   <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>Usher Documentation</title></head><body>
 <h2>Introduction</h2>
@@ -110,8 +111,14 @@ give commands of the following form, end
 connections on the specified address:port. The connecting client can
 give commands of the following form, ending with a newline:<br>
 <div style="margin-left: 40px;">COMMAND [arg] ...<br>
-</div>
-After any command except USERPASS the usher will send a reply and close the connection. The reply will end with a newline.<br>
+</div>Arguments can be quoted with single or double quotes, and
+the backslash character can be used to quote any other character except
+inside single quotes ("\n" becomes a newline, backslash followed by any
+other character becomes that character). You cannot use literal
+newlines even inside
+quotes, but must use "\n" if you want a newline character.<br>
+<br>
+After any command except USERPASS the usher will send a reply and close the connection. The reply will end with a newline. 
 <h3>Administrative commands</h3>
 <dl>
   <dt>USERPASS username password</dt>
@@ -188,7 +195,8 @@ connections to list.<br>
 the remote end of the connection. Returns "none" if there are no
 connections to list.<br>
   </dd>
-  <dt>STOP servername</dt>
+  <dt>STOP servername [reason]<br>
+</dt>
   <dd>Prevent the given local server from receiving further
 connections, and stop it once all connections are closed. The result
 will be the new status of that server: ACTIVE local servers will become
@@ -199,7 +207,8 @@ become ACTIVE, and STOPPED servers becom
   <dd>Allow a STOPPED or STOPPING server to receive connections again.
 The result will be the new status of that server: STOPPING servers
 become ACTIVE, and STOPPED servers become SLEEPING. Servers in other
-states are not affected.</dd><dt>KILL_NOW servername</dt>
+states are not affected.</dd><dt>KILL_NOW servername [reason]<br>
+</dt>
   <dd>Immediately kill the given local server, dropping any open
 connections, and prevent it from receiving new connections and
 restarting. The named server will immediately change to state STOPPED.<br>
@@ -210,7 +219,8 @@ of all servers which are in the given st
 space-separated list of all servers. With an argument, returns a list
 of all servers which are in the given state.<br>
   </dd>
-  <dt>SHUTDOWN</dt>
+  <dt>SHUTDOWN [reason]<br>
+</dt>
   <dd>Do not accept new connections for any servers, local or remote. Returns "ok".<br>
   </dd>
   <dt>STARTUP</dt>
@@ -222,14 +232,11 @@ will be "ok", and will not be given unti
   <dt>RELOAD</dt>
   <dd>Reload the config file, the same as sending SIGHUP. The reply
 will be "ok", and will not be given until the config file has been
-reloaded.</dd><dt>RUN scriptname arg "a r g"</dt>
+reloaded.</dd><dt>SCRIPT scriptname [arg ...]<br>
+</dt>
   <dd>Run the named script, which was defined with the "script" config
 file directive. Arguments given here are appended to the end of the
-command line, after any arguments given in the "script" directive.
-Arguments with spaces can be quoted with single or double quotes, and
-the "\n", "\'", "\"", and "\\" escape sequences are recognized except
-inside single quotes. You cannot use literal newlines even inside
-quotes, but must use "\n" if you want a newline character. Returns the
+command line, after any arguments given in the "script" directive.&nbsp; Returns the
 output (combined stdout and stderr) of the script, followed by a
 newline, the exit status and a comment, and another newline.<br>
   </dd>
@@ -242,8 +249,7 @@ the named server doesn't exist.<br>
   </dt>
   <dd>Add a server with the given name and startup arguments (or name and address for remote servers).
 "arg ..." is either "hostname port" for remote servers, or arguments
-to the underlying monotone server for local servers. Quotes are
-treated the same as for RUN. Returns "ok", or an error message.<br>
+to the underlying monotone server for local servers. Returns "ok", or an error message.<br>
   </dd>
 
 </dl>

reply via email to

[Prev in Thread] Current Thread [Next in Thread]