class Awful::AutoScaling

Constants

COLORS

Public Instance Methods

activities(name) click to toggle source
# File lib/awful/auto_scaling.rb, line 382
def activities(name)
  autoscaling.describe_scaling_activities(auto_scaling_group_name: name).activities.output do |activities|
    if options[:long]
      print_table activities.map { |a| [color(a.status_code), a.description, a.start_time, a.end_time] }
    elsif options[:cause]
      print_table activities.map { |a| [color(a.status_code), a.description, a.start_time, a.end_time, "\n#{a.cause}\n\n"] }
    else
      puts activities.map(&:activity_id)
    end
  end
end
all_matching_asgs(name) click to toggle source
# File lib/awful/auto_scaling.rb, line 35
def all_matching_asgs(name)
  autoscaling.describe_auto_scaling_groups.map(&:auto_scaling_groups).flatten.select do |asg|
    asg.auto_scaling_group_name.match(name) or tag_name(asg, '').match(name)
  end
end
asg_instance_details(*names) click to toggle source

lookup ec2 details for instances in named ASGs

# File lib/awful/auto_scaling.rb, line 47
def asg_instance_details(*names)
  ids = asg_instances(*names).map(&:instance_id)
  ec2.describe_instances(instance_ids: ids).map(&:reservations).flatten.map(&:instances).flatten.sort_by(&:launch_time)
end
asg_instances(*names) click to toggle source

return instances for named ASGs

# File lib/awful/auto_scaling.rb, line 42
def asg_instances(*names)
  autoscaling.describe_auto_scaling_groups(auto_scaling_group_names: names).auto_scaling_groups.map(&:instances).flatten
end
attach(name, *instance_ids) click to toggle source
# File lib/awful/auto_scaling.rb, line 305
def attach(name, *instance_ids)
  autoscaling.attach_instances(auto_scaling_group_name: name, instance_ids: instance_ids)
end
color(string) click to toggle source
# File lib/awful/auto_scaling.rb, line 31
def color(string)
  set_color(string, COLORS.fetch(string.to_sym, :yellow))
end
create(file = nil) click to toggle source
# File lib/awful/auto_scaling.rb, line 169
def create(file = nil)
  opt = load_cfg(options, file)
  whitelist = %i[auto_scaling_group_name launch_configuration_name instance_id min_size max_size desired_capacity default_cooldown availability_zones
                 load_balancer_names health_check_type health_check_grace_period placement_group vpc_zone_identifier termination_policies tags ]

  opt = remove_empty_strings(opt)
  opt = only_keys_matching(opt, whitelist)

  ## scrub aws-provided keys from tags
  opt[:tags] = opt.has_key?(:tags) ? opt[:tags].map { |tag| only_keys_matching(tag, %i[key value propagate_at_launch]) } : []

  autoscaling.create_auto_scaling_group(opt)
end
delete(name) click to toggle source
# File lib/awful/auto_scaling.rb, line 80
def delete(name)
  if yes? "Really delete auto-scaling group #{name}?", :yellow
    autoscaling.delete_auto_scaling_group(auto_scaling_group_name: name)
  end
end
detach(name, *instance_ids) click to toggle source
# File lib/awful/auto_scaling.rb, line 311
def detach(name, *instance_ids)
  autoscaling.detach_instances(auto_scaling_group_name: name, instance_ids: instance_ids, should_decrement_desired_capacity: options[:decrement])
end
dump(name) click to toggle source
# File lib/awful/auto_scaling.rb, line 155
def dump(name)
  all_matching_asgs(name).map(&:to_hash).output do |asgs|
    asgs.each do |asg|
      puts YAML.dump(stringify_keys(asg)) unless options[:quiet]
    end
  end
end
enter_standby(name, *instance_ids) click to toggle source
# File lib/awful/auto_scaling.rb, line 406
def enter_standby(name, *instance_ids)
  autoscaling.enter_standby(
    auto_scaling_group_name: name,
    instance_ids: instance_ids,
    should_decrement_desired_capacity: options[:decrement]
  )
end
exit_standby(name, *instance_ids) click to toggle source
# File lib/awful/auto_scaling.rb, line 415
def exit_standby(name, *instance_ids)
  autoscaling.exit_standby(auto_scaling_group_name: name, instance_ids: instance_ids)
end
instance_lifecycle_state(*instance_ids) click to toggle source
# File lib/awful/auto_scaling.rb, line 52
def instance_lifecycle_state(*instance_ids)
  autoscaling.describe_auto_scaling_instances(instance_ids: instance_ids).auto_scaling_instances.map(&:lifecycle_state)
end
instances(*names) click to toggle source
# File lib/awful/auto_scaling.rb, line 89
def instances(*names)
  instances = asg_instances(*names)

  ## make extra call to get asg name as part of object
  if options[:describe]
    instances = autoscaling.describe_auto_scaling_instances(instance_ids: instances.map(&:instance_id)).auto_scaling_instances
  end

  instances.output do |list|
    if options[:long]
      print_table list.map { |i|
        [
          i.instance_id,
          options[:describe] ? i.auto_scaling_group_name : nil,
          i.availability_zone,
          color(i.lifecycle_state),
          color(i.health_status),
          i.launch_configuration_name,
        ].compact
      }
    else
      puts list.map(&:instance_id)
    end
  end
end
ips(*names) click to toggle source
# File lib/awful/auto_scaling.rb, line 117
def ips(*names)
  asg_instance_details(*names).output do |instances|
    if options[:long]
      print_table instances.map { |i|
        [ i.public_ip_address, i.private_ip_address, i.instance_id, i.image_id, i.instance_type, i.placement.availability_zone, color(i.state.name), i.launch_time ]
      }
    else
      puts instances.map(&:public_ip_address)
    end
  end
end
launch_configuration(*names) click to toggle source
# File lib/awful/auto_scaling.rb, line 317
def launch_configuration(*names)
  autoscaling.describe_auto_scaling_groups(
    auto_scaling_group_names: names
  ).map(&:auto_scaling_groups).flatten.each_with_object({}) do |asg, h|
    h[asg.auto_scaling_group_name] = asg.launch_configuration_name
  end.output do |hash|
    if options[:long]
      print_table hash
    else
      puts hash.values
    end
  end
end
ls(*names) click to toggle source
# File lib/awful/auto_scaling.rb, line 59
def ls(*names)
  autoscaling.describe_auto_scaling_groups(auto_scaling_group_names: names).auto_scaling_groups.output do |asgs|
    if options[:long]
      print_table asgs.map { |a|
        [
          tag_name(a, '-')[0,40],
          a.auto_scaling_group_name[0,40],
          a.launch_configuration_name[0,40],
          "#{a.instances.length}/#{a.desired_capacity}",
          "#{a.min_size}-#{a.max_size}",
          a.availability_zones.map{ |az| az[-1,1] }.sort.join(','),
          a.created_time
        ]
      }
    else
      puts asgs.map(&:auto_scaling_group_name)
    end
  end
end
newest(name) click to toggle source

return array of instances in auto-scaling group, reverse sorted by age, newest first

# File lib/awful/auto_scaling.rb, line 232
def newest(name)
  oldest(name).reverse
end
old_instances(*names) click to toggle source
# File lib/awful/auto_scaling.rb, line 338
def old_instances(*names)
  asgs = autoscaling.describe_auto_scaling_groups(auto_scaling_group_names: names).map(&:auto_scaling_groups).flatten

  ## get hash of old instances by ASG name
  olds = asgs.each_with_object({}) do |asg, hash|
    outdated = asg.instances.select do |instance|
      instance.launch_configuration_name != asg.launch_configuration_name
    end
    hash[asg.auto_scaling_group_name] = outdated unless outdated.empty?
  end

  if olds.empty?
  # noop
  elsif options[:detach]
    autoscaling.detach_instances(auto_scaling_group_name: name, instance_ids: olds.values.flatten.map(&:instance_id), should_decrement_desired_capacity: options[:decrement])
  elsif options[:deregister]
    asgs.select do |asg|
      olds.has_key?(asg.auto_scaling_group_name)
    end.each do |asg|
      instance_ids = olds[asg.auto_scaling_group_name].flatten.map(&:instance_id)
      asg.load_balancer_names.each do |elb_name|
        say "Deregistering #{instance_ids.join(',')} from ELB #{elb_name}", :yellow
        elb.deregister_instances_from_load_balancer(load_balancer_name: elb_name, instances: instance_ids.map { |id| {instance_id: id} })
      end
    end
  elsif options[:terminate]
    olds.values.flatten.map do |instance|
      autoscaling.terminate_instance_in_auto_scaling_group(instance_id: instance.instance_id, should_decrement_desired_capacity: options[:decrement] && true)
      instance.instance_id
    end.output { |ids| say("Terminated: #{ids.join(',')}", :yellow) }
  elsif options[:groups]
    puts olds.keys
  elsif options[:long]
    print_table olds.map { |asg, ins| ins.map { |i| [i.instance_id, asg, i.launch_configuration_name] }.flatten }
  else
    puts olds.values.flatten.map(&:instance_id)
  end

  olds
end
oldest(name) click to toggle source

return array of instances in auto-scaling group sorted by age

# File lib/awful/auto_scaling.rb, line 220
def oldest(name)
  instance_ids = autoscaling.describe_auto_scaling_instances.map(&:auto_scaling_instances).flatten.select do |instance|
    instance.auto_scaling_group_name == name
  end.map(&:instance_id)
  if instance_ids.empty?
    []
  else
    ec2.describe_instances(instance_ids: instance_ids).map(&:reservations).flatten.map(&:instances).flatten.sort_by(&:launch_time)
  end
end
processes() click to toggle source
# File lib/awful/auto_scaling.rb, line 273
def processes
  autoscaling.describe_scaling_process_types.processes.map(&:process_name).sort.output do |procs|
    puts procs
  end
end
resume(name, *procs) click to toggle source
# File lib/awful/auto_scaling.rb, line 296
def resume(name, *procs)
  if procs.empty?
    autoscaling.resume_processes(auto_scaling_group_name: name)
  else
    autoscaling.resume_processes(auto_scaling_group_name: name, scaling_processes: procs)
  end
end
ssh(name, *args) click to toggle source
# File lib/awful/auto_scaling.rb, line 135
def ssh(name, *args)
  instances = asg_instance_details(name)

  ## filter by list of instance id patterns
  if options[:instances]
    instances.select! do |i|
      options[:instances].map{ |pattern| i.instance_id.match(pattern) }.any?
    end
  end

  ips = instances.map(&:public_ip_address)
  num = options[:all] ? ips.count : options[:number].to_i
  login_name = options[:login_name] ? "-l #{options[:login_name]}" : ''
  ips.last(num).each do |ip|
    puts ip if options[:verbose]
    system "ssh #{login_name} #{ip} #{Array(args).join(' ')}"
  end
end
stop(name, num = 1) click to toggle source
# File lib/awful/auto_scaling.rb, line 263
def stop(name, num = 1)
  ins = options[:newest] ? newest(name) : oldest(name)
  ins.first(num.to_i).map(&:instance_id).output do |ids|
    if yes? "Really stop #{num} instances: #{ids.join(',')}?", :yellow
      ec2.stop_instances(instance_ids: ids)
    end
  end
end
suspend(name, *procs) click to toggle source
# File lib/awful/auto_scaling.rb, line 281
def suspend(name, *procs)
  if options[:list]
    autoscaling.describe_auto_scaling_groups(
      auto_scaling_group_names: Array(name)
    ).map(&:auto_scaling_groups).flatten.first.suspended_processes.output do |list|
      print_table list.map{ |proc| [ proc.process_name, proc.suspension_reason] }
    end
  elsif procs.empty?
    autoscaling.suspend_processes(auto_scaling_group_name: name)
  else
    autoscaling.suspend_processes(auto_scaling_group_name: name, scaling_processes: procs)
  end
end
terminate(name, num = 1) click to toggle source
# File lib/awful/auto_scaling.rb, line 242
def terminate(name, num = 1)
  ins = options[:newest] ? newest(name) : oldest(name)
  num = ins.length if options[:all] # all instances if requested

  if ins.empty?
    say 'No instances to terminate.', :green
  else
    ids = ins.first(num.to_i).map(&:instance_id)
    if yes? "Really terminate #{num} instances: #{ids.join(',')}?", :yellow
      ids.each do |id|
        puts "Terminating instance: #{id}"
        autoscaling.terminate_instance_in_auto_scaling_group(instance_id: id, should_decrement_desired_capacity: options[:decrement] && true)
      end
    else
      puts 'Nothing terminated'
    end
  end
end
update(name, file = nil) click to toggle source
# File lib/awful/auto_scaling.rb, line 188
def update(name, file = nil)
  opt = load_cfg(options, file)

  ## allow matching by group name or name tag, but ensure we get only one
  asgs = all_matching_asgs(name)
  if asgs.length < 1
    warn "no match for #{name}"
    return
  elsif asgs.length > 1
    warn "ambiguous match for #{name}:", asgs.map(&:auto_scaling_group_name)
    return
  end

  ## cleanup the group options
  opt[:auto_scaling_group_name] = asgs.first.auto_scaling_group_name
  opt = remove_empty_strings(opt)

  ## update the group
  whitelist = %i[auto_scaling_group_name launch_configuration_name min_size max_size desired_capacity default_cooldown availability_zones
                 health_check_type health_check_grace_period placement_group vpc_zone_identifier termination_policies ]
  autoscaling.update_auto_scaling_group(only_keys_matching(opt, whitelist))

  ## update any tags
  if opt[:tags]
    tags = opt[:tags].map { |tag| tag.merge(resource_id: name, resource_type: 'auto-scaling-group') }
    autoscaling.create_or_update_tags(tags: tags)
  end
end
wait(*instance_ids) click to toggle source
# File lib/awful/auto_scaling.rb, line 397
def wait(*instance_ids)
  until instance_lifecycle_state(*instance_ids).all?{ |s| s == options[:state] }
    puts "waiting for #{instance_ids.count} instances to enter state #{options[:state]}" unless options[:quiet]
    sleep options[:period]
  end
end