ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MP/bin/aemp
Revision: 1.52
Committed: Fri Mar 2 19:48:18 2012 UTC (12 years, 3 months ago) by root
Branch: MAIN
Changes since 1.51: +24 -18 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.38 #!/opt/bin/perl
2 root 1.1
3     =head1 NAME
4    
5     aemp - AnyEvent:MP utility
6    
7     =head1 SYNOPSIS
8    
9     aemp command args...
10    
11     # protocol commands
12 root 1.19 aemp snd <port> <arg...> # send a message
13     aemp mon <port> # wait till port is killed
14 root 1.41 aemp cal <port> <arg...> # send message, append reply
15 root 1.19 aemp eval <node> <expr...> # evaluate expression
16 root 1.42 aemp shell [<node>] # run an interactive shell
17 root 1.37 aemp trace <node> # trace the network topology
18 root 1.8
19     # run a node
20 root 1.26 aemp run configure_args... # run a node
21 root 1.37 aemp restart <node> # restart a node if running under watchdog
22 root 1.8
23 root 1.23 # node configuration: node ID
24 root 1.19 aemp setnodeid <nodeid> # configure the real node id
25     aemp delnodeid # reset node id to default (= inherit)
26 root 1.1
27 root 1.47 # node configuration: authentication
28 root 1.19 aemp gensecret # generate a random shared secret
29     aemp setsecret <secret> # set the shared secret
30     aemp delsecret # remove the secret (= inherit)
31     aemp gencert # generate a random certificate
32     aemp setcert <file> # set a certificate (key.pem + certificate.pem)
33     aemp delcert # remove certificate (= inherit)
34 root 1.8
35 root 1.17 # node configuration: seed addresses for bootstrapping
36 root 1.19 aemp setseeds <host:port>,... # set seeds
37     aemp delseeds # clear all seeds (= inherit)
38     aemp addseed <host:port> # add a seed
39     aemp delseed <host:port> # remove seed
40 root 1.17
41     # node configuration: bind addresses
42 root 1.19 aemp setbinds <host:port>,... # set binds
43     aemp delbinds # clear all binds (= inherit)
44     aemp addbind <host:port> # add a bind address
45     aemp delbind <host:port> # remove a bind address
46 root 1.8
47     # node configuration: services
48 root 1.19 aemp setservices initfunc,... # set service functions
49     aemp delservices # clear all services (= inherit)
50     aemp addservice <initfunc> # add an instance of a service
51     aemp delservice <initfunc> # delete one instance of a service
52 root 1.6
53 root 1.47 # profile management
54 root 1.10 aemp profile <name> <command>... # apply command to profile only
55 root 1.26 aemp setparent <name> # specify a parent profile
56 root 1.25 aemp delparent # clear parent again
57 root 1.19 aemp delprofile <name> # eradicate the named profile
58     aemp showprofile <name> # display given profile
59 root 1.25 aemp showconfig <name> ... # display effective config
60 root 1.10
61 root 1.47 # node configuration: low-level protocol
62     aemp [set|del]monitor_timeout <seconds>
63     aemp [set|del]connect_interval <seconds>
64     aemp [set|del]framing_format [array]
65     aemp [set|del]auth_offer [array]
66     aemp [set|del]auth_accept [array]
67     aemp [set|del]autocork <boolean>
68     aemp [set|del]nodelay <boolean>
69    
70 root 1.1 =head1 DESCRIPTION
71    
72 root 1.8 With aemp you can configure various aspects of AnyEvent::MP and its
73 root 1.22 protocol, send various messages and even run a node.
74 root 1.1
75 root 1.23 The F<aemp> utility works like F<cvs>, F<svn> or other commands: the first
76     argument defines which operation (subcommand) is requested, after which
77     arguments for this operation are expected. When a subcommand does not eat
78     all remaining arguments, the remaining arguments will again be interpreted
79     as subcommand and so on.
80    
81     This means you can chain multiple commands, which is handy for profile
82     configuration, e.g.:
83    
84 root 1.27 aemp gensecret profile xyzzy binds 4040,4041 nodeid anon/
85    
86     Please note that all C<setxxx> subcommands have an alias without the
87     C<set> prefix.
88 root 1.23
89 root 1.34 All configuration data is stored in a human-readable (JSON) config file
90 root 1.46 stored in F<~/.perl-anyevent-mp> (or F<%appdata%/perl-anyevent-mp> on
91 root 1.49 loser systems, or wherever C<$ENV{PERL_ANYEVENT_MP_RC}> points to). Feel
92 root 1.46 free to look at it or edit it, the format is relatively simple.
93 root 1.34
94 root 1.35 =head2 SPECIFYING ARGUMENTS
95    
96     Arguments can be specified just as with any other shell command, with a
97     few special cases:
98    
99     If the I<first> argument starts with a literal C<[>-character, then it is
100     interpreted as a UTF-8 encoded JSON text. The resulting array replaces all
101     arguments.
102    
103     Otherwise, if I<any> argument starts with one of C<[>, C<{> or C<">, then
104     it is interpreted as UTF-8 encoded JSON text (or a single value in case of
105     C<">), and the resulting reference or scalar replaces the argument.
106    
107     This allows you, for example, to specify binds in F<aemp run> (using POSIX
108     shell syntax):
109    
110     aemp run binds '["*:4040"]'
111    
112 root 1.23 =head2 RUNNING A NODE
113    
114     This can be used to run a node - together with some services, this makes
115 elmex 1.32 it unnecessary to write any wrapper programs.
116 root 1.23
117     =over 4
118    
119 root 1.30 =item run <configure_args>...
120 root 1.23
121 root 1.26 Runs a node by calling C<AnyEvent::MP::Kernel::configure> with the given
122 root 1.23 arguments. The node runs under L<AnyEvent::Watchdog>, can be restarted
123 root 1.30 (and autorestarted, see the L<AnyEvent::Watchdog> manual). A very common
124 root 1.33 invocation is to just specify a profile using the profile name
125 root 1.30
126 root 1.33 aemp run database-backend
127 root 1.30
128     ... but you can use most arguments that C<configure> understands:
129    
130     aemp run nodeid mynode2 profile someprofile
131 root 1.23
132     Care has been taken to load (almost) no modules other than
133     L<AnyEvent::Watchdog> and the modules it loads, so everything (including
134     the L<AnyEvent::MP> modules themselves) will be freshly loaded on restart,
135     which makes upgrading everything except the perl binary easy.
136    
137 root 1.37 =item restart <node>
138    
139     Restarts the node using C<AnyEvent::Watchdog::Util::restart>. This works
140     for nodes started by C<aemp run>, but also for any other node that uses
141     L<AnyEvent::Watchdog>.
142    
143 root 1.23 =back
144    
145     =head2 PROTOCOL COMMANDS
146    
147     These commands actually communicate with other nodes. They all use a node
148 elmex 1.32 profile name of C<aemp> (specifying a default node ID of C<anon/> and a
149 root 1.25 binds list containing C<*:*> only).
150 root 1.23
151     They all use a timeout of five seconds, after which they give up.
152    
153     =over 4
154    
155     =item snd <port> <arguments...>
156    
157     Simply send a message to the given port - where you get the port ID from
158     is your problem.
159    
160     Exits after ensuring that the message has been delivered to its node.
161    
162 elmex 1.32 Most useful to take advantage of some undocumented functionality inside
163 root 1.23 nodes, such as node ports being able to call any method:
164    
165     aemp snd doomed AnyEvent::Watchdog::restart 1
166    
167 root 1.41 =item cal <port> <arg...>
168 root 1.23
169 root 1.41 Like F<aemp cal>: appends a local reply port to the message and waits for
170     a message to it.
171 root 1.23
172     Any return values will be JSON-encoded and printed separated by commas
173     (kind of like a JSON array without []-brackets).
174    
175 root 1.41 Example: ask the (undocumented) time service of a node for its current
176 root 1.23 time.
177    
178 root 1.41 aemp cal mynode time
179 root 1.23
180     =item mon <port>
181    
182     Monitors the port and exits when it's monitorign callback is called. Most
183     useful to monitor node ports.
184    
185     Example: monitor some node.
186    
187     aemp mon doomed
188    
189     =item eval <node> <expr...>
190    
191     Joins all remaining arguments into a string and evaluates it on the given
192 root 1.41 node. Return values are handled as with F<aemp cal>.
193 root 1.23
194     Example: find the unix process ID of the node called posicks.
195    
196     aemp eval posicks '$$'
197    
198     =item trace <node>
199    
200     Asks the given node for all currently connected nodes, then asks those
201     nodes for the same, thus tracing all node connections.
202    
203 root 1.31 =back
204 root 1.23
205     =head2 CONFIGURATION/NODE ID/SECRET/CERTIFICATE
206    
207     These commands deal with rather basic settings, the node ID, the shared
208     secret and the TLS certificate.
209    
210     =over 4
211    
212     =item setnodeid <nodeid>
213    
214 root 1.50 Set the node ID to the given string. If it ends with a slash (C</>), then
215     a random string is appended to make it unique.
216    
217     If no nodeid is specified in any profile, then the profile name, plus
218     appended slash, is used.
219 root 1.23
220     =item delnodeid
221    
222     Removes the node ID again, which means it is inherited again from it's
223     parent profile, or stays unset.
224    
225     =item gensecret
226    
227 root 1.51 Generates a random shared secret (currently 1071 bits) and sets it. The
228     shared secret is used to authenticate nodes to each other when TLS is not
229     required.
230 root 1.23
231     =item setsecret <secret>
232    
233 root 1.51 Sets the shared secret to the given string, which can be anything.
234 root 1.23
235     =item delsecret
236    
237     Removes the shared secret again, which means it is inherited again from
238     it's parent profile, or stays unset.
239    
240     =item gencert
241    
242 elmex 1.32 Generates a self-signed certificate and key, and sets it. This works
243 root 1.23 similarly to a shared secret: when all nodes have it, TLS will be used to
244     authenticate and encrypt all traffic.
245    
246     =item setcert <file>
247    
248     Set a node certificate (and optionally any CA certificates) from the given
249     file. The file must contain the key, followed by the certificate, followed
250     by any CA certificates you want to trust, all in PEM format.
251    
252     See L<AnyEvent::TLS> for some more details - this sets the C<cert> and
253     C<ca_cert> options.
254    
255     =item delcert
256    
257     Removes the certificate(s) again, which means it is inherited again from
258     it's parent profile, or stays unset.
259    
260     =back
261    
262     =head2 CONFIGURATION/SEEDS
263    
264     To discover the network you have to specify some seed addresses, which are
265     basically C<host:port> pairs where you expect some long-running nodes. It
266     does no harm to have a node as its own seed (they will eventually be
267     ignored).
268    
269 root 1.31 =over 4
270    
271 root 1.23 =item setseeds <host:port>,...
272    
273     Sets or replaces the list of seeds, which must be specified as a
274     comma-separated list of C<host:port> pairs. The C<host> can be a hostname,
275 root 1.36 an IP address, or C<*> to signify all local host addresses (which makes
276     little sense for seeds, outside some examples, but a lot of sense for
277     binds).
278 root 1.23
279     An empty list is allowed.
280    
281     Example: use C<doomed> with default port as only seednode.
282    
283     aemp setseeds doomed
284    
285     =item delseeds
286    
287     Removes the seed list again, which means it is inherited again from it's
288     parent profile, or stays unset.
289    
290     =item addseed <host:port>
291    
292     Adds a single seed address.
293    
294     =item delseed <host:port>
295    
296     Deletes the given seed address, if it exists.
297    
298     =back
299    
300     =head2 CONFIGURATION/BINDS
301    
302     To be able to be reached from other nodes, a node must I<bind> itself
303     to some listening socket(s). The list of these can either bs specified
304     manually, or AnyEvent::MP can guess them. Nodes without any binds are
305     possible to some extent.
306    
307     =over 4
308    
309     =item setbinds <host:port>,...
310    
311     Sets the list of bind addresses explicitly - see the F<aemp setseeds>
312 root 1.36 command for the exact syntax. In addition, a value of C<*> for the port,
313     or not specifying a port, means to use a dynamically-assigned port.
314 root 1.23
315 root 1.36 Note that the C<*>, C<*:*> or C<*:port> patterns are very useful here.
316 root 1.23
317 root 1.36 Example: bind on a ephemeral port on all local interfaces.
318 root 1.23
319     aemp setbinds "*"
320    
321     Example: bind on a random port on all local interfaces.
322    
323 root 1.25 aemp setbinds "*:*"
324 root 1.23
325     Example: resolve "doomed.mydomain" and try to bind on port C<4040> of all
326     IP addressess returned.
327    
328 root 1.36 aep setbinds doomed.mydomain:4040
329 root 1.23
330     =item delbinds
331    
332     Removes the bind list again, which means it is inherited again from it's
333     parent profile, or stays unset.
334    
335     =item addbind <host:port>
336    
337     Adds a single bind address.
338    
339     =item delbind <host:port>
340    
341     Deletes the given bind address, if it exists.
342    
343     =back
344    
345     =head2 CONFIGURATION/SERVICES
346    
347     Services are modules (or functions) that are automatically loaded (or
348     executed) when a node starts. They are especially useful when used in
349     conjunction with F<aemp run>, to configure which services a node should
350     run.
351    
352 root 1.47 Despite the daunting name, services really I<are> nothing more than a
353     module name or a function name with arguments. The "service" aspect comes
354     only from the behaviour of the module or function, which is supposed to
355     implement, well, some kind of service for the node, network etc.
356    
357     Instead of writing a standalone program for each different node type in
358     your network, you can simply put your code into a module, and then let the
359     configuration decide which node runs which "services". This also makes it
360     easy to combine multiple different services within the same node.
361    
362 root 1.23 =over 4
363    
364     =item setservices <initfunc>...
365    
366     Sets or replaces the list of services, which must be specified as a
367 root 1.37 comma-separated list or a JSON array.
368    
369     Each string entry in the list is interpreted as either a module name to
370     load (when it ends with C<::>) or a function to call (all other cases).
371    
372     Each entry which is an array itself (you need to use JSON format to
373     specify those) is interpreted as a function name and the arguments to
374     pass.
375 root 1.23
376 root 1.37 The algorithm to find the function is the same as used for C<<
377 root 1.23 L<AnyEvent::MP>::spawn >>.
378    
379 root 1.37 Example: run the globa service (which runs anyway, but this doesn't hurt).
380    
381     aemp setservices AnyEvent::MP::Global::
382    
383     Example: call the mymod::myfun function with arguments 1, 2 and 3.
384    
385     aemp setservices '[["mymod::myfun", 1,2,3]]'
386    
387 root 1.23 =item delservices
388    
389     Removes the service list again, which means it is inherited again from
390     it's parent profile, or stays unset.
391    
392     =item addservice <initfunc>
393    
394     Adds a single service.
395    
396     =item delservice <initfunc>
397    
398     Deletes the given service, if it exists.
399    
400     =back
401    
402     =head2 CONFIGURATION/PROFILE MANAGEMENT
403    
404     All the above configuration functions by default affect the I<global
405     default configuration>, which is basically used to augment every profile
406     and node configuration.
407    
408     =over 4
409    
410     =item profile <name> ...
411    
412     This subcommand makes the following subcommands act only on a specific
413     named profile, instead of on the global default. The profile is created if
414     necessary.
415    
416     Example: create a C<server> profile, give it a random node name, some seed
417     nodes and bind it on an unspecified port on all local interfaces. You
418     should add some services then and run the node...
419    
420 root 1.30 aemp profile server nodeid anon/ seeds doomed,10.0.0.2:5000 binds "*:*"
421 root 1.23
422     =item delprofile <name>
423    
424     Deletes the profile of the given name.
425    
426 root 1.26 =item setparent <name>
427 root 1.24
428     Sets the parent profile to use - values not specified in a profile will be
429     taken from the parent profile (even recursively, with the global default
430     config being the default parent). This is useful to configure profile
431     I<classes> and then to inherit from them for individual nodes.
432    
433     Note that you can specify circular parent chains and even a parent for the
434     global configuration. Neither will do you any good, however.
435    
436     Example: inherit all values not specified in the C<doomed> profile from
437     the C<server> profile.
438    
439 root 1.26 aemp profile doomed setparent server
440 root 1.24
441     =item delparent
442    
443     Removes the parent again from the profile, if any was set, so the profile
444     inherits directly from the global default config again.
445    
446 root 1.23 =item showprofile <name>
447    
448     Shows the values of the given profile, and only those, no inherited
449     values.
450    
451 root 1.25 =item showconfig <name> <key value...>
452 root 1.23
453 root 1.24 Shows the I<effective> config, i.e. the values as used by a node started
454 root 1.25 with the given profile name. Any additional key-value pairs specified
455 root 1.26 augment the configuration, just as with C<configure>.
456 root 1.24
457 root 1.25 If all arguments are omitted, show the global default config.
458 root 1.23
459     =back
460    
461 root 1.47 =head2 LOW-LEVEL TRANSPORT PROTOCOL
462    
463     The low-level transport protocol betwene two nodes also has a number of
464     configurable options, most of which should not be touched unless you know
465     what you are doing.
466    
467     =over 4
468    
469     =item [set|del]monitor_timeout <seconds>
470    
471     Sets the default monitor timeout, that is, when a connection to a node
472     cannot be established within this many seconds, the node is declared
473     unreachable and all monitors will fire.
474    
475     C<30> seconds are usually a good time span for this.
476    
477     =item [set|del]connect_interval <seconds>
478    
479     When a connection cannot be established successfully within this many
480     seconds, try the next transport address (e.g. the next IP address). If
481     your nodes have a lot of transports, you might have to set this to a low
482     value so that they will actually all be tried within the monitor timeout
483     interval.
484    
485     C<2> is usually a good value, unless you live in new zealand.
486    
487     =item [set|del]framing_format [array]
488    
489     Configures the list of framing formats offered to the other side. This is
490     simply a list of formatted read/write types used with L<AnyEvent::Handle>,
491     in order of decreasing preference.
492    
493     Nodes support both C<json> and C<storable> framing formats for data
494     packets out of the box, and usually choose C<json> because it is first in
495     the list.
496    
497     Example: prefer the C<My::Personal::Format> framing format over JSON over
498     Storable.
499    
500     aemp setframing_format '["My::Personal::Format", "json", "storable"]'
501    
502     =item [set|del]auth_offer [array]
503    
504     Configures the list of authentication types that the node offers to the
505     other side as acceptable, in order of decreasing preference. Only auth
506     methods that the node can actually support will be offered.
507    
508     The default is '["tls_md6_64_256", "hmac_md6_64_256"]' and is usually good
509     enough.
510    
511     =item [set|del]auth_accept [array]
512    
513     Configures the list of authentication types that remote nodes can use to
514     authenticate, in order of decreasing preference.
515    
516     The default is '["tls_md6_64_256", "hmac_md6_64_256", "tls_anon",
517     "cleartext"]' and is usually good enough.
518    
519     =item [set|del]autocork <boolean>
520    
521     Sets the default C<autocork> option value for the L<AnyEvent::Handle>
522     object used by transports. By default, autocorking is off.
523    
524     =item [set|del]nodelay <boolean>
525    
526     Sets the default C<nodelay> option value for the L<AnyEvent::Handle>
527     object used by transports. By default, nodelay is on.
528    
529     =back
530    
531 root 1.1 =cut
532    
533     use common::sense;
534    
535 root 1.19 # should come before anything else, so all modules
536     # will be loaded on each restart
537 root 1.22 BEGIN {
538 root 1.35 if (@ARGV == 1 && $ARGV[0] =~ /^\[/) {
539     require JSON::XS;
540     @ARGV = @{ JSON::XS->new->utf8->decode (shift) };
541     } else {
542     for (@ARGV) {
543     if (/^[\[\{\"]/) {
544     require JSON::XS;
545     $_ = JSON::XS->new->utf8->allow_nonref->decode ($_);
546     }
547     }
548     }
549    
550 root 1.8 if ($ARGV[0] eq "run") {
551     shift;
552    
553 root 1.13 # d'oh
554 root 1.22 require AnyEvent::Watchdog;
555 root 1.48 # only now can we load additional modules
556    
557     require AnyEvent;
558 root 1.19
559 root 1.29 require AnyEvent::Watchdog::Util;
560     AnyEvent::Watchdog::Util::autorestart (1);
561     AnyEvent::Watchdog::Util::heartbeat (300);
562 root 1.13
563 root 1.25 require AnyEvent::MP::Kernel;
564 root 1.26 AnyEvent::MP::Kernel::configure (@ARGV);
565 root 1.8
566 root 1.16 AnyEvent::detect () eq "AnyEvent::Impl::EV"
567 root 1.8 ? EV::loop ()
568     : AE::cv ()->recv;
569     }
570 root 1.22 }
571 root 1.8
572 root 1.1 use Carp ();
573    
574 root 1.17 use JSON::XS;
575    
576 root 1.1 use AnyEvent;
577 root 1.4 use AnyEvent::Util;
578    
579 root 1.8 use AnyEvent::MP;
580 root 1.1 use AnyEvent::MP::Config;
581    
582     sub my_run_cmd {
583     my ($cmd) = @_;
584    
585     my $cv = &run_cmd;
586     my $status = $cv->recv;
587    
588     $status
589     and die "@$cmd: command failed with exit status $status.";
590     }
591    
592     sub gen_cert {
593 root 1.2 my_run_cmd [qw(openssl req
594     -new -nodes -x509 -days 3650
595     -newkey rsa:2048 -keyout /dev/fd/3
596     -batch -subj /CN=AnyEvent::MP
597     )],
598 root 1.5 "<", "/dev/null",
599 root 1.1 ">" , \my $cert,
600     "3>", \my $key,
601 root 1.4 "2>", "/dev/null";
602 root 1.1
603     "$cert$key"
604     }
605    
606 root 1.25 sub init {
607 root 1.26 configure profile => "aemp", nodeid => "anon/";
608 root 1.25 }
609    
610 root 1.10 our $cfg = AnyEvent::MP::Config::config;
611 root 1.8 our $profile = $cfg;
612 root 1.1
613 root 1.11 sub trace {
614     my ($node) = @_;
615     my $cv = AE::cv;
616     my %seen;
617    
618 root 1.28 my $to = AE::timer 15, 0, sub { exit 1 };
619 root 1.11
620 root 1.25 init;
621 root 1.11
622     my $reply = port {
623 root 1.12 my ($node, @neigh) = @_;
624 root 1.11
625 root 1.12 @neigh = grep $_ ne $NODE, @neigh;
626    
627     print +(join " ", $node, @neigh), "\n";
628    
629     for (@neigh) {
630 root 1.11 unless ($seen{$_}++) {
631     $cv->begin;
632     snd $_, up_nodes => $SELF => $_;
633     }
634     }
635    
636     $cv->end;
637     };
638    
639     $cv->begin;
640     snd $reply, seed => $node;
641    
642     $cv->recv;
643     }
644    
645 root 1.42 sub shell {
646     init;
647    
648     my $node = shift @ARGV || $NODE;
649     $| = 1;
650    
651     print <<EOF;
652     Entering interactive shell - no commandline editing of course (use rlfe etc.).
653    
654 root 1.43 \= display a list of nodes
655     \=name switch to another node
656 root 1.51 package P switch to package P when evaluating
657     \$ECHO contains the name of a port that echos everything sent to it
658 root 1.42
659     EOF
660 root 1.52 my $pkg = "AnyEvent::MP::Kernel";
661 root 1.42 my $cv = AE::cv;
662 root 1.51 my $echo = port {
663 root 1.52 print "\n ECHO<$AnyEvent::MP::Kernel::SRCNODE->{id}> ", JSON::XS::encode_json \@_, "\n$node $pkg> ";
664 root 1.51 };
665 root 1.52 print "$node $pkg> ";
666 root 1.42 my $t = AE::io *STDIN, 0, sub {
667     chomp (my $line = <STDIN>);
668    
669     if ($line =~ s/^=//) {
670     if (length $line) {
671     $node = $line;
672     } else {
673     print +(join " ", AnyEvent::MP::Kernel::up_nodes), "\n";
674     }
675 root 1.51 } elsif ($line =~ /^\s*package\s+(\S+)\s*;?\s*$/) {
676 root 1.52 $pkg = $1;
677 root 1.51 } elsif ($line =~ /\S/) {
678 root 1.42 my $time = AE::time;
679 root 1.52 AnyEvent::MP::Kernel::eval_on
680     $node,
681     "package $pkg; my \$ECHO = '$echo'; $line",
682     port {
683     kil $SELF;
684    
685     my ($err, @res) = @_;
686    
687     $time = AE::time - $time;
688    
689     print "\n $node: $line\n";
690     if (length $err) {
691     print " $err @res";
692     } else {
693     print " ", JSON::XS::encode_json \@res;
694     }
695     printf "\n %0.3fs\n", $time;
696     print "$node $pkg> ";
697 root 1.42 }
698 root 1.52 ;
699 root 1.42 }
700    
701 root 1.52 print "$node $pkg> ";
702 root 1.42 };
703     $cv->recv;
704     }
705    
706 root 1.37 sub node_eval {
707     my ($node, $expr) = @_;
708    
709     init;
710    
711     my $cv = AE::cv;
712     my $to = AE::timer 5, 0, sub { exit 1 };
713     AnyEvent::MP::Kernel::eval_on $node, $expr, port { &$cv };
714     mon $node, $cv;
715    
716     my ($err, @res) = $cv->recv;
717    
718 root 1.39 die "$err @res" if length $err;
719 root 1.37
720     print +(substr JSON::XS->new->encode (\@res), 1, -1), "\n";
721     }
722    
723 root 1.10 sub docmd;
724    
725 root 1.1 our %CMD = (
726     snd => sub {
727 root 1.17 my $port = shift @ARGV;
728 root 1.25 init;
729 root 1.1
730 root 1.7 snd $port, @ARGV; @ARGV = ();
731 root 1.1
732     my $cv = AE::cv;
733 root 1.28 my $to = AE::timer 5, 0, sub { exit 1 };
734 root 1.1 mon $port, $cv;
735 root 1.19 my $reply = port sub { &$cv };
736     snd node_of $port, snd => $reply, "message sent successfully";
737 root 1.1
738     print join " ", $cv->recv, "\n";
739     },
740    
741 root 1.41 cal => sub {
742 root 1.17 my $port = shift @ARGV;
743 root 1.25 init;
744 root 1.7
745     my $cv = AE::cv;
746 root 1.41 cal $port, @ARGV, sub { &$cv }; @ARGV = ();
747 root 1.7
748 root 1.23 print +(substr JSON::XS->new->encode ([$cv->recv]), 1, -1), "\n";
749 root 1.7 },
750    
751 root 1.1 mon => sub {
752 root 1.17 my $port = shift @ARGV;
753 root 1.25 init;
754 root 1.1
755     mon $port, my $cv = AE::cv;
756     print join " ", $cv->recv, "\n";
757     },
758    
759 root 1.19 eval => sub {
760     my $node = node_of shift @ARGV;
761     my $expr = join " ", @ARGV; @ARGV = ();
762 root 1.37 node_eval $node, $expr;
763 root 1.19 },
764    
765 root 1.42 shell => \&shell,
766    
767 root 1.11 trace => sub {
768     @ARGV >= 1
769 root 1.17 or die "node id missing\n";
770 root 1.11
771 root 1.17 trace shift @ARGV;
772 root 1.11 },
773 root 1.37 restart => sub {
774     my $node = node_of shift @ARGV;
775 root 1.44 node_eval $node, 'my $w; $w = AE::idle sub { '
776     . 'undef $w; '
777     . 'use AnyEvent::Watchdog::Util ();'
778     . 'AnyEvent::Watchdog::Util::restart'
779     . '}; ()';
780 root 1.37 },
781 root 1.11
782 root 1.17 setnodeid => sub {
783 root 1.8 @ARGV >= 1
784     or die "shared secret missing\n";
785    
786 root 1.17 $profile->{nodeid} = shift @ARGV;
787 root 1.8 ++$cfg->{dirty};
788     },
789 root 1.17 delnodeid => sub {
790     delete $profile->{nodeid};
791 root 1.8 ++$cfg->{dirty};
792     },
793    
794 root 1.1 setsecret => sub {
795 root 1.8 @ARGV >= 1
796 root 1.1 or die "shared secret missing\n";
797    
798 root 1.8 $profile->{secret} = shift @ARGV;
799 root 1.1 ++$cfg->{dirty};
800     },
801     gensecret => sub {
802 root 1.51 $profile->{secret} = AnyEvent::MP::Kernel::nonce62 180; # ~1071 bits
803 root 1.1 ++$cfg->{dirty};
804     },
805 root 1.17 delsecret => sub {
806 root 1.8 delete $profile->{secret};
807 root 1.1 ++$cfg->{dirty};
808     },
809    
810     setcert => sub {
811 root 1.8 @ARGV >= 1
812 root 1.1 or die "key+certificate pem filename missing\n";
813    
814 elmex 1.45 my $certfile = shift @ARGV;
815    
816     open my $fh, "<", $certfile
817     or die "$certfile: $!";
818 root 1.1
819     local $/;
820 root 1.8 $profile->{cert} = <$fh>;
821 root 1.1 ++$cfg->{dirty};
822     },
823     gencert => sub {
824 root 1.8 $profile->{cert} = gen_cert;
825 root 1.1 ++$cfg->{dirty};
826     },
827 root 1.17 delcert => sub {
828 root 1.8 delete $profile->{cert};
829 root 1.1 ++$cfg->{dirty};
830     },
831 root 1.6
832 root 1.17 setbinds => sub {
833 root 1.19 @ARGV >= 1
834     or die "bind addresses missing\n";
835 root 1.38 my $list = shift @ARGV;
836     $profile->{binds} = ref $list ? $list : [split /,/, $list];
837 root 1.17 ++$cfg->{dirty};
838     },
839     delbinds => sub {
840     delete $profile->{binds};
841     ++$cfg->{dirty};
842     },
843     addbind => sub {
844     @ARGV >= 1
845     or die "bind address missing\n";
846     my $bind = shift @ARGV;
847    
848     @{ $profile->{binds} } = grep $_ ne $bind, @{ $profile->{binds} };
849     push @{ $profile->{binds} }, $bind;
850     ++$cfg->{dirty};
851     },
852     delbind => sub {
853     @ARGV >= 1
854     or die "bind address missing\n";
855     my $bind = shift @ARGV;
856    
857     @{ $profile->{binds} } = grep $_ ne $bind, @{ $profile->{binds} };
858     ++$cfg->{dirty};
859     },
860    
861 root 1.6 setseeds => sub {
862 root 1.19 @ARGV >= 1
863     or die "seed addresses missing\n";
864 root 1.38 my $list = shift @ARGV;
865     $profile->{seeds} = ref $list ? $list : [split /,/, $list];
866 root 1.6 ++$cfg->{dirty};
867     },
868 root 1.17 delseeds => sub {
869     delete $profile->{seeds};
870     ++$cfg->{dirty};
871     },
872 root 1.6 addseed => sub {
873 root 1.10 @ARGV >= 1
874 root 1.17 or die "seed address missing\n";
875 root 1.6 my $seed = shift @ARGV;
876 root 1.10
877 root 1.8 @{ $profile->{seeds} } = grep $_ ne $seed, @{ $profile->{seeds} };
878     push @{ $profile->{seeds} }, $seed;
879     ++$cfg->{dirty};
880     },
881     delseed => sub {
882 root 1.10 @ARGV >= 1
883 root 1.17 or die "seed address missing\n";
884 root 1.8 my $seed = shift @ARGV;
885 root 1.10
886 root 1.8 @{ $profile->{seeds} } = grep $_ ne $seed, @{ $profile->{seeds} };
887     ++$cfg->{dirty};
888     },
889    
890     setservices => sub {
891 root 1.19 @ARGV >= 1
892     or die "service specifications missing\n";
893 root 1.38 my $list = shift @ARGV;
894     $profile->{services} = ref $list ? $list : [split /,/, $list];
895 root 1.6 ++$cfg->{dirty};
896     },
897 root 1.17 delservices => sub {
898     delete $profile->{services};
899     ++$cfg->{dirty};
900     },
901 root 1.9 addservice => sub {
902 root 1.10 @ARGV >= 1
903     or die "service specification missing\n";
904 root 1.8 my $service = shift @ARGV;
905     push @{ $profile->{services} }, $service;
906     ++$cfg->{dirty};
907     },
908 root 1.9 delservice => sub {
909 root 1.10 @ARGV >= 1
910     or die "service specification missing\n";
911 root 1.8 my $service = shift @ARGV;
912     for (0 .. $#{ $profile->{services} }) {
913     next unless $profile->{services}[$_] eq $service;
914     splice @{ $profile->{services} }, $_, 1;
915     last;
916     }
917 root 1.6 ++$cfg->{dirty};
918     },
919 root 1.10
920     profile => sub {
921 root 1.19 @ARGV >= 1
922     or die "profile name is missing\n";
923 root 1.10 my $name = shift @ARGV;
924    
925     $profile = $cfg->{profile}{$name} ||= {};
926 root 1.14 ++$cfg->{dirty};
927 root 1.10 },
928     delprofile => sub {
929     @ARGV >= 1
930     or die "profile name is missing\n";
931     my $name = shift @ARGV;
932    
933     delete $cfg->{profile}{$name};
934 root 1.14 ++$cfg->{dirty};
935 root 1.10 },
936 root 1.26 setparent => sub {
937 root 1.24 @ARGV >= 1
938     or die "profile name is missing\n";
939    
940     $profile->{parent} = shift @ARGV;
941     ++$cfg->{dirty};
942     },
943     delparent => sub {
944     delete $profile->{parent};
945     ++$cfg->{dirty};
946     },
947 root 1.17 showprofile => sub {
948     @ARGV >= 1
949     or die "profile name is missing\n";
950     my $name = shift @ARGV;
951    
952     print JSON::XS->new->pretty->encode ($cfg->{profile}{$name} || {});
953     },
954     showconfig => sub {
955     my $name = @ARGV ? shift @ARGV : AnyEvent::MP::Kernel::_nodename;
956    
957 root 1.25 my $profile = AnyEvent::MP::Config::find_profile $name, @ARGV;
958     @ARGV = ();
959 root 1.24
960     # make it look nicer:
961     delete $profile->{profile};
962     delete $profile->{parent};
963    
964     print JSON::XS->new->pretty->encode ($profile);
965 root 1.17 },
966 root 1.25
967     # undocumented
968     _resolve => sub {
969     print +(join ",", (AnyEvent::MP::Kernel::_resolve shift @ARGV)->recv), "\n";
970     },
971 root 1.1 );
972    
973 root 1.47 for my $attr (qw(
974     monitor_timeout connect_interval framing_format auth_offer
975     auth_accept autocork nodelay
976     )) {
977     $CMD{"set$attr"} = sub {
978     @ARGV >= 1
979     or die "$attr value is missing\n";
980    
981     $profile->{$attr} = shift @ARGV;
982     ++$cfg->{dirty};
983     };
984     $CMD{"del$attr"} = sub {
985     delete $profile->{$attr};
986     ++$cfg->{dirty};
987     };
988     }
989    
990 root 1.27 for (keys %CMD) {
991     $CMD{$1} = $CMD{$_} if /^set(.*)$/;
992     }
993    
994 root 1.1 sub docmd {
995     my $cmd = shift @ARGV;
996    
997     $CMD{$cmd}
998 root 1.23 or die "$cmd: no such aemp command (try perldoc aemp, or man aemp)";
999 root 1.1
1000     $CMD{$cmd}();
1001     }
1002    
1003     @ARGV
1004 root 1.23 or die "Usage: aemp subcommand ... (try perldoc aemp, or man aemp)\n";
1005 root 1.1
1006 root 1.19 docmd while @ARGV;
1007 root 1.1
1008