aemp - AnyEvent:MP utility
aemp command args... # protocol commands aemp snd <port> <arg...> # send a message aemp mon <port> # wait till port is killed aemp cal <port> <arg...> # send message, append reply aemp eval <node> <expr...> # evaluate expression aemp shell [<node>] # run an interactive shell aemp trace <node> # trace the network topology # run a node aemp run configure_args... # run a node aemp restart <node> # restart a node if running under watchdog # node configuration: node ID aemp setnodeid <nodeid> # configure the real node id aemp delnodeid # reset node id to default (= inherit) # node configuration: authentication aemp gensecret # generate a random shared secret aemp setsecret <secret> # set the shared secret aemp delsecret # remove the secret (= inherit) aemp gencert # generate a random certificate aemp setcert <file> # set a certificate (key.pem + certificate.pem) aemp delcert # remove certificate (= inherit) # node configuration: seed addresses for bootstrapping aemp setseeds <host:port>,... # set seeds aemp delseeds # clear all seeds (= inherit) aemp addseed <host:port> # add a seed aemp delseed <host:port> # remove seed # node configuration: bind addresses aemp setbinds <host:port>,... # set binds aemp delbinds # clear all binds (= inherit) aemp addbind <host:port> # add a bind address aemp delbind <host:port> # remove a bind address # node configuration: services aemp setservices initfunc,... # set service functions aemp delservices # clear all services (= inherit) aemp addservice <initfunc> # add an instance of a service aemp delservice <initfunc> # delete one instance of a service # profile management aemp profile <name> <command>... # apply command to profile only aemp setparent <name> # specify a parent profile aemp delparent # clear parent again aemp delprofile <name> # eradicate the named profile aemp showprofile <name> # display given profile aemp showconfig <name> ... # display effective config # node configuration: low-level protocol aemp [set|del]secure <boolean> aemp [set|del]monitor_timeout <seconds> aemp [set|del]connect_interval <seconds> aemp [set|del]framing_format [array] aemp [set|del]auth_offer [array] aemp [set|del]auth_accept [array] aemp [set|del]autocork <boolean> aemp [set|del]nodelay <boolean>
With aemp you can configure various aspects of AnyEvent::MP and its protocol, send various messages and even run a node.
The aemp utility works like cvs, svn or other commands: the first argument defines which operation (subcommand) is requested, after which arguments for this operation are expected. When a subcommand does not eat all remaining arguments, the remaining arguments will again be interpreted as subcommand and so on.
This means you can chain multiple commands, which is handy for profile configuration, e.g.:
aemp gensecret profile xyzzy binds 4040,4041 nodeid anon/
Please note that all setxxx subcommands have an alias without the set prefix.
setxxx
set
All configuration data is stored in a human-readable (JSON) config file stored in ~/.perl-anyevent-mp (or %appdata%/perl-anyevent-mp on loser systems, or wherever $ENV{PERL_ANYEVENT_MP_RC} points to). Feel free to look at it or edit it, the format is relatively simple.
$ENV{PERL_ANYEVENT_MP_RC}
Arguments can be specified just as with any other shell command, with a few special cases:
If the first argument starts with a literal [-character, then it is interpreted as a UTF-8 encoded JSON text. The resulting array replaces all arguments.
[
Otherwise, if any argument starts with one of [, { or ", then it is interpreted as UTF-8 encoded JSON text (or a single value in case of "), and the resulting reference or scalar replaces the argument.
{
"
This allows you, for example, to specify binds in aemp run (using POSIX shell syntax):
aemp run binds '["*:4040"]'
This can be used to run a node - together with some services, this makes it unnecessary to write any wrapper programs.
Runs a node by calling AnyEvent::MP::Kernel::configure with the given arguments. The node runs under AnyEvent::Watchdog, can be restarted (and autorestarted, see the AnyEvent::Watchdog manual). A very common invocation is to just specify a profile using the profile name
AnyEvent::MP::Kernel::configure
aemp run database-backend
... but you can use most arguments that configure understands:
configure
aemp run nodeid mynode2 profile someprofile
Care has been taken to load (almost) no modules other than AnyEvent::Watchdog and the modules it loads, so everything (including the AnyEvent::MP modules themselves) will be freshly loaded on restart, which makes upgrading everything except the perl binary easy.
Restarts the node using AnyEvent::Watchdog::Util::restart. This works for nodes started by aemp run, but also for any other node that uses AnyEvent::Watchdog.
AnyEvent::Watchdog::Util::restart
aemp run
These commands actually communicate with other nodes. They all use a node profile name of aemp (specifying a default node ID of anon/ and a binds list containing *:* only).
aemp
anon/
*:*
They all use a timeout of five seconds, after which they give up.
Simply send a message to the given port - where you get the port ID from is your problem.
Exits after ensuring that the message has been delivered to its node.
Most useful to take advantage of some undocumented functionality inside nodes, such as node ports being able to call any method:
aemp snd doomed AnyEvent::Watchdog::restart 1
Like aemp cal: appends a local reply port to the message and waits for a message to it.
Any return values will be JSON-encoded and printed separated by commas (kind of like a JSON array without []-brackets).
Example: ask the (undocumented) time service of a node for its current time.
aemp cal mynode time
Monitors the port and exits when it's monitorign callback is called. Most useful to monitor node ports.
Example: monitor some node.
aemp mon doomed
Joins all remaining arguments into a string and evaluates it on the given node. Return values are handled as with aemp cal.
Example: find the unix process ID of the node called posicks.
aemp eval posicks '$$'
Asks the given node for all currently connected nodes, then asks those nodes for the same, thus tracing all node connections.
These commands deal with rather basic settings, the node ID, the shared secret and the TLS certificate.
All setxxx commands have an alias without the set prefix (for exmaple, setnodeid can be shortened to nodeid), unless that alias is already used for somethign else (for exmaple, eval is not an alias for seteval).
setnodeid
nodeid
eval
seteval
Set the node ID to the given string. If it ends with a slash (/), then a random string is appended to make it unique.
/
If no nodeid is specified in any profile, then the profile name, plus appended slash, is used.
Removes the node ID again, which means it is inherited again from it's parent profile, or stays unset.
Generates a random shared secret (currently 1071 bits) and sets it. The shared secret is used to authenticate nodes to each other when TLS is not required.
Sets the shared secret to the given string, which can be anything.
Removes the shared secret again, which means it is inherited again from it's parent profile, or stays unset.
Generates a self-signed certificate and key, and sets it. This works similarly to a shared secret: when all nodes have it, TLS will be used to authenticate and encrypt all traffic.
Set a node certificate (and optionally any CA certificates) from the given file. The file must contain the key, followed by the certificate, followed by any CA certificates you want to trust, all in PEM format.
See AnyEvent::TLS for some more details - this sets the cert and ca_cert options.
cert
ca_cert
Removes the certificate(s) again, which means it is inherited again from it's parent profile, or stays unset.
To discover the network you have to specify some seed addresses, which are basically host:port pairs where you expect some long-running nodes. It does no harm to have a node as its own seed (they will eventually be ignored).
host:port
Sets or replaces the list of seeds, which must be specified as a comma-separated list of host:port pairs. The host can be a hostname, an IP address, or * to signify all local host addresses (which makes little sense for seeds, outside some examples, but a lot of sense for binds).
host
*
An empty list is allowed.
Example: use doomed with default port as only seednode.
doomed
aemp setseeds doomed
Removes the seed list again, which means it is inherited again from it's parent profile, or stays unset.
Adds a single seed address.
Deletes the given seed address, if it exists.
To be able to be reached from other nodes, a node must bind itself to some listening socket(s). The list of these can either bs specified manually, or AnyEvent::MP can guess them. Nodes without any binds are possible to some extent.
Sets the list of bind addresses explicitly - see the aemp setseeds command for the exact syntax. In addition, a value of * for the port, or not specifying a port, means to use a dynamically-assigned port.
Note that the *, *:* or *:port patterns are very useful here.
*:port
Example: bind on a ephemeral port on all local interfaces.
aemp setbinds "*"
Example: bind on a random port on all local interfaces.
aemp setbinds "*:*"
Example: resolve "doomed.mydomain" and try to bind on port 4040 of all IP addressess returned.
4040
aep setbinds doomed.mydomain:4040
Removes the bind list again, which means it is inherited again from it's parent profile, or stays unset.
Adds a single bind address.
Deletes the given bind address, if it exists.
Services are modules (or functions) that are automatically loaded (or executed) when a node starts. They are especially useful when used in conjunction with aemp run, to configure which services a node should run.
Despite the daunting name, services really are nothing more than a module name or a function name with arguments. The "service" aspect comes only from the behaviour of the module or function, which is supposed to implement, well, some kind of service for the node, network etc.
Instead of writing a standalone program for each different node type in your network, you can simply put your code into a module, and then let the configuration decide which node runs which "services". This also makes it easy to combine multiple different services within the same node.
Sets or replaces the list of services, which must be specified as a comma-separated list or a JSON array.
Each string entry in the list is interpreted as either a module name to load (when it ends with ::) or a function to call (all other cases).
::
Each entry which is an array itself (you need to use JSON format to specify those) is interpreted as a function name and the arguments to pass.
The algorithm to find the function is the same as used for AnyEvent::MP::spawn.
AnyEvent::MP::spawn
Example: run the global service.
aemp setservices AnyEvent::MP::Global::
Example: call the mymod::myfun function with arguments 1, 2 and 3.
aemp setservices '[["mymod::myfun", 1,2,3]]'
Removes the service list again, which means it is inherited again from it's parent profile, or stays unset.
Adds a single service.
Deletes the given service, if it exists.
Sometimes, all you need is to evaluate a small perl snippet to bring a node up. This sets a perl string that is eval'ed after the node has been configured.
Delete any eval string set with seteval.
All the above configuration functions by default affect the global default configuration, which is basically used to augment every profile and node configuration.
This subcommand makes the following subcommands act only on a specific named profile, instead of on the global default. The profile is created if necessary.
Example: create a server profile, give it a random node name, some seed nodes and bind it on an unspecified port on all local interfaces. You should add some services then and run the node...
server
aemp profile server nodeid anon/ seeds doomed,10.0.0.2:5000 binds "*:*"
Deletes the profile of the given name.
Sets the parent profile to use - values not specified in a profile will be taken from the parent profile (even recursively, with the global default config being the default parent). This is useful to configure profile classes and then to inherit from them for individual nodes.
Note that you can specify circular parent chains and even a parent for the global configuration. Neither will do you any good, however.
Example: inherit all values not specified in the doomed profile from the server profile.
aemp profile doomed setparent server
Removes the parent again from the profile, if any was set, so the profile inherits directly from the global default config again.
Shows the values of the given profile, and only those, no inherited values.
Shows the effective config, i.e. the values as used by a node started with the given profile name. Any additional key-value pairs specified augment the configuration, just as with configure.
If all arguments are omitted, show the global default config.
The low-level transport protocol betwene two nodes also has a number of configurable options, most of which should not be touched unless you know what you are doing.
Normally, nodes allow anything to be done to them by remote nodes, including remotely-triggered execution of code.
Sometimes a more secure mode is desired - this can be achieved by setting the secure option to a true value.
When secure mode is enabled, then the node will not execute code locally, at least not via the normal node protocol. All other messages are still allowed. This means remote nodes can monitor, kill or snd to local ports (port names can also be easily guessed).
At the moment, this setting ignores snd_on, eval_on and spawn requests.
snd_on
eval_on
spawn
Sets the default monitor timeout, that is, when a connection to a node cannot be established within this many seconds, the node is declared unreachable and all monitors will fire.
30 seconds are usually a good time span for this.
30
When a connection cannot be established successfully within this many seconds, try the next transport address (e.g. the next IP address). If your nodes have a lot of transports, you might have to set this to a low value so that they will actually all be tried within the monitor timeout interval.
2 is usually a good value, unless you live in new zealand.
2
Configures the list of framing formats offered to the other side. This is simply a list of formatted read/write types used with AnyEvent::Handle, in order of decreasing preference.
Nodes support cbor, json and storable framing formats for data packets out of the box, and usually choose cbor because it is first in the list.
cbor
json
storable
Example: prefer the My::Personal::Format framing format over JSON over Storable.
My::Personal::Format
aemp setframing_format '["My::Personal::Format", "json", "storable"]'
Configures the list of authentication types that the node offers to the other side as acceptable, in order of decreasing preference. Only auth methods that the node can actually support will be offered.
The default is '["tls_sha3_512", "hmac_sha3_512"]' and is usually good enough.
Configures the list of authentication types that remote nodes can use to authenticate, in order of decreasing preference.
The default is '["tls_sha3_512", "hmac_sha3_512", "tls_anon", "cleartext"]' and is usually good enough.
Sets the default autocork option value for the AnyEvent::Handle object used by transports. By default, autocorking is off, potentially reducing latency.
autocork
Sets the default nodelay option value for the AnyEvent::Handle object used by transports. By default, nodelay is on, potentially reducing latency.
nodelay
To install AnyEvent::MP, copy and paste the appropriate command in to your terminal.
cpanm
cpanm AnyEvent::MP
CPAN shell
perl -MCPAN -e shell install AnyEvent::MP
For more information on module installation, please visit the detailed CPAN module installation guide.