vm_shepherd 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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