[Top][All Lists]
[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. 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>
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Monotone-commits-diffs] net.venge.monotone.contrib.usher: cc30eea18819ad3237d718fa62475d7632fbbe6e,
code <=