bosh_vsphere_cpi 2.0.0 → 2.1.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 +4 -4
- data/lib/cloud/vsphere.rb +1 -0
- data/lib/cloud/vsphere/agent_env.rb +2 -2
- data/lib/cloud/vsphere/client.rb +2 -12
- data/lib/cloud/vsphere/cloud.rb +33 -20
- data/lib/cloud/vsphere/cloud_searcher.rb +3 -3
- data/lib/cloud/vsphere/disk_provider.rb +12 -1
- data/lib/cloud/vsphere/file_provider.rb +2 -2
- data/lib/cloud/vsphere/fixed_cluster_placer.rb +7 -0
- data/lib/cloud/vsphere/object_stringifier.rb +15 -0
- data/lib/cloud/vsphere/resources.rb +4 -2
- data/lib/cloud/vsphere/resources/cluster.rb +14 -4
- data/lib/cloud/vsphere/resources/cluster_provider.rb +2 -2
- data/lib/cloud/vsphere/resources/datacenter.rb +16 -9
- data/lib/cloud/vsphere/resources/datastore.rb +2 -0
- data/lib/cloud/vsphere/resources/disk/ephemeral_disk.rb +2 -1
- data/lib/cloud/vsphere/resources/folder.rb +1 -1
- data/lib/cloud/vsphere/resources/vm.rb +10 -2
- data/lib/cloud/vsphere/vm_creator.rb +9 -4
- data/lib/cloud/vsphere/vm_provider.rb +1 -1
- metadata +3 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 60b9ea302efbf07e91dd0adc105f975ec8dcacd8
         | 
| 4 | 
            +
              data.tar.gz: 1c8ef64cfb700603dd0a14f8c3e4179461225e2d
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 6c86a93bead968a65f17b37c63b03110ec6a41d4ec8a6507796243a6d4a2da4e4327c41fb314e6deeeb4ee513d3c3321133fb45cd0cf7cbda8e4fba2132aa654
         | 
| 7 | 
            +
              data.tar.gz: 07864ca78d8e30f593e91f031d24248eedacdb93472d20654e3409f79fd2aa746d844dd75f54b7f018eb797c0108b9906faae4f58f17d4b20a92d2efc5d5fc0a
         | 
    
        data/lib/cloud/vsphere.rb
    CHANGED
    
    
| @@ -17,11 +17,11 @@ module VSphereCloud | |
| 17 17 | 
             
                  datastore_name = cdrom.backing.datastore.name
         | 
| 18 18 | 
             
                  datastore_pattern = Regexp.escape(datastore_name)
         | 
| 19 19 | 
             
                  result = env_iso_folder.match(/\[#{datastore_pattern}\] (.*)/)
         | 
| 20 | 
            -
                  raise Bosh::Clouds::CloudError.new( | 
| 20 | 
            +
                  raise Bosh::Clouds::CloudError.new("Could not find matching datastore name '#{datastore_name}'") unless result
         | 
| 21 21 | 
             
                  env_path = result[1]
         | 
| 22 22 |  | 
| 23 23 | 
             
                  contents = @file_provider.fetch_file(datacenter_name, datastore_name, "#{env_path}/env.json")
         | 
| 24 | 
            -
                  raise Bosh::Clouds::CloudError.new( | 
| 24 | 
            +
                  raise Bosh::Clouds::CloudError.new("Unable to load env.json from '#{env_path}/env.json'") unless contents
         | 
| 25 25 |  | 
| 26 26 | 
             
                  JSON.load(contents)
         | 
| 27 27 | 
             
                end
         | 
    
        data/lib/cloud/vsphere/client.rb
    CHANGED
    
    | @@ -62,7 +62,7 @@ module VSphereCloud | |
| 62 62 | 
             
                  raise 'Recommendations were detected, you may be running in Manual DRS mode. Aborting.' if result.recommendations.any?
         | 
| 63 63 |  | 
| 64 64 | 
             
                  if result.attempted.empty?
         | 
| 65 | 
            -
                    raise "Could not power on VM: #{result.not_attempted.map(&:msg).join(', ')}"
         | 
| 65 | 
            +
                    raise "Could not power on VM '#{vm}': #{result.not_attempted.map(&:fault).map(&:msg).join(', ')}"
         | 
| 66 66 | 
             
                  else
         | 
| 67 67 | 
             
                    task = result.attempted.first.task
         | 
| 68 68 | 
             
                    wait_for_task(task)
         | 
| @@ -120,16 +120,6 @@ module VSphereCloud | |
| 120 120 | 
             
                  @service_content.root_folder.create_folder(name)
         | 
| 121 121 | 
             
                end
         | 
| 122 122 |  | 
| 123 | 
            -
                def move_into_folder(folder, objects)
         | 
| 124 | 
            -
                  task = folder.move_into(objects)
         | 
| 125 | 
            -
                  wait_for_task(task)
         | 
| 126 | 
            -
                end
         | 
| 127 | 
            -
             | 
| 128 | 
            -
                def move_into_root_folder(objects)
         | 
| 129 | 
            -
                  task = @service_content.root_folder.move_into(objects)
         | 
| 130 | 
            -
                  wait_for_task(task)
         | 
| 131 | 
            -
                end
         | 
| 132 | 
            -
             | 
| 133 123 | 
             
                def delete_folder(folder)
         | 
| 134 124 | 
             
                  task = folder.destroy
         | 
| 135 125 | 
             
                  wait_for_task(task)
         | 
| @@ -152,7 +142,7 @@ module VSphereCloud | |
| 152 142 | 
             
                    )[task]
         | 
| 153 143 |  | 
| 154 144 | 
             
                    duration = Time.now - started
         | 
| 155 | 
            -
                    raise "Task  | 
| 145 | 
            +
                    raise "Task exceeded 60 minutes, task properties: #{properties}" if duration > 3600 # 1 hour
         | 
| 156 146 |  | 
| 157 147 | 
             
                    # Update the polling interval based on task progress
         | 
| 158 148 | 
             
                    if properties["info.progress"] && properties["info.progress"] > 0
         | 
    
        data/lib/cloud/vsphere/cloud.rb
    CHANGED
    
    | @@ -8,8 +8,16 @@ module VSphereCloud | |
| 8 8 | 
             
                include RetryBlock
         | 
| 9 9 |  | 
| 10 10 | 
             
                class TimeoutException < StandardError; end
         | 
| 11 | 
            +
                class NetworkException < StandardError
         | 
| 12 | 
            +
                  attr_accessor :vm_cid
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def message
         | 
| 15 | 
            +
                    super + (vm_cid ? " for VM '#{vm_cid}'" : '')
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 11 18 |  | 
| 12 19 | 
             
                attr_accessor :client
         | 
| 20 | 
            +
                attr_reader :datacenter
         | 
| 13 21 |  | 
| 14 22 | 
             
                def initialize(options)
         | 
| 15 23 | 
             
                  @config = Config.build(options)
         | 
| @@ -71,10 +79,10 @@ module VSphereCloud | |
| 71 79 | 
             
                    Dir.mktmpdir do |temp_dir|
         | 
| 72 80 | 
             
                      @logger.info("Extracting stemcell to: #{temp_dir}")
         | 
| 73 81 | 
             
                      output = `tar -C #{temp_dir} -xzf #{image} 2>&1`
         | 
| 74 | 
            -
                      raise "Corrupt image, tar exit status: #{$?.exitstatus} output: #{output}" if $?.exitstatus != 0
         | 
| 82 | 
            +
                      raise "Corrupt image '#{image}', tar exit status: #{$?.exitstatus}, output: #{output}" if $?.exitstatus != 0
         | 
| 75 83 |  | 
| 76 84 | 
             
                      ovf_file = Dir.entries(temp_dir).find { |entry| File.extname(entry) == '.ovf' }
         | 
| 77 | 
            -
                      raise  | 
| 85 | 
            +
                      raise "Missing OVF for stemcell '#{stemcell}'" if ovf_file.nil?
         | 
| 78 86 | 
             
                      ovf_file = File.join(temp_dir, ovf_file)
         | 
| 79 87 |  | 
| 80 88 | 
             
                      name = "sc-#{SecureRandom.uuid}"
         | 
| @@ -276,8 +284,12 @@ module VSphereCloud | |
| 276 284 | 
             
                    @logger.debug("Reading current agent env: #{env.pretty_inspect}")
         | 
| 277 285 |  | 
| 278 286 | 
             
                    devices = @cloud_searcher.get_property(vm.mob, Vim::VirtualMachine, 'config.hardware.device', ensure_all: true)
         | 
| 279 | 
            -
                     | 
| 280 | 
            -
             | 
| 287 | 
            +
                    begin
         | 
| 288 | 
            +
                      env['networks'] = generate_network_env(devices, networks, dvs_index)
         | 
| 289 | 
            +
                    rescue NetworkException => e
         | 
| 290 | 
            +
                      e.vm_cid = vm_cid
         | 
| 291 | 
            +
                      raise e
         | 
| 292 | 
            +
                    end
         | 
| 281 293 | 
             
                    @logger.debug("Updating agent env to: #{env.pretty_inspect}")
         | 
| 282 294 | 
             
                    location = get_vm_location(vm.mob, datacenter: @datacenter.name)
         | 
| 283 295 | 
             
                    @agent_env.set_env(vm.mob, location, env)
         | 
| @@ -334,7 +346,7 @@ module VSphereCloud | |
| 334 346 |  | 
| 335 347 | 
             
                    vm.reload
         | 
| 336 348 | 
             
                    virtual_disk = vm.disk_by_cid(disk.cid)
         | 
| 337 | 
            -
                    raise Bosh::Clouds::DiskNotAttached.new(true), "Disk  | 
| 349 | 
            +
                    raise Bosh::Clouds::DiskNotAttached.new(true), "Disk '#{disk.cid}' is not attached to VM '#{vm.cid}'" if virtual_disk.nil?
         | 
| 338 350 |  | 
| 339 351 | 
             
                    config = Vim::Vm::ConfigSpec.new
         | 
| 340 352 | 
             
                    config.device_change = []
         | 
| @@ -353,7 +365,7 @@ module VSphereCloud | |
| 353 365 | 
             
                      break if virtual_disk.nil?
         | 
| 354 366 | 
             
                      sleep(1.0)
         | 
| 355 367 | 
             
                    end
         | 
| 356 | 
            -
                    raise "Failed to detach disk | 
| 368 | 
            +
                    raise "Failed to detach disk '#{disk.cid}' from vm '#{vm.cid}'" unless virtual_disk.nil?
         | 
| 357 369 |  | 
| 358 370 | 
             
                    @logger.info('Finished detaching disk')
         | 
| 359 371 | 
             
                  end
         | 
| @@ -386,9 +398,9 @@ module VSphereCloud | |
| 386 398 | 
             
                end
         | 
| 387 399 |  | 
| 388 400 | 
             
                def replicate_stemcell(cluster, datastore, stemcell)
         | 
| 389 | 
            -
                   | 
| 390 | 
            -
             | 
| 391 | 
            -
                  raise "Could not find 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?
         | 
| 392 404 | 
             
                  stemcell_datastore = @cloud_searcher.get_property(stemcell_vm, Vim::VirtualMachine, 'datastore', ensure_all: true)
         | 
| 393 405 |  | 
| 394 406 | 
             
                  if stemcell_datastore != datastore.mob
         | 
| @@ -435,7 +447,9 @@ module VSphereCloud | |
| 435 447 | 
             
                  networks.each do |network_name, network|
         | 
| 436 448 | 
             
                    network_entry = network.dup
         | 
| 437 449 | 
             
                    v_network_name = network['cloud_properties']['name']
         | 
| 438 | 
            -
                     | 
| 450 | 
            +
                    network = nics[v_network_name]
         | 
| 451 | 
            +
                    raise NetworkException, "Could not find network '#{v_network_name}'" if network.nil?
         | 
| 452 | 
            +
                    nic = network.pop
         | 
| 439 453 | 
             
                    network_entry['mac'] = nic.mac_address
         | 
| 440 454 | 
             
                    network_env[network_name] = network_entry
         | 
| 441 455 | 
             
                  end
         | 
| @@ -481,7 +495,7 @@ module VSphereCloud | |
| 481 495 |  | 
| 482 496 | 
             
                    unless datastore_name
         | 
| 483 497 | 
             
                      devices = vm_properties['config.hardware.device']
         | 
| 484 | 
            -
                      datastore = get_primary_datastore(devices)
         | 
| 498 | 
            +
                      datastore = get_primary_datastore(devices, vm_name)
         | 
| 485 499 | 
             
                      datastore_name = @cloud_searcher.get_property(datastore, Vim::Datastore, 'name')
         | 
| 486 500 | 
             
                    end
         | 
| 487 501 | 
             
                  end
         | 
| @@ -489,17 +503,16 @@ module VSphereCloud | |
| 489 503 | 
             
                  { datacenter: datacenter_name, datastore: datastore_name, vm: vm_name }
         | 
| 490 504 | 
             
                end
         | 
| 491 505 |  | 
| 492 | 
            -
                def get_primary_datastore(devices)
         | 
| 506 | 
            +
                def get_primary_datastore(devices, vm_name = nil)
         | 
| 493 507 | 
             
                  ephemeral_disks = devices.select { |device| device.kind_of?(Vim::Vm::Device::VirtualDisk) &&
         | 
| 494 508 | 
             
                    device.backing.disk_mode != Vim::Vm::Device::VirtualDiskOption::DiskMode::INDEPENDENT_PERSISTENT }
         | 
| 495 509 |  | 
| 496 | 
            -
                  datastore =  | 
| 497 | 
            -
                  ephemeral_disks. | 
| 498 | 
            -
             | 
| 499 | 
            -
             | 
| 500 | 
            -
                     | 
| 501 | 
            -
             | 
| 502 | 
            -
                    end
         | 
| 510 | 
            +
                  datastore = ephemeral_disks.first.backing.datastore
         | 
| 511 | 
            +
                  disk_in_wrong_datastore = ephemeral_disks.find { |disk| !datastore.eql?(disk.backing.datastore) }
         | 
| 512 | 
            +
                  if disk_in_wrong_datastore
         | 
| 513 | 
            +
                    error_msg = vm_name ? "for VM '#{vm_name}'" : ""
         | 
| 514 | 
            +
                    raise "Ephemeral disks #{error_msg} should all be on the same datastore. " +
         | 
| 515 | 
            +
                        "Expected datastore '#{datastore}' to match datastore '#{disk_in_wrong_datastore.backing.datastore}'"
         | 
| 503 516 | 
             
                  end
         | 
| 504 517 |  | 
| 505 518 | 
             
                  datastore
         | 
| @@ -524,7 +537,7 @@ module VSphereCloud | |
| 524 537 | 
             
                end
         | 
| 525 538 |  | 
| 526 539 | 
             
                def create_nic_config_spec(v_network_name, network, controller_key, dvs_index)
         | 
| 527 | 
            -
                  raise " | 
| 540 | 
            +
                  raise "Invalid network '#{v_network_name}'" if network.nil?
         | 
| 528 541 | 
             
                  if network.class == Vim::Dvs::DistributedVirtualPortgroup
         | 
| 529 542 | 
             
                    portgroup_properties = @cloud_searcher.get_properties(network,
         | 
| 530 543 | 
             
                                                                 Vim::Dvs::DistributedVirtualPortgroup,
         | 
| @@ -50,7 +50,7 @@ module VSphereCloud | |
| 50 50 | 
             
                        end
         | 
| 51 51 | 
             
                      end
         | 
| 52 52 | 
             
                      unless remaining_properties.empty?
         | 
| 53 | 
            -
                        raise MissingPropertiesException.new("The object[s] #{obj} " +
         | 
| 53 | 
            +
                        raise MissingPropertiesException.new("The object[s] '#{obj}' " +
         | 
| 54 54 | 
             
                          "should have the following properties: #{properties.pretty_inspect}, " +
         | 
| 55 55 | 
             
                          "but they were missing these: #{remaining_properties.pretty_inspect}.")
         | 
| 56 56 | 
             
                      end
         | 
| @@ -93,8 +93,8 @@ module VSphereCloud | |
| 93 93 |  | 
| 94 94 | 
             
                def get_managed_object(type, options)
         | 
| 95 95 | 
             
                  result = get_managed_objects(type, options)
         | 
| 96 | 
            -
                  raise "Could not find #{type}: #{options.pretty_inspect}" if result.length == 0
         | 
| 97 | 
            -
                  raise "Found more than one #{type}: #{options.pretty_inspect}" if result.length > 1
         | 
| 96 | 
            +
                  raise "Could not find '#{type}': #{options.pretty_inspect}" if result.length == 0
         | 
| 97 | 
            +
                  raise "Found more than one '#{type}': #{options.pretty_inspect}" if result.length > 1
         | 
| 98 98 | 
             
                  result.first
         | 
| 99 99 | 
             
                end
         | 
| 100 100 |  | 
| @@ -26,7 +26,9 @@ module VSphereCloud | |
| 26 26 |  | 
| 27 27 | 
             
                def find_and_move(disk_cid, cluster, datacenter, accessible_datastores)
         | 
| 28 28 | 
             
                  disk = find(disk_cid)
         | 
| 29 | 
            -
                   | 
| 29 | 
            +
                  disk_in_persistent_datastore = @datacenter.persistent_datastores.include?(disk.datastore.name)
         | 
| 30 | 
            +
                  disk_in_accessible_datastore = accessible_datastores.include?(disk.datastore.name)
         | 
| 31 | 
            +
                  return disk if disk_in_persistent_datastore && disk_in_accessible_datastore
         | 
| 30 32 |  | 
| 31 33 | 
             
                  destination_datastore = @resources.pick_persistent_datastore_in_cluster(cluster.name, disk.size_in_mb)
         | 
| 32 34 |  | 
| @@ -46,6 +48,15 @@ module VSphereCloud | |
| 46 48 | 
             
                  @logger.debug("Looking for disk #{disk_cid} in datastores: #{persistent_datastores}")
         | 
| 47 49 | 
             
                  persistent_datastores.each do |_, datastore|
         | 
| 48 50 | 
             
                    disk = @client.find_disk(disk_cid, datastore, @disk_path)
         | 
| 51 | 
            +
                    @logger.debug("disk #{disk_cid} found in: #{datastore}") unless disk.nil?
         | 
| 52 | 
            +
                    return disk unless disk.nil?
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  other_datastores = @datacenter.all_datastores.reject{|datastore_name, _| persistent_datastores[datastore_name] }
         | 
| 56 | 
            +
                  @logger.debug("disk #{disk_cid} not found in filtered persistent datastores, trying other datastores: #{other_datastores}")
         | 
| 57 | 
            +
                  other_datastores.each do |_, datastore|
         | 
| 58 | 
            +
                    disk = @client.find_disk(disk_cid, datastore, @disk_path)
         | 
| 59 | 
            +
                    @logger.debug("disk #{disk_cid} found in: #{datastore}") unless disk.nil?
         | 
| 49 60 | 
             
                    return disk unless disk.nil?
         | 
| 50 61 | 
             
                  end
         | 
| 51 62 |  | 
| @@ -19,7 +19,7 @@ module VSphereCloud | |
| 19 19 | 
             
                    elsif response.code == 404
         | 
| 20 20 | 
             
                      nil
         | 
| 21 21 | 
             
                    else
         | 
| 22 | 
            -
                      raise "Could not fetch file | 
| 22 | 
            +
                      raise "Could not fetch file '#{url}', received status code '#{response.code}'"
         | 
| 23 23 | 
             
                    end
         | 
| 24 24 | 
             
                  end
         | 
| 25 25 | 
             
                end
         | 
| @@ -35,7 +35,7 @@ module VSphereCloud | |
| 35 35 | 
             
                      { 'Content-Type' => 'application/octet-stream', 'Content-Length' => contents.length })
         | 
| 36 36 |  | 
| 37 37 | 
             
                    unless response.code < 400
         | 
| 38 | 
            -
                      raise "Could not upload file | 
| 38 | 
            +
                      raise "Could not upload file '#{url}', received status code '#{response.code}'"
         | 
| 39 39 | 
             
                    end
         | 
| 40 40 | 
             
                  end
         | 
| 41 41 | 
             
                end
         | 
| @@ -1,5 +1,8 @@ | |
| 1 1 | 
             
            module VSphereCloud
         | 
| 2 2 | 
             
              class FixedClusterPlacer
         | 
| 3 | 
            +
                include ObjectStringifier
         | 
| 4 | 
            +
                stringify_with :cluster
         | 
| 5 | 
            +
             | 
| 3 6 | 
             
                attr_reader :drs_rules
         | 
| 4 7 |  | 
| 5 8 | 
             
                def initialize(cluster, drs_rules)
         | 
| @@ -21,5 +24,9 @@ module VSphereCloud | |
| 21 24 | 
             
                def pick_persistent_datastore(_, _)
         | 
| 22 25 | 
             
                  raise NotImplementedError
         | 
| 23 26 | 
             
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                private
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                attr_reader :cluster
         | 
| 24 31 | 
             
              end
         | 
| 25 32 | 
             
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            module VSphereCloud
         | 
| 2 | 
            +
              module ObjectStringifier
         | 
| 3 | 
            +
                def self.included(base)
         | 
| 4 | 
            +
                  base.extend ClassMethods
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                module ClassMethods
         | 
| 8 | 
            +
                  def stringify_with(*attributes)
         | 
| 9 | 
            +
                    define_method(:to_s) do
         | 
| 10 | 
            +
                      "(#{self.class.name} (#{attributes.map{|attr| "#{attr}=\"#{self.send(attr)}\""}.join(', ')}))"
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -2,6 +2,8 @@ require 'cloud/vsphere/resources/datacenter' | |
| 2 2 |  | 
| 3 3 | 
             
            module VSphereCloud
         | 
| 4 4 | 
             
              class Resources
         | 
| 5 | 
            +
                include ObjectStringifier
         | 
| 6 | 
            +
                stringify_with :datacenter
         | 
| 5 7 | 
             
                MEMORY_HEADROOM = 128
         | 
| 6 8 | 
             
                DISK_HEADROOM = 1024
         | 
| 7 9 | 
             
                STALE_TIMEOUT = 60
         | 
| @@ -28,7 +30,7 @@ module VSphereCloud | |
| 28 30 | 
             
                  @lock.synchronize do
         | 
| 29 31 | 
             
                    cluster = @datacenter.clusters[cluster_name]
         | 
| 30 32 | 
             
                    if cluster.nil?
         | 
| 31 | 
            -
                      raise Bosh::Clouds::CloudError, "Couldn't find cluster '#{cluster_name}'. Found #{@datacenter.clusters.values.map(&:name)}"
         | 
| 33 | 
            +
                      raise Bosh::Clouds::CloudError, "Couldn't find cluster '#{cluster_name}'. Found: #{@datacenter.clusters.values.map(&:name)}"
         | 
| 32 34 | 
             
                    end
         | 
| 33 35 |  | 
| 34 36 | 
             
                    datastore = cluster.pick_persistent(disk_size_in_mb)
         | 
| @@ -122,7 +124,7 @@ module VSphereCloud | |
| 122 124 |  | 
| 123 125 | 
             
                private
         | 
| 124 126 |  | 
| 125 | 
            -
                attr_reader :config
         | 
| 127 | 
            +
                attr_reader :config, :datacenter
         | 
| 126 128 |  | 
| 127 129 |  | 
| 128 130 | 
             
                class PersistentDiskIndex
         | 
| @@ -4,6 +4,8 @@ module VSphereCloud | |
| 4 4 | 
             
              class Resources
         | 
| 5 5 | 
             
                class Cluster
         | 
| 6 6 | 
             
                  include VimSdk
         | 
| 7 | 
            +
                  include ObjectStringifier
         | 
| 8 | 
            +
                  stringify_with :name
         | 
| 7 9 |  | 
| 8 10 | 
             
                  PROPERTIES = %w(name datastore resourcePool host)
         | 
| 9 11 | 
             
                  HOST_PROPERTIES = %w(hardware.memorySize runtime.inMaintenanceMode)
         | 
| @@ -114,14 +116,22 @@ module VSphereCloud | |
| 114 116 | 
             
                    @persistent_datastores ||= select_datastores(@datacenter_persistent_datastore_pattern)
         | 
| 115 117 | 
             
                  end
         | 
| 116 118 |  | 
| 119 | 
            +
                  def all_datastores
         | 
| 120 | 
            +
                    @all_datastores ||= Datastore.build_from_client(
         | 
| 121 | 
            +
                      @client,
         | 
| 122 | 
            +
                      properties['datastore']
         | 
| 123 | 
            +
                    ).inject({}) do |acc, datastore|
         | 
| 124 | 
            +
                      acc[datastore.name] = datastore
         | 
| 125 | 
            +
                      acc
         | 
| 126 | 
            +
                    end
         | 
| 127 | 
            +
                  end
         | 
| 128 | 
            +
             | 
| 117 129 | 
             
                  private
         | 
| 118 130 |  | 
| 119 131 | 
             
                  attr_reader :config, :client, :properties, :logger
         | 
| 120 132 |  | 
| 121 133 | 
             
                  def select_datastores(pattern)
         | 
| 122 | 
            -
                     | 
| 123 | 
            -
                    matching_datastores = @datastores.select { |datastore| datastore.name =~ pattern }
         | 
| 124 | 
            -
                    matching_datastores.inject({}) { |h, datastore| h[datastore.name] = datastore; h }
         | 
| 134 | 
            +
                    all_datastores.select { |name, datastore| name =~ pattern }
         | 
| 125 135 | 
             
                  end
         | 
| 126 136 |  | 
| 127 137 | 
             
                  def pick_store(type, size)
         | 
| @@ -204,7 +214,7 @@ module VSphereCloud | |
| 204 214 | 
             
                  # @return [void]
         | 
| 205 215 | 
             
                  def fetch_resource_pool_utilization
         | 
| 206 216 | 
             
                    properties = @client.cloud_searcher.get_properties(resource_pool.mob, Vim::ResourcePool, 'summary')
         | 
| 207 | 
            -
                    raise "Failed to get utilization for resource pool #{resource_pool}" if properties.nil?
         | 
| 217 | 
            +
                    raise "Failed to get utilization for resource pool '#{resource_pool}'" if properties.nil?
         | 
| 208 218 |  | 
| 209 219 | 
             
                    runtime_info = properties["summary"].runtime
         | 
| 210 220 |  | 
| @@ -9,13 +9,13 @@ module VSphereCloud | |
| 9 9 |  | 
| 10 10 | 
             
                  def find(name, config)
         | 
| 11 11 | 
             
                    cluster_mob = cluster_mobs[name]
         | 
| 12 | 
            -
                    raise "Can't find cluster | 
| 12 | 
            +
                    raise "Can't find cluster '#{name}'" if cluster_mob.nil?
         | 
| 13 13 |  | 
| 14 14 | 
             
                    cluster_properties = @client.cloud_searcher.get_properties(
         | 
| 15 15 | 
             
                      cluster_mob, VimSdk::Vim::ClusterComputeResource,
         | 
| 16 16 | 
             
                      Cluster::PROPERTIES, :ensure_all => true
         | 
| 17 17 | 
             
                    )
         | 
| 18 | 
            -
                    raise "Can't find properties for cluster | 
| 18 | 
            +
                    raise "Can't find properties for cluster '#{name}'" if cluster_properties.nil?
         | 
| 19 19 |  | 
| 20 20 | 
             
                    Cluster.new(
         | 
| 21 21 | 
             
                      @datacenter,
         | 
| @@ -4,6 +4,8 @@ module VSphereCloud | |
| 4 4 | 
             
              class Resources
         | 
| 5 5 | 
             
                class Datacenter
         | 
| 6 6 | 
             
                  include VimSdk
         | 
| 7 | 
            +
                  include ObjectStringifier
         | 
| 8 | 
            +
                  stringify_with :name
         | 
| 7 9 |  | 
| 8 10 | 
             
                  attr_accessor :config
         | 
| 9 11 |  | 
| @@ -27,7 +29,7 @@ module VSphereCloud | |
| 27 29 |  | 
| 28 30 | 
             
                  def mob
         | 
| 29 31 | 
             
                    mob = @client.find_by_inventory_path(name)
         | 
| 30 | 
            -
                    raise "Datacenter | 
| 32 | 
            +
                    raise "Datacenter '#{name}' not found" if mob.nil?
         | 
| 31 33 | 
             
                    mob
         | 
| 32 34 | 
             
                  end
         | 
| 33 35 |  | 
| @@ -70,17 +72,22 @@ module VSphereCloud | |
| 70 72 | 
             
                    @clusters.each do |cluster_name, cluster_config|
         | 
| 71 73 | 
             
                      clusters[cluster_name] = @cluster_provider.find(cluster_name, cluster_config)
         | 
| 72 74 | 
             
                    end
         | 
| 75 | 
            +
                    @logger.debug("All clusters provided: #{@clusters}")
         | 
| 73 76 | 
             
                    clusters
         | 
| 74 77 | 
             
                  end
         | 
| 75 78 |  | 
| 76 79 | 
             
                  def persistent_datastores
         | 
| 77 | 
            -
                     | 
| 78 | 
            -
             | 
| 79 | 
            -
                       | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 80 | 
            +
                    clusters.values.inject({}) do |acc, cluster|
         | 
| 81 | 
            +
                      acc.merge!(cluster.persistent_datastores)
         | 
| 82 | 
            +
                      acc
         | 
| 83 | 
            +
                    end
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                  def all_datastores
         | 
| 87 | 
            +
                    clusters.values.inject({}) do |acc, cluster|
         | 
| 88 | 
            +
                      acc.merge!(cluster.all_datastores)
         | 
| 89 | 
            +
                      acc
         | 
| 82 90 | 
             
                    end
         | 
| 83 | 
            -
                    datastores
         | 
| 84 91 | 
             
                  end
         | 
| 85 92 |  | 
| 86 93 | 
             
                  def pick_persistent_datastore(size)
         | 
| @@ -95,14 +102,14 @@ module VSphereCloud | |
| 95 102 | 
             
                    datastores = persistent_datastores.values
         | 
| 96 103 | 
             
                    available_datastores = datastores.reject { |datastore| datastore.free_space - size < DISK_HEADROOM }
         | 
| 97 104 |  | 
| 98 | 
            -
                    @logger.debug("Looking for a #{type} datastore with #{size}MB free space.")
         | 
| 105 | 
            +
                    @logger.debug("Looking for a '#{type}' datastore with #{size}MB free space.")
         | 
| 99 106 | 
             
                    @logger.debug("All datastores: #{datastores.map(&:debug_info)}")
         | 
| 100 107 | 
             
                    @logger.debug("Datastores with enough space: #{available_datastores.map(&:debug_info)}")
         | 
| 101 108 |  | 
| 102 109 | 
             
                    selected_datastore = Util.weighted_random(available_datastores.map { |datastore| [datastore, datastore.free_space] })
         | 
| 103 110 |  | 
| 104 111 | 
             
                    if selected_datastore.nil?
         | 
| 105 | 
            -
                      raise Bosh::Clouds::NoDiskSpace.new(true), "Couldn't find a #{type} datastore with #{size}MB of free space. Found:\n #{datastores.map(&:debug_info).join("\n ")}\n"
         | 
| 112 | 
            +
                      raise Bosh::Clouds::NoDiskSpace.new(true), "Couldn't find a '#{type}' datastore with #{size}MB of free space. Found:\n #{datastores.map(&:debug_info).join("\n ")}\n"
         | 
| 106 113 | 
             
                    end
         | 
| 107 114 | 
             
                    selected_datastore
         | 
| 108 115 | 
             
                  end
         | 
| @@ -2,6 +2,7 @@ require 'cloud/vsphere/resources/disk/disk_config' | |
| 2 2 |  | 
| 3 3 | 
             
            module VSphereCloud
         | 
| 4 4 | 
             
              class EphemeralDisk
         | 
| 5 | 
            +
                DISK_NAME = 'ephemeral_disk'
         | 
| 5 6 | 
             
                def initialize(size_in_mb, folder_name, datastore)
         | 
| 6 7 | 
             
                  @folder_name = folder_name
         | 
| 7 8 | 
             
                  @datastore = datastore
         | 
| @@ -15,7 +16,7 @@ module VSphereCloud | |
| 15 16 | 
             
                private
         | 
| 16 17 |  | 
| 17 18 | 
             
                def filename
         | 
| 18 | 
            -
                  "[#{@datastore.name}] #{@folder_name} | 
| 19 | 
            +
                  "[#{@datastore.name}] #{@folder_name}/#{DISK_NAME}.vmdk"
         | 
| 19 20 | 
             
                end
         | 
| 20 21 | 
             
              end
         | 
| 21 22 | 
             
            end
         | 
| @@ -18,7 +18,7 @@ module VSphereCloud | |
| 18 18 | 
             
                  def find_or_create_folder(path_components)
         | 
| 19 19 | 
             
                    if path_components.empty?
         | 
| 20 20 | 
             
                      folder = root_vm_folder
         | 
| 21 | 
            -
                      raise "Root VM Folder not found | 
| 21 | 
            +
                      raise "Root VM Folder not found '#{@datacenter_name}/vm'" if folder.nil?
         | 
| 22 22 | 
             
                      return folder
         | 
| 23 23 | 
             
                    end
         | 
| 24 24 |  | 
| @@ -3,6 +3,8 @@ module VSphereCloud | |
| 3 3 | 
             
                class VM
         | 
| 4 4 | 
             
                  include VimSdk
         | 
| 5 5 | 
             
                  include RetryBlock
         | 
| 6 | 
            +
                  include ObjectStringifier
         | 
| 7 | 
            +
                  stringify_with :cid
         | 
| 6 8 |  | 
| 7 9 | 
             
                  attr_reader :mob, :cid
         | 
| 8 10 |  | 
| @@ -64,6 +66,12 @@ module VSphereCloud | |
| 64 66 | 
             
                    end
         | 
| 65 67 | 
             
                  end
         | 
| 66 68 |  | 
| 69 | 
            +
                  def ephemeral_disk
         | 
| 70 | 
            +
                    devices.find do |device|
         | 
| 71 | 
            +
                      device.kind_of?(Vim::Vm::Device::VirtualDisk) && device.backing.file_name =~ /#{VSphereCloud::EphemeralDisk::DISK_NAME}.vmdk$/
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 67 75 | 
             
                  def pci_controller
         | 
| 68 76 | 
             
                    devices.find { |device| device.kind_of?(Vim::Vm::Device::VirtualPCIController) }
         | 
| 69 77 | 
             
                  end
         | 
| @@ -157,12 +165,12 @@ module VSphereCloud | |
| 157 165 | 
             
                    end
         | 
| 158 166 | 
             
                  end
         | 
| 159 167 |  | 
| 160 | 
            -
                  private
         | 
| 161 | 
            -
             | 
| 162 168 | 
             
                  def power_state
         | 
| 163 169 | 
             
                    properties['runtime.powerState']
         | 
| 164 170 | 
             
                  end
         | 
| 165 171 |  | 
| 172 | 
            +
                  private
         | 
| 173 | 
            +
             | 
| 166 174 | 
             
                  def properties
         | 
| 167 175 | 
             
                    @properties ||= cloud_searcher.get_properties(
         | 
| 168 176 | 
             
                      @mob,
         | 
| @@ -19,7 +19,7 @@ module VSphereCloud | |
| 19 19 |  | 
| 20 20 | 
             
                def create(agent_id, stemcell_cid, networks, persistent_disk_cids, environment)
         | 
| 21 21 | 
             
                  stemcell_vm = @cpi.stemcell_vm(stemcell_cid)
         | 
| 22 | 
            -
                  raise "Could not find stemcell | 
| 22 | 
            +
                  raise "Could not find VM for stemcell '#{stemcell_cid}'" if stemcell_vm.nil?
         | 
| 23 23 |  | 
| 24 24 | 
             
                  stemcell_size =
         | 
| 25 25 | 
             
                    @cloud_searcher.get_property(stemcell_vm, VimSdk::Vim::VirtualMachine, 'summary.storage.committed', ensure_all: true)
         | 
| @@ -94,13 +94,18 @@ module VSphereCloud | |
| 94 94 |  | 
| 95 95 | 
             
                    @agent_env.set_env(created_vm.mob, location, env)
         | 
| 96 96 |  | 
| 97 | 
            -
                    @logger.info("Powering on VM: #{created_vm} | 
| 97 | 
            +
                    @logger.info("Powering on VM: #{created_vm}")
         | 
| 98 98 | 
             
                    created_vm.power_on
         | 
| 99 99 |  | 
| 100 100 | 
             
                    create_drs_rules(created_vm.mob, cluster)
         | 
| 101 101 | 
             
                  rescue => e
         | 
| 102 | 
            +
                    e.vm_cid = vm_cid if e.instance_of?(Cloud::NetworkException)
         | 
| 102 103 | 
             
                    @logger.info("#{e} - #{e.backtrace.join("\n")}")
         | 
| 103 | 
            -
                     | 
| 104 | 
            +
                    begin
         | 
| 105 | 
            +
                      created_vm.delete if created_vm
         | 
| 106 | 
            +
                    rescue => ex
         | 
| 107 | 
            +
                      @logger.info("Failed to delete vm '#{vm_cid}' with message:  #{ex.inspect}")
         | 
| 108 | 
            +
                    end
         | 
| 104 109 | 
             
                    raise e
         | 
| 105 110 | 
             
                  end
         | 
| 106 111 |  | 
| @@ -118,7 +123,7 @@ module VSphereCloud | |
| 118 123 | 
             
                  rule_config = @placer.drs_rules.first
         | 
| 119 124 |  | 
| 120 125 | 
             
                  if rule_config['type'] != 'separate_vms'
         | 
| 121 | 
            -
                    raise "vSphere CPI only supports DRS rule of 'separate_vms' type"
         | 
| 126 | 
            +
                    raise "vSphere CPI only supports DRS rule of 'separate_vms' type, not '#{rule_config['type']}'"
         | 
| 122 127 | 
             
                  end
         | 
| 123 128 |  | 
| 124 129 | 
             
                  drs_rule = VSphereCloud::DrsRule.new(
         | 
| @@ -8,7 +8,7 @@ module VSphereCloud | |
| 8 8 |  | 
| 9 9 | 
             
                def find(vm_cid)
         | 
| 10 10 | 
             
                  vm_mob = @client.find_by_inventory_path(@datacenter.vm_path(vm_cid))
         | 
| 11 | 
            -
                  raise Bosh::Clouds::VMNotFound, "VM  | 
| 11 | 
            +
                  raise Bosh::Clouds::VMNotFound, "VM '#{vm_cid}' not found at path '#{@datacenter.vm_path(vm_cid)}'" if vm_mob.nil?
         | 
| 12 12 |  | 
| 13 13 | 
             
                  Resources::VM.new(vm_cid, vm_mob, @client, @logger)
         | 
| 14 14 | 
             
                end
         | 
    
        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. | 
| 4 | 
            +
              version: 2.1.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - VMware
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2015-09- | 
| 11 | 
            +
            date: 2015-09-28 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bosh_common
         | 
| @@ -133,6 +133,7 @@ files: | |
| 133 133 | 
             
            - lib/cloud/vsphere/fixed_cluster_placer.rb
         | 
| 134 134 | 
             
            - lib/cloud/vsphere/lease_obtainer.rb
         | 
| 135 135 | 
             
            - lib/cloud/vsphere/lease_updater.rb
         | 
| 136 | 
            +
            - lib/cloud/vsphere/object_stringifier.rb
         | 
| 136 137 | 
             
            - lib/cloud/vsphere/path_finder.rb
         | 
| 137 138 | 
             
            - lib/cloud/vsphere/resources.rb
         | 
| 138 139 | 
             
            - lib/cloud/vsphere/resources/cluster.rb
         |