Revision: 122
Author: discipleofranok
Date: Tue Dec 8 06:25:13 2009
Log: Improve the web interface, and fix a few bugs in osp_manager
http://code.google.com/p/openserverplatform/source/detail?r=122
Modified:
/trunk/README
/trunk/src/osp_manager.erl
/trunk/src/osp_web.erl
/trunk/start-osp.sh
/trunk/www/app.html
/trunk/www/app.js
/trunk/www/compile.html
/trunk/www/style.css
=======================================
--- /trunk/README Wed Nov 4 05:36:34 2009
+++ /trunk/README Tue Dec 8 06:25:13 2009
@@ -1,6 +1,6 @@
Open Server Platform
Version 0.4
-11/1/09
+11/9/09
Coyright (C) 2009 Jacob Torrey
Open Server Platform (OSP) is an open source (MIT License) project to make
it easier to create secure,
@@ -19,8 +19,13 @@
-> The XML::Simple perl module
-> Netcat
+Building
+ Once you have the requirements installed, running make from inside of src
+should build the system, then you can return to the main OSP directory.
+
Starting OSP
- Once you have the OSP environment downloaded, edit the include/osp.conf
and run:
+ Once you have the OSP environment downloaded and built, edit the
include/conf.hrl
+and run:
./bin/osp_ctl start
This will start an OSP instance on the local machine prepared to server
=======================================
--- /trunk/src/osp_manager.erl Sun Nov 8 15:53:31 2009
+++ /trunk/src/osp_manager.erl Tue Dec 8 06:25:13 2009
@@ -7,7 +7,7 @@
-export([startup/0, stop_node/0]).
% Export the admin functions
--export([shutdown_osp/0, stats/0, uptime/0, nodeapp/0, start_servlet/3,
stop_servlet/2, bkup_db/2]).
+-export([shutdown_osp/0, stats/0, uptime/0, nodeapp/0, start_servlet/3,
stop_servlet/2, bkup_db/2, servlet_running/2]).
% Define the Mnesia record
-record(osp_table, {key, val}).
@@ -169,19 +169,37 @@
start_servlet(App, Port, Node) ->
case lists:member(Node, [node() | nodes()]) of
true ->
- case code:load_file(App) of
- {module, App} ->
- if
- Node =:= node() ->
- osp_broker:start(App, Port);
- true->
- start_db(Node, App),
- rpc:call(Node, osp_broker, start, [App, Port])
- end,
+ case servlet_running(Node, App) of
+ false ->
+ case erlang:module_loaded(App) of
+ false ->
+ case code:load_file(App) of
+ {module, App} ->
+ if
+ Node =:= node() ->
+ osp_broker:start(App, Port);
+ true->
+ start_db(Node, App),
+ rpc:call(Node, osp_broker, start, [App, Port])
+ end,
+ add_app_to_list(Node, App, Port),
+ ok;
+ {error, _} ->
+ {error, noapp}
+ end;
+ true ->
+ if
+ Node =:= node() ->
+ osp_broker:start(App, Port);
+ true->
+ start_db(Node, App),
+ rpc:call(Node, osp_broker, start, [App, Port])
+ end,
add_app_to_list(Node, App, Port),
- ok;
- {error, _} ->
- {error, noapp}
+ ok
+ end;
+ true ->
+ {error, apprunning}
end;
false ->
{error, nonode}
@@ -207,10 +225,26 @@
store(nodeapp, []),
init:stop().
+%% @doc A boolean test function for whether a servlet is running on a
given node
+%% @spec servlet_running(node(), atom()) -> true | false
+servlet_running(Node, App) ->
+ NodeApp = nodeapp(),
+ case lists:keyfind(Node, 1, NodeApp) of
+ false ->
+ false;
+ {Node, Applist} ->
+ case lists:keyfind(App, 1, Applist) of
+ false ->
+ false;
+ _ ->
+ true
+ end
+ end.
+
%% @doc Deletes an application from the list of running applications
%% @spec del_app_from_list(atom(), atom()) -> ok
del_app_from_list(Node, App) ->
- NodeApp = retrieve(nodeapp),
+ NodeApp = nodeapp(),
{Node, AppList} = lists:keyfind(Node, 1, NodeApp),
AL2 = lists:keydelete(App, 1, AppList),
store(nodeapp, lists:keyreplace(Node, 1, NodeApp, {Node, AL2})),
@@ -219,7 +253,7 @@
%% @doc Adds an application to the list of running applications
%% @spec add_app_to_list(atom(), atom(), integer()) -> ok
add_app_to_list(Node, App, Port) ->
- Nodeapp = retrieve(nodeapp),
+ Nodeapp = nodeapp(),
case lists:keyfind(Node, 1, Nodeapp) of
false ->
store(nodeapp, [{Node, [{App, Port}]} | Nodeapp]);
=======================================
--- /trunk/src/osp_web.erl Sun Nov 8 15:53:31 2009
+++ /trunk/src/osp_web.erl Tue Dec 8 06:25:13 2009
@@ -2,7 +2,7 @@
%% @copyright 2009 Jacob Torrey <
torr...@clarkson.edu>
%% @doc Provides the httpd and web interface for OSP
-module(osp_web).
--export([start/0, reload/0, stop/1, clusterwide/3]).
+-export([start/0, reload/0, stop/1, clusterwide/3, upload/3]).
-define(CONF_FILE, "include/httpd.conf").
@@ -39,7 +39,15 @@
Tokens = string:tokens(Str, "$\n"),
string:join(Tokens, "\n<br />").
-
+%% @doc Adds support for uploading a servlet
+%% @spec upload(any(), list(), string()) -> ok, {error, Reason}
+upload(Session, _Env, Input) ->
+ mod_esi:deliver(Session, io_lib:format("~p", [Input])).
+
+%% @doc Writes a servlet to disk and returns its filename
+%% @spec parse_upload(string()) -> string()
+parse_upload(Input) ->
+ Input.
%% @doc Provides cluster wide ajax callbacks for the web administrative
system
%% @spec(any(), list(), string()) -> ok | {error, Reason}
@@ -48,27 +56,72 @@
{value, {operation, Op}} = lists:keysearch(operation, 1, Args),
case Op of
"shutdown" ->
- mod_esi:deliver(Session, "OSP Shutdown"),
+ mod_esi:deliver(Session, "Content-type: text/plain\r\n\r\n" ++ "OSP
Shutdown"),
osp_manager:shutdown_osp();
+ "start_app" ->
+ {value, {node, Node}} = lists:keysearch(node, 1, Args),
+ {value, {app, App}} = lists:keysearch(app, 1, Args),
+ {value, {port, Port}} = lists:keysearch(port, 1, Args),
+ case osp_manager:start_servlet(erlang:list_to_atom(App),
erlang:list_to_integer(Port), erlang:list_to_atom(Node)) of
+ ok ->
+ mod_esi:deliver(Session, ct_string(text) ++ "Application started
successfully");
+ {error, _} ->
+ mod_esi:deliver(Session, ct_string(text) ++ "There was an error
starting the application")
+ end;
+ "stop_app" ->
+ {value, {node, Node}} = lists:keysearch(node, 1, Args),
+ {value, {app, App}} = lists:keysearch(app, 1, Args),
+ case osp_manager:stop_servlet(erlang:list_to_atom(App),
erlang:list_to_atom(Node)) of
+ ok ->
+ mod_esi:deliver(Session, ct_string(text) ++ "Application stopped
successfully");
+ error ->
+ mod_esi:deliver(Session, ct_string(text) ++ "There was an error
stopping the application")
+ end;
"stats" ->
- mod_esi:deliver(Session, nl2br(osp_manager:stats()));
+ mod_esi:deliver(Session, ct_string(html) ++
nl2br(osp_manager:stats()));
"uptime" ->
- mod_esi:deliver(Session, osp_manager:uptime());
+ mod_esi:deliver(Session, ct_string(text) ++ osp_manager:uptime());
"nodes" ->
- mod_esi:deliver(Session, erlang:integer_to_list(length([node() |
nodes()])));
+ mod_esi:deliver(Session, ct_string(text) ++
erlang:integer_to_list(length([node() | nodes()])));
"appnode" ->
- mod_esi:deliver(Session, json_nodeapp(osp_manager:nodeapp()));
+ mod_esi:deliver(Session, ct_string(json) ++
json_nodeapp(osp_manager:nodeapp()));
+ "apps" ->
+ mod_esi:deliver(Session, ct_string(json) ++ json_apps());
_ ->
mod_esi:deliver(Session, "")
end.
+%% @doc Returns a Content-Type string for a given MIME type
+%% @spec ct_string(atom()) -> string()
+ct_string(text) ->
+ "Content-type: text/plain\r\n\r\n";
+ct_string(html) ->
+ "Content-type: text/html\r\n\r\n";
+ct_string(json) ->
+ "Content-type: application/json\r\n\r\n";
+ct_string(_) ->
+ "Content-type: text/plain\r\n\r\n".
+
+json_apps() ->
+ "".
+
%% @doc JSONizes the nodeapp information for the web application frontend
%% @spec json_nodeapp(list()) -> string()
json_nodeapp(NA) ->
F1 = fun({App, Port}, Str) ->
- Str ++ "{\"name: \"" ++ erlang:atom_to_list(App) ++ "\", \"port\": \""
++ erlang:integer_to_list(Port) ++ "\"}"
+ case Str of
+ "" ->
+ "{\"name\": \"" ++ erlang:atom_to_list(App) ++ "\", \"port\": \"" ++
erlang:integer_to_list(Port) ++ "\"}";
+ _ ->
+ Str ++ ", {\"name\": \"" ++ erlang:atom_to_list(App) ++ "\", \"port\":
\"" ++ erlang:integer_to_list(Port) ++ "\"}"
+ end
end,
F2 = fun({Node, Applist}, Str) ->
- Str ++ "{\"node\": \"" ++ erlang:atom_to_list(Node) ++ "\",
\"running_apps\": [" ++ lists:foldl(F1, "", Applist) ++ "]}"
+ case Str of
+ "" ->
+ "{\"node\": \"" ++ erlang:atom_to_list(Node) ++ "\", \"running_apps\":
[" ++ lists:foldl(F1, "", Applist) ++ "]}";
+ _ ->
+ Str ++ ", {\"node\": \"" ++ erlang:atom_to_list(Node) ++ "\",
\"running_apps\": [" ++ lists:foldl(F1, "", Applist) ++ "]}"
+ end
end,
"[" ++ lists:foldl(F2, "", NA) ++ "]".
=======================================
--- /trunk/start-osp.sh Wed Nov 4 05:36:34 2009
+++ /trunk/start-osp.sh Tue Dec 8 06:25:13 2009
@@ -6,5 +6,10 @@
epmd -daemon
erl -smp auto -detached -mnesia dir "mnesia" -boot osp_rel-0.4 -pa ./ebin
sleep 10
+nc localhost -w 0 9876 > /dev/null
+if [ $? -eq 1 ]; then
+ echo "There was an error starting OSP"
+ exit -1
+fi
echo "Open Server Platform started"
echo "Telnet to localhost port 9876 or go to
http://localhost:9877 to
continue"
=======================================
--- /trunk/www/app.html Wed Nov 4 05:36:34 2009
+++ /trunk/www/app.html Tue Dec 8 06:25:13 2009
@@ -30,28 +30,13 @@
<div id="apps" class="border">
<h3 class="center">Available Applications</h3>
<ul>
- <li class="draggable border" id="osp_admin">osp_admin Port: <input
type="text" style="width: 2em;" id="osp_admin-port" /></li>
+ <li class="draggable border" id="osp_admin">osp_admin Port: <input
type="text" style="width: 3em;" id="osp_admin-port" /></li>
</ul>
</div>
<br />
<div id="nodes" class="border sortable">
<h3 class="center">Running Nodes</h3>
- <div class="border node" id="master_localhost" style="float: left;
margin-right: 20px;"><h4 class="center">Master@localhost</h4>
- <ul class="sortable droppable">
- <li></li>
- </ul>
- </div>
- <div class="border node" id="slave_localhost" style="float: left;
margin-right: 20px;"><h4 class="center">Slave@localhost</h4>
- <ul class="sortable droppable">
- <li></li>
- </ul>
- </div>
- <div class="border node" id="leetpute_example_com" style="float: left;
margin-right: 20px;"><h4 class="center">
Leet...@example.com</h4>
- <ul class="sortable droppable">
- <li></li>
- </ul>
- </div>
- <br style="clear: both;" />
+ <span id="node_loading">Loading...</span>
</div>
</div>
<div id="footer">
=======================================
--- /trunk/www/app.js Wed Nov 4 05:36:34 2009
+++ /trunk/www/app.js Tue Dec 8 06:25:13 2009
@@ -1,18 +1,43 @@
-$(function() {
+$(function() {
+ $.getJSON("app/osp_web/clusterwide?operation=appnode",
+ function(nodes) {
+ $.each(nodes,
+ function(node_num, n) {
+ var node_block = "";
+ node_block = '<div id="node_' + node_num + '" class="border node"
style="float: left; margin-right: 20px;">' +
+ ' <h4 class="center">' + n.node + '</h4>' +
+ ' <ul class="sortable droppable">';
+ $.each(n.running_apps,
+ function(app_num, app) {
+ node_block += '<li class="draggable border" id="app_' + app_num
+'">' +
+
app.name + ' Port: <input type="text" style="width:
3em;" id="app_' + app_num + '_port" value="' + app.port + '"/>' +
+ '<br /><br /><a href="#" id="stop_app_' + app_num + '"
class="stop_app">Stop</a>' +
+ '</li>';
+ });
+ node_block += ' <li></li>' +
+ ' </ul>' +
+ '</div>';
+
+ $("#node_loading").remove();
+ $("#nodes").append(node_block);
+ });
+ $("#nodes").append('<br style="clear: both;" />');
+
+ $(".droppable").sortable({
+ connectWith: '.droppable',
+ stop: function(event, ui) {
+ if ($(ui.item).children("a").size() == 0) {
+ $(ui.item).append('<br /><br /><a href="#"
class="stop_app">Stop</a>');
+ }
+ }
+ });
+ });
+
$(".draggable").draggable({
helper: 'clone',
connectToSortable: ".sortable"
});
- $(".droppable").sortable({
- connectWith: '.droppable',
- stop: function(event, ui) {
- if ($(ui.item).children("a").size() == 0) {
- $(ui.item).append('<br /><br /><a href="#"
class="stop_app">Stop</a>');
- }
- }
- });
-
$("body").click(function(event) {
var $target = $(event.target);
if ($
target.is(".stop_app")) {
=======================================
--- /trunk/www/compile.html Wed Nov 4 05:36:34 2009
+++ /trunk/www/compile.html Tue Dec 8 06:25:13 2009
@@ -29,7 +29,7 @@
<h1 class="center underline">Upload and Compile a Servlet</h1>
<p>Upload a servlet to have it compiled and distributed:</p>
<form action="app/osp_web/upload" method="post"
enctype="multipart/form-data">
- <input type="file" name="sdf" /><br />
+ <input type="file" name="servlet" /><br />
<input type="submit" name="" value="Upload Servlet" />
</form>
</div>
=======================================
--- /trunk/www/style.css Wed Nov 4 05:36:34 2009
+++ /trunk/www/style.css Tue Dec 8 06:25:13 2009
@@ -117,6 +117,7 @@
text-indent: 2px;
border: 2px solid #0099CC;
padding: 1px;
+ background-color: #282828;
}
ul {