ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-MP/bin/aemp
Revision: 1.58
Committed: Fri Mar 23 00:38:14 2012 UTC (12 years, 2 months ago) by root
Branch: MAIN
Changes since 1.57: +22 -1 lines
Log Message:
*** empty log message ***

File Contents

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