capistrano-asg-rolling 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef34189670d90583e896e138bb9d8de0647adcfbea6b9e9680de7de8d676bb77
4
- data.tar.gz: f33d46261711274cfec41257f2d627d50ffb4e8bbe6c01b8dbbb899a7655f246
3
+ metadata.gz: cceded2d7adcb767bc8bb432781055a91af8268303514564a4c1de86ccb2ac2e
4
+ data.tar.gz: 8d08579c0a00000bb2457348e9808758d10d74751a08f7071e50fa794fb1ea72
5
5
  SHA512:
6
- metadata.gz: 51334eff0a1cee5fe93b86da3e1494be9422ac9936bffbeaf3fa714a73618913593b688f602ee7edf29be6575a1ef4639901d707ad05448c5844cbdbd1d88deb
7
- data.tar.gz: e25f26ef2ca81085af106b2708c7b13038e247e43c5c036e5c5a750f91f16989a771ce726f2efce0c80e2a45eecc99e86f20aac388cd344ede587faf47c1cd94
6
+ metadata.gz: 964743e3ab4ad9813100f3968e45b044d80fc46d6e9141a85b07686b0b4566f8c12bb79f3614fa5d473b358782d3c002d03532f72b60440b666423c4bc5e4947
7
+ data.tar.gz: 3366b9a2268485d777a101d1f29335aba073979122347c48e3191f318188ed3ce41eb2f3ec39861b286fa4a0148f9632af23b1d57f93f4e1d857f8f742e929b8
@@ -9,7 +9,7 @@ jobs:
9
9
  runs-on: ubuntu-latest
10
10
  strategy:
11
11
  matrix:
12
- ruby-version: ['3.0', '3.1', '3.2', '3.3', '3.4']
12
+ ruby-version: ['3.1', '3.2', '3.3', '3.4', '4.0']
13
13
 
14
14
  steps:
15
15
  - uses: actions/checkout@v2
data/.rubocop.yml CHANGED
@@ -5,7 +5,7 @@ plugins:
5
5
 
6
6
  AllCops:
7
7
  NewCops: enable
8
- TargetRubyVersion: 3.0
8
+ TargetRubyVersion: 3.1
9
9
  DisplayCopNames: true
10
10
  DisplayStyleGuide: true
11
11
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- capistrano-asg-rolling (0.6.0)
4
+ capistrano-asg-rolling (0.7.0)
5
5
  aws-sdk-autoscaling (~> 1, >= 1.100.0)
6
6
  aws-sdk-ec2 (~> 1)
7
7
  capistrano (~> 3)
@@ -10,77 +10,80 @@ PATH
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
- addressable (2.8.7)
14
- public_suffix (>= 2.0.2, < 7.0)
15
- airbrussh (1.5.3)
13
+ addressable (2.8.8)
14
+ public_suffix (>= 2.0.2, < 8.0)
15
+ airbrussh (1.6.0)
16
16
  sshkit (>= 1.6.1, != 1.7.0)
17
- ast (2.4.2)
18
- aws-eventstream (1.3.2)
19
- aws-partitions (1.1066.0)
20
- aws-sdk-autoscaling (1.132.0)
21
- aws-sdk-core (~> 3, >= 3.216.0)
17
+ ast (2.4.3)
18
+ aws-eventstream (1.4.0)
19
+ aws-partitions (1.1198.0)
20
+ aws-sdk-autoscaling (1.149.0)
21
+ aws-sdk-core (~> 3, >= 3.239.1)
22
22
  aws-sigv4 (~> 1.5)
23
- aws-sdk-core (3.220.1)
23
+ aws-sdk-core (3.240.0)
24
24
  aws-eventstream (~> 1, >= 1.3.0)
25
25
  aws-partitions (~> 1, >= 1.992.0)
26
26
  aws-sigv4 (~> 1.9)
27
27
  base64
28
+ bigdecimal
28
29
  jmespath (~> 1, >= 1.6.1)
29
- aws-sdk-ec2 (1.512.0)
30
- aws-sdk-core (~> 3, >= 3.216.0)
30
+ logger
31
+ aws-sdk-ec2 (1.587.0)
32
+ aws-sdk-core (~> 3, >= 3.239.1)
31
33
  aws-sigv4 (~> 1.5)
32
- aws-sigv4 (1.11.0)
34
+ aws-sigv4 (1.12.1)
33
35
  aws-eventstream (~> 1, >= 1.0.2)
34
- base64 (0.2.0)
35
- bigdecimal (3.1.9)
36
- capistrano (3.19.2)
36
+ base64 (0.3.0)
37
+ bigdecimal (4.0.1)
38
+ capistrano (3.20.0)
37
39
  airbrussh (>= 1.0.0)
38
40
  i18n
39
41
  rake (>= 10.0.0)
40
42
  sshkit (>= 1.9.0)
41
- concurrent-ruby (1.3.5)
42
- crack (1.0.0)
43
+ concurrent-ruby (1.3.6)
44
+ crack (1.0.1)
43
45
  bigdecimal
44
46
  rexml
45
- diff-lcs (1.6.0)
46
- hashdiff (1.1.2)
47
- i18n (1.14.7)
47
+ diff-lcs (1.6.2)
48
+ hashdiff (1.2.1)
49
+ i18n (1.14.8)
48
50
  concurrent-ruby (~> 1.0)
49
51
  jmespath (1.6.2)
50
- json (2.10.2)
51
- language_server-protocol (3.17.0.4)
52
+ json (2.18.0)
53
+ language_server-protocol (3.17.0.5)
52
54
  lint_roller (1.1.0)
53
- logger (1.6.6)
55
+ logger (1.7.0)
54
56
  net-scp (4.1.0)
55
57
  net-ssh (>= 2.6.5, < 8.0.0)
56
58
  net-sftp (4.0.0)
57
59
  net-ssh (>= 5.0.0, < 8.0.0)
58
60
  net-ssh (7.3.0)
59
- ostruct (0.6.1)
60
- parallel (1.26.3)
61
- parser (3.3.7.1)
61
+ ostruct (0.6.3)
62
+ parallel (1.27.0)
63
+ parser (3.3.10.0)
62
64
  ast (~> 2.4.1)
63
65
  racc
64
- public_suffix (6.0.1)
66
+ prism (1.7.0)
67
+ public_suffix (6.0.2)
65
68
  racc (1.8.1)
66
69
  rainbow (3.1.1)
67
- rake (13.2.1)
68
- regexp_parser (2.10.0)
69
- rexml (3.4.1)
70
- rspec (3.13.0)
70
+ rake (13.3.1)
71
+ regexp_parser (2.11.3)
72
+ rexml (3.4.4)
73
+ rspec (3.13.2)
71
74
  rspec-core (~> 3.13.0)
72
75
  rspec-expectations (~> 3.13.0)
73
76
  rspec-mocks (~> 3.13.0)
74
- rspec-core (3.13.3)
77
+ rspec-core (3.13.6)
75
78
  rspec-support (~> 3.13.0)
76
- rspec-expectations (3.13.3)
79
+ rspec-expectations (3.13.5)
77
80
  diff-lcs (>= 1.2.0, < 2.0)
78
81
  rspec-support (~> 3.13.0)
79
- rspec-mocks (3.13.2)
82
+ rspec-mocks (3.13.7)
80
83
  diff-lcs (>= 1.2.0, < 2.0)
81
84
  rspec-support (~> 3.13.0)
82
- rspec-support (3.13.2)
83
- rubocop (1.74.0)
85
+ rspec-support (3.13.6)
86
+ rubocop (1.82.0)
84
87
  json (~> 2.3)
85
88
  language_server-protocol (~> 3.17.0.2)
86
89
  lint_roller (~> 1.1.0)
@@ -88,33 +91,34 @@ GEM
88
91
  parser (>= 3.3.0.2)
89
92
  rainbow (>= 2.2.2, < 4.0)
90
93
  regexp_parser (>= 2.9.3, < 3.0)
91
- rubocop-ast (>= 1.38.0, < 2.0)
94
+ rubocop-ast (>= 1.48.0, < 2.0)
92
95
  ruby-progressbar (~> 1.7)
93
96
  unicode-display_width (>= 2.4.0, < 4.0)
94
- rubocop-ast (1.38.1)
95
- parser (>= 3.3.1.0)
96
- rubocop-performance (1.24.0)
97
+ rubocop-ast (1.48.0)
98
+ parser (>= 3.3.7.2)
99
+ prism (~> 1.4)
100
+ rubocop-performance (1.26.1)
97
101
  lint_roller (~> 1.1)
98
- rubocop (>= 1.72.1, < 2.0)
99
- rubocop-ast (>= 1.38.0, < 2.0)
102
+ rubocop (>= 1.75.0, < 2.0)
103
+ rubocop-ast (>= 1.47.1, < 2.0)
100
104
  rubocop-rake (0.7.1)
101
105
  lint_roller (~> 1.1)
102
106
  rubocop (>= 1.72.1)
103
- rubocop-rspec (3.5.0)
107
+ rubocop-rspec (3.8.0)
104
108
  lint_roller (~> 1.1)
105
- rubocop (~> 1.72, >= 1.72.1)
109
+ rubocop (~> 1.81)
106
110
  ruby-progressbar (1.13.0)
107
- sshkit (1.24.0)
111
+ sshkit (1.25.0)
108
112
  base64
109
113
  logger
110
114
  net-scp (>= 1.1.2)
111
115
  net-sftp (>= 2.1.2)
112
116
  net-ssh (>= 2.8.0)
113
117
  ostruct
114
- unicode-display_width (3.1.4)
115
- unicode-emoji (~> 4.0, >= 4.0.4)
116
- unicode-emoji (4.0.4)
117
- webmock (3.25.1)
118
+ unicode-display_width (3.2.0)
119
+ unicode-emoji (~> 4.1)
120
+ unicode-emoji (4.2.0)
121
+ webmock (3.26.1)
118
122
  addressable (>= 2.8.0)
119
123
  crack (>= 0.3.2)
120
124
  hashdiff (>= 0.4.0, < 2.0.0)
@@ -134,4 +138,4 @@ DEPENDENCIES
134
138
  webmock (~> 3.11)
135
139
 
136
140
  BUNDLED WITH
137
- 2.3.7
141
+ 2.6.7
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/capistrano-asg-rolling.svg)](https://badge.fury.io/rb/capistrano-asg-rolling)
4
4
  [![Build Status](https://github.com/KentaaNL/capistrano-asg-rolling/actions/workflows/test.yml/badge.svg)](https://github.com/KentaaNL/capistrano-asg-rolling/actions)
5
- [![Code Climate](https://codeclimate.com/github/KentaaNL/capistrano-asg-rolling/badges/gpa.svg)](https://codeclimate.com/github/KentaaNL/capistrano-asg-rolling)
5
+ [![CodeQL](https://github.com/KentaaNL/capistrano-asg-rolling/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/KentaaNL/capistrano-asg-rolling/actions/workflows/github-code-scanning/codeql)
6
6
 
7
7
  Capistrano plugin for performing rolling updates to AWS Auto Scaling Groups using the [instance refresh feature](https://docs.aws.amazon.com/autoscaling/ec2/userguide/asg-instance-refresh.html).
8
8
 
@@ -181,6 +181,26 @@ autoscale 'web-autoscale-group', rolling: true, user: 'deployer'
181
181
 
182
182
  With these two stages, you can run any tasks with `cap production <task name>` and rolling deployments with `cap production_rolling deploy`.
183
183
 
184
+ ### Tags
185
+
186
+ During deployment, the following tags will be added to the AMI and snapshot containing information about the current application, stage and deployment:
187
+ - `capistrano-asg-rolling:application`
188
+ - `capistrano-asg-rolling:stage`
189
+ - `capistrano-asg-rolling:deployment-branch`
190
+ - `capistrano-asg-rolling:deployment-release`
191
+ - `capistrano-asg-rolling:deployment-revision`
192
+ - `capistrano-asg-rolling:deployment-user`
193
+
194
+ In addition to that, the tag `capistrano-asg-rolling:gem-version` will be added with the value of the current gem version.
195
+ This tag is also used to determine if the AMI was created by this gem, and can be deleted automatically.
196
+
197
+ You can add custom tag(s) to the AMI and snapshot by setting the property `asg_rolling_ami_tags`, for example:
198
+
199
+ ```ruby
200
+ # config/deploy/<stage>.rb
201
+ set :asg_rolling_ami_tags, { 'Application' => 'My Application', 'Environment' => 'Production' }
202
+ ```
203
+
184
204
  ## Useful commands
185
205
 
186
206
  ### Test deployment
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
27
  spec.require_paths = ['lib']
28
28
 
29
- spec.required_ruby_version = '>= 3.0.0'
29
+ spec.required_ruby_version = '>= 3.1.0'
30
30
 
31
31
  spec.add_development_dependency 'bundler', '~> 2.0'
32
32
  spec.add_development_dependency 'rake', '~> 13.0'
@@ -15,8 +15,8 @@ module Capistrano
15
15
  @groups << group
16
16
  end
17
17
 
18
- def each(&block)
19
- @groups.reject { |group| filtered?(group) }.each(&block)
18
+ def each(&)
19
+ @groups.reject { |group| filtered?(group) }.each(&)
20
20
  end
21
21
 
22
22
  def launch_templates
@@ -39,6 +39,13 @@ module Capistrano
39
39
  super('No instances have been launched. Are you using a configuration with rolling deployments?')
40
40
  end
41
41
  end
42
+
43
+ # Exception when waiting for SSH availability timed out.
44
+ class SSHAvailabilityTimeoutError < Capistrano::ASG::Rolling::Exception
45
+ def initialize(timeout)
46
+ super("Timed out waiting for SSH to become available after #{timeout} seconds")
47
+ end
48
+ end
42
49
  end
43
50
  end
44
51
  end
@@ -65,18 +65,6 @@ module Capistrano
65
65
  new(instance.instance_id, instance.private_ip_address, instance.public_ip_address, instance.image_id, autoscaling_group)
66
66
  end
67
67
 
68
- def wait_for_ssh
69
- started_at = Time.now
70
-
71
- loop do
72
- result = SSH.test?(ip_address, autoscale_group.properties[:user], Configuration.ssh_options)
73
-
74
- break if result || Time.now - started_at > 300
75
-
76
- sleep 1
77
- end
78
- end
79
-
80
68
  def ip_address
81
69
  Configuration.use_private_ip_address? ? private_ip_address : public_ip_address
82
70
  end
@@ -15,8 +15,8 @@ module Capistrano
15
15
  @instances << instance
16
16
  end
17
17
 
18
- def each(&block)
19
- instances.each(&block)
18
+ def each(&)
19
+ instances.each(&)
20
20
  end
21
21
 
22
22
  def empty?
@@ -31,10 +31,6 @@ module Capistrano
31
31
  self.class.new(select { |instance| instance.image_id == image_id })
32
32
  end
33
33
 
34
- def wait_for_ssh
35
- Parallel.run(instances, &:wait_for_ssh)
36
- end
37
-
38
34
  def stop
39
35
  Parallel.run(instances, &:stop)
40
36
  end
@@ -21,8 +21,8 @@ module Capistrano
21
21
  @templates.merge(templates)
22
22
  end
23
23
 
24
- def each(&block)
25
- @templates.each(&block)
24
+ def each(&)
25
+ @templates.each(&)
26
26
  end
27
27
 
28
28
  def empty?
@@ -29,6 +29,7 @@ module Capistrano
29
29
  after 'rolling:update', 'rolling:cleanup'
30
30
  after 'rolling:create_ami', 'rolling:cleanup'
31
31
  after 'rolling:update', 'rolling:instance_refresh_status'
32
+ after 'rolling:trigger_instance_refresh', 'rolling:instance_refresh_status'
32
33
 
33
34
  # Register an exit hook to do some cleanup when Capistrano
34
35
  # terminates without calling our after cleanup hook.
@@ -47,6 +48,16 @@ module Capistrano
47
48
  Capistrano::ASG::Rolling::Configuration
48
49
  end
49
50
 
51
+ # Add an instance to the Capistrano server list, with the given properties.
52
+ def add_instance(instance, properties)
53
+ server_properties = properties.merge(instance_id: instance.id)
54
+
55
+ logger.verbose "Adding server: **#{instance.ip_address}**"
56
+
57
+ server(instance.ip_address, server_properties)
58
+ end
59
+
60
+ # Make sure any instances that were launched for rolling updates are terminated.
50
61
  def cleanup
51
62
  instances = config.instances.auto_terminate
52
63
  return if instances.empty?
@@ -1,22 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'time'
4
+
3
5
  module Capistrano
4
6
  module ASG
5
7
  module Rolling
6
- # SSH availability test.
8
+ # Test the SSHKit backend for availability.
7
9
  module SSH
8
10
  module_function
9
11
 
10
- def test?(ip_address, user, ssh_options)
11
- options = ssh_options || {}
12
- options[:timeout] = 10
12
+ WAIT_TIMEOUT = 300
13
+
14
+ def wait_for_availability(backend)
15
+ timeout = WAIT_TIMEOUT
16
+ expires_at = Time.now + timeout
17
+
18
+ loop do
19
+ break if available?(backend)
20
+
21
+ raise SSHAvailabilityTimeoutError, timeout if Time.now > expires_at
13
22
 
14
- ::Net::SSH.start(ip_address, user, options) do |ssh|
15
- ssh.exec!('echo hello')
23
+ sleep 1
16
24
  end
25
+ end
26
+
27
+ def available?(backend)
28
+ backend.test('echo hello')
17
29
 
18
30
  true
19
- rescue ::Net::SSH::ConnectionTimeout, ::Net::SSH::Proxy::ConnectError, Errno::ECONNREFUSED, Errno::ETIMEDOUT
31
+ rescue ::Net::SSH::AuthenticationFailed, ::Net::SSH::Authentication::DisallowedMethod
32
+ # SSH server is reachable and responding.
33
+ true
34
+ rescue ::Net::SSH::ConnectionTimeout, ::Net::SSH::Proxy::ConnectError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ETIMEDOUT, Errno::ECONNRESET
35
+ # SSH server not reachable or port closed.
36
+ false
37
+ rescue ::Net::SSH::Disconnect # rubocop:disable Lint/DuplicateBranch
38
+ # SSH server is reachable, but the connection dropped unexpectedly.
20
39
  false
21
40
  end
22
41
  end
@@ -3,7 +3,7 @@
3
3
  module Capistrano
4
4
  module ASG
5
5
  module Rolling
6
- VERSION = '0.6.0'
6
+ VERSION = '0.7.0'
7
7
  end
8
8
  end
9
9
  end
@@ -14,10 +14,7 @@ namespace :rolling do
14
14
  logger.info "Launched Instance: **#{instance.id}**"
15
15
  config.instances << instance
16
16
 
17
- logger.verbose "Adding server: **#{instance.ip_address}**"
18
-
19
- # Add server to the Capistrano server list.
20
- server(instance.ip_address, group.properties)
17
+ add_instance(instance, group.properties)
21
18
  else
22
19
  logger.info "Auto Scaling Group: **#{group.name}**, standard deployment strategy."
23
20
 
@@ -29,17 +26,17 @@ namespace :rolling do
29
26
  server_properties = group.properties
30
27
  end
31
28
 
32
- logger.verbose "Adding server: **#{instance.ip_address}**"
33
-
34
- # Add server to the Capistrano server list.
35
- server(instance.ip_address, server_properties)
29
+ add_instance(instance, server_properties)
36
30
  end
37
31
  end
38
32
  end
39
33
 
40
34
  unless config.instances.empty?
41
35
  logger.info 'Waiting for SSH to be available...'
42
- config.instances.wait_for_ssh
36
+
37
+ on roles(:all) do
38
+ Capistrano::ASG::Rolling::SSH.wait_for_availability(self)
39
+ end
43
40
  end
44
41
  end
45
42
 
@@ -71,6 +68,17 @@ namespace :rolling do
71
68
  end
72
69
  end
73
70
 
71
+ desc 'Trigger instance refresh of deployed autoscaling groups'
72
+ task :trigger_instance_refresh do
73
+ logger.info 'Triggering Instance Refresh on Auto Scaling Group(s)...'
74
+ config.autoscale_groups.each do |group|
75
+ group.start_instance_refresh(group.launch_template)
76
+ logger.info "Successfully started Instance Refresh on Auto Scaling Group **#{group.name}**."
77
+ rescue Capistrano::ASG::Rolling::StartInstanceRefreshError => e
78
+ logger.info "Failed to start Instance Refresh on Auto Scaling Group **#{group.name}**: #{e.message}"
79
+ end
80
+ end
81
+
74
82
  desc 'Clean up old Launch Template versions and AMIs and terminate instances'
75
83
  task :cleanup do
76
84
  unless config.launch_templates.empty?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano-asg-rolling
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kentaa
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-03-14 00:00:00.000000000 Z
11
+ date: 2025-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -181,14 +181,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
181
181
  requirements:
182
182
  - - ">="
183
183
  - !ruby/object:Gem::Version
184
- version: 3.0.0
184
+ version: 3.1.0
185
185
  required_rubygems_version: !ruby/object:Gem::Requirement
186
186
  requirements:
187
187
  - - ">="
188
188
  - !ruby/object:Gem::Version
189
189
  version: '0'
190
190
  requirements: []
191
- rubygems_version: 3.2.33
191
+ rubygems_version: 3.3.27
192
192
  signing_key:
193
193
  specification_version: 4
194
194
  summary: Capistrano plugin for performing rolling updates to AWS Auto Scaling Groups