kitchen-rackspace 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -16,3 +16,5 @@ test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
18
  .kitchen
19
+ *.sw?
20
+ *~
@@ -4,7 +4,6 @@ gemfile:
4
4
  - Gemfile
5
5
 
6
6
  rvm:
7
- - 1.8.7
8
7
  - 1.9.2
9
8
  - 1.9.3
10
9
  - 2.0.0
@@ -0,0 +1,20 @@
1
+ # 0.2.0 / 2013-05-11
2
+
3
+ ### New Features
4
+
5
+ * PR [#8][] - Support `rackspace_region:` option; at request of [@claco][]
6
+
7
+ ### Improvements
8
+
9
+ * PR [#7][] - Clean up/refactor to pass style checks
10
+ * PR [#9][] - Add some (probably overkill) RSpec tests
11
+
12
+ # 0.1.0 / 2013-03-12
13
+
14
+ * Initial release! Woo!
15
+
16
+ [#9]: https://github.com/RoboticCheese/kitchen-rackspace/pull/9
17
+ [#8]: https://github.com/RoboticCheese/kitchen-rackspace/pull/8
18
+ [#7]: https://github.com/RoboticCheese/kitchen-rackspace/pull/7
19
+
20
+ [@claco]: https://github.com/claco
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Build Status](https://travis-ci.org/RoboticCheese/kitchen-rackspace.png?branch=master)](https://travis-ci.org/RoboticCheese/kitchen-rackspace) [![Code Climate](https://codeclimate.com/github/RoboticCheese/kitchen-rackspace.png)](https://codeclimate.com/github/RoboticCheese/kitchen-rackspace)
2
+
1
3
  # Kitchen::Rackspace
2
4
 
3
5
  A Rackspace Cloud Servers driver for Test Kitchen 1.0!
@@ -29,13 +31,14 @@ Provide, at a minimum, the required driver options in your `.kitchen.yml` file:
29
31
  rackspace_api_key: [YOUR RACKSPACE CLOUD API KEY]
30
32
  require_chef_omnibus: latest (if you'll be using Chef)
31
33
 
32
- By default, the driver will spawn a 512MB Ubuntu 12.10 instance.
33
- Additional, optional settings can be provided:
34
+ By default, the driver will spawn a 512MB Ubuntu 12.10 instance in your default
35
+ Rackspace region. Additional, optional settings can be provided:
34
36
 
35
37
  image_id: [SERVER IMAGE ID]
36
38
  flavor_id: [SERVER FLAVOR ID]
37
39
  name: [A UNIQUE SERVER NAME]
38
40
  public_key_path: [PATH TO YOUR PUBLIC SSH KEY]
41
+ rackspace_region: [A VALID RACKSPACE DC/REGION]
39
42
 
40
43
  ## Contributing
41
44
 
data/Rakefile CHANGED
@@ -1,12 +1,15 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'tailor/rake_task'
3
3
  require 'cane/rake_task'
4
+ require 'rspec/core/rake_task'
4
5
 
5
6
  desc 'Run Cane to check quality metrics'
6
7
  Cane::RakeTask.new
7
8
 
8
9
  desc 'Run Tailor to lint check code'
9
- Tailor::RakeTask.new
10
+ Tailor::RakeTask.new do |task|
11
+ task.file_set '**/**/*.rb'
12
+ end
10
13
 
11
14
  desc 'Display LOC stats'
12
15
  task :loc do
@@ -14,6 +17,9 @@ task :loc do
14
17
  sh 'countloc -r lib/kitchen'
15
18
  end
16
19
 
17
- task :default => [ :cane, :tailor, :loc ]
20
+ desc 'Run RSpec unit tests'
21
+ RSpec::Core::RakeTask.new(:spec)
22
+
23
+ task :default => [ :cane, :tailor, :loc, :spec ]
18
24
 
19
25
  # vim: ai et ts=2 sts=2 sw=2 ft=ruby fdm=marker
@@ -19,13 +19,14 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ['lib']
20
20
 
21
21
  spec.add_dependency 'test-kitchen', '~> 1.0.0.alpha'
22
- spec.add_dependency 'fog'
22
+ spec.add_dependency 'fog', '~> 1.11'
23
23
 
24
- spec.add_development_dependency 'bundler', '~> 1.3'
24
+ spec.add_development_dependency 'bundler'
25
25
  spec.add_development_dependency 'rake'
26
26
  spec.add_development_dependency 'tailor'
27
27
  spec.add_development_dependency 'cane'
28
28
  spec.add_development_dependency 'countloc'
29
+ spec.add_development_dependency 'rspec'
29
30
  end
30
31
 
31
32
  # vim: ai et ts=2 sts=2 sw=2 ft=ruby
@@ -28,20 +28,17 @@ module Kitchen
28
28
  #
29
29
  # @author Jonathan Hartman <j@p4nt5.com>
30
30
  class Rackspace < Kitchen::Driver::SSHBase
31
- default_config :version, 'v2'
32
- default_config :image_id, '8a3a9f96-b997-46fd-b7a8-a9e740796ffd'
33
- default_config :flavor_id, '2'
34
- default_config :name, nil
35
- default_config :public_key_path, File.expand_path('~/.ssh/id_dsa.pub')
36
- default_config :username, 'root'
37
- default_config :port, '22'
31
+ default_config :version, 'v2'
32
+ default_config :image_id, '8a3a9f96-b997-46fd-b7a8-a9e740796ffd'
33
+ default_config :flavor_id, '2'
34
+ default_config :name, nil
35
+ default_config :public_key_path, File.expand_path('~/.ssh/id_dsa.pub')
36
+ default_config :username, 'root'
37
+ default_config :port, '22'
38
+ default_config :rackspace_region, nil
38
39
 
39
40
  def create(state)
40
- if not config[:name]
41
- # Generate what should be a unique server name
42
- config[:name] = "#{instance.name}-#{Etc.getlogin}-" +
43
- "#{Socket.gethostname}-#{Array.new(8){rand(36).to_s(36)}.join}"
44
- end
41
+ config[:name] ||= generate_name(instance.name)
45
42
  server = create_server
46
43
  state[:server_id] = server.id
47
44
  info("Rackspace instance <#{state[:server_id]}> created.")
@@ -65,12 +62,16 @@ module Kitchen
65
62
  private
66
63
 
67
64
  def compute
68
- Fog::Compute.new(
65
+ server_def = {
69
66
  :provider => "Rackspace",
70
67
  :version => config[:version],
71
68
  :rackspace_username => config[:rackspace_username],
72
69
  :rackspace_api_key => config[:rackspace_api_key]
73
- )
70
+ }
71
+ if config[:rackspace_region]
72
+ server_def[:rackspace_region] = config[:rackspace_region]
73
+ end
74
+ Fog::Compute.new(server_def)
74
75
  end
75
76
 
76
77
  def create_server
@@ -81,6 +82,12 @@ module Kitchen
81
82
  :public_key_path => config[:public_key_path]
82
83
  )
83
84
  end
85
+
86
+ def generate_name(base)
87
+ # Generate what should be a unique server name
88
+ rand_str = Array.new(8) { rand(36).to_s(36) }.join
89
+ "#{base}-#{Etc.getlogin}-#{Socket.gethostname}-#{rand_str}"
90
+ end
84
91
  end
85
92
  end
86
93
  end
@@ -19,7 +19,7 @@
19
19
  module Kitchen
20
20
  module Driver
21
21
  # Version string for Rackspace Kitchen driver
22
- RACKSPACE_VERSION = '0.1.0'
22
+ RACKSPACE_VERSION = '0.2.0'
23
23
  end
24
24
  end
25
25
 
@@ -0,0 +1,265 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Jonathan Hartman (<j@p4nt5.com>)
4
+ #
5
+ # Copyright (C) 2013, Jonathan Hartman
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require 'logger'
20
+ require 'stringio'
21
+ require 'rspec'
22
+ require 'kitchen'
23
+ require_relative '../../spec_helper'
24
+
25
+ describe Kitchen::Driver::Rackspace do
26
+ let(:logged_output) { StringIO.new }
27
+ let(:logger) { Logger.new(logged_output) }
28
+ let(:config) { Hash.new }
29
+ let(:state) { Hash.new }
30
+
31
+ let(:instance) do
32
+ stub(:name => 'potatoes', :logger => logger, :to_str => 'instance')
33
+ end
34
+
35
+ let(:driver) do
36
+ d = Kitchen::Driver::Rackspace.new(config)
37
+ d.instance = instance
38
+ d
39
+ end
40
+
41
+ describe '#initialize'do
42
+ context 'default options' do
43
+ it 'defaults to v2 cloud' do
44
+ expect(driver[:version]).to eq('v2')
45
+ end
46
+
47
+ it 'defaults to a Ubuntu 12.10 image ID' do
48
+ expect(driver[:image_id]).to eq('8a3a9f96-b997-46fd-b7a8-a9e740796ffd')
49
+ end
50
+
51
+ it 'defaults to the smallest flavor size' do
52
+ expect(driver[:flavor_id]).to eq('2')
53
+ end
54
+
55
+ it 'defaults to local user\'s SSH public key' do
56
+ expect(driver[:public_key_path]).to eq(File.expand_path(
57
+ '~/.ssh/id_dsa.pub'))
58
+ end
59
+
60
+ it 'defaults to SSH with root user on port 22' do
61
+ expect(driver[:username]).to eq('root')
62
+ expect(driver[:port]).to eq('22')
63
+ end
64
+
65
+ it 'defaults to no server name' do
66
+ expect(driver[:name]).to eq(nil)
67
+ end
68
+
69
+ it 'defaults to no region' do
70
+ expect(driver[:rackspace_region]).to eq(nil)
71
+ end
72
+ end
73
+
74
+ context 'overridden options' do
75
+ let(:config) do
76
+ {
77
+ :image_id => '22',
78
+ :flavor_id => '33',
79
+ :public_key_path => '/tmp',
80
+ :username => 'admin',
81
+ :port => '2222',
82
+ :name => 'puppy',
83
+ :rackspace_region => 'ord'
84
+ }
85
+ end
86
+
87
+ it 'uses all the overridden options' do
88
+ drv = driver
89
+ config.each do |k, v|
90
+ expect(drv[k]).to eq(v)
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ describe '#create' do
97
+ let(:server) do
98
+ stub(:id => 'test123', :wait_for => true,
99
+ :public_ip_address => '1.2.3.4')
100
+ end
101
+ let(:driver) do
102
+ d = Kitchen::Driver::Rackspace.new(config)
103
+ d.instance = instance
104
+ d.stub(:generate_name).with('potatoes').and_return('a_monkey!')
105
+ d.stub(:create_server).and_return(server)
106
+ d.stub(:wait_for_sshd).with('1.2.3.4').and_return(true)
107
+ d
108
+ end
109
+
110
+ context 'username and API key only provided' do
111
+ let(:config) do
112
+ {
113
+ :rackspace_username => 'hello',
114
+ :rackspace_api_key => 'world'
115
+ }
116
+ end
117
+
118
+ it 'generates a server name in the absence of one' do
119
+ driver.create(state)
120
+ expect(driver[:name]).to eq('a_monkey!')
121
+ end
122
+
123
+ it 'gets a proper server ID' do
124
+ driver.create(state)
125
+ expect(state[:server_id]).to eq('test123')
126
+ end
127
+
128
+ it 'gets a proper hostname (IP)' do
129
+ driver.create(state)
130
+ expect(state[:hostname]).to eq('1.2.3.4')
131
+ end
132
+ end
133
+ end
134
+
135
+ describe '#destroy' do
136
+ let(:server_id) { '12345' }
137
+ let(:hostname) { 'example.com' }
138
+ let(:state) { { :server_id => server_id, :hostname => hostname } }
139
+ let(:server) { stub(:nil? => false, :destroy => true) }
140
+ let(:servers) { stub(:get => server) }
141
+ let(:compute) { stub(:servers => servers) }
142
+
143
+ let(:driver) do
144
+ d = Kitchen::Driver::Rackspace.new(config)
145
+ d.instance = instance
146
+ d.stub(:compute).and_return(compute)
147
+ d
148
+ end
149
+
150
+ context 'a live server that needs to be destroyed' do
151
+ it 'destroys the server' do
152
+ state.should_receive(:delete).with(:server_id)
153
+ state.should_receive(:delete).with(:hostname)
154
+ driver.destroy(state)
155
+ end
156
+ end
157
+
158
+ context 'no server ID present' do
159
+ let(:state) { Hash.new }
160
+
161
+ it 'does nothing' do
162
+ driver.stub(:compute)
163
+ driver.should_not_receive(:compute)
164
+ state.should_not_receive(:delete)
165
+ driver.destroy(state)
166
+ end
167
+ end
168
+
169
+ context 'a server that was already destroyed' do
170
+ let(:servers) do
171
+ s = double('servers')
172
+ s.stub(:get).with('12345').and_return(nil)
173
+ s
174
+ end
175
+ let(:compute) { stub(:servers => servers) }
176
+ let(:driver) do
177
+ d = Kitchen::Driver::Rackspace.new(config)
178
+ d.instance = instance
179
+ d.stub(:compute).and_return(compute)
180
+ d
181
+ end
182
+
183
+ it 'does not try to destroy the server again' do
184
+ allow_message_expectations_on_nil
185
+ driver.destroy(state)
186
+ end
187
+ end
188
+ end
189
+
190
+ describe '#compute' do
191
+ let(:config) do
192
+ {
193
+ :rackspace_username => 'monkey',
194
+ :rackspace_api_key => 'potato',
195
+ :rackspace_region => 'ord'
196
+ }
197
+ end
198
+
199
+ context 'all requirements provided' do
200
+ it 'creates a new compute connection' do
201
+ Fog::Compute.stub(:new) { |arg| arg }
202
+ res = config.merge({ :provider => 'Rackspace', :version => 'v2' })
203
+ expect(driver.send(:compute)).to eq(res)
204
+ end
205
+ end
206
+
207
+ context 'no username provided' do
208
+ let(:config) { { :rackspace_api_key => '1234' } }
209
+
210
+ it 'raises an error' do
211
+ expect { driver.send(:compute) }.to raise_error(ArgumentError)
212
+ end
213
+ end
214
+
215
+ context 'no API key provided' do
216
+ let(:config) { { :rackspace_username => 'monkey' } }
217
+
218
+ it 'raises an error' do
219
+ expect { driver.send(:compute) }.to raise_error(ArgumentError)
220
+ end
221
+ end
222
+ end
223
+
224
+ describe '#create_server' do
225
+ let(:config) do
226
+ {
227
+ :name => 'hello',
228
+ :image_id => 'there',
229
+ :flavor_id => 'captain',
230
+ :public_key_path => 'tarpals'
231
+ }
232
+ end
233
+ before(:each) { @config = config.dup }
234
+ let(:servers) do
235
+ s = double('servers')
236
+ s.stub(:bootstrap) { |arg| arg }
237
+ s
238
+ end
239
+ let(:compute) { stub(:servers => servers) }
240
+ let(:driver) do
241
+ d = Kitchen::Driver::Rackspace.new(config)
242
+ d.instance = instance
243
+ d.stub(:compute).and_return(compute)
244
+ d
245
+ end
246
+
247
+ it 'creates the server using a compute connection' do
248
+ expect(driver.send(:create_server)).to eq(@config)
249
+ end
250
+ end
251
+
252
+ describe '#generate_name' do
253
+ before(:each) do
254
+ Etc.stub(:getlogin).and_return('user')
255
+ Socket.stub(:gethostname).and_return('host')
256
+ end
257
+
258
+ it 'generates a name' do
259
+ expect(driver.send(:generate_name, 'monkey')).to match(
260
+ /^monkey-user-host-/)
261
+ end
262
+ end
263
+ end
264
+
265
+ # vim: ai et ts=2 sts=2 sw=2 ft=ruby
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Jonathan Hartman (<j@p4nt5.com>)
4
+ #
5
+ # Copyright (C) 2013, Jonathan Hartman
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require 'rspec'
20
+ require_relative '../lib/kitchen/driver/rackspace'
21
+
22
+ # vim: ai et ts=2 sts=2 sw=2 ft=ruby
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-rackspace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-12 00:00:00.000000000 Z
12
+ date: 2013-05-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: test-kitchen
@@ -32,33 +32,33 @@ dependencies:
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
35
- - - ! '>='
35
+ - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: '0'
37
+ version: '1.11'
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
- - - ! '>='
43
+ - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: '0'
45
+ version: '1.11'
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: bundler
48
48
  requirement: !ruby/object:Gem::Requirement
49
49
  none: false
50
50
  requirements:
51
- - - ~>
51
+ - - ! '>='
52
52
  - !ruby/object:Gem::Version
53
- version: '1.3'
53
+ version: '0'
54
54
  type: :development
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  none: false
58
58
  requirements:
59
- - - ~>
59
+ - - ! '>='
60
60
  - !ruby/object:Gem::Version
61
- version: '1.3'
61
+ version: '0'
62
62
  - !ruby/object:Gem::Dependency
63
63
  name: rake
64
64
  requirement: !ruby/object:Gem::Requirement
@@ -123,6 +123,22 @@ dependencies:
123
123
  - - ! '>='
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: rspec
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
126
142
  description: A Test Kitchen Rackspace driver
127
143
  email:
128
144
  - j@p4nt5.com
@@ -132,6 +148,7 @@ extra_rdoc_files: []
132
148
  files:
133
149
  - .gitignore
134
150
  - .travis.yml
151
+ - CHANGELOG.md
135
152
  - Gemfile
136
153
  - LICENSE.txt
137
154
  - README.md
@@ -139,6 +156,8 @@ files:
139
156
  - kitchen-rackspace.gemspec
140
157
  - lib/kitchen/driver/rackspace.rb
141
158
  - lib/kitchen/driver/rackspace_version.rb
159
+ - spec/kitchen/driver/rackspace_spec.rb
160
+ - spec/spec_helper.rb
142
161
  homepage: https://github.com/RoboticCheese/kitchen-rackspace
143
162
  licenses:
144
163
  - Apache
@@ -164,5 +183,6 @@ rubygems_version: 1.8.23
164
183
  signing_key:
165
184
  specification_version: 3
166
185
  summary: A Test Kitchen Rackspace driver
167
- test_files: []
168
- has_rdoc:
186
+ test_files:
187
+ - spec/kitchen/driver/rackspace_spec.rb
188
+ - spec/spec_helper.rb