class Souffle::Provider::AWS

The AWS souffle provider.

Attributes

access_key[R]
access_secret[R]

Public Class Methods

get_base_ec2_info() click to toggle source

Returns the base (configured) ec2 object for status updates.

@return [ RightAws::Ec2 ] The base RightAws Ec2 object.

# File lib/souffle/provider/aws.rb, line 716
def get_base_ec2_info
  access_key = Souffle::Config[:aws_access_key]
  access_secret = Souffle::Config[:aws_access_secret]
  aws_region = Souffle::Config[:aws_region]

  if Souffle::Config[:debug]
    logger = Souffle::Log.logger
  else
    logger = Logger.new('/dev/null')
  end

  RightAws::Ec2.new(access_key, access_secret,
    :region => aws_region, :logger => logger)
rescue
  nil
end
new() click to toggle source

Setup the internal AWS configuration and object.

Calls superclass method Souffle::Provider::Base::new
# File lib/souffle/provider/aws.rb, line 33
def initialize
  super()
  @access_key    = @system.try_opt(:aws_access_key)
  @access_secret = @system.try_opt(:aws_access_secret)
  @newest_cookbooks = create_cookbooks_tarball

  if Souffle::Config[:debug]
    logger = Souffle::Log.logger
  else
    logger = Logger.new('/dev/null')
  end
  
  @ec2 = RightAws::Ec2.new(
    @access_key, @access_secret,
    :region => @system.try_opt(:aws_region),
    :logger => logger)
  rescue
    raise Souffle::Exceptions::InvalidAwsKeys,
          "AWS access keys are required to operate on EC2"
end
update_status(ec2=nil) click to toggle source

Updates the souffle status with the latest AWS information.

@param [ RightAws::Ec2 ] ec2 The ec2 object to use for the status update.

# File lib/souffle/provider/aws.rb, line 702
def update_status(ec2=nil)
  ec2 = get_base_ec2_info if ec2.nil?
  return if ec2.nil?

  ec2.describe_instances(
      :filters => { 'tag-key' => "souffle" }).each do |instance|
    instance[:tags]["souffle"]
    # TODO: ADD Status update.
  end
end

Public Instance Methods

_format_device(node, device, filesystem="ext4") click to toggle source

Formats a device on a given node with the provided filesystem.

@param [ Souffle::Node ] node The node to format a device on. @param [ String ] device The device to format. @param [ String ] filesystem The filesystem to use when formatting.

# File lib/souffle/provider/aws.rb, line 193
def _format_device(node, device, filesystem="ext4")
  return if node.options[:volumes].nil?
  setup_lvm(node)
  ssh_block(node) do |ssh|
    ssh.exec!("#{fs_formatter(filesystem)} #{device}")
    mount_lvm(node) { node.provisioner.device_formatted }
  end
end
attach_ebs(node) click to toggle source

Attaches ebs volumes to the given node.

@param [ Souffle::Node ] node The node to attach ebs volumes onto.

# File lib/souffle/provider/aws.rb, line 392
def attach_ebs(node)
  Souffle::Log.info "#{node.log_prefix} Attaching EBS..."
  node.options[:volumes].each_with_index do |volume, index|
    @ec2.attach_volume(
      volume[:aws_id],
      node.options[:aws_instance_id],
      volume_id_to_aws_device(index) )
    @ec2.modify_block_device_delete_on_termination_attribute(
      node.options[:aws_instance_id],
      volume_id_to_aws_device(index),
      node.try_opt(:delete_on_termination) )
  end
end
boot(node) click to toggle source

Wait for the machine to boot up.

@param [ Souffle::Node ] node The node to boot up.

# File lib/souffle/provider/aws.rb, line 175
def boot(node)
  wait_for_boot(node)
end
create_ebs(node) click to toggle source

Creates ebs volumes for the given node.

@param [ Souffle::Node ] node The node to create ebs volumes for.

@return [ Array ] The list of created ebs volumes.

# File lib/souffle/provider/aws.rb, line 309
def create_ebs(node)
  volumes = Array.new
  node.options.fetch(:volume_count, 0).times do
    volumes << @ec2.create_volume(
      node.try_opt(:aws_snapshot_id),
      node.try_opt(:aws_ebs_size),
      node.try_opt(:aws_availability_zone) )
  end
  node.options[:volumes] = volumes
  volumes
end
create_node(node, tag=nil) click to toggle source

Takes a node definition and begins the provisioning process.

@param [ Souffle::Node ] node The node to instantiate. @param [ String ] tag The tag to use for the node.

# File lib/souffle/provider/aws.rb, line 91
def create_node(node, tag=nil)
  opts = prepare_node_options(node)
  node.options[:tag] = tag unless tag.nil?

  create_ebs(node)
  instance_info = @ec2.launch_instances(
    node.try_opt(:aws_image_id), opts).first

  node.options[:aws_instance_id] = instance_info[:aws_instance_id]
  wait_until_node_running(node) { tag_node(node, node.try_opt(:tag)) }
end
create_raid(node, devices=[], md_device=0, chunk=64, level="raid0") { || ... } click to toggle source

Creates a raid array with the given requirements.

@param [ Souffle::Node ] node The node to the raid for. @param [ Array ] devices The list of devices to use for the raid. @param [ Fixnum ] md_device The md device number. @param [ Fixnum ] chunk The chunk size in kilobytes. @param [ String ] level The raid level to use. options are: linear, raid0, 0, stipe, raid1, 1, mirror, raid4, 4, raid5, 5, raid6, 6, multipath, mp

# File lib/souffle/provider/aws.rb, line 157
def create_raid(node, devices=[], md_device=0, chunk=64, level="raid0")
  dev_list = devices.map { |s| "#{s}1" }
  mdadm_string =  "/sbin/mdadm --create /dev/md#{md_device} "
  mdadm_string << "--chunk=#{chunk} --level=#{level} "
  mdadm_string << "--raid-devices=#{devices.size} #{dev_list.join(' ')}"

  export_mdadm = "/sbin/mdadm --detail --scan > /etc/mdadm.conf"

  ssh_block(node) do |ssh|
    ssh.exec!(mdadm_string)
    ssh.exec!(export_mdadm)
    yield if block_given?
  end
end
create_system(system, tag_prefix=nil) click to toggle source

Creates a system using aws as the provider.

@param [ Souffle::System ] system The system to instantiate. @param [ String ] tag_prefix The tag prefix to use for the system.

@return [ String ] The tag for the created system.

# File lib/souffle/provider/aws.rb, line 73
def create_system(system, tag_prefix=nil)
  system.options[:tag] = generate_tag(tag_prefix)
  system.provisioner = Souffle::Provisioner::System.new(system, self)
  system.provisioner.initialized
  system.options[:tag]
end
delete_ebs(node) click to toggle source

Deletes the ebs volumes from a given node.

@param [ Souffle::Node ] node The node to delete volumes from.

# File lib/souffle/provider/aws.rb, line 432
def delete_ebs(node)
  node.options[:volumes].each do |volume|
    @ec2.delete_volume(volume[:aws_id])
  end
end
detach_and_delete_ebs(node) click to toggle source

Detach and delete all volumes from a given node.

@param [ Souffle::Node ] node The node to destroy ebs volumes from.

# File lib/souffle/provider/aws.rb, line 409
def detach_and_delete_ebs(node)
  detach_ebs(node, force=true)
  delete_ebs(node)
end
detach_ebs(node, force=false) click to toggle source

Detaches all ebs volumes from a given node.

@param [ Souffle::Node ] node The node to detach volumes from. @param [ Boolean ] force Whether or not to force the detachment.

# File lib/souffle/provider/aws.rb, line 419
def detach_ebs(node, force=false)
  node.options[:volumes].each_with_index do |volume, index|
    @ec2.detach_volume(
      volume[:aws_id],
      node.options[:aws_instance_id],
      volume_id_to_aws_device(index),
      force)
  end
end
format_device(node) click to toggle source

Formats all of the devices on a given node for the provisioner interface.

@param [ Souffle::Node ] node The node to format it's new partitions.

# File lib/souffle/provider/aws.rb, line 182
def format_device(node)
  partition_device(node, "/dev/md0", "8e") do
    _format_device(node, "/dev/md0p1")
  end
end
fs_formatter(filesystem) click to toggle source

Chooses the appropriate formatter for the given filesystem.

@param [ String ] filesystem The filessytem you intend to use.

@return [ String ] The filesystem formatter.

# File lib/souffle/provider/aws.rb, line 694
def fs_formatter(filesystem)
  "mkfs.#{filesystem}"
end
generate_tag(tag_prefix="sys") click to toggle source

Generates a prefixed unique tag.

@param [ String ] tag_prefix The tag prefix to use.

@return [ String ] The unique tag with prefix.

# File lib/souffle/provider/aws.rb, line 59
def generate_tag(tag_prefix="sys")
  if tag_prefix
    "#{tag_prefix}-#{SecureRandom.hex(4)}"
  else
    SecureRandom.hex(4)
  end
end
instance_id_list(nodes) click to toggle source

Takes a list of nodes and returns the list of their aws instance_ids.

@param [ Array ] nodes The list of nodes to get instance_id's from.

# File lib/souffle/provider/aws.rb, line 83
def instance_id_list(nodes)
  Array(nodes).map { |n| n.options[:aws_instance_id] }
end
kill(nodes) click to toggle source

Takes a list of nodes and kills them. (Haha)

@param [ Souffle::Node ] nodes The list of nodes to terminate.

# File lib/souffle/provider/aws.rb, line 136
def kill(nodes)
  @ec2.terminate_instances(instance_id_list(nodes))
end
kill_and_recreate(nodes) click to toggle source

Takes a list of nodes kills them and then recreates them.

@param [ Souffle::Node ] nodes The list of nodes to kill and recreate.

# File lib/souffle/provider/aws.rb, line 143
def kill_and_recreate(nodes)
  kill(nodes)
  @provisioner.reclaimed
end
mount_lvm(node) { || ... } click to toggle source

Mounts the newly created lvm configuration and adds it to fstab.

@param [ Souffle::Node ] node The node to mount lvm on.

# File lib/souffle/provider/aws.rb, line 268
def mount_lvm(node)
  fstab_str =  "/dev/md0p1      /data"
  fstab_str << "     ext4    noatime,nodiratime  1  1"

  mount_str =  "mount -o rw,noatime,nodiratime"
  mount_str << " /dev/mapper/VolGroup00-data /data"
  ssh_block(node) do |ssh|
    ssh.exec!("mkdir /data")
    ssh.exec!(mount_str)
    ssh.exec!("echo #{fstab_str} >> /etc/fstab")
    ssh.exec!("echo #{fstab_str} >> /etc/mtab")
    yield if block_given?
  end
end
partition(node, iteration=0) click to toggle source

Partition each of the volumes with raid for the node.

@param [ Souffle::Node ] node The node to partition the volumes on. @param [ Fixnum ] iteration The current retry iteration.

# File lib/souffle/provider/aws.rb, line 206
def partition(node, iteration=0)
  return node.provisioner.error_occurred if iteration == 3
  Souffle::PollingEvent.new(node) do
    timeout 30

    pre_event do
      @partitions = 0
      @provider = node.provider
      node.options[:volumes].each_with_index do |volume, index|
        @provider.partition_device(
          node, @provider.volume_id_to_device(index)) do |count|
          @partitions += count
        end
      end
    end

    event_loop do
      if @partitions == node.options[:volumes].size
        event_complete
        node.provisioner.partitioned_device
      end
    end

    error_handler do
      error_msg = "#{node.log_prefix} Timeout during partitioning..."
      Souffle::Log.error error_msg
      @provider.partition(node, iteration+1)
    end
  end
end
partition_device(node, device, partition_type="fd") { |1| ... } click to toggle source

Partitions a device on a given node with the given partition_type.

@note Currently this is a naive implementation and uses the full disk.

@param [ Souffle::Node ] node The node to partition a device on. @param [ String ] device The device to partition. @param [ String ] partition_type The type of partition to create.

# File lib/souffle/provider/aws.rb, line 244
def partition_device(node, device, partition_type="fd")
  partition_cmd =  "echo \",,#{partition_type}\""
  partition_cmd << "| /sbin/sfdisk #{device}"
  ssh_block(node) do |ssh|
    ssh.exec!("#{partition_cmd}")
    yield(1) if block_given?
  end
end
prepare_node_options(node) click to toggle source

Prepares the node options using the system or global defaults.

@param [ Souffle::Node ] node The node you wish to prepare options for.

@return [ Hash ] The options hash to pass into ec2 launch instance.

# File lib/souffle/provider/aws.rb, line 642
def prepare_node_options(node)
  opts = Hash.new
  opts[:instance_type] = node.try_opt(:aws_instance_type)
  opts[:min_count] = 1
  opts[:max_count] = 1
  if using_vpc?(node)
    opts[:subnet_id] = node.try_opt(:aws_subnet_id)
    opts[:aws_subnet_id] = node.try_opt(:aws_subnet_id)
    opts[:aws_vpc_id] = Array(node.try_opt(:aws_vpc_id))
    opts[:group_ids] = Array(node.try_opt(:group_ids))
  else
    opts[:group_names] = node.try_opt(:group_names)
  end
  opts[:key_name] = node.try_opt(:key_name)
  opts
end
provision(node) click to toggle source

Provisions a node with the chef/chef-solo configuration.

@todo Setup the chef/chef-solo tar gzip and ssh connections.

# File lib/souffle/provider/aws.rb, line 480
def provision(node)
  set_hostname(node)
  if node.try_opt(:chef_provisioner).to_s.downcase == "solo"
    provision_chef_solo(node, generate_chef_json(node))
  else
    provision_chef_client(node)
  end
end
provision_chef_client(node) click to toggle source

Provisions a box using the chef_client provisioner.

@todo Chef client provisioner needs to be completed.

# File lib/souffle/provider/aws.rb, line 589
def provision_chef_client(node)
  client_cmds =  "chef-client -N #{node.fqdn} "
  client_cmds << "-j /tmp/client.json "
  client_cmds << "-S #{node.try_opt(:chef_server)} "
  n = node; ssh_block(node) do |ssh|
    write_temp_chef_json(ssh, n)
    ssh.exec!(client_cmds)
    cleanup_temp_chef_files(ssh, n)
    node.provisioner.provisioned
  end
end
provision_chef_solo(node, solo_json) click to toggle source

Provisions a box using the chef_solo provisioner.

@param [ String ] node The node to provision. @param [ String ] solo_json The chef solo json string to use.

# File lib/souffle/provider/aws.rb, line 569
def provision_chef_solo(node, solo_json)
  rsync_file(node, @newest_cookbooks, "/tmp")
  solo_config =  "node_name \"#{node.fqdn}\"\n"
  solo_config << "cookbook_path \"/tmp/cookbooks\"\n"
  solo_config << 'role_path "/tmp/roles"'
  n = node; ssh_block(node) do |ssh|
    ssh.exec!("sleep 2; tar -zxf /tmp/cookbooks-latest.tar.gz -C /tmp")
    ssh.exec!("echo '#{solo_config}' >/tmp/solo.rb")
    ssh.exec!("echo '#{solo_json}' >/tmp/solo.json")
    ssh.exec!("chef-solo -c /tmp/solo.rb -j /tmp/solo.json")
    rm_files = %w{ /tmp/cookbooks /tmp/cookbooks-latest.tar.gz
      /tmp/roles /tmp/solo.rb /tmp/solo.json /tmp/chef_bootstrap }
    ssh.exec!("rm -rf #{rm_files}")
    n.provisioner.provisioned
  end
end
rsync_file(node, file, path='.') click to toggle source

Rsync's a file to a remote node.

@param [ Souffle::Node ] node The node to connect to. @param [ String ] file The file to rsync. @param [ String ] path The remote path to rsync.

Calls superclass method Souffle::Provider::Base#rsync_file
# File lib/souffle/provider/aws.rb, line 606
def rsync_file(node, file, path='.')
  n = @ec2.describe_instances(node.options[:aws_instance_id]).first
  super(n[:private_ip_address], file, path)
end
set_hostname(node) click to toggle source

Sets the hostname for the given node for the chef run.

@param [ Souffle:Node ] node The node to update the hostname for.

# File lib/souffle/provider/aws.rb, line 555
def set_hostname(node)
  local_lookup = "127.0.0.1       #{node.fqdn} #{node.name}\n"
  fqdn = node.fqdn
  ssh_block(node) do |ssh|
    ssh.exec!("hostname '#{fqdn}'")
    ssh.exec!("echo \"#{local_lookup}\" >> /etc/hosts")
    ssh.exec!("echo \"HOSTNAME=#{fqdn}\" >> /etc/sysconfig/network")
  end
end
setup_lvm(node) click to toggle source

Sets up the lvm partition for the raid devices.

@param [ Souffle::Node ] node The node to setup lvm on.

# File lib/souffle/provider/aws.rb, line 256
def setup_lvm(node)
  return if node.options[:volumes].nil?
  ssh_block(node) do |ssh|
    ssh.exec!("pvcreate /dev/md0p1")
    ssh.exec!("vgcreate VolGroup00 /dev/md0p1")
    ssh.exec!("lvcreate -l 100%vg VolGroup00 -n data")
  end
end
setup_mdadm(node) click to toggle source

Installs mdadm (multiple device administration) to manage raid.

@param [ Souffle::Node ] node The node to install mdadm on.

# File lib/souffle/provider/aws.rb, line 286
def setup_mdadm(node)
  n = node; ssh_block(node) do |ssh|
    ssh.exec!("/usr/bin/yum install -y mdadm")
    n.provisioner.mdadm_installed
  end
end
setup_raid(node) click to toggle source

Sets up software raid for the given node.

@param [ Souffle::Node ] node The node setup raid for.

# File lib/souffle/provider/aws.rb, line 296
def setup_raid(node)
  volume_list = []
  node.options[:volumes].each_with_index do |volume, index|
    volume_list << volume_id_to_device(index)
  end
  create_raid(node, volume_list) { node.provisioner.raid_initialized }
end
ssh_block(node, user="root", pass=nil, opts={}) click to toggle source

Yields an ssh object to manage the commands naturally from there.

@param [ Souffle::Node ] node The node to run commands against. @param [ String ] user The user to connect as. @param [ String, NilClass ] pass By default publickey and password auth will be attempted. @param [ Hash ] opts The options hash. @option opts [ Hash ] :net_ssh Options to pass to Net::SSH, see Net::SSH.start @option opts [ Hash ] :timeout (TIMEOUT) default timeout for all wait_for and send_wait calls. @option opts [ Boolean ] :reconnect When disconnected reconnect.

@yield [ EventMachine::Ssh::Session ] The ssh session.

Calls superclass method Souffle::Provider::Base#ssh_block
# File lib/souffle/provider/aws.rb, line 625
def ssh_block(node, user="root", pass=nil, opts={})
  n = @ec2.describe_instances(node.options[:aws_instance_id]).first
  if n.nil?
    raise AwsInstanceDoesNotExist,
      "The AWS instance (#{node.options[:aws_instance_id]}) does not exist."
  else
    key = n[:ssh_key_name]
    opts[:keys] = ssh_key(key) if ssh_key_exists?(key)
    super(n[:private_ip_address], user, pass, opts)
  end
end
stop_nodes(nodes) click to toggle source

Takes a list of nodes an stops the instances.

@param [ Souffle::Node, Array ] nodes The list of nodes to stop.

# File lib/souffle/provider/aws.rb, line 122
def stop_nodes(nodes)
  @ec2.stop_instances(instance_id_list(nodes))
end
stop_system(system) click to toggle source

Stops all nodes in a given system.

@param [ Souffle::System ] system The system to stop.

# File lib/souffle/provider/aws.rb, line 129
def stop_system(system)
  stop_nodes(system.nodes)
end
subnet_exists?(node) click to toggle source

Checks whether or not the subnet currently exists.

@param [ Souffle::Node ] node The node to check vpc information for.

@return [ Boolean ] Whether or not the subnet exists.

# File lib/souffle/provider/aws.rb, line 472
def subnet_exists?(node)
  @ec2.describe_subnets({:filters =>
    { 'subnet-id' => node.try_opt(:aws_subnet_id) } }).any?
end
tag_node(node, tag="") click to toggle source

Tags a node and it's volumes.

@param [ Souffle::Node ] node The node to tag. @param [ String ] tag The tag to use for the node.

# File lib/souffle/provider/aws.rb, line 107
def tag_node(node, tag="")
  @ec2.create_tags(Array(node.options[:aws_instance_id]), {
    :Name => node.name,
    :souffle => tag
  })
  volume_ids = node.options[:volumes].map { |vol| vol[:aws_id] }
  @ec2.create_tags(Array(volume_ids), {
    :instance_id => node.options[:aws_instance_id],
    :souffle => tag
  }) unless Array(volume_ids).empty?
end
using_vpc?(node) click to toggle source

Whether or not to use a vpc instance and subnet for provisioning.

@param [ Souffle::Node ] node The node to check vpc information for. @return [ Boolean ] Whether to use a vpc instance and specific subnet.

# File lib/souffle/provider/aws.rb, line 443
def using_vpc?(node)
  !!node.try_opt(:aws_vpc_id) and
  !!node.try_opt(:aws_subnet_id)
end
volume_id_to_aws_device(volume_id) click to toggle source

Takes the volume count in the array and converts it to a device name.

@note This starts at /dev/xvda and goes to /dev/xvdb, etc. And due to the special case on AWS, skips /dev/xvde.

@param [ Fixnum ] volume_id The count in the array for the volume id.

@return [ String ] The device string to mount to.

# File lib/souffle/provider/aws.rb, line 682
def volume_id_to_aws_device(volume_id)
  if volume_id >= 4
    volume_id += 1
  end
  "/dev/hd#{(volume_id + "a".ord).chr}"
end
volume_id_to_device(volume_id) click to toggle source

Takes the volume count in the array and converts it to a device name.

@note This starts at /dev/xvda and goes to /dev/xvdb, etc. And due to the special case on AWS, skips /dev/xvde.

@param [ Fixnum ] volume_id The count in the array for the volume id.

@return [ String ] The device string to mount to.

# File lib/souffle/provider/aws.rb, line 667
def volume_id_to_device(volume_id)
  if volume_id >= 4
    volume_id += 1
  end
  "/dev/xvd#{(volume_id + "a".ord).chr}"
end
vpc_exists?(node) click to toggle source

Checks whether or not the vpc currently exists.

@param [ Souffle::Node ] node The node to check vpc information for.

@return [ Boolean ] Whether or not the vpc exists.

# File lib/souffle/provider/aws.rb, line 462
def vpc_exists?(node)
  @ec2.describe_vpcs({:filters =>
    { 'vpc-id' => node.try_opt(:aws_vpc_id) } }).any?
end
vpc_setup?(node) click to toggle source

Checks whether or not the vpc and subnet are setup proeprly.

@param [ Souffle::Node ] node The node to check vpc information for.

@return [ Boolean ] Whether or not the vpc is setup.

# File lib/souffle/provider/aws.rb, line 453
def vpc_setup?(node)
  vpc_exists? and subnet_exists?
end
wait_for_boot(node, user="root", pass=nil, opts={}, poll_timeout=100, iteration=0, &blk) click to toggle source

Waits for ssh to be accessible for a node for the initial connection and yields an ssh object to manage the commands naturally from there.

@param [ Souffle::Node ] node The node to run commands against. @param [ String ] user The user to connect as. @param [ String, NilClass ] pass By default publickey and password auth will be attempted. @param [ Hash ] opts The options hash. @param [ Fixnum ] poll_timeout The maximum number of seconds to wait. @param [ Fixnum ] iteration The current retry iteration.

@option opts [ Hash ] :net_ssh Options to pass to Net::SSH, see Net::SSH.start @option opts [ Hash ] :timeout (TIMEOUT) default timeout for all wait_for and send_wait calls. @option opts [ Boolean ] :reconnect When disconnected reconnect.

@yield [ Eventmachine::Ssh:Session ] The ssh session.

# File lib/souffle/provider/aws.rb, line 507
def wait_for_boot(node, user="root", pass=nil, opts={},
                  poll_timeout=100, iteration=0, &blk)
  return node.provisioner.error_occurred if iteration == 3

  ec2 = @ec2; Souffle::PollingEvent.new(node) do
    timeout poll_timeout
    interval EM::Ssh::Connection::TIMEOUT

    pre_event do
      Souffle::Log.info "#{node.log_prefix} Waiting for ssh..."
      @provider = node.provider
      @blk = blk
    end

    event_loop do
      n = ec2.describe_instances(node.options[:aws_instance_id]).first
      unless n.nil?
        key = n[:ssh_key_name]
        if @provider.ssh_key_exists?(key)
          opts[:keys] = @provider.ssh_key(key)
        end
        opts[:password] = pass unless pass.nil?
        opts[:paranoid] = false
        address = n[:private_ip_address]

        EM::Ssh.start(address, user, opts) do |connection|
          connection.errback  { |err| nil }
          connection.callback do |ssh|
            event_complete
            node.provisioner.booted
            @blk.call(ssh) unless @blk.nil?
            ssh.close
          end
        end
      end
    end

    error_handler do
      Souffle::Log.error "#{node.log_prefix} SSH Boot timeout..."
      @provider.wait_for_boot(node, user, pass, opts,
        poll_timeout, iteration+1, &blk)
    end
  end
end
wait_until_ebs_ready(node, poll_timeout=100, poll_interval=2) click to toggle source

Polls the EBS volume status until they're ready then runs the given block.

@param [ Souffle::Node ] node The node to wait for EBS on. @param [ Fixnum ] poll_timeout The maximum number of seconds to wait. @param [ Fixnum ] poll_interval The interval in seconds to poll EC2.

# File lib/souffle/provider/aws.rb, line 360
def wait_until_ebs_ready(node, poll_timeout=100, poll_interval=2)
  ec2 = @ec2; Souffle::PollingEvent.new(node) do
    timeout poll_timeout
    interval poll_interval

    pre_event do
      Souffle::Log.info "#{node.log_prefix} Waiting for EBS to be ready..."
      @provider = node.provider
      @volume_ids = node.options[:volumes].map { |v| v[:aws_id] }
    end

    event_loop do
      vol_status = ec2.describe_volumes(@volume_ids)
      avail = Array(vol_status).select { |v| v[:aws_status] == "available" }
      if avail.size == vol_status.size
        event_complete
        @provider.attach_ebs(node)
        node.provisioner.created
      end
    end

    error_handler do
      error_msg = "#{node.log_prefix} Waiting for EBS Timed out..."
      Souffle::Log.error error_msg
      node.provisioner.error_occurred
    end
  end
end
wait_until_node_running(node, poll_timeout=100, poll_interval=2, &blk) click to toggle source

Polls the EC2 instance information until it is in the running state.

@param [ Souffle::Node ] node The node to wait until running on. @param [ Fixnum ] poll_timeout The maximum number of seconds to wait. @param [ Fixnum ] poll_interval The interval in seconds to poll EC2.

# File lib/souffle/provider/aws.rb, line 326
def wait_until_node_running(node, poll_timeout=100, poll_interval=2, &blk)
  ec2 = @ec2; Souffle::PollingEvent.new(node) do
    timeout poll_timeout
    interval poll_interval

    pre_event do
      Souffle::Log.info "#{node.log_prefix} Waiting for node running..."
      @provider = node.provider
      @blk = blk
    end

    event_loop do
      instance = ec2.describe_instances(
        node.options[:aws_instance_id]).first
      if instance[:aws_state].downcase == "running"
        event_complete
        @blk.call unless @blk.nil?
        @provider.wait_until_ebs_ready(node)
      end
    end

    error_handler do
      error_msg = "#{node.log_prefix} Wait for node running timeout..."
      Souffle::Log.error error_msg
      node.provisioner.error_occurred
    end
  end
end

Private Instance Methods

cleanup_temp_chef_files(ssh, node) click to toggle source

Removes the temporary chef-client files.

@param [ EventMachine::Ssh::Connection ] ssh The em-ssh connection. @param [ Souffle::Node ] node The given node to work with.

# File lib/souffle/provider/aws.rb, line 748
def cleanup_temp_chef_files(ssh, node)
  ssh.exec!("rm -f /tmp/client.json")
  ssh.exec!("rm -f /etc/chef/validation.pem")
end
write_temp_chef_json(ssh, node) click to toggle source

Writes a temporary chef-client json file.

@param [ EventMachine::Ssh::Connection ] ssh The em-ssh connection. @param [ Souffle::Node ] node The given node to work with.

# File lib/souffle/provider/aws.rb, line 740
def write_temp_chef_json(ssh, node)
  ssh.exec!("echo '''#{generate_chef_json(node)}''' > /tmp/client.json")
end