slushy 0.1.1 → 0.1.2

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.
data/README.md CHANGED
@@ -8,12 +8,15 @@ Assumes Fog's API for connecting to and creating instances.
8
8
  Provision and converge an instance:
9
9
 
10
10
  ```ruby
11
- connection = Fog::Compute.new :provider => 'AWS', :aws_access_key => 'KEY',
12
- :aws_secret_access_key => 'SECRET'
11
+ connection = Fog::Compute.new(:provider => 'AWS', :aws_access_key_id => 'KEY', :aws_secret_access_key => 'SECRET')
12
+
13
13
  # Second arg is a hash passed to Fog::Compute::AWS::Servers.create
14
- instance = Slushy::Instance.launch connection, :flavor_id => 'm1.large', :more => :keys
14
+ instance = Slushy::Instance.launch(connection, :flavor_id => 'm1.large', :more => :keys)
15
+
16
+ # Install ruby and Chef
15
17
  instance.bootstrap
16
- # Point at directory containing Chef cookbooks
18
+
19
+ # Converge using your Chef cookbooks
17
20
  instance.converge Rails.root.join('provision')
18
21
  ```
19
22
 
@@ -0,0 +1,2 @@
1
+ class Slushy::CommandFailedError < Slushy::Error
2
+ end
@@ -0,0 +1,2 @@
1
+ class Slushy::Error < StandardError
2
+ end
@@ -1,13 +1,11 @@
1
1
  require 'timeout'
2
2
 
3
3
  class Slushy::Instance
4
- class AptInstallError < StandardError; end
5
-
6
4
  attr_reader :connection, :instance_id
7
5
 
8
6
  def self.launch(connection, config)
9
7
  server = connection.servers.create(config)
10
- server.wait_for { ready? }
8
+ server.wait_for { ready? } or raise Slushy::TimeoutError.new("Timeout launching server #{server.id}")
11
9
  new(connection, server.id)
12
10
  end
13
11
 
@@ -36,23 +34,23 @@ class Slushy::Instance
36
34
  response = connection.create_image(instance_id, name, description)
37
35
  image_id = response.body["imageId"]
38
36
  image = connection.images.get(image_id)
39
- image.wait_for { state == "available" }
37
+ image.wait_for(3600) { ready? } or raise Slushy::TimeoutError.new("Timeout creating snapshot #{image_id}")
40
38
  image_id
41
39
  end
42
40
 
43
41
  def terminate
44
42
  server.destroy
45
- server.wait_for { state == "terminated" }
43
+ server.wait_for { state == "terminated" } or raise Slushy::TimeoutError.new("Timeout terminating server #{server.id}")
46
44
  end
47
45
 
48
46
  def stop
49
47
  server.stop
50
- server.wait_for { state == "stopped" }
48
+ server.wait_for { state == "stopped" } or raise Slushy::TimeoutError.new("Timeout stopping server #{server.id}")
51
49
  end
52
50
 
53
51
  def wait_for_connectivity
54
52
  puts "Waiting for ssh connectivity..."
55
- retry_block(5, [Errno::ECONNREFUSED, Timeout::Error], "Connecting to Amazon refused") do
53
+ retry_block(5, [Errno::ECONNREFUSED, Timeout::Error], Slushy::TimeoutError.new("Timeout connecting to server #{server.id}")) do
56
54
  sleep 10
57
55
  Timeout.timeout(60) { ssh('ls') }
58
56
  end
@@ -65,21 +63,17 @@ class Slushy::Instance
65
63
  end
66
64
 
67
65
  def run_command!(command)
68
- exit 1 unless run_command(command)
69
- end
70
-
71
- def run_apt_command!(command)
72
- raise AptInstallError unless run_command(command)
66
+ raise Slushy::CommandFailedError.new("Failed running '#{command}'") unless run_command(command)
73
67
  end
74
68
 
75
69
  def apt_installs
76
- retry_block(5, [AptInstallError], "Command 'apt-get' failed") do
70
+ retry_block(5, [Slushy::CommandFailedError], Slushy::CommandFailedError.new("Command 'apt-get' failed")) do
77
71
  puts "Updating apt cache..."
78
- run_apt_command!('sudo apt-get update')
72
+ run_command!('sudo apt-get update')
79
73
  puts "Installing ruby..."
80
- run_apt_command!('sudo apt-get -y install ruby')
74
+ run_command!('sudo apt-get -y install ruby')
81
75
  puts "Installing rubygems..."
82
- run_apt_command!('sudo apt-get -y install rubygems1.8')
76
+ run_command!('sudo apt-get -y install rubygems1.8')
83
77
  end
84
78
  end
85
79
 
@@ -95,12 +89,14 @@ class Slushy::Instance
95
89
  cookbooks_path = "#{cookbooks_path}/" unless cookbooks_path.to_s.end_with?('/')
96
90
  scp(cookbooks_path, '/tmp/chef-solo', :recursive => true)
97
91
  puts "Converging server, this may take a while (10-20 minutes)"
98
- run_command!('cd /tmp/chef-solo && sudo /var/lib/gems/1.8/bin/chef-solo -c solo.rb -j dna.json')
92
+ path_part = 'PATH=/var/lib/gems/1.8/bin:/usr/local/bin:$PATH'
93
+ cmd = "cd /tmp/chef-solo && #{path_part} sudo chef-solo -c solo.rb -j dna.json"
94
+ run_command!(cmd)
99
95
  end
100
96
 
101
97
  protected
102
98
 
103
- def retry_block(times, errors, failure)
99
+ def retry_block(times, retryable_exceptions, retries_failed_exception)
104
100
  succeeded = false
105
101
  attempts = 0
106
102
  last_error = nil
@@ -108,13 +104,13 @@ class Slushy::Instance
108
104
  begin
109
105
  retval = yield
110
106
  succeeded = true
111
- rescue *errors => e
107
+ rescue *retryable_exceptions => e
112
108
  attempts +=1
113
- puts "#{failure}. Attempting retry #{attempts}..."
109
+ puts "#{retries_failed_exception.message}. Attempting retry #{attempts}..."
114
110
  last_error = e
115
111
  end
116
112
  end
117
- exit 1 if !succeeded
113
+ raise retries_failed_exception unless succeeded
118
114
  retval
119
115
  end
120
116
 
@@ -0,0 +1,2 @@
1
+ class Slushy::TimeoutError < Slushy::Error
2
+ end
@@ -1,3 +1,3 @@
1
1
  module Slushy
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
data/lib/slushy.rb CHANGED
@@ -1,4 +1,7 @@
1
1
  module Slushy; end
2
2
 
3
3
  require 'slushy/version'
4
+ require 'slushy/error'
5
+ require 'slushy/command_failed_error'
6
+ require 'slushy/timeout_error'
4
7
  require 'slushy/instance'
@@ -20,6 +20,13 @@ describe Slushy::Instance do
20
20
  lambda { described_class.launch(connection, config) }.should change { connection.servers.size }.by(1)
21
21
  end
22
22
 
23
+ it "raises if wait_for fails" do
24
+ servers = stub(:create => server)
25
+ connection.stub(:servers).and_return(servers)
26
+ server.stub(:wait_for).and_return(false)
27
+ lambda { described_class.launch(connection, config) }.should raise_error(Slushy::TimeoutError)
28
+ end
29
+
23
30
  it "returns the instance object" do
24
31
  described_class.launch(connection, config).should be_a Slushy::Instance
25
32
  end
@@ -57,21 +64,56 @@ describe Slushy::Instance do
57
64
  it "does NOT return until image creation is complete" do
58
65
  connection.stub(:create_image).and_return(response)
59
66
  images.should_receive(:get).with(:some_ami_id).and_return(image)
60
- image.should_receive(:wait_for)
67
+ image.should_receive(:ready?).ordered.and_return(false)
68
+ image.should_receive(:ready?).ordered.and_return(true)
61
69
  instance.snapshot(:some_name, :some_description)
62
70
  end
71
+
72
+ it "raises if wait_for fails" do
73
+ connection.stub(:create_image).and_return(response)
74
+ images.should_receive(:get).with(:some_ami_id).and_return(image)
75
+ image.stub(:wait_for).and_return(false)
76
+ lambda { instance.snapshot(:some_name, :some_description) }.should raise_error(Slushy::TimeoutError)
77
+ end
63
78
  end
64
79
 
65
80
  describe "#terminate" do
66
81
  it "terminates the given instance" do
67
82
  instance.stub(:server).and_return(server)
68
83
  server.should_receive(:destroy)
69
- server.should_receive(:wait_for)
84
+ server.should_receive(:state).ordered.and_return("running")
85
+ server.should_receive(:state).ordered.and_return("terminated")
70
86
  instance.terminate
71
87
  end
88
+
89
+ it "raises if wait_for fails" do
90
+ instance.stub(:server).and_return(server)
91
+ server.stub(:destroy)
92
+ server.stub(:wait_for).and_return(false)
93
+ lambda { instance.terminate }.should raise_error(Slushy::TimeoutError)
94
+ end
95
+ end
96
+
97
+ describe "#stop" do
98
+ it "stops the given instance" do
99
+ instance.stub(:server).and_return(server)
100
+ server.should_receive(:stop)
101
+ server.should_receive(:state).ordered.and_return("running")
102
+ server.should_receive(:state).ordered.and_return("stopped")
103
+ instance.stop
104
+ end
105
+
106
+ it "raises if wait_for fails" do
107
+ instance.stub(:server).and_return(server)
108
+ server.stub(:stop)
109
+ server.stub(:wait_for).and_return(false)
110
+ lambda { instance.stop }.should raise_error(Slushy::TimeoutError)
111
+ end
72
112
  end
73
113
 
74
114
  describe '#wait_for_connectivity' do
115
+ before { instance.stub(:server).and_return(server) }
116
+
75
117
  it 'retries if the first attempt fails' do
76
118
  instance.should_receive(:ssh).ordered.and_raise(Errno::ECONNREFUSED)
77
119
  instance.should_receive(:ssh).ordered.and_return([mock_job])
@@ -91,12 +133,12 @@ describe Slushy::Instance do
91
133
  stdout.should include 'Attempting retry 3...'
92
134
  end
93
135
 
94
- it 'retries up to five times, then aborts' do
136
+ it 'retries up to five times, then fails' do
95
137
  instance.should_receive(:ssh).exactly(5).times.and_raise(Errno::ECONNREFUSED)
96
138
  instance.stub(:sleep).and_return(10)
97
139
  expect do
98
140
  capture_stdout { instance.wait_for_connectivity }
99
- end.to raise_error SystemExit
141
+ end.to raise_error Slushy::TimeoutError
100
142
  end
101
143
  end
102
144
 
@@ -107,7 +149,7 @@ describe Slushy::Instance do
107
149
  capture_stdout do
108
150
  expect do
109
151
  instance.run_command!("ls")
110
- end.to raise_error SystemExit
152
+ end.to raise_error Slushy::CommandFailedError
111
153
  end.should =~ /STDERR: FAIL WHALE/
112
154
  end
113
155
  end
@@ -124,11 +166,11 @@ describe Slushy::Instance do
124
166
  end.to_not raise_error
125
167
  end
126
168
 
127
- it 'retries up to five times, then aborts' do
169
+ it 'retries up to five times, then fails' do
128
170
  instance.should_receive(:ssh).exactly(5).times.with('sudo apt-get update').and_return([mock_job(:status => 1)])
129
171
  expect do
130
172
  capture_stdout { instance.apt_installs }
131
- end.to raise_error SystemExit
173
+ end.to raise_error Slushy::CommandFailedError
132
174
  end
133
175
  end
134
176
 
data/spec/spec_helper.rb CHANGED
@@ -6,7 +6,6 @@ require 'slushy'
6
6
  Dir[File.expand_path("support/*.rb", File.dirname(__FILE__))].each {|f| require f}
7
7
 
8
8
  RSpec.configure do |config|
9
- config.include OutputStreams
10
9
  config.filter_run :focused => true
11
10
  config.filter_run_excluding :disabled => true
12
11
  config.run_all_when_everything_filtered = true
@@ -10,3 +10,7 @@ module OutputStreams
10
10
  fake.string
11
11
  end
12
12
  end
13
+
14
+ RSpec.configure do |config|
15
+ config.include OutputStreams
16
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slushy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-04-28 00:00:00.000000000 Z
14
+ date: 2012-07-09 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: fog
@@ -92,7 +92,10 @@ files:
92
92
  - README.md
93
93
  - Rakefile
94
94
  - lib/slushy.rb
95
+ - lib/slushy/command_failed_error.rb
96
+ - lib/slushy/error.rb
95
97
  - lib/slushy/instance.rb
98
+ - lib/slushy/timeout_error.rb
96
99
  - lib/slushy/version.rb
97
100
  - slushy.gemspec
98
101
  - spec/lib/instance_spec.rb
@@ -112,7 +115,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
112
115
  version: '0'
113
116
  segments:
114
117
  - 0
115
- hash: 663044203149620506
118
+ hash: -3387664004883499874
116
119
  required_rubygems_version: !ruby/object:Gem::Requirement
117
120
  none: false
118
121
  requirements:
@@ -121,10 +124,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
124
  version: '0'
122
125
  segments:
123
126
  - 0
124
- hash: 663044203149620506
127
+ hash: -3387664004883499874
125
128
  requirements: []
126
129
  rubyforge_project:
127
- rubygems_version: 1.8.21
130
+ rubygems_version: 1.8.24
128
131
  signing_key:
129
132
  specification_version: 3
130
133
  summary: An Aussie kitchen hand helping out Chef