class Chef::Knife::Ec2ServerCreate

Attributes

initial_sleep_delay[RW]
server[R]

Public Instance Methods

assign_default_port() click to toggle source

Set default port 5986 if winrm_ssl return true otherwise set it to 5985 Set default port 22 for ssh protocol @return [Integer]

# File lib/chef/knife/ec2_server_create.rb, line 1383
def assign_default_port
  if winrm?
    config[:winrm_ssl] ? 5986 : 5985
  else
    22
  end
end
associate_address(elastic_ip) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1193
def associate_address(elastic_ip)
  if vpc_mode?
    ec2_connection.associate_address({
      allocation_id: elastic_ip.allocation_id,
      instance_id: server.id,
    })
  else
    ec2_connection.associate_address({
      public_ip: elastic_ip.public_ip,
      instance_id: server.id,
    })
  end
end
attach_nics() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1240
def attach_nics
  attachments = []
  config[:network_interfaces].each_with_index do |nic_id, index|
    attachments << ec2_connection.attach_network_interface({
      device_index: index + 1,
      instance_id: server.id,
      network_interface_id: nic_id,
    })
  end
  wait_for_nic_attachment

  attachments
end
bootstrap_common_params() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 537
def bootstrap_common_params
  config[:encrypted_data_bag_secret] = s3_secret || config[:secret]
  config[:encrypted_data_bag_secret_file] = config[:secret_file]
  # retrieving the secret from S3 is unique to knife-ec2, so we need to set "command line secret" to the value fetched from S3
  # When linux vm is spawned, the chef's secret option proc function sets the value "command line secret" and this value is used by
  # chef's code to check if secret option is passed through command line or not
  config[:cl_secret] = s3_secret if config[:s3_secret]
  config[:secret] = s3_secret || config[:secret]

  # Modify global configuration state to ensure hint gets set by
  # knife-bootstrap
  config[:hints] ||= {}
  config[:hints]["ec2"] ||= {}
end
check_windows_password_available(server_id) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1337
def check_windows_password_available(server_id)
  sleep 10
  response = fetch_password_data(server_id)
  return false unless response.password_data

  true
end
configure_ssh_gateway(ssh_gateway) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1079
def configure_ssh_gateway(ssh_gateway)
  gw_host, gw_user = ssh_gateway.split("@").reverse
  gw_host, gw_port = gw_host.split(":")
  gateway_options = { port: gw_port || 22 }

  # Load the SSH config for the SSH gateway host.
  # Set the gateway user if it was not part of the
  # SSH gateway string, and use any configured
  # SSH keys.
  ssh_gateway_config = Net::SSH::Config.for(gw_host)
  gw_user ||= ssh_gateway_config[:user]

  # Always use the gateway keys from the SSH Config
  gateway_keys = ssh_gateway_config[:keys]

  # Use the keys specificed on the command line if available (overrides SSH Config)
  if config[:ssh_gateway_identity]
    gateway_keys = Array(config[:ssh_gateway_identity])
  end

  unless gateway_keys.nil?
    gateway_options[:keys] = gateway_keys
  end

  Net::SSH::Gateway.new(gw_host, gw_user, gateway_options)
end
connect_attribute() click to toggle source

Identify connection attribute if: Option –server-connect-attribute is set. For VPC mode check if public IP or elastic IP has been requested. Otherwise assign public DNS or public IP. @return [String]

# File lib/chef/knife/ec2_server_create.rb, line 1141
def connect_attribute
  @connect_attribute ||= begin
    if !!config[:server_connect_attribute]
      config[:server_connect_attribute]
    elsif vpc_mode? && !(subnet_public_ip_on_launch? || config[:associate_public_ip] || config[:associate_eip])
      "private_ip_address"
    else
      server.public_dns_name ? "public_dns_name" : "public_ip_address"
    end
  end
end
connection_host() click to toggle source

Assign connection host based on attribute passed @return [String]

# File lib/chef/knife/ec2_server_create.rb, line 1129
def connection_host
  @connection_host ||= server.send(connect_attribute)

  puts "\nSSH Target Address: #{@connection_host}(#{connect_attribute})"
  @connection_host
end
connection_port() click to toggle source

TODO: connection_protocol and connection_port used to choose winrm/ssh or 5985/22 based on the image chosen

# File lib/chef/knife/ec2_server_create.rb, line 1373
def connection_port
  port = config[:connection_port] || config[knife_key_for_protocol(:port)]
  return port if port

  assign_default_port
end
connection_protocol_ec2() click to toggle source

url values override CLI flags, if you provide both we'll use the one that you gave in the URL.

# File lib/chef/knife/ec2_server_create.rb, line 1393
def connection_protocol_ec2
  return @connection_protocol_ec2 if @connection_protocol_ec2

  default_protocol = is_image_windows? ? "winrm" : "ssh"
  from_url = host_descriptor =~ %r{^(.*)://} ? $1 : nil
  from_config = config[:connection_protocol]
  @connection_protocol_ec2 = from_url || from_config || default_protocol
end
connection_user() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1402
def connection_user
  @connection_user ||= config[:connection_user] || config[knife_key_for_protocol(:user)]
end
create_ec2_instance(attributes) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 985
def create_ec2_instance(attributes)
  ec2_connection.run_instances(attributes)
end
create_key_pair() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1175
def create_key_pair
  key_name = "#{config[:connection_user].delete(".\\")}-#{SecureRandom.hex(10)}"
  key_pair = ec2_connection.create_key_pair({
    key_name: key_name,
  })

  save_keypair_file(key_pair) if key_pair
end
create_tags(hashed_tags) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1153
def create_tags(hashed_tags)
  request_tags = []
  hashed_tags.each_pair do |key, val|
    request_tags << { key: key, value: val }
  end

  if request_tags.length > 0
    ec2_connection.create_tags(tags: request_tags, resources: [server.id])
  end
end
create_volume_tags(hashed_volume_tags) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1164
def create_volume_tags(hashed_volume_tags)
  request_tags = []
  hashed_volume_tags.each_pair do |key, val|
    request_tags << { key: key, value: val }
  end

  if request_tags.length > 0
    ec2_connection.create_tags(tags: request_tags, resources: [server.volume_id])
  end
end
decrypt_admin_password(encoded_password, key) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1329
def decrypt_admin_password(encoded_password, key)
  require "base64" unless defined?(Base64)
  require "openssl" unless defined?(OpenSSL)
  private_key = OpenSSL::PKey::RSA.new(key)
  encrypted_password = Base64.decode64(encoded_password)
  private_key.private_decrypt(encrypted_password)
end
default_bootstrap_template() click to toggle source

return the default bootstrap template based on platform @return [String]

# File lib/chef/knife/ec2_server_create.rb, line 493
def default_bootstrap_template
  is_image_windows? ? "windows-chef-client-msi" : "chef-full"
end
disable_source_dest_check() click to toggle source

disable_source_dest_check option is used to set value of source_dest_check attribute in ec2. By default the source destination check is enabled in ec2. This value must be disable for a NAT instance to perform NAT.

# File lib/chef/knife/ec2_server_create.rb, line 1265
def disable_source_dest_check
  ec2_connection.modify_instance_attribute({
    source_dest_check: {
      value: false,
    },
    instance_id: server.id,
  })
end
download_validation_key(tempfile) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 512
def download_validation_key(tempfile)
  Chef::Log.debug "Downloading validation key " \
    "<#{config[:validation_key_url]}> to file " \
    "<#{tempfile}>"

  case URI(config[:validation_key_url]).scheme
  when "s3"
    File.open(tempfile, "w") { |f| f.write(s3_validation_key) }
  end
end
eip_scope() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 747
def eip_scope
  if vpc_mode?
    "vpc"
  else
    "standard"
  end
end
encode_data(text) click to toggle source

base64-encoded text

# File lib/chef/knife/ec2_server_create.rb, line 836
def encode_data(text)
  require "base64" unless defined?(Base64)
  Base64.encode64(text)
end
evaluate_node_name(node_name) click to toggle source

Returns the name of node after evaluation of server id if %s is present. Eg: “Test-%s” will return “Test-i-12345” in case the instance id is i-12345

# File lib/chef/knife/ec2_server_create.rb, line 1368
def evaluate_node_name(node_name)
  node_name % server.id
end
fetch_server_fqdn(ip_addr) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 552
def fetch_server_fqdn(ip_addr)
  require "resolv"
  Resolv.getname(ip_addr)
end
get_ssh_gateway_for(hostname) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1021
def get_ssh_gateway_for(hostname)
  if config[:ssh_gateway]
    # The ssh_gateway specified in the knife config (if any) takes
    # precedence over anything in the SSH configuration
    Chef::Log.debug("Using ssh gateway #{config[:ssh_gateway]} from knife config")
    config[:ssh_gateway]
  else
    # Next, check if the SSH configuration has a ProxyCommand
    # directive for this host. If there is one, parse out the
    # host from the proxy command
    ssh_proxy = Net::SSH::Config.for(hostname)[:proxy]
    if ssh_proxy.respond_to?(:command_line_template)
      # ssh gateway_hostname nc %h %p
      proxy_pattern = /ssh\s+(\S+)\s+nc/
      matchdata = proxy_pattern.match(ssh_proxy.command_line_template)
      if matchdata.nil?
        Chef::Log.debug("Unable to determine ssh gateway for '#{hostname}' from ssh config template: #{ssh_proxy.command_line_template}")
        nil
      else
        # Return hostname extracted from command line template
        Chef::Log.debug("Using ssh gateway #{matchdata[1]} from ssh config")
        matchdata[1]
      end
    else
      # Return nil if we cannot find an ssh_gateway
      Chef::Log.debug("No ssh gateway found, making a direct connection")
      nil
    end
  end
end
hashed_tags() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1444
def hashed_tags
  ht = {}
  parse_aws_tags.map { |t| key, val = t.split("="); ht[key] = val } unless parse_aws_tags.nil?

  # Always set the Name tag
  unless ht.key?("Name")
    if config[:chef_node_name]
      ht["Name"] = evaluate_node_name(config[:chef_node_name])
    else
      ht["Name"] = server.id
    end
  end

  ht
end
hashed_volume_tags() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1432
def hashed_volume_tags
  hvt = {}
  volume_tags = config[:volume_tags]
  volume_tags.map { |t| key, val = t.split("="); hvt[key] = val } unless volume_tags.nil?

  hvt
end
host_descriptor()
Alias for: server_name
instances_wait_until_ready(instance_id) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 998
def instances_wait_until_ready(instance_id)
  ec2_connection.wait_until(:instance_running, instance_ids: [instance_id]) do |w|
    w.max_attempts = max_attempts
  end
rescue Aws::Waiters::Errors::WaiterFailed => error
  puts "failed waiting for instance running: #{error.message}"
end
max_attempts() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1006
def max_attempts
  delay = 15 # Default Delay for waiter
  attempts = 40 # Default max attempts for waiter

  if config[:aws_connection_timeout]
    attempts = (config[:aws_connection_timeout].to_f / delay).to_i
  end
  attempts
end
parse_aws_tags() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 738
def parse_aws_tags
  tags = config[:aws_tag]
  if !tags.nil? && (tags.length != tags.to_s.count("="))
    ui.error("AWS Tags should be entered in a key = value pair")
    exit 1
  end
  tags
end
plugin_create_instance!() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 271
def plugin_create_instance!
  requested_elastic_ip = config[:associate_eip] if config[:associate_eip]

  # For VPC EIP assignment we need the allocation ID so fetch full EIP details
  elastic_ip = ec2_connection.describe_addresses.addresses.detect { |addr| addr if addr.public_ip == requested_elastic_ip }

  if config[:spot_price]
    server_def = spot_instances_attributes
    spot_request = ec2_connection.request_spot_instances(server_def)
    msg_pair("Spot Request ID", spot_request.spot_instance_request_id)
    msg_pair("Spot Request Type", spot_request.type)
    msg_pair("Spot Price", spot_request.spot_price)

    case config[:spot_wait_mode]
    when "prompt", "", nil
      wait_msg = "Do you want to wait for Spot Instance Request fulfillment? (Y/N) \n"
      wait_msg += "Y - Wait for Spot Instance request fulfillment\n"
      wait_msg += "N - Do not wait for Spot Instance request fulfillment. "
      wait_msg += ui.color("[WARN :: Request would be alive on AWS ec2 side but execution of Chef Bootstrap on the target instance will get skipped.]\n", :red, :bold)
      wait_msg += ui.color("\n[WARN :: For any of the above mentioned choices, (Y) - if the instance does not get allocated before the command itself times-out or (N) - user decides to exit, then in both cases user needs to manually bootstrap the instance in the future after it gets allocated.]\n\n", :cyan, :bold)
      confirm(wait_msg)
    when "wait"
      # wait for the node and run Chef bootstrap
    when "exit"
      ui.color("The 'exit' option was specified for --spot-wait-mode, exiting.", :cyan)
      exit
    else
      raise "Invalid value for --spot-wait-mode: '#{config[:spot_wait_mode]}', " \
        "valid values: wait, exit, prompt"
    end

    print ui.color("Waiting for Spot Request fulfillment:  ", :cyan)
    spot_response = spot_instances_wait_until_ready(spot_request.spot_instance_request_id)

    @server = fetch_ec2_instance(spot_response.instance_id)
  else
    begin
      response_obj = create_ec2_instance(server_attributes)
      instance_id = response_obj.instances[0].instance_id
      print "\n#{ui.color("Waiting for EC2 to create the instance\n", :magenta)}"

      # wait for instance to come up before acting against it
      instances_wait_until_ready(instance_id)
      @server = fetch_ec2_instance(instance_id)
    rescue => error
      error.message.sub("download completed, but downloaded file not found", "Verify that you have public internet access.")
      ui.error error.message
      Chef::Log.debug("#{error.backtrace.join("\n")}")
      exit
    end
  end
  msg_pair("Instance ID", server.id)
  msg_pair("Flavor", server.instance_type)
  msg_pair("Image", server.image_id)
  msg_pair("Region", fetch_region)
  msg_pair("Availability Zone", server.availability_zone)
  msg_pair("Security Groups", printed_security_groups) unless vpc_mode? || (server.groups && server.security_groups_ids)
  msg_pair("Security Group Ids", printed_security_group_ids) if vpc_mode? || server.security_groups_ids

  msg_pair("IAM Profile", config[:iam_instance_profile])

  msg_pair("AWS Tags", printed_aws_tags)
  msg_pair("Volume Tags", printed_volume_tags)
  msg_pair("SSH Key", server.key_name)
  msg_pair("T2/T3 Unlimited", printed_t2_t3_unlimited)

  puts("\n")

  # occasionally 'ready?' isn't, so retry a couple times if needed.
  tries = 6
  begin
    disable_source_dest_check if vpc_mode? && config[:disable_source_dest_check]

    create_tags(hashed_tags) unless hashed_tags.empty?
    create_volume_tags(hashed_volume_tags) unless hashed_volume_tags.empty?
    associate_address(elastic_ip) if config[:associate_eip]
    enable_classic_link(config[:classic_link_vpc_id], config[:classic_link_vpc_security_group_ids]) if config[:classic_link_vpc_id]
  rescue Aws::EC2::Errors::ServiceError, Aws::EC2::Errors::Error
    raise if (tries -= 1) <= 0

    ui.warn("server not ready, retrying tag application (retries left: #{tries})")
    sleep 5
    retry
  end

  attach_nics if config[:network_interfaces]

  # Re-fetch the latest server data after assigning vpc or network interfaces
  @server = fetch_ec2_instance(instance_id) if reload_server_data_required?

  if vpc_mode?
    msg_pair("Subnet ID", server.subnet_id)
    msg_pair("Tenancy", server.tenancy)
    if config[:associate_public_ip]
      msg_pair("Public DNS Name", server.public_dns_name)
    end
    if elastic_ip
      msg_pair("Public IP Address", server.public_ip_address)
    end
  else
    msg_pair("Public DNS Name", server.public_dns_name)
    msg_pair("Public IP Address", server.public_ip_address)
    msg_pair("Private DNS Name", server.private_dns_name)
  end
  msg_pair("Private IP Address", server.private_ip_address)

  if config[:validation_key_url]
    download_validation_key(validation_key_path)
    Chef::Config[:validation_key] = validation_key_path
  end

  # Check if Server is Windows or Linux
  if is_image_windows?
    if winrm?
      print "\n#{ui.color("Waiting for winrm access to become available", :magenta)}"
      print(".") until tcp_test_winrm(connection_host, connection_port) do
        sleep 10
        puts("done")
      end
    else
      print "\n#{ui.color("Waiting for sshd access to become available", :magenta)}"
      # If FreeSSHd, winsshd etc are available
      print(".") until tcp_test_ssh(connection_host, connection_port) do
        sleep @initial_sleep_delay ||= (vpc_mode? ? 40 : 10)
        puts("done")
      end
    end
  else
    print "\n#{ui.color("Waiting for sshd access to become available", :magenta)}"
    wait_for_sshd(connection_host)
  end

  fqdn = connection_host
  if winrm?
    if config[:kerberos_realm]
      # Fetch AD/WINS based fqdn if any for Kerberos-based Auth
      fqdn = config[:fqdn] || fetch_server_fqdn(server.private_ip_address)
    end
    config[:connection_password] = windows_password
  end
  @name_args = [fqdn]

  if config[:chef_node_name]
    config[:chef_node_name] = evaluate_node_name(config[:chef_node_name])
  else
    config[:chef_node_name] = server.id
  end
  bootstrap_common_params
end
plugin_finalize() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 421
def plugin_finalize
  puts "\n"
  msg_pair("Instance ID", server.id)
  msg_pair("Flavor", server.instance_type)
  msg_pair("Placement Group", server.placement_group) unless server.placement_group.nil?
  msg_pair("Image", server.image_id)
  msg_pair("Region", fetch_region)
  msg_pair("Availability Zone", server.availability_zone)
  msg_pair("Security Groups", printed_security_groups) unless vpc_mode? || (server.groups.nil? && server.security_group_ids)
  msg_pair("Security Group Ids", printed_security_group_ids) if vpc_mode? || server.security_group_ids
  msg_pair("IAM Profile", config[:iam_instance_profile]) if config[:iam_instance_profile]
  msg_pair("Primary ENI", config[:primary_eni]) if config[:primary_eni]
  msg_pair("AWS Tags", printed_aws_tags)
  msg_pair("Chef Tags", config[:tags]) if config[:tags].any?
  msg_pair("SSH Key", server.key_name)
  msg_pair("Root Device Type", server.root_device_type)
  msg_pair("Root Volume Tags", printed_volume_tags)
  if server.root_device_type == "ebs"
    device_map = server.block_device_mappings.first
    msg_pair("Root Device Name", device_map.device_name)
    msg_pair("Root Volume ID", device_map.ebs.volume_id)
    msg_pair("Root Device Delete on Terminate", device_map.ebs.delete_on_termination)
    msg_pair("Standard or Provisioned IOPS", device_map.ebs.volume_type) if device_map.ebs.respond_to?("volume_type")
    msg_pair("IOPS rate", device_map.ebs.iops) if device_map.ebs.respond_to?("iops")

    print "\n#{ui.color("Block devices", :magenta)}\n"
    print "#{ui.color("===========================", :magenta)}\n"
    server.block_device_mappings.each do |device_map|
      msg_pair("Device Name", device_map.device_name)
      msg_pair("Volume ID", device_map.ebs.volume_id)
      msg_pair("Delete on Terminate", device_map.ebs.delete_on_termination.to_s)
      msg_pair("Standard or Provisioned IOPS", device_map.ebs.volume_type) if device_map.ebs.respond_to?("volume_type")
      msg_pair("IOPS rate", device_map.ebs.iops) if device_map.ebs.respond_to?("iops")
      print "\n"
    end
    print "#{ui.color("===========================", :magenta)}\n"

    if config[:ebs_size]
      volume_size = ami.block_device_mappings[0].ebs.volume_size
      if volume_size.to_i < config[:ebs_size].to_i
        volume_too_large_warning = "#{config[:ebs_size]}GB " +
          "EBS volume size is larger than size set in AMI of " +
          "#{volume_size}GB.\n" +
          "Use file system tools to make use of the increased volume size."
        msg_pair("Warning", volume_too_large_warning, :yellow)
      end
    end
  end
  if config[:ebs_optimized]
    msg_pair("EBS is Optimized", server.ebs_optimized.to_s)
  end
  if vpc_mode?
    msg_pair("Subnet ID", server.subnet_id)
    msg_pair("Tenancy", server.tenancy)
    if config[:associate_public_ip]
      msg_pair("Public DNS Name", server.public_dns_name)
    end
  else
    msg_pair("Public DNS Name", server.public_dns_name)
    msg_pair("Public IP Address", server.public_ip_address)
    msg_pair("Private DNS Name", server.private_dns_name)
  end
  msg_pair("Private IP Address", server.private_ip_address)
  msg_pair("Environment", config[:environment] || "_default")
  msg_pair("Run List", (config[:run_list] || []).join(", "))
  if config[:first_boot_attributes] || config[:first_boot_attributes_from_file]
    msg_pair("JSON Attributes", config[:first_boot_attributes] || config[:first_boot_attributes_from_file])
  end
end
plugin_setup!() click to toggle source

When options connection_protocol and connection_port are not provided It will set as default

# File lib/chef/knife/ec2_server_create.rb, line 565
def plugin_setup!
  validate_aws_config!(%i{image aws_access_key_id aws_secret_access_key})
  config[:connection_protocol] ||= connection_protocol_ec2
  config[:connection_port] ||= connection_port
end
plugin_validate_options!() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 575
def plugin_validate_options!
  if config.key?(:aws_ssh_key_id)
    config[:ssh_key_name] = config[:aws_ssh_key_id] unless config[:ssh_key_name]
    config.delete(:aws_ssh_key_id)
    ui.warn("Use of aws_ssh_key_id option in knife.rb/config.rb config is deprecated, use ssh_key_name option instead.")
  end
  create_key_pair unless config[:ssh_key_name]

  validate_nics! if config[:network_interfaces]

  if ami.nil?
    ui.error("The provided AMI value '#{config[:image]}' could not be found. Is this AMI availble in the provided region #{config[:region]}?")
    exit 1
  end

  if vpc_mode? && !!config[:security_groups]
    ui.error("You are using a VPC, security groups specified with '-G' are not allowed, specify one or more security group ids with '-g' instead.")
    exit 1
  end

  if !vpc_mode? && !!config[:private_ip_address]
    ui.error("You can only specify a private IP address if you are using VPC.")
    exit 1
  end

  if config[:dedicated_instance] && !vpc_mode?
    ui.error("You can only specify a Dedicated Instance if you are using VPC.")
    exit 1
  end

  if !vpc_mode? && config[:associate_public_ip]
    ui.error("--associate-public-ip option only applies to VPC instances, and you have not specified a subnet id.")
    exit 1
  end

  if config[:associate_eip]
    eips = ec2_connection.describe_addresses.addresses.collect { |addr| addr if addr.domain == eip_scope }.compact

    unless eips.detect { |addr| addr.public_ip == config[:associate_eip] && (addr.instance_id.nil? || addr.instance_id.empty?) }
      ui.error("Elastic IP requested is not available.")
      exit 1
    end
  end

  if config[:ebs_provisioned_iops] && (config[:ebs_volume_type] != "io1")
    ui.error("--provisioned-iops option is only supported for volume type of 'io1'")
    exit 1
  end

  if (config[:ebs_volume_type] == "io1") && config[:ebs_provisioned_iops].nil?
    ui.error("--provisioned-iops option is required when using volume type of 'io1'")
    exit 1
  end

  if config[:ebs_volume_type] && ! %w{gp2 io1 standard st1 sc1}.include?(config[:ebs_volume_type])
    ui.error("--ebs-volume-type must be 'standard' or 'io1' or 'gp2' or 'st1' or 'sc1'")
    msg opt_parser
    exit 1
  end

  # validation for ebs_size
  if (%w{st1 sc1}.include?(config[:ebs_volume_type])) && ! config[:ebs_size].to_i.between?(500, 16384)
    ui.error("--ebs-size should be in between 500-16384 for 'st1' or 'sc1' ebs volume type.")
    exit 1
  end

  if config[:security_groups] && config[:security_groups].class == String
    ui.error("Invalid value type for knife[:security_groups] in knife configuration file (i.e knife.rb/config.rb). Type should be array. e.g - knife[:security_groups] = ['sgroup1']")
    exit 1
  end

  # Validation for security_group_ids passed through knife.rb/config.rb. It will raise error if values are not provided in Array.
  if config[:security_group_ids] && config[:security_group_ids].class == String
    ui.error("Invalid value type for knife[:security_group_ids] in knife configuration file (i.e knife.rb/config.rb). Type should be array. e.g - knife[:security_group_ids] = ['sgroup1']")
    exit 1
  end

  if config[:classic_link_vpc_id].nil? ^ config[:classic_link_vpc_security_group_ids].nil?
    ui.error("--classic-link-vpc-id and --classic-link-vpc-security-group-ids must be used together")
    exit 1
  end

  if vpc_mode? && config[:classic_link_vpc_id]
    ui.error("You can only use ClassicLink if you are not using a VPC")
    exit 1
  end

  if config[:ebs_encrypted]
    error_message = ""
    errors = []
    # validation for flavor and ebs_encrypted
    if !config[:flavor]
      ui.error("--ebs-encrypted option requires valid flavor to be specified.")
      exit 1
    elsif config[:ebs_encrypted] && ! %w{m3.medium m3.large m3.xlarge m3.2xlarge m4.large m4.xlarge
                                       m4.2xlarge m4.4xlarge m4.10xlarge m4.16xlarge t2.nano t2.micro t2.small
                                       t2.medium t2.large t2.xlarge t2.2xlarge d2.xlarge d2.2xlarge d2.4xlarge
                                       d2.8xlarge c4.large c4.xlarge c4.2xlarge c4.4xlarge c4.8xlarge c3.large
                                       c3.xlarge c3.2xlarge c3.4xlarge c3.8xlarge cr1.8xlarge r3.large r3.xlarge
                                       r3.2xlarge r3.4xlarge r3.8xlarge r4.large r4.xlarge r4.2xlarge r4.4xlarge
                                       r4.8xlarge r4.16xlarge x1.16xlarge x1.32xlarge i2.xlarge i2.2xlarge i2.4xlarge
                                       i2.8xlarge i3.large i3.xlarge i3.2xlarge i3.4xlarge i3.8xlarge i3.16xlarge
                                       f1.2xlarge f1.16xlarge g2.2xlarge g2.8xlarge p2.xlarge p2.8xlarge p2.16xlarge}.include?(config[:flavor])
      ui.error("--ebs-encrypted option is not supported for #{config[:flavor]} flavor.")
      exit 1
    end

    # validation for ebs_size and ebs_volume_type and ebs_encrypted
    if !config[:ebs_size]
      errors << "--ebs-encrypted option requires valid --ebs-size to be specified."
    elsif (config[:ebs_volume_type] == "gp2") && ! config[:ebs_size].to_i.between?(1, 16384)
      errors << "--ebs-size should be in between 1-16384 for 'gp2' ebs volume type."
    elsif (config[:ebs_volume_type] == "io1") && ! config[:ebs_size].to_i.between?(4, 16384)
      errors << "--ebs-size should be in between 4-16384 for 'io1' ebs volume type."
    elsif (config[:ebs_volume_type] == "standard") && ! config[:ebs_size].to_i.between?(1, 1024)
      errors << "--ebs-size should be in between 1-1024 for 'standard' ebs volume type."
    end

    if errors.each { |e| error_message = "#{error_message} #{e}" }.any?
      ui.error(error_message)
      exit 1
    end
  end

  if config[:spot_price] && config[:disable_api_termination]
    ui.error("spot-price and disable-api-termination options cannot be passed together as 'Termination Protection' cannot be enabled for spot instances.")
    exit 1
  end

  if config[:spot_price].nil? && config[:spot_wait_mode]
    unless config[:spot_wait_mode].casecmp("prompt") == 0
      ui.error("spot-wait-mode option requires that a spot-price option is set.")
      exit 1
    end
  end

  volume_tags = config[:volume_tags]
  if !volume_tags.nil? && (volume_tags.length != volume_tags.to_s.count("="))
    ui.error("Volume Tags should be entered in a key = value pair")
    exit 1
  end

  if winrm? && !config[:connection_password].nil?
    reg = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,40}$/
    unless config[:connection_password]&.match?(reg)
      ui.error("Complexity requirements are not met. Password length should be 8-40 characters and include: 1 uppercase, 1 lowercase, 1 digit, and 1 special character")
      exit 1
    end
  end

  if config[:chef_tag]
    # If --chef-tag is provided then it will be set in chef as single value e.g. --chef-tag "myTag"
    # --tags has been removed from knife-ec2, now it's available in core
    config[:tags] += config[:chef_tag]
    ui.warn("[DEPRECATED] --chef-tag option is deprecated and will be removed in future release. Use --tags TAGS option instead.")
  end

  if config[:cpu_credits] && !config[:flavor]
    ui.error("Instance type should be specified and should be any of T2/T3 type.")
    exit 1
  end
end
printed_aws_tags() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1460
def printed_aws_tags
  hashed_tags.map { |tag, val| "#{tag}: #{val}" }.join(", ")
end
printed_security_group_ids() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1424
def printed_security_group_ids
  if server.security_group_ids
    server.security_group_ids.join(", ")
  else
    "default"
  end
end
printed_security_groups() click to toggle source

If we don't specify a security group or security group id, Fog will pick the appropriate default one. In case of a VPC we don't know the default security group id at this point unless we look it up, hence 'default' is printed if no id was specified.

# File lib/chef/knife/ec2_server_create.rb, line 1416
def printed_security_groups
  if server.groups
    server.groups.join(", ")
  else
    "default"
  end
end
printed_t2_t3_unlimited() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1464
def printed_t2_t3_unlimited
  if config[:cpu_credits] == "unlimited"
    "Enabled"
  else
    "Disabled"
  end
end
printed_volume_tags() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1440
def printed_volume_tags
  hashed_volume_tags.map { |tag, val| "#{tag}: #{val}" }.join(", ")
end
process_user_data(script_lines) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 816
def process_user_data(script_lines)
  unless ssl_config_data_already_exist?
    ps_start_tag = "<powershell>\n"
    ps_end_tag = "</powershell>\n"
    ps_start_tag_index = script_lines.index(ps_start_tag) || script_lines.index(ps_start_tag.strip)
    ps_end_tag_index = script_lines.index(ps_end_tag) || script_lines.index(ps_end_tag.strip)
    case
    when ( ps_start_tag_index && !ps_end_tag_index ) || ( !ps_start_tag_index && ps_end_tag_index )
      ui.error("Provided user_data file is invalid.")
      exit 1
    when ps_start_tag_index && ps_end_tag_index
      script_lines[ps_end_tag_index] = ssl_config_user_data + ps_end_tag
    when !ps_start_tag_index && !ps_end_tag_index
      script_lines.insert(-1, "\n\n" + ps_start_tag + ssl_config_user_data + ps_end_tag)
    end
  end
  script_lines
end
reload_server_data_required?() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1472
def reload_server_data_required?
  !!config[:associate_eip] || !!config[:classic_link_vpc_id] || !!config[:network_interfaces]
end
s3_secret() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 529
def s3_secret
  @s3_secret ||= begin
    return false unless config[:s3_secret]

    Chef::Knife::S3Source.fetch(config[:s3_secret], config)
  end
end
s3_validation_key() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 523
def s3_validation_key
  @s3_validation_key ||= begin
    Chef::Knife::S3Source.fetch(config[:validation_key_url], config)
  end
end
save_keypair_file(key_pair) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1184
def save_keypair_file(key_pair)
  file_path = File.join(Config.config_dir, "#{key_pair.key_name}.pem")
  file = File.open(file_path, "w+") { |f| f << key_pair.key_material }

  config[:ssh_key_name] = key_pair.key_name
  config[:ssh_identity_file] = file.path
  puts "\nGenerated keypair file: #{file.path}"
end
server_attributes() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 850
def server_attributes
  attributes = {
    image_id: config[:image],
    instance_type: config[:flavor],
    key_name: config[:ssh_key_name],
    max_count: 1,
    min_count: 1,
    placement: {
      availability_zone: config[:availability_zone],
    },
  }

  network_attrs = {}
  if !!config[:primary_eni]
    network_attrs[:network_interface_id] = config[:primary_eni]
  elsif vpc_mode?
    network_attrs[:subnet_id] = config[:subnet_id]
  end

  if vpc_mode?
    network_attrs[:groups] = config[:security_group_ids] if !!config[:security_group_ids]
    network_attrs[:private_ip_address] = config[:private_ip_address]
    network_attrs[:associate_public_ip_address] = config[:associate_public_ip]
  else
    attributes[:security_groups] = config[:security_groups]
  end

  if network_attrs.length > 0
    network_attrs[:device_index] = 0
    attributes[:network_interfaces] = [network_attrs]
  else
    attributes[:security_group_ids] = config[:security_group_ids]
  end

  attributes[:placement][:group_name] = config[:placement_group]
  attributes[:placement][:tenancy] = "dedicated" if vpc_mode? && config[:dedicated_instance]
  attributes[:iam_instance_profile] = {}
  attributes[:iam_instance_profile][:name] = config[:iam_instance_profile]
  if config[:winrm_ssl]
    if config[:aws_user_data]
      begin
        user_data = File.readlines(config[:aws_user_data])
        if config[:create_ssl_listener]
          user_data = process_user_data(user_data)
        end
        user_data = user_data.join
        attributes.merge!(user_data: encode_data(user_data))
      rescue
        ui.warn("Cannot read #{config[:aws_user_data]}: #{$!.inspect}. Ignoring option.")
      end
    else
      if config[:create_ssl_listener]
        attributes[:user_data] = encode_data("<powershell>\n" + ssl_config_user_data + "</powershell>\n")
      end
    end
  else
    if config[:aws_user_data]
      begin
        user_data = File.read(config[:aws_user_data])
        attributes.merge!(user_data: encode_data(user_data))
      rescue
        ui.warn("Cannot read #{config[:aws_user_data]}: #{$!.inspect}. Ignoring option.")
      end
    end
  end
  attributes[:ebs_optimized] = !!config[:ebs_optimized]

  if ami.root_device_type == "ebs"
    if config[:ebs_encrypted] || %w{st1 sc1}.include?(config[:ebs_volume_type])
      ami_map = ami.block_device_mappings[1]
    else
      ami_map = ami.block_device_mappings.first
    end

    ebs_size = begin
                 if config[:ebs_size]
                   Integer(config[:ebs_size]).to_s
                 else
                   ami_map.ebs.volume_size.to_s if ami_map.ebs.respond_to?(:volume_size)
                 end
               rescue ArgumentError
                 puts "--ebs-size must be an integer"
                 msg opt_parser
                 exit 1
               end

    delete_term = config[:ebs_delete_on_term]

    iops_rate = begin
                  if config[:ebs_provisioned_iops]
                    Integer(config[:ebs_provisioned_iops]).to_s
                  else
                    ami_map.ebs.iops.to_s if ami_map.ebs.respond_to?(:iops)
                  end
                rescue ArgumentError
                  puts "--provisioned-iops must be an integer"
                  msg opt_parser
                  exit 1
                end

    attributes[:block_device_mappings] =
      [{
         device_name: ami_map.device_name,
         ebs: {
            delete_on_termination: delete_term,
            volume_size: ebs_size,
            volume_type: config[:ebs_volume_type], # accepts standard, io1, gp2, sc1, st1
          },
       }]
    attributes[:block_device_mappings][0][:ebs][:iops] = iops_rate unless iops_rate.nil? || iops_rate.empty?
    attributes[:block_device_mappings][0][:ebs][:encrypted] = true if config[:ebs_encrypted]
  end

  if config[:ephemeral] && config[:ephemeral].length > 0
    ephemeral_blocks = []
    config[:ephemeral].each_with_index do |device_name, i|
      ephemeral_blocks << { virtual_name: "ephemeral#{i}", device_name: device_name }
    end
    attributes[:block_device_mappings] += ephemeral_blocks
  end

  ## cannot pass disable_api_termination option to the API when using spot instances ##
  attributes[:disable_api_termination] = config[:disable_api_termination] if config[:spot_price].nil?

  attributes[:instance_initiated_shutdown_behavior] = config[:instance_initiated_shutdown_behavior]

  if config[:cpu_credits]
    attributes[:credit_specification] =
      {
        cpu_credits: config[:cpu_credits],
      }
  end
  attributes
end
server_name() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1406
def server_name
  server ? connection_host : nil
end
Also aliased as: host_descriptor
spot_instances_attributes() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 841
def spot_instances_attributes
  attributes = {
    instance_count: 1,
    launch_specification: server_attributes,
    spot_price: config[:spot_price],
    type: config[:spot_request_type],
  }
end
spot_instances_wait_until_ready(spot_request_id) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 989
def spot_instances_wait_until_ready(spot_request_id)
  ec2_connection.wait_until(
    :spot_instance_request_fulfilled,
    spot_instance_request_ids: [spot_request_id]
  ).spot_instance_requests[0]
rescue Aws::Waiters::Errors::WaiterFailed => error
  puts "failed waiting for spot request fulfill: #{error.message}"
end
ssl_config_data_already_exist?() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 812
def ssl_config_data_already_exist?
  File.read(config[:aws_user_data]).gsub(/\\\\/, "\\").include? ssl_config_user_data.strip
end
ssl_config_user_data() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 755
      def ssl_config_user_data
        user_related_commands = ""
        user = connection_user.split("\\")
        if (user[0] == ".") || (user[0] == "") || (user.length == 1)
          user_related_commands = <<~EOH
            net user /add #{connection_user.delete('.\\')} #{windows_password} #{@allow_long_password};
            net localgroup Administrators /add #{connection_user.delete('.\\')};
          EOH
        end
        <<~EOH
          #{user_related_commands}
          If (-Not (Get-Service WinRM | Where-Object {$_.status -eq "Running"})) {
            winrm quickconfig -q
          }
          If (winrm e winrm/config/listener | Select-String -Pattern " Transport = HTTP\\b" -Quiet) {
            winrm delete winrm/config/listener?Address=*+Transport=HTTP
          }
          $vm_name = invoke-restmethod -uri http://169.254.169.254/latest/meta-data/public-ipv4
          If (-Not $vm_name) {
            $vm_name = invoke-restmethod -uri http://169.254.169.254/latest/meta-data/local-ipv4
          }

          $name = new-object -com "X509Enrollment.CX500DistinguishedName.1"
          $name.Encode("CN=$vm_name", 0)
          $key = new-object -com "X509Enrollment.CX509PrivateKey.1"
          $key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
          $key.KeySpec = 1
          $key.Length = 2048
          $key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
          $key.MachineContext = 1
          $key.Create()
          $serverauthoid = new-object -com "X509Enrollment.CObjectId.1"
          $serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1")
          $ekuoids = new-object -com "X509Enrollment.CObjectIds.1"
          $ekuoids.add($serverauthoid)
          $ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
          $ekuext.InitializeEncode($ekuoids)
          $cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1"
          $cert.InitializeFromPrivateKey(2, $key, "")
          $cert.Subject = $name
          $cert.Issuer = $cert.Subject
          $cert.NotBefore = get-date
          $cert.NotAfter = $cert.NotBefore.AddYears(10)
          $cert.X509Extensions.Add($ekuext)
          $cert.Encode()
          $enrollment = new-object -com "X509Enrollment.CX509Enrollment.1"
          $enrollment.InitializeFromRequest($cert)
          $certdata = $enrollment.CreateRequest(0)
          $enrollment.InstallResponse(2, $certdata, 0, "")

          $thumbprint = (Get-ChildItem -Path cert:\\localmachine\\my | Where-Object {$_.Subject -match "$vm_name"}).Thumbprint;
          $create_listener_cmd = "winrm create winrm/config/Listener?Address=*+Transport=HTTPS '@{Hostname=`"$vm_name`";CertificateThumbprint=`"$thumbprint`"}'"
          iex $create_listener_cmd
          netsh advfirewall firewall add rule name="WinRM HTTPS" protocol=TCP dir=in Localport=5986 remoteport=any action=allow localip=any remoteip=any profile=any enable=yes
        EOH
      end
subnet_public_ip_on_launch?() click to toggle source

@return [Boolean]

# File lib/chef/knife/ec2_server_create.rb, line 1120
def subnet_public_ip_on_launch?
  return false unless server.subnet_id

  subnet = fetch_subnet(server.subnet_id)
  subnet.map_public_ip_on_launch
end
tcp_test_ssh(hostname, ssh_port) { || ... } click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1298
def tcp_test_ssh(hostname, ssh_port)
  tcp_socket = TCPSocket.new(hostname, ssh_port)
  readable = IO.select([tcp_socket], nil, nil, 5)
  if readable
    ssh_banner = tcp_socket.gets
    if ssh_banner.nil? || ssh_banner.empty?
      false
    else
      Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{ssh_banner}")
      yield
      true
    end
  else
    false
  end
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ENOTCONN, IOError
  Chef::Log.debug("ssh failed to connect: #{hostname}")
  sleep 2
  false
rescue Errno::EPERM, Errno::ETIMEDOUT
  Chef::Log.debug("ssh timed out: #{hostname}")
  false
# This happens on some mobile phone networks
rescue Errno::ECONNRESET
  Chef::Log.debug("ssh reset its connection: #{hostname}")
  sleep 2
  false
ensure
  tcp_socket && tcp_socket.close
end
tcp_test_winrm(ip_addr, port) { || ... } click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1274
def tcp_test_winrm(ip_addr, port)
  tcp_socket = TCPSocket.new(ip_addr, port)
  yield
  true
rescue SocketError
  sleep 2
  false
rescue Errno::ETIMEDOUT
  false
rescue Errno::EPERM
  false
rescue Errno::ECONNREFUSED
  sleep 2
  false
rescue Errno::EHOSTUNREACH
  sleep 2
  false
rescue Errno::ENETUNREACH
  sleep 2
  false
ensure
  tcp_socket && tcp_socket.close
end
tunnel_test_ssh(ssh_gateway, hostname, &block) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1065
def tunnel_test_ssh(ssh_gateway, hostname, &block)
  status = false
  gateway = configure_ssh_gateway(ssh_gateway)
  gateway.open(hostname, connection_port) do |local_tunnel_port|
    status = tcp_test_ssh("localhost", local_tunnel_port, &block)
  end
  status
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
  sleep 2
  false
rescue Errno::EPERM, Errno::ETIMEDOUT
  false
end
validate_name_args!() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 571
def validate_name_args!
  # We don't know the name of our instance yet
end
validate_nics!() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1207
def validate_nics!
  params = {}
  if vpc_mode?
    network_attrs = { name: "vpc_id", value: [vpc_id] }
    params["filters"] = [network_attrs]
  end

  interfaces = ec2_connection.describe_network_interfaces(params)
  valid_nic_ids = interfaces.network_interfaces.map(&:network_interface_id)
  invalid_nic_ids = config[:network_interfaces] - valid_nic_ids

  return true if invalid_nic_ids.empty?

  ui.error "The following network interfaces are invalid: " \
    "#{invalid_nic_ids.join(", ")}"
  exit 1
end
validation_key_path() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 497
def validation_key_path
  @validation_key_path ||= begin
    if URI(config[:validation_key_url]).scheme == "file"
      URI(config[:validation_key_url]).path
    else
      validation_key_tmpfile.path
    end
  end
end
validation_key_tmpfile() click to toggle source

@return [Tempfile]

# File lib/chef/knife/ec2_server_create.rb, line 508
def validation_key_tmpfile
  @validation_key_tmpfile ||= Tempfile.new("validation_key")
end
vpc_id() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1225
def vpc_id
  @vpc_id ||= fetch_subnet(config[:subnet_id]).vpc_id
end
vpc_mode?() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 557
def vpc_mode?
  # Amazon Virtual Private Cloud requires a subnet_id. If
  # present, do a few things differently
  !!config[:subnet_id]
end
wait_for_direct_sshd(hostname, ssh_port) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1106
def wait_for_direct_sshd(hostname, ssh_port)
  initial = true
  print(".") until tcp_test_ssh(hostname, ssh_port) do
    if initial
      initial = false
      sleep (vpc_mode? ? 40 : 10)
    else
      sleep 10
    end
    puts("done")
  end
end
wait_for_nic_attachment() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1229
def wait_for_nic_attachment
  attached_nics_count = 0
  until attached_nics_count == config[:network_interfaces].count
    attachment_nics =
      config[:network_interfaces].map do |nic_id|
        fetch_network_interfaces(nic_id).attachment.status
      end
    attached_nics_count = attachment_nics.grep("attached").count
  end
end
wait_for_sshd(hostname) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1016
def wait_for_sshd(hostname)
  ssh_gateway = get_ssh_gateway_for(hostname)
  ssh_gateway ? wait_for_tunnelled_sshd(ssh_gateway, hostname) : wait_for_direct_sshd(hostname, connection_port)
end
wait_for_tunnelled_sshd(ssh_gateway, hostname) click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1052
def wait_for_tunnelled_sshd(ssh_gateway, hostname)
  initial = true
  print(".") until tunnel_test_ssh(ssh_gateway, hostname) do
    if initial
      initial = false
      sleep (vpc_mode? ? 40 : 10)
    else
      sleep 10
    end
    puts("done")
  end
end
windows_password() click to toggle source
# File lib/chef/knife/ec2_server_create.rb, line 1345
def windows_password
  if not config[:connection_password]
    if config[:ssh_identity_file]
      if server
        print "\n#{ui.color("Waiting for Windows Admin password to be available: ", :magenta)}"
        print(".") until check_windows_password_available(server.id) { puts("done") }
        response = fetch_password_data(server.id)
        data = File.read(config[:ssh_identity_file])
        config[:connection_password] = decrypt_admin_password(response.password_data, data)
      else
        print "\n#{ui.color("Fetching instance details: \n", :magenta)}"
      end
    else
      ui.error("Cannot find SSH Identity file, required to fetch dynamically generated password")
      exit 1
    end
  else
    config[:connection_password]
  end
end