is one of most popular weapons of choice for managing IT infrastructure as code. And what could be better than controlling chef directly from your chat using Hubot? In this chapter we will write a custom Hubot script that will be running commands for you.
To begin the integration, you have to get knife
command to work on your bot server. For that you need to install chef
gem and .
You have a couple of options here, one is to make knife
work from any directory by placing the configuration at /etc/chef
, other is to have your *.pem
and knife.rb
in some directory from where knife command will work without being available globally. Our example script will be running knife from /home/hubot/knife
directory.
Here is a quick example of Hubot script with one, yet very powerful chef’s knife
command:
scripts/chef.coffee
1
# Description
2
# Hubot script that runs Chef's knife
3
#
4
# Commands:
5
# hubot knife <command> - execute knife command
6
#
7
# Author:
8
# spajus
9
10
module.exports =
(robot) ->
11
knife_opts =
{
cwd:
'/home/hubot/knife'
}
12
cp =
require
'child_process'
13
robot
.
respond
/knife (.*)/i
,
(msg) ->
14
cp
.
exec
"knife
#{
msg
.
match
[
1
]
}
"
,
knife_opts
,
(error, stdout, stderr) ->
15
msg
.
send
stdout
if
stdout
16
msg
.
send
"Error:
#{
stderr
}
"
if
stderr
If your knife
command works globally, you may set knife_opts
to {}
.
This script is written using the technique explained in “Hubot Scripting” chapter - see the calendar script in “Reacting To Messages In Chatroom” section for explanation how invoking shell commands works with Hubot scripts.
Example of this script in action:
Tomas V. hubot knife role list | grep jobs$ Hubot analytics-jobs core-jobs
Yes, even pipe works. This script is so powerfull, that you MUST take precautions to secure it properly, or somebody can can do devastating things not only to hubot’s machine, but to all your servers. A good way is to execute cp.exec
only when it’s invoked in devops
or admins
room or by small set of trusted users. See “Roles And Authentication” chapter to see how it can be done, and use it at your own risk.
While the script we’ve written is very powerful already, we may want to make our lives easier and let Hubot do the thinking. This is especially helpful if you want to expose a set of secure commands for your developers to perform actions without getting to know how chef
and knife
works. Behold, the advanced chef integration script, that includes hubot knife
command.
scripts/chef.coffee
1
# Description
2
# Hubot script that runs Chef's knife
3
#
4
# Commands:
5
# hubot knife <command> - execute knife command (only in devops chat)
6
# hubot server list - list all our servers registered with chef
7
# hubot server list <pattern> - list our servers registered with chef match\
8
ing
a
pattern
9
# hubot server search <pattern> - search for servers matching chef role (* \
10
works
)
11
# hubot servers <pattern> - search for servers matching '*-<pattern>' chef \
12
role
13
# hubot server roles - list all chef roles
14
# hubot server roles <pattern> - list chef roles matching a pattern
15
#
16
# Author:
17
# spajus
18
19
module.exports =
(robot) ->
20
21
cp =
require
'child_process'
22
knife_opts =
{
cwd:
'/home/hubot/knife'
}
23
24
handle_response =
(msg) ->
25
(error, stdout, stderr) ->
26
msg
.
send
stdout
if
stdout
27
msg
.
send
"Error:
#{
stderr
}
"
if
stderr
28
29
robot
.
respond
/knife (.*)/i
,
(msg) ->
30
if
msg
.
message
.
room
!=
'<insert devops room id>'
31
msg
.
send
"Do it in devops room please"
32
return
33
cp
.
exec
"knife
#{
msg
.
match
[
1
]
}
"
,
34
knife_opts
,
handle_response
(
msg
)
35
36
robot
.
respond
/server list$/i
,
(msg) ->
37
cp
.
exec
"knife node list"
,
38
knife_opts
,
handle_response
(
msg
)
39
40
robot
.
respond
/server list (.*)/i
,
(msg) ->
41
cp
.
exec
"knife node list | grep
#{
msg
.
match
[
1
]
}
"
,
42
knife_opts
,
handle_response
(
msg
)
43
44
robot
.
respond
/server roles?$/i
,
(msg) ->
45
cp
.
exec
"knife role list"
,
46
knife_opts
,
handle_response
(
msg
)
47
48
robot
.
respond
/server roles? (.*)/i
,
(msg) ->
49
cp
.
exec
"knife role list | grep
#{
msg
.
match
[
1
]
}
$"
,
50
knife_opts
,
handle_response
(
msg
)
51
52
robot
.
respond
/server search (.*)/i
,
(msg) ->
53
cp
.
exec
"knife search node 'roles:
#{
msg
.
match
[
1
]
}
' -a run_list"
,
54
knife_opts
,
handle_response
(
msg
)
55
56
robot
.
respond
/servers (.*)/i
,
(msg) ->
57
cp
.
exec
"knife search node 'roles:*-
#{
msg
.
match
[
1
]
}
' -i"
,
58
knife_opts
,
handle_response
(
msg
)
You can find this script at .
Script in action:
Tomas V. hubot help server Hubot hubot server list - list all our servers registered with chef hubot server list <pattern> - list our servers registered with chef\ matching a pattern hubot server roles - list all chef roles hubot server roles <pattern> - list chef roles matching a pattern hubot server search <pattern> - search for servers matching chef ro\ le (* works) hubot servers <pattern> - search for servers matching '*-<pattern>'\ chef role Tomas V. hubot server list indexer Hubot indexer.botserv.org Tomas V. hubot server list redis Hubot redis1.botserv.org Tomas V. hubot server list static Hubot static1.botserv.org static2.botserv.org static-x1.botserv.org static-x2.botserv.org static11.botserv.org static12.botserv.org static13.botserv.org static14.botserv.org Tomas V. hubot server roles redis Hubot core-redis redis Tomas V. hubot server search core-redis Hubot 2 items found db3.botserv.org: run_list: role[machine], role[core-redis] redis1.botserv.org: run_list: role[machine], role[redis], role[core-redis] Tomas V. hubot servers uk Hubot 14 items found indexer.botserv.org static2.botserv.org front2.botserv.org app4.botserv.org jobs9.botserv.org db4.botserv.org app1.botserv.org search2.botserv.org front1.botserv.org app2.botserv.org db1.botserv.org static1.botserv.org db2.botserv.org search1.botserv.org
Tune this script and add shortcuts to your favorite knife
commands.
There are Hubot scripts out there that work nearly the same. For example, this package at GitHub: . It may be a good alternative if you want something working right out of the box, however, I believe Hubot Chef integration is too important, you can’t just throw something in and expect it will suit your needs. You should write every bit of it yourself, add safety precautions, enrich it with shorthands for most often used commands. By getting very intimate with this integration script you will be sure it does all you want, and you will be able to sleep at night knowing that you built it in a way that nobody can do any harm to your infrastructure.
This book will not cover these, however you can use same techniques that were used in Chef’s integration to write yourself a custom integration with any infrastructure management tool. Just make sure you follow through the chapter and understand how chef.coffee
works.