Web interface: first try of API server + javascript based starting/stopping of instances
This commit is contained in:
parent
a71462650e
commit
b8926b4f0c
6 changed files with 100 additions and 5 deletions
|
@ -12,6 +12,12 @@
|
|||
#include <string>
|
||||
#include <cerrno>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
|
||||
<link href="/style.css" rel="stylesheet" type="text/css" media="all">
|
||||
<link href="/form.css" rel="stylesheet" type="text/css" media="all">
|
||||
|
||||
<link href="https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet" type="text/css" media="all">
|
||||
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
|
||||
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
|
||||
<script src="/js/app.js"></script>
|
||||
<title>Spectrum 2</title>
|
||||
</head>
|
||||
|
||||
|
@ -20,7 +23,7 @@
|
|||
<img id="logo" src="/logo.png" style="width:250px; margin-left: auto;margin-right: auto; display:block;">
|
||||
|
||||
<section id="menu" style="text-align: center;">
|
||||
<a class="menuitem" href="/">Instances</a>
|
||||
<a class="menuitem" href="/instances">Instances</a>
|
||||
<a class="menuitem" href="/users">Users</a>
|
||||
<a class="menuitem" href="/logout">Logout</a>
|
||||
</section>
|
||||
|
@ -30,3 +33,4 @@
|
|||
<!-- MAIN CONTENT -->
|
||||
<div id="main_content_wrap" class="outer">
|
||||
<section id="main_content" class="inner">
|
||||
|
9
spectrum_manager/src/html/instances/index.shtml
Normal file
9
spectrum_manager/src/html/instances/index.shtml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<!--#include virtual="/header.html" -->
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
show_instances();
|
||||
});
|
||||
</script>
|
||||
|
||||
<!--#include virtual="/footer.html" -->
|
20
spectrum_manager/src/html/js/app.js
Normal file
20
spectrum_manager/src/html/js/app.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
function show_instances() {
|
||||
$.get("/api/v1/instances", function(data) {
|
||||
$("#main_content").html("<h2>List of Spectrum 2 instances</h2><table id='main_result'><tr><th>Hostname<th>Status</th><th>Command</th></tr>");
|
||||
$.each(data.instances, function(i, instance) {
|
||||
var command = instance.running ? "stop" : "start";
|
||||
var row = '<tr><td>'+ instance.name + '</td><td>' +
|
||||
instance.status + '</td><td><a class="button_command" href="/api/v1/instances/' +
|
||||
command + '/' + instance.id + '">' + command + '</a>' + '</td></tr>';
|
||||
$("#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();
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Reference in a new issue