class Kitchen::Driver::Vra

Public Instance Methods

c_load() click to toggle source
# File lib/kitchen/driver/vra.rb, line 103
def c_load
  if File.exist? ".kitchen/cached_vra"
    encrypted = File.read(".kitchen/cached_vra")
    iv_user = Base64.decode64(encrypted.split(":")[0] + '\n')
    username = Base64.decode64(encrypted.split(":")[1] + "\n")
    iv_pwd = Base64.decode64(encrypted.split(":")[2] + "\n")
    password = Base64.decode64(encrypted.split(":")[3] + "\n")
    cipher = OpenSSL::Cipher.new("cip-her-aes")
    cipher.decrypt
    cipher.key = Digest::SHA1.hexdigest(config[:base_url])
    cipher.iv = iv_user
    config[:username] = cipher.update(username) + cipher.final
    cipher.iv = iv_pwd
    config[:password] = cipher.update(password) + cipher.final
  end
rescue
  puts "Failed to load cached credentials"
end
c_save() click to toggle source
# File lib/kitchen/driver/vra.rb, line 85
def c_save
  cipher = OpenSSL::Cipher.new("cip-her-aes")
  cipher.encrypt
  cipher.key = Digest::SHA1.hexdigest(config[:base_url])
  iv_user = cipher.random_iv
  cipher.iv = iv_user
  username = cipher.update(config[:username]) + cipher.final
  iv_pwd = cipher.random_iv
  cipher.iv = iv_pwd
  password = cipher.update(config[:password]) + cipher.final
  output = "#{Base64.encode64(iv_user).strip!}:#{Base64.encode64(username).strip!}:#{Base64.encode64(iv_pwd).strip!}:#{Base64.encode64(password).strip!}"
  file = File.open(".kitchen/cached_vra", "w")
  file.write(output)
  file.close
rescue
  puts "Unable to save credentials"
end
catalog_request() click to toggle source
# File lib/kitchen/driver/vra.rb, line 220
def catalog_request # rubocop:disable Metrics/MethodLength
  unless config[:catalog_name].nil?
    info("Fetching Catalog ID by Catalog Name")
    catalog_items = vra_client.catalog.fetch_catalog_items(config[:catalog_name])
    begin
      config[:catalog_id] = catalog_items[0].id
      info("Using Catalog with ID: #{catalog_items[0].id}")
    rescue
      error("Unable to retrieve Catalog ID from Catalog Name: #{config[:catalog_name]}")
    end
  end

  if config[:catalog_id].nil?
    raise Kitchen::InstanceFailure, "Unable to create deployment without a valid catalog"
  end

  deployment_params = {
    image_mapping: config[:image_mapping],
    flavor_mapping: config[:flavor_mapping],
    project_id: config[:project_id],
    version: config[:version],
  }.tap do |h|
    h[:name] = config[:deployment_name] unless config[:unique_name]
  end

  catalog_request = vra_client.catalog.request(config[:catalog_id], deployment_params)

  config[:extra_parameters].each do |key, value_data|
    catalog_request.set_parameters(key, value_data)
  end

  catalog_request
end
check_config(force_change = false) click to toggle source
# File lib/kitchen/driver/vra.rb, line 75
def check_config(force_change = false)
  config[:username] = config[:username] || ENV["VRA_USER_NAME"]
  config[:password] = config[:password] || ENV["VRA_USER_PASSWORD"]
  c_load if config[:username].nil? && config[:password].nil?

  config[:username] = ask("Enter Username: e.g. johnsmith") if config[:username].nil? || force_change
  config[:password] = ask("Enter password: ") { |q| q.echo = "*" } if config[:password].nil? || force_change
  c_save if config[:cache_credentials]
end
create(state) click to toggle source
# File lib/kitchen/driver/vra.rb, line 122
def create(state)
  return if state[:deployment_id]

  server = request_server
  state[:deployment_id] = server.deployment_id
  state[:hostname]    = hostname_for(server)
  state[:ssh_key]     = config[:private_key_path] unless config[:private_key_path].nil?

  wait_for_server(state, server)
  info("Server #{server.deployment_id} (#{server.name}) ready.")
end
destroy(state) click to toggle source
# File lib/kitchen/driver/vra.rb, line 196
def destroy(state)
  return if state[:deployment_id].nil?

  begin
    server = vra_client.deployments.by_id(state[:deployment_id])
  rescue ::Vra::Exception::NotFound
    warn("No server found with ID #{state[:deployment_id]}, assuming it has been destroyed already.")
    return
  end

  begin
    destroy_request = server.destroy
  rescue ::Vra::Exception::NotFound
    info("Server not found, or no destroy action available, perhaps because it is already destroyed.")
    return
  end
  info("Destroy request #{destroy_request.id} submitted.")
  wait_for_request(destroy_request)
  info("Destroy request complete.")

  File.delete(".kitchen/cached_vra") if File.exist?(".kitchen/cached_vra")
  info("Removed cached file")
end
hostname_for(server) click to toggle source
# File lib/kitchen/driver/vra.rb, line 134
def hostname_for(server)
  if config[:use_dns]
    raise "No server name returned for the vRA request" if server.name.nil?

    return config[:dns_suffix] ? "#{server.name}.#{config[:dns_suffix]}" : server.name
  end

  ip_address = server.ip_address
  if ip_address.nil?
    warn("Server #{server.deployment_id} has no IP address. Falling back to server name (#{server.name})...")
    server.name
  else
    ip_address
  end
end
name() click to toggle source
# File lib/kitchen/driver/vra.rb, line 71
def name
  "vRA"
end
request_server() click to toggle source
# File lib/kitchen/driver/vra.rb, line 150
def request_server
  info("Building vRA catalog request...")

  deployment_request = catalog_request.submit

  info("Catalog request #{deployment_request.id} submitted.")
  if config[:unique_name]
    info("Deployment name is deployment_#{deployment_request.id}")
  end

  wait_for_request(deployment_request)
  raise "The vRA request failed: #{deployment_request.completion_details}" if deployment_request.failed?

  servers = deployment_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 == 0

  servers.first
end
vra_client() click to toggle source
# File lib/kitchen/driver/vra.rb, line 254
def vra_client
  check_config config[:cache_credentials]
  @client ||= ::Vra::Client.new(
    base_url:   config[:base_url],
    username:   config[:username],
    password:   config[:password],
    domain:     config[:domain],
    verify_ssl: config[:verify_ssl]
  )
rescue => _e
  check_config true
end
wait_for_request(request) click to toggle source
# File lib/kitchen/driver/vra.rb, line 267
def wait_for_request(request)
  # config = check_config config

  last_status = ""
  wait_time   = config[:request_timeout]
  sleep_time  = config[:request_refresh_rate]

  Timeout.timeout(wait_time) do
    loop do
      request.refresh
      break if request.completed?

      unless last_status == request.status
        last_status = request.status
        info("Current request status: #{request.status}")
      end

      sleep sleep_time
    end
  end
rescue Timeout::Error
  error("Request did not complete in #{wait_time} seconds. Check the Requests tab in the vRA UI for more information.")
  raise
end
wait_for_server(state, server) click to toggle source
# File lib/kitchen/driver/vra.rb, line 170
def wait_for_server(state, server)
  info("Server #{server.id} (#{server.name}) created. Waiting until ready...")

  try = 0
  sleep_time = 0

  begin
    instance.transport.connection(state).wait_until_ready
  rescue => e
    warn("Server #{server.id} (#{server.name}) not reachable: #{e.class} -- #{e.message}")

    try += 1
    sleep_time += 5 if sleep_time < 30

    if try > config[:server_ready_retries]
      error("Retries exceeded. Destroying server...")
      destroy(state)
      raise
    else
      warn("Sleeping #{sleep_time} seconds and retrying...")
      sleep sleep_time
      retry
    end
  end
end