ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MP/bin/aemp
Revision: 1.47
Committed: Wed Dec 30 13:37:53 2009 UTC (14 years, 5 months ago) by root
Branch: MAIN
CVS Tags: rel-1_26, rel-1_27
Changes since 1.46: +108 -4 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     loser systems, or wherever C<$ENV{PERL_ANYEVENT_MPRC}> points to). Feel
92     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     Set the node ID to the given string.
215    
216     =item delnodeid
217    
218     Removes the node ID again, which means it is inherited again from it's
219     parent profile, or stays unset.
220    
221     =item gensecret
222    
223     Generates a random shared secret and sets it. The shared secret is used to
224     authenticate nodes to each other when TLS is not required.
225    
226     =item setsecret <secret>
227    
228     Sets the shared secret tot he given string, which can be anything.
229    
230     =item delsecret
231    
232     Removes the shared secret again, which means it is inherited again from
233     it's parent profile, or stays unset.
234    
235     =item gencert
236    
237 elmex 1.32 Generates a self-signed certificate and key, and sets it. This works
238 root 1.23 similarly to a shared secret: when all nodes have it, TLS will be used to
239     authenticate and encrypt all traffic.
240    
241     =item setcert <file>
242    
243     Set a node certificate (and optionally any CA certificates) from the given
244     file. The file must contain the key, followed by the certificate, followed
245     by any CA certificates you want to trust, all in PEM format.
246    
247     See L<AnyEvent::TLS> for some more details - this sets the C<cert> and
248     C<ca_cert> options.
249    
250     =item delcert
251    
252     Removes the certificate(s) again, which means it is inherited again from
253     it's parent profile, or stays unset.
254    
255     =back
256    
257     =head2 CONFIGURATION/SEEDS
258    
259     To discover the network you have to specify some seed addresses, which are
260     basically C<host:port> pairs where you expect some long-running nodes. It
261     does no harm to have a node as its own seed (they will eventually be
262     ignored).
263    
264 root 1.31 =over 4
265    
266 root 1.23 =item setseeds <host:port>,...
267    
268     Sets or replaces the list of seeds, which must be specified as a
269     comma-separated list of C<host:port> pairs. The C<host> can be a hostname,
270 root 1.36 an IP address, or C<*> to signify all local host addresses (which makes
271     little sense for seeds, outside some examples, but a lot of sense for
272     binds).
273 root 1.23
274     An empty list is allowed.
275    
276     Example: use C<doomed> with default port as only seednode.
277    
278     aemp setseeds doomed
279    
280     =item delseeds
281    
282     Removes the seed list again, which means it is inherited again from it's
283     parent profile, or stays unset.
284    
285     =item addseed <host:port>
286    
287     Adds a single seed address.
288    
289     =item delseed <host:port>
290    
291     Deletes the given seed address, if it exists.
292    
293     =back
294    
295     =head2 CONFIGURATION/BINDS
296    
297     To be able to be reached from other nodes, a node must I<bind> itself
298     to some listening socket(s). The list of these can either bs specified
299     manually, or AnyEvent::MP can guess them. Nodes without any binds are
300     possible to some extent.
301    
302     =over 4
303    
304     =item setbinds <host:port>,...
305    
306     Sets the list of bind addresses explicitly - see the F<aemp setseeds>
307 root 1.36 command for the exact syntax. In addition, a value of C<*> for the port,
308     or not specifying a port, means to use a dynamically-assigned port.
309 root 1.23
310 root 1.36 Note that the C<*>, C<*:*> or C<*:port> patterns are very useful here.
311 root 1.23
312 root 1.36 Example: bind on a ephemeral port on all local interfaces.
313 root 1.23
314     aemp setbinds "*"
315    
316     Example: bind on a random port on all local interfaces.
317    
318 root 1.25 aemp setbinds "*:*"
319 root 1.23
320     Example: resolve "doomed.mydomain" and try to bind on port C<4040> of all
321     IP addressess returned.
322    
323 root 1.36 aep setbinds doomed.mydomain:4040
324 root 1.23
325     =item delbinds
326    
327     Removes the bind list again, which means it is inherited again from it's
328     parent profile, or stays unset.
329    
330     =item addbind <host:port>
331    
332     Adds a single bind address.
333    
334     =item delbind <host:port>
335    
336     Deletes the given bind address, if it exists.
337    
338     =back
339    
340     =head2 CONFIGURATION/SERVICES
341    
342     Services are modules (or functions) that are automatically loaded (or
343     executed) when a node starts. They are especially useful when used in
344     conjunction with F<aemp run>, to configure which services a node should
345     run.
346    
347 root 1.47 Despite the daunting name, services really I<are> nothing more than a
348     module name or a function name with arguments. The "service" aspect comes
349     only from the behaviour of the module or function, which is supposed to
350     implement, well, some kind of service for the node, network etc.
351    
352     Instead of writing a standalone program for each different node type in
353     your network, you can simply put your code into a module, and then let the
354     configuration decide which node runs which "services". This also makes it
355     easy to combine multiple different services within the same node.
356    
357 root 1.23 =over 4
358    
359     =item setservices <initfunc>...
360    
361     Sets or replaces the list of services, which must be specified as a
362 root 1.37 comma-separated list or a JSON array.
363    
364     Each string entry in the list is interpreted as either a module name to
365     load (when it ends with C<::>) or a function to call (all other cases).
366    
367     Each entry which is an array itself (you need to use JSON format to
368     specify those) is interpreted as a function name and the arguments to
369     pass.
370 root 1.23
371 root 1.37 The algorithm to find the function is the same as used for C<<
372 root 1.23 L<AnyEvent::MP>::spawn >>.
373    
374 root 1.37 Example: run the globa service (which runs anyway, but this doesn't hurt).
375    
376     aemp setservices AnyEvent::MP::Global::
377    
378     Example: call the mymod::myfun function with arguments 1, 2 and 3.
379    
380     aemp setservices '[["mymod::myfun", 1,2,3]]'
381    
382 root 1.23 =item delservices
383    
384     Removes the service list again, which means it is inherited again from
385     it's parent profile, or stays unset.
386    
387     =item addservice <initfunc>
388    
389     Adds a single service.
390    
391     =item delservice <initfunc>
392    
393     Deletes the given service, if it exists.
394    
395     =back
396    
397     =head2 CONFIGURATION/PROFILE MANAGEMENT
398    
399     All the above configuration functions by default affect the I<global
400     default configuration>, which is basically used to augment every profile
401     and node configuration.
402    
403     =over 4
404    
405     =item profile <name> ...
406    
407     This subcommand makes the following subcommands act only on a specific
408     named profile, instead of on the global default. The profile is created if
409     necessary.
410    
411     Example: create a C<server> profile, give it a random node name, some seed
412     nodes and bind it on an unspecified port on all local interfaces. You
413     should add some services then and run the node...
414    
415 root 1.30 aemp profile server nodeid anon/ seeds doomed,10.0.0.2:5000 binds "*:*"
416 root 1.23
417     =item delprofile <name>
418    
419     Deletes the profile of the given name.
420    
421 root 1.26 =item setparent <name>
422 root 1.24
423     Sets the parent profile to use - values not specified in a profile will be
424     taken from the parent profile (even recursively, with the global default
425     config being the default parent). This is useful to configure profile
426     I<classes> and then to inherit from them for individual nodes.
427    
428     Note that you can specify circular parent chains and even a parent for the
429     global configuration. Neither will do you any good, however.
430    
431     Example: inherit all values not specified in the C<doomed> profile from
432     the C<server> profile.
433    
434 root 1.26 aemp profile doomed setparent server
435 root 1.24
436     =item delparent
437    
438     Removes the parent again from the profile, if any was set, so the profile
439     inherits directly from the global default config again.
440    
441 root 1.23 =item showprofile <name>
442    
443     Shows the values of the given profile, and only those, no inherited
444     values.
445    
446 root 1.25 =item showconfig <name> <key value...>
447 root 1.23
448 root 1.24 Shows the I<effective> config, i.e. the values as used by a node started
449 root 1.25 with the given profile name. Any additional key-value pairs specified
450 root 1.26 augment the configuration, just as with C<configure>.
451 root 1.24
452 root 1.25 If all arguments are omitted, show the global default config.
453 root 1.23
454     =back
455    
456 root 1.47 =head2 LOW-LEVEL TRANSPORT PROTOCOL
457    
458     The low-level transport protocol betwene two nodes also has a number of
459     configurable options, most of which should not be touched unless you know
460     what you are doing.
461    
462     =over 4
463    
464     =item [set|del]monitor_timeout <seconds>
465    
466     Sets the default monitor timeout, that is, when a connection to a node
467     cannot be established within this many seconds, the node is declared
468     unreachable and all monitors will fire.
469    
470     C<30> seconds are usually a good time span for this.
471    
472     =item [set|del]connect_interval <seconds>
473    
474     When a connection cannot be established successfully within this many
475     seconds, try the next transport address (e.g. the next IP address). If
476     your nodes have a lot of transports, you might have to set this to a low
477     value so that they will actually all be tried within the monitor timeout
478     interval.
479    
480     C<2> is usually a good value, unless you live in new zealand.
481    
482     =item [set|del]framing_format [array]
483    
484     Configures the list of framing formats offered to the other side. This is
485     simply a list of formatted read/write types used with L<AnyEvent::Handle>,
486     in order of decreasing preference.
487    
488     Nodes support both C<json> and C<storable> framing formats for data
489     packets out of the box, and usually choose C<json> because it is first in
490     the list.
491    
492     Example: prefer the C<My::Personal::Format> framing format over JSON over
493     Storable.
494    
495     aemp setframing_format '["My::Personal::Format", "json", "storable"]'
496    
497     =item [set|del]auth_offer [array]
498    
499     Configures the list of authentication types that the node offers to the
500     other side as acceptable, in order of decreasing preference. Only auth
501     methods that the node can actually support will be offered.
502    
503     The default is '["tls_md6_64_256", "hmac_md6_64_256"]' and is usually good
504     enough.
505    
506     =item [set|del]auth_accept [array]
507    
508     Configures the list of authentication types that remote nodes can use to
509     authenticate, in order of decreasing preference.
510    
511     The default is '["tls_md6_64_256", "hmac_md6_64_256", "tls_anon",
512     "cleartext"]' and is usually good enough.
513    
514     =item [set|del]autocork <boolean>
515    
516     Sets the default C<autocork> option value for the L<AnyEvent::Handle>
517     object used by transports. By default, autocorking is off.
518    
519     =item [set|del]nodelay <boolean>
520    
521     Sets the default C<nodelay> option value for the L<AnyEvent::Handle>
522     object used by transports. By default, nodelay is on.
523    
524     =back
525    
526 root 1.1 =cut
527    
528     use common::sense;
529    
530 root 1.19 # should come before anything else, so all modules
531     # will be loaded on each restart
532 root 1.22 BEGIN {
533 root 1.35 if (@ARGV == 1 && $ARGV[0] =~ /^\[/) {
534     require JSON::XS;
535     @ARGV = @{ JSON::XS->new->utf8->decode (shift) };
536     } else {
537     for (@ARGV) {
538     if (/^[\[\{\"]/) {
539     require JSON::XS;
540     $_ = JSON::XS->new->utf8->allow_nonref->decode ($_);
541     }
542     }
543     }
544    
545 root 1.8 if ($ARGV[0] eq "run") {
546     shift;
547    
548 root 1.13 # d'oh
549 root 1.22 require AnyEvent::Watchdog;
550 root 1.19 # now we can load extra modules
551    
552 root 1.29 require AnyEvent::Watchdog::Util;
553     AnyEvent::Watchdog::Util::autorestart (1);
554     AnyEvent::Watchdog::Util::heartbeat (300);
555 root 1.13
556 root 1.8 require AnyEvent;
557 root 1.25 require AnyEvent::MP::Kernel;
558 root 1.26 AnyEvent::MP::Kernel::configure (@ARGV);
559 root 1.8
560 root 1.16 AnyEvent::detect () eq "AnyEvent::Impl::EV"
561 root 1.8 ? EV::loop ()
562     : AE::cv ()->recv;
563     }
564 root 1.22 }
565 root 1.8
566 root 1.1 use Carp ();
567    
568 root 1.17 use JSON::XS;
569    
570 root 1.1 use AnyEvent;
571 root 1.4 use AnyEvent::Util;
572    
573 root 1.8 use AnyEvent::MP;
574 root 1.1 use AnyEvent::MP::Config;
575    
576     sub my_run_cmd {
577     my ($cmd) = @_;
578    
579     my $cv = &run_cmd;
580     my $status = $cv->recv;
581    
582     $status
583     and die "@$cmd: command failed with exit status $status.";
584     }
585    
586     sub gen_cert {
587 root 1.2 my_run_cmd [qw(openssl req
588     -new -nodes -x509 -days 3650
589     -newkey rsa:2048 -keyout /dev/fd/3
590     -batch -subj /CN=AnyEvent::MP
591     )],
592 root 1.5 "<", "/dev/null",
593 root 1.1 ">" , \my $cert,
594     "3>", \my $key,
595 root 1.4 "2>", "/dev/null";
596 root 1.1
597     "$cert$key"
598     }
599    
600 root 1.25 sub init {
601 root 1.26 configure profile => "aemp", nodeid => "anon/";
602 root 1.25 }
603    
604 root 1.10 our $cfg = AnyEvent::MP::Config::config;
605 root 1.8 our $profile = $cfg;
606 root 1.1
607 root 1.11 sub trace {
608     my ($node) = @_;
609     my $cv = AE::cv;
610     my %seen;
611    
612 root 1.28 my $to = AE::timer 15, 0, sub { exit 1 };
613 root 1.11
614 root 1.25 init;
615 root 1.11
616     my $reply = port {
617 root 1.12 my ($node, @neigh) = @_;
618 root 1.11
619 root 1.12 @neigh = grep $_ ne $NODE, @neigh;
620    
621     print +(join " ", $node, @neigh), "\n";
622    
623     for (@neigh) {
624 root 1.11 unless ($seen{$_}++) {
625     $cv->begin;
626     snd $_, up_nodes => $SELF => $_;
627     }
628     }
629    
630     $cv->end;
631     };
632    
633     $cv->begin;
634     snd $reply, seed => $node;
635    
636     $cv->recv;
637     }
638    
639 root 1.42 sub shell {
640     init;
641    
642     my $node = shift @ARGV || $NODE;
643     $| = 1;
644    
645     print <<EOF;
646     Entering interactive shell - no commandline editing of course (use rlfe etc.).
647    
648 root 1.43 \= display a list of nodes
649     \=name switch to another node
650 root 1.42
651     EOF
652     print "$node> ";
653     my $cv = AE::cv;
654     my $t = AE::io *STDIN, 0, sub {
655     chomp (my $line = <STDIN>);
656    
657     if ($line =~ s/^=//) {
658     if (length $line) {
659     $node = $line;
660     } else {
661     print +(join " ", AnyEvent::MP::Kernel::up_nodes), "\n";
662     }
663     } else {
664     my $time = AE::time;
665     AnyEvent::MP::Kernel::eval_on $node, $line, port {
666     my ($err, @res) = @_;
667    
668     $time = AE::time - $time;
669    
670     print "\n $node: $line\n";
671     if (length $err) {
672     print " $err @res";
673     } else {
674     print " ", JSON::XS::encode_json \@_;
675     }
676     printf "\n %0.3fs\n", $time;
677     print "$node> ";
678     };
679     }
680    
681     print "$node> ";
682     };
683     $cv->recv;
684     }
685    
686 root 1.37 sub node_eval {
687     my ($node, $expr) = @_;
688    
689     init;
690    
691     my $cv = AE::cv;
692     my $to = AE::timer 5, 0, sub { exit 1 };
693     AnyEvent::MP::Kernel::eval_on $node, $expr, port { &$cv };
694     mon $node, $cv;
695    
696     my ($err, @res) = $cv->recv;
697    
698 root 1.39 die "$err @res" if length $err;
699 root 1.37
700     print +(substr JSON::XS->new->encode (\@res), 1, -1), "\n";
701     }
702    
703 root 1.10 sub docmd;
704    
705 root 1.1 our %CMD = (
706     snd => sub {
707 root 1.17 my $port = shift @ARGV;
708 root 1.25 init;
709 root 1.1
710 root 1.7 snd $port, @ARGV; @ARGV = ();
711 root 1.1
712     my $cv = AE::cv;
713 root 1.28 my $to = AE::timer 5, 0, sub { exit 1 };
714 root 1.1 mon $port, $cv;
715 root 1.19 my $reply = port sub { &$cv };
716     snd node_of $port, snd => $reply, "message sent successfully";
717 root 1.1
718     print join " ", $cv->recv, "\n";
719     },
720    
721 root 1.41 cal => sub {
722 root 1.17 my $port = shift @ARGV;
723 root 1.25 init;
724 root 1.7
725     my $cv = AE::cv;
726 root 1.41 cal $port, @ARGV, sub { &$cv }; @ARGV = ();
727 root 1.7
728 root 1.23 print +(substr JSON::XS->new->encode ([$cv->recv]), 1, -1), "\n";
729 root 1.7 },
730    
731 root 1.1 mon => sub {
732 root 1.17 my $port = shift @ARGV;
733 root 1.25 init;
734 root 1.1
735     mon $port, my $cv = AE::cv;
736     print join " ", $cv->recv, "\n";
737     },
738    
739 root 1.19 eval => sub {
740     my $node = node_of shift @ARGV;
741     my $expr = join " ", @ARGV; @ARGV = ();
742 root 1.37 node_eval $node, $expr;
743 root 1.19 },
744    
745 root 1.42 shell => \&shell,
746    
747 root 1.11 trace => sub {
748     @ARGV >= 1
749 root 1.17 or die "node id missing\n";
750 root 1.11
751 root 1.17 trace shift @ARGV;
752 root 1.11 },
753 root 1.37 restart => sub {
754     my $node = node_of shift @ARGV;
755 root 1.44 node_eval $node, 'my $w; $w = AE::idle sub { '
756     . 'undef $w; '
757     . 'use AnyEvent::Watchdog::Util ();'
758     . 'AnyEvent::Watchdog::Util::restart'
759     . '}; ()';
760 root 1.37 },
761 root 1.11
762 root 1.17 setnodeid => sub {
763 root 1.8 @ARGV >= 1
764     or die "shared secret missing\n";
765    
766 root 1.17 $profile->{nodeid} = shift @ARGV;
767 root 1.8 ++$cfg->{dirty};
768     },
769 root 1.17 delnodeid => sub {
770     delete $profile->{nodeid};
771 root 1.8 ++$cfg->{dirty};
772     },
773    
774 root 1.1 setsecret => sub {
775 root 1.8 @ARGV >= 1
776 root 1.1 or die "shared secret missing\n";
777    
778 root 1.8 $profile->{secret} = shift @ARGV;
779 root 1.1 ++$cfg->{dirty};
780     },
781     gensecret => sub {
782 root 1.18 $profile->{secret} = AnyEvent::MP::Kernel::alnumbits AnyEvent::MP::Kernel::nonce 64;
783 root 1.1 ++$cfg->{dirty};
784     },
785 root 1.17 delsecret => sub {
786 root 1.8 delete $profile->{secret};
787 root 1.1 ++$cfg->{dirty};
788     },
789    
790     setcert => sub {
791 root 1.8 @ARGV >= 1
792 root 1.1 or die "key+certificate pem filename missing\n";
793    
794 elmex 1.45 my $certfile = shift @ARGV;
795    
796     open my $fh, "<", $certfile
797     or die "$certfile: $!";
798 root 1.1
799     local $/;
800 root 1.8 $profile->{cert} = <$fh>;
801 root 1.1 ++$cfg->{dirty};
802     },
803     gencert => sub {
804 root 1.8 $profile->{cert} = gen_cert;
805 root 1.1 ++$cfg->{dirty};
806     },
807 root 1.17 delcert => sub {
808 root 1.8 delete $profile->{cert};
809 root 1.1 ++$cfg->{dirty};
810     },
811 root 1.6
812 root 1.17 setbinds => sub {
813 root 1.19 @ARGV >= 1
814     or die "bind addresses missing\n";
815 root 1.38 my $list = shift @ARGV;
816     $profile->{binds} = ref $list ? $list : [split /,/, $list];
817 root 1.17 ++$cfg->{dirty};
818     },
819     delbinds => sub {
820     delete $profile->{binds};
821     ++$cfg->{dirty};
822     },
823     addbind => sub {
824     @ARGV >= 1
825     or die "bind address missing\n";
826     my $bind = shift @ARGV;
827    
828     @{ $profile->{binds} } = grep $_ ne $bind, @{ $profile->{binds} };
829     push @{ $profile->{binds} }, $bind;
830     ++$cfg->{dirty};
831     },
832     delbind => sub {
833     @ARGV >= 1
834     or die "bind address missing\n";
835     my $bind = shift @ARGV;
836    
837     @{ $profile->{binds} } = grep $_ ne $bind, @{ $profile->{binds} };
838     ++$cfg->{dirty};
839     },
840    
841 root 1.6 setseeds => sub {
842 root 1.19 @ARGV >= 1
843     or die "seed addresses missing\n";
844 root 1.38 my $list = shift @ARGV;
845     $profile->{seeds} = ref $list ? $list : [split /,/, $list];
846 root 1.6 ++$cfg->{dirty};
847     },
848 root 1.17 delseeds => sub {
849     delete $profile->{seeds};
850     ++$cfg->{dirty};
851     },
852 root 1.6 addseed => sub {
853 root 1.10 @ARGV >= 1
854 root 1.17 or die "seed address missing\n";
855 root 1.6 my $seed = shift @ARGV;
856 root 1.10
857 root 1.8 @{ $profile->{seeds} } = grep $_ ne $seed, @{ $profile->{seeds} };
858     push @{ $profile->{seeds} }, $seed;
859     ++$cfg->{dirty};
860     },
861     delseed => sub {
862 root 1.10 @ARGV >= 1
863 root 1.17 or die "seed address missing\n";
864 root 1.8 my $seed = shift @ARGV;
865 root 1.10
866 root 1.8 @{ $profile->{seeds} } = grep $_ ne $seed, @{ $profile->{seeds} };
867     ++$cfg->{dirty};
868     },
869    
870     setservices => sub {
871 root 1.19 @ARGV >= 1
872     or die "service specifications missing\n";
873 root 1.38 my $list = shift @ARGV;
874     $profile->{services} = ref $list ? $list : [split /,/, $list];
875 root 1.6 ++$cfg->{dirty};
876     },
877 root 1.17 delservices => sub {
878     delete $profile->{services};
879     ++$cfg->{dirty};
880     },
881 root 1.9 addservice => sub {
882 root 1.10 @ARGV >= 1
883     or die "service specification missing\n";
884 root 1.8 my $service = shift @ARGV;
885     push @{ $profile->{services} }, $service;
886     ++$cfg->{dirty};
887     },
888 root 1.9 delservice => sub {
889 root 1.10 @ARGV >= 1
890     or die "service specification missing\n";
891 root 1.8 my $service = shift @ARGV;
892     for (0 .. $#{ $profile->{services} }) {
893     next unless $profile->{services}[$_] eq $service;
894     splice @{ $profile->{services} }, $_, 1;
895     last;
896     }
897 root 1.6 ++$cfg->{dirty};
898     },
899 root 1.10
900     profile => sub {
901 root 1.19 @ARGV >= 1
902     or die "profile name is missing\n";
903 root 1.10 my $name = shift @ARGV;
904    
905     $profile = $cfg->{profile}{$name} ||= {};
906 root 1.14 ++$cfg->{dirty};
907 root 1.10 },
908     delprofile => sub {
909     @ARGV >= 1
910     or die "profile name is missing\n";
911     my $name = shift @ARGV;
912    
913     delete $cfg->{profile}{$name};
914 root 1.14 ++$cfg->{dirty};
915 root 1.10 },
916 root 1.26 setparent => sub {
917 root 1.24 @ARGV >= 1
918     or die "profile name is missing\n";
919    
920     $profile->{parent} = shift @ARGV;
921     ++$cfg->{dirty};
922     },
923     delparent => sub {
924     delete $profile->{parent};
925     ++$cfg->{dirty};
926     },
927 root 1.17 showprofile => sub {
928     @ARGV >= 1
929     or die "profile name is missing\n";
930     my $name = shift @ARGV;
931    
932     print JSON::XS->new->pretty->encode ($cfg->{profile}{$name} || {});
933     },
934     showconfig => sub {
935     my $name = @ARGV ? shift @ARGV : AnyEvent::MP::Kernel::_nodename;
936    
937 root 1.25 my $profile = AnyEvent::MP::Config::find_profile $name, @ARGV;
938     @ARGV = ();
939 root 1.24
940     # make it look nicer:
941     delete $profile->{profile};
942     delete $profile->{parent};
943    
944     print JSON::XS->new->pretty->encode ($profile);
945 root 1.17 },
946 root 1.25
947     # undocumented
948     _resolve => sub {
949     print +(join ",", (AnyEvent::MP::Kernel::_resolve shift @ARGV)->recv), "\n";
950     },
951 root 1.1 );
952    
953 root 1.47 for my $attr (qw(
954     monitor_timeout connect_interval framing_format auth_offer
955     auth_accept autocork nodelay
956     )) {
957     $CMD{"set$attr"} = sub {
958     @ARGV >= 1
959     or die "$attr value is missing\n";
960    
961     $profile->{$attr} = shift @ARGV;
962     ++$cfg->{dirty};
963     };
964     $CMD{"del$attr"} = sub {
965     delete $profile->{$attr};
966     ++$cfg->{dirty};
967     };
968     }
969    
970 root 1.27 for (keys %CMD) {
971     $CMD{$1} = $CMD{$_} if /^set(.*)$/;
972     }
973    
974 root 1.1 sub docmd {
975     my $cmd = shift @ARGV;
976    
977     $CMD{$cmd}
978 root 1.23 or die "$cmd: no such aemp command (try perldoc aemp, or man aemp)";
979 root 1.1
980     $CMD{$cmd}();
981     }
982    
983     @ARGV
984 root 1.23 or die "Usage: aemp subcommand ... (try perldoc aemp, or man aemp)\n";
985 root 1.1
986 root 1.19 docmd while @ARGV;
987 root 1.1
988