From 875b25284f9289e9e6ea1a43c67c7fa7c8dd21ca Mon Sep 17 00:00:00 2001 From: Peter Postma Date: Fri, 22 Dec 2023 13:49:11 +0100 Subject: [PATCH] Don't set a default minimum healthy percentage of 100% anymore, so either the default of 90% will be used, or the percentage set in the instance maintenance policy for the ASG. Introduce the properties `min_healthy_percentage` and `max_healthy_percentage` on the autoscale definitions for tuning these settings. The property `healthy_percentage` is still supported but will give a deprecation warning, and will be removed somewhere in the future. Gem `aws-sdk-autoscaling` >= 1.100.0 is now required to support setting the maximum healthy percentage. --- .rubocop.yml | 3 ++ Gemfile.lock | 2 +- capistrano-asg-rolling.gemspec | 2 +- lib/capistrano/asg/rolling/autoscale_group.rb | 21 ++++++++--- .../asg/rolling/autoscale_group_spec.rb | 36 ++++++++++++++++--- 5 files changed, 52 insertions(+), 12 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 141a643..5173c63 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -38,3 +38,6 @@ RSpec/IndexedLet: RSpec/MultipleExpectations: Max: 5 + +Style/GuardClause: + Enabled: false diff --git a/Gemfile.lock b/Gemfile.lock index 70caea1..c8aea05 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,7 +2,7 @@ PATH remote: . specs: capistrano-asg-rolling (0.4.1) - aws-sdk-autoscaling (~> 1, >= 1.67.0) + aws-sdk-autoscaling (~> 1, >= 1.100.0) aws-sdk-ec2 (~> 1) capistrano (~> 3) concurrent-ruby (~> 1) diff --git a/capistrano-asg-rolling.gemspec b/capistrano-asg-rolling.gemspec index 8da3fb0..66670a9 100644 --- a/capistrano-asg-rolling.gemspec +++ b/capistrano-asg-rolling.gemspec @@ -33,7 +33,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'rspec', '~> 3.0' spec.add_development_dependency 'webmock', '~> 3.11' - spec.add_dependency 'aws-sdk-autoscaling', '~> 1', '>= 1.67.0' + spec.add_dependency 'aws-sdk-autoscaling', '~> 1', '>= 1.100.0' spec.add_dependency 'aws-sdk-ec2', '~> 1' spec.add_dependency 'capistrano', '~> 3' spec.add_dependency 'concurrent-ruby', '~> 1' diff --git a/lib/capistrano/asg/rolling/autoscale_group.rb b/lib/capistrano/asg/rolling/autoscale_group.rb index c8a91ca..33169a5 100644 --- a/lib/capistrano/asg/rolling/autoscale_group.rb +++ b/lib/capistrano/asg/rolling/autoscale_group.rb @@ -19,6 +19,12 @@ class AutoscaleGroup def initialize(name, properties = {}) @name = name @properties = properties + + if properties[:healthy_percentage] + properties[:min_healthy_percentage] = properties.delete(:healthy_percentage) + + Kernel.warn('WARNING: the property `healthy_percentage` is deprecated and will be removed in a future release. Please update to `min_healthy_percentage`.') + end end def exists? @@ -42,8 +48,12 @@ def instance_warmup_time aws_autoscaling_group.health_check_grace_period end - def healthy_percentage - properties.fetch(:healthy_percentage, 100) + def min_healthy_percentage + properties.fetch(:min_healthy_percentage, nil) + end + + def max_healthy_percentage + properties.fetch(:max_healthy_percentage, nil) end def start_instance_refresh(launch_template) @@ -58,9 +68,10 @@ def start_instance_refresh(launch_template) }, preferences: { instance_warmup: instance_warmup_time, - min_healthy_percentage: healthy_percentage, - skip_matching: true - } + skip_matching: true, + min_healthy_percentage: min_healthy_percentage, + max_healthy_percentage: max_healthy_percentage + }.compact ).instance_refresh_id rescue Aws::AutoScaling::Errors::InstanceRefreshInProgress => e raise Capistrano::ASG::Rolling::InstanceRefreshFailed, e diff --git a/spec/capistrano/asg/rolling/autoscale_group_spec.rb b/spec/capistrano/asg/rolling/autoscale_group_spec.rb index f887d43..22e9f1b 100644 --- a/spec/capistrano/asg/rolling/autoscale_group_spec.rb +++ b/spec/capistrano/asg/rolling/autoscale_group_spec.rb @@ -63,18 +63,34 @@ end end - describe '#healthy_percentage' do + describe '#min_healthy_percentage' do context 'when no value is set' do - it 'returns the default healthy percentage (100)' do - expect(group.healthy_percentage).to eq(100) + it 'returns nil' do + expect(group.min_healthy_percentage).to be_nil end end context 'when a value is set' do - subject(:group) { described_class.new('test-asg', healthy_percentage: 50) } + subject(:group) { described_class.new('test-asg', min_healthy_percentage: 50) } it 'returns the value set in the configuration (50)' do - expect(group.healthy_percentage).to eq(50) + expect(group.min_healthy_percentage).to eq(50) + end + end + end + + describe '#max_healthy_percentage' do + context 'when no value is set' do + it 'returns nil' do + expect(group.max_healthy_percentage).to be_nil + end + end + + context 'when a value is set' do + subject(:group) { described_class.new('test-asg', max_healthy_percentage: 110) } + + it 'returns the value set in the configuration (110)' do + expect(group.max_healthy_percentage).to eq(110) end end end @@ -108,6 +124,16 @@ expect { group.start_instance_refresh(template) }.to raise_error(Capistrano::ASG::Rolling::InstanceRefreshFailed, 'An Instance Refresh is already in progress and blocks the execution of this Instance Refresh.') end end + + context 'when min and max healthy percentage is set' do + subject(:group) { described_class.new('test-asg', min_healthy_percentage: 50, max_healthy_percentage: 110) } + + it 'calls the API to start instance refresh with the given healthy percentages' do + group.start_instance_refresh(template) + expect(WebMock).to have_requested(:post, /amazonaws.com/) + .with(body: /Action=StartInstanceRefresh&AutoScalingGroupName=test-asg&DesiredConfiguration.LaunchTemplate.LaunchTemplateId=lt-1234567890&DesiredConfiguration.LaunchTemplate.Version=1&Preferences.InstanceWarmup=300&Preferences.MaxHealthyPercentage=110&Preferences.MinHealthyPercentage=50&Preferences.SkipMatching=true&Strategy=Rolling/).once + end + end end describe '#instances' do