capistrano-autoscale-hannah 1.1.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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +39 -0
  5. data/.travis.yml +13 -0
  6. data/Gemfile +8 -0
  7. data/Gemfile.lock +208 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +84 -0
  10. data/Rakefile +10 -0
  11. data/capistrano-autoscale.gemspec +33 -0
  12. data/lib/capistrano/autoscale/aws/ami.rb +70 -0
  13. data/lib/capistrano/autoscale/aws/autoscale_group.rb +96 -0
  14. data/lib/capistrano/autoscale/aws/base.rb +50 -0
  15. data/lib/capistrano/autoscale/aws/instance.rb +24 -0
  16. data/lib/capistrano/autoscale/aws/instance_collection.rb +35 -0
  17. data/lib/capistrano/autoscale/aws/launch_template.rb +57 -0
  18. data/lib/capistrano/autoscale/aws/snapshot.rb +26 -0
  19. data/lib/capistrano/autoscale/aws/taggable.rb +19 -0
  20. data/lib/capistrano/autoscale/dsl.rb +50 -0
  21. data/lib/capistrano/autoscale/errors/create_image_failed.rb +16 -0
  22. data/lib/capistrano/autoscale/errors/no_auto_scaling_group.rb +10 -0
  23. data/lib/capistrano/autoscale/errors/no_launch_template.rb +10 -0
  24. data/lib/capistrano/autoscale/logger.rb +43 -0
  25. data/lib/capistrano/autoscale/plugin.rb +20 -0
  26. data/lib/capistrano/autoscale/version.rb +7 -0
  27. data/lib/capistrano/autoscale.rb +24 -0
  28. data/lib/capistrano/tasks/autoscale.rake +129 -0
  29. data/spec/capistrano/autoscale/aws/ami_spec.rb +119 -0
  30. data/spec/capistrano/autoscale/aws/autoscale_group_spec.rb +70 -0
  31. data/spec/capistrano/autoscale/aws/instance_collection_spec.rb +55 -0
  32. data/spec/capistrano/autoscale/aws/instance_spec.rb +32 -0
  33. data/spec/capistrano/autoscale/aws/launch_template_spec.rb +90 -0
  34. data/spec/capistrano/autoscale/aws/taggable_spec.rb +34 -0
  35. data/spec/capistrano/autoscale_spec.rb +89 -0
  36. data/spec/spec_helper.rb +26 -0
  37. data/spec/support/stubs/CreateImage.200.xml +4 -0
  38. data/spec/support/stubs/CreateLaunchTemplateVersion.200.xml +16 -0
  39. data/spec/support/stubs/CreateTags.200.xml +5 -0
  40. data/spec/support/stubs/DeleteSnapshot.200.xml +4 -0
  41. data/spec/support/stubs/DeregisterImage.200.xml +4 -0
  42. data/spec/support/stubs/DescribeAutoScalingGroups.200.xml +60 -0
  43. data/spec/support/stubs/DescribeImages.200.xml +70 -0
  44. data/spec/support/stubs/DescribeInstances.200.xml +231 -0
  45. data/spec/support/stubs/DescribeInstances_Empty.200.xml +17 -0
  46. data/spec/support/stubs/DescribeInstances_MultipleReservations.200.xml +243 -0
  47. data/spec/support/stubs/DescribeInstances_MultipleRunning.200.xml +338 -0
  48. data/spec/support/stubs/DescribeLaunchTemplateVersions.200.xml +106 -0
  49. data/spec/support/stubs/DescribeSnapshots.200.xml +18 -0
  50. data/spec/support/stubs/DescribeTags.200.xml +17 -0
  51. data/spec/support/stubs/UpdateAutoScalingGroup.200.xml +5 -0
  52. data/spec/support/stubs/security-credentials.200.json +9 -0
  53. metadata +244 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 37a7f2e1a67b257817b60b0d96b555d4e675b4a7f571e9e40784884b5c755935
4
+ data.tar.gz: 43a96392b008a1f4964dbf4a0f20101d6e889b1e7307750fb1548cc5845f81b5
5
+ SHA512:
6
+ metadata.gz: b63ac6c1b20a777a589ad981bca9089899117adc0c979ed6a3cff8e84dba2aa0d6382bc00c168e50980da9adfa609bef0780b52ac286619fd373be70c93e782f
7
+ data.tar.gz: 9ae10046c10028cb55916e97bef4d94f876c294c74b8571c680e5949bfcd126cfb603f863476b43fd2822499b1f78ad97c533aa52ec31d901ebea3870e6eee05
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ bin/
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ .ruby-version
15
+ .ruby-gemset
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+ *.bundle
20
+ *.so
21
+ *.o
22
+ *.a
23
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,39 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
3
+
4
+ Layout/HashAlignment:
5
+ Enabled: false
6
+
7
+ Layout/LineLength:
8
+ Enabled: false
9
+
10
+ Metrics/AbcSize:
11
+ Max: 27
12
+
13
+ Metrics/BlockLength:
14
+ Enabled: false
15
+
16
+ Metrics/MethodLength:
17
+ Max: 28
18
+
19
+ Style/BlockDelimiters:
20
+ Exclude:
21
+ - 'spec/**/*.rb'
22
+
23
+ Style/Documentation:
24
+ Enabled: false
25
+
26
+ Style/HashEachMethods:
27
+ Enabled: true
28
+
29
+ Style/HashTransformKeys:
30
+ Enabled: true
31
+
32
+ Style/HashTransformValues:
33
+ Enabled: true
34
+
35
+ Style/StderrPuts:
36
+ Enabled: false
37
+
38
+ Style/SymbolArray:
39
+ EnforcedStyle: brackets
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ os: linux
2
+ dist: xenial
3
+ language: ruby
4
+ cache: bundler
5
+ before_install:
6
+ - gem update --system
7
+ - gem install bundler -v '< 2'
8
+ - bundle --version
9
+ rvm:
10
+ - 2.4.10
11
+ - 2.5.8
12
+ - 2.6.6
13
+ - 2.7.1
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in capistrano-autoscale.gemspec
6
+ gemspec
7
+
8
+ gem 'rubocop', '~> 0.80.1'
data/Gemfile.lock ADDED
@@ -0,0 +1,208 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ capistrano-autoscale (1.0.0)
5
+ aws-sdk-autoscaling (~> 1)
6
+ aws-sdk-ec2 (~> 1)
7
+ capistrano (~> 3.9, > 3.9)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actioncable (5.2.4.3)
13
+ actionpack (= 5.2.4.3)
14
+ nio4r (~> 2.0)
15
+ websocket-driver (>= 0.6.1)
16
+ actionmailer (5.2.4.3)
17
+ actionpack (= 5.2.4.3)
18
+ actionview (= 5.2.4.3)
19
+ activejob (= 5.2.4.3)
20
+ mail (~> 2.5, >= 2.5.4)
21
+ rails-dom-testing (~> 2.0)
22
+ actionpack (5.2.4.3)
23
+ actionview (= 5.2.4.3)
24
+ activesupport (= 5.2.4.3)
25
+ rack (~> 2.0, >= 2.0.8)
26
+ rack-test (>= 0.6.3)
27
+ rails-dom-testing (~> 2.0)
28
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
29
+ actionview (5.2.4.3)
30
+ activesupport (= 5.2.4.3)
31
+ builder (~> 3.1)
32
+ erubi (~> 1.4)
33
+ rails-dom-testing (~> 2.0)
34
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
35
+ activejob (5.2.4.3)
36
+ activesupport (= 5.2.4.3)
37
+ globalid (>= 0.3.6)
38
+ activemodel (5.2.4.3)
39
+ activesupport (= 5.2.4.3)
40
+ activerecord (5.2.4.3)
41
+ activemodel (= 5.2.4.3)
42
+ activesupport (= 5.2.4.3)
43
+ arel (>= 9.0)
44
+ activestorage (5.2.4.3)
45
+ actionpack (= 5.2.4.3)
46
+ activerecord (= 5.2.4.3)
47
+ marcel (~> 0.3.1)
48
+ activesupport (5.2.4.3)
49
+ concurrent-ruby (~> 1.0, >= 1.0.2)
50
+ i18n (>= 0.7, < 2)
51
+ minitest (~> 5.1)
52
+ tzinfo (~> 1.1)
53
+ addressable (2.7.0)
54
+ public_suffix (>= 2.0.2, < 5.0)
55
+ airbrussh (1.4.0)
56
+ sshkit (>= 1.6.1, != 1.7.0)
57
+ arel (9.0.0)
58
+ ast (2.4.1)
59
+ aws-eventstream (1.1.0)
60
+ aws-partitions (1.338.0)
61
+ aws-sdk-autoscaling (1.43.0)
62
+ aws-sdk-core (~> 3, >= 3.99.0)
63
+ aws-sigv4 (~> 1.1)
64
+ aws-sdk-core (3.103.0)
65
+ aws-eventstream (~> 1, >= 1.0.2)
66
+ aws-partitions (~> 1, >= 1.239.0)
67
+ aws-sigv4 (~> 1.1)
68
+ jmespath (~> 1.0)
69
+ aws-sdk-ec2 (1.174.0)
70
+ aws-sdk-core (~> 3, >= 3.99.0)
71
+ aws-sigv4 (~> 1.1)
72
+ aws-sigv4 (1.2.1)
73
+ aws-eventstream (~> 1, >= 1.0.2)
74
+ builder (3.2.4)
75
+ capistrano (3.14.1)
76
+ airbrussh (>= 1.0.0)
77
+ i18n
78
+ rake (>= 10.0.0)
79
+ sshkit (>= 1.9.0)
80
+ concurrent-ruby (1.1.6)
81
+ crack (0.4.3)
82
+ safe_yaml (~> 1.0.0)
83
+ crass (1.0.6)
84
+ diff-lcs (1.4.4)
85
+ erubi (1.9.0)
86
+ globalid (0.4.2)
87
+ activesupport (>= 4.2.0)
88
+ hashdiff (1.0.1)
89
+ i18n (1.8.3)
90
+ concurrent-ruby (~> 1.0)
91
+ jaro_winkler (1.5.4)
92
+ jmespath (1.4.0)
93
+ loofah (2.6.0)
94
+ crass (~> 1.0.2)
95
+ nokogiri (>= 1.5.9)
96
+ mail (2.7.1)
97
+ mini_mime (>= 0.1.1)
98
+ marcel (0.3.3)
99
+ mimemagic (~> 0.3.2)
100
+ method_source (1.0.0)
101
+ mimemagic (0.3.5)
102
+ mini_mime (1.0.2)
103
+ mini_portile2 (2.4.0)
104
+ minitest (5.14.1)
105
+ net-scp (3.0.0)
106
+ net-ssh (>= 2.6.5, < 7.0.0)
107
+ net-ssh (6.1.0)
108
+ nio4r (2.5.2)
109
+ nokogiri (1.10.9)
110
+ mini_portile2 (~> 2.4.0)
111
+ parallel (1.19.2)
112
+ parser (2.7.1.4)
113
+ ast (~> 2.4.1)
114
+ public_suffix (4.0.5)
115
+ rack (2.2.3)
116
+ rack-test (1.1.0)
117
+ rack (>= 1.0, < 3)
118
+ rails (5.2.4.3)
119
+ actioncable (= 5.2.4.3)
120
+ actionmailer (= 5.2.4.3)
121
+ actionpack (= 5.2.4.3)
122
+ actionview (= 5.2.4.3)
123
+ activejob (= 5.2.4.3)
124
+ activemodel (= 5.2.4.3)
125
+ activerecord (= 5.2.4.3)
126
+ activestorage (= 5.2.4.3)
127
+ activesupport (= 5.2.4.3)
128
+ bundler (>= 1.3.0)
129
+ railties (= 5.2.4.3)
130
+ sprockets-rails (>= 2.0.0)
131
+ rails-dom-testing (2.0.3)
132
+ activesupport (>= 4.2.0)
133
+ nokogiri (>= 1.6)
134
+ rails-html-sanitizer (1.3.0)
135
+ loofah (~> 2.3)
136
+ railties (5.2.4.3)
137
+ actionpack (= 5.2.4.3)
138
+ activesupport (= 5.2.4.3)
139
+ method_source
140
+ rake (>= 0.8.7)
141
+ thor (>= 0.19.0, < 2.0)
142
+ rainbow (3.0.0)
143
+ rake (13.0.1)
144
+ rexml (3.2.4)
145
+ rspec (3.9.0)
146
+ rspec-core (~> 3.9.0)
147
+ rspec-expectations (~> 3.9.0)
148
+ rspec-mocks (~> 3.9.0)
149
+ rspec-core (3.9.2)
150
+ rspec-support (~> 3.9.3)
151
+ rspec-expectations (3.9.2)
152
+ diff-lcs (>= 1.2.0, < 2.0)
153
+ rspec-support (~> 3.9.0)
154
+ rspec-mocks (3.9.1)
155
+ diff-lcs (>= 1.2.0, < 2.0)
156
+ rspec-support (~> 3.9.0)
157
+ rspec-support (3.9.3)
158
+ rubocop (0.80.1)
159
+ jaro_winkler (~> 1.5.1)
160
+ parallel (~> 1.10)
161
+ parser (>= 2.7.0.1)
162
+ rainbow (>= 2.2.2, < 4.0)
163
+ rexml
164
+ ruby-progressbar (~> 1.7)
165
+ unicode-display_width (>= 1.4.0, < 1.7)
166
+ ruby-progressbar (1.10.1)
167
+ safe_yaml (1.0.5)
168
+ sprockets (3.7.2)
169
+ concurrent-ruby (~> 1.0)
170
+ rack (> 1, < 3)
171
+ sprockets-rails (3.2.1)
172
+ actionpack (>= 4.0)
173
+ activesupport (>= 4.0)
174
+ sprockets (>= 3.0.0)
175
+ sshkit (1.21.0)
176
+ net-scp (>= 1.1.2)
177
+ net-ssh (>= 2.8.0)
178
+ thor (1.0.1)
179
+ thread_safe (0.3.6)
180
+ tzinfo (1.2.7)
181
+ thread_safe (~> 0.1)
182
+ unicode-display_width (1.6.1)
183
+ webmock (3.8.3)
184
+ addressable (>= 2.3.6)
185
+ crack (>= 0.3.2)
186
+ hashdiff (>= 0.4.0, < 2.0.0)
187
+ webmock-rspec-helper (0.0.5)
188
+ rails (>= 3.0.0)
189
+ rspec
190
+ webmock
191
+ websocket-driver (0.7.2)
192
+ websocket-extensions (>= 0.1.0)
193
+ websocket-extensions (0.1.5)
194
+
195
+ PLATFORMS
196
+ ruby
197
+
198
+ DEPENDENCIES
199
+ bundler (~> 1.14)
200
+ capistrano-autoscale!
201
+ rake (~> 13.0)
202
+ rspec (~> 3.0, > 3.0)
203
+ rubocop (~> 0.80.1)
204
+ webmock (~> 3.8)
205
+ webmock-rspec-helper (~> 0.0.5)
206
+
207
+ BUNDLED WITH
208
+ 1.17.3
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Logan Serman
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # Capistrano Autoscale
2
+
3
+ [![Build Status](https://travis-ci.org/KentaaNL/capistrano-autoscale.svg?branch=master)](https://travis-ci.org/KentaaNL/capistrano-autoscale)
4
+
5
+ This is a fork of [lserman/capistrano-elbas](https://github.com/lserman/capistrano-elbas), with several improvements.
6
+
7
+ Capistrano-autoscale was written to ease the deployment of Rails applications to AWS Auto Scaling
8
+ Groups. During your Capistrano deployment, capistrano-autoscale will:
9
+
10
+ - Suspend Launch & Terminate processes on the Auto Scaling Group.
11
+ - Deploy your code to each running instance connected to a given Auto Scaling Group.
12
+ - After deployment, create an AMI from one of the running instances.
13
+ - Create a new Launch Template version with the AMI ID based on the current Auto Scaling Group's Launch Template.
14
+ - Delete any outdated Launch Template versions, AMIs and snapshots created by previous deployments.
15
+ - Resume Launch & Terminate processes on the Auto Scaling Group.
16
+
17
+ ## Installation
18
+
19
+ Add to Gemfile, then run `bundle`:
20
+
21
+ `gem 'capistrano-autoscale', require: false, git: 'https://github.com/KentaaNL/capistrano-autoscale.git'`
22
+
23
+ Add to Capfile:
24
+
25
+ `require 'capistrano/autoscale'`
26
+
27
+ ## Configuration
28
+
29
+ Setup AWS credentials:
30
+
31
+ ```ruby
32
+ set :aws_access_key_id, ENV['AWS_ACCESS_KEY_ID']
33
+ set :aws_secret_access_key, ENV['AWS_SECRET_ACCESS_KEY']
34
+ set :aws_region, ENV['AWS_REGION']
35
+ ```
36
+
37
+ To configure the prefix that AMIs will get (defaults to stage name):
38
+
39
+ ```ruby
40
+ set :aws_autoscale_ami_prefix, "my-ami"
41
+ ```
42
+
43
+ To add custom tags to AMIs and snapshots you can specify a hash:
44
+
45
+ ```ruby
46
+ set :aws_autoscale_ami_tags, { "Environment" => "Sandbox" }
47
+ set :aws_autoscale_snapshot_tags, { "Environment" => "Sandbox" }
48
+ ```
49
+
50
+ By default, the Launch & Terminate processes will be suspended during deployment. To disable this:
51
+
52
+ ```ruby
53
+ set :aws_autoscale_suspend_processes, false
54
+ ```
55
+
56
+ After deployment, any outdated Launch Template versions, AMIs and snapshots will be deleted. By default, the number of `keep_releases` will be kept. To change this, set:
57
+
58
+ ```ruby
59
+ set :aws_autoscale_cleanup_old_versions, true
60
+ set :aws_autoscale_keep_versions, 8
61
+ ```
62
+
63
+ ## Usage
64
+
65
+ Instead of using Capistrano's `server` method, use `autoscale` instead in
66
+ `deploy/<environment>.rb` (replace &lt;environment&gt; with your environment). Provide
67
+ the name of your Auto Scaling group instead of a hostname:
68
+
69
+ ```ruby
70
+ autoscale 'my-autoscale-group', user: 'apps', roles: [:app, :web, :db]
71
+ ```
72
+
73
+ If you have multiple autoscaling groups to deploy to, specify each of them:
74
+
75
+ ```ruby
76
+ autoscale 'app-autoscale-group', user: 'apps', roles: [:app, :web]
77
+ autoscale 'worker-autoscale-group', user: 'apps', roles: [:worker]
78
+ ```
79
+
80
+ Run `cap production deploy`.
81
+
82
+ Note: Your Auto Scaling Group must use Launch Templates as opposed to Launch Configurations.
83
+ This allows capistrano-autoscale to simply create a new Launch Template version with the new AMI ID after a deployment.
84
+ Failure to use a Launch Template will result in a `Capistrano::Autoscale::Errors::NoLaunchTemplate` error.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new(:rubocop)
9
+
10
+ task default: [:spec, :rubocop]
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'capistrano/autoscale/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'capistrano-autoscale-hannah'
9
+ spec.version = Capistrano::Autoscale::VERSION
10
+ spec.authors = ['François Fitzpatrick']
11
+ spec.email = ['francois.fitzpatrick@gmail.com']
12
+ spec.summary = 'Capistrano plugin for deploying to AWS Auto Scaling Groups with enhanced features.'
13
+ spec.description = spec.summary
14
+ spec.homepage = 'https://github.com/ID-Soft/capistrano-autoscale'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.required_ruby_version = '>= 2.3.0'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.14'
25
+ spec.add_development_dependency 'rake', '~> 13.0'
26
+ spec.add_development_dependency 'rspec', '~> 3.0', '> 3.0'
27
+ spec.add_development_dependency 'webmock', '~> 3.8'
28
+ spec.add_development_dependency 'webmock-rspec-helper', '~> 0.0.5'
29
+
30
+ spec.add_dependency 'aws-sdk-autoscaling', '~> 1'
31
+ spec.add_dependency 'aws-sdk-ec2', '~> 1'
32
+ spec.add_dependency 'capistrano', '~> 3.9', '> 3.9'
33
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capistrano
4
+ module Autoscale
5
+ module AWS
6
+ class AMI < Base
7
+ include Taggable
8
+
9
+ DEPLOY_GROUP_TAG = 'Autoscale-Deploy-group'
10
+
11
+ attr_reader :aws_counterpart, :id, :snapshots
12
+
13
+ def initialize(id, block_device_mappings = [])
14
+ @id = id
15
+ @aws_counterpart = ::Aws::EC2::Image.new id, client: ec2_client
16
+
17
+ @snapshots = block_device_mappings.map do |mapping|
18
+ Capistrano::Autoscale::AWS::Snapshot.new mapping&.ebs&.snapshot_id
19
+ end
20
+ end
21
+
22
+ def deploy_group
23
+ tags[DEPLOY_GROUP_TAG]
24
+ end
25
+
26
+ def delete
27
+ ec2_client.deregister_image image_id: id
28
+ snapshots.each(&:delete)
29
+ end
30
+
31
+ def self.create(instance, prefix: 'autoscale', no_reboot: false)
32
+ name = "#{prefix}-#{Time.now.to_i}"
33
+
34
+ image = instance.aws_counterpart.create_image(
35
+ name: name,
36
+ instance_id: instance.id,
37
+ no_reboot: no_reboot
38
+ )
39
+ image = image.wait_until_exists
40
+
41
+ block_device_mappings = nil
42
+ # Wait until block_device_mappings/snapshots are available.
43
+ loop do
44
+ block_device_mappings = image.block_device_mappings
45
+ snapshot_ids = block_device_mappings.map { |mapping| mapping.ebs&.snapshot_id }.compact
46
+ break if !snapshot_ids.empty? || image.state == 'failed'
47
+
48
+ sleep 1
49
+ image.load
50
+ end
51
+
52
+ raise Capistrano::Autoscale::Errors::CreateImageFailed, image if image.state == 'failed'
53
+
54
+ ami = new image.id, block_device_mappings
55
+ ami.tag 'Name', name
56
+ ami.snapshots.each { |snapshot| snapshot.tag 'Name', name }
57
+ ami
58
+ end
59
+
60
+ def create_tags(deploy_group)
61
+ tag(DEPLOY_GROUP_TAG, deploy_group)
62
+
63
+ aws_autoscale_ami_tags.each { |key, value| tag(key, value) }
64
+
65
+ snapshots.each(&:create_tags)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capistrano
4
+ module Autoscale
5
+ module AWS
6
+ class AutoscaleGroup < Base
7
+ SUSPEND_PROCESSES = %w[Launch Terminate].freeze
8
+
9
+ LIFECYCLE_STATE_IN_SERVICE = 'InService'
10
+ LIFECYCLE_STATE_STANDBY = 'Standby'
11
+
12
+ AMI_PREFIX_TAG = 'Autoscale-Ami-Prefix'
13
+
14
+ attr_reader :name, :aws_counterpart
15
+
16
+ def initialize(name)
17
+ @name = name
18
+ @aws_counterpart = Aws::AutoScaling::AutoScalingGroup.new name: name, client: autoscaling_client
19
+
20
+ raise Capistrano::Autoscale::Errors::NoAutoScalingGroup, name unless @aws_counterpart.exists?
21
+ end
22
+
23
+ def instances
24
+ instance_ids = aws_counterpart.instances.map(&:instance_id)
25
+ InstanceCollection.new(instance_ids)
26
+ end
27
+
28
+ def instances_in_service
29
+ instance_ids = aws_counterpart.instances.select { |i| i.lifecycle_state == LIFECYCLE_STATE_IN_SERVICE }.map(&:instance_id)
30
+ InstanceCollection.new(instance_ids)
31
+ end
32
+
33
+ def launch_template
34
+ lts = aws_launch_template || aws_launch_template_specification
35
+ raise Capistrano::Autoscale::Errors::NoLaunchTemplate unless lts
36
+
37
+ LaunchTemplate.new(
38
+ lts.launch_template_id,
39
+ lts.launch_template_name,
40
+ lts.version,
41
+ false,
42
+ nil
43
+ )
44
+ end
45
+
46
+ def suspend
47
+ aws_counterpart.suspend_processes(scaling_processes: SUSPEND_PROCESSES)
48
+ end
49
+
50
+ def resume
51
+ aws_counterpart.resume_processes(scaling_processes: SUSPEND_PROCESSES)
52
+ end
53
+
54
+ def suspended?
55
+ aws_counterpart.suspended_processes.map(&:process_name).any? { |name| SUSPEND_PROCESSES.include?(name) }
56
+ end
57
+
58
+ def tags
59
+ aws_counterpart.tags.map { |tag| [tag.key, tag.value] }.to_h
60
+ end
61
+
62
+ def ami_prefix
63
+ tags[AMI_PREFIX_TAG]
64
+ end
65
+
66
+ def enter_standby(instance)
67
+ instance = aws_counterpart.instances.select { |i| i.id == instance.id }.first
68
+ instance.enter_standby(should_decrement_desired_capacity: true)
69
+
70
+ loop do
71
+ break if instance.lifecycle_state == LIFECYCLE_STATE_STANDBY
72
+
73
+ sleep 1
74
+ instance.load
75
+ end
76
+ end
77
+
78
+ def exit_standby(instance)
79
+ instance = aws_counterpart.instances.select { |i| i.id == instance.id }.first
80
+ instance.exit_standby
81
+ end
82
+
83
+ private
84
+
85
+ def aws_launch_template
86
+ aws_counterpart.launch_template
87
+ end
88
+
89
+ def aws_launch_template_specification
90
+ aws_counterpart.mixed_instances_policy&.launch_template
91
+ &.launch_template_specification
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capistrano
4
+ module Autoscale
5
+ module AWS
6
+ class Base
7
+ include Capistrano::DSL
8
+
9
+ def ec2_client
10
+ @ec2_client ||= ::Aws::EC2::Client.new(aws_options)
11
+ end
12
+
13
+ def autoscaling_client
14
+ @autoscaling_client ||= ::Aws::AutoScaling::Client.new(aws_options)
15
+ end
16
+
17
+ def aws_options
18
+ options = {}
19
+ options[:region] = aws_region if aws_region
20
+ options[:credentials] = aws_credentials if aws_credentials.set?
21
+ options
22
+ end
23
+
24
+ def aws_credentials
25
+ fetch :aws_credentials, ::Aws::Credentials.new(aws_access_key_id, aws_secret_access_key)
26
+ end
27
+
28
+ def aws_access_key_id
29
+ fetch :aws_access_key_id
30
+ end
31
+
32
+ def aws_secret_access_key
33
+ fetch :aws_secret_access_key
34
+ end
35
+
36
+ def aws_region
37
+ fetch :aws_region
38
+ end
39
+
40
+ def aws_autoscale_ami_tags
41
+ fetch :aws_autoscale_ami_tags
42
+ end
43
+
44
+ def aws_autoscale_snapshot_tags
45
+ fetch :aws_autoscale_snapshot_tags
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end