vm_shepherd 3.6.0 → 3.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +1 -1
- data/.ruby-version +1 -1
- data/lib/vm_shepherd/aws_manager.rb +1 -1
- data/lib/vm_shepherd/shepherd.rb +3 -1
- data/lib/vm_shepherd/version.rb +1 -1
- data/lib/vm_shepherd/vsphere_manager.rb +43 -49
- data/spec/fixtures/ova_manager/default.ovf +136 -0
- data/spec/fixtures/ova_manager/without_public_ssh_key.ovf +132 -0
- data/spec/vm_shepherd/aws_manager_spec.rb +21 -0
- data/spec/vm_shepherd/shepherd_spec.rb +98 -24
- data/spec/vm_shepherd/vsphere_manager_spec.rb +31 -2
- data/vm_shepherd.gemspec +1 -0
- metadata +24 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f0c4eae538ba72ae93a1bc16e07b93153be92fb3730b0c1ee995c75aaa7bbec6
|
4
|
+
data.tar.gz: c46d2af2473fb238bfb1bec5e85f8ec13d19f9a0e32f5d7c88db23bd0ad3ac25
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c24318537ae944dc68ccd6c214baa05c1906ba78011ae2391a4a1e8b115c5fddc20813f1556a0634a95436dfcf6b73679570bccb35386ac77936e576cc76628e
|
7
|
+
data.tar.gz: 8db0afde7bfa78be5acaf6d0736cd0a4d0fb75cce46054777873125a5ead9f6c4a479834bbeb69ab765cba7ca4bc9189708ec9b4ae6119148e231189bc04dcbc
|
data/.rubocop.yml
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.6.3
|
@@ -167,7 +167,7 @@ module VmShepherd
|
|
167
167
|
key_name: vm_config.fetch('key_name'),
|
168
168
|
security_group_ids: [env_config.fetch('outputs').fetch('security_group')],
|
169
169
|
subnet: env_config.fetch('outputs').fetch('public_subnet_id'),
|
170
|
-
instance_type: OPS_MANAGER_INSTANCE_TYPE
|
170
|
+
instance_type: vm_config.dig('instance_type') || OPS_MANAGER_INSTANCE_TYPE
|
171
171
|
}
|
172
172
|
|
173
173
|
if (instance_profile = env_config.fetch('outputs').fetch('instance_profile', nil))
|
data/lib/vm_shepherd/shepherd.rb
CHANGED
@@ -164,6 +164,8 @@ module VmShepherd
|
|
164
164
|
datacenter_folders_to_clean: vm_shepherd_config.dig('cleanup', 'datacenter_folders_to_clean'),
|
165
165
|
datastores: vm_shepherd_config.dig('cleanup', 'datastores'),
|
166
166
|
datastore_folders_to_clean: vm_shepherd_config.dig('cleanup', 'datastore_folders_to_clean'),
|
167
|
+
cluster_name: vm_shepherd_config.dig('vsphere', 'cluster'),
|
168
|
+
resource_pool_name: vm_shepherd_config.dig('vsphere', 'resource_pool'),
|
167
169
|
)
|
168
170
|
end
|
169
171
|
when VmShepherd::AWS_IAAS_TYPE then
|
@@ -202,7 +204,7 @@ module VmShepherd
|
|
202
204
|
end
|
203
205
|
|
204
206
|
def get_vsphere_vm_password(input_config)
|
205
|
-
ENV['PROVISION_WITH_PASSWORD'] == 'false' ? nil : (input_config.dig('vm', 'vm_password') || 'tempest')
|
207
|
+
ENV['PROVISION_WITH_PASSWORD'] == 'false' ? nil : (input_config.dig('vm', 'vm_password') || ENV['VSPHERE_VM_PASSWORD'] || 'tempest')
|
206
208
|
end
|
207
209
|
|
208
210
|
def get_vsphere_vm_public_ssh_key(input_config)
|
data/lib/vm_shepherd/version.rb
CHANGED
@@ -27,12 +27,12 @@ module VmShepherd
|
|
27
27
|
FileUtils.remove_entry_secure(ovf_file_path, force: true) unless ovf_file_path.nil?
|
28
28
|
end
|
29
29
|
|
30
|
-
def clean_environment(datacenter_folders_to_clean:, datastores:, datastore_folders_to_clean:)
|
30
|
+
def clean_environment(datacenter_folders_to_clean:, datastores:, datastore_folders_to_clean:, cluster_name: nil, resource_pool_name: nil)
|
31
31
|
return if datacenter_folders_to_clean.nil? || datastores.nil? || datacenter_folders_to_clean.nil?
|
32
32
|
|
33
33
|
datacenter_folders_to_clean.each do |folder_name|
|
34
34
|
validate_folder_name!(folder_name)
|
35
|
-
delete_folder_and_vms(folder_name)
|
35
|
+
delete_folder_and_vms(folder_name, cluster_name, resource_pool_name)
|
36
36
|
end
|
37
37
|
|
38
38
|
datastore_folders_to_clean.each do |folder_name|
|
@@ -105,18 +105,23 @@ module VmShepherd
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def create_network_mappings(ovf_file_path, vsphere_config)
|
108
|
-
ovf =
|
109
|
-
ovf.remove_namespaces!
|
108
|
+
ovf = parse_ovf(ovf_file_path)
|
110
109
|
networks = ovf.xpath('//NetworkSection/Network').map { |x| x['name'] }
|
111
110
|
Hash[networks.map { |ovf_network| [ovf_network, network(vsphere_config)] }]
|
112
111
|
end
|
113
112
|
|
113
|
+
def parse_ovf(ovf_file_path)
|
114
|
+
ovf = Nokogiri::XML(File.read(ovf_file_path))
|
115
|
+
ovf.remove_namespaces!
|
116
|
+
ovf
|
117
|
+
end
|
118
|
+
|
114
119
|
def boot_vm(ovf_file_path, vm_config, vsphere_config)
|
115
120
|
ensure_folder_exists(vsphere_config[:folder])
|
116
121
|
template = deploy_ovf_template(ovf_file_path, vsphere_config)
|
117
122
|
vm = create_vm_from_template(template, vm_config, vsphere_config)
|
118
123
|
|
119
|
-
reconfigure_vm(vm, vm_config)
|
124
|
+
reconfigure_vm(vm, vm_config, ovf_file_path)
|
120
125
|
power_on_vm(vm)
|
121
126
|
end
|
122
127
|
|
@@ -124,12 +129,13 @@ module VmShepherd
|
|
124
129
|
datacenter.vmFolder.traverse(folder_name, RbVmomi::VIM::Folder, true)
|
125
130
|
end
|
126
131
|
|
127
|
-
def delete_folder_and_vms(folder_name)
|
132
|
+
def delete_folder_and_vms(folder_name, cluster_name = nil, resource_pool_name = nil)
|
128
133
|
3.times do |attempt|
|
129
134
|
break unless (folder = datacenter.vmFolder.traverse(folder_name))
|
130
135
|
|
131
136
|
find_vms(folder).each do |vm|
|
132
137
|
power_off_vm(vm)
|
138
|
+
convert_template_to_vm(vm, cluster_name, resource_pool_name)
|
133
139
|
end
|
134
140
|
|
135
141
|
begin
|
@@ -155,6 +161,7 @@ module VmShepherd
|
|
155
161
|
|
156
162
|
def power_off_vm(vm)
|
157
163
|
2.times do
|
164
|
+
# This will implicitly skip over VM templates, which always are in the "poweredOff" state
|
158
165
|
break if vm.runtime.powerState == 'poweredOff'
|
159
166
|
|
160
167
|
begin
|
@@ -168,6 +175,14 @@ module VmShepherd
|
|
168
175
|
end
|
169
176
|
end
|
170
177
|
|
178
|
+
def convert_template_to_vm(vm, cluster_name, resource_pool_name)
|
179
|
+
return unless vm.config.template
|
180
|
+
|
181
|
+
cluster = datacenter.find_compute_resource(cluster_name)
|
182
|
+
pool = cluster.resourcePool.resourcePool.find { |rp| rp.name == resource_pool_name }
|
183
|
+
vm.MarkAsVirtualMachine(pool: pool)
|
184
|
+
end
|
185
|
+
|
171
186
|
def deploy_ovf_template(ovf_file_path, vsphere_config)
|
172
187
|
template_name = [TEMPLATE_PREFIX, Time.new.strftime('%F-%H-%M'), cluster(vsphere_config).name].join('-')
|
173
188
|
logger.info("BEGIN deploy_ovf ovf_file=#{ovf_file_path} template_name=#{template_name}")
|
@@ -233,8 +248,8 @@ module VmShepherd
|
|
233
248
|
}
|
234
249
|
end
|
235
250
|
|
236
|
-
def reconfigure_vm(vm, vm_config)
|
237
|
-
virtual_machine_config_spec = create_virtual_machine_config_spec(vm_config)
|
251
|
+
def reconfigure_vm(vm, vm_config, ovf_file_path)
|
252
|
+
virtual_machine_config_spec = create_virtual_machine_config_spec(vm_config, ovf_file_path)
|
238
253
|
logger.info("BEGIN reconfigure_vm_task virtual_machine_config_spec=#{virtual_machine_config_spec.inspect}")
|
239
254
|
vm.ReconfigVM_Task(
|
240
255
|
spec: virtual_machine_config_spec
|
@@ -243,12 +258,12 @@ module VmShepherd
|
|
243
258
|
}
|
244
259
|
end
|
245
260
|
|
246
|
-
def create_virtual_machine_config_spec(vm_config)
|
261
|
+
def create_virtual_machine_config_spec(vm_config, ovf_file_path)
|
247
262
|
logger.info('BEGIN VmConfigSpec creation')
|
248
263
|
vm_config_spec =
|
249
264
|
RbVmomi::VIM::VmConfigSpec.new.tap do |vcs|
|
250
265
|
vcs.ovfEnvironmentTransport = ['com.vmware.guestInfo']
|
251
|
-
vcs.property = create_vapp_property_specs(vm_config)
|
266
|
+
vcs.property = create_vapp_property_specs(vm_config, ovf_file_path)
|
252
267
|
end
|
253
268
|
logger.info("END VmConfigSpec creation: #{vm_config_spec.inspect}")
|
254
269
|
|
@@ -259,57 +274,36 @@ module VmShepherd
|
|
259
274
|
end
|
260
275
|
end
|
261
276
|
|
262
|
-
def create_vapp_property_specs(vm_config)
|
263
|
-
|
264
|
-
'ip0'
|
265
|
-
'netmask0'
|
266
|
-
'gateway'
|
267
|
-
'DNS'
|
277
|
+
def create_vapp_property_specs(vm_config, ovf_file_path)
|
278
|
+
property_value_map = {
|
279
|
+
'ip0' => vm_config[:ip],
|
280
|
+
'netmask0' => vm_config[:netmask],
|
281
|
+
'gateway' => vm_config[:gateway],
|
282
|
+
'DNS' => vm_config[:dns],
|
268
283
|
'ntp_servers' => vm_config[:ntp_servers],
|
284
|
+
'admin_password' => vm_config[:vm_password],
|
285
|
+
'public_ssh_key' => vm_config[:public_ssh_key],
|
286
|
+
'custom_hostname' => vm_config[:custom_hostname],
|
269
287
|
}
|
270
288
|
|
271
289
|
vapp_property_specs = []
|
272
290
|
|
273
|
-
logger.info("BEGIN VAppPropertySpec creation configuration=#{
|
274
|
-
|
275
|
-
|
291
|
+
logger.info("BEGIN VAppPropertySpec creation configuration=#{property_value_map.inspect}")
|
292
|
+
|
293
|
+
# VAppPropertySpec order must match OVF template property order
|
294
|
+
ovf = parse_ovf(ovf_file_path)
|
295
|
+
ovf.xpath('//ProductSection/Property').each_with_index do |property, index|
|
296
|
+
label = property.attribute('key').value
|
276
297
|
vapp_property_specs << RbVmomi::VIM::VAppPropertySpec.new.tap do |spec|
|
277
298
|
spec.operation = 'edit'
|
278
299
|
spec.info = RbVmomi::VIM::VAppPropertyInfo.new.tap do |p|
|
279
|
-
p.key =
|
280
|
-
p.label =
|
281
|
-
p.value =
|
300
|
+
p.key = index
|
301
|
+
p.label = label
|
302
|
+
p.value = property_value_map[label]
|
282
303
|
end
|
283
304
|
end
|
284
305
|
end
|
285
306
|
|
286
|
-
vapp_property_specs << RbVmomi::VIM::VAppPropertySpec.new.tap do |spec|
|
287
|
-
spec.operation = 'edit'
|
288
|
-
spec.info = RbVmomi::VIM::VAppPropertyInfo.new.tap do |p|
|
289
|
-
p.key = 5 # this needs to be 5th to match the ovf template property order.
|
290
|
-
p.label = 'admin_password'
|
291
|
-
p.value = vm_config[:vm_password]
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
vapp_property_specs << RbVmomi::VIM::VAppPropertySpec.new.tap do |spec|
|
296
|
-
spec.operation = 'edit'
|
297
|
-
spec.info = RbVmomi::VIM::VAppPropertyInfo.new.tap do |p|
|
298
|
-
p.key = 6 # ditto. see above. it makes me sad, too.
|
299
|
-
p.label = 'public_ssh_key'
|
300
|
-
p.value = vm_config[:public_ssh_key]
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
vapp_property_specs << RbVmomi::VIM::VAppPropertySpec.new.tap do |spec|
|
305
|
-
spec.operation = 'edit'
|
306
|
-
spec.info = RbVmomi::VIM::VAppPropertyInfo.new.tap do |p|
|
307
|
-
p.key = 7 # ditto. see above. it makes me sad, too.
|
308
|
-
p.label = 'custom_hostname'
|
309
|
-
p.value = vm_config[:custom_hostname]
|
310
|
-
end
|
311
|
-
end unless vm_config[:custom_hostname].nil?
|
312
|
-
|
313
307
|
logger.info("END VAppPropertySpec creation vapp_property_specs=#{vapp_property_specs.inspect}")
|
314
308
|
vapp_property_specs
|
315
309
|
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<Envelope ovf:version="1.0"
|
3
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
4
|
+
xml:lang="en-US" xmlns="http://schemas.dmtf.org/ovf/envelope/1"
|
5
|
+
xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"
|
6
|
+
xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
|
7
|
+
xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
|
8
|
+
xmlns:vmw="http://www.vmware.com/schema/ovf">
|
9
|
+
|
10
|
+
<References>
|
11
|
+
<File ovf:href="pivotal-ops-manager-disk1.vmdk" ovf:size="4243996160" ovf:id="file1"/>
|
12
|
+
</References>
|
13
|
+
|
14
|
+
<DiskSection>
|
15
|
+
<Info>List of the virtual disks used in the package</Info>
|
16
|
+
<Disk ovf:capacity="171798603879"
|
17
|
+
ovf:diskId="vmdisk1"
|
18
|
+
ovf:fileRef="file1"
|
19
|
+
ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized"/>
|
20
|
+
</DiskSection>
|
21
|
+
|
22
|
+
<NetworkSection>
|
23
|
+
<Info>Logical networks used in the package</Info>
|
24
|
+
<Network ovf:name="Network 1">
|
25
|
+
<Description>Logical network used by this appliance.</Description>
|
26
|
+
</Network>
|
27
|
+
</NetworkSection>
|
28
|
+
|
29
|
+
<vmw:IpAssignmentSection ovf:required="false" vmw:protocols="IPv4" vmw:schemes="">
|
30
|
+
<Info>Supported IP assignment schemes</Info>
|
31
|
+
</vmw:IpAssignmentSection>
|
32
|
+
|
33
|
+
<VirtualSystem ovf:id="FAKE_FILENAME">
|
34
|
+
<Info>A virtual machine</Info>
|
35
|
+
|
36
|
+
<ProductSection>
|
37
|
+
<Info/>
|
38
|
+
<Product>Ops Manager</Product>
|
39
|
+
<Vendor>Pivotal</Vendor>
|
40
|
+
<Version>2.3-build.203</Version>
|
41
|
+
<Property ovf:key="ip0" ovf:userConfigurable="true" ovf:type="string">
|
42
|
+
<Label>IP Address</Label>
|
43
|
+
<Description>The IP address for the Ops Manager. Leave blank if DHCP is desired.</Description>
|
44
|
+
</Property>
|
45
|
+
<Property ovf:key="netmask0" ovf:userConfigurable="true" ovf:type="string">
|
46
|
+
<Label>Netmask</Label>
|
47
|
+
<Description>The netmask for the Ops Manager's network. Leave blank if DHCP is desired.</Description>
|
48
|
+
</Property>
|
49
|
+
<Property ovf:key="gateway" ovf:userConfigurable="true" ovf:type="string">
|
50
|
+
<Label>Default Gateway</Label>
|
51
|
+
<Description>The default gateway address for the Ops Manager's network. Leave blank if DHCP is desired.</Description>
|
52
|
+
</Property>
|
53
|
+
<Property ovf:key="DNS" ovf:userConfigurable="true" ovf:type="string">
|
54
|
+
<Label>DNS</Label>
|
55
|
+
<Description>The domain name servers for the Ops Manager (comma separated). Leave blank if DHCP is desired.</Description>
|
56
|
+
</Property>
|
57
|
+
<Property ovf:key="ntp_servers" ovf:userConfigurable="true" ovf:type="string">
|
58
|
+
<Label>NTP Servers</Label>
|
59
|
+
<Description>Comma-delimited list of NTP servers</Description>
|
60
|
+
</Property>
|
61
|
+
<Property ovf:key="admin_password" ovf:userConfigurable="true" ovf:type="password">
|
62
|
+
<Label>Admin Password</Label>
|
63
|
+
<Description>This password is used to SSH into the Ops Manager. The username is 'ubuntu'. One or both of Admin Password and SSH Key is required.</Description>
|
64
|
+
</Property>
|
65
|
+
<Property ovf:key="public_ssh_key" ovf:userConfigurable="true" ovf:type="string">
|
66
|
+
<Label>Public SSH Key</Label>
|
67
|
+
<Description>The Public SSH Key is used to allow SSHing into the Ops Manager with your private ssh key. The username is 'ubuntu'. One or both of Admin Password and SSH Key is required.</Description>
|
68
|
+
</Property>
|
69
|
+
<Property ovf:key="custom_hostname" ovf:userConfigurable="true" ovf:type="string">
|
70
|
+
<Label>Custom Hostname</Label>
|
71
|
+
<Description>This will be set as the hostname on the VM. Default: 'pivotal-ops-manager'.</Description>
|
72
|
+
</Property>
|
73
|
+
</ProductSection>
|
74
|
+
|
75
|
+
<AnnotationSection>
|
76
|
+
<Info/>
|
77
|
+
<Annotation>Ops Manager for Pivotal Cloud Foundry
|
78
|
+
installs and manages PCF products and services.</Annotation>
|
79
|
+
</AnnotationSection>
|
80
|
+
|
81
|
+
<VirtualHardwareSection ovf:required="false" ovf:transport="com.vmware.guestInfo">
|
82
|
+
<Info>Virtual hardware requirements for a virtual machine</Info>
|
83
|
+
<System>
|
84
|
+
<vssd:ElementName>Virtual Hardware Family</vssd:ElementName>
|
85
|
+
<vssd:InstanceID>0</vssd:InstanceID>
|
86
|
+
<vssd:VirtualSystemIdentifier>FAKE_FILENAME</vssd:VirtualSystemIdentifier>
|
87
|
+
<vssd:VirtualSystemType>vmx-09</vssd:VirtualSystemType>
|
88
|
+
</System>
|
89
|
+
<Item>
|
90
|
+
<rasd:Caption>1 virtual CPU</rasd:Caption>
|
91
|
+
<rasd:Description>Number of virtual CPUs</rasd:Description>
|
92
|
+
<rasd:ElementName>1 virtual CPU</rasd:ElementName>
|
93
|
+
<rasd:InstanceID>1</rasd:InstanceID>
|
94
|
+
<rasd:ResourceType>3</rasd:ResourceType>
|
95
|
+
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>
|
96
|
+
</Item>
|
97
|
+
<Item>
|
98
|
+
<rasd:AllocationUnits>MegaBytes</rasd:AllocationUnits>
|
99
|
+
<rasd:Caption>8192 MB of memory</rasd:Caption>
|
100
|
+
<rasd:Description>Memory Size</rasd:Description>
|
101
|
+
<rasd:ElementName>8192 MB of memory</rasd:ElementName>
|
102
|
+
<rasd:InstanceID>2</rasd:InstanceID>
|
103
|
+
<rasd:ResourceType>4</rasd:ResourceType>
|
104
|
+
<rasd:VirtualQuantity>8192</rasd:VirtualQuantity>
|
105
|
+
</Item>
|
106
|
+
<Item>
|
107
|
+
<rasd:Address>0</rasd:Address>
|
108
|
+
<rasd:Caption>scsiController0</rasd:Caption>
|
109
|
+
<rasd:Description>SCSI Controller</rasd:Description>
|
110
|
+
<rasd:ElementName>scsiController0</rasd:ElementName>
|
111
|
+
<rasd:InstanceID>3</rasd:InstanceID>
|
112
|
+
<rasd:ResourceSubType>lsilogic</rasd:ResourceSubType>
|
113
|
+
<rasd:ResourceType>6</rasd:ResourceType>
|
114
|
+
</Item>
|
115
|
+
<Item>
|
116
|
+
<rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
|
117
|
+
<rasd:Caption>Ethernet adapter on 'Network 1'</rasd:Caption>
|
118
|
+
<rasd:Connection>Network 1</rasd:Connection>
|
119
|
+
<rasd:ElementName>Ethernet adapter on 'Network 1'</rasd:ElementName>
|
120
|
+
<rasd:InstanceID>4</rasd:InstanceID>
|
121
|
+
<rasd:ResourceSubType>E1000</rasd:ResourceSubType>
|
122
|
+
<rasd:ResourceType>10</rasd:ResourceType>
|
123
|
+
</Item>
|
124
|
+
<Item>
|
125
|
+
<rasd:AddressOnParent>0</rasd:AddressOnParent>
|
126
|
+
<rasd:Caption>disk1</rasd:Caption>
|
127
|
+
<rasd:Description>Disk Image</rasd:Description>
|
128
|
+
<rasd:ElementName>disk1</rasd:ElementName>
|
129
|
+
<rasd:HostResource>/disk/vmdisk1</rasd:HostResource>
|
130
|
+
<rasd:InstanceID>5</rasd:InstanceID>
|
131
|
+
<rasd:Parent>3</rasd:Parent>
|
132
|
+
<rasd:ResourceType>17</rasd:ResourceType>
|
133
|
+
</Item>
|
134
|
+
</VirtualHardwareSection>
|
135
|
+
</VirtualSystem>
|
136
|
+
</Envelope>
|
@@ -0,0 +1,132 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<Envelope ovf:version="1.0"
|
3
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
4
|
+
xml:lang="en-US" xmlns="http://schemas.dmtf.org/ovf/envelope/1"
|
5
|
+
xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"
|
6
|
+
xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
|
7
|
+
xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
|
8
|
+
xmlns:vmw="http://www.vmware.com/schema/ovf">
|
9
|
+
|
10
|
+
<References>
|
11
|
+
<File ovf:href="pivotal-ops-manager-disk1.vmdk" ovf:size="4223308288" ovf:id="file1"/>
|
12
|
+
</References>
|
13
|
+
|
14
|
+
<DiskSection>
|
15
|
+
<Info>List of the virtual disks used in the package</Info>
|
16
|
+
<Disk ovf:capacity="171798603879"
|
17
|
+
ovf:diskId="vmdisk1"
|
18
|
+
ovf:fileRef="file1"
|
19
|
+
ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized"/>
|
20
|
+
</DiskSection>
|
21
|
+
|
22
|
+
<NetworkSection>
|
23
|
+
<Info>Logical networks used in the package</Info>
|
24
|
+
<Network ovf:name="Network 1">
|
25
|
+
<Description>Logical network used by this appliance.</Description>
|
26
|
+
</Network>
|
27
|
+
</NetworkSection>
|
28
|
+
|
29
|
+
<vmw:IpAssignmentSection ovf:required="false" vmw:protocols="IPv4" vmw:schemes="">
|
30
|
+
<Info>Supported IP assignment schemes</Info>
|
31
|
+
</vmw:IpAssignmentSection>
|
32
|
+
|
33
|
+
<VirtualSystem ovf:id="FAKE_FILENAME">
|
34
|
+
<Info>A virtual machine</Info>
|
35
|
+
|
36
|
+
<ProductSection>
|
37
|
+
<Info/>
|
38
|
+
<Product>Ops Manager</Product>
|
39
|
+
<Vendor>Pivotal</Vendor>
|
40
|
+
<Version>2.2-build.365</Version>
|
41
|
+
<Property ovf:key="ip0" ovf:userConfigurable="true" ovf:type="string">
|
42
|
+
<Label>IP Address</Label>
|
43
|
+
<Description>The IP address for the Ops Manager. Leave blank if DHCP is desired.</Description>
|
44
|
+
</Property>
|
45
|
+
<Property ovf:key="netmask0" ovf:userConfigurable="true" ovf:type="string">
|
46
|
+
<Label>Netmask</Label>
|
47
|
+
<Description>The netmask for the Ops Manager's network. Leave blank if DHCP is desired.</Description>
|
48
|
+
</Property>
|
49
|
+
<Property ovf:key="gateway" ovf:userConfigurable="true" ovf:type="string">
|
50
|
+
<Label>Default Gateway</Label>
|
51
|
+
<Description>The default gateway address for the Ops Manager's network. Leave blank if DHCP is desired.</Description>
|
52
|
+
</Property>
|
53
|
+
<Property ovf:key="DNS" ovf:userConfigurable="true" ovf:type="string">
|
54
|
+
<Label>DNS</Label>
|
55
|
+
<Description>The domain name servers for the Ops Manager (comma separated). Leave blank if DHCP is desired.</Description>
|
56
|
+
</Property>
|
57
|
+
<Property ovf:key="ntp_servers" ovf:userConfigurable="true" ovf:type="string">
|
58
|
+
<Label>NTP Servers</Label>
|
59
|
+
<Description>Comma-delimited list of NTP servers</Description>
|
60
|
+
</Property>
|
61
|
+
<Property ovf:key="admin_password" ovf:required="true" ovf:userConfigurable="true" ovf:type="password">
|
62
|
+
<Label>Admin Password</Label>
|
63
|
+
<Description>This password is used to SSH into the Ops Manager. The username is 'ubuntu'.</Description>
|
64
|
+
</Property>
|
65
|
+
<Property ovf:key="custom_hostname" ovf:userConfigurable="true" ovf:type="string">
|
66
|
+
<Label>Custom Hostname</Label>
|
67
|
+
<Description>This will be set as the hostname on the VM. Default: 'pivotal-ops-manager'.</Description>
|
68
|
+
</Property>
|
69
|
+
</ProductSection>
|
70
|
+
|
71
|
+
<AnnotationSection>
|
72
|
+
<Info/>
|
73
|
+
<Annotation>Ops Manager for Pivotal Cloud Foundry
|
74
|
+
installs and manages PCF products and services.</Annotation>
|
75
|
+
</AnnotationSection>
|
76
|
+
|
77
|
+
<VirtualHardwareSection ovf:required="false" ovf:transport="com.vmware.guestInfo">
|
78
|
+
<Info>Virtual hardware requirements for a virtual machine</Info>
|
79
|
+
<System>
|
80
|
+
<vssd:ElementName>Virtual Hardware Family</vssd:ElementName>
|
81
|
+
<vssd:InstanceID>0</vssd:InstanceID>
|
82
|
+
<vssd:VirtualSystemIdentifier>FAKE_FILENAME</vssd:VirtualSystemIdentifier>
|
83
|
+
<vssd:VirtualSystemType>vmx-09</vssd:VirtualSystemType>
|
84
|
+
</System>
|
85
|
+
<Item>
|
86
|
+
<rasd:Caption>1 virtual CPU</rasd:Caption>
|
87
|
+
<rasd:Description>Number of virtual CPUs</rasd:Description>
|
88
|
+
<rasd:ElementName>1 virtual CPU</rasd:ElementName>
|
89
|
+
<rasd:InstanceID>1</rasd:InstanceID>
|
90
|
+
<rasd:ResourceType>3</rasd:ResourceType>
|
91
|
+
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>
|
92
|
+
</Item>
|
93
|
+
<Item>
|
94
|
+
<rasd:AllocationUnits>MegaBytes</rasd:AllocationUnits>
|
95
|
+
<rasd:Caption>8192 MB of memory</rasd:Caption>
|
96
|
+
<rasd:Description>Memory Size</rasd:Description>
|
97
|
+
<rasd:ElementName>8192 MB of memory</rasd:ElementName>
|
98
|
+
<rasd:InstanceID>2</rasd:InstanceID>
|
99
|
+
<rasd:ResourceType>4</rasd:ResourceType>
|
100
|
+
<rasd:VirtualQuantity>8192</rasd:VirtualQuantity>
|
101
|
+
</Item>
|
102
|
+
<Item>
|
103
|
+
<rasd:Address>0</rasd:Address>
|
104
|
+
<rasd:Caption>scsiController0</rasd:Caption>
|
105
|
+
<rasd:Description>SCSI Controller</rasd:Description>
|
106
|
+
<rasd:ElementName>scsiController0</rasd:ElementName>
|
107
|
+
<rasd:InstanceID>3</rasd:InstanceID>
|
108
|
+
<rasd:ResourceSubType>lsilogic</rasd:ResourceSubType>
|
109
|
+
<rasd:ResourceType>6</rasd:ResourceType>
|
110
|
+
</Item>
|
111
|
+
<Item>
|
112
|
+
<rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
|
113
|
+
<rasd:Caption>Ethernet adapter on 'Network 1'</rasd:Caption>
|
114
|
+
<rasd:Connection>Network 1</rasd:Connection>
|
115
|
+
<rasd:ElementName>Ethernet adapter on 'Network 1'</rasd:ElementName>
|
116
|
+
<rasd:InstanceID>4</rasd:InstanceID>
|
117
|
+
<rasd:ResourceSubType>E1000</rasd:ResourceSubType>
|
118
|
+
<rasd:ResourceType>10</rasd:ResourceType>
|
119
|
+
</Item>
|
120
|
+
<Item>
|
121
|
+
<rasd:AddressOnParent>0</rasd:AddressOnParent>
|
122
|
+
<rasd:Caption>disk1</rasd:Caption>
|
123
|
+
<rasd:Description>Disk Image</rasd:Description>
|
124
|
+
<rasd:ElementName>disk1</rasd:ElementName>
|
125
|
+
<rasd:HostResource>/disk/vmdisk1</rasd:HostResource>
|
126
|
+
<rasd:InstanceID>5</rasd:InstanceID>
|
127
|
+
<rasd:Parent>3</rasd:Parent>
|
128
|
+
<rasd:ResourceType>17</rasd:ResourceType>
|
129
|
+
</Item>
|
130
|
+
</VirtualHardwareSection>
|
131
|
+
</VirtualSystem>
|
132
|
+
</Envelope>
|
@@ -320,6 +320,27 @@ module VmShepherd
|
|
320
320
|
end
|
321
321
|
end
|
322
322
|
|
323
|
+
context 'when the instance type is specified in the vm config' do
|
324
|
+
let(:vm_config) do
|
325
|
+
{
|
326
|
+
'vm_name' => 'some-vm-name',
|
327
|
+
'key_name' => 'ssh-key-name',
|
328
|
+
'instance_type' => 't3.medium'
|
329
|
+
}
|
330
|
+
end
|
331
|
+
|
332
|
+
it 'creates an instance' do
|
333
|
+
expect(ec2).to receive_message_chain(:instances, :create).with(
|
334
|
+
image_id: ami_id,
|
335
|
+
key_name: 'ssh-key-name',
|
336
|
+
security_group_ids: ['security-group-id'],
|
337
|
+
subnet: 'public-subnet-id',
|
338
|
+
instance_type: 't3.medium').and_return(instance)
|
339
|
+
|
340
|
+
ami_manager.deploy(ami_file_path: ami_file_path, vm_config: vm_config)
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
323
344
|
context 'when the ip address is in use' do
|
324
345
|
it 'retries until the IP address is available' do
|
325
346
|
expect(instances).to receive(:create).and_raise(AWS::EC2::Errors::InvalidIPAddress::InUse).once
|
@@ -300,30 +300,100 @@ module VmShepherd
|
|
300
300
|
context 'and it is true' do
|
301
301
|
before { stub_const('ENV', {'PROVISION_WITH_PASSWORD' => 'true'}) }
|
302
302
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
303
|
+
context 'when the vm_password is set' do
|
304
|
+
before { stub_const('ENV', {'PROVISION_WITH_PASSWORD' => 'true', 'VSPHERE_VM_PASSWORD' => 'a-password'}) }
|
305
|
+
it 'deploys with the set vm password' do
|
306
|
+
expect(first_ova_manager).to receive(:deploy).with(
|
307
|
+
'FIRST_FAKE_PATH',
|
308
|
+
{
|
309
|
+
ip: first_config.dig('vm', 'ip'),
|
310
|
+
gateway: first_config.dig('vm', 'gateway'),
|
311
|
+
netmask: first_config.dig('vm', 'netmask'),
|
312
|
+
dns: first_config.dig('vm', 'dns'),
|
313
|
+
ntp_servers: first_config.dig('vm', 'ntp_servers'),
|
314
|
+
cpus: first_config.dig('vm', 'cpus'),
|
315
|
+
ram_mb: first_config.dig('vm', 'ram_mb'),
|
316
|
+
vm_password: first_config.dig('vm', 'vm_password'),
|
317
|
+
public_ssh_key: 'A PUBLIC KEY',
|
318
|
+
custom_hostname: first_config.dig('vm', 'custom_hostname')
|
319
|
+
},
|
320
|
+
{
|
321
|
+
cluster: first_config.dig('vsphere', 'cluster'),
|
322
|
+
resource_pool: first_config.dig('vsphere', 'resource_pool'),
|
323
|
+
datastore: first_config.dig('vsphere', 'datastore'),
|
324
|
+
network: first_config.dig('vsphere', 'network'),
|
325
|
+
folder: first_config.dig('vsphere', 'folder'),
|
326
|
+
},
|
327
|
+
)
|
328
|
+
|
329
|
+
manager.deploy(paths: ['FIRST_FAKE_PATH'])
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
context 'when the ENV vsphere VM password is set' do
|
334
|
+
before do
|
335
|
+
stub_const('ENV', { 'PROVISION_WITH_PASSWORD' => 'true', 'VSPHERE_VM_PASSWORD' => 'a-password' })
|
336
|
+
first_config['vm']['vm_password'] = nil
|
337
|
+
end
|
338
|
+
|
339
|
+
it 'deploys with the ENV vm password' do
|
340
|
+
expect(first_ova_manager).to receive(:deploy).with(
|
341
|
+
'FIRST_FAKE_PATH',
|
342
|
+
{
|
343
|
+
ip: first_config.dig('vm', 'ip'),
|
344
|
+
gateway: first_config.dig('vm', 'gateway'),
|
345
|
+
netmask: first_config.dig('vm', 'netmask'),
|
346
|
+
dns: first_config.dig('vm', 'dns'),
|
347
|
+
ntp_servers: first_config.dig('vm', 'ntp_servers'),
|
348
|
+
cpus: first_config.dig('vm', 'cpus'),
|
349
|
+
ram_mb: first_config.dig('vm', 'ram_mb'),
|
350
|
+
vm_password: 'a-password',
|
351
|
+
public_ssh_key: 'A PUBLIC KEY',
|
352
|
+
custom_hostname: first_config.dig('vm', 'custom_hostname')
|
353
|
+
},
|
354
|
+
{
|
355
|
+
cluster: first_config.dig('vsphere', 'cluster'),
|
356
|
+
resource_pool: first_config.dig('vsphere', 'resource_pool'),
|
357
|
+
datastore: first_config.dig('vsphere', 'datastore'),
|
358
|
+
network: first_config.dig('vsphere', 'network'),
|
359
|
+
folder: first_config.dig('vsphere', 'folder'),
|
360
|
+
},
|
361
|
+
)
|
362
|
+
|
363
|
+
manager.deploy(paths: ['FIRST_FAKE_PATH'])
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
context 'and neither vm password is set' do
|
368
|
+
before do
|
369
|
+
first_config['vm']['vm_password'] = nil
|
370
|
+
end
|
371
|
+
|
372
|
+
it 'deploys with the hardcoded vm password' do
|
373
|
+
expect(first_ova_manager).to receive(:deploy).with(
|
374
|
+
'FIRST_FAKE_PATH',
|
375
|
+
{
|
376
|
+
ip: first_config.dig('vm', 'ip'),
|
377
|
+
gateway: first_config.dig('vm', 'gateway'),
|
378
|
+
netmask: first_config.dig('vm', 'netmask'),
|
379
|
+
dns: first_config.dig('vm', 'dns'),
|
380
|
+
ntp_servers: first_config.dig('vm', 'ntp_servers'),
|
381
|
+
cpus: first_config.dig('vm', 'cpus'),
|
382
|
+
ram_mb: first_config.dig('vm', 'ram_mb'),
|
383
|
+
vm_password: 'tempest',
|
384
|
+
public_ssh_key: 'A PUBLIC KEY',
|
385
|
+
custom_hostname: first_config.dig('vm', 'custom_hostname')
|
386
|
+
},
|
387
|
+
{
|
388
|
+
cluster: first_config.dig('vsphere', 'cluster'),
|
389
|
+
resource_pool: first_config.dig('vsphere', 'resource_pool'),
|
390
|
+
datastore: first_config.dig('vsphere', 'datastore'),
|
391
|
+
network: first_config.dig('vsphere', 'network'),
|
392
|
+
folder: first_config.dig('vsphere', 'folder'),
|
393
|
+
},
|
394
|
+
)
|
395
|
+
manager.deploy(paths: ['FIRST_FAKE_PATH'])
|
396
|
+
end
|
327
397
|
end
|
328
398
|
end
|
329
399
|
|
@@ -755,6 +825,8 @@ module VmShepherd
|
|
755
825
|
datacenter_folders_to_clean: first_config.dig('cleanup', 'datacenter_folders_to_clean'),
|
756
826
|
datastores: first_config.dig('cleanup', 'datastores'),
|
757
827
|
datastore_folders_to_clean: first_config.dig('cleanup', 'datastore_folders_to_clean'),
|
828
|
+
cluster_name: first_config.dig('vsphere', 'cluster'),
|
829
|
+
resource_pool_name: first_config.dig('vsphere', 'resource_pool'),
|
758
830
|
}
|
759
831
|
end
|
760
832
|
let(:last_ova_manager) { instance_double(VsphereManager) }
|
@@ -763,6 +835,8 @@ module VmShepherd
|
|
763
835
|
datacenter_folders_to_clean: last_config.dig('cleanup', 'datacenter_folders_to_clean'),
|
764
836
|
datastores: last_config.dig('cleanup', 'datastores'),
|
765
837
|
datastore_folders_to_clean: last_config.dig('cleanup', 'datastore_folders_to_clean'),
|
838
|
+
cluster_name: last_config.dig('vsphere', 'cluster'),
|
839
|
+
resource_pool_name: last_config.dig('vsphere', 'resource_pool'),
|
766
840
|
}
|
767
841
|
end
|
768
842
|
|
@@ -48,18 +48,20 @@ module VmShepherd
|
|
48
48
|
let(:ovf_template) { instance_double(RbVmomi::VIM::VirtualMachine, name: 'vm_name', add_delta_disk_layer_on_all_disks: nil, MarkAsTemplate: nil) }
|
49
49
|
let(:vsphere_config) { { folder: folder_name, datastore: datastore_name } }
|
50
50
|
let(:vm_config) { {ip: '10.0.0.1'} }
|
51
|
+
let(:ovf_path) { 'spec/fixtures/ova_manager/default.ovf' }
|
51
52
|
|
52
53
|
before do
|
53
54
|
allow(vsphere_manager).to receive(:system).with("nc -z -w 1 #{vm_config[:ip]} 443").and_return(false)
|
54
55
|
allow(vsphere_manager).to receive(:system).with(/tar xfv/).and_return(true)
|
55
|
-
allow(Dir).to receive(:[]).and_return([
|
56
|
+
allow(Dir).to receive(:[]).and_return([ovf_path])
|
57
|
+
allow(FileUtils).to receive(:remove_entry_secure)
|
56
58
|
allow(vsphere_manager).to receive(:datacenter).and_return(datacenter)
|
57
59
|
allow(vsphere_manager).to receive(:connection).and_return(connection)
|
58
60
|
allow(ovf_manager).to receive(:deployOVF).and_return(ovf_template)
|
59
61
|
allow(vsphere_manager).to receive(:ovf_template_options).and_return({})
|
60
62
|
end
|
61
63
|
|
62
|
-
context 'When
|
64
|
+
context 'When a property value is not set' do
|
63
65
|
it 'verifies the value of custom hostname is nil' do
|
64
66
|
expect(vsphere_manager).to receive(:create_vm_from_template).and_return(vm1)
|
65
67
|
allow(subject).to receive(:power_on_vm)
|
@@ -69,7 +71,34 @@ module VmShepherd
|
|
69
71
|
custom_hostname_property = options[:spec].vAppConfig.property.find do |prop|
|
70
72
|
prop.instance_variable_get(:@props)[:info].instance_variable_get(:@props)[:label] == 'custom_hostname'
|
71
73
|
end
|
74
|
+
expect(custom_hostname_property.info.value).to be_nil
|
75
|
+
task
|
76
|
+
end
|
77
|
+
|
78
|
+
subject.deploy(ova_path, vm_config, vsphere_config)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'When the ovf does not contain a public_ssh_key property' do
|
83
|
+
let(:ovf_path) { 'spec/fixtures/ova_manager/without_public_ssh_key.ovf' }
|
84
|
+
let(:vm_config) { {ip: '10.0.0.1', custom_hostname: 'meow' } }
|
85
|
+
|
86
|
+
it 'does not create a property spec' do
|
87
|
+
expect(vsphere_manager).to receive(:create_vm_from_template).and_return(vm1)
|
88
|
+
allow(subject).to receive(:power_on_vm)
|
89
|
+
allow(task).to receive(:wait_for_completion)
|
90
|
+
|
91
|
+
expect(vm1).to receive(:ReconfigVM_Task) do |options|
|
92
|
+
custom_hostname_property = options[:spec].vAppConfig.property.find do |prop|
|
93
|
+
prop.instance_variable_get(:@props)[:info].instance_variable_get(:@props)[:label] == 'custom_hostname'
|
94
|
+
end
|
95
|
+
expect(custom_hostname_property.info.key).to eq(6)
|
96
|
+
|
97
|
+
custom_hostname_property = options[:spec].vAppConfig.property.find do |prop|
|
98
|
+
prop.instance_variable_get(:@props)[:info].instance_variable_get(:@props)[:label] == 'public_ssh_key'
|
99
|
+
end
|
72
100
|
expect(custom_hostname_property).to be_nil
|
101
|
+
|
73
102
|
task
|
74
103
|
end
|
75
104
|
|
data/vm_shepherd.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vm_shepherd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ops Manager Team
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-v1
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - '='
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 1.11.3
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: xmlrpc
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: bundler
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -167,7 +181,9 @@ files:
|
|
167
181
|
- lib/vm_shepherd/version.rb
|
168
182
|
- lib/vm_shepherd/vsphere_manager.rb
|
169
183
|
- spec/backport_refinements_spec.rb
|
184
|
+
- spec/fixtures/ova_manager/default.ovf
|
170
185
|
- spec/fixtures/ova_manager/foo.ova
|
186
|
+
- spec/fixtures/ova_manager/without_public_ssh_key.ovf
|
171
187
|
- spec/fixtures/shepherd/aws-no-elb.yml
|
172
188
|
- spec/fixtures/shepherd/aws.yml
|
173
189
|
- spec/fixtures/shepherd/openstack.yml
|
@@ -191,7 +207,7 @@ files:
|
|
191
207
|
homepage: ''
|
192
208
|
licenses: []
|
193
209
|
metadata: {}
|
194
|
-
post_install_message:
|
210
|
+
post_install_message:
|
195
211
|
rdoc_options: []
|
196
212
|
require_paths:
|
197
213
|
- lib
|
@@ -206,14 +222,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
206
222
|
- !ruby/object:Gem::Version
|
207
223
|
version: '0'
|
208
224
|
requirements: []
|
209
|
-
|
210
|
-
|
211
|
-
signing_key:
|
225
|
+
rubygems_version: 3.0.3
|
226
|
+
signing_key:
|
212
227
|
specification_version: 4
|
213
228
|
summary: A tool for booting and tearing down Ops Manager VMs on various Infrastructures.
|
214
229
|
test_files:
|
215
230
|
- spec/backport_refinements_spec.rb
|
231
|
+
- spec/fixtures/ova_manager/default.ovf
|
216
232
|
- spec/fixtures/ova_manager/foo.ova
|
233
|
+
- spec/fixtures/ova_manager/without_public_ssh_key.ovf
|
217
234
|
- spec/fixtures/shepherd/aws-no-elb.yml
|
218
235
|
- spec/fixtures/shepherd/aws.yml
|
219
236
|
- spec/fixtures/shepherd/openstack.yml
|