boucher 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,75 @@
1
+ require_relative "../spec_helper"
2
+ require 'boucher/compute'
3
+ require 'boucher/nagios'
4
+ require 'ostruct'
5
+
6
+ describe "Boucher Cloud" do
7
+
8
+ after do
9
+ Boucher::Config[:env] = "dev"
10
+ end
11
+
12
+ it "knows connections options" do
13
+ connection = Boucher.compute
14
+ connection.should_not == nil
15
+ Boucher::EC2_CONFIG[:aws_secret_access_key].should == "secret key"
16
+ Boucher::EC2_CONFIG[:aws_access_key_id].should == "public id"
17
+ end
18
+
19
+ it "ssh's a command" do
20
+ server = OpenStruct.new(:dns_name => "test_dns")
21
+
22
+ system "echo > /dev/null" # to populate $?
23
+ Kernel.should_receive(:system).with("ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i #{Boucher::Config[:aws_key_filename]}.pem #{Boucher::Config[:username]}@test_dns \"some command\"")
24
+
25
+ Boucher.ssh(server, "some command")
26
+ end
27
+
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
+ it "opens an ssh shell" do
45
+ server = OpenStruct.new(:dns_name => "test_dns")
46
+
47
+ system "echo > /dev/null" # to populate $?
48
+ Kernel.should_receive(:system).with("ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i #{Boucher::Config[:aws_key_filename]}.pem #{Boucher::Config[:username]}@test_dns ")
49
+
50
+ Boucher.ssh(server)
51
+ end
52
+
53
+ it "updates recipes and rsyncs local changes" do
54
+ server = OpenStruct.new(:id => "test_id")
55
+ 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
+
60
+ Boucher.update_recipes(server)
61
+ end
62
+
63
+ it "cooks a meal" do
64
+ server = OpenStruct.new(:id => "test_id")
65
+
66
+ Boucher.should_receive(:update_recipes).with(server)
67
+ 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
+ Boucher::Config[:branch] = "branch_name"
71
+ Boucher::Config[:env] = "env_name"
72
+
73
+ Boucher.cook_meal(server, "meal_name")
74
+ end
75
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Environment" do
4
+ describe "env" do
5
+ before do
6
+ @old_env = ENV['BUTCHER_ENV']
7
+ end
8
+
9
+ after do
10
+ ENV['BUTCHER_ENV'] = @old_env
11
+ end
12
+
13
+ it "defaults to :dev" do
14
+ ENV.delete('BUTCHER_ENV')
15
+ #load File.expand_path(File.dirname(__FILE__) + "/../../lib/boucher/env.rb")
16
+ Boucher::env_name.should == :dev
17
+ end
18
+
19
+ it "can be set via an environment variable" do
20
+ ENV['BUTCHER_ENV'] = "ci"
21
+ load File.expand_path(File.dirname(__FILE__) + "/../../lib/boucher/env.rb")
22
+ Boucher::env_name.should == "ci"
23
+ end
24
+ end
25
+
26
+ describe "branch" do
27
+ before do
28
+ @old_branch = ENV['BRANCH']
29
+ ENV.delete('BRANCH')
30
+ end
31
+
32
+ after do
33
+ ENV['BRANCH'] = @old_branch
34
+ end
35
+
36
+ it "defaults to master" do
37
+ Boucher.force_env!(:dev)
38
+ Boucher::Config[:branch].should == "master"
39
+ end
40
+
41
+ it "can be set via an environment variable" do
42
+ ENV['BRANCH'] = "some_branch"
43
+ Boucher.force_env!(:dev)
44
+ Boucher::Config[:branch].should == "some_branch"
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,68 @@
1
+ require_relative "../spec_helper"
2
+ require "boucher/io"
3
+ require 'ostruct'
4
+
5
+ describe "Boucher IO" do
6
+
7
+ before do
8
+ Boucher::IO.mock!
9
+ end
10
+
11
+ it "prints server table header" do
12
+ Boucher.print_server_table_header
13
+
14
+ output = $stdout.string
15
+ puts "output: #{output}"
16
+ %w{ID Env Class Creator State Public IP Private IP}.each do |header|
17
+ output.should include(header)
18
+ end
19
+ end
20
+
21
+ it "prints a server" do
22
+ server = OpenStruct.new(
23
+ :id => "test_id",
24
+ :tags => {"Env" => "test_env", "Class" => "test_class", "Creator" => "Joe"},
25
+ :state => "test_state",
26
+ :public_ip_address => "1.2.3.4")
27
+
28
+ Boucher.print_server server
29
+ output = $stdout.string
30
+
31
+ output.should include("test_id")
32
+ output.should include("test_")
33
+ output.should include("test_class")
34
+ output.should include("Joe")
35
+ output.should include("test_state")
36
+ output.should include("1.2.3.4")
37
+ end
38
+
39
+ it "prints servers ordered by Env, then Class" do
40
+ server_1 = OpenStruct.new(
41
+ :id => "test_id_1",
42
+ :tags => {"Env" => "test_env", "Class" => "test_class", "Creator" => "Joe"},
43
+ :state => "test_state",
44
+ :public_ip_address => "1.2.3.4")
45
+
46
+ server_2 = OpenStruct.new(
47
+ :id => "test_id_2",
48
+ :tags => {"Env" => "better_env", "Class" => "test_class_1", "Creator" => "Joe"},
49
+ :state => "test_state",
50
+ :public_ip_address => "1.2.3.5")
51
+
52
+ server_3 = OpenStruct.new(
53
+ :id => "test_id_3",
54
+ :tags => {"Env" => "better_env", "Class" => "test_class_2", "Creator" => "Joe"},
55
+ :state => "test_state",
56
+ :public_ip_address => "1.2.3.6")
57
+
58
+ Boucher.print_servers([server_1, server_2, server_3])
59
+ output = $stdout.string
60
+
61
+ lines = output.split("\n")
62
+ lines[0].should == ""
63
+ lines[2].should include("------")
64
+ lines[3].should include("test_id_2")
65
+ lines[4].should include("test_id_3")
66
+ lines[5].should include("test_id_1")
67
+ end
68
+ end
@@ -0,0 +1,77 @@
1
+ require_relative "../spec_helper"
2
+ require 'boucher/provision'
3
+
4
+ describe "Boucher Provisioning" do
5
+
6
+ before do
7
+ Boucher::Config[:elastic_ips] = nil
8
+ end
9
+
10
+ after do
11
+ Boucher::Config[:env] = "test"
12
+ end
13
+
14
+ describe "establish server" do
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")
18
+
19
+ Boucher.establish_server nil, "class_of_server"
20
+ end
21
+
22
+ it "starts a server if it is stopped" do
23
+ server = mock(:id => "the id", :state => "stopped")
24
+ Boucher.stub(:server_classes).and_return({:class_of_server => "server details"})
25
+ Boucher.should_receive(:change_server_state).with("the id", :start, "running")
26
+ server.should_receive(:reload)
27
+ Boucher.should_receive(:cook_meals_on_server).with("class_of_server", "server details", server)
28
+
29
+ Boucher.establish_server server, "class_of_server"
30
+ end
31
+
32
+ it "attaches elastic IPs if the server was stopped" do
33
+ Boucher::Config[:elastic_ips] = { "class_of_server" => "1.2.3.4" }
34
+ server = mock(:id => "the id", :state => "stopped", :reload => nil)
35
+ Boucher.stub(:server_classes).and_return({:class_of_server => {:meals => []}})
36
+ Boucher.stub(:change_server_state)
37
+ Boucher.compute.should_receive(:associate_address).with(anything, "1.2.3.4")
38
+
39
+ Boucher.establish_server server, "class_of_server"
40
+ end
41
+
42
+ it "cooks meals on server if it is up and running" do
43
+ 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)
46
+
47
+ Boucher.establish_server running_server, "class_of_server"
48
+ end
49
+ end
50
+
51
+ describe "provision" do
52
+ it "provisions a server" do
53
+ Boucher.stub!(:ssh)
54
+ Boucher.should_receive(:classify)
55
+ Boucher.should_receive(:cook_meal).with(anything, "foo")
56
+
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"}]}
66
+ end
67
+
68
+ it "provisions a server with elastic IP" do
69
+ Boucher.stub!(:ssh)
70
+ Boucher::Config[:elastic_ips] = { "foo" => "1.2.3.4" }
71
+ Boucher.should_receive(:classify)
72
+ Boucher.compute.should_receive(:associate_address).with(anything, "1.2.3.4")
73
+
74
+ Boucher.provision "foo", {:meals => []}
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,79 @@
1
+ require_relative "../spec_helper"
2
+ require 'boucher/servers'
3
+ require 'ostruct'
4
+
5
+ describe "Boucher::Servers" do
6
+
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")]
12
+ }
13
+
14
+ before do
15
+ @env = Boucher::Config[:env]
16
+ Boucher.compute.stub(:servers).and_return(remote_servers)
17
+ end
18
+
19
+ after do
20
+ Boucher::Config[:env] = @env
21
+ end
22
+
23
+ it "finds all servers" do
24
+ Boucher::Servers.all.size.should == 4
25
+ Boucher::Servers.all.should == remote_servers
26
+ end
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"]
32
+ end
33
+
34
+ it "finds with env servers" do
35
+ Boucher::Servers.in_env("blah").should == []
36
+ Boucher::Servers.in_env("test").map(&:id).should == ["s1", "s2"]
37
+ Boucher::Servers.in_env("dev").map(&:id).should == ["s3", "s4"]
38
+ end
39
+
40
+ it "finds servers in a given state" do
41
+ Boucher::Servers.in_state("running").map(&:id).should == ["s4"]
42
+ Boucher::Servers.in_state("terminated").map(&:id).should == ["s3"]
43
+ Boucher::Servers.in_state("pending").map(&:id).should == ["s2"]
44
+ Boucher::Servers.in_state("stopped").map(&:id).should == ["s1"]
45
+ end
46
+
47
+ it "finds the first matching server" do
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"
51
+ Boucher::Servers.find(:env => "test").id.should == "s1"
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
59
+ end
60
+
61
+ it "raises an error if find returns no results" do
62
+ expect { Boucher::Servers.find(:class => "blah") }.to raise_error(Boucher::Servers::NotFound)
63
+ end
64
+
65
+ it "gets a server based on current env when all the servers are running" do
66
+ Boucher::Config[:env] = "test"
67
+ expect { Boucher::Servers["foo"] }.to raise_error
68
+ expect { Boucher::Servers["bar"] }.to raise_error
69
+
70
+ Boucher::Config[:env] = "dev"
71
+ expect { Boucher::Servers["foo"] }.to raise_error
72
+ Boucher::Servers["bar"].id.should == "s4"
73
+ end
74
+
75
+ it "stops a server" do
76
+ Boucher.should_receive(:change_server_state).with("the id", :stop, "stopped")
77
+ Boucher::Servers.stop("the id")
78
+ end
79
+ end
@@ -0,0 +1,47 @@
1
+ require_relative "../spec_helper"
2
+ require 'boucher/storage'
3
+ require 'ostruct'
4
+
5
+ describe "Boucher Storage" do
6
+
7
+ it "knows connections options" do
8
+ connection = Boucher.storage
9
+ connection.should_not == nil
10
+ Boucher::S3_CONFIG[:aws_secret_access_key].should == Boucher::Config[:aws_secret_access_key]
11
+ Boucher::S3_CONFIG[:aws_access_key_id].should == Boucher::Config[:aws_access_key_id]
12
+ end
13
+
14
+ context "with dir" do
15
+ before do
16
+ Boucher.storage.directories.create(:key => "test_bucket")
17
+ File.open("test_file.txt", "w") { |f| f.write "wakka wakka" }
18
+ end
19
+
20
+ after do
21
+ File.delete("test_file.txt") if File.exists?("test_file.txt")
22
+ File.delete("test_file2.txt") if File.exists?("test_file2.txt")
23
+ end
24
+
25
+ it "puts a file" do
26
+ Boucher::Storage.put("test_bucket", "test_file", "test_file.txt")
27
+ dir = Boucher.storage.directories.get("test_bucket")
28
+ file = dir.files.get("test_file")
29
+ file.body.should == "wakka wakka"
30
+ end
31
+
32
+ it "gets a file" do
33
+ Boucher::Storage.put("test_bucket", "test_file", "test_file.txt")
34
+ time = Time.now
35
+ Time.stub!(:now).and_return(time)
36
+ Kernel.should_receive(:system) do |*args|
37
+ args[0].should == "curl"
38
+ args[1].should == Boucher.storage.directories.get("test_bucket").files.get_https_url("test_file", time + 3600)
39
+ args[2].should == "-o"
40
+ args[3].should == "test_file2.txt"
41
+ end
42
+
43
+ Boucher::Storage.get("test_bucket", "test_file", "test_file2.txt")
44
+ end
45
+ end
46
+
47
+ end
@@ -0,0 +1,36 @@
1
+ # MDM - Need to set config because it's never loaded in test
2
+ module Boucher
3
+ NO_LOAD_CONFIG = true
4
+ Config = {
5
+ :aws_secret_access_key => "secret key",
6
+ :aws_access_key_id => "public id",
7
+ :aws_key_filename => "test_key"
8
+ }
9
+ end
10
+
11
+ require 'fog'
12
+ require 'boucher/io'
13
+ require 'boucher/env'
14
+
15
+ Boucher.force_env!("dev")
16
+
17
+ Fog.mock!
18
+ Boucher::IO.mock!
19
+
20
+
21
+ # MDM - Monkey patch wait_for methods so the tests are FASTER!
22
+ module Fog
23
+ def self.wait_for(timeout=Fog.timeout, interval=1)
24
+ yield
25
+ end
26
+ end
27
+
28
+ require 'fog/core/model'
29
+
30
+ module Fog
31
+ class Model
32
+ def wait_for(timeout=Fog.timeout, interval=1, &block)
33
+ yield
34
+ end
35
+ end
36
+ end
metadata ADDED
@@ -0,0 +1,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: boucher
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - ! '''Micah Micah'''
9
+ autorequire: boucher/tasks
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.9.2.2
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.9.2.2
30
+ - !ruby/object:Gem::Dependency
31
+ name: fog
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 1.6.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 1.6.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: retryable
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: 1.3.1
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 1.3.1
62
+ - !ruby/object:Gem::Dependency
63
+ name: pry
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: 0.9.10
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 0.9.10
78
+ description: AWS system deployment and management
79
+ email:
80
+ - ! '''micah@8thlight.com'''
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - .gitmodules
87
+ - .rvmrc
88
+ - Gemfile
89
+ - Gemfile.lock
90
+ - LICENSE
91
+ - README.md
92
+ - Rakefile
93
+ - boucher.gemspec
94
+ - lib/boucher/ci.rb
95
+ - lib/boucher/classes.rb
96
+ - lib/boucher/compute.rb
97
+ - lib/boucher/env.rb
98
+ - lib/boucher/io.rb
99
+ - lib/boucher/nagios.rb
100
+ - lib/boucher/provision.rb
101
+ - lib/boucher/servers.rb
102
+ - lib/boucher/storage.rb
103
+ - lib/boucher/tasks.rb
104
+ - lib/boucher/tasks/console.rake
105
+ - lib/boucher/tasks/env.rake
106
+ - lib/boucher/tasks/nagios.rake
107
+ - lib/boucher/tasks/servers.rake
108
+ - lib/boucher/tasks/storage.rake
109
+ - lib/boucher/tasks/volumes.rake
110
+ - lib/boucher/util.rb
111
+ - lib/boucher/volumes.rb
112
+ - spec/boucher/classes_spec.rb
113
+ - spec/boucher/compute_spec.rb
114
+ - spec/boucher/env_spec.rb
115
+ - spec/boucher/io_spec.rb
116
+ - spec/boucher/provision_spec.rb
117
+ - spec/boucher/servers_spec.rb
118
+ - spec/boucher/storage_spec.rb
119
+ - spec/spec_helper.rb
120
+ homepage: http://github.com/8thlight/boucher
121
+ licenses: []
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ! '>='
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubyforge_project:
140
+ rubygems_version: 1.8.24
141
+ signing_key:
142
+ specification_version: 3
143
+ summary: AWS system deployment and management
144
+ test_files:
145
+ - spec/boucher/classes_spec.rb
146
+ - spec/boucher/compute_spec.rb
147
+ - spec/boucher/env_spec.rb
148
+ - spec/boucher/io_spec.rb
149
+ - spec/boucher/provision_spec.rb
150
+ - spec/boucher/servers_spec.rb
151
+ - spec/boucher/storage_spec.rb
152
+ - spec/spec_helper.rb