auser-poolparty 0.2.16 → 0.2.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. data/Manifest.txt +72 -7
  2. data/PostInstall.txt +1 -1
  3. data/Rakefile +11 -0
  4. data/bin/cloud-provision +6 -10
  5. data/bin/server-build-messenger +20 -0
  6. data/bin/server-fire-cmd +0 -2
  7. data/bin/server-list-responding +24 -0
  8. data/bin/server-start-master +4 -9
  9. data/bin/server-start-node +7 -6
  10. data/lib/erlang/messenger/Emakefile +1 -0
  11. data/lib/erlang/messenger/Rakefile +29 -20
  12. data/lib/erlang/messenger/ebin/master_app.beam +0 -0
  13. data/lib/erlang/messenger/ebin/node_app.beam +0 -0
  14. data/lib/erlang/messenger/ebin/packager.app +19 -0
  15. data/lib/erlang/messenger/ebin/pm_client.beam +0 -0
  16. data/lib/erlang/messenger/ebin/pm_cluster.beam +0 -0
  17. data/lib/erlang/messenger/ebin/pm_event_handler.beam +0 -0
  18. data/lib/erlang/messenger/ebin/pm_master.beam +0 -0
  19. data/lib/erlang/messenger/ebin/pm_master_rel-0.1.rel +1 -7
  20. data/lib/erlang/messenger/ebin/pm_master_supervisor.beam +0 -0
  21. data/lib/erlang/messenger/ebin/pm_node.beam +0 -0
  22. data/lib/erlang/messenger/ebin/pm_node_rel-0.1.rel +1 -7
  23. data/lib/erlang/messenger/ebin/pm_node_supervisor.beam +0 -0
  24. data/lib/erlang/messenger/ebin/pm_packager.beam +0 -0
  25. data/lib/erlang/messenger/ebin/utils.beam +0 -0
  26. data/lib/erlang/messenger/lib/eunit/AUTHORS +2 -0
  27. data/lib/erlang/messenger/lib/eunit/CHANGELOG +14 -0
  28. data/lib/erlang/messenger/lib/eunit/COPYING +504 -0
  29. data/lib/erlang/messenger/lib/eunit/Makefile +28 -0
  30. data/lib/erlang/messenger/lib/eunit/NOTES +276 -0
  31. data/lib/erlang/messenger/lib/eunit/README +3 -0
  32. data/lib/erlang/messenger/lib/eunit/doc/edoc-info +3 -0
  33. data/lib/erlang/messenger/lib/eunit/doc/erlang.png +0 -0
  34. data/lib/erlang/messenger/lib/eunit/doc/eunit.html +172 -0
  35. data/lib/erlang/messenger/lib/eunit/doc/index.html +17 -0
  36. data/lib/erlang/messenger/lib/eunit/doc/modules-frame.html +12 -0
  37. data/lib/erlang/messenger/lib/eunit/doc/overview-summary.html +984 -0
  38. data/lib/erlang/messenger/lib/eunit/doc/overview.edoc +980 -0
  39. data/lib/erlang/messenger/lib/eunit/doc/packages-frame.html +11 -0
  40. data/lib/erlang/messenger/lib/eunit/doc/stylesheet.css +55 -0
  41. data/lib/erlang/messenger/lib/eunit/ebin/autoload.beam +0 -0
  42. data/lib/erlang/messenger/lib/eunit/ebin/code_monitor.beam +0 -0
  43. data/lib/erlang/messenger/lib/eunit/ebin/eunit.app +21 -0
  44. data/lib/erlang/messenger/lib/eunit/ebin/eunit.appup +1 -0
  45. data/lib/erlang/messenger/lib/eunit/ebin/eunit.beam +0 -0
  46. data/lib/erlang/messenger/lib/eunit/ebin/eunit_autoexport.beam +0 -0
  47. data/lib/erlang/messenger/lib/eunit/ebin/eunit_data.beam +0 -0
  48. data/lib/erlang/messenger/lib/eunit/ebin/eunit_lib.beam +0 -0
  49. data/lib/erlang/messenger/lib/eunit/ebin/eunit_proc.beam +0 -0
  50. data/lib/erlang/messenger/lib/eunit/ebin/eunit_serial.beam +0 -0
  51. data/lib/erlang/messenger/lib/eunit/ebin/eunit_server.beam +0 -0
  52. data/lib/erlang/messenger/lib/eunit/ebin/eunit_striptests.beam +0 -0
  53. data/lib/erlang/messenger/lib/eunit/ebin/eunit_test.beam +0 -0
  54. data/lib/erlang/messenger/lib/eunit/ebin/eunit_tests.beam +0 -0
  55. data/lib/erlang/messenger/lib/eunit/ebin/eunit_tty.beam +0 -0
  56. data/lib/erlang/messenger/lib/eunit/ebin/file_monitor.beam +0 -0
  57. data/lib/erlang/messenger/lib/eunit/examples/eunit_examples.erl +339 -0
  58. data/lib/erlang/messenger/lib/eunit/examples/fib.erl +19 -0
  59. data/lib/erlang/messenger/lib/eunit/examples/tests.txt +1 -0
  60. data/lib/erlang/messenger/lib/eunit/include/eunit.hrl +313 -0
  61. data/lib/erlang/messenger/lib/eunit/src/Makefile +46 -0
  62. data/lib/erlang/messenger/lib/eunit/src/autoload.erl +388 -0
  63. data/lib/erlang/messenger/lib/eunit/src/code_monitor.erl +243 -0
  64. data/lib/erlang/messenger/lib/eunit/src/eunit.app.src +21 -0
  65. data/lib/erlang/messenger/lib/eunit/src/eunit.appup.src +1 -0
  66. data/lib/erlang/messenger/lib/eunit/src/eunit.erl +196 -0
  67. data/lib/erlang/messenger/lib/eunit/src/eunit_autoexport.erl +102 -0
  68. data/lib/erlang/messenger/lib/eunit/src/eunit_data.erl +798 -0
  69. data/lib/erlang/messenger/lib/eunit/src/eunit_internal.hrl +48 -0
  70. data/lib/erlang/messenger/lib/eunit/src/eunit_lib.erl +682 -0
  71. data/lib/erlang/messenger/lib/eunit/src/eunit_proc.erl +552 -0
  72. data/lib/erlang/messenger/lib/eunit/src/eunit_serial.erl +157 -0
  73. data/lib/erlang/messenger/lib/eunit/src/eunit_server.erl +340 -0
  74. data/lib/erlang/messenger/lib/eunit/src/eunit_striptests.erl +64 -0
  75. data/lib/erlang/messenger/lib/eunit/src/eunit_test.erl +334 -0
  76. data/lib/erlang/messenger/lib/eunit/src/eunit_tests.erl +45 -0
  77. data/lib/erlang/messenger/lib/eunit/src/eunit_tty.erl +272 -0
  78. data/lib/erlang/messenger/lib/eunit/src/file_monitor.erl +409 -0
  79. data/lib/erlang/messenger/lib/eunit/sys.config +9 -0
  80. data/lib/erlang/messenger/lib/eunit/vsn.mk +1 -0
  81. data/lib/erlang/messenger/pm_master_rel-0.1.boot +0 -0
  82. data/lib/erlang/messenger/pm_master_rel-0.1.script +75 -2
  83. data/lib/erlang/messenger/pm_node_rel-0.1.boot +0 -0
  84. data/lib/erlang/messenger/pm_node_rel-0.1.script +75 -2
  85. data/lib/erlang/messenger/src/pm_client.erl +8 -3
  86. data/lib/erlang/messenger/src/pm_cluster.erl +32 -9
  87. data/lib/erlang/messenger/src/pm_master.erl +10 -11
  88. data/lib/erlang/messenger/src/pm_node.erl +2 -3
  89. data/lib/erlang/messenger/src/pm_packager.erl +73 -0
  90. data/lib/erlang/messenger/src/utils.erl +3 -10
  91. data/lib/poolparty/base_packages/heartbeat.rb +9 -9
  92. data/lib/poolparty/base_packages/poolparty.rb +16 -10
  93. data/lib/poolparty/config/allowed_commands.yml +1 -0
  94. data/lib/poolparty/core/object.rb +8 -0
  95. data/lib/poolparty/exceptions/UnacceptableCommand.rb +5 -0
  96. data/lib/poolparty/helpers/messenger.rb +29 -0
  97. data/lib/poolparty/helpers/provisioner_base.rb +7 -7
  98. data/lib/poolparty/helpers/provisioners/master.rb +3 -7
  99. data/lib/poolparty/helpers/provisioners/slave.rb +1 -0
  100. data/lib/poolparty/modules/cloud_resourcer.rb +7 -5
  101. data/lib/poolparty/modules/configurable.rb +1 -1
  102. data/lib/poolparty/modules/method_missing_sugar.rb +6 -1
  103. data/lib/poolparty/modules/pretty_printer.rb +1 -0
  104. data/lib/poolparty/modules/resourcing_dsl.rb +2 -1
  105. data/lib/poolparty/monitors/monitors/cpu_monitor.rb +1 -1
  106. data/lib/poolparty/net/remoter.rb +3 -1
  107. data/lib/poolparty/plugins/git.rb +3 -3
  108. data/lib/poolparty/pool/base.rb +7 -2
  109. data/lib/poolparty/pool/cloud.rb +3 -3
  110. data/lib/poolparty/pool/resource.rb +38 -24
  111. data/lib/poolparty/pool/resources/class_package.rb +2 -2
  112. data/lib/poolparty/pool/resources/conditional.rb +8 -4
  113. data/lib/poolparty/pool/resources/{gem.rb → gem_package.rb} +0 -0
  114. data/lib/poolparty/pool/resources/package.rb +8 -1
  115. data/lib/poolparty/version.rb +1 -1
  116. data/lib/poolparty.rb +1 -1
  117. data/poolparty.gemspec +476 -61
  118. data/spec/poolparty/core/object_spec.rb +20 -0
  119. data/spec/poolparty/helpers/messenger_spec.rb +14 -0
  120. data/spec/poolparty/helpers/provisioners/master_spec.rb +2 -2
  121. data/spec/poolparty/net/remoter_spec.rb +1 -1
  122. data/spec/poolparty/plugins/git_spec.rb +26 -19
  123. data/spec/poolparty/pool/base_spec.rb +20 -2
  124. data/spec/poolparty/pool/cloud_spec.rb +256 -249
  125. data/spec/poolparty/pool/custom_resource_spec.rb +6 -1
  126. data/spec/poolparty/pool/plugin_spec.rb +71 -65
  127. data/spec/poolparty/pool/resource_spec.rb +314 -237
  128. data/spec/poolparty/pool/resources/class_package_spec.rb +71 -66
  129. data/spec/poolparty/pool/resources/conditional_spec.rb +30 -26
  130. data/spec/poolparty/pool/resources/gem_spec.rb +18 -14
  131. data/spec/poolparty/pool/resources/variable_spec.rb +1 -1
  132. data/spec/poolparty/pool/script_spec.rb +46 -37
  133. data/spec/poolparty/spec_helper.rb +4 -0
  134. data/tasks/cloud.rake +0 -54
  135. data/tasks/development.rake +11 -14
  136. data/tasks/ec2.rake +10 -17
  137. data/tasks/instance.rake +0 -61
  138. data/website/index.html +1 -1
  139. metadata +83 -10
@@ -0,0 +1,409 @@
1
+ %% This library is free software; you can redistribute it and/or modify
2
+ %% it under the terms of the GNU Lesser General Public License as
3
+ %% published by the Free Software Foundation; either version 2 of the
4
+ %% License, or (at your option) any later version.
5
+ %%
6
+ %% This library is distributed in the hope that it will be useful, but
7
+ %% WITHOUT ANY WARRANTY; without even the implied warranty of
8
+ %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9
+ %% Lesser General Public License for more details.
10
+ %%
11
+ %% You should have received a copy of the GNU Lesser General Public
12
+ %% License along with this library; if not, write to the Free Software
13
+ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
14
+ %% USA
15
+ %%
16
+ %% $Id: file_monitor.erl 250 2008-08-23 09:12:02Z rcarlsson $
17
+ %%
18
+ %% @private (for now)
19
+ %% @author Richard Carlsson <richardc@it.uu.se>
20
+ %% @copyright 2006 Richard Carlsson
21
+ %% @doc Erlang file monitoring service
22
+
23
+ %% The behaviour of this service is inspired by the open source FAM
24
+ %% daemon [http://oss.sgi.com/projects/fam/].
25
+
26
+ -module(file_monitor).
27
+
28
+ -export([start/0, start/1, start/2, stop/0, stop/1, monitor_file/2,
29
+ monitor_file/3, monitor_dir/2, monitor_dir/3, demonitor/1,
30
+ demonitor/2]).
31
+
32
+ -export([main/1]). %% private
33
+
34
+ -include_lib("kernel/include/file.hrl").
35
+
36
+ -define(POLL_TIME, 5000). % default; change with option poll_time
37
+ -define(SERVER, file_monitor).
38
+
39
+ %% NOTE: paths should be absolute, but this is not checked
40
+
41
+ %% We don't change the paths, e.g. from relative to absolute, but we
42
+ %% make sure that the path is a flat string and return it to the caller.
43
+
44
+ monitor_file(Path, Pid) ->
45
+ monitor_file(?SERVER, Path, Pid).
46
+
47
+ monitor_file(Server, Path, Pid) ->
48
+ monitor(Server, file, filename:flatten(Path), Pid).
49
+
50
+ monitor_dir(Path, Pid) ->
51
+ monitor_dir(?SERVER, Path, Pid).
52
+
53
+ monitor_dir(Server, Path, Pid) ->
54
+ monitor(Server, dir, filename:flatten(Path), Pid).
55
+
56
+ monitor(Server, Type, Path, Pid) when is_pid(Pid) ->
57
+ {ok, Ref} = command(Server, {monitor, {Type, Path}, Pid}),
58
+ {ok, Path, Ref}.
59
+
60
+ demonitor(Ref) ->
61
+ demonitor(?SERVER, Ref).
62
+
63
+ demonitor(Server, Ref) ->
64
+ ok = command(Server, {demonitor, Ref}).
65
+
66
+
67
+ command(Server, Cmd) ->
68
+ ServerPid = ensure_started(Server),
69
+ ServerPid ! {command, self(), Cmd},
70
+ receive
71
+ {ServerPid, Result} -> Result
72
+ end.
73
+
74
+
75
+ stop() ->
76
+ stop(?SERVER).
77
+
78
+ stop(Server) ->
79
+ Server ! stop,
80
+ ok.
81
+
82
+ ensure_started(Name) when is_atom(Name) ->
83
+ start(Name, []);
84
+ ensure_started(Pid) when is_pid(Pid) ->
85
+ Pid.
86
+
87
+ start() ->
88
+ start([]).
89
+
90
+ start(Options) ->
91
+ start(?SERVER, Options).
92
+
93
+ start(Name, Options) ->
94
+ case whereis(Name) of
95
+ undefined ->
96
+ Parent = self(),
97
+ Pid = spawn(fun () -> server_init(Name, Parent, Options) end),
98
+ receive
99
+ {Pid, ok} -> Pid;
100
+ {Pid, error} -> throw(no_server)
101
+ end;
102
+ Pid -> Pid
103
+ end.
104
+
105
+ -record(state, {name, time, dirs, files, clients, refs}).
106
+
107
+ server_init(undefined = Name, Parent, Options) ->
108
+ %% anonymous server
109
+ server_init_1(Name, Parent, Options);
110
+ server_init(Name, Parent, Options) ->
111
+ case catch register(Name, self()) of
112
+ true ->
113
+ server_init_1(Name, Parent, Options);
114
+ _ ->
115
+ Parent ! {self(), error},
116
+ exit(failed)
117
+ end.
118
+
119
+ server_init_1(Name, Parent, Options) ->
120
+ Parent ! {self(), ok},
121
+ server(set_timer(init_state(Name, Options))).
122
+
123
+ init_state(Name, Options) ->
124
+ Time = case proplists:get_value(poll_time, Options) of
125
+ N when is_integer(N), N >= 100 -> N;
126
+ _ -> ?POLL_TIME
127
+ end,
128
+ #state{name = Name,
129
+ time = Time,
130
+ dirs = dict:new(),
131
+ files = dict:new(),
132
+ clients = dict:new(),
133
+ refs = dict:new()}.
134
+
135
+ server(St) -> ?MODULE:main(St).
136
+
137
+ %% @private
138
+ main(St) ->
139
+ receive
140
+ {command, From, {monitor, Object, Pid}} when is_pid(Pid) ->
141
+ {Ref, St1} = new_monitor(Object, Pid, St),
142
+ server_reply(From, {ok, Ref}),
143
+ server(add_client(Pid, St1));
144
+ {command, From, {demonitor, Ref}} ->
145
+ server_reply(From, ok),
146
+ server(delete_monitor(Ref, St));
147
+ stop ->
148
+ exit(normal);
149
+ time ->
150
+ server(set_timer(poll(St)));
151
+ {'DOWN', _Ref, process, Pid, _Info} ->
152
+ server(purge_pid(Pid, del_client(Pid, St)));
153
+ _ ->
154
+ server(St)
155
+ end.
156
+
157
+ server_reply(To, Msg) ->
158
+ To ! {self(), Msg}.
159
+
160
+ set_timer(St) ->
161
+ erlang:send_after(St#state.time, self(), time),
162
+ St.
163
+
164
+
165
+ %% client monitoring (once a client, always a client - until death)
166
+
167
+ add_client(Pid, St) ->
168
+ case dict:is_key(Pid, St#state.clients) of
169
+ true ->
170
+ St;
171
+ false ->
172
+ Ref = erlang:monitor(process, Pid),
173
+ St#state{clients = dict:store(Pid, Ref, St#state.clients)}
174
+ end.
175
+
176
+ del_client(Pid, St) ->
177
+ case dict:find(Pid, St#state.clients) of
178
+ {ok, Ref} ->
179
+ erlang:demonitor(Ref, [flush]),
180
+ St#state{clients = dict:erase(Pid, St#state.clients)};
181
+ error ->
182
+ St
183
+ end.
184
+
185
+
186
+ -record(monitor, {pid, reference}).
187
+
188
+ -record(entry, {info = undefined, files = [], monitors = sets:new()}).
189
+
190
+ new_monitor(Object, Pid, St) ->
191
+ Ref = make_ref(),
192
+ Monitor = #monitor{pid = Pid, reference = Ref},
193
+ new_monitor(Object, Monitor, Ref,
194
+ St#state{refs = dict:store(Ref, {Pid, Object},
195
+ St#state.refs)}).
196
+
197
+ %% We must separate the namespaces for files and dirs, since we can't
198
+ %% trust the users to keep them distinct; there may be simultaneous file
199
+ %% and dir monitors for the same path.
200
+
201
+ new_monitor({file, Path}, Monitor, Ref, St) ->
202
+ {Ref, St#state{files = add_monitor(Path, Monitor, file,
203
+ St#state.files)}};
204
+ new_monitor({dir, Path}, Monitor, Ref, St) ->
205
+ {Ref, St#state{dirs = add_monitor(Path, Monitor, dir,
206
+ St#state.dirs)}}.
207
+
208
+ %% Adding a new monitor forces an immediate poll of the file, such that
209
+ %% previous monitors only see any real change, while the new monitor
210
+ %% either gets {exists, ...} or {error, ...}.
211
+
212
+ add_monitor(Path, Monitor, Type, Dict) ->
213
+ Entry = case dict:find(Path, Dict) of
214
+ {ok, OldEntry} -> poll_file(Path, OldEntry, Type);
215
+ error -> new_entry(Path, Type)
216
+ end,
217
+ event(#entry{}, dummy_entry(Entry, Monitor), Type, Path),
218
+ NewEntry = Entry#entry{monitors =
219
+ sets:add_element(Monitor,
220
+ Entry#entry.monitors)},
221
+ dict:store(Path, NewEntry, Dict).
222
+
223
+ dummy_entry(Entry, Monitor) ->
224
+ Entry#entry{monitors = sets:add_element(Monitor, sets:new())}.
225
+
226
+ new_entry(Path, Type) ->
227
+ refresh_entry(Path, #entry{monitors = sets:new()}, Type).
228
+
229
+ %% deleting a monitor by reference
230
+
231
+ delete_monitor(Ref, St) ->
232
+ case dict:find(Ref, St#state.refs) of
233
+ {ok, {_Pid, Object}} ->
234
+ St1 = St#state{refs = dict:erase(Ref, St#state.refs)},
235
+ delete_monitor_1(Ref, Object, St1);
236
+ error ->
237
+ St
238
+ end.
239
+
240
+ delete_monitor_1(Ref, {file, Path}, St) ->
241
+ St#state{files = delete_monitor_2(Path, Ref, St#state.files)};
242
+ delete_monitor_1(Ref, {dir, Path}, St) ->
243
+ St#state{dirs = delete_monitor_2(Path, Ref, St#state.dirs)}.
244
+
245
+ delete_monitor_2(Path, Ref, Dict) ->
246
+ case dict:find(Path, Dict) of
247
+ {ok, Entry} ->
248
+ purge_empty_sets(
249
+ dict:store(Path, purge_monitor_ref(Ref, Entry), Dict));
250
+ error ->
251
+ Dict
252
+ end.
253
+
254
+ purge_monitor_ref(Ref, Entry) ->
255
+ Entry#entry{monitors =
256
+ sets:filter(fun (#monitor{reference = R})
257
+ when R == Ref -> false;
258
+ (_) -> true
259
+ end,
260
+ Entry#entry.monitors)}.
261
+
262
+ %% purging monitors belonging to dead clients
263
+
264
+ purge_pid(Pid, St) ->
265
+ Files = dict:map(fun (_Path, Entry) ->
266
+ purge_monitor_pid(Pid, Entry)
267
+ end,
268
+ St#state.files),
269
+ Dirs = dict:map(fun (_Path, Entry) ->
270
+ purge_monitor_pid(Pid, Entry)
271
+ end,
272
+ St#state.dirs),
273
+ Refs = dict:filter(fun (_Ref, {P, _})
274
+ when P == Pid -> false;
275
+ (_, _) -> true
276
+ end,
277
+ St#state.refs),
278
+ St#state{refs = Refs,
279
+ files = purge_empty_sets(Files),
280
+ dirs = purge_empty_sets(Dirs)}.
281
+
282
+ purge_monitor_pid(Pid, Entry) ->
283
+ Entry#entry{monitors =
284
+ sets:filter(fun (#monitor{pid = P})
285
+ when P == Pid -> false;
286
+ (_) -> true
287
+ end,
288
+ Entry#entry.monitors)}.
289
+
290
+ purge_empty_sets(Dict) ->
291
+ dict:filter(fun (_Path, Entry) ->
292
+ sets:size(Entry#entry.monitors) > 0
293
+ end, Dict).
294
+
295
+
296
+ %% generating events upon state changes
297
+
298
+ %% Message formats:
299
+ %% {exists, Path, Type, #file_info{}, Files}
300
+ %% {changed, Path, Type, #file_info{}, Files}
301
+ %% {error, Path, Type, Info}
302
+ %%
303
+ %% Type is dir or file. If Type is file, Files is always []. If Type is
304
+ %% dir, Files is a list of {added, FileName} and {deleted, FileName},
305
+ %% where FileName is relative to dir, without any path component.
306
+ %%
307
+ %% When a new monitor is installed for a path, an initial {exists,...}
308
+ %% or {error,...} message will be sent to the monitor owner.
309
+ %%
310
+ %% Subsequent events will be either {changed,...} or {error,...}.
311
+
312
+ event(#entry{info = Info}, #entry{info = Info}, _Type, _Path) ->
313
+ %% no change in state
314
+ ok;
315
+ event(#entry{info = undefined}, #entry{info = NewInfo}=Entry,
316
+ Type, Path)
317
+ when not is_atom(NewInfo) ->
318
+ %% file or directory exists, for a fresh monitor
319
+ Files = [{added, F} || F <- Entry#entry.files],
320
+ cast({exists, Path, Type, NewInfo, Files}, Entry#entry.monitors);
321
+ event(_OldEntry, #entry{info = NewInfo}=Entry, Type, Path)
322
+ when is_atom(NewInfo) ->
323
+ %% file is not available
324
+ cast({error, Path, Type, NewInfo}, Entry#entry.monitors);
325
+ event(_OldEntry, Entry, file, Path) ->
326
+ %% a normal file has changed
327
+ cast({changed, Path, file, Entry#entry.info, []},
328
+ Entry#entry.monitors);
329
+ event(#entry{info = OldInfo}, #entry{info = NewInfo}=Entry, dir, Path)
330
+ when is_atom(OldInfo) ->
331
+ %% a directory has suddenly become available
332
+ Files = [{added, F} || F <- Entry#entry.files],
333
+ cast({changed, Path, dir, NewInfo, Files}, Entry#entry.monitors);
334
+ event(OldEntry, #entry{info = NewInfo}=Entry, dir, Path) ->
335
+ %% a directory has changed
336
+ Files = diff_lists(Entry#entry.files, OldEntry#entry.files),
337
+ cast({changed, Path, dir, NewInfo, Files}, Entry#entry.monitors).
338
+
339
+
340
+ poll(St) ->
341
+ St#state{files = dict:map(fun (Path, Entry) ->
342
+ poll_file(Path, Entry, file)
343
+ end,
344
+ St#state.files),
345
+ dirs = dict:map(fun (Path, Entry) ->
346
+ poll_file(Path, Entry, dir)
347
+ end,
348
+ St#state.dirs)}.
349
+
350
+ poll_file(Path, Entry, Type) ->
351
+ NewEntry = refresh_entry(Path, Entry, Type),
352
+ event(Entry, NewEntry, Type, Path),
353
+ NewEntry.
354
+
355
+ refresh_entry(Path, Entry, Type) ->
356
+ Info = get_file_info(Path),
357
+ Files = case Type of
358
+ dir when not is_atom(Info) -> get_dir_files(Path);
359
+ _ -> []
360
+ end,
361
+ Entry#entry{info = Info, files = Files}.
362
+
363
+
364
+ %% We clear some fields of the file_info so that we only trigger on real
365
+ %% changes; see the //kernel/file.erl manual and file.hrl for details.
366
+
367
+ get_file_info(Path) ->
368
+ case file:read_file_info(Path) of
369
+ {ok, Info} ->
370
+ Info#file_info{access = undefined,
371
+ atime = undefined};
372
+ {error, Error} ->
373
+ Error % posix error code as atom
374
+ end.
375
+
376
+ %% Listing the members of a directory; note that it yields the empty
377
+ %% list if it fails - this is not the place for error detection.
378
+
379
+ get_dir_files(Path) ->
380
+ case file:list_dir(Path) of
381
+ {ok, Files} -> lists:sort(Files);
382
+ {error, _} -> []
383
+ end.
384
+
385
+ %% both lists must be sorted for this diff to work
386
+
387
+ diff_lists([F1 | Fs1], [F2 | _]=Fs2) when F1 < F2 ->
388
+ [{added, F1} | diff_lists(Fs1, Fs2)];
389
+ diff_lists([F1 | _]=Fs1, [F2 | Fs2]) when F1 > F2 ->
390
+ [{deleted, F2} | diff_lists(Fs1, Fs2)];
391
+ diff_lists([_ | Fs1], [_ | Fs2]) ->
392
+ diff_lists(Fs1, Fs2);
393
+ diff_lists([F | Fs1], Fs2) ->
394
+ [{added, F} | diff_lists(Fs1, Fs2)];
395
+ diff_lists(Fs1, [F | Fs2]) ->
396
+ [{deleted, F} | diff_lists(Fs1, Fs2)];
397
+ diff_lists([], []) ->
398
+ [].
399
+
400
+
401
+ %% Multicasting events to clients
402
+
403
+ cast(Msg, Monitors) ->
404
+ sets:fold(fun (#monitor{pid = Pid, reference = Ref}, Msg) ->
405
+ %%erlang:display({file_monitor, Ref, Msg}),
406
+ Pid ! {file_monitor, Ref, Msg},
407
+ Msg % note that this is a fold, not a map
408
+ end,
409
+ Msg, Monitors).
@@ -0,0 +1,9 @@
1
+ [
2
+ {kernel,
3
+ [{error_logger,
4
+ {file, "priv/eunit.log"}}]},
5
+ {sasl,
6
+ [{sasl_error_logger, false},
7
+ {error_logger_mf_dir, "."},
8
+ {error_logger_mf_maxfiles, 20},
9
+ {error_logger_mf_maxbytes, 1000000}]}].
@@ -0,0 +1 @@
1
+ EUNIT_VSN = 2.0 beta 1
@@ -1,6 +1,6 @@
1
- %% script generated at {2008,10,23} {2,11,55}
1
+ %% script generated at {2008,10,25} {16,17,48}
2
2
  {script,
3
- {"pm_master_rel","0.1"},
3
+ {"master","0.1"},
4
4
  [{preLoaded,
5
5
  [erlang,erl_prim_loader,prim_file,prim_inet,init,otp_ring0]},
6
6
  {progress,preloaded},
@@ -39,6 +39,27 @@
39
39
  erl_compile,erl_bits,epp,edlin_expand,edlin,digraph_utils,
40
40
  digraph,dict,dets_v9,dets_v8,dets_utils,dets_sup,
41
41
  dets_server,dets,calendar,c,beam_lib,base64,array]},
42
+ {path,["/opt/local/lib/erlang/lib/inets-5.0.5/ebin"]},
43
+ {primLoad,
44
+ [tftp_sup,tftp_lib,tftp_file,tftp_engine,tftp_binary,tftp,
45
+ mod_trace,mod_security_server,mod_security,
46
+ mod_responsecontrol,mod_range,mod_log,mod_include,
47
+ mod_htaccess,mod_head,mod_get,mod_esi,mod_disk_log,mod_dir,
48
+ mod_cgi,mod_browser,mod_auth_server,mod_auth_plain,
49
+ mod_auth_mnesia,mod_auth_dets,mod_auth,mod_alias,
50
+ mod_actions,inets_sup,inets_service,inets_app,inets,
51
+ httpd_util,httpd_sup,httpd_socket,httpd_script_env,
52
+ httpd_response,httpd_request_handler,httpd_request,
53
+ httpd_misc_sup,httpd_manager,httpd_log,httpd_instance_sup,
54
+ httpd_file,httpd_example,httpd_esi,httpd_conf,httpd_cgi,
55
+ httpd_acceptor_sup,httpd_acceptor,httpd,httpc_sup,
56
+ httpc_response,httpc_request,httpc_profile_sup,
57
+ httpc_manager,httpc_handler_sup,httpc_handler,http_util,
58
+ http_uri,http_transport,http_response,http_request,
59
+ http_cookie,http_chunk,http,ftp_sup,ftp_response,
60
+ ftp_progress,ftp]},
61
+ {path,["/opt/local/lib/erlang/lib/crypto-1.5.1.1/ebin"]},
62
+ {primLoad,[crypto_sup,crypto_server,crypto_app,crypto]},
42
63
  {path,["/opt/local/lib/erlang/lib/sasl-2.1.5.2/ebin"]},
43
64
  {primLoad,
44
65
  [systools_relup,systools_rc,systools_make,systools_lib,
@@ -52,6 +73,8 @@
52
73
  {path,
53
74
  ["/opt/local/lib/erlang/lib/kernel-2.12.2/ebin",
54
75
  "/opt/local/lib/erlang/lib/stdlib-1.15.2/ebin",
76
+ "/opt/local/lib/erlang/lib/inets-5.0.5/ebin",
77
+ "/opt/local/lib/erlang/lib/crypto-1.5.1.1/ebin",
55
78
  "/opt/local/lib/erlang/lib/sasl-2.1.5.2/ebin",
56
79
  "/Users/auser/Sites/work/citrusbyte/internal/gems/pool-party/poolparty/lib/erlang/messenger/ebin"]},
57
80
  {kernelProcess,heart,{heart,start,[]}},
@@ -124,6 +147,54 @@
124
147
  {start_phases,undefined},
125
148
  {maxT,infinity},
126
149
  {maxP,infinity}]}]}},
150
+ {apply,
151
+ {application,load,
152
+ [{application,inets,
153
+ [{description,"INETS CXC 138 49"},
154
+ {vsn,"5.0.5"},
155
+ {id,[]},
156
+ {modules,
157
+ [inets,inets_sup,inets_app,inets_service,ftp,
158
+ ftp_progress,ftp_response,ftp_sup,http,httpc_handler,
159
+ httpc_handler_sup,httpc_manager,httpc_profile_sup,
160
+ httpc_request,httpc_response,httpc_sup,http_cookie,
161
+ http_uri,http_chunk,http_request,http_response,
162
+ http_transport,http_util,httpd,httpd_acceptor,
163
+ httpd_acceptor_sup,httpd_cgi,httpd_conf,httpd_esi,
164
+ httpd_example,httpd_file,httpd_instance_sup,httpd_log,
165
+ httpd_manager,httpd_misc_sup,httpd_request,
166
+ httpd_request_handler,httpd_response,httpd_script_env,
167
+ httpd_socket,httpd_sup,httpd_util,mod_actions,
168
+ mod_alias,mod_auth,mod_auth_dets,mod_auth_mnesia,
169
+ mod_auth_plain,mod_auth_server,mod_browser,mod_cgi,
170
+ mod_dir,mod_disk_log,mod_esi,mod_get,mod_head,
171
+ mod_htaccess,mod_include,mod_log,mod_range,
172
+ mod_responsecontrol,mod_security,mod_security_server,
173
+ mod_trace,tftp,tftp_binary,tftp_engine,tftp_file,
174
+ tftp_lib,tftp_sup]},
175
+ {registered,[inets_sup,httpc_manager]},
176
+ {applications,[kernel,stdlib]},
177
+ {included_applications,[]},
178
+ {env,[]},
179
+ {start_phases,undefined},
180
+ {maxT,infinity},
181
+ {maxP,infinity},
182
+ {mod,{inets_app,[]}}]}]}},
183
+ {apply,
184
+ {application,load,
185
+ [{application,crypto,
186
+ [{description,"CRYPTO version 1"},
187
+ {vsn,"1.5.1.1"},
188
+ {id,[]},
189
+ {modules,[crypto,crypto_app,crypto_sup,crypto_server]},
190
+ {registered,[crypto_sup,crypto_server]},
191
+ {applications,[kernel,stdlib]},
192
+ {included_applications,[]},
193
+ {env,[]},
194
+ {start_phases,undefined},
195
+ {maxT,infinity},
196
+ {maxP,infinity},
197
+ {mod,{crypto_app,[]}}]}]}},
127
198
  {apply,
128
199
  {application,load,
129
200
  [{application,sasl,
@@ -163,6 +234,8 @@
163
234
  {progress,applications_loaded},
164
235
  {apply,{application,start_boot,[kernel,permanent]}},
165
236
  {apply,{application,start_boot,[stdlib,permanent]}},
237
+ {apply,{application,start_boot,[inets,permanent]}},
238
+ {apply,{application,start_boot,[crypto,permanent]}},
166
239
  {apply,{application,start_boot,[sasl,permanent]}},
167
240
  {apply,{application,start_boot,[master,permanent]}},
168
241
  {apply,{c,erlangrc,[]}},
@@ -1,6 +1,6 @@
1
- %% script generated at {2008,10,23} {2,11,55}
1
+ %% script generated at {2008,10,25} {16,17,48}
2
2
  {script,
3
- {"pm_node_rel","0.1"},
3
+ {"node","0.1"},
4
4
  [{preLoaded,
5
5
  [erlang,erl_prim_loader,prim_file,prim_inet,init,otp_ring0]},
6
6
  {progress,preloaded},
@@ -39,6 +39,27 @@
39
39
  erl_compile,erl_bits,epp,edlin_expand,edlin,digraph_utils,
40
40
  digraph,dict,dets_v9,dets_v8,dets_utils,dets_sup,
41
41
  dets_server,dets,calendar,c,beam_lib,base64,array]},
42
+ {path,["/opt/local/lib/erlang/lib/inets-5.0.5/ebin"]},
43
+ {primLoad,
44
+ [tftp_sup,tftp_lib,tftp_file,tftp_engine,tftp_binary,tftp,
45
+ mod_trace,mod_security_server,mod_security,
46
+ mod_responsecontrol,mod_range,mod_log,mod_include,
47
+ mod_htaccess,mod_head,mod_get,mod_esi,mod_disk_log,mod_dir,
48
+ mod_cgi,mod_browser,mod_auth_server,mod_auth_plain,
49
+ mod_auth_mnesia,mod_auth_dets,mod_auth,mod_alias,
50
+ mod_actions,inets_sup,inets_service,inets_app,inets,
51
+ httpd_util,httpd_sup,httpd_socket,httpd_script_env,
52
+ httpd_response,httpd_request_handler,httpd_request,
53
+ httpd_misc_sup,httpd_manager,httpd_log,httpd_instance_sup,
54
+ httpd_file,httpd_example,httpd_esi,httpd_conf,httpd_cgi,
55
+ httpd_acceptor_sup,httpd_acceptor,httpd,httpc_sup,
56
+ httpc_response,httpc_request,httpc_profile_sup,
57
+ httpc_manager,httpc_handler_sup,httpc_handler,http_util,
58
+ http_uri,http_transport,http_response,http_request,
59
+ http_cookie,http_chunk,http,ftp_sup,ftp_response,
60
+ ftp_progress,ftp]},
61
+ {path,["/opt/local/lib/erlang/lib/crypto-1.5.1.1/ebin"]},
62
+ {primLoad,[crypto_sup,crypto_server,crypto_app,crypto]},
42
63
  {path,["/opt/local/lib/erlang/lib/sasl-2.1.5.2/ebin"]},
43
64
  {primLoad,
44
65
  [systools_relup,systools_rc,systools_make,systools_lib,
@@ -52,6 +73,8 @@
52
73
  {path,
53
74
  ["/opt/local/lib/erlang/lib/kernel-2.12.2/ebin",
54
75
  "/opt/local/lib/erlang/lib/stdlib-1.15.2/ebin",
76
+ "/opt/local/lib/erlang/lib/inets-5.0.5/ebin",
77
+ "/opt/local/lib/erlang/lib/crypto-1.5.1.1/ebin",
55
78
  "/opt/local/lib/erlang/lib/sasl-2.1.5.2/ebin",
56
79
  "/Users/auser/Sites/work/citrusbyte/internal/gems/pool-party/poolparty/lib/erlang/messenger/ebin"]},
57
80
  {kernelProcess,heart,{heart,start,[]}},
@@ -124,6 +147,54 @@
124
147
  {start_phases,undefined},
125
148
  {maxT,infinity},
126
149
  {maxP,infinity}]}]}},
150
+ {apply,
151
+ {application,load,
152
+ [{application,inets,
153
+ [{description,"INETS CXC 138 49"},
154
+ {vsn,"5.0.5"},
155
+ {id,[]},
156
+ {modules,
157
+ [inets,inets_sup,inets_app,inets_service,ftp,
158
+ ftp_progress,ftp_response,ftp_sup,http,httpc_handler,
159
+ httpc_handler_sup,httpc_manager,httpc_profile_sup,
160
+ httpc_request,httpc_response,httpc_sup,http_cookie,
161
+ http_uri,http_chunk,http_request,http_response,
162
+ http_transport,http_util,httpd,httpd_acceptor,
163
+ httpd_acceptor_sup,httpd_cgi,httpd_conf,httpd_esi,
164
+ httpd_example,httpd_file,httpd_instance_sup,httpd_log,
165
+ httpd_manager,httpd_misc_sup,httpd_request,
166
+ httpd_request_handler,httpd_response,httpd_script_env,
167
+ httpd_socket,httpd_sup,httpd_util,mod_actions,
168
+ mod_alias,mod_auth,mod_auth_dets,mod_auth_mnesia,
169
+ mod_auth_plain,mod_auth_server,mod_browser,mod_cgi,
170
+ mod_dir,mod_disk_log,mod_esi,mod_get,mod_head,
171
+ mod_htaccess,mod_include,mod_log,mod_range,
172
+ mod_responsecontrol,mod_security,mod_security_server,
173
+ mod_trace,tftp,tftp_binary,tftp_engine,tftp_file,
174
+ tftp_lib,tftp_sup]},
175
+ {registered,[inets_sup,httpc_manager]},
176
+ {applications,[kernel,stdlib]},
177
+ {included_applications,[]},
178
+ {env,[]},
179
+ {start_phases,undefined},
180
+ {maxT,infinity},
181
+ {maxP,infinity},
182
+ {mod,{inets_app,[]}}]}]}},
183
+ {apply,
184
+ {application,load,
185
+ [{application,crypto,
186
+ [{description,"CRYPTO version 1"},
187
+ {vsn,"1.5.1.1"},
188
+ {id,[]},
189
+ {modules,[crypto,crypto_app,crypto_sup,crypto_server]},
190
+ {registered,[crypto_sup,crypto_server]},
191
+ {applications,[kernel,stdlib]},
192
+ {included_applications,[]},
193
+ {env,[]},
194
+ {start_phases,undefined},
195
+ {maxT,infinity},
196
+ {maxP,infinity},
197
+ {mod,{crypto_app,[]}}]}]}},
127
198
  {apply,
128
199
  {application,load,
129
200
  [{application,sasl,
@@ -163,6 +234,8 @@
163
234
  {progress,applications_loaded},
164
235
  {apply,{application,start_boot,[kernel,permanent]}},
165
236
  {apply,{application,start_boot,[stdlib,permanent]}},
237
+ {apply,{application,start_boot,[inets,permanent]}},
238
+ {apply,{application,start_boot,[crypto,permanent]}},
166
239
  {apply,{application,start_boot,[sasl,permanent]}},
167
240
  {apply,{application,start_boot,[node,permanent]}},
168
241
  {apply,{c,erlangrc,[]}},
@@ -1,9 +1,11 @@
1
1
  -module (pm_client).
2
- -export ([send_cmd/1, reconfigure_cloud/0, get_load/1, get_live_nodes/0]).
3
-
2
+ -export ([init/0, send_cmd/1, reconfigure_cloud/0, get_load/1, get_live_nodes/0]).
3
+ -export ([shutdown/0]).
4
4
  % Run commands on the running master process
5
5
  % erl -pa ./ebin/ -run pm_client get_load cpu -run init stop -noshell
6
6
 
7
+ % Connect to the master
8
+ init() -> net_adm:ping(master@master).
7
9
  % Send the command Cmd to the pm_master process
8
10
  send_cmd(Cmd) -> pm_master:fire_cmd(Cmd).
9
11
  % Reconfigure the cloud
@@ -11,4 +13,7 @@ reconfigure_cloud() -> pm_master:reconfigure_cloud().
11
13
  % Get the load on the cloud of type Type
12
14
  get_load(Type) -> pm_master:get_load(Type).
13
15
  % Get a list of the live nodes
14
- get_live_nodes() -> pm_master:get_live_nodes().
16
+ get_live_nodes() -> pm_master:get_live_nodes().
17
+ % Terminate the cloud messenger
18
+ % This sends a shutdown to the whole cloud
19
+ shutdown() -> pm_master:shutdown_cloud().