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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7f6b6214ffbebb1d5c6866126ce143ca0ca1917be593c03a60b3e53bbc425294
4
- data.tar.gz: 8098e48a08bbbd61e1945c5a420939118d2951ddfb250ea669b0f4d8d141ed10
3
+ metadata.gz: 140ff8c2812256ee7b0db1c2675052859dd933593d6f3766adf68e855c2297b5
4
+ data.tar.gz: 76ba60506093dac285def220cb11c8f114140c525d3c65644e5d6af983edaaaf
5
5
  SHA512:
6
- metadata.gz: '08d8756a4754a72fb9e5e688f633a5cbc4f495d1db2abdb777548f05efddc25a0714d8d53cf13de66fa01691ec15fd99f8797997205018c7861ccf7939ebaa63'
7
- data.tar.gz: d985258bb1de520e96a577a5fcbf1c77de176172aa674a381e5e729d661d4218b683d8fd21e9629f2a016fbf56cc1a803cd661381c569d0ac91b7a7b14af49ca
6
+ metadata.gz: 85c502bd99f24aea1dd05fc2a499dbc3aec81be2b951dd9be3c056d1527ba51bf0d605eca6b3ab40ece1f3a7d559f400cafb50ca5884567d214c665fd7e50057
7
+ data.tar.gz: bd945c98f2dc32c63e7fac3df0a82ea9ab7a75b2cc2caeab6b24d640bd7af9bfe79c1f6f863f467a42f14d7043f18775667706cae4631552d7199a45a55b6edc
@@ -1,13 +1,15 @@
1
1
  name: CI
2
2
 
3
- on: [push]
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.22.1'
11
- gem 'rubocop-performance', '~> 1.11.5'
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.5.0'
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.1.0)
5
- aws-sdk-autoscaling (~> 1, >= 1.39)
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.516.0)
20
- aws-sdk-autoscaling (1.69.0)
21
- aws-sdk-core (~> 3, >= 3.120.0)
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.121.1)
23
+ aws-sdk-core (3.130.0)
24
24
  aws-eventstream (~> 1, >= 1.0.2)
25
- aws-partitions (~> 1, >= 1.239.0)
25
+ aws-partitions (~> 1, >= 1.525.0)
26
26
  aws-sigv4 (~> 1.1)
27
27
  jmespath (~> 1.0)
28
- aws-sdk-ec2 (1.270.0)
29
- aws-sdk-core (~> 3, >= 3.120.0)
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.16.0)
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.9)
38
+ concurrent-ruby (1.1.10)
39
39
  crack (0.4.5)
40
40
  rexml
41
- diff-lcs (1.4.4)
41
+ diff-lcs (1.5.0)
42
42
  hashdiff (1.0.1)
43
- i18n (1.8.10)
43
+ i18n (1.10.0)
44
44
  concurrent-ruby (~> 1.0)
45
- jmespath (1.4.0)
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.21.0)
50
- parser (3.0.2.0)
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.0.0)
53
+ rainbow (3.1.1)
54
54
  rake (13.0.6)
55
- regexp_parser (2.1.1)
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.1)
61
+ rspec-core (3.10.2)
62
62
  rspec-support (~> 3.10.0)
63
- rspec-expectations (3.10.1)
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.2)
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.2)
70
- rubocop (1.22.1)
69
+ rspec-support (3.10.3)
70
+ rubocop (1.26.1)
71
71
  parallel (~> 1.10)
72
- parser (>= 3.0.0.0)
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.12.0, < 2.0)
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.12.0)
80
- parser (>= 3.0.1.1)
81
- rubocop-performance (1.11.5)
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.5.0)
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 (~> 1.17)
102
+ bundler (~> 2.0)
103
103
  capistrano-asg-rolling!
104
104
  rake (~> 13.0)
105
105
  rspec (~> 3.0)
106
- rubocop (~> 1.22.1)
107
- rubocop-performance (~> 1.11.5)
106
+ rubocop (~> 1.26.1)
107
+ rubocop-performance (~> 1.13.3)
108
108
  rubocop-rake (~> 0.6.0)
109
- rubocop-rspec (~> 2.5.0)
109
+ rubocop-rspec (~> 2.9.0)
110
110
  webmock (~> 3.11)
111
111
 
112
112
  BUNDLED WITH
113
- 1.17.3
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 with the new AMIs.
15
- - Trigger Instance Refresh on the Auto Scaling Group(s) to perform an rolling update.
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
- Make sure you have configured the Auto Scaling Groups with the Launch Template version set to `Latest` so instance refresh will work.
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', '~> 1.17'
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.39'
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
- options[:tag_specifications] = tags.flat_map do |key, value|
29
- [
30
- { resource_type: 'image', tags: [{ key: key, value: value }] },
31
- { resource_type: 'snapshot', tags: [{ key: key, value: value }] }
32
- ]
33
- end
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 with_launch_template(launch_template)
25
- self.class.new(select { |group| group.launch_template == launch_template })
26
- end
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 start_instance_refresh
44
- each(&:start_instance_refresh)
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 ||= Set.new
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
@@ -12,6 +12,9 @@ module Capistrano
12
12
 
13
13
  class NoLaunchTemplate < Capistrano::ASG::Rolling::Exception
14
14
  end
15
+
16
+ class InstanceRefreshFailed < Capistrano::ASG::Rolling::Exception
17
+ end
15
18
  end
16
19
  end
17
20
  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: [{ key: 'Name', value: autoscaling_group.name_tag }] },
51
- { resource_type: 'volume', tags: [{ key: 'Name', value: autoscaling_group.name_tag }] }
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
- now = Time.now
95
- name ||= "#{autoscale_group.name_tag} on #{now.strftime('%Y-%m-%d')} at #{now.strftime('%H.%M.%S')}"
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
- AMI.create(instance: self, name: name, description: description, tags: { 'Name' => autoscale_group.name_tag })
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 color(format_text(text), :red) # rubocop:disable Style/StderrPuts
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
- def bold(text, color = :light_white)
25
- color(text, color, :bold)
26
- end
24
+ private
27
25
 
28
- def color(text, color, mode = nil)
29
- _color.colorize(text, color, mode)
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
- private
31
+ def bold_text(text)
32
+ "\e[1m#{text}\e[22m"
33
+ end
33
34
 
34
- def format_text(text)
35
- text.gsub(/\*\*(.+?)\*\*/, bold('\\1'))
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
@@ -3,7 +3,7 @@
3
3
  module Capistrano
4
4
  module ASG
5
5
  module Rolling
6
- VERSION = '0.1.0'
6
+ VERSION = '0.2.0'
7
7
  end
8
8
  end
9
9
  end
@@ -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.update_launch_templates(amis: amis, description: revision_log_message)
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
- launch_templates.each do |launch_template|
60
- config.autoscale_groups.with_launch_template(launch_template).start_instance_refresh
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(launch_templates)
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 ami.exists?
82
- logger.verbose "Deleting AMI **#{version.ami.id}** and snapshots..."
83
- ami.delete
84
- end
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.1.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: 2021-10-15 00:00:00.000000000 Z
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: '1.17'
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: '1.17'
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: '1.39'
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: '1.39'
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.0.9
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