Class: Awful::AutoScaling

Inherits:
Cli
  • Object
show all
Defined in:
lib/awful/auto_scaling.rb

Constant Summary collapse

COLORS =
{
  ## lifecycle states
  Pending:     :yellow,
  InService:   :green,
  Terminating: :red,
  ## health statuses
  Healthy:     :green,
  Unhealthy:   :red,
  ## activity status
  Successful:   :green,
  Failed:      :red,
  Cancelled:   :red,
  ## instance state
  running:    :green,
  stopped:    :yellow,
  terminated: :red,
}

Instance Method Summary collapse

Methods inherited from Cli

#initialize

Constructor Details

This class inherits a constructor from Awful::Cli

Instance Method Details

#activities(name) ⇒ Object



339
340
341
342
343
344
345
346
347
348
349
# File 'lib/awful/auto_scaling.rb', line 339

def activities(name)
  autoscaling.describe_scaling_activities(auto_scaling_group_name: name).activities.tap 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

#attach(name, *instance_ids) ⇒ Object



266
267
268
# File 'lib/awful/auto_scaling.rb', line 266

def attach(name, *instance_ids)
  autoscaling.attach_instances(auto_scaling_group_name: name, instance_ids: instance_ids)
end

#create(file = nil) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/awful/auto_scaling.rb', line 132

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) ⇒ Object



58
59
60
61
62
# File 'lib/awful/auto_scaling.rb', line 58

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) ⇒ Object



272
273
274
# File 'lib/awful/auto_scaling.rb', line 272

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) ⇒ Object



118
119
120
121
122
123
124
# File 'lib/awful/auto_scaling.rb', line 118

def dump(name)
  all_matching_asgs(name).map(&:to_hash).tap do |asgs|
    asgs.each do |asg|
      puts YAML.dump(stringify_keys(asg)) unless options[:quiet]
    end
  end
end

#instances(name) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/awful/auto_scaling.rb', line 67

def instances(name)
  all_matching_asgs(name).map(&:instances).flatten.tap do |instances|
    if options[:long]
      print_table instances.map { |i|
        [
          i.instance_id,
          i.availability_zone,
          color(i.lifecycle_state),
          color(i.health_status),
          i.launch_configuration_name,
        ]
      }
    else
      puts instances.map(&:instance_id)
    end
  end
end

#ips(name) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/awful/auto_scaling.rb', line 87

def ips(name)
  ## get instance IDs for matching ASGs
  ids = all_matching_asgs(name).map(&:instances).flatten.map(&:instance_id)

  ## get instance details for these IDs
  ec2.describe_instances(instance_ids: ids).map(&:reservations).flatten.map(&:instances).flatten.sort_by(&:launch_time).tap 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) ⇒ Object



278
279
280
281
282
283
284
285
286
287
288
# File 'lib/awful/auto_scaling.rb', line 278

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.tap do |hash|
    if options[:long]
      print_table hash
    else
      puts hash.values
    end
  end
end

#ls(name = /./) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/awful/auto_scaling.rb', line 37

def ls(name = /./)
  all_matching_asgs(name).tap 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

#old_instances(*names) ⇒ Object



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/awful/auto_scaling.rb', line 297

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.tap { |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
end

#processesObject



236
237
238
239
240
# File 'lib/awful/auto_scaling.rb', line 236

def processes
  autoscaling.describe_scaling_process_types.processes.map(&:process_name).sort.tap do |procs|
    puts procs
  end
end

#resume(name, *procs) ⇒ Object



257
258
259
260
261
262
263
# File 'lib/awful/auto_scaling.rb', line 257

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) ⇒ Object



108
109
110
111
112
113
114
115
# File 'lib/awful/auto_scaling.rb', line 108

def ssh(name, *args)
  ips = ips(name).map(&:public_ip_address)
  num = options[:all] ? ips.count : options[:number].to_i
   = options[:login_name] ? "-l #{options[:login_name]}" : ''
  ips.last(num).each do |ip|
    system "ssh #{} #{ip} #{Array(args).join(' ')}"
  end
end

#stop(name, num = 1) ⇒ Object



226
227
228
229
230
231
232
233
# File 'lib/awful/auto_scaling.rb', line 226

def stop(name, num = 1)
  ins = options[:newest] ? newest(name) : oldest(name)
  ins.first(num.to_i).map(&:instance_id).tap do |ids|
    if yes? "Really stop #{num} instances: #{ids.join(',')}?", :yellow
      ec2.stop_instances(instance_ids: ids)
    end
  end
end

#suspend(name, *procs) ⇒ Object



244
245
246
247
248
249
250
251
252
253
254
# File 'lib/awful/auto_scaling.rb', line 244

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.tap 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) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/awful/auto_scaling.rb', line 205

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) ⇒ Object



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/awful/auto_scaling.rb', line 151

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