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