kitchen-rackspace 0.1.0 → 0.2.0

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/.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