AnyEvent::Consul::Exec - Execute a remote command across a Consul cluster
use AnyEvent;
use AnyEvent::Consul::Exec;
my $cv = AE::cv;
my $e = AnyEvent::Consul::Exec->new(
# command to run
command => 'uptime',
# number of seconds target will wait for command, without sending
# output, before terminating it
wait => 2,
# called once job is submitted to Consul
on_submit => sub {
say "job submitted";
},
# called as each target node starts to process the job
# multiple calls, once per node
on_ack => sub {
my ($node) = @_;
say "$node: ack";
},
# called when a node has output from the job
# can be called zero or more times per node, as more output
# becomes available
on_output => sub {
my ($node, $output) = @_;
say "$node: output:";
say "$node> $_" for split("\n", $output);
},
# called when the node completes a job
# multiple calls, one per node
on_exit => sub {
my ($node, $rc) = @_;
say "$node: exit: $rc";
},
# called once all nodes have reported completion
# object is unusable past this point
on_done => sub {
say "job done";
$cv->send;
},
# called if an error occurs anywhere during processing (not command errors)
# typically called if Consul is unable to service requests
# object is unusable past this point
on_error => sub {
my ($err) = @_;
say "error: $err";
$cv->send;
},
);
# begin execution
$e->start;
$cv->recv;
AnyEvent::Consul::Exec is an interface to Consul's "exec" agent function. This is the same thing you get when you run consul exec.
consul exec
is great, but its output is text-based, making it awkward to
parse to determine what happened on each node that ran the command.
AnyEvent::Consul::Exec
replaces the client portion with a library you can
use to get info about what is happening on each node as it happens.
As the name implies, it expects to be run inside an AnyEvent event loop.
Start off by instantiating a AnyEvent::Consul::Exec
object with the command
you want to run:
my $e = AnyEvent::Consul::Exec->new(
command => 'uptime',
);
Then call start
to kick it off:
$e->start;
As the AnyEvent
event loop progresses, the command will be executed on
remote nodes. Output and results of that command on each node will be posted to
callbacks you can optionally provide to the constructor.
When calling the constructor, you can include the consul_args
option with an
arrayref as a value. Anything in that arrayref will be passed as-is to the
AnyEvent::Consul
constructor. Use this to set the various client options
documented in AnyEvent::Consul and Consul.
The wait
option will tell the target agent how long to wait, without
receiving output, before killing the command. This does the same thing as the
-wait
option to consul exec
.
The node
, service
and tag
each take basic regexes that will be used to
match nodes to run the command on. See the corresponding options to consul exec
for more info.
If you specify <min_node_count>, at *least* this many nodes must report in
before we consider a job done. Without this, some nodes might report back
results before we've seen an ack from the others, and your job may prematurely
be canceled on those other nodes, or your on_done callback will be called
prematurely. This is most useful if node
is a regex that matches an
explicit amount of nodes, for example:
node => /^(host1|host2|host3)$/,
min_node_count => 3,
The dc
option can take the name of the datacenter to run the command in. The
exec mechanism is limited to a single datacentre. This option will cause
AnyEvent::Consul::Exec to find a Consul agent in the named datacenter and
execute the command there (without it, the local node is used).
AnyEvent::Consul::Exec
will arrange for various callbacks to be called as
the command is run on each node and its output and exit code returned. Set this
up by passing code refs to the constructor:
-
on_submit
Called when the command is fully accepted by Consul (ie in the KV store, ready for nodes to find).
-
on_ack($node)
Called for each node as they notice the command has been entered into the KV store and start running it.
-
on_output($node, $output)
Called when a command emits some output. May be called multiple times per node, or not at all if the command has no output.
-
on_exit($node, $rc)
Called when a command completes.
-
on_done
Called when all remote commands have completed. After this call, the object is no longer useful.
-
on_error($err)
Called if an error occurs while communicating with Consul (local agent unavailable, quorum loss, etc). After this call, the object is no longer useful.
Consul's remote execution protocol is internal to Consul itself and is not documented. This module has been confirmed to work in Consul 0.9.0 (the latest release at the time of writing). The Consul authors may change the underlying mechanism in the future, but this module should continue to work.
Please report any bugs or feature requests through the issue tracker at https://github.com/robn/AnyEvent-Consul-Exec/issues. You will be notified automatically of any progress on your issue.
This is open source software. The code repository is available for public review and contribution under the terms of the license.
https://github.com/robn/AnyEvent-Consul-Exec
git clone https://github.com/robn/AnyEvent-Consul-Exec.git
- Rob Norris [email protected]
- Matthew Horsfall [email protected]
This software is copyright (c) 2017 by Rob N โ and was supported by FastMail Pty Ltd.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.