Recently we switched from chef-solo to a chef-server setup on our infrastructure, a good occasion to refactor our recipes to better practices. I spent some time figuring out how to replace the fabric
scripts I had for remote execution of actions on various servers, by using a knife plugin. That way I can just use knife abilities and don’t need fabric anymore.
So I created a new file in .chef/plugins/knife/
named apt.rb
for a test:
require 'chef/knife'
module KnifeOpenvpn
class Apt < Chef::Knife
banner "knife apt <update|upgrade|simulate> <nodename>"
deps do
require 'chef/knife/ssh'
require 'chef/node'
Chef::Knife::Ssh.load_deps
end
def run
if name_args.size == 2
command_arg = name_args.shift
server = name_args.shift
else
ui.fatal "Syntax: knife apt <update|upgrade|simulate> <nodename>"
ui.fatal "Where <nodename> is a node name."
exit 1
end
command = case command_arg
when 'update'
'update'
when 'upgrade'
'-y upgrade'
when 'simulate'
'-y -s upgrade'
end
knife_ssh(Chef::Node.load(server).ipaddress, "sudo apt-get #{command}").run
end
def knife_ssh(server, command)
ssh = Chef::Knife::Ssh.new
ssh.name_args = [ server, command ]
ssh.config[:ssh_user] = Chef::Config[:knife][:ssh_user]
ssh.config[:ssh_port] = Chef::Config[:knife][:ssh_port]
ssh.config[:identity_file] = Chef::Config[:knife][:identity_file]
ssh.config[:ssh_gateway] = Chef::Config[:knife][:ssh_gateway]
ssh.config[:manual] = true
ssh.config[:host_key_verify] = Chef::Config[:knife][:host_key_verify]
ssh.config[:on_error] = :raise
ssh
end
end
end
Then I just run a knife apt simulate my-server
to execute a apt-get -s -y upgrade
on the my-server
client node. Pretty useful. But I guess that’s only a beginning, I should extend it to run on various nodes at the same time and maybe inside threads or something like that, to match the fabric
power.