vm_shepherd 0.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,287 @@
1
+ require 'vm_shepherd/vapp_manager/deployer'
2
+
3
+ module VmShepherd
4
+ module VappManager
5
+ RSpec.describe Deployer do
6
+ let(:login_info) do
7
+ {
8
+ url: 'FAKE_URL',
9
+ organization: 'FAKE_ORGANIZATION',
10
+ user: 'FAKE_USER',
11
+ password: 'FAKE_PASSWORD',
12
+ }
13
+ end
14
+ let(:location) do
15
+ {
16
+ catalog: 'FAKE_CATALOG',
17
+ network: 'FAKE_NETWORK',
18
+ vdc: 'FAKE_VDC',
19
+ }
20
+ end
21
+ let(:logger) { instance_double(Logger).as_null_object }
22
+
23
+ let(:deployer) { Deployer.new(login_info, location, logger) }
24
+
25
+ describe '#deploy' do
26
+ let(:vapp_config) do
27
+ {
28
+ ip: 'FAKE_IP',
29
+ name: 'FAKE_NAME',
30
+ gateway: 'FAKE_GATEWAY',
31
+ dns: 'FAKE_DNS',
32
+ ntp: 'FAKE_NTP',
33
+ ip: 'FAKE_IP',
34
+ netmask: 'FAKE_NETMASK',
35
+ }
36
+ end
37
+ let(:vapp_template_path) { 'FAKE_VAPP_TEMPLATE_PATH' }
38
+ let(:tmpdir) { 'FAKE_TMP_DIR' }
39
+
40
+ before { allow(Dir).to receive(:mktmpdir).and_return(tmpdir) }
41
+
42
+ context 'when NO host exists at the specified IP' do
43
+ let(:expanded_vapp_template_path) { 'FAKE_EXPANDED_VAPP_TEMPLATE_PATH' }
44
+
45
+ before do
46
+ allow(deployer).to receive(:system).with("ping -c 5 #{vapp_config.fetch(:ip)}").and_return(false)
47
+
48
+ allow(File).to receive(:expand_path).with(vapp_template_path).and_return(expanded_vapp_template_path)
49
+
50
+ allow(FileUtils).to receive(:remove_entry_secure)
51
+ end
52
+
53
+ it 'expands the vapp_template into a TMP dir' do
54
+ expect(deployer).to receive(:system).with("cd #{tmpdir} && tar xfv '#{expanded_vapp_template_path}'")
55
+
56
+ expect { deployer.deploy(vapp_template_path, vapp_config) }.to raise_error
57
+ end
58
+
59
+ context 'when the template can be expanded' do
60
+ let(:client) { instance_double(VCloudSdk::Client) }
61
+ let(:catalog) { instance_double(VCloudSdk::Catalog) }
62
+ let(:network_config) { instance_double(VCloudSdk::NetworkConfig) }
63
+ let(:vapp) { instance_double(VCloudSdk::VApp) }
64
+ let(:vm) { instance_double(VCloudSdk::VM) }
65
+
66
+ before do
67
+ allow(deployer).to receive(:system).with("cd #{tmpdir} && tar xfv '#{expanded_vapp_template_path}'").
68
+ and_return(true)
69
+ end
70
+
71
+ context 'when the vApp can be deployed' do
72
+ let(:expected_properties) do
73
+ [
74
+ {
75
+ 'type' => 'string',
76
+ 'key' => 'gateway',
77
+ 'value' => vapp_config.fetch(:gateway),
78
+ 'password' => 'false',
79
+ 'userConfigurable' => 'true',
80
+ 'Label' => 'Default Gateway',
81
+ 'Description' => 'The default gateway address for the VM network. Leave blank if DHCP is desired.'
82
+ },
83
+ {
84
+ 'type' => 'string',
85
+ 'key' => 'DNS',
86
+ 'value' => vapp_config.fetch(:dns),
87
+ 'password' => 'false',
88
+ 'userConfigurable' => 'true',
89
+ 'Label' => 'DNS',
90
+ 'Description' => 'The domain name servers for the VM (comma separated). Leave blank if DHCP is desired.',
91
+ },
92
+ {
93
+ 'type' => 'string',
94
+ 'key' => 'ntp_servers',
95
+ 'value' => vapp_config.fetch(:ntp),
96
+ 'password' => 'false',
97
+ 'userConfigurable' => 'true',
98
+ 'Label' => 'NTP Servers',
99
+ 'Description' => 'Comma-delimited list of NTP servers'
100
+ },
101
+ {
102
+ 'type' => 'string',
103
+ 'key' => 'admin_password',
104
+ 'value' => 'tempest',
105
+ 'password' => 'true',
106
+ 'userConfigurable' => 'true',
107
+ 'Label' => 'Admin Password',
108
+ 'Description' => 'This password is used to SSH into the VM. The username is "tempest".',
109
+ },
110
+ {
111
+ 'type' => 'string',
112
+ 'key' => 'ip0',
113
+ 'value' => vapp_config.fetch(:ip),
114
+ 'password' => 'false',
115
+ 'userConfigurable' => 'true',
116
+ 'Label' => 'IP Address',
117
+ 'Description' => 'The IP address for the VM. Leave blank if DHCP is desired.',
118
+ },
119
+ {
120
+ 'type' => 'string',
121
+ 'key' => 'netmask0',
122
+ 'value' => vapp_config.fetch(:netmask),
123
+ 'password' => 'false',
124
+ 'userConfigurable' => 'true',
125
+ 'Label' => 'Netmask',
126
+ 'Description' => 'The netmask for the VM network. Leave blank if DHCP is desired.'
127
+ }
128
+ ]
129
+ end
130
+
131
+ before do
132
+ allow(VCloudSdk::Client).to receive(:new).and_return(client)
133
+ allow(client).to receive(:catalog_exists?)
134
+ allow(client).to receive(:delete_catalog_by_name)
135
+
136
+ allow(client).to receive(:create_catalog).and_return(catalog)
137
+ allow(catalog).to receive(:upload_vapp_template)
138
+ allow(catalog).to receive(:instantiate_vapp_template).and_return(vapp)
139
+
140
+ allow(VCloudSdk::NetworkConfig).to receive(:new).and_return(network_config)
141
+
142
+ allow(vapp).to receive(:find_vm_by_name).and_return(vm)
143
+ allow(vm).to receive(:product_section_properties=)
144
+ allow(vapp).to receive(:power_on)
145
+ end
146
+
147
+ it 'uses VCloudSdk::Client' do
148
+ expect(VCloudSdk::Client).to receive(:new).with(
149
+ login_info.fetch(:url),
150
+ [login_info.fetch(:user), login_info.fetch(:organization)].join('@'),
151
+ login_info.fetch(:password),
152
+ {},
153
+ logger,
154
+ ).and_return(client)
155
+
156
+ deployer.deploy(vapp_template_path, vapp_config)
157
+ end
158
+
159
+ describe 'catalog deletion' do
160
+ before do
161
+ allow(client).to receive(:catalog_exists?).and_return(catalog_exists)
162
+ end
163
+
164
+ context 'when the catalog exists' do
165
+ let(:catalog_exists) { true }
166
+
167
+ it 'deletes the catalog' do
168
+ expect(client).to receive(:delete_catalog_by_name).with(location.fetch(:catalog))
169
+
170
+ deployer.deploy(vapp_template_path, vapp_config)
171
+ end
172
+ end
173
+
174
+ context 'when the catalog does not exist' do
175
+ let(:catalog_exists) { false }
176
+
177
+ it 'does not delete the catalog' do
178
+ expect(client).not_to receive(:delete_catalog_by_name).with(location.fetch(:catalog))
179
+
180
+ deployer.deploy(vapp_template_path, vapp_config)
181
+ end
182
+ end
183
+ end
184
+
185
+ it 'creates the catalog' do
186
+ expect(client).to receive(:create_catalog).with(location.fetch(:catalog)).and_return(catalog)
187
+
188
+ deployer.deploy(vapp_template_path, vapp_config)
189
+ end
190
+
191
+ it 'uploads the vApp template' do
192
+ expect(catalog).to receive(:upload_vapp_template).with(
193
+ location.fetch(:vdc),
194
+ vapp_config.fetch(:name),
195
+ tmpdir,
196
+ ).and_return(catalog)
197
+
198
+ deployer.deploy(vapp_template_path, vapp_config)
199
+ end
200
+
201
+ it 'creates a VCloudSdk::NetworkConfig' do
202
+ expect(VCloudSdk::NetworkConfig).to receive(:new).with(
203
+ location.fetch(:network),
204
+ 'Network 1',
205
+ ).and_return(network_config)
206
+
207
+ deployer.deploy(vapp_template_path, vapp_config)
208
+ end
209
+
210
+ it 'instantiates the vApp template' do
211
+ expect(catalog).to receive(:instantiate_vapp_template).with(
212
+ vapp_config.fetch(:name),
213
+ location.fetch(:vdc),
214
+ vapp_config.fetch(:name),
215
+ nil,
216
+ nil,
217
+ network_config
218
+ ).and_return(vapp)
219
+
220
+ deployer.deploy(vapp_template_path, vapp_config)
221
+ end
222
+
223
+ it 'sets the product section properties' do
224
+ expect(vm).to receive(:product_section_properties=).with(expected_properties)
225
+
226
+ deployer.deploy(vapp_template_path, vapp_config)
227
+ end
228
+
229
+ it 'powers on the vApp' do
230
+ expect(vapp).to receive(:power_on)
231
+
232
+ deployer.deploy(vapp_template_path, vapp_config)
233
+ end
234
+
235
+ it 'removes the expanded vApp template' do
236
+ expect(FileUtils).to receive(:remove_entry_secure).with(tmpdir, force: true)
237
+
238
+ deployer.deploy(vapp_template_path, vapp_config)
239
+ end
240
+ end
241
+
242
+ context 'when the vApp can NOT be deployed' do
243
+ it 'removes the expanded vApp template' do
244
+ expect(FileUtils).to receive(:remove_entry_secure).with(tmpdir, force: true)
245
+
246
+ expect { deployer.deploy(vapp_template_path, vapp_config) }.to raise_error
247
+ end
248
+ end
249
+ end
250
+
251
+ context 'when the template can NOT be expanded' do
252
+ let(:tar_expand_cmd) { "cd #{tmpdir} && tar xfv '#{expanded_vapp_template_path}'" }
253
+ before do
254
+ allow(deployer).to receive(:system).with(tar_expand_cmd).and_return(false)
255
+ end
256
+
257
+ it 'raises an error' do
258
+ expect { deployer.deploy(vapp_template_path, vapp_config) }.to raise_error("Error executing: #{tar_expand_cmd.inspect}")
259
+ end
260
+
261
+ it 'removes the expanded vApp template' do
262
+ expect(FileUtils).to receive(:remove_entry_secure).with(tmpdir, force: true)
263
+
264
+ expect { deployer.deploy(vapp_template_path, vapp_config) }.to raise_error
265
+ end
266
+ end
267
+ end
268
+
269
+ context 'when a host exists at the specified IP' do
270
+ before do
271
+ allow(deployer).to receive(:system).with("ping -c 5 #{vapp_config.fetch(:ip)}").and_return(true)
272
+ end
273
+
274
+ it 'raises an error' do
275
+ expect { deployer.deploy(vapp_template_path, vapp_config) }.to raise_error("VM exists at #{vapp_config.fetch(:ip)}")
276
+ end
277
+
278
+ it 'removes the expanded vApp template' do
279
+ expect(FileUtils).to receive(:remove_entry_secure).with(tmpdir, force: true)
280
+
281
+ expect { deployer.deploy(vapp_template_path, vapp_config) }.to raise_error
282
+ end
283
+ end
284
+ end
285
+ end
286
+ end
287
+ end
@@ -0,0 +1,104 @@
1
+ require 'vm_shepherd/vapp_manager/destroyer'
2
+
3
+ module VmShepherd
4
+ module VappManager
5
+ RSpec.describe Destroyer do
6
+ let(:login_info) do
7
+ {
8
+ url: 'FAKE_URL',
9
+ organization: 'FAKE_ORGANIZATION',
10
+ user: 'FAKE_USER',
11
+ password: 'FAKE_PASSWORD',
12
+ }
13
+ end
14
+ let(:location) do
15
+ {
16
+ catalog: 'FAKE_CATALOG',
17
+ vdc: 'FAKE_VDC',
18
+ }
19
+ end
20
+ let(:logger) { instance_double(Logger).as_null_object }
21
+
22
+ let(:destroyer) { Destroyer.new(login_info, location, logger) }
23
+
24
+ describe '#destroy' do
25
+ let(:client) { instance_double(VCloudSdk::Client) }
26
+ let(:vdc) { instance_double(VCloudSdk::VDC) }
27
+ let(:vapp) { instance_double(VCloudSdk::VApp) }
28
+ let(:vapp_name) { 'FAKE_VAPP_NAME' }
29
+
30
+ context 'when the catalog exists' do
31
+ before do
32
+ allow(client).to receive(:catalog_exists?).with(location.fetch(:catalog)).and_return(true)
33
+ end
34
+
35
+ it 'uses VCloudSdk::Client to delete the vApp' do
36
+ expect(client).to receive(:find_vdc_by_name).with(location.fetch(:vdc)).and_return(vdc)
37
+ expect(vdc).to receive(:find_vapp_by_name).with(vapp_name).and_return(vapp)
38
+ expect(vapp).to receive(:power_off)
39
+ expect(vapp).to receive(:delete)
40
+ expect(client).to receive(:delete_catalog_by_name).with(location.fetch(:catalog))
41
+
42
+ expect(VCloudSdk::Client).to receive(:new).with(
43
+ login_info.fetch(:url),
44
+ [login_info.fetch(:user), login_info.fetch(:organization)].join('@'),
45
+ login_info.fetch(:password),
46
+ {},
47
+ logger,
48
+ ).and_return(client)
49
+
50
+ destroyer.destroy(vapp_name)
51
+ end
52
+
53
+ context 'when an VCloudSdk::ObjectNotFoundError is thrown' do
54
+ before do
55
+ allow(VCloudSdk::Client).to receive(:new).and_return(client)
56
+ allow(client).to receive(:find_vdc_by_name).and_return(vdc)
57
+ allow(vdc).to receive(:find_vapp_by_name).and_return(vapp)
58
+ allow(vapp).to receive(:power_off)
59
+ allow(vapp).to receive(:delete)
60
+
61
+ allow(client).to receive(:delete_catalog_by_name)
62
+ end
63
+
64
+ it 'catches the error' do
65
+ allow(client).to receive(:find_vdc_by_name).and_raise(VCloudSdk::ObjectNotFoundError)
66
+
67
+ expect { destroyer.destroy(vapp_name) }.not_to raise_error
68
+ end
69
+
70
+ it 'deletes to catalog' do
71
+ expect(client).to receive(:delete_catalog_by_name).with(location.fetch(:catalog))
72
+
73
+ destroyer.destroy(vapp_name)
74
+ end
75
+ end
76
+ end
77
+
78
+ context 'when the catalog does not exist' do
79
+ before do
80
+ allow(client).to receive(:catalog_exists?).with(location.fetch(:catalog)).and_return(false)
81
+ end
82
+
83
+ it 'uses VCloudSdk::Client to delete the vApp' do
84
+ expect(client).to receive(:find_vdc_by_name).with(location.fetch(:vdc)).and_return(vdc)
85
+ expect(vdc).to receive(:find_vapp_by_name).with(vapp_name).and_return(vapp)
86
+ expect(vapp).to receive(:power_off)
87
+ expect(vapp).to receive(:delete)
88
+ expect(client).not_to receive(:delete_catalog_by_name).with(location.fetch(:catalog))
89
+
90
+ expect(VCloudSdk::Client).to receive(:new).with(
91
+ login_info.fetch(:url),
92
+ [login_info.fetch(:user), login_info.fetch(:organization)].join('@'),
93
+ login_info.fetch(:password),
94
+ {},
95
+ logger,
96
+ ).and_return(client)
97
+
98
+ destroyer.destroy(vapp_name)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'vm_shepherd/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'vm_shepherd'
8
+ spec.version = VmShepherd::VERSION
9
+ spec.authors = ['Ops Manager Team']
10
+ spec.email = ['cf-tempest-eng@pivotal.io']
11
+ spec.summary = %q{A tool for booting and tearing down Ops Manager VMs on various Infrastructures.}
12
+ spec.description = %q{A tool for booting and tearing down Ops Manager VMs on various Infrastructures.}
13
+ spec.homepage = ''
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_dependency 'aws-sdk-v1'
21
+
22
+ spec.add_dependency 'ruby_vcloud_sdk', '~> 0.7.0'
23
+
24
+ spec.add_dependency 'rbvmomi'
25
+ spec.add_dependency 'vsphere_clients'
26
+
27
+ spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'rspec', '~> 3.2'
29
+ spec.add_development_dependency 'recursive-open-struct', '~> 0.5.0'
30
+ spec.add_development_dependency 'rubocop'
31
+ end
metadata ADDED
@@ -0,0 +1,198 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vm_shepherd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ops Manager Team
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk-v1
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ruby_vcloud_sdk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.7.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.7.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rbvmomi
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: vsphere_clients
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '10.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '10.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.2'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: recursive-open-struct
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.5.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.5.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
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
+ description: A tool for booting and tearing down Ops Manager VMs on various Infrastructures.
126
+ email:
127
+ - cf-tempest-eng@pivotal.io
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".rspec"
134
+ - ".ruby-version"
135
+ - Gemfile
136
+ - README.md
137
+ - Rakefile
138
+ - ci/run_specs.sh
139
+ - lib/vm_shepherd/ami_manager.rb
140
+ - lib/vm_shepherd/ova_manager/base.rb
141
+ - lib/vm_shepherd/ova_manager/deployer.rb
142
+ - lib/vm_shepherd/ova_manager/destroyer.rb
143
+ - lib/vm_shepherd/ova_manager/open_monkey_patch.rb
144
+ - lib/vm_shepherd/shepherd.rb
145
+ - lib/vm_shepherd/vapp_manager/deployer.rb
146
+ - lib/vm_shepherd/vapp_manager/destroyer.rb
147
+ - lib/vm_shepherd/version.rb
148
+ - spec/fixtures/ova_manager/foo.ova
149
+ - spec/fixtures/shepherd/aws.yml
150
+ - spec/fixtures/shepherd/unknown.yml
151
+ - spec/fixtures/shepherd/vcloud.yml
152
+ - spec/fixtures/shepherd/vsphere.yml
153
+ - spec/spec_helper.rb
154
+ - spec/vm_shepherd/ami_manager_spec.rb
155
+ - spec/vm_shepherd/ova_manager/base_spec.rb
156
+ - spec/vm_shepherd/ova_manager/deployer_spec.rb
157
+ - spec/vm_shepherd/ova_manager/destroyer_spec.rb
158
+ - spec/vm_shepherd/shepherd_spec.rb
159
+ - spec/vm_shepherd/vapp_manager/deployer_spec.rb
160
+ - spec/vm_shepherd/vapp_manager/destroyer_spec.rb
161
+ - vm_shepherd.gemspec
162
+ homepage: ''
163
+ licenses: []
164
+ metadata: {}
165
+ post_install_message:
166
+ rdoc_options: []
167
+ require_paths:
168
+ - lib
169
+ required_ruby_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ required_rubygems_version: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ requirements: []
180
+ rubyforge_project:
181
+ rubygems_version: 2.4.6
182
+ signing_key:
183
+ specification_version: 4
184
+ summary: A tool for booting and tearing down Ops Manager VMs on various Infrastructures.
185
+ test_files:
186
+ - spec/fixtures/ova_manager/foo.ova
187
+ - spec/fixtures/shepherd/aws.yml
188
+ - spec/fixtures/shepherd/unknown.yml
189
+ - spec/fixtures/shepherd/vcloud.yml
190
+ - spec/fixtures/shepherd/vsphere.yml
191
+ - spec/spec_helper.rb
192
+ - spec/vm_shepherd/ami_manager_spec.rb
193
+ - spec/vm_shepherd/ova_manager/base_spec.rb
194
+ - spec/vm_shepherd/ova_manager/deployer_spec.rb
195
+ - spec/vm_shepherd/ova_manager/destroyer_spec.rb
196
+ - spec/vm_shepherd/shepherd_spec.rb
197
+ - spec/vm_shepherd/vapp_manager/deployer_spec.rb
198
+ - spec/vm_shepherd/vapp_manager/destroyer_spec.rb