module RubyAemAws::HealthyCountVerifier

Mixin for checking health of a component via ELB 'healthy' count vs ASG desired_capacity. Add this to a component to make it capable of determining its own health.

Public Instance Methods

health_state() click to toggle source

Provides detail of the state of the instances comprising the component. @return one of:

  • no_asg: AutoScalingGroup could not be located (by StackPrefix and Component tags).

  • no_elb: ElasticLoadBalancer could not be located (by StackPrefix and aws:cloudformation:logical-id tags).

  • misconfigured: AutoScalingGroup.desired_capacity is less than 1.

  • recovering: ELB running instance count is less than AutoScalingGroup.desired_capacity.

  • scaling: ELB running instance count is more than AutoScalingGroup.desired_capacity.

  • ready: ELB running instance count is equal to AutoScalingGroup.desired_capacity.

# File lib/ruby_aem_aws/mixins/healthy_count_verifier.rb, line 35
def health_state
  asg = find_auto_scaling_group(asg_client)
  return :no_asg if asg.nil?

  # Debug:
  # unless asg.nil?
  #   puts("ASG: #{asg} #{asg.auto_scaling_group_name} (#{asg.desired_capacity})")
  #   asg.instances.each do |i|
  #     puts("  Instance #{i.instance_id}: #{i.health_status}")
  #   end
  # end

  elb = find_elb(elb_client)
  return :no_elb if elb.nil?

  elb_running_instances = 0
  get_instances_state_from_elb(elb).each do |i|
    elb_running_instances += 1 if i[:state] == RubyAemAws::Constants::INSTANCE_STATE_HEALTHY
  end

  desired_capacity = asg.desired_capacity

  return :misconfigured if desired_capacity < 1
  return :recovering if elb_running_instances < desired_capacity
  return :scaling if elb_running_instances > desired_capacity

  :ready
end
healthy?() click to toggle source

Aggregate health_states considered healthy. @return health_state is ready or scaling.

# File lib/ruby_aem_aws/mixins/healthy_count_verifier.rb, line 23
def healthy?
  %i[ready scaling].include? health_state
end
wait_until_healthy() click to toggle source

@return true, if all EC2 instances within the ELB are running

# File lib/ruby_aem_aws/mixins/healthy_count_verifier.rb, line 65
def wait_until_healthy
  raise ELBMisconfiguration if health_state.eql?(:misconfigured)

  sleep 60 while health_state.eql?(:recovering) || health_state.eql?(:scaling)
  return true if health_state.eql?(:ready)
end

Private Instance Methods

find_auto_scaling_group(asg_client) click to toggle source

@return AutoScalingGroup by StackPrefix and Component tags.

# File lib/ruby_aem_aws/mixins/healthy_count_verifier.rb, line 75
def find_auto_scaling_group(asg_client)
  autoscaling_groups = asg_client.describe_auto_scaling_groups(max_records: 50)
  find_auto_scaling_group = find_auto_scaling_group_name(autoscaling_groups)

  return find_auto_scaling_group unless find_auto_scaling_group.nil?

  until autoscaling_groups.next_token.nil?
    autoscaling_groups = asg_client.describe_auto_scaling_groups(max_records: 50, next_token: autoscaling_groups.next_token)
    find_auto_scaling_group = find_auto_scaling_group_name(autoscaling_groups)
    return find_auto_scaling_group unless find_auto_scaling_group.nil?
  end
  return nil if find_auto_scaling_group.nil?
end
find_auto_scaling_group_name(autoscaling_groups) click to toggle source
# File lib/ruby_aem_aws/mixins/healthy_count_verifier.rb, line 89
def find_auto_scaling_group_name(autoscaling_groups)
  autoscaling_groups.auto_scaling_groups.each do |autoscaling_group|
    asg_matches_stack_prefix = false
    asg_matches_component = false
    tags = autoscaling_group.tags
    tags.each do |tag|
      if tag.key == 'StackPrefix' && tag.value == descriptor.stack_prefix
        asg_matches_stack_prefix = true
        break if asg_matches_component

        next
      end
      if tag.key == 'Component' && tag.value == descriptor.ec2.component
        asg_matches_component = true
        break if asg_matches_stack_prefix
      end
    end
    return autoscaling_group if asg_matches_stack_prefix && asg_matches_component
  end
  nil
end
find_elb(elb_client) click to toggle source

@return ElasticLoadBalancer by StackPrefix and logical-id tags.

# File lib/ruby_aem_aws/mixins/healthy_count_verifier.rb, line 112
def find_elb(elb_client)
  elbs = elb_client.describe_load_balancers.load_balancer_descriptions
  elbs.each do |elb|
    elb_matches_stack_prefix = false
    elb_matches_logical_id = false
    tag_descriptions = elb_client.describe_tags(load_balancer_names: [elb.load_balancer_name]).tag_descriptions
    next if tag_descriptions.empty?

    tags = tag_descriptions[0].tags
    tags.each do |tag|
      if tag.key == 'StackPrefix' && tag.value == descriptor.stack_prefix
        elb_matches_stack_prefix = true
        break if elb_matches_logical_id

        next
      end
      if tag.key == 'aws:cloudformation:logical-id' && tag.value == descriptor.elb.id
        elb_matches_logical_id = true
        break if elb_matches_stack_prefix
      end
    end
    return elb if elb_matches_stack_prefix && elb_matches_logical_id
  end
  nil
end
get_instances_state_from_elb(elb) click to toggle source
# File lib/ruby_aem_aws/mixins/healthy_count_verifier.rb, line 138
def get_instances_state_from_elb(elb)
  stack_prefix_instances = []
  elb.instances.each do |i|
    instance = get_instance_by_id(i.instance_id)
    next if instance.nil?

    instance.tags.each do |tag|
      next if tag.key != 'StackPrefix'
      break if tag.value != descriptor.stack_prefix

      stack_prefix_instances.push(id: i.instance_id, state: instance.state.name)
    end
  end
  stack_prefix_instances
end