NkROLE is a framework for managing complex relations among arbitrary objects in an Erlang cluster. You can create any number of generic objects and define relations among them, based on roles. Any object can have any role over any other object. Also, you can define that all objects having a specific role over an object have automatically the same or other role over another object, and this complex relations can be nested at any level.
NkROLE creates a number of caches, so that, once all objects having a role over another object are found, the list is saved for future queries. If any of the base conditions used for the calculation change (because the base object or any of the objects used for the calculation have changed) all related caches are automatically invalidated (and only the related caches).
NkROLE creates a process for each used object in the cluster called the role proxy. Role proxies have a timeout value. If no further query is received for a period of time, they are removed. Role proxies will typically be started by another Erlang process representing the real object.
For each query that involves nested roles, a cache (another Erlang process) is started for each specific role at each related proxy, also with an specific timeout value, so that new queries are very fast, even with a huge number of objects and nested relations.
NkROLES uses by default ETS storage, and you must populate it calling nkrole_backend:put_rolemap/2
. However, you can supply the option get_rolemap_fun
to most API calls, and it will be called to get the rolemap
for an specific object instead of the built-in storage.
Let's say we want to model a member relationship, following this schema:
- Members of object
root
are all objects being members oforgA
ororgB
. - Members of
orgA
are all objects members ofdepA1
,depA2
ordepA3
. - Member of
depA1
areu01
andu02
. - Members of
depA2
aredepA21
,depA22
and also all object being members of thouse objects. - ... and so on.
Let's say we want to create this structure:
$ make shell
> nkrole_backend:put_rolemap(root, #{member=>[#{member=>orgA}, #{member=>orgB}]}).
ok
> nkrole_backend:put_rolemap(orgA, #{member=>[#{member=>depA1}, #{member=>depA2}, #{member=>depA3}]}).
ok
> nkrole_backend:put_rolemap(orgB, #{member=>[u10, #{member=>depB1}]}).
ok
and so on.
You also could first create the objects and then apply the roles:
> nkrole_backend:put_rolemap(root, #{}).
ok
> nkrole:add_subrole(member, root, member, orgA, #{}).
ok
This particular structure happens to be used at the included tests, and you can create all if it at once:
$ make build_tests
$ make shell
> test_util:insert(set1).
ok
Now we can query in many ways:
> % Get direct roles
> nkrole:get_role_objs(member, orgB, #{}).
{ok, [u10, #{member=>depB1}]}
> % Get nested roles
> nkrole:find_role_objs(member, orgB, #{}).
{ok, [u10, u11, 12]}
> nkrole:find_role_objs(member, root, #{}).
{ok,[u01,u02,depA21,depA22,u03,u04,u05,u06,u07,u08,u10,u11,u12]}.
> % Check users
> nkrole:has_role(u03, member, depA21, #{}).
{ok, true}
> nkrole:has_role(u03, member, depB1, #{}).
{ok, false}
> nkrole:has_role(u03, member, root, #{}).
{ok, true}
The previous test data adds also another role structure to the same schema, using the head
role:
Imagine we want to say that all users report to their department (except u10
), departments to their organizations, and organizations to root:
$ make build_tests
$ make shell
> test_util:insert(set1).
ok
Now we can query:
> nkrole:get_role_objs(head, u05, #{}).
{ok,[depA22,#{head=>depA22}]}
> nkrole:find_role_objs(head, u05, #{}).
{ok,[depA22, depA2, orgA, root]}
This second example is very similar to the case for nested configuration, where an object is configured based on one or more parents.
NkROLE uses standard Erlang application environment variables. The same Erlang application is used for agents and controllers.
Option | Type | Default | Desc |
---|---|---|---|
proxy_timeout | pos_integer() |
180000 |
Timeout for proxy objects |
cache_timeout | pos_integer() |
180000 |
Timeout for cache objects |