Skip to content

Instantly share code, notes, and snippets.

@kamal
Created November 3, 2009 14:49
Show Gist options
  • Save kamal/225092 to your computer and use it in GitHub Desktop.
Save kamal/225092 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
#
# Create a custom chef index for deb packages on the system
require "rubygems"
require "chef"
require "chef/rest"
require "open4"
require "ohai"
class DpkgIndexer
DESIRED = {"u" => "unknown", "i" => "install", "r" => "remove", "p" => "purge", "h" => "hold"}
STATUS = {"n" => "not-installed", "i" => "installed", "c" => "config-files", "u" => "unpacked", "f" => "failed-config", "h" => "half-installed", "w" => "triggers-awaited", "t" => "triggers-pending"}
ERROR = {" " => nil, "h" => "hold", "r" => "reinst-required", "x" => "both-problems"}
def initialize
Chef::Config.from_file("/etc/chef/client.rb")
@rest = Chef::REST.new(Chef::Config[:registration_url])
end
def run
start_time = Time.now
register
authenticate
index
unless @status.exitstatus == 0 || @status.exitstatus == 1
raise Chef::Exceptions::Package, "dpkg -l failed - #{status.inspect}!"
end
end_time = Time.now
Chef::Log.info("Chef Run complete in #{end_time - start_time} seconds")
end
private
def index
@status = Open4::popen4("dpkg -l") do |pid, stdin, stdout, stderr|
stdout.each do |line|
if pkginfo = /^([uirph])([nicufhwt])([\ hrx])\s+([a-z\d\-\+]+)\s+([\w\d.-]+)\s+.*$/.match(line)
@rest.post_rest("search/dpkg/entries",
{
:id => pkginfo[4],
:desired => DESIRED[pkginfo[1]],
:status => STATUS[pkginfo[2]],
:error => ERROR[pkginfo[3]],
:name => pkginfo[4],
:version => pkginfo[5]
}
)
end
end
end
end
# Everything below is copied wholesale from lib/chef/client.rb
def run_ohai
@ohai ||= Ohai::System.new
if @ohai.keys
@ohai.refresh_plugins
else
@ohai.all_plugins
end
end
def authenticate
determine_node_name unless @node_name
Chef::Log.debug("Authenticating #{@safe_name} via openid")
response = @rest.post_rest('openid/consumer/start', {
"openid_identifier" => "#{Chef::Config[:openid_url]}/openid/server/node/#{@safe_name}",
"submit" => "Verify"
})
@rest.post_rest(
"#{Chef::Config[:openid_url]}#{response["action"]}",
{ "password" => @secret }
)
end
def determine_node_name
run_ohai
unless @safe_name && @node_name
@node_name ||= @ohai[:fqdn] ? @ohai[:fqdn] : @ohai[:hostname]
@safe_name = @node_name.gsub(/\./, '_')
end
@node_name
end
def register
determine_node_name unless @node_name
Chef::Log.debug("Registering #{@safe_name} for an openid")
begin
if @rest.get_rest("registrations/#{@safe_name}")
@secret = Chef::FileCache.load(File.join("registration", @safe_name))
end
rescue Net::HTTPServerException => e
case e.message
when /^404/
create_registration
else
raise
end
rescue Chef::Exceptions::FileNotFound
Chef::Application.fatal! "A remote registration already exists for #{@safe_name}, however the local shared secret does not exist." +
" To remedy this, you could delete the registration via webUI/REST, change the node_name option in config.rb" +
" (or use the -N/--node-name option to the CLI) or" +
" copy the old shared secret to #{File.join(Chef::Config[:file_cache_path], 'registration', @safe_name)}", 3
end
true
end
def create_registration
@secret = random_password(500)
Chef::FileCache.store(File.join("registration", @safe_name), @secret)
@rest.post_rest("registrations", { :id => @safe_name, :password => @secret, :validation_token => @validation_token })
true
end
protected
# Generates a random password of "len" length.
def random_password(len)
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
newpass = ""
1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
newpass
end
end
DpkgIndexer.new.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment