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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 756d9a70d96ccda7ec70f94f6696609f891ca919
4
- data.tar.gz: 8de386223858e604289442480c2afc2ec13b1a2b
2
+ SHA256:
3
+ metadata.gz: f0c4eae538ba72ae93a1bc16e07b93153be92fb3730b0c1ee995c75aaa7bbec6
4
+ data.tar.gz: c46d2af2473fb238bfb1bec5e85f8ec13d19f9a0e32f5d7c88db23bd0ad3ac25
5
5
  SHA512:
6
- metadata.gz: aeca796706b5cadc48fef207c01f27025dc53d7a042caa1d2e02d5734ac41f6b179c171be2ac107262989390ab58f0f786933fa0f6ad23795686fec4718bf787
7
- data.tar.gz: ba4b1dc89e6bf841b0081722120e39a23672e17a2c687383e283d4069ae59c9335c4afbd92a2eb82d93048e97565f653b0b380b9f29d6dd0fa6c0c491f12c166
6
+ metadata.gz: c24318537ae944dc68ccd6c214baa05c1906ba78011ae2391a4a1e8b115c5fddc20813f1556a0634a95436dfcf6b73679570bccb35386ac77936e576cc76628e
7
+ data.tar.gz: 8db0afde7bfa78be5acaf6d0736cd0a4d0fb75cce46054777873125a5ead9f6c4a479834bbeb69ab765cba7ca4bc9189708ec9b4ae6119148e231189bc04dcbc
data/.rubocop.yml CHANGED
@@ -3,4 +3,4 @@ AllCops:
3
3
  - Gemfile
4
4
  - Rakefile
5
5
  - vm_shepherd.gemspec
6
- TargetRubyVersion: 2.2
6
+ TargetRubyVersion: 2.6
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.2.4
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))
@@ -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)
@@ -1,3 +1,3 @@
1
1
  module VmShepherd
2
- VERSION = '3.6.0'.freeze
2
+ VERSION = '3.7.1'.freeze
3
3
  end
@@ -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 = Nokogiri::XML(File.read(ovf_file_path))
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
- ip_configuration = {
264
- 'ip0' => vm_config[:ip],
265
- 'netmask0' => vm_config[:netmask],
266
- 'gateway' => vm_config[:gateway],
267
- 'DNS' => vm_config[: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=#{ip_configuration.inspect}")
274
- # IP Configuration key order must match OVF template property order
275
- ip_configuration.each_with_index do |(key, value), i|
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 = i
280
- p.label = key
281
- p.value = 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
- it 'deploys with the set vm password' do
304
- expect(first_ova_manager).to receive(:deploy).with(
305
- 'FIRST_FAKE_PATH',
306
- {
307
- ip: first_config.dig('vm', 'ip'),
308
- gateway: first_config.dig('vm', 'gateway'),
309
- netmask: first_config.dig('vm', 'netmask'),
310
- dns: first_config.dig('vm', 'dns'),
311
- ntp_servers: first_config.dig('vm', 'ntp_servers'),
312
- cpus: first_config.dig('vm', 'cpus'),
313
- ram_mb: first_config.dig('vm', 'ram_mb'),
314
- vm_password: first_config.dig('vm', 'vm_password'),
315
- public_ssh_key: 'A PUBLIC KEY',
316
- custom_hostname: first_config.dig('vm', 'custom_hostname')
317
- },
318
- {
319
- cluster: first_config.dig('vsphere', 'cluster'),
320
- resource_pool: first_config.dig('vsphere', 'resource_pool'),
321
- datastore: first_config.dig('vsphere', 'datastore'),
322
- network: first_config.dig('vsphere', 'network'),
323
- folder: first_config.dig('vsphere', 'folder'),
324
- },
325
- )
326
- manager.deploy(paths: ['FIRST_FAKE_PATH'])
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(['foo.ovf'])
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 custom hostname is not set' do
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
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.add_dependency 'ruby_vcloud_sdk', '0.7.4'
25
25
 
26
26
  spec.add_dependency 'rbvmomi', '1.11.3'
27
+ spec.add_dependency 'xmlrpc'
27
28
 
28
29
  spec.add_development_dependency 'bundler'
29
30
  spec.add_development_dependency 'rake'
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.6.0
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: 2018-08-23 00:00:00.000000000 Z
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
- rubyforge_project:
210
- rubygems_version: 2.4.5.1
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