diff --git a/spectrum_manager/src/APIServer.cpp b/spectrum_manager/src/APIServer.cpp index 359f6d48..8dd645c3 100644 --- a/spectrum_manager/src/APIServer.cpp +++ b/spectrum_manager/src/APIServer.cpp @@ -12,6 +12,12 @@ #include #include +#define ALLOW_ONLY_ADMIN() if (!session->admin) { \ + std::string _json = "{\"error\":1, \"message\": \"Only administrators can do this API call.\"}"; \ + send_json(conn, _json); \ + return; \ + } + static std::string get_http_var(const struct http_message *hm, const char *name) { char data[4096]; data[0] = '\0'; @@ -29,6 +35,11 @@ static std::string get_http_var(const struct http_message *hm, const char *name) return ""; } +static int has_prefix(const struct mg_str *uri, const char *prefix) { + size_t prefix_len = strlen(prefix); + return uri->len >= prefix_len && memcmp(uri->p, prefix, prefix_len) == 0; +} + APIServer::APIServer(ManagerConfig *config, StorageBackend *storage) { m_config = config; m_storage = storage; @@ -37,7 +48,15 @@ APIServer::APIServer(ManagerConfig *config, StorageBackend *storage) { APIServer::~APIServer() { } +std::string &APIServer::safe_arg(std::string &arg) { + boost::replace_all(arg, "\n", ""); + boost::replace_all(arg, "\"", "'"); + return arg; +} + void APIServer::send_json(struct mg_connection *conn, const std::string &json) { + std::cout << "Sending JSON:\n"; + std::cout << json << "\n"; mg_printf(conn, "HTTP/1.1 200 OK\r\n" "Content-Type: text/json\r\n" @@ -70,7 +89,13 @@ void APIServer::serve_instances(Server *server, Server::session *session, struct else if (*(status.end() - 1) == '\n') { status.erase(status.end() - 1); } - json += "\"status\":\"" + status + "\""; + json += "\"status\":\"" + safe_arg(status) + "\","; + + bool running = true; + if (status.find("Running") == std::string::npos) { + running = false; + } + json += "\"running\":" + (running ? std::string("1") : std::string("0")); json += "},"; } json.erase(json.end() - 1); @@ -79,8 +104,42 @@ void APIServer::serve_instances(Server *server, Server::session *session, struct send_json(conn, json); } +void APIServer::serve_instances_start(Server *server, Server::session *session, struct mg_connection *conn, struct http_message *hm) { + ALLOW_ONLY_ADMIN(); + + std::string uri(hm->uri.p, hm->uri.len); + std::string instance = uri.substr(uri.rfind("/") + 1); + start_instances(m_config, instance); + std::string response = get_response(); + std::string error = response.find("OK") == std::string::npos ? "1" : "0"; + std::string json = "{\"error\":" + error + ", \"message\": \"" + safe_arg(response) + "\"}"; + + // TODO: So far it needs some time to reload Spectrum 2, so just sleep here. + sleep(1); + + send_json(conn, json); +} + +void APIServer::serve_instances_stop(Server *server, Server::session *session, struct mg_connection *conn, struct http_message *hm) { + ALLOW_ONLY_ADMIN(); + + std::string uri(hm->uri.p, hm->uri.len); + std::string instance = uri.substr(uri.rfind("/") + 1); + stop_instances(m_config, instance); + std::string response = get_response(); + std::string error = response.find("OK") == std::string::npos ? "1" : "0"; + std::string json = "{\"error\":" + error + ", \"message\": \"" + safe_arg(response) + "\"}"; \ + send_json(conn, json); +} + void APIServer::handleRequest(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm) { - if (mg_vcmp(&hm->uri, "/api/v1/instances") == 0) { + if (has_prefix(&hm->uri, "/api/v1/instances/start/")) { + serve_instances_start(server, sess, conn, hm); + } + else if (has_prefix(&hm->uri, "/api/v1/instances/stop/")) { + serve_instances_stop(server, sess, conn, hm); + } + else if (mg_vcmp(&hm->uri, "/api/v1/instances") == 0) { serve_instances(server, sess, conn, hm); } } diff --git a/spectrum_manager/src/APIServer.h b/spectrum_manager/src/APIServer.h index fdc71045..c90714a7 100644 --- a/spectrum_manager/src/APIServer.h +++ b/spectrum_manager/src/APIServer.h @@ -50,6 +50,9 @@ class APIServer { private: void serve_instances(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm); + void serve_instances_start(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm); + void serve_instances_stop(Server *server, Server::session *sess, struct mg_connection *conn, struct http_message *hm); + std::string &safe_arg(std::string &); void send_json(struct mg_connection *conn, const std::string &json); private: diff --git a/spectrum_manager/src/html/header.html b/spectrum_manager/src/html/header.html index b3dce4d9..9f574d6f 100644 --- a/spectrum_manager/src/html/header.html +++ b/spectrum_manager/src/html/header.html @@ -7,7 +7,10 @@ - + + + + Spectrum 2 @@ -20,7 +23,7 @@ @@ -30,3 +33,4 @@
+ \ No newline at end of file diff --git a/spectrum_manager/src/html/instances/index.shtml b/spectrum_manager/src/html/instances/index.shtml new file mode 100644 index 00000000..f7992f92 --- /dev/null +++ b/spectrum_manager/src/html/instances/index.shtml @@ -0,0 +1,9 @@ + + + + + diff --git a/spectrum_manager/src/html/js/app.js b/spectrum_manager/src/html/js/app.js new file mode 100644 index 00000000..146a2f79 --- /dev/null +++ b/spectrum_manager/src/html/js/app.js @@ -0,0 +1,20 @@ +function show_instances() { + $.get("/api/v1/instances", function(data) { + $("#main_content").html("

List of Spectrum 2 instances

"); + $.each(data.instances, function(i, instance) { + var command = instance.running ? "stop" : "start"; + var row = ''; + $("#main_result > tbody:last-child").append(row); + $(".button_command").click(function(e) { + e.preventDefault(); + $(this).parent().empty().progressbar( {value: false} ).css('height', '1em'); + var url = $(this).attr('href'); + $.get(url, function(data) { + show_instances(); + }); + }) + }); +}); +} diff --git a/spectrum_manager/src/server.cpp b/spectrum_manager/src/server.cpp index 4d156e18..44e4c13b 100644 --- a/spectrum_manager/src/server.cpp +++ b/spectrum_manager/src/server.cpp @@ -180,7 +180,7 @@ void Server::authorize(struct mg_connection *conn, struct http_message *hm) { "Set-Cookie: user=%s\r\n" // Set user, needed by Javascript code "Set-Cookie: admin=%s\r\n" // Set user, needed by Javascript code "Set-Cookie: original_url=/; max-age=0\r\n" // Delete original_url - "Location: /\r\n\r\n", + "Location: /instances\r\n\r\n", session->session_id, session->user, session->admin ? "1" : "0"); } else { // Authentication failure, redirect to login.
HostnameStatusCommand
'+ instance.name + '' + + instance.status + '' + command + '' + '