How could I use knife programmatically in a ruby script?

Instead of shelling out to knife each time, could I just require ‘Chef’,
initialize a few values, and work from there?

I might be able to figure it out by looking thru the chef source code, but
I am lazy, so I thought I would ask first :wink:

#!/usr/bin/env ruby

servers = %x[ knife search node “name:econ” -i].split
servers = servers.slice(3, servers.length)

servers.each do |s|
run_list_str = %[knife node show #{s} -r -f json]
run_list = JSON.parse(s_run_list)
if not run_list.include? “role[base]”
%x[knife node run_list add #{s} “role[base]”]
end
if not run_list.include? “role[int0]” or not run_list.include? "role[ext0]"
if s =~ /^ext.*/ %x[knife node run_list add #{s} "role[ext0]"] else %x[knife node run_list add #{s} "role[int0]"] end end if not run_list.include? "role[econ]" %x[knife node run_list add #{s} "role[econ]"] end %x[ knife ssh name:{s} “chef-client” -x root -i .chef/identity ]
end

Hi Bryan

Here's part of the code I use to launch knife bootstrap programatically.
It's a mix of several parts so it won't work as is, but you can figure out
the variables:

require "chef"
require 'chef/knife'
require 'chef/knife/bootstrap'
require "chef/knife/core/bootstrap_context"
require 'chef/knife/ssh'
require 'net/ssh'
require 'net/ssh/multi'
config_file = File.exists?(File.join(Dir.getwd, '.chef', 'knife.rb')) ?
File.join(Dir.getwd, '.chef', 'knife.rb') :
File.join(File.expand_path('~'), '.chef', 'knife.rb')
Chef::Config.from_file(config_file)
kb = Chef::knife::Bootstrap.new
kb.name_args = target
Chef::Config[:environment] = options[:env]
kb.config[:ssh_user] = "ubuntu"
kb.config[:run_list] = options[:run_list]
kb.config[:use_sudo] = true
kb.config[:chef_node_name] = name
kb.run

HTH

Haim

On Wed, Nov 23, 2011 at 7:14 PM, Bryan Berry bryan.berry@gmail.com wrote:

loads missing roles for a set of nodes · GitHub

Instead of shelling out to knife each time, could I just require 'Chef',
initialize a few values, and work from there?

I might be able to figure it out by looking thru the chef source code, but
I am lazy, so I thought I would ask first :wink:

#!/usr/bin/env ruby

servers = %x[ knife search node "name:econ" -i].split
servers = servers.slice(3, servers.length)

servers.each do |s|
run_list_str = %[knife node show #{s} -r -f json]
run_list = JSON.parse(s_run_list)
if not run_list.include? "role[base]"
%x[knife node run_list add #{s} "role[base]"]
end
if not run_list.include? "role[int0]" or not run_list.include? "role[ext0]"
if s =~ /^ext.*$/
%x[knife node run_list add #{s} "role[ext0]"]
else
%x[knife node run_list add #{s} "role[int0]"]
end
end
if not run_list.include? "role[econ]"
%x[knife node run_list add #{s} "role[econ]"]
end
%x[ knife ssh name:${s} "chef-client" -x root -i .chef/identity ]
end

--
Haim

On Wed, Nov 23, 2011 at 12:14 PM, Bryan Berry bryan.berry@gmail.com wrote:

Instead of shelling out to knife each time, could I just require 'Chef',
initialize a few values, and work from there?

You could use Chef as a library. Some people use knife as a library,
which is discouraged because it is a client that uses the chef library
itself, but I understand why.

For something simple like this, you should use 'knife exec'

http://wiki.opscode.com/display/chef/Knife+Exec
http://blog.loftninjas.org/2010/12/29/knife-one-liners/
http://blog.loftninjas.org/2011/01/12/knife-reporting-apt-updates/

Bryan

toda raba! ata totach!

you've saved me a good bit of effort

On Wed, Nov 23, 2011 at 6:22 PM, Haim Ashkenazi haim.ashkenazi@gmail.comwrote:

Hi Bryan

Here's part of the code I use to launch knife bootstrap programatically.
It's a mix of several parts so it won't work as is, but you can figure out
the variables:

require "chef"
require 'chef/knife'
require 'chef/knife/bootstrap'
require "chef/knife/core/bootstrap_context"
require 'chef/knife/ssh'
require 'net/ssh'
require 'net/ssh/multi'
config_file = File.exists?(File.join(Dir.getwd, '.chef', 'knife.rb')) ?
File.join(Dir.getwd, '.chef', 'knife.rb') :
File.join(File.expand_path('~'), '.chef', 'knife.rb')
Chef::Config.from_file(config_file)
kb = Chef::knife::Bootstrap.new
kb.name_args = target
Chef::Config[:environment] = options[:env]
kb.config[:ssh_user] = "ubuntu"
kb.config[:run_list] = options[:run_list]
kb.config[:use_sudo] = true
kb.config[:chef_node_name] = name
kb.run

HTH

Haim

On Wed, Nov 23, 2011 at 7:14 PM, Bryan Berry bryan.berry@gmail.comwrote:

loads missing roles for a set of nodes · GitHub

Instead of shelling out to knife each time, could I just require 'Chef',
initialize a few values, and work from there?

I might be able to figure it out by looking thru the chef source code,
but I am lazy, so I thought I would ask first :wink:

#!/usr/bin/env ruby

servers = %x[ knife search node "name:econ" -i].split

servers = servers.slice(3, servers.length)

servers.each do |s|

run_list_str = %[knife node show #{s} -r -f json]

run_list = JSON.parse(s_run_list)

if not run_list.include? "role[base]"

%x[knife node run_list add #{s} "role[base]"]

end

if not run_list.include? "role[int0]" or not run_list.include? "role[ext0]"

if s =~ /^ext.*$/

  %x[knife node run_list add #{s} "role[ext0]"]

else

  %x[knife node run_list add #{s} "role[int0]"]

end

end

if not run_list.include? "role[econ]"

%x[knife node run_list add #{s} "role[econ]"]

end

%x[ knife ssh name:${s} "chef-client" -x root -i .chef/identity ]

end

--
Haim

Hi

On Wed, Nov 23, 2011 at 7:25 PM, Bryan Berry bryan.berry@gmail.com wrote:

toda raba! ata totach!

Thanks (I guess it's for me :).

you've saved me a good bit of effort

BTW, reading through the chef code is surprisingly easy. It's very well
written.

Bye

Haim

I've used the Spice library with some success:

GitHub - danryan/spice: A zesty Chef server API wrapper

The only trouble I had was with the search, I always got MissingMethods
errors. Did not have enough time to figure it out and moved to something
else.

But it worked perfectly well to interact with nodes and databags.

On Wed, Nov 23, 2011 at 12:43 PM, Haim Ashkenazi
haim.ashkenazi@gmail.comwrote:

Hi

On Wed, Nov 23, 2011 at 7:25 PM, Bryan Berry bryan.berry@gmail.comwrote:

toda raba! ata totach!

Thanks (I guess it's for me :).

you've saved me a good bit of effort

BTW, reading through the chef code is surprisingly easy. It's very well
written.

Bye

Haim

Thanks btm, I was.aware of knife exec but didn't know that it had access to
all of chefs API and the node object
On Nov 23, 2011 6:24 PM, "Bryan McLellan" btm@loftninjas.org wrote:

On Wed, Nov 23, 2011 at 12:14 PM, Bryan Berry bryan.berry@gmail.com
wrote:

Instead of shelling out to knife each time, could I just require 'Chef',
initialize a few values, and work from there?

You could use Chef as a library. Some people use knife as a library,
which is discouraged because it is a client that uses the chef library
itself, but I understand why.

For something simple like this, you should use 'knife exec'

http://wiki.opscode.com/display/chef/Knife+Exec
Knife one-liners | btm.geek
Knife Reporting: apt + updates | btm.geek

Bryan