boucher 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +19 -0
- data/.gitmodules +3 -0
- data/.rvmrc +2 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +53 -0
- data/LICENSE +9 -0
- data/README.md +82 -0
- data/Rakefile +10 -0
- data/boucher.gemspec +21 -0
- data/lib/boucher/ci.rb +18 -0
- data/lib/boucher/classes.rb +39 -0
- data/lib/boucher/compute.rb +93 -0
- data/lib/boucher/env.rb +46 -0
- data/lib/boucher/io.rb +108 -0
- data/lib/boucher/nagios.rb +50 -0
- data/lib/boucher/provision.rb +121 -0
- data/lib/boucher/servers.rb +92 -0
- data/lib/boucher/storage.rb +43 -0
- data/lib/boucher/tasks/console.rake +21 -0
- data/lib/boucher/tasks/env.rake +42 -0
- data/lib/boucher/tasks/nagios.rake +74 -0
- data/lib/boucher/tasks/servers.rake +127 -0
- data/lib/boucher/tasks/storage.rake +32 -0
- data/lib/boucher/tasks/volumes.rake +14 -0
- data/lib/boucher/tasks.rb +6 -0
- data/lib/boucher/util.rb +9 -0
- data/lib/boucher/volumes.rb +41 -0
- data/spec/boucher/classes_spec.rb +35 -0
- data/spec/boucher/compute_spec.rb +75 -0
- data/spec/boucher/env_spec.rb +47 -0
- data/spec/boucher/io_spec.rb +68 -0
- data/spec/boucher/provision_spec.rb +77 -0
- data/spec/boucher/servers_spec.rb +79 -0
- data/spec/boucher/storage_spec.rb +47 -0
- data/spec/spec_helper.rb +36 -0
- metadata +152 -0
data/.gitignore
ADDED
data/.gitmodules
ADDED
data/.rvmrc
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
builder (3.1.3)
|
5
|
+
coderay (1.0.7)
|
6
|
+
diff-lcs (1.1.3)
|
7
|
+
excon (0.16.3)
|
8
|
+
fog (1.6.0)
|
9
|
+
builder
|
10
|
+
excon (~> 0.14)
|
11
|
+
formatador (~> 0.2.0)
|
12
|
+
mime-types
|
13
|
+
multi_json (~> 1.0)
|
14
|
+
net-scp (~> 1.0.4)
|
15
|
+
net-ssh (>= 2.1.3)
|
16
|
+
nokogiri (~> 1.5.0)
|
17
|
+
ruby-hmac
|
18
|
+
formatador (0.2.3)
|
19
|
+
jruby-pageant (1.1.1)
|
20
|
+
method_source (0.8)
|
21
|
+
mime-types (1.19)
|
22
|
+
multi_json (1.3.6)
|
23
|
+
net-scp (1.0.4)
|
24
|
+
net-ssh (>= 1.99.1)
|
25
|
+
net-ssh (2.6.0)
|
26
|
+
jruby-pageant (>= 1.1.1)
|
27
|
+
nokogiri (1.5.5)
|
28
|
+
pry (0.9.10)
|
29
|
+
coderay (~> 1.0.5)
|
30
|
+
method_source (~> 0.8)
|
31
|
+
slop (~> 3.3.1)
|
32
|
+
rake (0.9.2.2)
|
33
|
+
retryable (1.3.1)
|
34
|
+
rspec (2.11.0)
|
35
|
+
rspec-core (~> 2.11.0)
|
36
|
+
rspec-expectations (~> 2.11.0)
|
37
|
+
rspec-mocks (~> 2.11.0)
|
38
|
+
rspec-core (2.11.1)
|
39
|
+
rspec-expectations (2.11.3)
|
40
|
+
diff-lcs (~> 1.1.3)
|
41
|
+
rspec-mocks (2.11.3)
|
42
|
+
ruby-hmac (0.4.0)
|
43
|
+
slop (3.3.3)
|
44
|
+
|
45
|
+
PLATFORMS
|
46
|
+
ruby
|
47
|
+
|
48
|
+
DEPENDENCIES
|
49
|
+
fog
|
50
|
+
pry
|
51
|
+
rake
|
52
|
+
retryable
|
53
|
+
rspec (~> 2.10)
|
data/LICENSE
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Copyright (c) 2012 8th Light, Inc.
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
<img src="" alt="boucher logo" title="Boucher" align="right"/>
|
2
|
+
# Boucher
|
3
|
+
|
4
|
+
...
|
5
|
+
|
6
|
+
## Getting Started
|
7
|
+
|
8
|
+
|
9
|
+
### Creating a base image
|
10
|
+
|
11
|
+
1. Launch new instance: Ubuntu Server 12.04.1 LTS
|
12
|
+
* Create a new key saved in your infrastructure project
|
13
|
+
* Be sure to add a security group that opens port 22 for SSH
|
14
|
+
|
15
|
+
2. Update config/env/shared.rb
|
16
|
+
* :aws_key_filename - name of the .pem file you just created and saved in the project root
|
17
|
+
* :aws_region - which AWS region did you use?
|
18
|
+
* :aws_access_key_id and aws_secret_access_key - available in the AWS Management Console under Security Credentials
|
19
|
+
|
20
|
+
3. List servers
|
21
|
+
|
22
|
+
rake servers:list
|
23
|
+
|
24
|
+
4. SSH into new server. (:username config must be 'ubunutu' at this point)
|
25
|
+
|
26
|
+
rake servers:ssh[<instance id>]
|
27
|
+
|
28
|
+
5. Create new poweruser (unless you like 'unubutu' as your poweruser).
|
29
|
+
|
30
|
+
sudo adduser <username>
|
31
|
+
sudo adduser <username> sudo
|
32
|
+
sudo mkdir /home/<username>/.ssh
|
33
|
+
sudo cp .ssh/authorized_keys /home/<username>/.ssh/
|
34
|
+
sudo chown -R <username>:<username> /home/<username>/.ssh
|
35
|
+
|
36
|
+
6. Logout. Update config :username. Log back in.
|
37
|
+
|
38
|
+
rake servers:ssh[<instance id>]
|
39
|
+
|
40
|
+
7. Delete the ubuntu user.
|
41
|
+
|
42
|
+
deluser ubuntu
|
43
|
+
|
44
|
+
8. Enable sudo without typing password
|
45
|
+
|
46
|
+
sudo visudo
|
47
|
+
# add the following line at the end of the file:
|
48
|
+
<username> ALL=(ALL) NOPASSWD: ALL
|
49
|
+
|
50
|
+
9. Install required pacakges and gems.
|
51
|
+
|
52
|
+
sudo apt-get update
|
53
|
+
sudo apt-get install ruby1.9.1 ruby1.9.1-dev git gcc make libxml2-dev libxslt1-dev
|
54
|
+
sudo apt-get upgrade
|
55
|
+
sudo gem install bundler chef
|
56
|
+
|
57
|
+
10. Checkout your infrstructure repo. (Yes. You should push your repo even in this early stage.)
|
58
|
+
If you use github, you'll have to generate ssh keys and add them to the github repo.
|
59
|
+
|
60
|
+
cd ~/.ssh
|
61
|
+
ssh-keygen -t rsa -C "your_email@youremail.com"
|
62
|
+
# Copy id_rsa.pub to your github user's ssh keys
|
63
|
+
cd ..
|
64
|
+
git clone git@github.com:<github account name>/<your infratructure project name>.git infrastructure
|
65
|
+
|
66
|
+
10. Customize to your liking.
|
67
|
+
|
68
|
+
* install your preferred vim dot files
|
69
|
+
* etc...
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
## Usage
|
76
|
+
|
77
|
+
...
|
78
|
+
|
79
|
+
## License
|
80
|
+
|
81
|
+
Copyright (c) 2012 8th Light, Inc.
|
82
|
+
MIT License
|
data/Rakefile
ADDED
data/boucher.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "boucher"
|
5
|
+
s.version = "0.1"
|
6
|
+
s.authors = ["'Micah Micah'"]
|
7
|
+
s.email = ["'micah@8thlight.com'"]
|
8
|
+
s.homepage = "http://github.com/8thlight/boucher"
|
9
|
+
s.summary = "AWS system deployment and management"
|
10
|
+
s.description = "AWS system deployment and management"
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
13
|
+
s.executables = []
|
14
|
+
s.require_paths = ["lib"]
|
15
|
+
s.autorequire = 'boucher/tasks'
|
16
|
+
|
17
|
+
s.add_dependency('rake', '>= 0.9.2.2')
|
18
|
+
s.add_dependency('fog', '>= 1.6.0')
|
19
|
+
s.add_dependency('retryable', '>= 1.3.1')
|
20
|
+
s.add_dependency('pry', '>= 0.9.10')
|
21
|
+
end
|
data/lib/boucher/ci.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Boucher
|
2
|
+
module CI
|
3
|
+
def self.each_server(&block)
|
4
|
+
threads = []
|
5
|
+
Boucher.each_required_server do |server, server_class|
|
6
|
+
thread = Thread.new { block.yield(server, server_class) }
|
7
|
+
threads << thread
|
8
|
+
end
|
9
|
+
threads.each { |t| t.join }
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.terminate_server(server_class)
|
13
|
+
server = Boucher.get_server(server_class, "ci", "running")
|
14
|
+
Boucher.change_server_state server.id, :destroy, "terminated" if server
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'boucher/env'
|
2
|
+
require 'boucher/util'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Boucher
|
6
|
+
|
7
|
+
def self.json_to_class(json)
|
8
|
+
parser = JSON.parser.new(json, :symbolize_names => true)
|
9
|
+
config = parser.parse
|
10
|
+
config[:boucher]
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.server_classes
|
14
|
+
if @server_classes.nil?
|
15
|
+
@server_classes = {}
|
16
|
+
Dir.glob(File.join("config", "*.json")).each do |file|
|
17
|
+
spec = json_to_class(IO.read(file))
|
18
|
+
class_name = File.basename(file).to_sym
|
19
|
+
@server_classes[class_name] = spec
|
20
|
+
end
|
21
|
+
end
|
22
|
+
@server_classes
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.classify(server, class_spec)
|
26
|
+
server.image_id = class_spec[:base_image_id] || Boucher::Config[:base_image_id]
|
27
|
+
server.flavor_id = class_spec[:flavor_id] || Boucher::Config[:default_instance_flavor_id]
|
28
|
+
server.groups = class_spec[:groups] || Boucher::Config[:default_instance_groups]
|
29
|
+
server.key_name = class_spec[:key_name] || Boucher::Config[:aws_key_filename]
|
30
|
+
server.tags = {}
|
31
|
+
server.tags["Name"] = "#{class_spec[:class_name] || "base"} #{Time.new.strftime("%Y%m%d%H%M%S")}"
|
32
|
+
server.tags["Class"] = class_spec[:class_name] || "base"
|
33
|
+
server.tags["CreatedAt"] = Time.new.strftime("%Y%m%d%H%M%S")
|
34
|
+
server.tags["Creator"] = current_user
|
35
|
+
server.tags["Env"] = Boucher::Config[:env]
|
36
|
+
server.tags["Volumes"] = class_spec[:volumes]
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'boucher/env'
|
2
|
+
require 'boucher/classes'
|
3
|
+
require 'boucher/io'
|
4
|
+
require 'fog'
|
5
|
+
require 'retryable'
|
6
|
+
|
7
|
+
module Boucher
|
8
|
+
|
9
|
+
EC2_CONFIG = {
|
10
|
+
:provider => 'AWS',
|
11
|
+
:aws_secret_access_key => Boucher::Config[:aws_secret_access_key],
|
12
|
+
:aws_access_key_id => Boucher::Config[:aws_access_key_id],
|
13
|
+
:region => Boucher::Config[:aws_region]
|
14
|
+
}
|
15
|
+
|
16
|
+
def self.compute
|
17
|
+
@compute ||= Fog::Compute.new(EC2_CONFIG)
|
18
|
+
@compute
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.snapshots
|
22
|
+
@snapshots ||= compute.snapshots
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.ssh(server, command=nil)
|
26
|
+
command_arg = nil
|
27
|
+
if command
|
28
|
+
command_arg = "\"#{command}\""
|
29
|
+
end
|
30
|
+
|
31
|
+
command = "#{ssh_command} #{Boucher::Config[:username]}@#{server.dns_name} #{command_arg}"
|
32
|
+
verbose command
|
33
|
+
Kernel.system command
|
34
|
+
raise "command failed with code #{$?.exitstatus}" unless $?.success?
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.ssh_command
|
38
|
+
"ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i #{Boucher::Config[:aws_key_filename]}.pem"
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.download(server, remote_filepath, local_filepath)
|
42
|
+
command = ["rsync", "-azb", "-e", ssh_command, "--delete-after", "#{Boucher::Config[:username]}@#{server.dns_name}:#{remote_filepath}", local_filepath]
|
43
|
+
Kernel.system(*command)
|
44
|
+
raise "command failed with code #{$?.exitstatus}: #{command.inspect}" unless $?.success?
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.rsync(server, from, to)
|
48
|
+
command = ["rsync", "-azb", "-e", ssh_command, "--delete-after",
|
49
|
+
from, "#{Boucher::Config[:username]}@#{server.dns_name}:#{to}"]
|
50
|
+
Kernel.system(*command)
|
51
|
+
raise "command failed with code #{$?.exitstatus}: #{command.inspect}" unless $?.success?
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.update_recipes(server)
|
55
|
+
puts "Updating recipes on #{server.id}"
|
56
|
+
ssh server, "cd infrastructure && git checkout . && git clean -d -f && git pull && bundle"
|
57
|
+
|
58
|
+
%w[cookbooks config tasks].each do |folder|
|
59
|
+
rsync server, "#{folder}/", "infrastructure/#{folder}/"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.cook_meal(server, meal)
|
64
|
+
Boucher::Nagios.remove_host(server)
|
65
|
+
|
66
|
+
update_recipes(server)
|
67
|
+
ssh server, "cd infrastructure && sudo BUTCHER_ENV=#{Boucher::Config[:env]} BRANCH=#{Boucher::Config[:branch]} chef-solo -c config/solo.rb -j config/#{meal}.json"
|
68
|
+
|
69
|
+
Boucher::Nagios.add_host(server)
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.ssh_open?(server)
|
73
|
+
ssh server, "echo 'SSH is open for business!'"
|
74
|
+
true
|
75
|
+
rescue Exception => e
|
76
|
+
false
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.change_server_state(server_id, command, new_state)
|
80
|
+
print "#{command}-ing server #{server_id}..."
|
81
|
+
server = compute.servers.get(server_id)
|
82
|
+
server.send(command.to_sym)
|
83
|
+
server.wait_for { print "."; state == new_state }
|
84
|
+
puts
|
85
|
+
Boucher.print_servers [server]
|
86
|
+
puts
|
87
|
+
puts "The server has been #{command}-ed."
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.find_servers
|
91
|
+
compute.servers
|
92
|
+
end
|
93
|
+
end
|
data/lib/boucher/env.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module Boucher
|
2
|
+
|
3
|
+
Config = {
|
4
|
+
:branch => ENV["BRANCH"] || "master"
|
5
|
+
} unless defined?(Boucher::Config)
|
6
|
+
|
7
|
+
def self.env_name
|
8
|
+
ENV["BUTCHER_ENV"] ? ENV["BUTCHER_ENV"] : :dev
|
9
|
+
end
|
10
|
+
|
11
|
+
env_dir = File.expand_path("config/env")
|
12
|
+
valid_envs = Dir[File.join(env_dir, "**", "*.rb")].map { |path| File.basename(path, ".rb") }
|
13
|
+
env_path = File.expand_path("#{env_name}.rb", env_dir)
|
14
|
+
|
15
|
+
unless defined?(Boucher::NO_LOAD_CONFIG)
|
16
|
+
unless File.exists?(env_path)
|
17
|
+
raise "Config file #{env_path} doesn't exist.\nYou need to change your BUTCHER_ENV environment variable to a valid environment name.\nValid environments: #{valid_envs.join(", ")}"
|
18
|
+
end
|
19
|
+
|
20
|
+
load env_path
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.force_env!(name)
|
24
|
+
env = name.to_sym
|
25
|
+
Boucher::Config[:branch] = ENV["BRANCH"] || "master"
|
26
|
+
load File.expand_path(File.dirname(__FILE__) + "/../../config/env/shared.rb") unless defined?(Boucher::NO_LOAD_CONFIG)
|
27
|
+
file = File.expand_path(File.dirname(__FILE__) + "/../../config/env/#{env}.rb")
|
28
|
+
unless defined?(Boucher::NO_LOAD_CONFIG)
|
29
|
+
if File.exist?(file)
|
30
|
+
load file
|
31
|
+
else
|
32
|
+
require_relative "../../config/env/shared"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.assert_env!
|
38
|
+
unless ENV['BUTCHER_ENV']
|
39
|
+
raise 'BUTCHER_ENV must be set before running this command'
|
40
|
+
end
|
41
|
+
|
42
|
+
unless ENV['BRANCH']
|
43
|
+
raise 'BRANCH must be set before running this command'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/boucher/io.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
module Boucher
|
2
|
+
|
3
|
+
module IO
|
4
|
+
|
5
|
+
def self.mock!
|
6
|
+
$stdout = StringIO.new
|
7
|
+
$stderr = StringIO.new
|
8
|
+
$stdin = StringIO.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.real!
|
12
|
+
$stdout = STDOUT
|
13
|
+
$stderr = STDERR
|
14
|
+
$stdin = STDIN
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.verbose(*args)
|
20
|
+
if ENV["VERBOSE"] != "false"
|
21
|
+
puts *args
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
SERVER_TABLE_FORMAT = "%-12s %-12s %-10s %-10s %-10s %-15s %-15s %-10s\n"
|
26
|
+
|
27
|
+
def self.print_server_table_header
|
28
|
+
puts
|
29
|
+
printf SERVER_TABLE_FORMAT, "ID", "Environment", "Class", "Creator", "State", "Public IP", "Private IP", "Inst. Size"
|
30
|
+
puts ("-" * 120)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.print_server(server)
|
34
|
+
printf SERVER_TABLE_FORMAT,
|
35
|
+
server.id,
|
36
|
+
(server.tags["Env"] || "???")[0...12],
|
37
|
+
(server.tags["Class"] || "???")[0...10],
|
38
|
+
(server.tags["Creator"] || "???")[0...10],
|
39
|
+
server.state,
|
40
|
+
server.public_ip_address,
|
41
|
+
server.private_ip_address,
|
42
|
+
server.flavor_id
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.print_servers(servers)
|
46
|
+
print_server_table_header
|
47
|
+
sorted_servers = servers.sort_by{|s| [s.tags["Env"] || "?",
|
48
|
+
s.tags["Class"] || "?"]}
|
49
|
+
sorted_servers.each do |server|
|
50
|
+
print_server(server) if server
|
51
|
+
end
|
52
|
+
puts
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.print_volumes(volumes)
|
56
|
+
id_sizes = []
|
57
|
+
size_sizes = []
|
58
|
+
state_sizes = []
|
59
|
+
zone_sizes = []
|
60
|
+
snapshot_sizes = []
|
61
|
+
|
62
|
+
Array(volumes).each do |volume|
|
63
|
+
id_sizes << volume.id.length
|
64
|
+
size_sizes << volume.size.to_s.length
|
65
|
+
state_sizes << volume.state.length
|
66
|
+
zone_sizes << volume.availability_zone.length
|
67
|
+
snapshot_sizes << volume.snapshot_id.to_s.length
|
68
|
+
end
|
69
|
+
|
70
|
+
id_length = id_sizes.max + 5
|
71
|
+
size_length = size_sizes.max + 5
|
72
|
+
state_length = state_sizes.max + 5
|
73
|
+
zone_length = zone_sizes.max + 5
|
74
|
+
snapshot_length = snapshot_sizes.max
|
75
|
+
|
76
|
+
puts "ID#{" "*(id_length - 2)}Size#{" "*(size_length - 4)}State#{" "*(state_length - 5)}Zone#{" "*(zone_length - 4)}Snapshot"
|
77
|
+
puts "-"*(id_length + size_length + state_length + zone_length + snapshot_length)
|
78
|
+
|
79
|
+
Array(volumes).each do |volume|
|
80
|
+
puts "#{volume.id}#{" "*(id_length - volume.id.length)}#{volume.size}GB#{" "*(size_length - volume.size.to_s.length - 2)}#{volume.state}#{" "*(state_length - volume.state.length)}#{volume.availability_zone}#{" "*(zone_length - volume.availability_zone.length)}#{volume.snapshot_id}#{" "*(snapshot_length - volume.snapshot_id.to_s.length)}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
FILE_TABLE_FORMAT = "%-60s %-10s %-25s %-32s\n"
|
85
|
+
|
86
|
+
def self.print_file_table_header
|
87
|
+
puts
|
88
|
+
printf FILE_TABLE_FORMAT, "Key", "Size", "Last Modified", "etag"
|
89
|
+
puts ("-" * 150)
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.print_file(file)
|
93
|
+
printf FILE_TABLE_FORMAT,
|
94
|
+
file.key,
|
95
|
+
file.content_length,
|
96
|
+
file.last_modified,
|
97
|
+
file.etag
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.print_files(files)
|
101
|
+
print_file_table_header
|
102
|
+
files.each do |file|
|
103
|
+
print_file(file) if file
|
104
|
+
end
|
105
|
+
puts
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'boucher/servers'
|
2
|
+
require 'boucher/compute'
|
3
|
+
|
4
|
+
module Boucher
|
5
|
+
module Nagios
|
6
|
+
def self.remove_host(host)
|
7
|
+
return if host.tags["Class"] == "nagios_server"
|
8
|
+
|
9
|
+
monitors_for(host.tags["Env"]).each do |monitor|
|
10
|
+
commands = [
|
11
|
+
"cd /home/#{Boucher::Config[:username]}/infrastructure",
|
12
|
+
"sudo rake nagios:remove_host[#{host.id}]",
|
13
|
+
"sudo /etc/init.d/nagios3 restart"
|
14
|
+
]
|
15
|
+
Boucher.ssh(monitor, commands.join(" && "))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.add_host(host)
|
20
|
+
return if checks_for(host.tags["Class"]).empty?
|
21
|
+
|
22
|
+
monitors_for(host.tags["Env"]).each do |monitor|
|
23
|
+
commands = [
|
24
|
+
"cd /home/#{Boucher::Config[:username]}/infrastructure",
|
25
|
+
"sudo rake nagios:add_host[#{host.id},#{host.public_ip_address},#{host.tags["Class"]}]",
|
26
|
+
"sudo /etc/init.d/nagios3 restart"
|
27
|
+
]
|
28
|
+
|
29
|
+
Boucher.ssh(monitor, commands.join(" && "))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.checks_for(server_class)
|
34
|
+
config_path = File.expand_path("../../../config/#{server_class}.json", __FILE__)
|
35
|
+
return [] unless File.exists? config_path
|
36
|
+
server_configuration = JSON.parse(File.read config_path)
|
37
|
+
server_configuration["nagios"] || []
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def self.monitors_for(env)
|
43
|
+
Boucher::Servers.all.select do |monitor|
|
44
|
+
monitor.tags["Class"] == "nagios_server" &&
|
45
|
+
monitor.tags["Env"] == env &&
|
46
|
+
monitor.dns_name
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|