160 likes | 327 Views
ErlHive Safe Erlang Reloaded. An angle on community web development Ulf Wiger, Ericsson AB. The Goal. Web-based multi-user information management Blog, forum, wiki, chat, access control, ... What set of abstractions could allow us to treat these as convenient building blocks?
E N D
ErlHiveSafe Erlang Reloaded An angle on community web developmentUlf Wiger, Ericsson AB
The Goal • Web-based multi-user information management • Blog, forum, wiki, chat, access control, ... • What set of abstractions could allow us to treat these as convenient building blocks? • Extensible and safe
The Frustration • Installed and tested lots of blogs, wikis and forums • Surprisingly difficult • Not particularly modular • Picky about perl/python/php/mysql versions • Esp. multi-user versions worked poorly • Obvious room for improvement • But with Erlang, lots of assembly required also.
The Tuple Store • Joe Armstrong’s idea • A simple on-line database for web development • Storing objects, sets and streams per user • Joe wrote the front-end • I wrote the back-end HTTP Authentication, etc. tuplestore DB
Stored modules extend the vision Safe, web-basedcommunity web application development Public code and data Authentication, etc. User A User E erlhive DB Private code and data
Back-end Concepts • Each account contains: • Variable declarations(scalars, arrays, streams, and modules) • Areas(public and private)
Classes of Variable • Scalar – can be of any type (a type grammar exists and is enforced) • Array – an associative array (ordered set) • Stream – like an inbox (append, lookup, delete) • Module – a safe-compiled Erlang module
Access control In the public area: • Data and code in the private area accessible only to the owner • The owner’s public modules can call the owner’s private modules
Safe code execution • Only side-effects allowed are through the erlhive API • Allow calls to modules/functions known to be safe (lists, ordsets, calendar, etc.) • No spawn, send, receive, link, etc. • Meta calls filtered at run-time (and possibly blocked) • Everything runs in mnesia transactions • Otherwise, no restrictions
Code example -module(ex3_pub).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, {time, calendar:universal_time()}, {caller, erlhive.user:caller()}, {from_module, erlhive.user:from_module()}, {owner, erlhive.user:owner()}, {ex3_priv, ex3_priv:f()}]. -module(ex3_priv).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, ...]. Owned by user <<”ulf”>> -module(ex3_joe).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, ..., {ex3_pub, erlhive.ulf.ex3_pub:f()}]. Owned by user <<”joe”>> 1> erlhive:with_user( <<”ulf”>>, fun(M) -> M:set_variable(ex3_pub, [{class, module},{area, public}]), M:store_module(ex3_pub, ”-module(ex3_pub).\n...”) end).
Code example -module(ex3_pub).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, {time, calendar:universal_time()}, {caller, erlhive.user:caller()}, {from_module, erlhive.user:from_module()}, {owner, erlhive.user:owner()}, {ex3_priv, ex3_priv:f()}]. -module(ex3_priv).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, ...]. -module(ex3_joe).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, ..., {ex3_pub, erlhive.ulf.ex3_pub:f()}]. ”Meta functions” for introspection Package syntax for callingother users’ modules
Execution -module(ex3_pub).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, {time, calendar:universal_time()}, {caller, erlhive.user:caller()}, {from_module, erlhive.user:from_module()}, {owner, erlhive.user:owner()}, {ex3_priv, ex3_priv:f()}]. -module(ex3_priv).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, ...]. 2> erlhive:with_user( <<”joe”>>, fun(M) -> M:apply(erlhive.joe.ex3_joe, f, []) end). [{’?MODULE’, ’erlhive.joe.ex3_joe’}, {caller, <<”joe”>>}, {from_module, ’erlhive.user’}, {owner, <<”joe”>>}, {ex3_pub, [{’?MODULE’, ’erlhive.ulf.ex3_pub’}, {time, {{2006,11,9},{16,53,17}}, {caller, <<”joe”>>}, {owner, <<”ulf”>>}, {ex3_priv, [{’?MODULE’, ’erlhive.ulf.ex3_priv’}, {caller, <<”ulf”>>}, {from_module, ’erlhive.ulf.ex3_pub’}, {owner, <<”ulf”>>}]}]}] -module(ex3_joe).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, ..., {ex3_pub, erlhive.ulf.ex3_pub:f()}].
Execution -module(ex3_pub).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, {caller, erlhive.user:caller()}, {from_module, erlhive.user:from_module()}, {owner, erlhive.user:owner()}, {ex3_priv, ex3_priv:f()}]. -module(ex3_priv).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, ...]. 2> erlhive:with_user( <<”joe”>>, fun(M) -> M:apply(erlhive.ulf.ex3_priv, f, []) end). ** exited: {aborted, {{undef,[{{’erlhive.ulf.ex3_priv’, <<”joe”>>, ’erlhive.user’}, f, 0}, {erlhive,with_watchdog,1}, ...]}, ...} -module(ex3_joe).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, ..., {ex3_pub, erlhive.ulf.ex3_pub:f()}]. Cannot call another user’s private modules.Restricted calls appear as undefs.
Profiling -module(ex3_pub).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, {caller, erlhive.user:caller()}, {from_module, erlhive.user:from_module()}, {owner, erlhive.user:owner()}, {ex3_priv, ex3_priv:f()}]. -module(ex3_priv).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, ...]. 2> erlhive:profile( <<”joe”>>, fun(M) -> M:apply(ex3_joe, f, []) end). {[{’?MODULE’,’erlhive.joe.ex3_joe’}, ...],[{trace,<0.403.0>,call,{erlhive_user,apply,4}}, {trace,<0.403.0>,call,{’erlhive.joe.ex3_joe’,f,1}}, {trace,<0.403.0>,call,{’erlhive.ulf.ex3_pub’,f,1}}, {trace,<0.403.0>,return_to,{’erlhive.ulf.ex3_pub’,f,1}}, {trace ,<0.403.0>,return_to,{’erlhive.ulf.ex3_pub’,f,1}}]} -module(ex3_joe).-export([f/0]).f() -> [{’?MODULE’, ?MODULE}, ..., {ex3_pub, erlhive.ulf.ex3_pub:f()}]. A censored call trace. Can be followed by a specifictrace on ’visible’ modules. (work in progress...)
Status • Beta version at Sourceforgehttp://www.sourceforge.net/projects/erlhive • Authenticating web server front-end • Components • Simple web-based management front-end • Blog with threaded comments • Wiki code syntax library • Role-Based Access Control library • Any day now!