bosh_vsphere_cpi 2.1.1 → 2.2.0

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
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