class Chef::Provisioning::VraDriver::Driver

Attributes

base_url[R]

Public Class Methods

canonicalize_url(driver_url, config) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 40
def self.canonicalize_url(driver_url, config)
  [ driver_url, config ]
end
from_url(driver_url, config) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 36
def self.from_url(driver_url, config)
  Driver.new(driver_url, config)
end
new(driver_url, config) click to toggle source
Calls superclass method
# File lib/chef/provisioning/vra_driver/driver.rb, line 44
def initialize(driver_url, config)
  super

  _, @base_url = driver_url.split(':', 2)
  @resources = {}
end

Public Instance Methods

allocate_machine(action_handler, machine_spec, machine_options) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 51
def allocate_machine(action_handler, machine_spec, machine_options)
  resource = resource_for(machine_spec)
  return unless resource.nil?

  bootstrap_options = bootstrap_options_for(machine_options)
  transport_options = transport_options_for(machine_options)

  action_handler.perform_action("Create #{machine_spec.name} with catalog ID #{bootstrap_options[:catalog_id]}") do
    resource = create_resource(action_handler, machine_spec, machine_options)
  end

  machine_spec.location = {
    'driver_url'     => driver_url,
    'driver_version' => Chef::Provisioning::VraDriver::VERSION,
    'resource_id'    => resource.id,
    'resource_name'  => resource.name,
    'allocated_at'   => Time.now.utc.to_s,
    'is_windows'     => transport_options[:is_windows]
  }
end
bootstrap_options_for(machine_options) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 393
def bootstrap_options_for(machine_options)
  machine_options.key?(:bootstrap_options) ? machine_options[:bootstrap_options] : {}
end
catalog_request(machine_spec, machine_options) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 161
def catalog_request(machine_spec, machine_options)
  bootstrap_options = bootstrap_options_for(machine_options)
  catalog_request = vra_client.catalog.request(bootstrap_options[:catalog_id])

  catalog_request.notes         = description(machine_spec)
  catalog_request.cpus          = bootstrap_options[:cpus]
  catalog_request.memory        = bootstrap_options[:memory]
  catalog_request.requested_for = bootstrap_options[:requested_for]
  catalog_request.lease_days    = bootstrap_options[:lease_days]   unless bootstrap_options[:lease_days].nil?
  catalog_request.subtenant_id  = bootstrap_options[:subtenant_id] unless bootstrap_options[:subtenant_id].nil?

  if bootstrap_options.key?(:extra_parameters) && bootstrap_options[:extra_parameters].respond_to?(:each)
    bootstrap_options[:extra_parameters].each do |key, value_data|
      catalog_request.set_parameter(key, value_data[:type], value_data[:value])
    end
  end

  catalog_request
end
connect_to_machine(machine_spec, machine_options) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 122
def connect_to_machine(machine_spec, machine_options)
  machine_for(machine_spec, machine_options)
end
convergence_strategy_for(machine_spec, machine_options) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 341
def convergence_strategy_for(machine_spec, machine_options)
  if windows?(machine_spec)
    Chef::Provisioning::ConvergenceStrategy::InstallMsi.new(machine_options[:convergence_options], config)
  else
    Chef::Provisioning::ConvergenceStrategy::InstallCached.new(machine_options[:convergence_options], config)
  end
end
create_resource(action_handler, machine_spec, machine_options) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 141
def create_resource(action_handler, machine_spec, machine_options)
  action_handler.report_progress("Submitting catalog request for #{machine_spec.name}")

  submitted_request = catalog_request(machine_spec, machine_options).submit
  action_handler.report_progress("Catalog request #{submitted_request.id} submitted.")

  wait_for(action_handler) do
    submitted_request.refresh
    submitted_request.completed?
  end

  raise "The vRA request failed: #{submitted_request.completion_details}" if submitted_request.failed?

  servers = submitted_request.resources.select(&:vm?)
  raise 'The vRA request created more than one server. The catalog blueprint should only return one.' if servers.size > 1
  raise 'the vRA request did not create any servers.' if servers.size.zero?

  servers.first
end
create_ssh_transport(machine_spec, machine_options, resource) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 288
def create_ssh_transport(machine_spec, machine_options, resource)
  ssh_options = ssh_options_for(machine_spec, machine_options, resource)
  remote_host = remote_host_for(machine_options, resource)
  username    = username_for(machine_spec, machine_options, 'root')
  options     = ssh_transport_options_for(machine_spec, username)

  Chef::Provisioning::Transport::SSH.new(remote_host, username, ssh_options, options, config)
end
create_winrm_transport(machine_spec, machine_options, resource) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 268
def create_winrm_transport(machine_spec, machine_options, resource)
  transport_options = transport_options_for(machine_options)
  remote_host       = remote_host_for(machine_options, resource)
  username          = username_for(machine_spec, machine_options, 'Administrator')
  url               = "http://#{remote_host}:5985/wsman"
  winrm_options     = winrm_options_for(username, transport_options[:password])

  Chef::Provisioning::Transport::WinRM.new(url, :plaintext, winrm_options, config)
end
description(machine_spec) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 126
def description(machine_spec)
  "X-Chef-Provisioning:#{machine_spec.name}"
end
destroy_machine(action_handler, machine_spec, _machine_options) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 103
def destroy_machine(action_handler, machine_spec, _machine_options)
  resource = resource_for(machine_spec)
  return if resource.nil?

  action_handler.report_progress("Submitting destroy request for #{machine_spec.name}")

  action_handler.perform_action("Destroy machine #{machine_spec.name}") do
    resource.refresh

    destroy_req = resource.destroy
    wait_for(action_handler) do
      destroy_req.refresh
      destroy_req.completed?
    end

    raise "The vRA request failed: #{destroy_req.completion_details}" if destroy_req.failed?
  end
end
machine_for(machine_spec, machine_options) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 329
def machine_for(machine_spec, machine_options)
  if windows?(machine_spec)
    Chef::Provisioning::Machine::WindowsMachine.new(machine_spec,
                                                    transport_for(machine_spec, machine_options),
                                                    convergence_strategy_for(machine_spec, machine_options))
  else
    Chef::Provisioning::Machine::UnixMachine.new(machine_spec,
                                                 transport_for(machine_spec, machine_options),
                                                 convergence_strategy_for(machine_spec, machine_options))
  end
end
max_retries() click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 231
def max_retries
  driver_options.fetch(:max_retries, 1).to_i
end
max_wait_time() click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 227
def max_wait_time
  driver_options.fetch(:max_wait_time, 600).to_i
end
power_off_machine(action_handler, resource) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 202
def power_off_machine(action_handler, resource)
  resource.refresh
  return if resource.machine_off? || resource.machine_turning_off?

  action_handler.report_progress("Submitting shutdown/power-off request for resource #{resource.id}")
  begin
    power_off_req = resource.shutdown
  rescue Vra::Exception::NotFound
    power_off_req = resource.poweroff
  end

  wait_for(action_handler) do
    power_off_req.refresh
    power_off_req.completed?
  end

  raise "The vRA request failed: #{power_off_req.completion_details}" if power_off_req.failed?

  action_handler.report_progress("Waiting for resource #{resource.id} to be powered off")
  wait_for(action_handler) do
    resource.refresh
    resource.machine_off?
  end
end
power_on_machine(action_handler, resource) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 181
def power_on_machine(action_handler, resource)
  resource.refresh
  return if resource.machine_on? || resource.machine_turning_on? || resource.machine_in_provisioned_state?

  action_handler.report_progress("Machine status is #{resource.machine_status}. " \
    "Submitting power-on request for resource #{resource.id}")
  power_on_req = resource.poweron
  wait_for(action_handler) do
    power_on_req.refresh
    power_on_req.completed?
  end

  raise "The vRA request failed: #{power_on_req.completion_details}" if power_on_req.failed?

  action_handler.report_progress("Waiting for resource #{resource.id} to be powered on")
  wait_for(action_handler) do
    resource.refresh
    resource.machine_on?
  end
end
ready_machine(action_handler, machine_spec, machine_options) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 72
def ready_machine(action_handler, machine_spec, machine_options)
  resource = resource_for(machine_spec)
  raise "Unable to locate machine for #{machine_spec.name}" if resource.nil?

  action_handler.report_progress("Powering on #{machine_spec.name} if needed")

  action_handler.perform_action("Power on machine #{machine_spec.name}") do
    power_on_machine(action_handler, resource)
  end

  action_handler.report_progress("Waiting for #{machine_spec.name} to be reachable")

  transport = transport_for(machine_spec, machine_options)
  action_handler.perform_action("Confirm #{machine_spec.name} is reachable") do
    wait_for(action_handler) { transport.available? }
  end

  machine_for(machine_spec, machine_options)
end
remote_host_for(machine_options, resource) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 310
def remote_host_for(machine_options, resource)
  transport_options = transport_options_for(machine_options)
  if resource.ip_addresses.empty? || transport_options[:use_hostname]
    resource.name
  else
    resource.ip_addresses.first
  end
end
resource_for(machine_spec) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 130
def resource_for(machine_spec)
  return nil if machine_spec.location.nil?

  begin
    resource_id = machine_spec.location['resource_id']
    @resources[resource_id] ||= vra_client.resources.by_id(resource_id)
  rescue Vra::Exception::NotFound
    nil
  end
end
ssh_options_for(machine_spec, machine_options, resource) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 349
def ssh_options_for(machine_spec, machine_options, resource)
  bootstrap_options = bootstrap_options_for(machine_options)
  transport_options = transport_options_for(machine_options)

  if transport_options.key?(:password)
    ssh_options = {
      auth_methods: [ 'password' ],
      keys_only:    false,
      password:     transport_options[:password]
    }
  else
    ssh_options = {
      auth_methods: [ 'publickey' ],
      keys_only:    true
    }

    if bootstrap_options[:key_path]
      ssh_options[:key_data] = [ IO.read(bootstrap_options[:key_path]) ]
    elsif bootstrap_options[:key_name]
      ssh_options[:key_data] = [ get_private_key(bootstrap_options[:key_name]) ]
    else
      raise "No key found to connect to #{machine_spec.name}" \
        " - set a key_path or key_name in the machine's bootstrap_options"
    end
  end

  ssh_options[:host_key_alias] = "#{resource.id}.vra"
  ssh_options.merge(machine_options[:ssh_options] || {})
end
ssh_transport_options_for(machine_spec, username) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 297
def ssh_transport_options_for(machine_spec, username)
  options = {}
  options[:prefix]         = 'sudo ' if use_sudo?(machine_spec, username)
  options[:ssh_pty_enable] = true
  options[:ssh_gateway]    = machine_spec.reference['ssh_gateway'] if machine_spec.reference['ssh_gateway']

  options
end
stop_machine(action_handler, machine_spec, _machine_options) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 92
def stop_machine(action_handler, machine_spec, _machine_options)
  resource = resource_for(machine_spec)
  raise "Unable to locate machine for #{machine_spec.name}" if resource.nil?

  action_handler.report_progress("Submitting shutdown / power-off request for #{machine_spec.name}")

  action_handler.perform_action("Powering off machine #{machine_spec.name}") do
    power_off_machine(action_handler, resource)
  end
end
transport_for(machine_spec, machine_options) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 319
def transport_for(machine_spec, machine_options)
  resource = resource_for(machine_spec)

  if windows?(machine_spec)
    create_winrm_transport(machine_spec, machine_options, resource)
  else
    create_ssh_transport(machine_spec, machine_options, resource)
  end
end
transport_options_for(machine_options) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 389
def transport_options_for(machine_options)
  machine_options.key?(:transport_options) ? machine_options[:transport_options] : {}
end
use_sudo?(machine_spec, username) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 306
def use_sudo?(machine_spec, username)
  machine_spec.reference[:sudo] || (!machine_spec.reference.key?(:sudo) && username != 'root')
end
username_for(machine_spec, machine_options, default_username) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 262
def username_for(machine_spec, machine_options, default_username)
  transport_options = transport_options_for(machine_options)

  machine_spec.reference['username'] || transport_options[:username] || default_username
end
vra_client() click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 379
def vra_client
  @vra_client ||= ::Vra::Client.new(
    base_url:   base_url,
    username:   driver_options[:username],
    password:   driver_options[:password],
    tenant:     driver_options[:tenant],
    verify_ssl: driver_options[:verify_ssl]
  )
end
wait_for(action_handler) { |== true| ... } click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 235
def wait_for(action_handler)
  sleep_time    = 5
  start_time    = Time.now.utc.to_i
  try           = 0

  Timeout.timeout(max_wait_time) do
    loop do
      begin
        return if yield == true
      rescue => e
        action_handler.report_progress("Error encountered: #{e.class} - #{e.message}")

        try += 1
        if try > max_retries
          action_handler.report_progress('Retries exceeded, aborting...')
          raise
        end
      end

      time_elapsed = Time.now.utc.to_i - start_time
      action_handler.report_progress("been waiting #{time_elapsed}/#{max_wait_time} seconds" \
        " -- sleeping #{sleep_time} seconds")
      sleep sleep_time
    end
  end
end
windows?(machine_spec) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 397
def windows?(machine_spec)
  machine_spec.location['is_windows'] ? true : false
end
winrm_options_for(username, password) click to toggle source
# File lib/chef/provisioning/vra_driver/driver.rb, line 278
def winrm_options_for(username, password)
  auth_type_opt = username.include?('\\') ? :disable_sspi : :basic_auth_only

  {
    user: username,
    pass: password,
    auth_type_opt => true
  }
end