wrap AwsHaRelease class in AwsMissingTools module
This commit is contained in:
parent
29aeb75ca3
commit
f6f07ec0fc
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
require 'aws-missing-tools'
|
require 'aws-missing-tools'
|
||||||
AwsHaRelease.new(ARGV.dup).execute!
|
AwsMissingTools::AwsHaRelease.new(ARGV.dup).execute!
|
||||||
|
|
|
@ -2,6 +2,5 @@ require 'aws-missing-tools/version'
|
||||||
|
|
||||||
module AwsMissingTools
|
module AwsMissingTools
|
||||||
require 'aws-sdk'
|
require 'aws-sdk'
|
||||||
|
|
||||||
require 'aws-missing-tools/aws-ha-release/aws-ha-release'
|
require 'aws-missing-tools/aws-ha-release/aws-ha-release'
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,165 +1,167 @@
|
||||||
require 'timeout'
|
require 'timeout'
|
||||||
require 'optparse'
|
require 'optparse'
|
||||||
|
|
||||||
class AwsHaRelease
|
module AwsMissingTools
|
||||||
attr_reader :group
|
class AwsHaRelease
|
||||||
|
attr_reader :group
|
||||||
|
|
||||||
def initialize(argv)
|
def initialize(argv)
|
||||||
@opts = AwsHaRelease.parse_options(argv)
|
@opts = AwsHaRelease.parse_options(argv)
|
||||||
|
|
||||||
AWS.config(access_key_id: @opts[:aws_access_key], secret_access_key: @opts[:aws_secret_key], region: @opts[:region])
|
AWS.config(access_key_id: @opts[:aws_access_key], secret_access_key: @opts[:aws_secret_key], region: @opts[:region])
|
||||||
|
|
||||||
@as = AWS::AutoScaling.new
|
@as = AWS::AutoScaling.new
|
||||||
@group = @as.groups[@opts[:as_group_name]]
|
@group = @as.groups[@opts[:as_group_name]]
|
||||||
|
|
||||||
if @group.nil?
|
if @group.nil?
|
||||||
raise ArgumentError, "The Auto Scaling Group named #{@opts[:as_group_name]} does not exist in #{@opts[:region]}."
|
raise ArgumentError, "The Auto Scaling Group named #{@opts[:as_group_name]} does not exist in #{@opts[:region]}."
|
||||||
|
end
|
||||||
|
|
||||||
|
@max_size_change = 0
|
||||||
|
@inservice_polling_time = 10
|
||||||
|
@processes_to_suspend = %w(ReplaceUnhealthy AlarmNotification ScheduledActions AZRebalance)
|
||||||
end
|
end
|
||||||
|
|
||||||
@max_size_change = 0
|
def self.parse_options(arguments)
|
||||||
@inservice_polling_time = 10
|
options = {
|
||||||
@processes_to_suspend = %w(ReplaceUnhealthy AlarmNotification ScheduledActions AZRebalance)
|
region: 'us-east-1',
|
||||||
end
|
elb_timeout: 60,
|
||||||
|
inservice_time_allowed: 300
|
||||||
|
}
|
||||||
|
|
||||||
def self.parse_options(arguments)
|
OptionParser.new do |opts|
|
||||||
options = {
|
opts.banner = 'Usage: aws-ha-release.rb -a <group name> [options]'
|
||||||
region: 'us-east-1',
|
|
||||||
elb_timeout: 60,
|
|
||||||
inservice_time_allowed: 300
|
|
||||||
}
|
|
||||||
|
|
||||||
OptionParser.new do |opts|
|
opts.on('-a', '--as-group-name GROUP_NAME', 'AutoScaling Group Name') do |v|
|
||||||
opts.banner = 'Usage: aws-ha-release.rb -a <group name> [options]'
|
options[:as_group_name] = v
|
||||||
|
end
|
||||||
|
|
||||||
opts.on('-a', '--as-group-name GROUP_NAME', 'AutoScaling Group Name') do |v|
|
opts.on('-r', '--region REGION', 'Region') do |v|
|
||||||
options[:as_group_name] = v
|
options[:region] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('-t', '--elb-timeout TIME', 'ELB Timeout (seconds)') do |v|
|
||||||
|
options[:elb_timeout] = v.to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('-i', '--inservice-time-allowed TIME', 'Time allowed for instance to come in service (seconds)') do |v|
|
||||||
|
options[:inservice_time_allowed] = v.to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('-o', '--aws_access_key AWS_ACCESS_KEY', 'AWS Access Key') do |v|
|
||||||
|
options[:aws_access_key] = v
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('-s', '--aws_secret_key AWS_SECRET_KEY', 'AWS Secret Key') do |v|
|
||||||
|
options[:aws_secret_key] = v
|
||||||
|
end
|
||||||
|
end.parse!(arguments)
|
||||||
|
|
||||||
|
raise OptionParser::MissingArgument, 'You must specify the AutoScaling Group Name: aws-ha-release.rb -a <group name>' if options[:as_group_name].nil?
|
||||||
|
|
||||||
|
if options[:aws_secret_key] && options[:aws_access_key].nil? || options[:aws_access_key] && options[:aws_secret_key].nil?
|
||||||
|
raise OptionParser::MissingArgument, 'If specifying either the AWS Access or Secret Key, then the other must also be specified. aws-ha-release.rb -a <group name> -o access_key -s secret_key'
|
||||||
|
elsif options[:aws_secret_key].nil? && options[:aws_access_key].nil?
|
||||||
|
options[:aws_access_key] = ENV['AWS_ACCESS_KEY']
|
||||||
|
options[:aws_secret_key] = ENV['AWS_SECRET_KEY']
|
||||||
end
|
end
|
||||||
|
|
||||||
opts.on('-r', '--region REGION', 'Region') do |v|
|
options
|
||||||
options[:region] = v
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on('-t', '--elb-timeout TIME', 'ELB Timeout (seconds)') do |v|
|
|
||||||
options[:elb_timeout] = v.to_i
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on('-i', '--inservice-time-allowed TIME', 'Time allowed for instance to come in service (seconds)') do |v|
|
|
||||||
options[:inservice_time_allowed] = v.to_i
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on('-o', '--aws_access_key AWS_ACCESS_KEY', 'AWS Access Key') do |v|
|
|
||||||
options[:aws_access_key] = v
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on('-s', '--aws_secret_key AWS_SECRET_KEY', 'AWS Secret Key') do |v|
|
|
||||||
options[:aws_secret_key] = v
|
|
||||||
end
|
|
||||||
end.parse!(arguments)
|
|
||||||
|
|
||||||
raise OptionParser::MissingArgument, 'You must specify the AutoScaling Group Name: aws-ha-release.rb -a <group name>' if options[:as_group_name].nil?
|
|
||||||
|
|
||||||
if options[:aws_secret_key] && options[:aws_access_key].nil? || options[:aws_access_key] && options[:aws_secret_key].nil?
|
|
||||||
raise OptionParser::MissingArgument, 'If specifying either the AWS Access or Secret Key, then the other must also be specified. aws-ha-release.rb -a <group name> -o access_key -s secret_key'
|
|
||||||
elsif options[:aws_secret_key].nil? && options[:aws_access_key].nil?
|
|
||||||
options[:aws_access_key] = ENV['AWS_ACCESS_KEY']
|
|
||||||
options[:aws_secret_key] = ENV['AWS_SECRET_KEY']
|
|
||||||
end
|
end
|
||||||
|
|
||||||
options
|
def execute!
|
||||||
end
|
%w(RemoveFromLoadBalancerLowPriority Terminate Launch HealthCheck AddToLoadBalancer).each do |process|
|
||||||
|
if @group.suspended_processes.keys.include? process
|
||||||
def execute!
|
raise "AutoScaling process #{process} is currently suspended on #{@group.name} but is necessary for this script."
|
||||||
%w(RemoveFromLoadBalancerLowPriority Terminate Launch HealthCheck AddToLoadBalancer).each do |process|
|
end
|
||||||
if @group.suspended_processes.keys.include? process
|
|
||||||
raise "AutoScaling process #{process} is currently suspended on #{@group.name} but is necessary for this script."
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
@group.suspend_processes @processes_to_suspend
|
@group.suspend_processes @processes_to_suspend
|
||||||
|
|
||||||
if @group.max_size == @group.desired_capacity
|
if @group.max_size == @group.desired_capacity
|
||||||
puts "#{@group.name} has a max-size of #{@group.max_size}. In order to recycle instances max-size will be temporarily increased by 1."
|
puts "#{@group.name} has a max-size of #{@group.max_size}. In order to recycle instances max-size will be temporarily increased by 1."
|
||||||
@group.update(max_size: @group.max_size + 1)
|
@group.update(max_size: @group.max_size + 1)
|
||||||
@max_size_change = 1
|
@max_size_change = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@group.update(desired_capacity: @group.desired_capacity + 1)
|
@group.update(desired_capacity: @group.desired_capacity + 1)
|
||||||
|
|
||||||
puts "The list of Instances in Auto Scaling Group #{@group.name} that will be terminated is:\n#{@group.ec2_instances.map(&:id)}"
|
puts "The list of Instances in Auto Scaling Group #{@group.name} that will be terminated is:\n#{@group.ec2_instances.map(&:id)}"
|
||||||
@group.ec2_instances.each do |instance|
|
@group.ec2_instances.each do |instance|
|
||||||
time_taken = 0
|
time_taken = 0
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Timeout::timeout(@opts[:inservice_time_allowed]) do
|
Timeout::timeout(@opts[:inservice_time_allowed]) do
|
||||||
|
|
||||||
until all_instances_inservice?(@group.load_balancers)
|
until all_instances_inservice?(@group.load_balancers)
|
||||||
puts "#{time_taken} seconds have elapsed while waiting for an Instance to reach InService status."
|
puts "#{time_taken} seconds have elapsed while waiting for an Instance to reach InService status."
|
||||||
|
|
||||||
time_taken += @inservice_polling_time
|
time_taken += @inservice_polling_time
|
||||||
sleep @inservice_polling_time
|
sleep @inservice_polling_time
|
||||||
|
end
|
||||||
|
|
||||||
|
deregister_instance instance, @group.load_balancers
|
||||||
|
sleep @opts[:elb_timeout]
|
||||||
|
|
||||||
|
puts "Instance #{instance.id} will now be terminated. By terminating this instance, the actual capacity will be decreased to 1 under desired-capacity."
|
||||||
|
instance.terminate false
|
||||||
|
end
|
||||||
|
rescue Timeout::Error => e
|
||||||
|
puts "\nDuring the last #{time_taken} seconds, a new AutoScaling instance failed to become healthy."
|
||||||
|
puts "The following settings were changed and will not be changed back by this script:\n"
|
||||||
|
|
||||||
|
puts "AutoScaling processes #{@processes_to_suspend} were suspended."
|
||||||
|
puts "The desired capacity was changed from #{@group.desired_capacity - 1} to #{@group.desired_capacity}."
|
||||||
|
|
||||||
|
if @max_size_change > 0
|
||||||
|
puts "The maximum size was changed from #{@group.max_size - @max_size_change} to #{@group.max_size}"
|
||||||
end
|
end
|
||||||
|
|
||||||
deregister_instance instance, @group.load_balancers
|
raise
|
||||||
sleep @opts[:elb_timeout]
|
|
||||||
|
|
||||||
puts "Instance #{instance.id} will now be terminated. By terminating this instance, the actual capacity will be decreased to 1 under desired-capacity."
|
|
||||||
instance.terminate false
|
|
||||||
end
|
end
|
||||||
rescue Timeout::Error => e
|
end
|
||||||
puts "\nDuring the last #{time_taken} seconds, a new AutoScaling instance failed to become healthy."
|
|
||||||
puts "The following settings were changed and will not be changed back by this script:\n"
|
|
||||||
|
|
||||||
puts "AutoScaling processes #{@processes_to_suspend} were suspended."
|
puts "#{@group.name} had its desired-capacity increased temporarily by 1 to a desired-capacity of #{@group.desired_capacity}."
|
||||||
puts "The desired capacity was changed from #{@group.desired_capacity - 1} to #{@group.desired_capacity}."
|
puts "$app_name will now return the desired-capacity of #{@group.name} to its original desired-capacity of #{@group.desired_capacity - 1}."
|
||||||
|
@group.update(desired_capacity: @group.desired_capacity - 1)
|
||||||
|
|
||||||
if @max_size_change > 0
|
if @max_size_change > 0
|
||||||
puts "The maximum size was changed from #{@group.max_size - @max_size_change} to #{@group.max_size}"
|
puts "\n#{@group.name} had its max_size increased temporarily by #{@max_size_change} to a max_size of #{@group.max_size}."
|
||||||
end
|
puts "The max_size of #{@group.name} will now be returned to its original max_size of #{@group.max_size - @max_size_change}."
|
||||||
|
|
||||||
raise
|
@group.update(max_size: @group.max_size - @max_size_change)
|
||||||
|
@max_size_change = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
@group.resume_all_processes
|
||||||
|
end
|
||||||
|
|
||||||
|
def deregister_instance(instance, load_balancers)
|
||||||
|
load_balancers.each do |load_balancer|
|
||||||
|
load_balancer.instances.deregister instance
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
puts "#{@group.name} had its desired-capacity increased temporarily by 1 to a desired-capacity of #{@group.desired_capacity}."
|
def instances_inservice?(load_balancer)
|
||||||
puts "$app_name will now return the desired-capacity of #{@group.name} to its original desired-capacity of #{@group.desired_capacity - 1}."
|
return false if load_balancer.instances.count != @group.desired_capacity
|
||||||
@group.update(desired_capacity: @group.desired_capacity - 1)
|
|
||||||
|
|
||||||
if @max_size_change > 0
|
load_balancer.instances.health.each do |instance_health|
|
||||||
puts "\n#{@group.name} had its max_size increased temporarily by #{@max_size_change} to a max_size of #{@group.max_size}."
|
unless instance_health[:state] == 'InService'
|
||||||
puts "The max_size of #{@group.name} will now be returned to its original max_size of #{@group.max_size - @max_size_change}."
|
puts "Instance #{instance_health[:instance].id} is currently #{instance_health[:state]} on load balancer #{load_balancer.name}."
|
||||||
|
|
||||||
@group.update(max_size: @group.max_size - @max_size_change)
|
return false
|
||||||
@max_size_change = 0
|
end
|
||||||
end
|
|
||||||
|
|
||||||
@group.resume_all_processes
|
|
||||||
end
|
|
||||||
|
|
||||||
def deregister_instance(instance, load_balancers)
|
|
||||||
load_balancers.each do |load_balancer|
|
|
||||||
load_balancer.instances.deregister instance
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def instances_inservice?(load_balancer)
|
|
||||||
return false if load_balancer.instances.count != @group.desired_capacity
|
|
||||||
|
|
||||||
load_balancer.instances.health.each do |instance_health|
|
|
||||||
unless instance_health[:state] == 'InService'
|
|
||||||
puts "Instance #{instance_health[:instance].id} is currently #{instance_health[:state]} on load balancer #{load_balancer.name}."
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
true
|
def all_instances_inservice?(load_balancers)
|
||||||
end
|
load_balancers.each do |load_balancer|
|
||||||
|
return false unless instances_inservice?(load_balancer)
|
||||||
|
end
|
||||||
|
|
||||||
def all_instances_inservice?(load_balancers)
|
true
|
||||||
load_balancers.each do |load_balancer|
|
|
||||||
return false unless instances_inservice?(load_balancer)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,26 +19,26 @@ describe 'aws-ha-release' do
|
||||||
as.groups.create opts[1]
|
as.groups.create opts[1]
|
||||||
|
|
||||||
AWS.should_receive(:config).with(access_key_id: 'testaccesskey', secret_access_key: 'testsecretkey', region: 'test_region')
|
AWS.should_receive(:config).with(access_key_id: 'testaccesskey', secret_access_key: 'testsecretkey', region: 'test_region')
|
||||||
AwsHaRelease.new(opts)
|
AwsMissingTools::AwsHaRelease.new(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'ensures the as group exists' do
|
it 'ensures the as group exists' do
|
||||||
lambda {
|
lambda {
|
||||||
opts[1] = 'fake_group'
|
opts[1] = 'fake_group'
|
||||||
AwsHaRelease.new(opts)
|
AwsMissingTools::AwsHaRelease.new(opts)
|
||||||
}.should raise_error
|
}.should raise_error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#parse_options' do
|
describe '#parse_options' do
|
||||||
it 'requires the autoscaling group name to be passed in' do
|
it 'requires the autoscaling group name to be passed in' do
|
||||||
expect{ AwsHaRelease.parse_options([]) }.to raise_error OptionParser::MissingArgument
|
expect{ AwsMissingTools::AwsHaRelease.parse_options([]) }.to raise_error OptionParser::MissingArgument
|
||||||
expect(AwsHaRelease.parse_options(%w(-a test_group))[:as_group_name]).to eq 'test_group'
|
expect(AwsMissingTools::AwsHaRelease.parse_options(%w(-a test_group))[:as_group_name]).to eq 'test_group'
|
||||||
expect(AwsHaRelease.parse_options(%w(--as-group-name test_group))[:as_group_name]).to eq 'test_group'
|
expect(AwsMissingTools::AwsHaRelease.parse_options(%w(--as-group-name test_group))[:as_group_name]).to eq 'test_group'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'sets default options' do
|
it 'sets default options' do
|
||||||
options = AwsHaRelease.parse_options(%w(-a test_group))
|
options = AwsMissingTools::AwsHaRelease.parse_options(%w(-a test_group))
|
||||||
expect(options[:elb_timeout]).not_to be_nil
|
expect(options[:elb_timeout]).not_to be_nil
|
||||||
expect(options[:region]).not_to be_nil
|
expect(options[:region]).not_to be_nil
|
||||||
expect(options[:inservice_time_allowed]).not_to be_nil
|
expect(options[:inservice_time_allowed]).not_to be_nil
|
||||||
|
@ -49,27 +49,27 @@ describe 'aws-ha-release' do
|
||||||
context 'optional params' do
|
context 'optional params' do
|
||||||
it 'ELB timeout' do
|
it 'ELB timeout' do
|
||||||
[%w(-a test_group -t 10), %w(-a test_group --elb-timeout 10)].each do |options|
|
[%w(-a test_group -t 10), %w(-a test_group --elb-timeout 10)].each do |options|
|
||||||
expect(AwsHaRelease.parse_options(options)[:elb_timeout]).to eq 10
|
expect(AwsMissingTools::AwsHaRelease.parse_options(options)[:elb_timeout]).to eq 10
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'region' do
|
it 'region' do
|
||||||
[%w(-a test_group -r test_region), %w(-a test_group --region test_region)].each do |options|
|
[%w(-a test_group -r test_region), %w(-a test_group --region test_region)].each do |options|
|
||||||
expect(AwsHaRelease.parse_options(options)[:region]).to eq 'test_region'
|
expect(AwsMissingTools::AwsHaRelease.parse_options(options)[:region]).to eq 'test_region'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'inservice time allowed' do
|
it 'inservice time allowed' do
|
||||||
[%w(-a test_group -i 300), %w(-a test_group --inservice-time-allowed 300)].each do |options|
|
[%w(-a test_group -i 300), %w(-a test_group --inservice-time-allowed 300)].each do |options|
|
||||||
expect(AwsHaRelease.parse_options(options)[:inservice_time_allowed]).to eq 300
|
expect(AwsMissingTools::AwsHaRelease.parse_options(options)[:inservice_time_allowed]).to eq 300
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'aws_access_key and aws_secret_key' do
|
it 'aws_access_key and aws_secret_key' do
|
||||||
expect{ AwsHaRelease.parse_options(%w(-a test_group -o testkey)) }.to raise_error OptionParser::MissingArgument
|
expect{ AwsMissingTools::AwsHaRelease.parse_options(%w(-a test_group -o testkey)) }.to raise_error OptionParser::MissingArgument
|
||||||
expect{ AwsHaRelease.parse_options(%w(-a test_group -s testsecretkey)) }.to raise_error OptionParser::MissingArgument
|
expect{ AwsMissingTools::AwsHaRelease.parse_options(%w(-a test_group -s testsecretkey)) }.to raise_error OptionParser::MissingArgument
|
||||||
|
|
||||||
options = AwsHaRelease.parse_options(%w(-a test_group -o testkey -s testsecretkey))
|
options = AwsMissingTools::AwsHaRelease.parse_options(%w(-a test_group -o testkey -s testsecretkey))
|
||||||
expect(options[:aws_access_key]).to eq 'testkey'
|
expect(options[:aws_access_key]).to eq 'testkey'
|
||||||
expect(options[:aws_secret_key]).to eq 'testsecretkey'
|
expect(options[:aws_secret_key]).to eq 'testsecretkey'
|
||||||
end
|
end
|
||||||
|
@ -79,7 +79,7 @@ describe 'aws-ha-release' do
|
||||||
describe '#execute!' do
|
describe '#execute!' do
|
||||||
before do
|
before do
|
||||||
@group = as.groups.create opts[1]
|
@group = as.groups.create opts[1]
|
||||||
@aws_ha_release = AwsHaRelease.new(opts)
|
@aws_ha_release = AwsMissingTools::AwsHaRelease.new(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'suspends certain autoscaling processes' do
|
it 'suspends certain autoscaling processes' do
|
||||||
|
@ -114,7 +114,7 @@ describe 'aws-ha-release' do
|
||||||
before do
|
before do
|
||||||
@group = as.groups.create opts[1]
|
@group = as.groups.create opts[1]
|
||||||
@group.update(desired_capacity: 2)
|
@group.update(desired_capacity: 2)
|
||||||
@aws_ha_release = AwsHaRelease.new(opts)
|
@aws_ha_release = AwsMissingTools::AwsHaRelease.new(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'checks all instances across a given load balancer' do
|
it 'checks all instances across a given load balancer' do
|
||||||
|
@ -194,7 +194,7 @@ describe 'aws-ha-release' do
|
||||||
describe '#deregister_instance' do
|
describe '#deregister_instance' do
|
||||||
before do
|
before do
|
||||||
@group = as.groups.create opts[1]
|
@group = as.groups.create opts[1]
|
||||||
@aws_ha_release = AwsHaRelease.new(opts)
|
@aws_ha_release = AwsMissingTools::AwsHaRelease.new(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'deregisters an instance across all load balancers' do
|
it 'deregisters an instance across all load balancers' do
|
||||||
|
|
Loading…
Reference in New Issue
Block a user