ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MP/bin/aemp
Revision: 1.19
Committed: Sun Aug 30 09:24:09 2009 UTC (14 years, 9 months ago) by root
Branch: MAIN
Changes since 1.18: +69 -47 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #!/opt/bin/perl
2
3 =head1 NAME
4
5 aemp - AnyEvent:MP utility
6
7 =head1 SYNOPSIS
8
9 aemp command args...
10
11 # protocol commands
12 aemp snd <port> <arg...> # send a message
13 aemp mon <port> # wait till port is killed
14 aemp rpc <port> <arg...> # send message, append reply
15 aemp eval <node> <expr...> # evaluate expression
16
17 # run a node
18 aemp run initialise_args... # run a node
19
20 # node configuration: protocol endpoints
21 aemp setnodeid <nodeid> # configure the real node id
22 aemp delnodeid # reset node id to default (= inherit)
23
24 # node configuration: secret
25 aemp gensecret # generate a random shared secret
26 aemp setsecret <secret> # set the shared secret
27 aemp delsecret # remove the secret (= inherit)
28
29 # node configuration: TLS
30 aemp gencert # generate a random certificate
31 aemp setcert <file> # set a certificate (key.pem + certificate.pem)
32 aemp delcert # remove certificate (= inherit)
33
34 # node configuration: seed addresses for bootstrapping
35 aemp setseeds <host:port>,... # set seeds
36 aemp delseeds # clear all seeds (= inherit)
37 aemp addseed <host:port> # add a seed
38 aemp delseed <host:port> # remove seed
39
40 # node configuration: bind addresses
41 aemp setbinds <host:port>,... # set binds
42 aemp delbinds # clear all binds (= inherit)
43 aemp addbind <host:port> # add a bind address
44 aemp delbind <host:port> # remove a bind address
45
46 # node configuration: services
47 aemp setservices initfunc,... # set service functions
48 aemp delservices # clear all services (= inherit)
49 aemp addservice <initfunc> # add an instance of a service
50 aemp delservice <initfunc> # delete one instance of a service
51
52 # profile-specific configuration
53 aemp profile <name> <command>... # apply command to profile only
54 aemp delprofile <name> # eradicate the named profile
55 aemp showprofile <name> # display given profile
56 aemp showconfig <name> # display effective config
57
58 # debugging
59 aemp trace <nodeid> # trace the network topology
60
61 =head1 DESCRIPTION
62
63 With aemp you can configure various aspects of AnyEvent::MP and its
64 protocol.
65
66 You can also start a "default node", a node that only depends on the
67 static configuration.
68
69 =cut
70
71 use common::sense;
72
73 # should come before anything else, so all modules
74 # will be loaded on each restart
75 BEGIN {
76 if ($ARGV[0] eq "run") {
77 shift;
78
79 # d'oh
80 require AnyEvent::Watchdog;
81 # now we can load extra modules
82
83 AnyEvent::Watchdog::autorestart (1);
84 AnyEvent::Watchdog::heartbeat (300);
85
86 require AnyEvent;
87 require AnyEvent::MP;
88 AnyEvent::MP::initialise_node (@ARGV);
89
90 AnyEvent::detect () eq "AnyEvent::Impl::EV"
91 ? EV::loop ()
92 : AE::cv ()->recv;
93 }
94 }
95
96 use Carp ();
97
98 use JSON::XS;
99
100 use AnyEvent;
101 use AnyEvent::Util;
102
103 use AnyEvent::MP;
104 use AnyEvent::MP::Config;
105
106 sub my_run_cmd {
107 my ($cmd) = @_;
108
109 my $cv = &run_cmd;
110 my $status = $cv->recv;
111
112 $status
113 and die "@$cmd: command failed with exit status $status.";
114 }
115
116 sub gen_cert {
117 my_run_cmd [qw(openssl req
118 -new -nodes -x509 -days 3650
119 -newkey rsa:2048 -keyout /dev/fd/3
120 -batch -subj /CN=AnyEvent::MP
121 )],
122 "<", "/dev/null",
123 ">" , \my $cert,
124 "3>", \my $key,
125 "2>", "/dev/null";
126
127 "$cert$key"
128 }
129
130 our $cfg = AnyEvent::MP::Config::config;
131 our $profile = $cfg;
132
133 sub trace {
134 my ($node) = @_;
135 my $cv = AE::cv;
136 my %seen;
137
138 my $to = AE::timer 15, 0, sub {
139 warn "timeout\n";
140 $cv->();
141 };
142
143 initialise_node "anon/";
144
145 my $reply = port {
146 my ($node, @neigh) = @_;
147
148 @neigh = grep $_ ne $NODE, @neigh;
149
150 print +(join " ", $node, @neigh), "\n";
151
152 for (@neigh) {
153 unless ($seen{$_}++) {
154 $cv->begin;
155 snd $_, up_nodes => $SELF => $_;
156 }
157 }
158
159 $cv->end;
160 };
161
162 $cv->begin;
163 snd $reply, seed => $node;
164
165 $cv->recv;
166 }
167
168 sub docmd;
169
170 our %CMD = (
171 snd => sub {
172 my $port = shift @ARGV;
173 initialise_node "anon/";
174
175 snd $port, @ARGV; @ARGV = ();
176
177 my $cv = AE::cv;
178 my $to = AE::timer 5, 0, sub { $cv->("timeout") };
179 mon $port, $cv;
180 my $reply = port sub { &$cv };
181 snd node_of $port, snd => $reply, "message sent successfully";
182
183 print join " ", $cv->recv, "\n";
184 },
185
186 rpc => sub {
187 my $port = shift @ARGV;
188 initialise_node "anon/";
189
190 my $cv = AE::cv;
191 my $to = AE::timer 5, 0, sub { $cv->("timeout") };
192 snd $port, @ARGV, port { &$cv }; @ARGV = ();
193 mon $port, $cv;
194
195 print join " ", $cv->recv, "\n";
196 },
197
198 mon => sub {
199 my $port = shift @ARGV;
200 initialise_node "anon/";
201
202 mon $port, my $cv = AE::cv;
203 print join " ", $cv->recv, "\n";
204 },
205
206 eval => sub {
207 my $node = node_of shift @ARGV;
208 my $expr = join " ", @ARGV; @ARGV = ();
209 initialise_node "anon/";
210
211 my $cv = AE::cv;
212 my $to = AE::timer 5, 0, sub { $cv->("timeout") };
213 AnyEvent::MP::Kernel::eval_on $node, $expr, port { &$cv };
214 mon $node, $cv;
215
216 my ($err, @res) = $cv->recv;
217
218 die $err if length $err;
219
220 print +(substr JSON::XS->new->encode (\@res), 1, -1), "\n";
221 },
222
223 trace => sub {
224 @ARGV >= 1
225 or die "node id missing\n";
226
227 trace shift @ARGV;
228 },
229
230 setnodeid => sub {
231 @ARGV >= 1
232 or die "shared secret missing\n";
233
234 $profile->{nodeid} = shift @ARGV;
235 ++$cfg->{dirty};
236 },
237 delnodeid => sub {
238 delete $profile->{nodeid};
239 ++$cfg->{dirty};
240 },
241
242 setsecret => sub {
243 @ARGV >= 1
244 or die "shared secret missing\n";
245
246 $profile->{secret} = shift @ARGV;
247 ++$cfg->{dirty};
248 },
249 gensecret => sub {
250 $profile->{secret} = AnyEvent::MP::Kernel::alnumbits AnyEvent::MP::Kernel::nonce 64;
251 ++$cfg->{dirty};
252 },
253 delsecret => sub {
254 delete $profile->{secret};
255 ++$cfg->{dirty};
256 },
257
258 setcert => sub {
259 @ARGV >= 1
260 or die "key+certificate pem filename missing\n";
261
262 open my $fh, "<", $ARGV[0]
263 or die "$ARGV[0]: $!";
264
265 local $/;
266 $profile->{cert} = <$fh>;
267 ++$cfg->{dirty};
268 },
269 gencert => sub {
270 $profile->{cert} = gen_cert;
271 ++$cfg->{dirty};
272 },
273 delcert => sub {
274 delete $profile->{cert};
275 ++$cfg->{dirty};
276 },
277
278 setbinds => sub {
279 @ARGV >= 1
280 or die "bind addresses missing\n";
281 $profile->{binds} = [split /,/, shift @ARGV];
282 ++$cfg->{dirty};
283 },
284 delbinds => sub {
285 delete $profile->{binds};
286 ++$cfg->{dirty};
287 },
288 addbind => sub {
289 @ARGV >= 1
290 or die "bind address missing\n";
291 my $bind = shift @ARGV;
292
293 @{ $profile->{binds} } = grep $_ ne $bind, @{ $profile->{binds} };
294 push @{ $profile->{binds} }, $bind;
295 ++$cfg->{dirty};
296 },
297 delbind => sub {
298 @ARGV >= 1
299 or die "bind address missing\n";
300 my $bind = shift @ARGV;
301
302 @{ $profile->{binds} } = grep $_ ne $bind, @{ $profile->{binds} };
303 ++$cfg->{dirty};
304 },
305
306 setseeds => sub {
307 @ARGV >= 1
308 or die "seed addresses missing\n";
309 $profile->{seeds} = [split /,/, shift @ARGV];
310 ++$cfg->{dirty};
311 },
312 delseeds => sub {
313 delete $profile->{seeds};
314 ++$cfg->{dirty};
315 },
316 addseed => sub {
317 @ARGV >= 1
318 or die "seed address missing\n";
319 my $seed = shift @ARGV;
320
321 @{ $profile->{seeds} } = grep $_ ne $seed, @{ $profile->{seeds} };
322 push @{ $profile->{seeds} }, $seed;
323 ++$cfg->{dirty};
324 },
325 delseed => sub {
326 @ARGV >= 1
327 or die "seed address missing\n";
328 my $seed = shift @ARGV;
329
330 @{ $profile->{seeds} } = grep $_ ne $seed, @{ $profile->{seeds} };
331 ++$cfg->{dirty};
332 },
333
334 setservices => sub {
335 @ARGV >= 1
336 or die "service specifications missing\n";
337 $profile->{services} = [split /,/, shift @ARGV];
338 @ARGV = ();
339 ++$cfg->{dirty};
340 },
341 delservices => sub {
342 delete $profile->{services};
343 ++$cfg->{dirty};
344 },
345 addservice => sub {
346 @ARGV >= 1
347 or die "service specification missing\n";
348 my $service = shift @ARGV;
349 push @{ $profile->{services} }, $service;
350 ++$cfg->{dirty};
351 },
352 delservice => sub {
353 @ARGV >= 1
354 or die "service specification missing\n";
355 my $service = shift @ARGV;
356 for (0 .. $#{ $profile->{services} }) {
357 next unless $profile->{services}[$_] eq $service;
358 splice @{ $profile->{services} }, $_, 1;
359 last;
360 }
361 ++$cfg->{dirty};
362 },
363
364 profile => sub {
365 @ARGV >= 1
366 or die "profile name is missing\n";
367 my $name = shift @ARGV;
368
369 $profile = $cfg->{profile}{$name} ||= {};
370 ++$cfg->{dirty};
371 },
372 delprofile => sub {
373 @ARGV >= 1
374 or die "profile name is missing\n";
375 my $name = shift @ARGV;
376
377 delete $cfg->{profile}{$name};
378 ++$cfg->{dirty};
379 },
380 showprofile => sub {
381 @ARGV >= 1
382 or die "profile name is missing\n";
383 my $name = shift @ARGV;
384
385 print JSON::XS->new->pretty->encode ($cfg->{profile}{$name} || {});
386 },
387 showconfig => sub {
388 my $name = @ARGV ? shift @ARGV : AnyEvent::MP::Kernel::_nodename;
389
390 print JSON::XS->new->pretty->encode (AnyEvent::MP::Config::find_profile $name);
391 },
392 );
393
394 sub docmd {
395 my $cmd = shift @ARGV;
396
397 $CMD{$cmd}
398 or die "$cmd: no such aemp command (try man aemp)";
399
400 $CMD{$cmd}();
401 }
402
403 @ARGV
404 or die "Usage: aemp subcommand ... (try man aemp)\n";
405
406 docmd while @ARGV;
407
408