Skip to content

Instantly share code, notes, and snippets.

@ejoubaud
Created December 14, 2016 17:46
Show Gist options
  • Save ejoubaud/e1d7099f7234a70cf49621a9e0300b3d to your computer and use it in GitHub Desktop.
Save ejoubaud/e1d7099f7234a70cf49621a9e0300b3d to your computer and use it in GitHub Desktop.
Checks the status and AMI ID of instances in the ASG of a CloudFormation stack (used to test an AMI rotation script)
#!/usr/bin/env ruby
require 'aws-sdk'
require 'forwardable'
DEFAULT_REGION = "us-east-1".freeze
STACK_NAMES = ['market-dj'].freeze
class Instance
extend Forwardable
delegate [:image_id] => :ec2_instance_resource
delegate [:health_status, :lifecycle_state] => :as_instance_resource
attr_reader :instance_id
def initialize(instance_id, client_options = { region: DEFAULT_REGION }, ec2_instance_resource: nil, as_instance_resource: nil)
@instance_id, @client_options = instance_id, client_options
@ec2_instance_resource, @as_instance_resource = ec2_instance_resource, as_instance_resource
end
private
def ec2_instance_resource
@ec2_instance_resource ||= ec2_client.describe_instances(instance_ids: [@instance_id]).reservations.first.instances.first
end
def as_instance_resource
@as_instance_resource ||= ec2_client.describe_instances(instance_ids: [@instance_id]).reservations.first.instances.first
end
def ec2_client
@ec2_client ||= Aws::EC2::Client.new(@client_options)
end
def as_client
@as_client ||= Aws::AutoScaling::Client.new(@client_options)
end
end
class Asg
def initialize(asg_name, client_options = { region: DEFAULT_REGION })
@asg_name, @client_options = asg_name, client_options
end
def latest_ami_id
@latest_ami_id ||= as_launch_config_resouce.image_id
end
def instances
as_instance_resources = as_asg_resource.instances.group_by(&:instance_id)
ec2_instance_resources = ec2_client.describe_instances(instance_ids: as_instance_resources.keys).reservations.flat_map(&:instances).group_by(&:instance_id)
as_instance_resources.map do |instance_id, as_instance_resources|
as_instance_resource = as_instance_resources.first
ec2_instance_resource = ec2_instance_resources[instance_id].first
# Passing the resources directly to the Instance allows us to make only 2 queries
# (one on the autoscaling client and one on the EC2 client) for all the instances
# rather than 2 queries for each instance
Instance.new(instance_id, @client_options, as_instance_resource: as_instance_resource, ec2_instance_resource: ec2_instance_resource)
end
end
def instance_statuses
instances.map do |i|
{ :id => i.instance_id, :health => i.health_status, :state => i.lifecycle_state, :ami => i.image_id }
end
end
private
def as_asg_resource
as_client.describe_auto_scaling_groups(auto_scaling_group_names: [@asg_name]).auto_scaling_groups.first
end
def as_launch_config_resource
as_client.describe_launch_configurations(launch_configuration_names: [as_asg_resource.launch_configuration_name]).launch_configurations.first
end
def as_client
@as_client ||= Aws::AutoScaling::Client.new(@client_options)
end
def ec2_client
@ec2_client ||= Aws::EC2::Client.new(@client_options)
end
end
class Stack
def initialize(stack_name, client_options = { region: DEFAULT_REGION })
@stack_name, @client_options = stack_name, client_options
end
def asg
@asg ||= Asg.new(asg_name, @client_options)
end
private
def asg_name
cf_asg_resource.physical_resource_id
end
def cf_asg_resource
@cf_asg_summary ||= cf_client.describe_stack_resources(stack_name: @stack_name, logical_resource_id: 'AutoScalingGroup').stack_resources.first
end
def cf_client
@cf_client ||= ::Aws::CloudFormation::Client.new(@client_options)
end
end
last_state = nil
while true do
new_state = Stack.new('market-dj').asg.instance_statuses
if new_state != last_state
p Time.now
new_state.each do |i|
print "#{i[:id]} #{i[:ami]} #{i[:state]} #{i[:health]}\n"
end
last_state = new_state
end
sleep 0.1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment