initial import

This commit is contained in:
2009-12-10 20:45:56 +02:00
commit 14f518ce91
44 changed files with 1867 additions and 0 deletions

92
init/lib/skyhook.rb Normal file
View File

@@ -0,0 +1,92 @@
##
# Skyhook Services - Libraries
##
require "yaml"
require "fileutils"
require "lib/skyhook/utils"
require "lib/skyhook/utils/initd"
require "lib/skyhook/utils/monit"
require "lib/skyhook/utils/nginx"
require "lib/skyhook/utils/object_overloads"
require "lib/skyhook/utils/svn"
require "lib/skyhook/project"
require "lib/skyhook/projects"
require "lib/skyhook/action"
require "lib/skyhook/mode"
class Skyhook
@info = {}
class << self
attr_accessor :info
end
def self.start
save_status if !load_status
if !@info.nil? && (!@info.has_key?(:booted) || @info[:booted] != true)
save_status({:booted => true})
end
if !Nginx.restore_enabled
Nginx.ensite("projects")
Nginx.ensite("default")
Nginx.ensite("monit-status")
end
Projects.boot
Action.perms :ensure
puts "Starting Skyhook services."
Initd.monit :start
sleep 1
Monit.start :all
sleep 1
Projects.start
write_status(1)
end
def self.stop
puts "Stopping Skyhook services."
Projects.stop
Monit.stop :all
sleep 1
Initd.monit :stop
write_status(0)
end
def self.restart
puts "Restarting Skyhook services."
Projects.restart
Monit.restart :all
sleep 1
Initd.monit :restart
end
def self.status
if File.exist?($status_file)
puts "Skyhook services are running."
else
puts "Skyhook services are not running."
end
end
def self.method_missing(method, *args)
call = (args.size > 0) ? args.shift : nil
Action.send(method, call, *args)
end
def self.load_status
if File.exist?("#{$skyhook_root}/init/status.yml")
@info = YAML.load_file("#{$skyhook_root}/init/status.yml")
return true
end
return false
end
def self.save_status(input = {})
@info = @info.merge(input)
File.open("#{$skyhook_root}/init/status.yml", "w") do |f|
YAML.dump(@info, f)
end
end
end

View File

@@ -0,0 +1,32 @@
class Action
@list = {}
class << self
attr_accessor :list
end
def default
puts "no default action defined"
end
def self.method_missing(action, call = nil, *args)
if @list.has_key?(action)
call = :default if call.nil?
@list[action].send(call, *args) rescue return false
return true
end
return false
end
def self.load
Dir.glob("#{$actions_config_path}/*.rb").each do |item|
item = item.gsub(/^.*\/(.*?)\.rb/, "\\1")
require "actions/#{item}"
@list[item.to_sym] = "#{item}Action".camelize.constantize.new
end
end
end
Action.load

102
init/lib/skyhook/mode.rb Normal file
View File

@@ -0,0 +1,102 @@
class Mode
@list = {}
@status = {}
class << self
attr_accessor :list
attr_reader :status
end
def self.enable(*args)
self.switch(:enable, *args)
end
def self.disable(*args)
self.switch(:disable, *args)
end
def self.switch(state, *args)
if args.size > 0
ret = true
result = nil
args.each do |mode|
if @list.has_key?(mode.to_sym)
if (state == :enable && !@status[mode.to_s]) || (state == :disable && @status[mode.to_s])
self.display_switch(mode, state)
result = @list[mode.to_sym].send(state) if @list[mode.to_sym].respond_to?(state)
ret = false if result == false
@status[mode.to_s] = (state == :enable) ? true : false
else
self.display_no_switch(mode, state)
end
else
self.display_not_found(mode)
end
end
self.save_status
return ret
end
end
def self.do(options = nil)
if !options.nil?
if options.is_a?(String)
options = options.split(" ")
end
if options.is_a?(Array)
options.each do |option|
if option =~ /([\-\+])([a-z0-9]+)/
state = ($1 == "+") ? :enable : :disable
mode = $2.to_sym
self.switch(state, mode)
end
end
end
end
end
def self.load_status
if File.exist?("#{$modes_config_path}/status.yml")
@status = YAML.load_file("#{$modes_config_path}/status.yml")
return true
end
return false
end
def self.save_status(input = {})
@status = @status.merge(input)
File.open("#{$modes_config_path}/status.yml", "w") do |f|
YAML.dump(@status, f)
end
end
def self.display_switch(mode, state)
msg = (state == :enable) ? "Enabling" : "Disabling"
puts "#{msg} #{mode.to_s.camelize} mode"
end
def self.display_no_switch(mode, state)
msg = (state == :enable) ? "enabled" : "disabled"
puts "#{mode.to_s.camelize} mode is already #{msg}"
end
def self.display_not_found(mode)
puts "ERROR: #{mode.to_s.camelize} mode does not exist"
end
def self.load
self.save_status if !self.load_status
Dir.glob("#{$modes_config_path}/*.rb").each do |item|
item = item.gsub(/^.*\/(.*?)\.rb/, "\\1")
require "modes/#{item}"
@list[item.to_sym] = "#{item}Mode".camelize.constantize.new
@status[item.to_s] = false if !@status.has_key?(item.to_s)
end
self.save_status
end
end
Mode.load

136
init/lib/skyhook/project.rb Normal file
View File

@@ -0,0 +1,136 @@
class Project
attr_reader :name
attr_reader :path
attr_reader :repo
attr_reader :revision
attr_reader :status
def initialize
@status = {} if @status.nil?
if File.exist?(@path)
save_status if !load_status
end
end
def active
@status["active"] if @status.has_key?("active")
end
def boot
init
checkout
activate
end
def update(*args)
checkout(*args)
end
# def restart
# shell "touch #{@path}/r#{@status[:active]}/tmp/restart.txt"
# end
def init
if !File.exist?(@path)
shell "mkdir -p #{@path}"
end
if File.exist?("#{$projects_config_path}/#{@name}.conf")
shell "rm #{$nginx_projects_config_path}/#{@name}.conf" if File.exist?("#{$nginx_projects_config_path}/#{@name}.conf")
shell "cp #{$projects_config_path}/#{@name}.conf #{$nginx_projects_config_path}/#{@name}.conf"
end
end
def has_latest?
versions = get_available_versions
if !@revision.nil? && versions.include?(@revision)
return true
end
head = SVN.last_changed_rev(@repo)
if !@status.has_key?("head") || @status["head"].nil? || @status["head"] != head
save_status("head" => head)
end
if !versions.include?(head)
return false
end
return true
end
def checkout(rev = nil)
if File.exist?(@path)
has_latest?
rev = @revision if rev.nil? && !@revision.nil?
version = (rev.nil? || rev.to_i > @status["head"] || rev.to_s.downcase == "head") ? @status["head"] : rev.to_i
if !version.nil?
rev_path = "#{@path}/r#{version}"
if !File.exist?(rev_path)
SVN.export @repo, rev_path, version
return true
end
return nil
end
end
return false
end
def activate(rev = nil)
versions = get_available_versions
version = nil
if rev.nil? && !@revision.nil?
version = @revision
elsif rev.to_s.downcase == "head" || rev.nil?
version = versions.last
elsif versions.include?(rev.to_i)
version = rev.to_i
else
version = versions.last
end
active = (@status.has_key?("active")) ? @status["active"] : nil
return nil if version == active
if !version.nil?
shell "rm #{@path}/htdocs" if File.exist?("#{@path}/htdocs")
shell "ln -s r#{version} #{@path}/htdocs"
save_status("active" => version)
return true
end
return false
end
def clean
leave = 5 # number of version copies to keep
versions = get_available_versions
keep = []
keep << @revision if !@revision.nil?
keep << active if !active.nil? && !keep.include?(active)
(leave-keep.size).times { versions.pop }
versions.each do |version|
if !keep.include?(version)
shell "rm -rf #{@path}/r#{version}"
end
end
end
def load_status
if File.exist?("#{@path}/status.yml")
@status = YAML.load_file("#{@path}/status.yml")
return true
end
return false
end
def save_status(input = {})
@status = @status.merge(input)
File.open("#{@path}/status.yml", "w") do |f|
YAML.dump(@status, f)
end
end
def get_available_versions
dirs = []
Dir.glob("#{@path}/r*").each do |item|
dirs << $1.to_i if item =~ /^.*\/r(\d+)$/
end
return dirs.sort
end
end

View File

@@ -0,0 +1,86 @@
##
# Skyhook Services - Require projects
##
class Projects
@list = {}
class << self
attr_accessor :list
end
def self.method_missing(method, *args)
if @list.has_key?(method)
return @list[method]
else
return self.do(method, *args)
end
end
def self.checkout(*args)
if args.size > 0
return self.do_on_projects(*(args << :update))
else
return self.do(:update)
end
end
def self.activate(*args)
if args.size > 0
return self.do_on_projects(*(args << :activate))
else
return self.do(:activate)
end
end
def self.has_latest?(*args)
ret = self.do_on_projects(*(args << :has_latest?))
puts (ret) ? "yes" : "no"
return ret
end
def self.load
Dir.glob("#{$projects_config_path}/*.rb").each do |item|
item = item.gsub(/^.*\/(.*?)\.rb/, "\\1")
require "projects/#{item}"
@list[item.to_sym] = "#{item}Project".camelize.constantize.new
end
end
private
def self.do(what, *args)
ret = true
result = nil
@list.each do |name, project|
result = project.send(what, *args) if project.respond_to?(what)
ret = false if result == false
end
return ret
end
def self.do_on_projects(*args)
if args.size > 0
method = args.pop.to_sym
if args.size > 0
ret = true
result = nil
args.each do |item|
if @list.has_key?(item.to_sym)
result = @list[item.to_sym].send(method)
ret = false if result == false
end
end
return ret
else
return self.do(method)
end
end
end
end
Projects.load

18
init/lib/skyhook/utils.rb Normal file
View File

@@ -0,0 +1,18 @@
# utility methods
def shell(*args)
if $debug.nil? || $debug > 1
send(:system, *args)
else
puts "DEBUG: " + args.join(" ")
end
end
def write_status(status)
case status
when 1
shell "echo '1' > #{$status_file}"
when 0
shell "rm #{$status_file}"
end
end

View File

@@ -0,0 +1,11 @@
class Initd
def self.method_missing(service, *args)
if $debug.nil? || $debug <= 1
shell "/etc/init.d/#{service.to_s} " + args.map { |i| i.to_s }.join(" ") if File.exist?("/etc/init.d/#{service.to_s}")
else
puts "DEBUG: /etc/init.d/#{service.to_s} " + args.map { |i| i.to_s }.join(" ")
end
end
end

View File

@@ -0,0 +1,11 @@
class Monit
def self.method_missing(cmd, *args)
if $debug.nil? || $debug <= 1
shell "monit #{cmd.to_s} " + args.map { |i| i.to_s }.join(" ")
else
puts "DEBUG: monit #{cmd.to_s} " + args.map { |i| i.to_s }.join(" ")
end
end
end

View File

@@ -0,0 +1,67 @@
class Nginx
@sites_enabled = []
@nginx_conf = "#{$nginx_config_path}"
@available_path = "#{@nginx_conf}/sites-available"
@enabled_path = "#{@nginx_conf}/sites-enabled"
class << self
attr_accessor :sites_enabled
attr_accessor :nginx_conf
attr_accessor :available
attr_accessor :enabled
end
def self.restore_enabled
if @sites_enabled.size > 0
@sites_enabled.each do |site|
self.ensite(site)
end
return true
end
return false
end
def self.ensite(site)
if File.exist?("#{@available_path}/#{site.to_s}")
self.dissite(site)
if $debug.nil? || $debug <= 1
shell "ln -s \"#{@available_path}/#{site.to_s}\" \"#{@enabled_path}/#{site.to_s}\""
@sites_enabled << site.to_s
self.save_status
else
puts "DEBUG: ln -s \"#{@available_path}/#{site.to_s}\" \"#{@enabled_path}/#{site.to_s}\""
end
end
end
def self.dissite(site)
if File.exist?("#{@enabled_path}/#{site.to_s}")
if $debug.nil? || $debug <= 1
shell "rm \"#{@enabled_path}/#{site.to_s}\""
@sites_enabled.delete(site.to_s)
self.save_status
else
puts "DEBUG: rm \"#{@enabled_path}/#{site.to_s}\""
end
end
end
def self.load_status
if File.exist?("#{$skyhook_root}/init/sites-enabled.yml")
@sites_enabled = YAML.load_file("#{$skyhook_root}/init/sites-enabled.yml")
return true
end
return false
end
def self.save_status(input = [])
@sites_enabled = @sites_enabled + input
File.open("#{$skyhook_root}/init/sites-enabled.yml", "w") do |f|
YAML.dump(@sites_enabled, f)
end
end
end
Nginx.save_status if !Nginx.load_status

View File

@@ -0,0 +1,26 @@
class Object
def constantize
unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ self
raise NameError, "#{self.inspect} is not a valid constant name!"
end
Object.module_eval("::#{$1}", __FILE__, __LINE__)
end
def camelize(first_letter_in_uppercase = true)
if first_letter_in_uppercase
self.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
else
self.first + camelize(lower_case_and_underscored_word)[1..-1]
end
end
def underscore
self.to_s.gsub(/::/, '/').
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').
tr("-", "_").
downcase
end
end

View File

@@ -0,0 +1,52 @@
class SVN
def self.checkout(repo, target = "", revision = nil)
self.checkout_or_export(:checkout, repo, target, revision)
end
def self.co(repo, target = "", revision = nil)
self.checkout_or_export(:co, repo, target, revision)
end
def self.export(repo, target = "", revision = nil)
self.checkout_or_export(:export, repo, target, revision)
end
def self.up(revision = nil, target = "")
rev = parse_revision(revision)
shell "svn up #{rev} #{target}"
end
def self.revision(repo)
self.info(repo)["Revision"].to_i
end
def self.last_changed_rev(repo)
self.info(repo)["Last Changed Rev"].to_i
end
def self.info(path)
data = `svn info #{path}`.split(/\n\r|\n|\r/)
info = {}
data.each do |item|
info[$1.strip] = $2.strip if item =~ /(.+?)\:(.+)/
end
return info
end
private
def self.checkout_or_export(method, repo, target = "", revision = nil)
if ["export", "co", "checkout"].include?(method.to_s)
rev = parse_revision(revision)
shell "svn #{method.to_s} #{rev} #{repo} #{target}"
return true
end
return false
end
def self.parse_revision(revision)
(!revision.to_s.match(/^\d+$/).nil?) ? "-r#{revision.to_s.match(/^\d+$/).to_s}" : ""
end
end