One of the features which makes MCollective truly unique is the ability to send requests from one client, and to process the responses with a different client or Listener
.
The first thing we’ll do here is to create a listener. What I’ll introduce to you here is a working listener from which you can debug any problem. You can also copy it and add new functionality. I put my listeners in the $libdir directory just like every other plugin, but that’s not necessary nor standard.
$
cat /
usr/libexec/mcollective
/mcollective/listener/debugger.rb# Parse options, load config, and start an MCollective client.
require
'mcollective'
optparser
=
MCollective
:
:Optionparser
.
new
options
=
optparser
.
parse
config
=
MCollective
:
:Config
.
instance
config
.
loadconfig
(
options
[
:config
]
)
MCollective
:
:PluginManager
[
"security_plugin"
].
initiated_by
=
:client
connector
=
MCollective
:
:PluginManager
[
'connector_plugin'
]
connector
.
connect
# Get pretty-print and the Log object
require
'pp'
Log
=
MCollective
:
:Log
# Get a reply queue name from anywhere, hardcoded here
replyqueue
=
'debugger'
queuename
=
'/queue/mcollective.reply.'
+
replyqueue
# Here is the queue we want to listen to
connector
.
connection
.
subscribe
(
queuename
,
{},
"$$"
.
to_i
)
# consume all the things...
loop
do
# Get an mcollective Message object and configure it as a reply
message
=
connector
.
receive
message
.
type
=
:reply
message
.
decode!
# security plugin validates authentication
# This is the real data, everything else is envelope
data
=
message
.
payload
[
:body
][
:data
]
# Do anything you want here
pp
data
[
:text
]
end
Now that we have a listener listening to our response queue, let’s kick off some commands:
$
mco rpc --agent service --action status --argument service=puppet --reply-to=/queue/mcollective.reply.
debugger
Request
sent
with
id
:
12
afa18ae2105390a73302967edddab8
replies
to
/queue/m
collective
.
reply
.
debugger
At the time this book was written, you had to use the direct RPC invocation of the agent to get a useful response back. This is filed under Puppet Labs BUG MCO-207 and I am hoping to remove this notice before the book goes to print.
Using a client application with the --reply-to option produces the following error message:
$
mco puppet status --reply-to /queue/mcollective.reply.
mylistener
The
mco
application
failed
to
run
,
use
-
v
for
full
error
backtrace
details
:
undefined
method
`length' for nil:NilClass
$
mco ping --reply-to /queue/mcollective.reply.
mylistener
----
ping
statistics
----
No
responses
received
Both of those commands will work—you’ll receive the results on your response queue. But mco will produce the error message and return a failure response code.
You’ll notice that ping claims no responses. That’s because it’s a simple application, and didn’t realize you sent the result elsewhere. Ping also has a different response format, which we will discuss in the next section.
Let’s look at the results we receive. We’re expecting the hostname, agent, statusmessage, and a pretty-print output of the body:
$
ruby
debugger
.
rb
geode
/
service
:
OK
=
0
{
:status
=>
"running"
}
sunstone
/
service
:
OK
=
0
{
:status
=>
"running"
}
heliotrope
/
service
:
OK
=
0
{
:status
=>
"running"
}
Yup, that’s exactly what we go. Now what about if we send it ping status? Ping is a discovery test that doesn’t include status messages. That’s the bottom part of the if/then in the code block. Here we just output the hostname and the body text.
$
ruby
debugger
.
rb
ruby
listen
.
rb
geode
:
"pong"
fireagate
:
"pong"
heliotrope
:
"pong"
sunstone
:
"pong"
How about if we do something with more data in the fields, like puppet status
?
geode
/
puppet
:
OK
=
0
{
:daemon_present
=>
true
,
:status
=>
"idling"
,
:enabled
=>
true
,
:message
=>
"Currently idling; last completed run 26 minutes 23 seconds ago"
,
:idling
=>
true
,
:applying
=>
false
,
:lastrun
=>
1393571918
,
:disable_message
=>
""
,
:since_lastrun
=>
1583
}
heliotrope
/
puppet
:
OK
=
0
...etc
As you can see, there are considerably more fields available to use in your output.
What if you want to see all the gory details? You might want to try adding one of the follow pretty-print commands. Each one of these is a little farther down, so you only need one of them. Looking at this output is an exercise for the reader: you’ll get to see a lot more of how a reply message is structured.
# Only use one of these, as each includes the ones beneath it.
# All the gory details
#pp message
# Everything we care about is here
#pp message.payload
# This contains just the data in the response
pp
message
.
payload
[
:body
]
How might you use this data? There’s no limit, really. Anything you can do in Ruby. Here’s a short list:
…I think you get the idea. Even the sky is not the limit, I hear that most satellites support RESTful APIs these days.
18.219.81.43