capistrano-asg-rolling 0.1.0 → 0.2.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 +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
|