bosh_vsphere_cpi 2.1.1 → 2.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 73c2f8de1b6a30b2e09442508f67a4429defaad3
4
- data.tar.gz: 8b6973f59b1e9df8353d4a530c236fe5b9ff0cfb
3
+ metadata.gz: 20484247b0bb76cefc40f2f28054428a6680991b
4
+ data.tar.gz: 1d48fb046acb02cf0417b6b803c28e6883291b0a
5
5
  SHA512:
6
- metadata.gz: ea07e43ec4a22772feab1ebd4bab1e30b7ffb66c42b84005ada82d12e36fd7fc521418685f539f48d183752387453ab8e4d9dc9072c79f4bb5a6c6fdeca22b8b
7
- data.tar.gz: ebe07d93fcb600539b6aeb6a778441159897c1b6661f564ba484726836d7eb5458c3219e25ed3d2f0ec20248d65a2aaf66c15781132cdf8ec74fba11a02e26f1
6
+ metadata.gz: 0ca9d5f7600ad20b84ce67c8ddeab6381c7d77ffa2baaff0323f492bfb267e57570385249b91f0c49970ddbb75b98c453b6422e02e5abd5c443f0e7f42d91627
7
+ data.tar.gz: 17673951c1c87149dc4e32ba21627f1d139a96af603d81cdd4deace7791dbcdf7a4cf341f9ec7ba0f5b825bb300e33ce3bd147beb60b2bc2cd387da756938bb1
@@ -13,7 +13,7 @@ module VSphereCloud
13
13
  def initialize(host, options={})
14
14
  @soap_stub = SoapStub.new(host, options[:soap_log]).create
15
15
 
16
- @service_instance =Vim::ServiceInstance.new('ServiceInstance', @soap_stub)
16
+ @service_instance = Vim::ServiceInstance.new('ServiceInstance', @soap_stub)
17
17
  @service_content = @service_instance.content
18
18
 
19
19
  @metrics_cache = {}
@@ -130,6 +130,31 @@ module VSphereCloud
130
130
  @service_content.search_index.find_by_inventory_path(full_path)
131
131
  end
132
132
 
133
+ def find_vm_by_ip(ip)
134
+ @service_content.search_index.find_by_ip(nil, ip, true)
135
+ end
136
+
137
+ def find_vm_by_name(datacenter, vm_name)
138
+ yield_all_resources_by_name(datacenter, 'VirtualMachine') do |vm_mob, name|
139
+ if name == vm_name
140
+ return vm_mob
141
+ end
142
+ end
143
+
144
+ nil
145
+ end
146
+
147
+ def find_all_stemcell_replicas(datacenter, stemcell_id)
148
+ matches = []
149
+ yield_all_resources_by_name(datacenter, 'VirtualMachine') do |vm_mob, name|
150
+ if name =~ Regexp.new(stemcell_id)
151
+ matches << vm_mob
152
+ end
153
+ end
154
+
155
+ matches
156
+ end
157
+
133
158
  def wait_for_task(task)
134
159
  interval = 1.0
135
160
  started = Time.now
@@ -208,13 +233,17 @@ module VSphereCloud
208
233
  disk_size_in_mb.nil? ? nil : Resources::Disk.new(disk_cid, disk_size_in_mb, datastore, disk_path)
209
234
  end
210
235
 
211
- def create_disk(datacenter, datastore, disk_cid, disk_folder, disk_size_in_mb)
236
+ def create_disk(datacenter, datastore, disk_cid, disk_folder, disk_size_in_mb, disk_type)
237
+ if disk_type.nil?
238
+ raise 'no disk type specified'
239
+ end
240
+
212
241
  disk_path = "[#{datastore.name}] #{disk_folder}/#{disk_cid}.vmdk"
213
242
 
214
243
  create_parent_folder(datacenter, disk_path)
215
244
 
216
245
  disk_spec = VimSdk::Vim::VirtualDiskManager::FileBackedVirtualDiskSpec.new
217
- disk_spec.disk_type = 'preallocated'
246
+ disk_spec.disk_type = disk_type
218
247
  disk_spec.capacity_kb = disk_size_in_mb * 1024
219
248
  disk_spec.adapter_type = 'lsiLogic'
220
249
 
@@ -296,5 +325,55 @@ module VSphereCloud
296
325
  metrics.each { |metric| result[metric_names[metric.counter_id]] = metric }
297
326
  result
298
327
  end
328
+
329
+ def create_filter_spec(datacenter, resource_type, property_names)
330
+ # Create a view to list all the resources in the root folder
331
+ container_view = @service_content.view_manager.create_container_view(datacenter.mob, [resource_type], true)
332
+
333
+ # Create an object spec to define the beginning of the traversal
334
+ object_spec = VimSdk::Vmodl::Query::PropertyCollector::ObjectSpec.new
335
+ object_spec.obj = container_view
336
+ object_spec.skip = false
337
+
338
+ # Create a traversal spec to select all objects in the 'view' of the ContainerView
339
+ vm_traversal_spec = VimSdk::Vmodl::Query::PropertyCollector::TraversalSpec.new
340
+ vm_traversal_spec.name = 'searchTraversalSpec'
341
+ vm_traversal_spec.path = 'view'
342
+ vm_traversal_spec.type = 'ContainerView'
343
+ object_spec.select_set << vm_traversal_spec
344
+
345
+ # Specify the properties for retrieval
346
+ property_spec = VimSdk::Vmodl::Query::PropertyCollector::PropertySpec.new
347
+ property_spec.type = resource_type
348
+ property_spec.path_set.concat(property_names)
349
+ property_spec.all = false
350
+
351
+ filter_spec = VimSdk::Vmodl::Query::PropertyCollector::FilterSpec.new
352
+ filter_spec.object_set << object_spec
353
+ filter_spec.prop_set << property_spec
354
+ filter_spec
355
+ end
356
+
357
+ def yield_all_resources_by_name(datacenter, type)
358
+ raise 'Requires a vSphere object type' if type.nil?
359
+ # Collect all the 'name' attributes of all VMs in the datacenter
360
+ vm_filter_spec = create_filter_spec(datacenter, type, ['name'])
361
+ ro = VimSdk::Vmodl::Query::PropertyCollector::RetrieveOptions.new
362
+ result = @service_content.property_collector.retrieve_properties_ex([vm_filter_spec], ro)
363
+
364
+ # Retrieve Properties Ex returns paginated results, so we continue retrieving
365
+ # more pages if the token indicates there are more pages.
366
+ token = "not nil"
367
+ until token.nil?
368
+ result.objects.each do |object_content|
369
+ # Yield the object MOB and its name
370
+ yield object_content.obj, object_content.prop_set.first.val
371
+ end
372
+ token = result.token
373
+ unless token.nil?
374
+ result = @service_content.property_collector.continue_retrieve_properties_ex(token)
375
+ end
376
+ end
377
+ end
299
378
  end
300
379
  end
@@ -133,25 +133,24 @@ module VSphereCloud
133
133
  with_thread_name("delete_stemcell(#{stemcell})") do
134
134
  Bosh::ThreadPool.new(max_threads: 32, logger: @logger).wrap do |pool|
135
135
  @logger.info("Looking for stemcell replicas in: #{@datacenter.name}")
136
- templates = @cloud_searcher.get_property(@datacenter.template_folder.mob, Vim::Folder, 'childEntity', ensure_all: true)
137
- template_properties = @cloud_searcher.get_properties(templates, Vim::VirtualMachine, ['name'])
138
- template_properties.each_value do |properties|
139
- template_name = properties['name'].gsub('%2f', '/')
140
- if template_name.split('/').first.strip == stemcell
141
- @logger.info("Found: #{template_name}")
142
- pool.process do
143
- @logger.info("Deleting: #{template_name}")
144
- client.delete_vm(properties[:obj])
145
- @logger.info("Deleted: #{template_name}")
146
- end
136
+ matches = client.find_all_stemcell_replicas(@datacenter, stemcell)
137
+
138
+ matches.each do |sc|
139
+ sc_name = sc.name
140
+ @logger.info("Found: #{sc_name}")
141
+ pool.process do
142
+ @logger.info("Deleting: #{sc_name}")
143
+ client.delete_vm(sc)
144
+ @logger.info("Deleted: #{sc_name}")
147
145
  end
148
146
  end
147
+
149
148
  end
150
149
  end
151
150
  end
152
151
 
153
152
  def stemcell_vm(name)
154
- client.find_by_inventory_path([@datacenter.name, 'vm', @datacenter.template_folder.path_components, name])
153
+ client.find_vm_by_name(@datacenter, name)
155
154
  end
156
155
 
157
156
  def create_vm(agent_id, stemcell, cloud_properties, networks, disk_locality = nil, environment = nil)
@@ -381,7 +380,8 @@ module VSphereCloud
381
380
  cluster = @datacenter.clusters[vm.cluster]
382
381
  end
383
382
 
384
- disk = disk_provider.create(size_in_mb, cluster)
383
+ disk_type = cloud_properties['type']
384
+ disk = disk_provider.create(size_in_mb, disk_type, cluster)
385
385
  @logger.info("Created disk: #{disk.inspect}")
386
386
  disk.cid
387
387
  end
@@ -398,21 +398,18 @@ module VSphereCloud
398
398
  end
399
399
 
400
400
  def replicate_stemcell(cluster, datastore, stemcell)
401
- stemcell_vm_path_components = [cluster.datacenter.name, 'vm', cluster.datacenter.template_folder.path_components, stemcell]
402
- stemcell_vm = client.find_by_inventory_path(stemcell_vm_path_components)
403
- raise "Could not find VM for stemcell '#{stemcell}' at path '#{stemcell_vm_path_components.join("/")}'" if stemcell_vm.nil?
401
+ stemcell_vm = client.find_vm_by_name(@datacenter, stemcell)
402
+ raise "Could not find VM for stemcell '#{stemcell}'" if stemcell_vm.nil?
404
403
  stemcell_datastore = @cloud_searcher.get_property(stemcell_vm, Vim::VirtualMachine, 'datastore', ensure_all: true)
405
404
 
406
405
  if stemcell_datastore != datastore.mob
407
406
  @logger.info("Stemcell lives on a different datastore, looking for a local copy of: #{stemcell}.")
408
407
  local_stemcell_name = "#{stemcell} %2f #{datastore.mob.__mo_id__}"
409
- local_stemcell_path =
410
- [cluster.datacenter.name, 'vm', cluster.datacenter.template_folder.path_components, local_stemcell_name]
411
- replicated_stemcell_vm = client.find_by_inventory_path(local_stemcell_path)
412
408
 
409
+ replicated_stemcell_vm = client.find_vm_by_name(@datacenter, local_stemcell_name)
413
410
  if replicated_stemcell_vm.nil?
414
411
  @logger.info("Cluster doesn't have stemcell #{stemcell}, replicating")
415
- replicated_stemcell_vm = replicate_stemcell_helper(stemcell, stemcell_vm, local_stemcell_name, cluster, datastore, replicated_stemcell_vm, local_stemcell_path)
412
+ replicated_stemcell_vm = replicate_stemcell_helper(stemcell, stemcell_vm, local_stemcell_name, cluster, datastore, replicated_stemcell_vm)
416
413
  else
417
414
  @logger.info("Found local stemcell replica: #{replicated_stemcell_vm}")
418
415
  end
@@ -704,7 +701,7 @@ module VSphereCloud
704
701
  placer.nil? ? @resources : placer
705
702
  end
706
703
 
707
- def replicate_stemcell_helper(stemcell, stemcell_vm, local_stemcell_name, cluster, datastore, replicated_stemcell_vm, local_stemcell_path)
704
+ def replicate_stemcell_helper(stemcell, stemcell_vm, local_stemcell_name, cluster, datastore, replicated_stemcell_vm)
708
705
  @logger.info("Replicating #{stemcell} (#{stemcell_vm}) to #{local_stemcell_name}")
709
706
  task = clone_vm(stemcell_vm,
710
707
  local_stemcell_name,
@@ -716,6 +713,8 @@ module VSphereCloud
716
713
  @logger.info("Replicated #{stemcell} (#{stemcell_vm}) to #{local_stemcell_name} (#{replicated_stemcell_vm})")
717
714
  rescue VSphereCloud::Client::DuplicateName => ex
718
715
  @logger.info("Stemcell is being replicated by another thread, waiting for #{local_stemcell_name} to be ready")
716
+ local_stemcell_path =
717
+ [cluster.datacenter.name, 'vm', cluster.datacenter.template_folder.path_components, local_stemcell_name]
719
718
  replicated_stemcell_vm = client.find_by_inventory_path(local_stemcell_path)
720
719
  # get_properties will ensure the existence of the snapshot by retrying.
721
720
  # This forces us to wait for a valid snapshot before returning with the
@@ -3,6 +3,16 @@ require 'cloud/vsphere/resources/disk'
3
3
 
4
4
  module VSphereCloud
5
5
  class DiskProvider
6
+ # https://pubs.vmware.com/vsphere-55/index.jsp?topic=%2Fcom.vmware.wssdk.apiref.doc%2Fvim.VirtualDiskManager.VirtualDiskType.html
7
+ SUPPORTED_DISK_TYPES = %w{
8
+ eagerZeroedThick
9
+ preallocated
10
+ thick
11
+ thin
12
+ }
13
+
14
+ DEFAULT_DISK_TYPE = 'preallocated'
15
+
6
16
  def initialize(virtual_disk_manager, datacenter, resources, disk_path, client, logger)
7
17
  @virtual_disk_manager = virtual_disk_manager
8
18
  @datacenter = datacenter
@@ -12,7 +22,16 @@ module VSphereCloud
12
22
  @logger = logger
13
23
  end
14
24
 
15
- def create(disk_size_in_mb, cluster)
25
+ def create(disk_size_in_mb, disk_type, cluster)
26
+ type = disk_type
27
+ if type.nil?
28
+ type = DEFAULT_DISK_TYPE
29
+ end
30
+
31
+ unless SUPPORTED_DISK_TYPES.include?(type)
32
+ raise "Disk type: '#{disk_type}' is not supported"
33
+ end
34
+
16
35
  if cluster
17
36
  datastore = @resources.pick_persistent_datastore_in_cluster(cluster.name, disk_size_in_mb)
18
37
  else
@@ -21,14 +40,17 @@ module VSphereCloud
21
40
  disk_cid = "disk-#{SecureRandom.uuid}"
22
41
  @logger.debug("Creating disk '#{disk_cid}' in datastore '#{datastore.name}'")
23
42
 
24
- @client.create_disk(@datacenter, datastore, disk_cid, @disk_path, disk_size_in_mb)
43
+ @client.create_disk(@datacenter, datastore, disk_cid, @disk_path, disk_size_in_mb, type)
25
44
  end
26
45
 
27
46
  def find_and_move(disk_cid, cluster, datacenter, accessible_datastores)
28
47
  disk = find(disk_cid)
29
48
  disk_in_persistent_datastore = @datacenter.persistent_datastores.include?(disk.datastore.name)
30
49
  disk_in_accessible_datastore = accessible_datastores.include?(disk.datastore.name)
31
- return disk if disk_in_persistent_datastore && disk_in_accessible_datastore
50
+ if disk_in_persistent_datastore && disk_in_accessible_datastore
51
+ @logger.info("Disk #{disk_cid} found in an accessible, persistent datastore '#{disk.datastore.name}'")
52
+ return disk
53
+ end
32
54
 
33
55
  destination_datastore = @resources.pick_persistent_datastore_in_cluster(cluster.name, disk.size_in_mb)
34
56
 
@@ -0,0 +1,41 @@
1
+ module VSphereCloud
2
+ class IPConflictDetector
3
+
4
+ def initialize(logger, client, networks)
5
+ @logger = logger
6
+ @client = client
7
+ @networks = networks
8
+ @desired_ip_mapping = []
9
+
10
+ @networks.map do |_, network_spec|
11
+ ip = network_spec['ip']
12
+ network_name = network_spec.fetch('cloud_properties', [])['name']
13
+
14
+ if ip && network_name
15
+ @desired_ip_mapping << {ip: ip, name: network_name}
16
+ end
17
+ end
18
+ end
19
+
20
+ def conflicts
21
+ conflicts = []
22
+ @desired_ip_mapping.each do |mapping|
23
+ @logger.info("Checking if ip '#{mapping[:ip]}' is in use")
24
+ vm = @client.find_vm_by_ip(mapping[:ip])
25
+ if vm.nil?
26
+ next
27
+ end
28
+
29
+ vm.guest.net.each do |nic|
30
+ if nic.ip_address.include?(mapping[:ip]) && nic.network == mapping[:name]
31
+ @logger.info("found conflicting vm: #{vm.name}, on network: #{mapping[:name]} with ip: #{mapping[:ip]}")
32
+ conflicts << {vm_name: vm.name, network_name: mapping[:name], ip: mapping[:ip]}
33
+ end
34
+ end
35
+ end
36
+
37
+ conflicts
38
+ end
39
+
40
+ end
41
+ end
@@ -139,7 +139,7 @@ module VSphereCloud
139
139
  available_datastores = datastores.reject { |datastore| datastore.free_space - size < DISK_HEADROOM }
140
140
 
141
141
  @logger.debug("Looking for a #{type} datastore in #{self.name} with #{size}MB free space.")
142
- @logger.debug("All datastores: #{datastores.map(&:debug_info)}")
142
+ @logger.debug("All datastores within cluster #{self.name}: #{datastores.map(&:debug_info)}")
143
143
  @logger.debug("Datastores with enough space: #{available_datastores.map(&:debug_info)}")
144
144
 
145
145
  selected_datastore = Util.weighted_random(available_datastores.map { |datastore| [datastore, datastore.free_space] })
@@ -68,12 +68,16 @@ module VSphereCloud
68
68
  end
69
69
 
70
70
  def clusters
71
- clusters = {}
72
- @clusters.each do |cluster_name, cluster_config|
73
- clusters[cluster_name] = @cluster_provider.find(cluster_name, cluster_config)
74
- end
75
71
  @logger.debug("All clusters provided: #{@clusters}")
76
- clusters
72
+ @clusters.keys.inject({}) do |acc, cluster_name|
73
+ acc[cluster_name] = find_cluster(cluster_name)
74
+ acc
75
+ end
76
+ end
77
+
78
+ def find_cluster(cluster_name)
79
+ cluster_config = @clusters[cluster_name]
80
+ @cluster_provider.find(cluster_name, cluster_config)
77
81
  end
78
82
 
79
83
  def persistent_datastores
@@ -103,7 +107,7 @@ module VSphereCloud
103
107
  available_datastores = datastores.reject { |datastore| datastore.free_space - size < DISK_HEADROOM }
104
108
 
105
109
  @logger.debug("Looking for a '#{type}' datastore with #{size}MB free space.")
106
- @logger.debug("All datastores: #{datastores.map(&:debug_info)}")
110
+ @logger.debug("All datastores within datacenter #{self.name}: #{datastores.map(&:debug_info)}")
107
111
  @logger.debug("Datastores with enough space: #{available_datastores.map(&:debug_info)}")
108
112
 
109
113
  selected_datastore = Util.weighted_random(available_datastores.map { |datastore| [datastore, datastore.free_space] })
@@ -18,6 +18,11 @@ module VSphereCloud
18
18
  end
19
19
 
20
20
  def create(agent_id, stemcell_cid, networks, persistent_disk_cids, environment)
21
+ ip_conflicts = IPConflictDetector.new(@logger, @client, networks).conflicts
22
+ unless ip_conflicts.empty?
23
+ raise "Cannot create new VM because of IP conflicts with other VMs on the same networks: #{ip_conflicts}"
24
+ end
25
+
21
26
  stemcell_vm = @cpi.stemcell_vm(stemcell_cid)
22
27
  raise "Could not find VM for stemcell '#{stemcell_cid}'" if stemcell_vm.nil?
23
28
 
@@ -7,8 +7,8 @@ module VSphereCloud
7
7
  end
8
8
 
9
9
  def find(vm_cid)
10
- vm_mob = @client.find_by_inventory_path(@datacenter.vm_path(vm_cid))
11
- raise Bosh::Clouds::VMNotFound, "VM '#{vm_cid}' not found at path '#{@datacenter.vm_path(vm_cid)}'" if vm_mob.nil?
10
+ vm_mob = @client.find_vm_by_name(@datacenter, vm_cid)
11
+ raise Bosh::Clouds::VMNotFound, "VM '#{vm_cid}' not found in datacenter '#{@datacenter.name}'" if vm_mob.nil?
12
12
 
13
13
  Resources::VM.new(vm_cid, vm_mob, @client, @logger)
14
14
  end
data/lib/cloud/vsphere.rb CHANGED
@@ -31,6 +31,7 @@ require 'cloud/vsphere/resources/util'
31
31
  require 'cloud/vsphere/soap_stub'
32
32
  require 'cloud/vsphere/vm_creator_builder'
33
33
  require 'cloud/vsphere/vm_provider'
34
+ require 'cloud/vsphere/ip_conflict_detector'
34
35
 
35
36
  module Bosh
36
37
  module Clouds
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bosh_vsphere_cpi
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - VMware
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-02 00:00:00.000000000 Z
11
+ date: 2015-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bosh_common
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - '='
88
88
  - !ruby/object:Gem::Version
89
- version: 2.7.1
89
+ version: 2.4.0
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - '='
95
95
  - !ruby/object:Gem::Version
96
- version: 2.7.1
96
+ version: 2.4.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: mono_logger
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -131,6 +131,7 @@ files:
131
131
  - lib/cloud/vsphere/drs_rules/vm_attribute_manager.rb
132
132
  - lib/cloud/vsphere/file_provider.rb
133
133
  - lib/cloud/vsphere/fixed_cluster_placer.rb
134
+ - lib/cloud/vsphere/ip_conflict_detector.rb
134
135
  - lib/cloud/vsphere/lease_obtainer.rb
135
136
  - lib/cloud/vsphere/lease_updater.rb
136
137
  - lib/cloud/vsphere/object_stringifier.rb
@@ -198,7 +199,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
199
  version: '0'
199
200
  requirements: []
200
201
  rubyforge_project:
201
- rubygems_version: 2.2.5
202
+ rubygems_version: 2.2.2
202
203
  signing_key:
203
204
  specification_version: 4
204
205
  summary: BOSH VSphere CPI