Created
May 11, 2011 00:56
-
-
Save ezmobius/965708 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# chef library for booting a Thin server during the chef-client or chef-solo run | |
# that returns JSON status messages of what the recipes run is currently working on | |
# comes in handy if you have a small tool that pushes recipes with ssh to a server | |
# and runs then, you can use rest-client or something like it to poll the status | |
# server for status, the status server requires a shared secret token during the run | |
# in order to poll it and only runs while the chef client/solo run is going and dies | |
# when the client run is over so its not always on. Also it runs the thin server | |
# within the chef process rather then requiring a whole separate process. | |
# feel free to use this under the MIT license | |
require 'rack' | |
require 'json' | |
require 'pp' | |
module Status | |
class JsonWrap | |
attr_reader :json | |
def initialize(file) | |
@file = file | |
reload | |
reset unless @json && @json['token'] | |
end | |
def save | |
File.open(@file, 'wb') do |f| | |
f.write @json.to_json | |
end | |
end | |
def reset | |
@json = {'status' => "initializing\n", 'token' => StatusServer.token} | |
File.open(@file, 'wb') {|f| f.write @json.to_json } | |
@json | |
end | |
def reload | |
@json = JSON.parse(IO.read(@file)) rescue nil | |
end | |
def method_missing(sym, *args, &blk) | |
@json.send sym, *args, &blk | |
end | |
end | |
class StatusServer | |
def self.token | |
@@token | |
end | |
def self.file | |
@@file | |
end | |
def initialize(host='0.0.0.0', port='80', token=nil) | |
@host, @port, @@token = host, port, token | |
end | |
def run(file='/etc/chef/status.json') | |
@@file = file | |
@db = JsonWrap.new(@@file) | |
@thread = Thread.new { Rack::Handler::Thin.run(::Status::StatusApp.new(@db), :Host => @host, :Port => @port) } | |
end | |
end | |
class StatusApp | |
def initialize(db) | |
@db = db | |
end | |
def call(env) | |
@db.reload | |
req = Rack::Request.new(env) | |
if StatusServer.token == req.params['token'] | |
[200, {'Content-Type' => 'application/json'}, [{:status => @db['status']}.to_json]] | |
else | |
[401, {'Content-Type' => 'application/json'}, [{:status => 'No Token'}.to_json]] | |
end | |
end | |
end | |
class StatusUpdate | |
def self.update(status) | |
@db = JsonWrap.new(StatusServer.file) | |
@db['status'] << "#{status}\n" | |
@db.save | |
end | |
end | |
end | |
def status(status) | |
ruby_block status do | |
block do | |
::Status::StatusUpdate.update(status) | |
end | |
end | |
end | |
def start_status_server(host, port, token) | |
$status_server_thread = VCAP::StatusServer.new(host, port, token).run | |
r = ruby_block "setup chef recipes" do | |
block do | |
::VCAP::StatusUpdate.new('running chef recipes...') | |
end | |
action :nothing | |
end | |
r.run_action(:create) | |
$status_server_thread | |
end | |
def kill_status_server | |
$status_server_thread.kill | |
end | |
# ----------------------------------------- | |
# Usage | |
# ----------------------------------------- | |
# at the beginning of your chef run | |
start_status_server('0.0.0.0', '8080', node[:status_server_token]) | |
# update status throughout your recipes: | |
status('Settting up something mumble mumble....') | |
status('Settting up something else mumble mumble....') | |
status('Settting up yet another mumble mumble....') | |
# at the end of your chef run | |
kill_status_server | |
# meanwhile during the run you can have your client | |
# poll with rest client or somethign else to display status of the run | |
msg = JSON.parse(RestClient.get("http://#{host}:#{port}/?token=#{token}")) | |
puts msg['status'] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment