boucher 0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -63,18 +63,16 @@ If you use github, you'll have to generate ssh keys and add them to the github r
63
63
  cd ..
64
64
  git clone git@github.com:<github account name>/<your infratructure project name>.git infrastructure
65
65
 
66
- 10. Customize to your liking.
66
+ 11. Customize to your liking.
67
67
 
68
68
  * install your preferred vim dot files
69
69
  * etc...
70
70
 
71
-
72
-
73
-
74
-
75
71
  ## Usage
76
72
 
77
- ...
73
+ Run rake to see the list of tasks provided.
74
+
75
+ rake -T
78
76
 
79
77
  ## License
80
78
 
data/Rakefile CHANGED
@@ -8,3 +8,10 @@ end
8
8
 
9
9
  desc "Default: run the specs."
10
10
  task :default => :spec
11
+
12
+ desc "Push gem to rubygems.org"
13
+ task :push do
14
+ system "rm boucher-*.gem"
15
+ system "gem build boucher.gemspec"
16
+ system "gem push boucher-*.gem"
17
+ end
data/boucher.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "boucher"
5
- s.version = "0.1"
5
+ s.version = "0.1.1"
6
6
  s.authors = ["'Micah Micah'"]
7
7
  s.email = ["'micah@8thlight.com'"]
8
8
  s.homepage = "http://github.com/8thlight/boucher"
@@ -1,5 +1,5 @@
1
1
  require 'boucher/env'
2
- require 'boucher/classes'
2
+ require 'boucher/meals'
3
3
  require 'boucher/io'
4
4
  require 'fog'
5
5
  require 'retryable'
@@ -38,35 +38,14 @@ module Boucher
38
38
  "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i #{Boucher::Config[:aws_key_filename]}.pem"
39
39
  end
40
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
41
  def self.update_recipes(server)
55
42
  puts "Updating recipes on #{server.id}"
56
43
  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
44
  end
62
45
 
63
- def self.cook_meal(server, meal)
64
- Boucher::Nagios.remove_host(server)
65
-
46
+ def self.cook_meal(server, meal_name)
66
47
  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)
48
+ ssh server, "cd infrastructure && sudo BUTCHER_ENV=#{Boucher::Config[:env]} BRANCH=#{Boucher::Config[:branch]} chef-solo -c config/solo.rb -j config/#{meal_name}.json"
70
49
  end
71
50
 
72
51
  def self.ssh_open?(server)
data/lib/boucher/env.rb CHANGED
@@ -38,9 +38,5 @@ module Boucher
38
38
  unless ENV['BUTCHER_ENV']
39
39
  raise 'BUTCHER_ENV must be set before running this command'
40
40
  end
41
-
42
- unless ENV['BRANCH']
43
- raise 'BRANCH must be set before running this command'
44
- end
45
41
  end
46
42
  end
data/lib/boucher/io.rb CHANGED
@@ -17,7 +17,7 @@ module Boucher
17
17
  end
18
18
 
19
19
  def self.verbose(*args)
20
- if ENV["VERBOSE"] != "false"
20
+ if ENV["VERBOSE"]
21
21
  puts *args
22
22
  end
23
23
  end
@@ -26,7 +26,7 @@ module Boucher
26
26
 
27
27
  def self.print_server_table_header
28
28
  puts
29
- printf SERVER_TABLE_FORMAT, "ID", "Environment", "Class", "Creator", "State", "Public IP", "Private IP", "Inst. Size"
29
+ printf SERVER_TABLE_FORMAT, "ID", "Environment", "Meal", "Creator", "State", "Public IP", "Private IP", "Inst. Size"
30
30
  puts ("-" * 120)
31
31
  end
32
32
 
@@ -34,7 +34,7 @@ module Boucher
34
34
  printf SERVER_TABLE_FORMAT,
35
35
  server.id,
36
36
  (server.tags["Env"] || "???")[0...12],
37
- (server.tags["Class"] || "???")[0...10],
37
+ (server.tags["Meal"] || "???")[0...10],
38
38
  (server.tags["Creator"] || "???")[0...10],
39
39
  server.state,
40
40
  server.public_ip_address,
@@ -45,7 +45,7 @@ module Boucher
45
45
  def self.print_servers(servers)
46
46
  print_server_table_header
47
47
  sorted_servers = servers.sort_by{|s| [s.tags["Env"] || "?",
48
- s.tags["Class"] || "?"]}
48
+ s.tags["Meal"] || "?"]}
49
49
  sorted_servers.each do |server|
50
50
  print_server(server) if server
51
51
  end
@@ -0,0 +1,45 @@
1
+ require 'boucher/env'
2
+ require 'boucher/util'
3
+ require 'json'
4
+
5
+ module Boucher
6
+
7
+ def self.json_to_meal(json)
8
+ parser = JSON.parser.new(json, :symbolize_names => true)
9
+ config = parser.parse
10
+ config[:boucher] || {}
11
+ end
12
+
13
+ def self.meals
14
+ if @meals.nil?
15
+ @meals = {}
16
+ Dir.glob(File.join("config", "*.json")).each do |file|
17
+ spec = json_to_meal(::IO.read(file))
18
+ meal_name = File.basename(file)[0...-5].to_sym
19
+ @meals[meal_name] = spec.merge(:name => meal_name)
20
+ end
21
+ end
22
+ @meals
23
+ end
24
+
25
+ def self.meal(meal_name)
26
+ the_meal = meals[meal_name.to_sym]
27
+ raise "Missing meal: #{mean_name}" unless the_meal
28
+ return the_meal
29
+ end
30
+
31
+ def self.setup_meal(server, meal)
32
+ server.image_id = meal[:base_image_id] || Boucher::Config[:base_image_id]
33
+ server.flavor_id = meal[:flavor_id] || Boucher::Config[:default_instance_flavor_id]
34
+ server.groups = meal[:groups] || Boucher::Config[:default_instance_groups]
35
+ server.key_name = meal[:key_name] || Boucher::Config[:aws_key_filename]
36
+ server.tags = {}
37
+ server.tags["Name"] = "#{meal[:meal_name] || "base"} #{Time.new.strftime("%Y%m%d%H%M%S")}"
38
+ server.tags["Meal"] = meal[:meal_name] || "base"
39
+ server.tags["CreatedAt"] = Time.new.strftime("%Y%m%d%H%M%S")
40
+ server.tags["Creator"] = current_user
41
+ server.tags["Env"] = Boucher::Config[:env]
42
+ server.tags["Volumes"] = meal[:volumes]
43
+ end
44
+
45
+ end
@@ -2,82 +2,61 @@ require 'boucher/compute'
2
2
  require 'boucher/io'
3
3
  require 'boucher/servers'
4
4
  require 'boucher/volumes'
5
- require 'boucher/nagios'
6
5
  require 'retryable'
7
6
 
8
7
  module Boucher
9
- def self.each_required_server(&block)
10
- Boucher::Config[:servers].each do |server_class|
11
- server = find_server(server_class, Boucher::Config[:env])
12
- block.yield(server, server_class)
13
- end
14
- end
15
8
 
16
- def self.get_server(server_class, environment, state)
9
+ def self.get_server(meal, environment, state)
17
10
  begin
18
- Boucher::Servers.find(:env => environment.to_s, :class => server_class, :state => state)
11
+ Boucher::Servers.find(:env => environment.to_s, :meal => meal, :state => state)
19
12
  rescue Boucher::Servers::NotFound
20
13
  nil
21
14
  end
22
15
  end
23
16
 
24
- def self.find_server(server_class, environment)
25
- get_server(server_class, environment, "stopped") || get_server(server_class, environment, "running")
26
- end
27
-
28
- def self.establish_all_servers
29
- Boucher.each_required_server do |server, server_class|
30
- # Retries after 2, 4, 8, 16, 32, and 64 seconds
31
- retryable(:tries => 6, :sleep => lambda { |n| 2**n }) do
32
- # A RuntimeError will sometimes be thrown here, with a message of:
33
- # "command failed with code 255"
34
- Boucher.establish_server(server, server_class)
35
- end
36
- end
17
+ def self.find_server(meal, environment)
18
+ get_server(meal, environment, "stopped") || get_server(meal, environment, "running")
37
19
  end
38
20
 
39
- def self.establish_server(server, server_class)
21
+ def self.establish_server(server, meal_name)
22
+ meal = Boucher.meal(meal_name)
40
23
  if server.nil?
41
- Boucher.provision(server_class, Boucher.server_classes[server_class.to_sym])
24
+ Boucher.provision(meal)
42
25
  elsif server.state == "stopped"
43
26
  Boucher::Servers.start(server.id)
44
27
  server.reload
45
- Boucher.cook_meals_on_server(server_class, Boucher.server_classes[server_class.to_sym], server)
28
+ Boucher.cook_meal_on_server(meal, server)
46
29
  else
47
- Boucher.cook_meals_on_server(server_class, Boucher.server_classes[server_class.to_sym], server)
30
+ Boucher.cook_meal_on_server(meal, server)
48
31
  end
49
32
  end
50
33
 
51
- def self.provision(class_name, class_map)
52
- puts "Provisioning new #{class_name} server..."
53
- server = create_classified_server(class_map)
34
+ def self.provision(meal)
35
+ puts "Provisioning new #{meal[:name]} server..."
36
+ server = create_meal_server(meal)
54
37
  wait_for_server_to_boot(server)
55
38
  wait_for_server_to_accept_ssh(server)
56
- volumes = create_volumes(class_map, server)
39
+ volumes = create_volumes(meal, server)
57
40
  attach_volumes(volumes, server)
58
- cook_meals_on_server(class_name, class_map, server)
59
- puts "\nThe new #{class_name} server has been provisioned! id: #{server.id}"
41
+ cook_meal_on_server(meal, server)
42
+ puts "\nThe new #{meal[:name]} server has been provisioned! id: #{server.id}"
60
43
  end
61
44
 
62
- def self.attach_elastic_ips(class_name, server)
45
+ def self.attach_elastic_ips(meal, server)
63
46
  puts "Attaching elastic IPs..."
64
- return unless Boucher::Config[:elastic_ips] && Boucher::Config[:elastic_ips][class_name]
47
+ ips = meal[:elastic_ips] || []
65
48
 
66
- puts "Associating #{server.id} with #{Boucher::Config[:elastic_ips][class_name]}"
67
- compute.associate_address(server.id, Boucher::Config[:elastic_ips][class_name])
49
+ ips.each do |ip|
50
+ puts "Associating #{server.id} with #{ip}"
51
+ compute.associate_address(server.id, ip)
52
+ end
68
53
  end
69
54
 
70
55
  private
71
56
 
72
- def self.cook_meals_on_server(class_name, class_map, server)
73
- return unless class_map[:meals]
74
-
75
- class_map[:meals].each do |meal|
76
- meal = meal.call if meal.is_a?(Proc)
77
- Boucher.cook_meal(server, meal)
78
- end
79
-
80
- attach_elastic_ips(class_name, server)
57
+ def self.cook_meal_on_server(meal, server)
58
+ Boucher.cook_meal(server, meal[:name])
59
+ attach_elastic_ips(meal, server)
81
60
  end
82
61
 
83
62
  def self.wait_for_server_to_accept_ssh(server)
@@ -93,16 +72,16 @@ module Boucher
93
72
  Boucher.print_servers([server])
94
73
  end
95
74
 
96
- def self.create_classified_server(class_map)
75
+ def self.create_meal_server(meal)
97
76
  server = compute.servers.new(:tags => {})
98
- Boucher.classify(server, class_map)
77
+ Boucher.setup_meal(server, meal)
99
78
  server.save
100
79
  Boucher.print_servers([server])
101
80
  server
102
81
  end
103
82
 
104
- def self.create_volumes(class_map, server)
105
- Array(class_map[:volumes]).map do |volume_name|
83
+ def self.create_volumes(meal, server)
84
+ Array(meal[:volumes]).map do |volume_name|
106
85
  attributes = Boucher.volume_configs[volume_name]
107
86
  snapshot = snapshots.get(attributes[:snapshot])
108
87
  puts "Creating volume from snapshot #{snapshot.id}..."
@@ -16,7 +16,7 @@ module Boucher
16
16
  cultivate(@instance)
17
17
  end
18
18
 
19
- %w{all of_class in_env in_state search find [] with_id}.each do |m|
19
+ %w{all of_meal in_env in_state search find [] with_id}.each do |m|
20
20
  module_eval "def #{m}(*args); instance.#{m}(*args); end"
21
21
  end
22
22
 
@@ -32,7 +32,7 @@ module Boucher
32
32
 
33
33
  def search(options={})
34
34
  servers = self
35
- servers = servers.of_class(options[:class]) if options[:class]
35
+ servers = servers.of_meal(options[:meal]) if options[:meal]
36
36
  servers = servers.in_env(options[:env]) if options[:env]
37
37
  servers = servers.in_state(options[:state]) if options[:state]
38
38
  servers
@@ -55,8 +55,8 @@ module Boucher
55
55
  Servers.cultivate(self.find_all {|s| s.state == state.to_s })
56
56
  end
57
57
 
58
- def of_class(klass)
59
- Servers.cultivate(self.find_all {|s| s.tags["Class"] == klass.to_s })
58
+ def of_meal(meal)
59
+ Servers.cultivate(self.find_all {|s| s.tags["Meal"] == meal.to_s })
60
60
  end
61
61
 
62
62
  def self.start(server_id)
@@ -68,7 +68,6 @@ module Boucher
68
68
  end
69
69
 
70
70
  def self.terminate(server)
71
- Boucher::Nagios.remove_host(server)
72
71
  volumes = server.volumes
73
72
  volumes_to_destroy = volumes.select {|v| !v.delete_on_termination}
74
73
 
@@ -85,8 +84,8 @@ module Boucher
85
84
  Servers.cultivate(self.find_all {|s| s.id == server_id}).first
86
85
  end
87
86
 
88
- def [](klass)
89
- find(:env => Boucher::Config[:env], :class => klass, :state => "running")
87
+ def [](meal)
88
+ find(:env => Boucher::Config[:env], :meal => meal, :state => "running")
90
89
  end
91
90
  end
92
91
  end
@@ -1,5 +1,5 @@
1
1
  require 'boucher/env'
2
- require 'boucher/classes'
2
+ require 'boucher/meals'
3
3
  require 'fog'
4
4
 
5
5
  module Boucher
@@ -1,11 +1,10 @@
1
1
  require 'boucher/compute'
2
2
  require 'boucher/env'
3
3
  require 'boucher/io'
4
- require 'boucher/classes'
4
+ require 'boucher/meals'
5
5
  require 'boucher/provision'
6
6
  require 'boucher/servers'
7
7
  require 'boucher/volumes'
8
- require 'boucher/nagios'
9
8
 
10
9
  desc "Starts a console with the Boucher modules loaded"
11
10
  task :console do
@@ -1,11 +1,10 @@
1
1
  require 'boucher/compute'
2
2
  require 'boucher/env'
3
3
  require 'boucher/io'
4
- require 'boucher/classes'
4
+ require 'boucher/meals'
5
5
  require 'boucher/provision'
6
6
  require 'boucher/servers'
7
7
  require 'boucher/volumes'
8
- require 'boucher/nagios'
9
8
  require 'retryable'
10
9
 
11
10
  def meals
@@ -40,9 +39,9 @@ namespace :servers do
40
39
  server_listing("in the '#{args.env}' environment", Boucher::Servers.in_env(args.env))
41
40
  end
42
41
 
43
- desc "List AWS servers in specified class"
44
- task :of_class, [:klass] do |t, args|
45
- server_listing("of class '#{args.klass}'", Boucher::Servers.of_class(args.klass))
42
+ desc "List AWS servers of the specified meal"
43
+ task :of_meal, [:meal] do |t, args|
44
+ server_listing("of meal '#{args.meal}'", Boucher::Servers.of_meal(args.meal))
46
45
  end
47
46
 
48
47
  desc "Terminates the specified server"
@@ -67,7 +66,6 @@ web console and click Instance Actions -> Change Termination Protection -> Yes."
67
66
  desc "Stops the specified server"
68
67
  task :stop, [:server_id] do |t, args|
69
68
  server = Boucher.compute.servers.get(args.server_id)
70
- Boucher::Nagios.remove_host(server)
71
69
  Boucher::Servers.stop(args.server_id)
72
70
  end
73
71
 
@@ -75,7 +73,6 @@ web console and click Instance Actions -> Change Termination Protection -> Yes."
75
73
  task :start, [:server_id] do |t, args|
76
74
  Boucher::Servers.start(args.server_id)
77
75
  server = Boucher.compute.servers.get(args.server_id)
78
- Boucher::Nagios.add_host(server)
79
76
  end
80
77
 
81
78
  desc "Open an SSH session with the specified server"
@@ -87,11 +84,9 @@ web console and click Instance Actions -> Change Termination Protection -> Yes."
87
84
 
88
85
  desc "Download a file from the server"
89
86
  task :download, [:server_id, :filepath] do |t, args|
90
- puts "Downloading #{args.filepath}"
91
-
92
- server = Boucher.compute.servers.get(args.server_id)
87
+ server = Boucher.compute.servers.get(args.server_id)
93
88
  remote_path = args.filepath
94
- local_path = File.expand_path(File.join("..", "..", File.basename(args.filepath)), __FILE__)
89
+ local_path = File.expand_path(File.join("..", "..", File.basename(args.filepath)), __FILE__)
95
90
 
96
91
  Boucher.download(server, remote_path, local_path)
97
92
  end
@@ -101,27 +96,22 @@ web console and click Instance Actions -> Change Termination Protection -> Yes."
101
96
  system "chmod 0600 *.pem"
102
97
  end
103
98
 
104
- desc "Provision new server [#{Boucher.server_classes.keys.sort.join(', ')}]"
105
- task :provision, [:klass] do |t, args|
106
- class_map = Boucher.server_classes[args.klass.to_sym]
107
- Boucher.provision(args.klass, class_map)
99
+ desc "Provision new server [#{Boucher.meals.keys.sort.join(', ')}]"
100
+ task :provision, [:meal] do |t, args|
101
+ meal = Boucher.meal(args.meal)
102
+ Boucher.provision(meal)
108
103
  end
109
104
 
110
- desc "Provision new, or chef existing server of the specified class"
111
- task :establish, [:klass] do |t, args|
112
- Boucher.assert_env!
113
- server = Boucher.find_server(args.klass, ENV['BUTCHER_ENV'])
114
- Boucher.establish_server(server, args.klass)
105
+ desc "Provision new, or chef existing server of the specified meal"
106
+ task :establish, [:meal] do |t, args|
107
+ server = Boucher.find_server(args.meal, ENV['BUTCHER_ENV'])
108
+ Boucher.establish_server(server, args.meal)
115
109
  end
116
110
 
117
- namespace :chef do
118
- meals.each do |s_class|
119
- desc "Cook #{s_class} meal"
120
- task s_class, [:server_id] do |t, args|
121
- Boucher.assert_env!
122
- server = Boucher.compute.servers.get(args.server_id)
123
- Boucher.cook_meal(server, s_class)
124
- end
125
- end
111
+ desc "Cook the given meal on the given server"
112
+ task :chef, [:meal, :server_id] do |t, args|
113
+ server = Boucher.compute.servers.get(args.server_id)
114
+ Boucher.cook_meal(server, args.meal)
126
115
  end
127
116
  end
117
+
@@ -1,6 +1,5 @@
1
1
  require_relative "../spec_helper"
2
2
  require 'boucher/compute'
3
- require 'boucher/nagios'
4
3
  require 'ostruct'
5
4
 
6
5
  describe "Boucher Cloud" do
@@ -25,22 +24,6 @@ describe "Boucher Cloud" do
25
24
  Boucher.ssh(server, "some command")
26
25
  end
27
26
 
28
- it "downloads a file" do
29
- server = stub(:dns_name => "test_dns")
30
- Kernel.should_receive(:system).with("rsync", "-azb", "-e", Boucher.ssh_command, "--delete-after", "#{Boucher::Config[:username]}@test_dns:/usr/lib/a_file.txt", "/usr/local/local_file.txt")
31
- Boucher.download(server, "/usr/lib/a_file.txt", "/usr/local/local_file.txt")
32
- end
33
-
34
- it "rsyncs files" do
35
- server = stub(:dns_name => "test_dns")
36
-
37
- system "echo > /dev/null" # to populate $?
38
- Kernel.should_receive(:system).with("rsync", "-azb", "-e", Boucher.ssh_command,
39
- "--delete-after", "foo", "#{Boucher::Config[:username]}@test_dns:bar")
40
-
41
- Boucher.rsync(server, "foo", "bar")
42
- end
43
-
44
27
  it "opens an ssh shell" do
45
28
  server = OpenStruct.new(:dns_name => "test_dns")
46
29
 
@@ -50,12 +33,9 @@ describe "Boucher Cloud" do
50
33
  Boucher.ssh(server)
51
34
  end
52
35
 
53
- it "updates recipes and rsyncs local changes" do
36
+ it "updates recipes" do
54
37
  server = OpenStruct.new(:id => "test_id")
55
38
  Boucher.should_receive(:ssh).with(server, "cd infrastructure && git checkout . && git clean -d -f && git pull && bundle")
56
- Boucher.should_receive(:rsync).with(server, "cookbooks/", "infrastructure/cookbooks/")
57
- Boucher.should_receive(:rsync).with(server, "config/", "infrastructure/config/")
58
- Boucher.should_receive(:rsync).with(server, "tasks/", "infrastructure/tasks/")
59
39
 
60
40
  Boucher.update_recipes(server)
61
41
  end
@@ -65,8 +45,6 @@ describe "Boucher Cloud" do
65
45
 
66
46
  Boucher.should_receive(:update_recipes).with(server)
67
47
  Boucher.should_receive(:ssh).with(server, "cd infrastructure && sudo BUTCHER_ENV=env_name BRANCH=branch_name chef-solo -c config/solo.rb -j config/meal_name.json")
68
- Boucher::Nagios.should_receive(:remove_host).with(server)
69
- Boucher::Nagios.should_receive(:add_host).with(server)
70
48
  Boucher::Config[:branch] = "branch_name"
71
49
  Boucher::Config[:env] = "env_name"
72
50
 
@@ -13,7 +13,7 @@ describe "Boucher IO" do
13
13
 
14
14
  output = $stdout.string
15
15
  puts "output: #{output}"
16
- %w{ID Env Class Creator State Public IP Private IP}.each do |header|
16
+ %w{ID Env Meal Creator State Public IP Private IP}.each do |header|
17
17
  output.should include(header)
18
18
  end
19
19
  end
@@ -21,7 +21,7 @@ describe "Boucher IO" do
21
21
  it "prints a server" do
22
22
  server = OpenStruct.new(
23
23
  :id => "test_id",
24
- :tags => {"Env" => "test_env", "Class" => "test_class", "Creator" => "Joe"},
24
+ :tags => {"Env" => "test_env", "Meal" => "test_class", "Creator" => "Joe"},
25
25
  :state => "test_state",
26
26
  :public_ip_address => "1.2.3.4")
27
27
 
@@ -36,22 +36,22 @@ describe "Boucher IO" do
36
36
  output.should include("1.2.3.4")
37
37
  end
38
38
 
39
- it "prints servers ordered by Env, then Class" do
39
+ it "prints servers ordered by Env, then Meal" do
40
40
  server_1 = OpenStruct.new(
41
41
  :id => "test_id_1",
42
- :tags => {"Env" => "test_env", "Class" => "test_class", "Creator" => "Joe"},
42
+ :tags => {"Env" => "test_env", "Meal" => "test_class", "Creator" => "Joe"},
43
43
  :state => "test_state",
44
44
  :public_ip_address => "1.2.3.4")
45
45
 
46
46
  server_2 = OpenStruct.new(
47
47
  :id => "test_id_2",
48
- :tags => {"Env" => "better_env", "Class" => "test_class_1", "Creator" => "Joe"},
48
+ :tags => {"Env" => "better_env", "Meal" => "test_class_1", "Creator" => "Joe"},
49
49
  :state => "test_state",
50
50
  :public_ip_address => "1.2.3.5")
51
51
 
52
52
  server_3 = OpenStruct.new(
53
53
  :id => "test_id_3",
54
- :tags => {"Env" => "better_env", "Class" => "test_class_2", "Creator" => "Joe"},
54
+ :tags => {"Env" => "better_env", "Meal" => "test_class_2", "Creator" => "Joe"},
55
55
  :state => "test_state",
56
56
  :public_ip_address => "1.2.3.6")
57
57
 
@@ -1,8 +1,8 @@
1
1
  require_relative "../spec_helper"
2
- require 'boucher/classes'
2
+ require 'boucher/meals'
3
3
  require 'ostruct'
4
4
 
5
- describe "Boucher Server Classes" do
5
+ describe "Boucher Server Meals" do
6
6
 
7
7
  before do
8
8
  Boucher.stub(:current_user).and_return("joe")
@@ -11,21 +11,24 @@ describe "Boucher Server Classes" do
11
11
 
12
12
  it "pull classification from json" do
13
13
  json = "{\"boucher\": {\"foo\": 1,\n \"bar\": 2}}"
14
- Boucher.json_to_class(json).should == {:foo => 1, :bar => 2}
14
+ Boucher.json_to_meal(json).should == {:foo => 1, :bar => 2}
15
+
16
+ json = "{}"
17
+ Boucher.json_to_meal(json).should == {}
15
18
  end
16
19
 
17
20
  it "can classify base server" do
18
- some_class = {:class_name => "base",
21
+ some_class = {:meal_name => "base",
19
22
  :meals => ["base"]}
20
23
  Boucher::Config[:default_instance_flavor_id] = 'm1.small'
21
24
  Boucher::Config[:default_instance_groups] = ["SSH"]
22
- Boucher.classify(@server, some_class)
25
+ Boucher.setup_meal(@server, some_class)
23
26
 
24
27
  @server.image_id.should == Boucher::Config[:base_image_id]
25
28
  @server.flavor_id.should == 'm1.small'
26
29
  @server.groups.should == ["SSH"]
27
30
  @server.key_name.should == "test_key"
28
- @server.tags["Class"].should == "base"
31
+ @server.tags["Meal"].should == "base"
29
32
  @server.tags["Name"].should_not == nil
30
33
  @server.tags["Creator"].should == "joe"
31
34
  @server.tags["Env"].should == Boucher::Config[:env]
@@ -13,65 +13,59 @@ describe "Boucher Provisioning" do
13
13
 
14
14
  describe "establish server" do
15
15
  it "provisions a server if one does not exist" do
16
- Boucher.stub(:server_classes).and_return({:class_of_server => "server details"})
17
- Boucher.should_receive(:provision).with("class_of_server", "server details")
16
+ Boucher.should_receive(:meal).with("some_meal").and_return(:meal)
17
+ Boucher.should_receive(:provision).with(:meal)
18
18
 
19
- Boucher.establish_server nil, "class_of_server"
19
+ Boucher.establish_server nil, "some_meal"
20
20
  end
21
21
 
22
22
  it "starts a server if it is stopped" do
23
23
  server = mock(:id => "the id", :state => "stopped")
24
- Boucher.stub(:server_classes).and_return({:class_of_server => "server details"})
24
+ meal = {:name => "some_meal"}
25
+ Boucher.stub(:meal).and_return(meal)
25
26
  Boucher.should_receive(:change_server_state).with("the id", :start, "running")
26
27
  server.should_receive(:reload)
27
- Boucher.should_receive(:cook_meals_on_server).with("class_of_server", "server details", server)
28
+ Boucher.should_receive(:cook_meal_on_server).with(meal, server)
28
29
 
29
- Boucher.establish_server server, "class_of_server"
30
+ Boucher.establish_server server, "some_meal"
30
31
  end
31
32
 
32
33
  it "attaches elastic IPs if the server was stopped" do
33
- Boucher::Config[:elastic_ips] = { "class_of_server" => "1.2.3.4" }
34
34
  server = mock(:id => "the id", :state => "stopped", :reload => nil)
35
- Boucher.stub(:server_classes).and_return({:class_of_server => {:meals => []}})
35
+ Boucher.stub(:meal).and_return({:name => "some_meal", :elastic_ips => %w(1.2.3.4)})
36
36
  Boucher.stub(:change_server_state)
37
+ Boucher.stub(:cook_meal)
37
38
  Boucher.compute.should_receive(:associate_address).with(anything, "1.2.3.4")
38
39
 
39
- Boucher.establish_server server, "class_of_server"
40
+ Boucher.establish_server server, "meal_name"
40
41
  end
41
42
 
42
43
  it "cooks meals on server if it is up and running" do
43
44
  running_server = mock(:id => "the id", :state => "running")
44
- Boucher.stub(:server_classes).and_return({:class_of_server => "server details"})
45
- Boucher.should_receive(:cook_meals_on_server).with("class_of_server", "server details", running_server)
45
+ meal = {:name => "some_meal"}
46
+ Boucher.stub(:meal).and_return(meal)
47
+ Boucher.should_receive(:cook_meal_on_server).with(meal, running_server)
46
48
 
47
- Boucher.establish_server running_server, "class_of_server"
49
+ Boucher.establish_server running_server, "some_meal"
48
50
  end
49
51
  end
50
52
 
51
53
  describe "provision" do
52
54
  it "provisions a server" do
53
55
  Boucher.stub!(:ssh)
54
- Boucher.should_receive(:classify)
55
- Boucher.should_receive(:cook_meal).with(anything, "foo")
56
+ Boucher.should_receive(:setup_meal)
57
+ Boucher.should_receive(:cook_meal).with(anything, "some_meal")
56
58
 
57
- Boucher.provision "foo", {:meals => ["foo"]}
58
- end
59
-
60
- it "provisions a server with Procs as meals" do
61
- Boucher.stub!(:ssh)
62
- Boucher.should_receive(:classify)
63
- Boucher.should_receive(:cook_meal).with(anything, "foo")
64
-
65
- Boucher.provision "foo", {:meals => [lambda{"foo"}]}
59
+ Boucher.provision :name => "some_meal"
66
60
  end
67
61
 
68
62
  it "provisions a server with elastic IP" do
69
63
  Boucher.stub!(:ssh)
70
- Boucher::Config[:elastic_ips] = { "foo" => "1.2.3.4" }
71
- Boucher.should_receive(:classify)
64
+ Boucher.should_receive(:setup_meal)
65
+ Boucher.stub(:cook_meal)
72
66
  Boucher.compute.should_receive(:associate_address).with(anything, "1.2.3.4")
73
67
 
74
- Boucher.provision "foo", {:meals => []}
68
+ Boucher.provision :name => "some_meal", :elastic_ips => %w(1.2.3.4)
75
69
  end
76
70
  end
77
71
  end
@@ -5,10 +5,10 @@ require 'ostruct'
5
5
  describe "Boucher::Servers" do
6
6
 
7
7
  let(:remote_servers) {
8
- [OpenStruct.new(:id => "s1", :tags => {"Env" => "test", "Class" => "foo"}, :state => "stopped"),
9
- OpenStruct.new(:id => "s2", :tags => {"Env" => "test", "Class" => "bar"}, :state => "pending"),
10
- OpenStruct.new(:id => "s3", :tags => {"Env" => "dev", "Class" => "foo"}, :state => "terminated"),
11
- OpenStruct.new(:id => "s4", :tags => {"Env" => "dev", "Class" => "bar"}, :state => "running")]
8
+ [OpenStruct.new(:id => "s1", :tags => {"Env" => "test", "Meal" => "foo"}, :state => "stopped"),
9
+ OpenStruct.new(:id => "s2", :tags => {"Env" => "test", "Meal" => "bar"}, :state => "pending"),
10
+ OpenStruct.new(:id => "s3", :tags => {"Env" => "dev", "Meal" => "foo"}, :state => "terminated"),
11
+ OpenStruct.new(:id => "s4", :tags => {"Env" => "dev", "Meal" => "bar"}, :state => "running")]
12
12
  }
13
13
 
14
14
  before do
@@ -25,10 +25,10 @@ describe "Boucher::Servers" do
25
25
  Boucher::Servers.all.should == remote_servers
26
26
  end
27
27
 
28
- it "finds classed servers" do
29
- Boucher::Servers.of_class("blah").should == []
30
- Boucher::Servers.of_class(:foo).map(&:id).should == ["s1", "s3"]
31
- Boucher::Servers.of_class("bar").map(&:id).should == ["s2", "s4"]
28
+ it "finds mealed servers" do
29
+ Boucher::Servers.of_meal("blah").should == []
30
+ Boucher::Servers.of_meal(:foo).map(&:id).should == ["s1", "s3"]
31
+ Boucher::Servers.of_meal("bar").map(&:id).should == ["s2", "s4"]
32
32
  end
33
33
 
34
34
  it "finds with env servers" do
@@ -46,20 +46,20 @@ describe "Boucher::Servers" do
46
46
 
47
47
  it "finds the first matching server" do
48
48
  Boucher::Servers.find.id.should == "s1"
49
- Boucher::Servers.find(:class => "foo").id.should == "s1"
50
- Boucher::Servers.find(:class => "bar").id.should == "s2"
49
+ Boucher::Servers.find(:meal => "foo").id.should == "s1"
50
+ Boucher::Servers.find(:meal => "bar").id.should == "s2"
51
51
  Boucher::Servers.find(:env => "test").id.should == "s1"
52
52
  Boucher::Servers.find(:env => "dev").id.should == "s3"
53
- Boucher::Servers.find(:class => "foo", :env => "test").id.should == "s1"
54
- Boucher::Servers.find(:class => "foo", :env => "dev").id.should == "s3"
55
- Boucher::Servers.find(:class => "bar", :env => "test").id.should == "s2"
56
- Boucher::Servers.find(:class => "bar", :env => "dev").id.should == "s4"
57
- expect { Boucher::Servers.find(:class => "blah", :env => "dev") }.to raise_error
58
- expect { Boucher::Servers.find(:class => "foo", :env => "blah") }.to raise_error
53
+ Boucher::Servers.find(:meal => "foo", :env => "test").id.should == "s1"
54
+ Boucher::Servers.find(:meal => "foo", :env => "dev").id.should == "s3"
55
+ Boucher::Servers.find(:meal => "bar", :env => "test").id.should == "s2"
56
+ Boucher::Servers.find(:meal => "bar", :env => "dev").id.should == "s4"
57
+ expect { Boucher::Servers.find(:meal => "blah", :env => "dev") }.to raise_error
58
+ expect { Boucher::Servers.find(:meal => "foo", :env => "blah") }.to raise_error
59
59
  end
60
60
 
61
61
  it "raises an error if find returns no results" do
62
- expect { Boucher::Servers.find(:class => "blah") }.to raise_error(Boucher::Servers::NotFound)
62
+ expect { Boucher::Servers.find(:meal => "blah") }.to raise_error(Boucher::Servers::NotFound)
63
63
  end
64
64
 
65
65
  it "gets a server based on current env when all the servers are running" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boucher
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire: boucher/tasks
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-25 00:00:00.000000000 Z
12
+ date: 2012-09-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -91,28 +91,24 @@ files:
91
91
  - README.md
92
92
  - Rakefile
93
93
  - boucher.gemspec
94
- - lib/boucher/ci.rb
95
- - lib/boucher/classes.rb
96
94
  - lib/boucher/compute.rb
97
95
  - lib/boucher/env.rb
98
96
  - lib/boucher/io.rb
99
- - lib/boucher/nagios.rb
97
+ - lib/boucher/meals.rb
100
98
  - lib/boucher/provision.rb
101
99
  - lib/boucher/servers.rb
102
100
  - lib/boucher/storage.rb
103
101
  - lib/boucher/tasks.rb
104
102
  - lib/boucher/tasks/console.rake
105
- - lib/boucher/tasks/env.rake
106
- - lib/boucher/tasks/nagios.rake
107
103
  - lib/boucher/tasks/servers.rake
108
104
  - lib/boucher/tasks/storage.rake
109
105
  - lib/boucher/tasks/volumes.rake
110
106
  - lib/boucher/util.rb
111
107
  - lib/boucher/volumes.rb
112
- - spec/boucher/classes_spec.rb
113
108
  - spec/boucher/compute_spec.rb
114
109
  - spec/boucher/env_spec.rb
115
110
  - spec/boucher/io_spec.rb
111
+ - spec/boucher/meals_spec.rb
116
112
  - spec/boucher/provision_spec.rb
117
113
  - spec/boucher/servers_spec.rb
118
114
  - spec/boucher/storage_spec.rb
@@ -129,6 +125,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
129
125
  - - ! '>='
130
126
  - !ruby/object:Gem::Version
131
127
  version: '0'
128
+ segments:
129
+ - 0
130
+ hash: -3836006143599038364
132
131
  required_rubygems_version: !ruby/object:Gem::Requirement
133
132
  none: false
134
133
  requirements:
@@ -142,10 +141,10 @@ signing_key:
142
141
  specification_version: 3
143
142
  summary: AWS system deployment and management
144
143
  test_files:
145
- - spec/boucher/classes_spec.rb
146
144
  - spec/boucher/compute_spec.rb
147
145
  - spec/boucher/env_spec.rb
148
146
  - spec/boucher/io_spec.rb
147
+ - spec/boucher/meals_spec.rb
149
148
  - spec/boucher/provision_spec.rb
150
149
  - spec/boucher/servers_spec.rb
151
150
  - spec/boucher/storage_spec.rb
data/lib/boucher/ci.rb DELETED
@@ -1,18 +0,0 @@
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
-
@@ -1,39 +0,0 @@
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
@@ -1,50 +0,0 @@
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
@@ -1,42 +0,0 @@
1
- require 'boucher/env'
2
- require 'boucher/provision'
3
- require 'retryable'
4
-
5
- namespace :env do
6
-
7
- desc "Attaches elastic IPs"
8
- task :elastic_ips, [:env] do |t, args|
9
- Boucher.force_env!(args.env)
10
- Boucher.each_required_server do |server, server_class|
11
- Boucher.attach_elastic_ips(server_class, server)
12
- end
13
- end
14
-
15
- desc "Starts and deploys all the servers for the specified environment"
16
- task :start, [:env] do |t, args|
17
- Boucher.force_env!(args.env)
18
- Boucher.assert_env!
19
- Boucher.establish_all_servers
20
- end
21
-
22
- desc "Stops all the servers for the specified environment"
23
- task :stop, [:env] do |t, args|
24
- Boucher.force_env!(args.env)
25
-
26
- Boucher.each_required_server do |server, server_class|
27
- if server
28
- Boucher::Servers.stop(server.id)
29
- else
30
- puts "No #{server_class} server found for #{Boucher::Config[:env]} environment."
31
- end
32
- end
33
- end
34
-
35
- desc "Terminates all servers for the specified environment"
36
- task :terminate, [:env] do |t, args|
37
- Boucher.force_env!(args.env)
38
- Boucher.each_required_server do |server, server_class|
39
- Boucher::Servers.terminate(server) if server
40
- end
41
- end
42
- end
@@ -1,74 +0,0 @@
1
- require 'json'
2
- require 'fileutils'
3
-
4
- def make_config_path(host_name)
5
- "/etc/nagios3/conf.d/#{host_name}.cfg"
6
- end
7
-
8
- def host_entry(host_name, ip)
9
- <<-HOST
10
- define host {
11
- host_name #{host_name}
12
- alias #{host_name}
13
- address #{ip}
14
- check_command check_ssh
15
- notification_interval 0
16
- notification_period 24x7
17
- max_check_attempts 10
18
- notification_options d,u,r
19
- notifications_enabled 1
20
- }
21
- HOST
22
- end
23
-
24
- def service_entry(host_name, ip, plugin)
25
- <<-SERVICE
26
- define command {
27
- command_name #{host_name}-#{plugin}
28
- command_line /usr/lib/nagios/plugins/check_nrpe -H #{ip} -c "#{plugin}"
29
- }
30
-
31
- define service {
32
- use generic-service
33
- host_name #{host_name}
34
- check_command #{host_name}-#{plugin}
35
- service_description #{plugin}
36
- normal_check_interval 5
37
- check_period 24x7
38
- notifications_enabled 1
39
- }
40
- SERVICE
41
- end
42
-
43
- namespace :nagios do
44
- desc "Remove a nagios host from this machine"
45
- task :remove_host, [:name] do |t, args|
46
- FileUtils.rm_f make_config_path(args.name)
47
- end
48
-
49
- desc "Adds a nagios host to be monitored by this machine"
50
- task :add_host, [:name, :ip, :klass] do |t, args|
51
- checks = Boucher::Nagios.checks_for(args.klass)
52
- return if checks.empty?
53
-
54
- File.open(make_config_path(args.name), "w") do |file|
55
- host_name = "#{args.klass}-#{args.name}"
56
-
57
- file.puts host_entry(host_name, args.ip)
58
-
59
- checks.each do |plugin, command|
60
- file.puts
61
- file.puts service_entry(host_name, args.ip, plugin)
62
- end
63
- end
64
- end
65
-
66
- desc "Opens the nagios web console"
67
- task :open do
68
- server = Boucher::Servers["nagios_server"]
69
- url = "http://#{server.public_ip_address}/nagios3"
70
- puts "Nagios lives at #{url}"
71
- puts "Login using nagiosadmin / 'we are many lonely souls'"
72
- `open #{url}`
73
- end
74
- end