initial import

This commit is contained in:
2009-12-10 19:09:00 +02:00
commit 21f1be78d6
6 changed files with 369 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.DS_Store

168
lib/skyline/console.rb Normal file
View File

@@ -0,0 +1,168 @@
def load_config
Skyline.load_config
end
def init
Skyline.init
end
def reload
Skyline.init(true)
end
def list(what = nil)
case what
when :all
Skyline.as_groups.each do |name, group|
puts name.to_s
group[:instances].each do |instance|
puts " #{instance[:id].ljust(10)} " +
"#{instance[:public_ip].ljust(15)} " +
"#{instance[:private_ip].ljust(15)} " +
"#{instance[:ami].ljust(10)} " +
"#{instance[:type].ljust(10)} " +
"#{instance[:state].ljust(15)} " +
"#{instance[:launch_date].ljust(15)}"
end
end
when :instances
Skyline.instances.each do |i, instance|
puts " #{instance[:id].ljust(10)} " +
"#{instance[:public_ip].ljust(15)} " +
"#{instance[:private_ip].ljust(15)} " +
"#{instance[:ami].ljust(10)} " +
"#{instance[:type].ljust(10)} " +
"#{instance[:status].ljust(15)} " +
"#{instance[:launch_date].ljust(15)}"
end
else
Skyline.as_groups.each { |name, group| puts name.to_s }
end
return
end
def selected
puts Skyline.selected
end
def cmd(command)
Skyline.cmd(command)
end
def icmd
if Skyline.selected.nil?
puts "ERROR: No AS Group selected. Please use"
puts "the \"use\" command to select one."
return nil
end
exit = false
started = false
while !exit
if !started
puts "Entering interactive remote-terminal mode."
puts ""
puts "All entered commands are executed on all remote"
puts "instances within selected auto-scaling group."
puts ""
puts "Type \"exit\"\" or \"halt\"\" to exit IRT mode."
puts ""
started = true
end
print "irt$ "
input = STDIN.readline.strip
if !input.nil? && input != ""
if input =~ /^exit|halt$/
exit = true
else
cmd(input)
end
end
end
end
def use
groups = ["All"] + Skyline.as_groups.map { |name, group| name }
valid_choice = false
while !valid_choice
puts "Please choose a group to use:"
groups.each_with_index { |group, i| puts "#{i}. #{group}" }
print "Enter your choice (0-9) or press Ctrl-C to abort: "
s = STDIN.readline.strip
s = (s =~ /^[\d]+$/) ? s.to_i : nil
if !s.nil? && !groups[s].nil?
valid_choice = true
groups[0] = :all if s == 0
puts groups[s].inspect
return Skyline.use(groups[s])
else
puts "\nERROR: Not a valid choice\n\n"
end
end
end
def help_me
cmds = [
[:reload, "Force-reload instance and AutoScaling Group info."],
[:list, <<-hd
List loaded information. Options are:
:all List AS Groups with instances.
:instances List all instances in your EC2 account.
hd
],
[:use, "Call without any arguments to choose which AS Group to work with."],
[:cmd, "Run a command on all selected remote machines."],
[:icmd, "Enter an interactive shell which runs entered commands on selected remote machines."]
]
puts "Available Skyline commands:"
cmds.each do |cmd, desc|
print " #{cmd.to_s.ljust(10)} "
desc = desc.split("\n")
if desc.size == 1
puts desc[0]
else
puts desc.shift
desc.each do |line|
puts " #{line}"
end
end
end
return
end
#
# Skyhook related commands
#
def skyhook(command)
cmd("skyhook #{command}")
end
def update(project = nil, rev = nil)
if project.nil?
puts "Please specify a project."
return
end
rev = rev.gsub(/[^0-9]/, "") if rev.is_a?(String)
commands = [
[ "skyhook update",
"Updating Skyhook on remote machines..." ],
[ "skyhook update.#{project} #{rev}",
"Fetching latest files for #{project} project on remote machines..." ],
[ "skyhook mode +maintenance",
"Putting remote machines in maintenance mode..." ],
[ "skyhook activate.#{project} #{rev}",
"Activating newly fetched version of #{project} on remote machines..." ],
[ "skyhook mode -maintenance",
"Disabling maintenance mode on remote machines" ]
]
commands.each do |command|
puts command[1] if !command[1].nil?
if !command[0].nil?
puts " Executing: #{command[0]}"
cmd command[0]
end
end
return
end

182
lib/skyline/skyline.rb Normal file
View File

@@ -0,0 +1,182 @@
require "rubygems"
require "yaml"
require "scanf"
class Skyline
@as_groups = {}
@instances = {}
@selected = nil
@config = {}
class << self
attr_accessor :as_groups
attr_accessor :instances
attr_accessor :selected
attr_accessor :config
end
def self.load_config
if File.exist?("skyline_config.yml")
@config = YAML.load_file("skyline_config.yml")
return true
end
return false
end
def self.init(force = false)
get_instances if @instances.size == 0 || force
get_as_groups if @as_groups.size == 0 || force
return
end
def self.use(group = nil)
if !group.nil?
if @as_groups.has_key?(group.to_s)
@selected = group.to_s
puts "Selected AutoScaling group: #{group}"
return true
elsif group == :all
@selected = :all
puts "NOTICE: You have selected all AutoScaling groups"
return true
else
puts "ERROR: AutoScaling group #{group} doesn't seem to exist"
return false
end
end
end
def self.cmd(command)
ssh_key = ""
ssh_key = "-i " + @config["ssh_key"] if @config.has_key?("ssh_key") && !@config["ssh_key"].nil?
template = "ssh #{ssh_key} root@{REMOTE_IP} " +
"\"export PATH=\\\"/opt/ruby-enterprise/bin:$PATH\\\"; {CMD}\""
cmds = []
if @selected.nil?
puts "ERROR: No AS Group selected."
return
end
@as_groups.each do |name, group|
if @selected.to_s == name.to_s || @selected == :all
group[:instances].each do |instance|
if instance[:state] == "InService" && !instance[:public_ip].nil?
cmds << template.gsub("{REMOTE_IP}", instance[:public_ip]).gsub("{CMD}", command.gsub(/(")/, "\\\\\\1"))
end
end
end
end
if cmds.size > 0
puts "\nRunning command on all machines"
self.call_parallel(cmds) do |results|
results.each do |result|
puts "------------------------------------------"
puts " Command: #{result[0]}"
puts " Exit code: #{result[2].to_i}"
puts " Output: "
puts "#{result[1]}"
end
puts "------------------------------------------"
end
else
puts "No machines available under current AS Group."
end
return
end
def self.call_parallel(cmds = [], check_interval = nil)
if cmds.size > 0
threads, results = [], []
cmds.each do |cmd|
threads << Thread.new { results << [cmd, `#{cmd}`, $?] }
end
is_done = false
check_interval = 0.2 if check_interval.nil?
while is_done == false do
sleep check_interval
done = true
threads.each { |thread| done = false if thread.status != false }
is_done = true if done
end
yield(results)
end
end
def self.get_instances
print "Loading EC2 instance information. "
raw = `ec2-describe-instances`
if raw =~ /service error/i
puts "ERROR: EC2 Service error."
return false
end
lines = raw.split("\n")
lines.each do |line|
line = line.strip.split(/\s/)
if line[0].downcase == "instance" && !line[5].nil? && line[5].downcase == "running"
@instances[line[1]] = {
:id => line[1], :ami => line[2], :public_dns => line[3], :private_dns => line[4],
:status => line[5], :ssh_key => line[6], :idx => line[7], :type => line[9],
:launch_date => line[10], :zone => line[11], :aki => line[12], :ari => line[13],
:monitoring => (line[15] == "monitoring-enabled") ? true : false,
:public_ip => line[16], :private_ip => line[17],
}
end
end
puts "DONE."
return
end
def self.get_as_groups
print "Loading EC2 AutoScaling Groups information. "
if @instances.size == 0
puts "ERROR: Instances not loaded, or no running instances."
return false
end
raw = `as-describe-auto-scaling-groups`
if raw =~ /service error/i
puts "ERROR: EC2 Service error"
return false
end
raw = raw.strip.split("AUTO-SCALING-GROUP")
raw.delete("")
raw.each do |group|
lines = group.split("\n")
head = lines.shift.strip.split(/\s+/)
instances = []
lines.each do |line|
line = line.split(/\s+/)
instance = {
:id => line[1],
:group => line[2],
:zone => line[3],
:state => line[4],
:public_ip => nil, :private_ip => nil, :ami => nil, :type => nil,
:status => nil, :ssh_key => nil, :public_dns => nil,
:private_dns => nil, :launch_date => nil
}
if !@instances[line[1]].nil?
instance = instance.merge({
:public_ip => @instances[line[1]][:public_ip],
:private_ip => @instances[line[1]][:private_ip],
:ami => @instances[line[1]][:ami],
:type => @instances[line[1]][:type],
:status => @instances[line[1]][:status],
:ssh_key => @instances[line[1]][:ssh_key],
:public_dns => @instances[line[1]][:public_dns],
:private_dns => @instances[line[1]][:private_dns],
:launch_date => @instances[line[1]][:launch_date]
})
end
instances << instance
end
@as_groups[head[0]] = {
:name => head[0], :launch_config => head[1], :zone => head[2], :load_balancer => head[3],
:min_size => head[4], :max_size => head[5], :current_size => head[6],
:instances => instances
}
end
puts "DONE."
return
end
end

14
lib/skyline_console.rb Normal file
View File

@@ -0,0 +1,14 @@
require "skyline/skyline"
require "skyline/console"
load_config
# init
puts <<-hd
Welcome to the Skyline console.
Available commands are:
list, use, cmd, icmd, reload and help_me.
hd

2
skyline Executable file
View File

@@ -0,0 +1,2 @@
#! /usr/bin/env ruby
exec "irb -rubygems -I lib --simple-prompt -r skyline_console.rb"

1
skyline_config.yml Normal file
View File

@@ -0,0 +1 @@
ssh_key: ~/.ec2/kp_jimeh_default