capricorn 2.0.8 → 2.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/erlang/lib/capricorn/ebin/capricorn.app +2 -1
  2. data/erlang/lib/capricorn/include/capricorn.hrl +1 -0
  3. data/erlang/lib/capricorn/src/cap_cluster_gems.erl +6 -1
  4. data/erlang/lib/capricorn/src/cap_console_dispatcher.erl +214 -0
  5. data/erlang/lib/capricorn/src/cap_machine_apps.erl +25 -1
  6. data/erlang/lib/capricorn/src/cap_sup.erl +14 -0
  7. data/erlang/lib/ejson/Makefile +24 -0
  8. data/erlang/lib/ejson/ebin/ejson.app +9 -0
  9. data/erlang/lib/ejson/include/ejson.hrl +40 -0
  10. data/erlang/lib/ejson/rebar.config +3 -0
  11. data/erlang/lib/ejson/src/ejson.erl +22 -0
  12. data/erlang/lib/ejson/src/ejson_decode.erl +337 -0
  13. data/erlang/lib/ejson/src/ejson_encode.erl +124 -0
  14. data/erlang/lib/ejson/test/arrays.escript +47 -0
  15. data/erlang/lib/ejson/test/compound.escript +56 -0
  16. data/erlang/lib/ejson/test/literals.escript +30 -0
  17. data/erlang/lib/ejson/test/numbers.escript +70 -0
  18. data/erlang/lib/ejson/test/objects.escript +51 -0
  19. data/erlang/lib/ejson/test/strings.escript +49 -0
  20. data/erlang/lib/ejson/test/timing.escript +43 -0
  21. data/erlang/lib/ejson/test/timing.json +382 -0
  22. data/erlang/lib/ejson/vendor/mochijson2.erl +621 -0
  23. data/erlang/lib/ejson/vendor/rfc4627.erl +625 -0
  24. data/erlang/lib/misultin/LICENSE.txt +41 -0
  25. data/erlang/lib/misultin/Makefile +26 -0
  26. data/erlang/lib/misultin/README.txt +120 -0
  27. data/erlang/lib/misultin/ebin/misultin.app +9 -0
  28. data/erlang/lib/misultin/examples/misultin_compress.erl +43 -0
  29. data/erlang/lib/misultin/examples/misultin_echo.erl +58 -0
  30. data/erlang/lib/misultin/examples/misultin_file.erl +43 -0
  31. data/erlang/lib/misultin/examples/misultin_gen_server.erl +158 -0
  32. data/erlang/lib/misultin/examples/misultin_get_variable.erl +55 -0
  33. data/erlang/lib/misultin/examples/misultin_hello_world.erl +43 -0
  34. data/erlang/lib/misultin/examples/misultin_rest.erl +68 -0
  35. data/erlang/lib/misultin/examples/misultin_ssl.erl +51 -0
  36. data/erlang/lib/misultin/examples/misultin_stream.erl +55 -0
  37. data/erlang/lib/misultin/examples/misultin_websocket_event_example.erl +103 -0
  38. data/erlang/lib/misultin/examples/misultin_websocket_example.erl +95 -0
  39. data/erlang/lib/misultin/include/misultin.hrl +95 -0
  40. data/erlang/lib/misultin/make.bat +55 -0
  41. data/erlang/lib/misultin/priv/README.txt +12 -0
  42. data/erlang/lib/misultin/priv/test_certificate.pem +21 -0
  43. data/erlang/lib/misultin/priv/test_privkey.pem +18 -0
  44. data/erlang/lib/misultin/rebar.config +3 -0
  45. data/erlang/lib/misultin/src/misultin.app.src +9 -0
  46. data/erlang/lib/misultin/src/misultin.erl +338 -0
  47. data/erlang/lib/misultin/src/misultin_http.erl +488 -0
  48. data/erlang/lib/misultin/src/misultin_req.erl +280 -0
  49. data/erlang/lib/misultin/src/misultin_socket.erl +193 -0
  50. data/erlang/lib/misultin/src/misultin_utility.erl +357 -0
  51. data/erlang/lib/misultin/src/misultin_websocket.erl +252 -0
  52. data/erlang/lib/misultin/src/misultin_ws.erl +78 -0
  53. data/erlang/rebar.config +2 -0
  54. data/erlang/rel/overlay/etc/capricorn/app.config +4 -0
  55. data/erlang/rel/reltool.config +5 -0
  56. data/lib/capricorn/recipes/apache-debian.rb +1 -1
  57. data/lib/capricorn/recipes/centos-plesk.rb +1 -1
  58. data/lib/capricorn/recipes/debian-plesk95.rb +1 -2
  59. data/lib/capricorn/recipes/macports.rb +1 -1
  60. data/lib/capricorn/version.rb +1 -1
  61. metadata +51 -4
@@ -20,6 +20,7 @@
20
20
  cap_cluster,
21
21
  cap_cluster_gems,
22
22
  cap_config,
23
+ cap_console_dispatcher,
23
24
  cap_dets_updater,
24
25
  cap_events,
25
26
  cap_event_sup,
@@ -53,6 +54,6 @@
53
54
  cap_secondary_services,
54
55
  cap_sup
55
56
  ]},
56
- {applications, [kernel, stdlib, sasl, inets, bertio, bertrpc, emq]},
57
+ {applications, [kernel, stdlib, sasl, inets, bertio, bertrpc, emq, misultin, ejson]},
57
58
  {mod, {capricorn_app, []}}
58
59
  ]}.
@@ -11,6 +11,7 @@
11
11
  %%
12
12
 
13
13
  -define(b2a(V), list_to_atom(binary_to_list(V))).
14
+ -define(a2b(V), list_to_binary(atom_to_list(V))).
14
15
  -define(b2l(V), binary_to_list(V)).
15
16
  -define(l2b(V), list_to_binary(V)).
16
17
 
@@ -2,7 +2,7 @@
2
2
  -behaviour(gen_server).
3
3
  -include("capricorn.hrl").
4
4
 
5
- -export([start_link/0, push/1, missing/0, lookup/1, lookup/2, pull/1, pull/2, check/0, all/0]).
5
+ -export([start_link/0, push/1, missing/0, lookup/1, lookup/2, pull/1, pull/2, check/0, all/0, all/1]).
6
6
  -export([init/1, handle_call/3, handle_cast/2,
7
7
  handle_info/2, terminate/2, code_change/3]).
8
8
 
@@ -52,6 +52,11 @@ all() ->
52
52
  gen_server:call(cap_cluster_gems, {all}).
53
53
 
54
54
 
55
+ -spec all(node()) -> {ok, [gem_id()]} .
56
+ all(Node) ->
57
+ gen_server:call({cap_cluster_gems, Node}, {all}).
58
+
59
+
55
60
  -spec check() -> ok .
56
61
  check() ->
57
62
  gen_server:cast(cap_cluster_gems, check).
@@ -0,0 +1,214 @@
1
+ -module(cap_console_dispatcher).
2
+ -export([start_link/1, stop/0]).
3
+ -include("capricorn.hrl").
4
+
5
+ % start misultin http server
6
+ start_link(Port) ->
7
+ misultin:start_link([
8
+ {port, Port},
9
+ {loop, fun(Req) -> handle_http(Req, Port) end},
10
+ {ws_loop, fun(Ws) -> handle_websocket(Ws) end}
11
+ ]).
12
+
13
+ % stop misultin
14
+ stop() ->
15
+ misultin:stop().
16
+
17
+ % callback on request received
18
+ handle_http(Req, _Port) ->
19
+ handle_rest(Req:get(method), Req:resource([lowercase, urldecode]), Req).
20
+
21
+
22
+ handle_rest('GET', [], Req) ->
23
+ Req:ok("Hello World.");
24
+
25
+ handle_rest(Method, ["machines" |Rest], Req) ->
26
+ handle_machines_rest(Method, Rest, Req);
27
+
28
+ handle_rest(Method, ["gems" |Rest], Req) ->
29
+ handle_gems_rest(Method, Rest, Req);
30
+
31
+ handle_rest(_, _, Req) ->
32
+ handle_404(Req).
33
+
34
+
35
+ handle_gems_rest('GET', [], Req) ->
36
+ {ok, All} = cap_cluster_gems:all(cap_config:get(machine, cluster, cluster)),
37
+ JSON = lists:foldl(fun(Gem, Acc) ->
38
+ [gem_id_to_json(Gem) |Acc]
39
+ end, [], All),
40
+ Req:ok([{"Content-Type", "application/json"}], ejson:encode(JSON));
41
+
42
+ handle_gems_rest('POST', [], Req) ->
43
+ Req:ok([{"Content-Type", "text/plain"}], "handle_gems_rest: POST, []");
44
+
45
+ handle_gems_rest(Method, [Gem, Version |Rest], Req) ->
46
+ handle_gem_rest(Method, {Gem, Version}, Rest, Req);
47
+
48
+ handle_gems_rest(_, _, Req) ->
49
+ handle_404(Req).
50
+
51
+
52
+ handle_gem_rest('GET', {Gem, Version}, [], Req) ->
53
+ Req:ok([{"Content-Type", "text/plain"}], "handle_gem_rest: GET, ~p, []", [{Gem, Version}]);
54
+
55
+ handle_gem_rest('PUT', {Gem, Version}, [], Req) ->
56
+ Req:ok([{"Content-Type", "text/plain"}], "handle_gem_rest: PUT, ~p, []", [{Gem, Version}]);
57
+
58
+ handle_gem_rest('DELETE', {Gem, Version}, [], Req) ->
59
+ Req:ok([{"Content-Type", "text/plain"}], "handle_gem_rest: DELETE, ~p, []", [{Gem, Version}]);
60
+
61
+ handle_gem_rest(_, _, _, Req) ->
62
+ handle_404(Req).
63
+
64
+
65
+ handle_machines_rest('GET', [], Req) ->
66
+ Nodes = [atom_to_list(node()) | [atom_to_list(Node) || Node <- nodes()]],
67
+ Machines = [list_to_binary(Node) || Node <- Nodes,
68
+ string:substr(Node, 1, 8) == "machine-"],
69
+ Req:ok([{"Content-Type", "application/json"}], ejson:encode(Machines));
70
+
71
+ handle_machines_rest(Method, [Machine |Rest], Req) ->
72
+ handle_machine_rest(Method, Machine, Rest, Req);
73
+
74
+ handle_machines_rest(_, _, Req) ->
75
+ handle_404(Req).
76
+
77
+
78
+ handle_machine_rest(Method, Machine, ["applications" |Rest], Req) ->
79
+ handle_apps_rest(Method, Machine, Rest, Req);
80
+
81
+ handle_machine_rest(_, _, _, Req) ->
82
+ handle_404(Req).
83
+
84
+
85
+ handle_apps_rest('GET', Machine, [], Req) ->
86
+ All = cap_machine_apps:all(list_to_atom(Machine)),
87
+ JSON = lists:foldl(fun(App, Acc) ->
88
+ [app_to_json(App) |Acc]
89
+ end, [], All),
90
+ Req:ok([{"Content-Type", "application/json"}], ejson:encode(JSON));
91
+
92
+ handle_apps_rest('POST', Machine, [], Req) ->
93
+ Req:ok([{"Content-Type", "text/plain"}], "handle_apps_rest: POST, ~p, []", [Machine]);
94
+
95
+ handle_apps_rest(Method, Machine, [Application |Rest], Req) ->
96
+ handle_app_rest(Method, Machine, Application, Rest, Req);
97
+
98
+ handle_apps_rest(_, _, _, Req) ->
99
+ handle_404(Req).
100
+
101
+
102
+ handle_app_rest('GET', Machine, Application, [], Req) ->
103
+ Resp = cap_machine_apps:one(list_to_atom(Machine), ?l2b(Application)),
104
+ case Resp of
105
+ {ok, App} ->
106
+ JSON = ejson:encode(app_to_json(App)),
107
+ Req:ok([{"Content-Type", "application/json"}], JSON);
108
+ _ ->
109
+ handle_404(Req)
110
+ end;
111
+
112
+ handle_app_rest('PUT', Machine, Application, [], Req) ->
113
+ Req:ok([{"Content-Type", "text/plain"}], "handle_apps_rest: PUT, ~p, ~p, []", [Machine, Application]);
114
+
115
+ handle_app_rest('DELETE', Machine, Application, [], Req) ->
116
+ Req:ok([{"Content-Type", "text/plain"}], "handle_apps_rest: DELETE, ~p, ~p, []", [Machine, Application]);
117
+
118
+ handle_app_rest('POST', Machine, Application, ["start"], Req) ->
119
+ Req:ok([{"Content-Type", "text/plain"}], "handle_apps_rest: POST, ~p, ~p, [start]", [Machine, Application]);
120
+
121
+ handle_app_rest('POST', Machine, Application, ["restart"], Req) ->
122
+ Req:ok([{"Content-Type", "text/plain"}], "handle_apps_rest: POST, ~p, ~p, [restart]", [Machine, Application]);
123
+
124
+ handle_app_rest('POST', Machine, Application, ["stop"], Req) ->
125
+ Req:ok([{"Content-Type", "text/plain"}], "handle_apps_rest: POST, ~p, ~p, [stop]", [Machine, Application]);
126
+
127
+ handle_app_rest('POST', Machine, Application, ["update"], Req) ->
128
+ Req:ok([{"Content-Type", "text/plain"}], "handle_apps_rest: POST, ~p, ~p, [update]", [Machine, Application]);
129
+
130
+ handle_app_rest(_, _, _, _, Req) ->
131
+ handle_404(Req).
132
+
133
+
134
+ handle_404(Req) ->
135
+ Req:respond(404, [{"Content-Type", "text/plain"}], "Page not found.").
136
+
137
+
138
+ % callback on received websockets data
139
+ handle_websocket(Ws) ->
140
+ receive
141
+ {browser, Data} ->
142
+ Ws:send(["received '", Data, "'"]),
143
+ handle_websocket(Ws);
144
+ _Ignore ->
145
+ handle_websocket(Ws)
146
+ after 5000 ->
147
+ Ws:send("pushing!"),
148
+ handle_websocket(Ws)
149
+ end.
150
+
151
+
152
+
153
+
154
+
155
+ app_to_json(App) ->
156
+ % -record(application, {
157
+ % id=undefined :: 'undefined' | binary(),
158
+ % node=undefined :: 'undefined' | atom(),
159
+ % name=undefined :: 'undefined' | binary(),
160
+ % domains=[] :: [binary(),...],
161
+ % environment=development :: atom(),
162
+ % www_user=undefined :: 'undefined' | binary(),
163
+ % www_group=undefined :: 'undefined' | binary(),
164
+ % root_path=undefined :: 'undefined' | binary(),
165
+ % installed_gems=[] :: [gem_id()],
166
+ % required_gems=[] :: [binary()],
167
+ % rvsn={rvsn, 0}
168
+ % }).
169
+
170
+ {[
171
+ {<<"id">>, App#application.id},
172
+ {<<"node">>, ?a2b(App#application.node)},
173
+ {<<"name">>, App#application.name},
174
+ {<<"domains">>, App#application.domains},
175
+ {<<"environment">>, ?a2b(App#application.environment)},
176
+ {<<"www_user">>, App#application.www_user},
177
+ {<<"www_group">>, App#application.www_group},
178
+ {<<"root_path">>, App#application.root_path},
179
+ {<<"installed_gems">>, lists:foldl(fun(Gem, Acc1) ->
180
+ [gem_id_to_json(Gem) |Acc1]
181
+ end, [], App#application.required_gems)},
182
+ {<<"required_gems">>, App#application.required_gems}
183
+ ]}.
184
+
185
+
186
+ gem_id_to_json(Gem) ->
187
+ % -record(gem_id, {
188
+ % name :: binary(),
189
+ % version :: version()
190
+ % }).
191
+ % -type version_part() :: pos_integer() | string() .
192
+ % -type version_parts() :: [version_part(),...] .
193
+ % -type version() :: {version_parts()} .
194
+
195
+ {Parts} = Gem#gem_id.version,
196
+ Version = lists:foldl(fun(Part, Acc2) ->
197
+ Str = case Part of
198
+ Part when is_integer(Part) ->
199
+ integer_to_list(Part);
200
+ Part ->
201
+ Part
202
+ end,
203
+
204
+ case Acc2 of
205
+ undefined -> Str;
206
+ _ -> Acc2 ++ [$. |Str]
207
+ end
208
+ end, undefined, Parts),
209
+
210
+ {[
211
+ {<<"name">>, Gem#gem_id.name},
212
+ {<<"version">>, ?l2b(Version)}
213
+ ]}.
214
+
@@ -5,7 +5,7 @@
5
5
 
6
6
 
7
7
  -export([start_link/0]).
8
- -export([create/4, create/5, import/7, import/8, update/3, update/4, fupdate/1, fupdate/2, update_gem/1, update_gem/2, all/0, all/1]).
8
+ -export([create/4, create/5, import/7, import/8, update/3, update/4, fupdate/1, fupdate/2, update_gem/1, update_gem/2, all/0, all/1, one/1, one/2]).
9
9
  -export([init/1, handle_call/3, handle_cast/2,
10
10
  handle_info/2, terminate/2, code_change/3]).
11
11
 
@@ -105,6 +105,20 @@ all(Node) ->
105
105
 
106
106
 
107
107
 
108
+ -spec one(binary()) -> application().
109
+
110
+ one(Id) ->
111
+ gen_server:call(cap_machine_apps, {one, Id}).
112
+
113
+
114
+
115
+ -spec one(atom(), binary()) -> application().
116
+
117
+ one(Node, Id) ->
118
+ gen_server:call({cap_machine_apps, Node}, {one, Id}).
119
+
120
+
121
+
108
122
  %%% Initialize the server
109
123
  init([]) ->
110
124
  Root = cap_config:get(machine, database, "var/run/capricorn"),
@@ -126,6 +140,16 @@ handle_call({all}, _From, #ctx{apps=Apps}=State) ->
126
140
  All = dets:foldl(fun(App, Acc) -> [App|Acc] end, [], Apps),
127
141
  {reply, All, State};
128
142
 
143
+ handle_call({one, Id}, _From, #ctx{}=State) ->
144
+ try
145
+ {ok, App} = do_lookup_app(Id, State),
146
+ {reply, {ok, App}, State}
147
+ catch
148
+ T:E ->
149
+ ?LOG_ERROR("error while getting one app ~s: ~p", [Id, E]),
150
+ {reply, {T, E}, State}
151
+ end;
152
+
129
153
  handle_call(_Request, _From, State) ->
130
154
  {reply, ok, State}.
131
155
 
@@ -88,6 +88,7 @@ start_server(NodeType) ->
88
88
 
89
89
  start_primary_services(cluster) ->
90
90
  ExternalApi = cap_config:get(cluster, api),
91
+ ConsolePort = cap_config:get(cluster, console_port),
91
92
 
92
93
  supervisor:start_link({local, cap_primary_services}, cap_sup,
93
94
  {{one_for_one, 10, 3600},[
@@ -121,6 +122,12 @@ start_primary_services(cluster) ->
121
122
  1000,
122
123
  worker,
123
124
  [cap_external_api]},
125
+ {cap_console_dispatcher,
126
+ {cap_console_dispatcher, start_link, [ConsolePort]},
127
+ permanent,
128
+ 1000,
129
+ worker,
130
+ [cap_console_dispatcher]},
124
131
  {cap_runtime,
125
132
  {cap_runtime, start_link, ["cluster"]},
126
133
  permanent,
@@ -130,6 +137,7 @@ start_primary_services(cluster) ->
130
137
  ]});
131
138
  start_primary_services(machine) ->
132
139
  InternalApi = cap_config:get(machine, api),
140
+ ConsolePort = cap_config:get(machine, console_port),
133
141
 
134
142
  supervisor:start_link({local, cap_primary_services}, cap_sup,
135
143
  {{one_for_one, 10, 3600},[
@@ -169,6 +177,12 @@ start_primary_services(machine) ->
169
177
  infinity,
170
178
  supervisor,
171
179
  [cap_machine_apps_sup]},
180
+ {cap_console_dispatcher,
181
+ {cap_console_dispatcher, start_link, [ConsolePort]},
182
+ permanent,
183
+ 1000,
184
+ worker,
185
+ [cap_console_dispatcher]},
172
186
  {cap_runtime,
173
187
  {cap_runtime, start_link, ["machine"]},
174
188
  permanent,
@@ -0,0 +1,24 @@
1
+
2
+ all: test
3
+
4
+ test: beam
5
+ test/literals.escript
6
+ test/numbers.escript
7
+ test/strings.escript
8
+ test/objects.escript
9
+ test/arrays.escript
10
+ test/compound.escript
11
+ test/timing.escript
12
+
13
+ BUILT=\
14
+ ebin/ejson.beam \
15
+ ebin/ejson_decode.beam \
16
+ ebin/ejson_encode.beam \
17
+ ebin/mochijson2.beam \
18
+ ebin/rfc4627.beam
19
+
20
+ beam: $(BUILT)
21
+
22
+ ebin/%.beam: src/%.erl
23
+ @mkdir -p ebin
24
+ erlc -o ebin/ $<
@@ -0,0 +1,9 @@
1
+ %% This is the application resource file (.app file) for the bert,
2
+ %% application.
3
+ {application, ejson,
4
+ [{description, "JSON encoder / decoder"},
5
+ {vsn, "0.1.0"},
6
+ {modules, [ejson, ejson_decode, ejson_encode]},
7
+ {registered,[]},
8
+ {applications, [kernel, stdlib]}
9
+ ]}.
@@ -0,0 +1,40 @@
1
+
2
+ % Characters
3
+ -define(DQ, 34). % Double quote
4
+ -define(PL, 43). % Plus sign
5
+ -define(CM, 44). % Comma
6
+ -define(HY, 45). % Hyphen
7
+ -define(PR, 46). % Period
8
+ -define(FS, 47). % Forward solidus
9
+ -define(ZR, 48). % Zero
10
+ -define(NI, 57). % Nine
11
+ -define(CL, 58). % Colon
12
+ -define(UE, 69). % E
13
+ -define(LB, 91). % Left bracket
14
+ -define(RS, 92). % Reverse solidus
15
+ -define(RB, 93). % Right bracket
16
+ -define(LE, 101). % e
17
+ -define(LC, 123). % Left curly brace
18
+ -define(RC, 125). % Right curly brace
19
+
20
+ % Escapes
21
+ -define(ESDQ, 16#5C22). % \"
22
+ -define(ESRS, 16#5C5C). % \\
23
+ -define(ESFS, 16#5C2F). % \/
24
+ -define(ESBS, 16#5C62). % \b
25
+ -define(ESFF, 16#5C66). % \f
26
+ -define(ESNL, 16#5C6E). % \n
27
+ -define(ESCR, 16#5C72). % \r
28
+ -define(ESTB, 16#5C74). % \t
29
+ -define(ESUE, 16#5C75). % \u
30
+
31
+ % Whitespace
32
+ -define(BS, 8). % Backspace
33
+ -define(TB, 9). % Tab
34
+ -define(NL, 10). % New line
35
+ -define(FF, 12). % Form feed
36
+ -define(CR, 13). % Carriage return
37
+ -define(SP, 32). % Space
38
+
39
+ % Error
40
+ -define(EXIT(E), throw({error, E})).
@@ -0,0 +1,3 @@
1
+ {cover_enabled, true}.
2
+ {erl_opts, [debug_info, fail_on_warning, {i, ".."}]}.
3
+ {lib_dirs, [".."]}.
@@ -0,0 +1,22 @@
1
+
2
+ -module(ejson).
3
+
4
+ -export([decode/1, encode/1]).
5
+
6
+ decode(Data) when is_list(Data) ->
7
+ decode(list_to_binary(Data));
8
+ decode(Data) when is_binary(Data) ->
9
+ case (catch ejson_decode:value(Data)) of
10
+ {error, Reason} ->
11
+ throw({invalid_json, Reason});
12
+ {_Rest, EJson} ->
13
+ EJson
14
+ end.
15
+
16
+ encode(Term) ->
17
+ case (catch ejson_encode:value(Term)) of
18
+ {error, Reason} ->
19
+ throw({invalid_erljson, Reason});
20
+ Else ->
21
+ Else
22
+ end.