beaker-vmpooler 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,276 @@
1
+ require 'spec_helper'
2
+
3
+ module Beaker
4
+ describe Vmpooler do
5
+
6
+ before :each do
7
+ vms = make_hosts()
8
+ MockVsphereHelper.set_config( fog_file_contents )
9
+ MockVsphereHelper.set_vms( vms )
10
+ stub_const( "VsphereHelper", MockVsphereHelper )
11
+ stub_const( "Net", MockNet )
12
+ allow( JSON ).to receive( :parse ) do |arg|
13
+ arg
14
+ end
15
+ allow( Socket ).to receive( :getaddrinfo ).and_return( true )
16
+ allow_any_instance_of( Beaker::Vmpooler ).to \
17
+ receive(:load_credentials).and_return(fog_file_contents)
18
+ end
19
+
20
+ describe '#get_template_url' do
21
+
22
+ it 'works returns the valid url when passed valid pooling_api and template name' do
23
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
24
+ uri = vmpooler.get_template_url("http://pooling.com", "template")
25
+ expect( uri ).to be === "http://pooling.com/vm/template"
26
+ end
27
+
28
+ it 'adds a missing scheme to a given URL' do
29
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
30
+ uri = vmpooler.get_template_url("pooling.com", "template")
31
+ expect( URI.parse(uri).scheme ).to_not be === nil
32
+ end
33
+
34
+ it 'raises an error on an invalid pooling api url' do
35
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
36
+ expect{ vmpooler.get_template_url("pooling### ", "template")}.to raise_error ArgumentError
37
+ end
38
+
39
+ it 'raises an error on an invalide template name' do
40
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
41
+ expect{ vmpooler.get_template_url("pooling.com", "t!e&m*p(l\\a/t e")}.to raise_error ArgumentError
42
+ end
43
+ end
44
+
45
+ describe '#add_tags' do
46
+ let(:vmpooler) { Beaker::Vmpooler.new(make_hosts({:host_tags => {'test_tag' => 'test_value'}}), make_opts) }
47
+
48
+ it 'merges tags correctly' do
49
+ vmpooler.instance_eval {
50
+ @options = @options.merge({:project => 'vmpooler-spec'})
51
+ }
52
+ host = vmpooler.instance_variable_get(:@hosts)[0]
53
+ merged_tags = vmpooler.add_tags(host)
54
+ expected_hash = {
55
+ test_tag: 'test_value',
56
+ beaker_version: Beaker::Version::STRING,
57
+ project: 'vmpooler-spec'
58
+ }
59
+ expect(merged_tags).to include(expected_hash)
60
+ end
61
+ end
62
+
63
+ describe '#disk_added?' do
64
+ let(:vmpooler) { Beaker::Vmpooler.new(make_hosts, make_opts) }
65
+ let(:response_hash_no_disk) {
66
+ {
67
+ "ok" => "true",
68
+ "hostname" => {
69
+ "template"=>"redhat-7-x86_64",
70
+ "domain"=>"delivery.puppetlabs.net"
71
+ }
72
+ }
73
+ }
74
+ let(:response_hash_disk) {
75
+ {
76
+ "ok" => "true",
77
+ "hostname" => {
78
+ "disk" => [
79
+ '+16gb',
80
+ '+8gb'
81
+ ],
82
+ "template"=>"redhat-7-x86_64",
83
+ "domain"=>"delivery.puppetlabs.net"
84
+ }
85
+ }
86
+ }
87
+ it 'returns false when there is no disk' do
88
+ host = response_hash_no_disk['hostname']
89
+ expect(vmpooler.disk_added?(host, "8", 0)).to be(false)
90
+ end
91
+
92
+ it 'returns true when there is a disk' do
93
+ host = response_hash_disk["hostname"]
94
+ expect(vmpooler.disk_added?(host, "16", 0)).to be(true)
95
+ expect(vmpooler.disk_added?(host, "8", 1)).to be(true)
96
+ end
97
+ end
98
+
99
+ describe "#provision" do
100
+
101
+ it 'provisions hosts from the pool' do
102
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
103
+ allow( vmpooler ).to receive( :require ).and_return( true )
104
+ allow( vmpooler ).to receive( :sleep ).and_return( true )
105
+ vmpooler.provision
106
+
107
+ hosts = vmpooler.instance_variable_get( :@hosts )
108
+ hosts.each do | host |
109
+ expect( host['vmhostname'] ).to be === 'pool'
110
+ end
111
+ end
112
+
113
+ it 'raises an error when a host template is not found in returned json' do
114
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
115
+
116
+ allow( vmpooler ).to receive( :require ).and_return( true )
117
+ allow( vmpooler ).to receive( :sleep ).and_return( true )
118
+ allow( vmpooler ).to receive( :get_host_info ).and_return( nil )
119
+
120
+ expect {
121
+ vmpooler.provision
122
+ }.to raise_error( RuntimeError,
123
+ /Vmpooler\.provision - requested VM templates \[.*\,.*\,.*\] not available/
124
+ )
125
+ end
126
+
127
+ it 'repeats asking only for failed hosts' do
128
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
129
+
130
+ allow( vmpooler ).to receive( :require ).and_return( true )
131
+ allow( vmpooler ).to receive( :sleep ).and_return( true )
132
+ allow( vmpooler ).to receive( :get_host_info ).with(
133
+ anything, "vm1_has_a_template" ).and_return( nil )
134
+ allow( vmpooler ).to receive( :get_host_info ).with(
135
+ anything, "vm2_has_a_template" ).and_return( 'y' )
136
+ allow( vmpooler ).to receive( :get_host_info ).with(
137
+ anything, "vm3_has_a_template" ).and_return( 'y' )
138
+
139
+ expect {
140
+ vmpooler.provision
141
+ }.to raise_error( RuntimeError,
142
+ /Vmpooler\.provision - requested VM templates \[[^\,]*\] not available/
143
+ ) # should be only one item in the list, no commas
144
+ end
145
+ end
146
+
147
+ describe "#cleanup" do
148
+
149
+ it "cleans up hosts in the pool" do
150
+ MockVsphereHelper.powerOn
151
+
152
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
153
+ allow( vmpooler ).to receive( :require ).and_return( true )
154
+ allow( vmpooler ).to receive( :sleep ).and_return( true )
155
+ vmpooler.provision
156
+ vmpooler.cleanup
157
+
158
+ hosts = vmpooler.instance_variable_get( :@hosts )
159
+ hosts.each do | host |
160
+ name = host.name
161
+ vm = MockVsphereHelper.find_vm( name )
162
+ expect( vm.runtime.powerState ).to be === "poweredOn" #handed back to the pool, stays on
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ describe Vmpooler do
169
+
170
+ before :each do
171
+ vms = make_hosts()
172
+ MockVsphereHelper.set_config( fog_file_contents )
173
+ MockVsphereHelper.set_vms( vms )
174
+ stub_const( "VsphereHelper", MockVsphereHelper )
175
+ stub_const( "Net", MockNet )
176
+ allow( JSON ).to receive( :parse ) do |arg|
177
+ arg
178
+ end
179
+ allow( Socket ).to receive( :getaddrinfo ).and_return( true )
180
+ end
181
+
182
+ describe "#load_credentials" do
183
+
184
+ it 'continues without credentials when fog file is missing' do
185
+ allow_any_instance_of( Beaker::Vmpooler ).to \
186
+ receive(:read_fog_file).and_raise(Errno::ENOENT.new)
187
+
188
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
189
+ expect( vmpooler.credentials ).to be == {}
190
+ end
191
+
192
+ it 'continues without credentials when fog file is empty' do
193
+ allow_any_instance_of( Beaker::Vmpooler ).to \
194
+ receive(:read_fog_file).and_return(false)
195
+
196
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
197
+ expect( vmpooler.credentials ).to be == {}
198
+ end
199
+
200
+ it 'continues without credentials when fog file contains no :default section' do
201
+ data = { :some => { :other => :data } }
202
+
203
+ allow_any_instance_of( Beaker::Vmpooler ).to \
204
+ receive(:read_fog_file).and_return(data)
205
+
206
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
207
+ expect( vmpooler.credentials ).to be == { }
208
+ end
209
+
210
+ it 'continues without credentials when fog file :default section has no :vmpooler_token' do
211
+ data = { :default => { :something_else => "TOKEN" } }
212
+
213
+ allow_any_instance_of( Beaker::Vmpooler ).to \
214
+ receive(:read_fog_file).and_return(data)
215
+
216
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
217
+ expect( vmpooler.credentials ).to be == { }
218
+ end
219
+
220
+ it 'continues without credentials when there are formatting errors in the fog file' do
221
+ data = { "'default'" => { :vmpooler_token => "b2wl8prqe6ddoii70md" } }
222
+
223
+ allow_any_instance_of( Beaker::Vmpooler ).to \
224
+ receive(:read_fog_file).and_return(data)
225
+
226
+ logger = double('logger')
227
+
228
+ expect(logger).to receive(:warn).with(/is missing a :default section with a :vmpooler_token value/)
229
+ make_opts = {:logger => logger}
230
+
231
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
232
+ expect( vmpooler.credentials ).to be == { }
233
+ end
234
+
235
+ it 'throws a TypeError and continues without credentials when there are syntax errors in the fog file' do
236
+ data = "'default'\n :vmpooler_token: z2wl8prqe0ddoii70ad"
237
+
238
+ allow( File ).to receive( :open ).and_yield( StringIO.new(data) )
239
+ logger = double('logger')
240
+
241
+ expect(logger).to receive(:warn).with(/TypeError: .* has invalid syntax/)
242
+ make_opts = {:logger => logger}
243
+
244
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
245
+
246
+ expect( vmpooler.credentials ).to be == { }
247
+ end
248
+
249
+ it 'throws a Psych::SyntaxError and continues without credentials when there are syntax errors in the fog file' do
250
+
251
+ data = ";default;\n :vmpooler_token: z2wl8prqe0ddoii707d"
252
+
253
+ allow( File ).to receive( :open ).and_yield( StringIO.new(data) )
254
+
255
+ logger = double('logger')
256
+
257
+ expect(logger).to receive(:warn).with(/Psych::SyntaxError: .* invalid syntax/)
258
+ make_opts = {:logger => logger}
259
+
260
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
261
+
262
+ expect( vmpooler.credentials ).to be == { }
263
+ end
264
+
265
+ it 'stores vmpooler token when found in fog file' do
266
+ data = { :default => { :vmpooler_token => "TOKEN" } }
267
+
268
+ allow_any_instance_of( Beaker::Vmpooler ).to \
269
+ receive(:read_fog_file).and_return(data)
270
+
271
+ vmpooler = Beaker::Vmpooler.new( make_hosts, make_opts )
272
+ expect( vmpooler.credentials ).to be == { :vmpooler_token => "TOKEN" }
273
+ end
274
+ end
275
+ end
276
+ end
@@ -0,0 +1,17 @@
1
+ require 'simplecov'
2
+ require 'rspec/its'
3
+ require 'beaker'
4
+ require 'beaker/hypervisor/vmpooler'
5
+ require 'beaker/hypervisor/vcloud'
6
+
7
+ # setup & require beaker's spec_helper.rb
8
+ beaker_gem_spec = Gem::Specification.find_by_name('beaker')
9
+ beaker_gem_dir = beaker_gem_spec.gem_dir
10
+ beaker_spec_path = File.join(beaker_gem_dir, 'spec')
11
+ $LOAD_PATH << beaker_spec_path
12
+ require File.join(beaker_spec_path, 'spec_helper.rb')
13
+
14
+ RSpec.configure do |config|
15
+ config.include TestFileHelpers
16
+ config.include HostHelpers
17
+ end
data/vmpooler.md ADDED
@@ -0,0 +1,45 @@
1
+ [vmpooler](https://github.com/puppetlabs/vmpooler) is a puppet-built abstraction
2
+ layer over vSphere infrastructure that pools VMs to be used by beaker & other
3
+ systems.
4
+
5
+ beaker's vmpooler hypervisor interacts with vmpooler to get Systems Under Test
6
+ (SUTs) for testing purposes.
7
+
8
+ **Note** that if you're a puppet-internal user, you'll have to setup your SSH
9
+ keys to communicate with vmpooler SUTs. To do that, refer to our
10
+ [internal doc](https://confluence.puppetlabs.com/display/SRE/SSH+access+to+vmpooler+VMs).
11
+
12
+ # Tokens
13
+
14
+ Using tokens will allow you to extend your VMs lifetime, as well as interact
15
+ with vmpooler and your VMs in more complex ways. You can have beaker do these
16
+ same things by providing your `vmpooler_token` in the `~/.fog` file. For more
17
+ info about how the `.fog` file works, please refer to the beaker
18
+ [hypervisor README](https://github.com/puppetlabs/beaker/blob/master/docs/how_to/hypervisors/README.md).
19
+
20
+ An example of a `.fog` file with just the vmpooler details is below:
21
+ ```yaml
22
+ :default:
23
+ :vmpooler_token: 'randomtokentext'
24
+ ```
25
+ # Additional Disks
26
+ Using the vmpooler API, Beaker enables you to attach additional storage disks in the host configuration file. The disks are added at the time the VM is created. Logic for using the disk must go into your tests.
27
+
28
+ Simply add the `disks` key and a list containing the sizes(in GB) of the disks you want to create and attach to that host.
29
+ For example, to create 2 disks sized 8GB and 16GB to example-box:
30
+
31
+ ```yaml
32
+ example-box:
33
+ disks:
34
+ - 8
35
+ - 16
36
+ roles:
37
+ - satellite
38
+ platform: el-7-x86_64
39
+ hypervisor: vmpooler
40
+ template: redhat-7-x86_64
41
+ ```
42
+
43
+ Users with Puppet credentials can follow our instructions for getting & using
44
+ vmpooler tokens in our
45
+ [internal documentation](https://confluence.puppetlabs.com/pages/viewpage.action?spaceKey=SRE&title=Generating+and+using+vmpooler+tokens).
metadata ADDED
@@ -0,0 +1,215 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: beaker-vmpooler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Rishi Javia, Kevin Imber, Tony Vu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-07-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '3.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec-its
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: fakefs
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '0.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '10.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '10.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '0.10'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '0.10'
97
+ - !ruby/object:Gem::Dependency
98
+ name: yard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: markdown
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: thin
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ! '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: stringify-hash
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ~>
144
+ - !ruby/object:Gem::Version
145
+ version: 0.0.0
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ~>
151
+ - !ruby/object:Gem::Version
152
+ version: 0.0.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: rbvmomi
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ~>
158
+ - !ruby/object:Gem::Version
159
+ version: '1.9'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ~>
165
+ - !ruby/object:Gem::Version
166
+ version: '1.9'
167
+ description: For use for the Beaker acceptance testing tool
168
+ email:
169
+ - rishi.javia@puppet.com, kevin.imber@puppet.com, tony.vu@puppet.com
170
+ executables:
171
+ - beaker-vmpooler
172
+ extensions: []
173
+ extra_rdoc_files: []
174
+ files:
175
+ - .gitignore
176
+ - .rspec
177
+ - .simplecov
178
+ - Gemfile
179
+ - LICENSE
180
+ - README.md
181
+ - Rakefile
182
+ - beaker-vmpooler.gemspec
183
+ - bin/beaker-vmpooler
184
+ - lib/beaker-vmpooler/version.rb
185
+ - lib/beaker/hypervisor/vcloud.rb
186
+ - lib/beaker/hypervisor/vmpooler.rb
187
+ - spec/beaker/hypervisor/vcloud_spec.rb
188
+ - spec/beaker/hypervisor/vmpooler_spec.rb
189
+ - spec/spec_helper.rb
190
+ - vmpooler.md
191
+ homepage: https://github.com/puppetlabs/beaker-vmpooler
192
+ licenses:
193
+ - Apache2
194
+ metadata: {}
195
+ post_install_message:
196
+ rdoc_options: []
197
+ require_paths:
198
+ - lib
199
+ required_ruby_version: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ! '>='
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ required_rubygems_version: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ! '>='
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ requirements: []
210
+ rubyforge_project:
211
+ rubygems_version: 2.4.6
212
+ signing_key:
213
+ specification_version: 4
214
+ summary: Beaker DSL Extension Helpers!
215
+ test_files: []