ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MP/bin/aemp
Revision: 1.51
Committed: Fri Mar 2 19:19:21 2012 UTC (12 years, 2 months ago) by root
Branch: MAIN
Changes since 1.50: +16 -7 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     print "$node> ";
661 root 1.51 my $pkg;
662 root 1.42 my $cv = AE::cv;
663 root 1.51 my $echo = port {
664     print "\n ECHO<$AnyEvent::MP::Kernel::SRCNODE->{id}> ", JSON::XS::encode_json \@_, "\n$node> ";
665     };
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     $pkg = "package $1";
677     } elsif ($line =~ /\S/) {
678 root 1.42 my $time = AE::time;
679 root 1.51 AnyEvent::MP::Kernel::eval_on $node, "$pkg; my \$ECHO = '$echo'; $line", port {
680 root 1.42 my ($err, @res) = @_;
681    
682     $time = AE::time - $time;
683    
684     print "\n $node: $line\n";
685     if (length $err) {
686     print " $err @res";
687     } else {
688 root 1.51 print " ", JSON::XS::encode_json \@res;
689 root 1.42 }
690     printf "\n %0.3fs\n", $time;
691     print "$node> ";
692     };
693     }
694    
695     print "$node> ";
696     };
697     $cv->recv;
698     }
699    
700 root 1.37 sub node_eval {
701     my ($node, $expr) = @_;
702    
703     init;
704    
705     my $cv = AE::cv;
706     my $to = AE::timer 5, 0, sub { exit 1 };
707     AnyEvent::MP::Kernel::eval_on $node, $expr, port { &$cv };
708     mon $node, $cv;
709    
710     my ($err, @res) = $cv->recv;
711    
712 root 1.39 die "$err @res" if length $err;
713 root 1.37
714     print +(substr JSON::XS->new->encode (\@res), 1, -1), "\n";
715     }
716    
717 root 1.10 sub docmd;
718    
719 root 1.1 our %CMD = (
720     snd => sub {
721 root 1.17 my $port = shift @ARGV;
722 root 1.25 init;
723 root 1.1
724 root 1.7 snd $port, @ARGV; @ARGV = ();
725 root 1.1
726     my $cv = AE::cv;
727 root 1.28 my $to = AE::timer 5, 0, sub { exit 1 };
728 root 1.1 mon $port, $cv;
729 root 1.19 my $reply = port sub { &$cv };
730     snd node_of $port, snd => $reply, "message sent successfully";
731 root 1.1
732     print join " ", $cv->recv, "\n";
733     },
734    
735 root 1.41 cal => sub {
736 root 1.17 my $port = shift @ARGV;
737 root 1.25 init;
738 root 1.7
739     my $cv = AE::cv;
740 root 1.41 cal $port, @ARGV, sub { &$cv }; @ARGV = ();
741 root 1.7
742 root 1.23 print +(substr JSON::XS->new->encode ([$cv->recv]), 1, -1), "\n";
743 root 1.7 },
744    
745 root 1.1 mon => sub {
746 root 1.17 my $port = shift @ARGV;
747 root 1.25 init;
748 root 1.1
749     mon $port, my $cv = AE::cv;
750     print join " ", $cv->recv, "\n";
751     },
752    
753 root 1.19 eval => sub {
754     my $node = node_of shift @ARGV;
755     my $expr = join " ", @ARGV; @ARGV = ();
756 root 1.37 node_eval $node, $expr;
757 root 1.19 },
758    
759 root 1.42 shell => \&shell,
760    
761 root 1.11 trace => sub {
762     @ARGV >= 1
763 root 1.17 or die "node id missing\n";
764 root 1.11
765 root 1.17 trace shift @ARGV;
766 root 1.11 },
767 root 1.37 restart => sub {
768     my $node = node_of shift @ARGV;
769 root 1.44 node_eval $node, 'my $w; $w = AE::idle sub { '
770     . 'undef $w; '
771     . 'use AnyEvent::Watchdog::Util ();'
772     . 'AnyEvent::Watchdog::Util::restart'
773     . '}; ()';
774 root 1.37 },
775 root 1.11
776 root 1.17 setnodeid => sub {
777 root 1.8 @ARGV >= 1
778     or die "shared secret missing\n";
779    
780 root 1.17 $profile->{nodeid} = shift @ARGV;
781 root 1.8 ++$cfg->{dirty};
782     },
783 root 1.17 delnodeid => sub {
784     delete $profile->{nodeid};
785 root 1.8 ++$cfg->{dirty};
786     },
787    
788 root 1.1 setsecret => sub {
789 root 1.8 @ARGV >= 1
790 root 1.1 or die "shared secret missing\n";
791    
792 root 1.8 $profile->{secret} = shift @ARGV;
793 root 1.1 ++$cfg->{dirty};
794     },
795     gensecret => sub {
796 root 1.51 $profile->{secret} = AnyEvent::MP::Kernel::nonce62 180; # ~1071 bits
797 root 1.1 ++$cfg->{dirty};
798     },
799 root 1.17 delsecret => sub {
800 root 1.8 delete $profile->{secret};
801 root 1.1 ++$cfg->{dirty};
802     },
803    
804     setcert => sub {
805 root 1.8 @ARGV >= 1
806 root 1.1 or die "key+certificate pem filename missing\n";
807    
808 elmex 1.45 my $certfile = shift @ARGV;
809    
810     open my $fh, "<", $certfile
811     or die "$certfile: $!";
812 root 1.1
813     local $/;
814 root 1.8 $profile->{cert} = <$fh>;
815 root 1.1 ++$cfg->{dirty};
816     },
817     gencert => sub {
818 root 1.8 $profile->{cert} = gen_cert;
819 root 1.1 ++$cfg->{dirty};
820     },
821 root 1.17 delcert => sub {
822 root 1.8 delete $profile->{cert};
823 root 1.1 ++$cfg->{dirty};
824     },
825 root 1.6
826 root 1.17 setbinds => sub {
827 root 1.19 @ARGV >= 1
828     or die "bind addresses missing\n";
829 root 1.38 my $list = shift @ARGV;
830     $profile->{binds} = ref $list ? $list : [split /,/, $list];
831 root 1.17 ++$cfg->{dirty};
832     },
833     delbinds => sub {
834     delete $profile->{binds};
835     ++$cfg->{dirty};
836     },
837     addbind => sub {
838     @ARGV >= 1
839     or die "bind address missing\n";
840     my $bind = shift @ARGV;
841    
842     @{ $profile->{binds} } = grep $_ ne $bind, @{ $profile->{binds} };
843     push @{ $profile->{binds} }, $bind;
844     ++$cfg->{dirty};
845     },
846     delbind => sub {
847     @ARGV >= 1
848     or die "bind address missing\n";
849     my $bind = shift @ARGV;
850    
851     @{ $profile->{binds} } = grep $_ ne $bind, @{ $profile->{binds} };
852     ++$cfg->{dirty};
853     },
854    
855 root 1.6 setseeds => sub {
856 root 1.19 @ARGV >= 1
857     or die "seed addresses missing\n";
858 root 1.38 my $list = shift @ARGV;
859     $profile->{seeds} = ref $list ? $list : [split /,/, $list];
860 root 1.6 ++$cfg->{dirty};
861     },
862 root 1.17 delseeds => sub {
863     delete $profile->{seeds};
864     ++$cfg->{dirty};
865     },
866 root 1.6 addseed => sub {
867 root 1.10 @ARGV >= 1
868 root 1.17 or die "seed address missing\n";
869 root 1.6 my $seed = shift @ARGV;
870 root 1.10
871 root 1.8 @{ $profile->{seeds} } = grep $_ ne $seed, @{ $profile->{seeds} };
872     push @{ $profile->{seeds} }, $seed;
873     ++$cfg->{dirty};
874     },
875     delseed => sub {
876 root 1.10 @ARGV >= 1
877 root 1.17 or die "seed address missing\n";
878 root 1.8 my $seed = shift @ARGV;
879 root 1.10
880 root 1.8 @{ $profile->{seeds} } = grep $_ ne $seed, @{ $profile->{seeds} };
881     ++$cfg->{dirty};
882     },
883    
884     setservices => sub {
885 root 1.19 @ARGV >= 1
886     or die "service specifications missing\n";
887 root 1.38 my $list = shift @ARGV;
888     $profile->{services} = ref $list ? $list : [split /,/, $list];
889 root 1.6 ++$cfg->{dirty};
890     },
891 root 1.17 delservices => sub {
892     delete $profile->{services};
893     ++$cfg->{dirty};
894     },
895 root 1.9 addservice => sub {
896 root 1.10 @ARGV >= 1
897     or die "service specification missing\n";
898 root 1.8 my $service = shift @ARGV;
899     push @{ $profile->{services} }, $service;
900     ++$cfg->{dirty};
901     },
902 root 1.9 delservice => sub {
903 root 1.10 @ARGV >= 1
904     or die "service specification missing\n";
905 root 1.8 my $service = shift @ARGV;
906     for (0 .. $#{ $profile->{services} }) {
907     next unless $profile->{services}[$_] eq $service;
908     splice @{ $profile->{services} }, $_, 1;
909     last;
910     }
911 root 1.6 ++$cfg->{dirty};
912     },
913 root 1.10
914     profile => sub {
915 root 1.19 @ARGV >= 1
916     or die "profile name is missing\n";
917 root 1.10 my $name = shift @ARGV;
918    
919     $profile = $cfg->{profile}{$name} ||= {};
920 root 1.14 ++$cfg->{dirty};
921 root 1.10 },
922     delprofile => sub {
923     @ARGV >= 1
924     or die "profile name is missing\n";
925     my $name = shift @ARGV;
926    
927     delete $cfg->{profile}{$name};
928 root 1.14 ++$cfg->{dirty};
929 root 1.10 },
930 root 1.26 setparent => sub {
931 root 1.24 @ARGV >= 1
932     or die "profile name is missing\n";
933    
934     $profile->{parent} = shift @ARGV;
935     ++$cfg->{dirty};
936     },
937     delparent => sub {
938     delete $profile->{parent};
939     ++$cfg->{dirty};
940     },
941 root 1.17 showprofile => sub {
942     @ARGV >= 1
943     or die "profile name is missing\n";
944     my $name = shift @ARGV;
945    
946     print JSON::XS->new->pretty->encode ($cfg->{profile}{$name} || {});
947     },
948     showconfig => sub {
949     my $name = @ARGV ? shift @ARGV : AnyEvent::MP::Kernel::_nodename;
950    
951 root 1.25 my $profile = AnyEvent::MP::Config::find_profile $name, @ARGV;
952     @ARGV = ();
953 root 1.24
954     # make it look nicer:
955     delete $profile->{profile};
956     delete $profile->{parent};
957    
958     print JSON::XS->new->pretty->encode ($profile);
959 root 1.17 },
960 root 1.25
961     # undocumented
962     _resolve => sub {
963     print +(join ",", (AnyEvent::MP::Kernel::_resolve shift @ARGV)->recv), "\n";
964     },
965 root 1.1 );
966    
967 root 1.47 for my $attr (qw(
968     monitor_timeout connect_interval framing_format auth_offer
969     auth_accept autocork nodelay
970     )) {
971     $CMD{"set$attr"} = sub {
972     @ARGV >= 1
973     or die "$attr value is missing\n";
974    
975     $profile->{$attr} = shift @ARGV;
976     ++$cfg->{dirty};
977     };
978     $CMD{"del$attr"} = sub {
979     delete $profile->{$attr};
980     ++$cfg->{dirty};
981     };
982     }
983    
984 root 1.27 for (keys %CMD) {
985     $CMD{$1} = $CMD{$_} if /^set(.*)$/;
986     }
987    
988 root 1.1 sub docmd {
989     my $cmd = shift @ARGV;
990    
991     $CMD{$cmd}
992 root 1.23 or die "$cmd: no such aemp command (try perldoc aemp, or man aemp)";
993 root 1.1
994     $CMD{$cmd}();
995     }
996    
997     @ARGV
998 root 1.23 or die "Usage: aemp subcommand ... (try perldoc aemp, or man aemp)\n";
999 root 1.1
1000 root 1.19 docmd while @ARGV;
1001 root 1.1
1002