capistrano-asg-rolling 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +4 -2
- data/Gemfile +3 -3
- data/Gemfile.lock +34 -34
- data/README.md +4 -12
- data/capistrano-asg-rolling.gemspec +4 -2
- data/lib/capistrano/asg/rolling/ami.rb +24 -6
- data/lib/capistrano/asg/rolling/autoscale_group.rb +12 -3
- data/lib/capistrano/asg/rolling/autoscale_groups.rb +5 -34
- data/lib/capistrano/asg/rolling/aws.rb +5 -1
- data/lib/capistrano/asg/rolling/configuration.rb +5 -3
- data/lib/capistrano/asg/rolling/exception.rb +3 -0
- data/lib/capistrano/asg/rolling/instance.rb +18 -6
- data/lib/capistrano/asg/rolling/instances.rb +2 -2
- data/lib/capistrano/asg/rolling/launch_template.rb +5 -4
- data/lib/capistrano/asg/rolling/launch_templates.rb +55 -0
- data/lib/capistrano/asg/rolling/logger.rb +10 -9
- data/lib/capistrano/asg/rolling/plugin.rb +0 -4
- data/lib/capistrano/asg/rolling/version.rb +1 -1
- data/lib/capistrano/asg/rolling.rb +1 -0
- data/lib/capistrano/asg/tasks/rolling.rake +32 -12
- metadata +10 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 140ff8c2812256ee7b0db1c2675052859dd933593d6f3766adf68e855c2297b5
|
4
|
+
data.tar.gz: 76ba60506093dac285def220cb11c8f114140c525d3c65644e5d6af983edaaaf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85c502bd99f24aea1dd05fc2a499dbc3aec81be2b951dd9be3c056d1527ba51bf0d605eca6b3ab40ece1f3a7d559f400cafb50ca5884567d214c665fd7e50057
|
7
|
+
data.tar.gz: bd945c98f2dc32c63e7fac3df0a82ea9ab7a75b2cc2caeab6b24d640bd7af9bfe79c1f6f863f467a42f14d7043f18775667706cae4631552d7199a45a55b6edc
|
data/.github/workflows/test.yml
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
name: CI
|
2
2
|
|
3
|
-
on:
|
3
|
+
on:
|
4
|
+
- push
|
5
|
+
- pull_request
|
4
6
|
|
5
7
|
jobs:
|
6
8
|
test:
|
7
9
|
runs-on: ubuntu-latest
|
8
10
|
strategy:
|
9
11
|
matrix:
|
10
|
-
ruby-version: ['2.5', '2.6', '2.7', '3.0']
|
12
|
+
ruby-version: ['2.5', '2.6', '2.7', '3.0', '3.1']
|
11
13
|
|
12
14
|
steps:
|
13
15
|
- uses: actions/checkout@v2
|
data/Gemfile
CHANGED
@@ -7,7 +7,7 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
|
7
7
|
# Specify your gem's dependencies in capistrano-asg-rolling.gemspec
|
8
8
|
gemspec
|
9
9
|
|
10
|
-
gem 'rubocop', '~> 1.
|
11
|
-
gem 'rubocop-performance', '~> 1.
|
10
|
+
gem 'rubocop', '~> 1.26.1'
|
11
|
+
gem 'rubocop-performance', '~> 1.13.3'
|
12
12
|
gem 'rubocop-rake', '~> 0.6.0'
|
13
|
-
gem 'rubocop-rspec', '~> 2.
|
13
|
+
gem 'rubocop-rspec', '~> 2.9.0'
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
capistrano-asg-rolling (0.
|
5
|
-
aws-sdk-autoscaling (~> 1, >= 1.
|
4
|
+
capistrano-asg-rolling (0.2.0)
|
5
|
+
aws-sdk-autoscaling (~> 1, >= 1.67.0)
|
6
6
|
aws-sdk-ec2 (~> 1)
|
7
7
|
capistrano (~> 3)
|
8
8
|
concurrent-ruby (~> 1)
|
@@ -16,74 +16,74 @@ GEM
|
|
16
16
|
sshkit (>= 1.6.1, != 1.7.0)
|
17
17
|
ast (2.4.2)
|
18
18
|
aws-eventstream (1.2.0)
|
19
|
-
aws-partitions (1.
|
20
|
-
aws-sdk-autoscaling (1.
|
21
|
-
aws-sdk-core (~> 3, >= 3.
|
19
|
+
aws-partitions (1.570.0)
|
20
|
+
aws-sdk-autoscaling (1.78.0)
|
21
|
+
aws-sdk-core (~> 3, >= 3.127.0)
|
22
22
|
aws-sigv4 (~> 1.1)
|
23
|
-
aws-sdk-core (3.
|
23
|
+
aws-sdk-core (3.130.0)
|
24
24
|
aws-eventstream (~> 1, >= 1.0.2)
|
25
|
-
aws-partitions (~> 1, >= 1.
|
25
|
+
aws-partitions (~> 1, >= 1.525.0)
|
26
26
|
aws-sigv4 (~> 1.1)
|
27
27
|
jmespath (~> 1.0)
|
28
|
-
aws-sdk-ec2 (1.
|
29
|
-
aws-sdk-core (~> 3, >= 3.
|
28
|
+
aws-sdk-ec2 (1.303.0)
|
29
|
+
aws-sdk-core (~> 3, >= 3.127.0)
|
30
30
|
aws-sigv4 (~> 1.1)
|
31
31
|
aws-sigv4 (1.4.0)
|
32
32
|
aws-eventstream (~> 1, >= 1.0.2)
|
33
|
-
capistrano (3.
|
33
|
+
capistrano (3.17.0)
|
34
34
|
airbrussh (>= 1.0.0)
|
35
35
|
i18n
|
36
36
|
rake (>= 10.0.0)
|
37
37
|
sshkit (>= 1.9.0)
|
38
|
-
concurrent-ruby (1.1.
|
38
|
+
concurrent-ruby (1.1.10)
|
39
39
|
crack (0.4.5)
|
40
40
|
rexml
|
41
|
-
diff-lcs (1.
|
41
|
+
diff-lcs (1.5.0)
|
42
42
|
hashdiff (1.0.1)
|
43
|
-
i18n (1.
|
43
|
+
i18n (1.10.0)
|
44
44
|
concurrent-ruby (~> 1.0)
|
45
|
-
jmespath (1.
|
45
|
+
jmespath (1.6.1)
|
46
46
|
net-scp (3.0.0)
|
47
47
|
net-ssh (>= 2.6.5, < 7.0.0)
|
48
48
|
net-ssh (6.1.0)
|
49
|
-
parallel (1.
|
50
|
-
parser (3.
|
49
|
+
parallel (1.22.0)
|
50
|
+
parser (3.1.1.0)
|
51
51
|
ast (~> 2.4.1)
|
52
52
|
public_suffix (4.0.6)
|
53
|
-
rainbow (3.
|
53
|
+
rainbow (3.1.1)
|
54
54
|
rake (13.0.6)
|
55
|
-
regexp_parser (2.
|
55
|
+
regexp_parser (2.2.1)
|
56
56
|
rexml (3.2.5)
|
57
57
|
rspec (3.10.0)
|
58
58
|
rspec-core (~> 3.10.0)
|
59
59
|
rspec-expectations (~> 3.10.0)
|
60
60
|
rspec-mocks (~> 3.10.0)
|
61
|
-
rspec-core (3.10.
|
61
|
+
rspec-core (3.10.2)
|
62
62
|
rspec-support (~> 3.10.0)
|
63
|
-
rspec-expectations (3.10.
|
63
|
+
rspec-expectations (3.10.2)
|
64
64
|
diff-lcs (>= 1.2.0, < 2.0)
|
65
65
|
rspec-support (~> 3.10.0)
|
66
|
-
rspec-mocks (3.10.
|
66
|
+
rspec-mocks (3.10.3)
|
67
67
|
diff-lcs (>= 1.2.0, < 2.0)
|
68
68
|
rspec-support (~> 3.10.0)
|
69
|
-
rspec-support (3.10.
|
70
|
-
rubocop (1.
|
69
|
+
rspec-support (3.10.3)
|
70
|
+
rubocop (1.26.1)
|
71
71
|
parallel (~> 1.10)
|
72
|
-
parser (>= 3.
|
72
|
+
parser (>= 3.1.0.0)
|
73
73
|
rainbow (>= 2.2.2, < 4.0)
|
74
74
|
regexp_parser (>= 1.8, < 3.0)
|
75
75
|
rexml
|
76
|
-
rubocop-ast (>= 1.
|
76
|
+
rubocop-ast (>= 1.16.0, < 2.0)
|
77
77
|
ruby-progressbar (~> 1.7)
|
78
78
|
unicode-display_width (>= 1.4.0, < 3.0)
|
79
|
-
rubocop-ast (1.
|
80
|
-
parser (>= 3.
|
81
|
-
rubocop-performance (1.
|
79
|
+
rubocop-ast (1.16.0)
|
80
|
+
parser (>= 3.1.1.0)
|
81
|
+
rubocop-performance (1.13.3)
|
82
82
|
rubocop (>= 1.7.0, < 2.0)
|
83
83
|
rubocop-ast (>= 0.4.0)
|
84
84
|
rubocop-rake (0.6.0)
|
85
85
|
rubocop (~> 1.0)
|
86
|
-
rubocop-rspec (2.
|
86
|
+
rubocop-rspec (2.9.0)
|
87
87
|
rubocop (~> 1.19)
|
88
88
|
ruby-progressbar (1.11.0)
|
89
89
|
sshkit (1.21.2)
|
@@ -99,15 +99,15 @@ PLATFORMS
|
|
99
99
|
ruby
|
100
100
|
|
101
101
|
DEPENDENCIES
|
102
|
-
bundler (~>
|
102
|
+
bundler (~> 2.0)
|
103
103
|
capistrano-asg-rolling!
|
104
104
|
rake (~> 13.0)
|
105
105
|
rspec (~> 3.0)
|
106
|
-
rubocop (~> 1.
|
107
|
-
rubocop-performance (~> 1.
|
106
|
+
rubocop (~> 1.26.1)
|
107
|
+
rubocop-performance (~> 1.13.3)
|
108
108
|
rubocop-rake (~> 0.6.0)
|
109
|
-
rubocop-rspec (~> 2.
|
109
|
+
rubocop-rspec (~> 2.9.0)
|
110
110
|
webmock (~> 3.11)
|
111
111
|
|
112
112
|
BUNDLED WITH
|
113
|
-
|
113
|
+
2.3.7
|
data/README.md
CHANGED
@@ -11,8 +11,8 @@ Instead of deploying to live servers, capistrano-asg-rolling will create a tempo
|
|
11
11
|
- Launch an instance from the AMI defined in the Launch Template of the Auto Scaling Group(s).
|
12
12
|
- Deploy your application to the launched instances.
|
13
13
|
- After deployment, stop the instances and create an AMI for each instance.
|
14
|
-
- Create new Launch Template versions
|
15
|
-
- Trigger Instance Refresh on the Auto Scaling Group(s) to perform
|
14
|
+
- Create new Launch Template versions for the new AMIs.
|
15
|
+
- Trigger Instance Refresh on the Auto Scaling Group(s) to perform a rolling update.
|
16
16
|
- Delete any outdated Launch Template versions, AMIs and snapshots created by previous deployments.
|
17
17
|
- Terminate the no longer needed instances.
|
18
18
|
|
@@ -26,7 +26,7 @@ Please be aware of the limitations of using instance refresh, in particular "Ins
|
|
26
26
|
|
27
27
|
This gem depends on Auto Scaling Groups with Launch Templates. Using an Auto Scaling Group with a Launch Configuration is not supported, and will raise an `Capistrano::ASG::Rolling::NoLaunchTemplate`.
|
28
28
|
|
29
|
-
|
29
|
+
Instance refresh uses the desired configuration to update the Launch Template version of the Auto Scaling Group after a succesful deployment. Setting the Launch Template version to `Latest` on the Auto Scaling Group is not needed.
|
30
30
|
|
31
31
|
#### Experimental
|
32
32
|
|
@@ -36,14 +36,6 @@ The configuration options are not considered stable and might be changed or remo
|
|
36
36
|
|
37
37
|
The gem could have a better / fancier name.
|
38
38
|
|
39
|
-
#### Bugs
|
40
|
-
|
41
|
-
Currently all Launch Template versions and AMIs will be deleted, also when not created by this gem.
|
42
|
-
|
43
|
-
When an Instance refresh is already in progress, the deployment will fail with an `Aws::AutoScaling::Errors::InstanceRefreshInProgress`.
|
44
|
-
|
45
|
-
Documentation is incomplete.
|
46
|
-
|
47
39
|
## Installation
|
48
40
|
|
49
41
|
Add this line to your application's Gemfile:
|
@@ -123,7 +115,7 @@ Now start a deployment with `cap <stage> deploy` and enjoy.
|
|
123
115
|
|
124
116
|
### Deploy without rolling update
|
125
117
|
|
126
|
-
There might be cases where you just want to deploy your code to the servers in the Auto Scaling Group(s) without a rolling update.
|
118
|
+
There might be cases where you just want to deploy your code to the servers in the Auto Scaling Group(s) without a rolling update.
|
127
119
|
|
128
120
|
You can configure rolling updates per autoscaling group by using the `rolling` option:
|
129
121
|
|
@@ -14,6 +14,8 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.homepage = 'https://github.com/KentaaNL/capistrano-asg-rolling'
|
15
15
|
spec.license = 'MIT'
|
16
16
|
|
17
|
+
spec.metadata = { 'rubygems_mfa_required' => 'true' }
|
18
|
+
|
17
19
|
# Specify which files should be added to the gem when it is released.
|
18
20
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
19
21
|
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
@@ -26,12 +28,12 @@ Gem::Specification.new do |spec|
|
|
26
28
|
|
27
29
|
spec.required_ruby_version = '>= 2.5.0'
|
28
30
|
|
29
|
-
spec.add_development_dependency 'bundler', '~>
|
31
|
+
spec.add_development_dependency 'bundler', '~> 2.0'
|
30
32
|
spec.add_development_dependency 'rake', '~> 13.0'
|
31
33
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
32
34
|
spec.add_development_dependency 'webmock', '~> 3.11'
|
33
35
|
|
34
|
-
spec.add_dependency 'aws-sdk-autoscaling', '~> 1', '>= 1.
|
36
|
+
spec.add_dependency 'aws-sdk-autoscaling', '~> 1', '>= 1.67.0'
|
35
37
|
spec.add_dependency 'aws-sdk-ec2', '~> 1'
|
36
38
|
spec.add_dependency 'capistrano', '~> 3'
|
37
39
|
spec.add_dependency 'concurrent-ruby', '~> 1'
|
@@ -25,12 +25,12 @@ module Capistrano
|
|
25
25
|
}
|
26
26
|
|
27
27
|
if tags
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
tag_specifications = tags.map { |key, value| { key: key, value: value } }
|
29
|
+
|
30
|
+
options[:tag_specifications] = [
|
31
|
+
{ resource_type: 'image', tags: tag_specifications },
|
32
|
+
{ resource_type: 'snapshot', tags: tag_specifications }
|
33
|
+
]
|
34
34
|
end
|
35
35
|
|
36
36
|
response = aws_ec2_client.create_image(options)
|
@@ -65,6 +65,24 @@ module Capistrano
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
+
def tags
|
69
|
+
@tags ||= aws_ec2_image.tags.map { |tag| [tag.key, tag.value] }.to_h
|
70
|
+
end
|
71
|
+
|
72
|
+
def tag?(key)
|
73
|
+
tags.key?(key)
|
74
|
+
end
|
75
|
+
|
76
|
+
def ==(other)
|
77
|
+
id == other.id
|
78
|
+
end
|
79
|
+
|
80
|
+
alias eql? ==
|
81
|
+
|
82
|
+
def hash
|
83
|
+
id.hash
|
84
|
+
end
|
85
|
+
|
68
86
|
private
|
69
87
|
|
70
88
|
def aws_ec2_image
|
@@ -28,7 +28,7 @@ module Capistrano
|
|
28
28
|
template = aws_autoscaling_group.launch_template
|
29
29
|
raise Capistrano::ASG::Rolling::NoLaunchTemplate if template.nil?
|
30
30
|
|
31
|
-
LaunchTemplate.new(template.launch_template_id, template.version)
|
31
|
+
LaunchTemplate.new(template.launch_template_id, template.version, template.launch_template_name)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
@@ -40,15 +40,24 @@ module Capistrano
|
|
40
40
|
aws_autoscaling_group.health_check_grace_period
|
41
41
|
end
|
42
42
|
|
43
|
-
def start_instance_refresh
|
43
|
+
def start_instance_refresh(launch_template)
|
44
44
|
aws_autoscaling_client.start_instance_refresh(
|
45
45
|
auto_scaling_group_name: name,
|
46
46
|
strategy: 'Rolling',
|
47
|
+
desired_configuration: {
|
48
|
+
launch_template: {
|
49
|
+
launch_template_id: launch_template.id,
|
50
|
+
version: launch_template.version
|
51
|
+
}
|
52
|
+
},
|
47
53
|
preferences: {
|
48
54
|
instance_warmup: instance_warmup_time,
|
49
|
-
min_healthy_percentage: 100
|
55
|
+
min_healthy_percentage: 100,
|
56
|
+
skip_matching: true
|
50
57
|
}
|
51
58
|
)
|
59
|
+
rescue Aws::AutoScaling::Errors::InstanceRefreshInProgress => e
|
60
|
+
raise Capistrano::ASG::Rolling::InstanceRefreshFailed, e
|
52
61
|
end
|
53
62
|
|
54
63
|
# Returns instances with lifecycle state "InService" for this Auto Scaling Group.
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'set'
|
4
|
-
|
5
3
|
module Capistrano
|
6
4
|
module ASG
|
7
5
|
module Rolling
|
@@ -21,27 +19,13 @@ module Capistrano
|
|
21
19
|
@groups.reject { |group| filtered?(group) }.each(&block)
|
22
20
|
end
|
23
21
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
def update_launch_templates(amis:, description: nil)
|
29
|
-
launch_templates = Set.new
|
30
|
-
|
31
|
-
amis.each do |ami|
|
32
|
-
old_image_id = ami.instance.image_id
|
33
|
-
new_image_id = ami.id
|
34
|
-
|
35
|
-
find_launch_templates_for(image_id: old_image_id).each do |launch_template|
|
36
|
-
launch_templates << launch_template.create_version(image_id: new_image_id, description: description)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
launch_templates
|
22
|
+
def launch_templates
|
23
|
+
templates = @groups.map(&:launch_template)
|
24
|
+
LaunchTemplates.new(templates)
|
41
25
|
end
|
42
26
|
|
43
|
-
def
|
44
|
-
|
27
|
+
def with_launch_template(launch_template)
|
28
|
+
self.class.new(select { |group| group.launch_template == launch_template })
|
45
29
|
end
|
46
30
|
|
47
31
|
private
|
@@ -51,19 +35,6 @@ module Capistrano
|
|
51
35
|
|
52
36
|
Configuration.auto_scaling_group_name != group.name
|
53
37
|
end
|
54
|
-
|
55
|
-
def find_launch_templates_for(image_id:)
|
56
|
-
launch_templates = Set.new
|
57
|
-
|
58
|
-
each do |group|
|
59
|
-
launch_template = group.launch_template
|
60
|
-
next if launch_template.image_id != image_id
|
61
|
-
|
62
|
-
launch_templates << launch_template
|
63
|
-
end
|
64
|
-
|
65
|
-
launch_templates
|
66
|
-
end
|
67
38
|
end
|
68
39
|
end
|
69
40
|
end
|
@@ -27,7 +27,7 @@ module Capistrano
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def aws_credentials
|
30
|
-
::Aws::Credentials.new(aws_access_key_id, aws_secret_access_key)
|
30
|
+
::Aws::Credentials.new(aws_access_key_id, aws_secret_access_key, aws_session_token)
|
31
31
|
end
|
32
32
|
|
33
33
|
def aws_access_key_id
|
@@ -38,6 +38,10 @@ module Capistrano
|
|
38
38
|
Configuration.aws_secret_access_key
|
39
39
|
end
|
40
40
|
|
41
|
+
def aws_session_token
|
42
|
+
Configuration.aws_session_token
|
43
|
+
end
|
44
|
+
|
41
45
|
def aws_region
|
42
46
|
Configuration.aws_region
|
43
47
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'set'
|
4
|
-
|
5
3
|
module Capistrano
|
6
4
|
module ASG
|
7
5
|
module Rolling
|
@@ -23,7 +21,7 @@ module Capistrano
|
|
23
21
|
|
24
22
|
# Updated Launch Templates.
|
25
23
|
def launch_templates
|
26
|
-
@launch_templates ||=
|
24
|
+
@launch_templates ||= LaunchTemplates.new
|
27
25
|
end
|
28
26
|
|
29
27
|
def aws_access_key_id
|
@@ -34,6 +32,10 @@ module Capistrano
|
|
34
32
|
fetch(:aws_secret_access_key)
|
35
33
|
end
|
36
34
|
|
35
|
+
def aws_session_token
|
36
|
+
fetch(:aws_session_token)
|
37
|
+
end
|
38
|
+
|
37
39
|
def aws_region
|
38
40
|
fetch(:aws_region)
|
39
41
|
end
|
@@ -46,9 +46,12 @@ module Capistrano
|
|
46
46
|
# Optionally override settings in the Launch Template.
|
47
47
|
options.merge!(overrides) if overrides
|
48
48
|
|
49
|
+
resource_tags = [
|
50
|
+
{ key: 'Name', value: autoscaling_group.name_tag }
|
51
|
+
]
|
49
52
|
options[:tag_specifications] = [
|
50
|
-
{ resource_type: 'instance', tags:
|
51
|
-
{ resource_type: 'volume', tags:
|
53
|
+
{ resource_type: 'instance', tags: resource_tags },
|
54
|
+
{ resource_type: 'volume', tags: resource_tags }
|
52
55
|
]
|
53
56
|
|
54
57
|
response = aws_ec2_client.run_instances(options)
|
@@ -90,11 +93,20 @@ module Capistrano
|
|
90
93
|
@terminated = true
|
91
94
|
end
|
92
95
|
|
93
|
-
def create_ami(name: nil, description: nil)
|
94
|
-
|
95
|
-
|
96
|
+
def create_ami(name: nil, description: nil, tags: nil)
|
97
|
+
ami_tags = {
|
98
|
+
'Name' => autoscale_group.name_tag,
|
99
|
+
'capistrano-asg-rolling:version' => Capistrano::ASG::Rolling::VERSION
|
100
|
+
}
|
101
|
+
ami_tags.merge!(tags) if tags
|
102
|
+
|
103
|
+
AMI.create(instance: self, name: name || ami_name, description: description, tags: ami_tags)
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
96
107
|
|
97
|
-
|
108
|
+
def ami_name
|
109
|
+
"#{autoscale_group.name_tag} on #{Time.now.strftime('%Y-%m-%d at %H.%M.%S')}"
|
98
110
|
end
|
99
111
|
end
|
100
112
|
end
|
@@ -43,9 +43,9 @@ module Capistrano
|
|
43
43
|
Parallel.run(instances, &:terminate)
|
44
44
|
end
|
45
45
|
|
46
|
-
def create_ami(name: nil, description: nil)
|
46
|
+
def create_ami(name: nil, description: nil, tags: nil)
|
47
47
|
Parallel.run(instances) do |instance|
|
48
|
-
instance.create_ami(name: name, description: description)
|
48
|
+
instance.create_ami(name: name, description: description, tags: tags)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
@@ -7,12 +7,13 @@ module Capistrano
|
|
7
7
|
class LaunchTemplate
|
8
8
|
include AWS
|
9
9
|
|
10
|
-
attr_reader :id, :version, :default_version
|
10
|
+
attr_reader :id, :version, :name, :default_version
|
11
11
|
alias default_version? default_version
|
12
12
|
|
13
|
-
def initialize(id, version, default_version: false)
|
13
|
+
def initialize(id, version, name, default_version: false)
|
14
14
|
@id = id
|
15
15
|
@version = version.to_s
|
16
|
+
@name = name
|
16
17
|
@default_version = default_version
|
17
18
|
end
|
18
19
|
|
@@ -25,7 +26,7 @@ module Capistrano
|
|
25
26
|
)
|
26
27
|
version = response.launch_template_version
|
27
28
|
|
28
|
-
self.class.new(version.launch_template_id, version.version_number, default_version: version.default_version)
|
29
|
+
self.class.new(version.launch_template_id, version.version_number, version.launch_template_name, default_version: version.default_version)
|
29
30
|
end
|
30
31
|
|
31
32
|
def delete
|
@@ -44,7 +45,7 @@ module Capistrano
|
|
44
45
|
.launch_template_versions
|
45
46
|
.sort_by { |v| -v.version_number }
|
46
47
|
.select { |v| v.version_number < version_number }
|
47
|
-
.map { |v| self.class.new(v.launch_template_id, v.version_number, default_version: v.default_version) }
|
48
|
+
.map { |v| self.class.new(v.launch_template_id, v.version_number, v.launch_template_name, default_version: v.default_version) }
|
48
49
|
end
|
49
50
|
|
50
51
|
def version_number
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module Capistrano
|
6
|
+
module ASG
|
7
|
+
module Rolling
|
8
|
+
# Collection of Launch Templates.
|
9
|
+
class LaunchTemplates
|
10
|
+
include Enumerable
|
11
|
+
|
12
|
+
def initialize(templates = [])
|
13
|
+
@templates = Set.new(templates)
|
14
|
+
end
|
15
|
+
|
16
|
+
def <<(template)
|
17
|
+
@templates << template
|
18
|
+
end
|
19
|
+
|
20
|
+
def merge(templates)
|
21
|
+
@templates.merge(templates)
|
22
|
+
end
|
23
|
+
|
24
|
+
def each(&block)
|
25
|
+
@templates.each(&block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def empty?
|
29
|
+
@templates.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
def update(amis:, description: nil)
|
33
|
+
updated_templates = []
|
34
|
+
|
35
|
+
amis.each do |ami|
|
36
|
+
old_image_id = ami.instance.image_id
|
37
|
+
new_image_id = ami.id
|
38
|
+
|
39
|
+
with_image(old_image_id).each do |template|
|
40
|
+
updated_templates << template.create_version(image_id: new_image_id, description: description)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
self.class.new(updated_templates)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def with_image(image_id)
|
50
|
+
self.class.new(select { |template| template.image_id == image_id })
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -14,25 +14,26 @@ module Capistrano
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def error(text)
|
17
|
-
$stderr.puts
|
17
|
+
$stderr.puts format_text(text, color: :red) # rubocop:disable Style/StderrPuts
|
18
18
|
end
|
19
19
|
|
20
20
|
def verbose(text)
|
21
21
|
info(text) if @verbose
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
color(text, color, :bold)
|
26
|
-
end
|
24
|
+
private
|
27
25
|
|
28
|
-
def
|
29
|
-
|
26
|
+
def format_text(text, color: nil)
|
27
|
+
text = colorize_text(text, color) if color
|
28
|
+
text.gsub(/\*\*(.+?)\*\*/, bold_text('\\1'))
|
30
29
|
end
|
31
30
|
|
32
|
-
|
31
|
+
def bold_text(text)
|
32
|
+
"\e[1m#{text}\e[22m"
|
33
|
+
end
|
33
34
|
|
34
|
-
def
|
35
|
-
|
35
|
+
def colorize_text(text, color)
|
36
|
+
_color.colorize(text, color)
|
36
37
|
end
|
37
38
|
|
38
39
|
def _color
|
@@ -12,10 +12,6 @@ module Capistrano
|
|
12
12
|
#
|
13
13
|
class Plugin < Capistrano::Plugin
|
14
14
|
def set_defaults
|
15
|
-
set_if_empty :aws_access_key_id, ENV['AWS_ACCESS_KEY_ID']
|
16
|
-
set_if_empty :aws_secret_access_key, ENV['AWS_SECRET_ACCESS_KEY']
|
17
|
-
set_if_empty :aws_region, ENV['AWS_REGION']
|
18
|
-
|
19
15
|
set_if_empty :asg_rolling_group_name, ENV['asg_name']
|
20
16
|
set_if_empty :asg_rolling_use_private_ip_address, true
|
21
17
|
set_if_empty :asg_rolling_verbose, true
|
@@ -12,6 +12,7 @@ require 'capistrano/asg/rolling/exception'
|
|
12
12
|
require 'capistrano/asg/rolling/instance'
|
13
13
|
require 'capistrano/asg/rolling/instances'
|
14
14
|
require 'capistrano/asg/rolling/launch_template'
|
15
|
+
require 'capistrano/asg/rolling/launch_templates'
|
15
16
|
require 'capistrano/asg/rolling/logger'
|
16
17
|
require 'capistrano/asg/rolling/parallel'
|
17
18
|
require 'capistrano/asg/rolling/plugin'
|
@@ -53,35 +53,55 @@ namespace :rolling do
|
|
53
53
|
amis = config.instances.create_ami(description: revision_log_message)
|
54
54
|
|
55
55
|
logger.info 'Updating Launch Template(s) with the new AMI(s)...'
|
56
|
-
launch_templates = config.autoscale_groups.
|
56
|
+
launch_templates = config.autoscale_groups.launch_templates
|
57
|
+
updated_templates = launch_templates.update(amis: amis, description: revision_log_message)
|
57
58
|
|
58
59
|
logger.info 'Triggering Instance Refresh on Auto Scaling Group(s)...'
|
59
|
-
|
60
|
-
config.autoscale_groups.with_launch_template(launch_template).
|
60
|
+
updated_templates.each do |launch_template|
|
61
|
+
config.autoscale_groups.with_launch_template(launch_template).each do |group|
|
62
|
+
group.start_instance_refresh(launch_template)
|
63
|
+
|
64
|
+
logger.verbose "Successfully started Instance Refresh on Auto Scaling Group **#{group.name}**."
|
65
|
+
rescue Capistrano::ASG::Rolling::InstanceRefreshFailed => e
|
66
|
+
logger.info "Failed to start Instance Refresh on Auto Scaling Group **#{group.name}**: #{e.message}"
|
67
|
+
end
|
61
68
|
end
|
62
69
|
|
63
|
-
config.launch_templates.merge(
|
70
|
+
config.launch_templates.merge(updated_templates)
|
64
71
|
end
|
65
72
|
end
|
66
73
|
|
67
74
|
desc 'Clean up old Launch Template versions and AMIs and terminate instances'
|
68
75
|
task :cleanup do
|
69
76
|
unless config.launch_templates.empty?
|
77
|
+
# Keep track of deleted AMIs, so we can clean up Launch Templates that use the same AMI.
|
78
|
+
deleted_amis = []
|
79
|
+
|
70
80
|
logger.info 'Cleaning up old Launch Template version(s) and AMI(s)...'
|
71
81
|
config.launch_templates.each do |launch_template|
|
72
|
-
launch_template.previous_versions.drop(config.keep_versions).each do |version|
|
73
|
-
next if version.default_version?
|
74
|
-
|
82
|
+
launch_template.previous_versions.reject(&:default_version?).drop(config.keep_versions).each do |version|
|
75
83
|
# Need to retrieve AMI before deleting the Launch Template version.
|
76
84
|
ami = version.ami
|
85
|
+
exists = ami.exists?
|
86
|
+
deleted = deleted_amis.include?(ami)
|
87
|
+
|
88
|
+
if !exists && !deleted
|
89
|
+
logger.info("WARNING: AMI **#{ami.id}** does not exist for Launch Template **#{version.name}** version **#{version.version}**.")
|
90
|
+
next
|
91
|
+
end
|
92
|
+
|
93
|
+
# Only clean up when AMI was tagged by us.
|
94
|
+
next if exists && !ami.tag?('capistrano-asg-rolling:version')
|
77
95
|
|
78
|
-
logger.verbose "Deleting Launch Template version **#{version.version}**..."
|
96
|
+
logger.verbose "Deleting Launch Template **#{version.name}** version **#{version.version}**..."
|
79
97
|
version.delete
|
80
98
|
|
81
|
-
if
|
82
|
-
|
83
|
-
|
84
|
-
|
99
|
+
next if deleted
|
100
|
+
|
101
|
+
logger.verbose "Deleting AMI **#{ami.id}** and snapshots..."
|
102
|
+
ami.delete
|
103
|
+
|
104
|
+
deleted_amis << ami
|
85
105
|
end
|
86
106
|
end
|
87
107
|
end
|
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.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kentaa
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-03-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '2.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -75,7 +75,7 @@ dependencies:
|
|
75
75
|
version: '1'
|
76
76
|
- - ">="
|
77
77
|
- !ruby/object:Gem::Version
|
78
|
-
version:
|
78
|
+
version: 1.67.0
|
79
79
|
type: :runtime
|
80
80
|
prerelease: false
|
81
81
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -85,7 +85,7 @@ dependencies:
|
|
85
85
|
version: '1'
|
86
86
|
- - ">="
|
87
87
|
- !ruby/object:Gem::Version
|
88
|
-
version:
|
88
|
+
version: 1.67.0
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
90
|
name: aws-sdk-ec2
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -159,6 +159,7 @@ files:
|
|
159
159
|
- lib/capistrano/asg/rolling/instance.rb
|
160
160
|
- lib/capistrano/asg/rolling/instances.rb
|
161
161
|
- lib/capistrano/asg/rolling/launch_template.rb
|
162
|
+
- lib/capistrano/asg/rolling/launch_templates.rb
|
162
163
|
- lib/capistrano/asg/rolling/logger.rb
|
163
164
|
- lib/capistrano/asg/rolling/parallel.rb
|
164
165
|
- lib/capistrano/asg/rolling/plugin.rb
|
@@ -169,7 +170,8 @@ files:
|
|
169
170
|
homepage: https://github.com/KentaaNL/capistrano-asg-rolling
|
170
171
|
licenses:
|
171
172
|
- MIT
|
172
|
-
metadata:
|
173
|
+
metadata:
|
174
|
+
rubygems_mfa_required: 'true'
|
173
175
|
post_install_message:
|
174
176
|
rdoc_options: []
|
175
177
|
require_paths:
|
@@ -185,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
185
187
|
- !ruby/object:Gem::Version
|
186
188
|
version: '0'
|
187
189
|
requirements: []
|
188
|
-
rubygems_version: 3.
|
190
|
+
rubygems_version: 3.3.7
|
189
191
|
signing_key:
|
190
192
|
specification_version: 4
|
191
193
|
summary: Capistrano plugin for performing rolling updates to AWS Auto Scaling Groups
|