capistrano3-autoscaling-deploy 1.6 → 2.0.1
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 +5 -5
- data/CHANGELOG.md +39 -0
- data/README.md +94 -47
- data/lib/capistrano/autoscaling_deploy/version.rb +1 -1
- data/lib/capistrano/autoscaling_deploy.rb +0 -1
- data/lib/capistrano/helpers/aws_helper.rb +48 -11
- data/lib/capistrano/helpers/cap_helper.rb +6 -1
- data/lib/capistrano/tasks/autoscaling.rake +12 -5
- metadata +41 -35
- data/.gitignore +0 -53
- data/.travis.yml +0 -12
- data/Gemfile +0 -4
- data/Gemfile.lock +0 -49
- data/Rakefile +0 -1
- data/capistrano3-autoscaling-deploy.gemspec +0 -26
- data/lib/capistrano/autoscaling_deploy/autoscaling_deploy.rb +0 -1
- data/test/autoscaling_test.rb +0 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 5125a4f0cf87e61f76c8693fa8d434d9799ecbfd210abe6b6d5d4d297f9d0616
|
|
4
|
+
data.tar.gz: 4afd807fd174d4305a797caa38189a951df32cfe08aa33bf5f09dfc2b7300ae5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2118d1de8dd0d3119f9799bb6e177c3790137ca24b368750ec1a8bb1d012ec86ad21b5f6876d3a73f2da2ab94fa6d2e98251b84c1b280c610e6db08b0e7a34b4
|
|
7
|
+
data.tar.gz: 5c8188565e47c2afd1045dac3f5993370c6a0beb49fc9544d16e558701436c482e2a29cb171ce3147f6002f72e6b0e04fc435222df8868b951c1d42be4c7a4a1
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 2.0.1
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Instances without an address for `aws_ip_type` (for example `public_dns_name` in a private subnet) now stop the deploy with an error naming them. Before, they were all registered as one server with an empty hostname, and each was treated as the primary server ([#23](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues/23)).
|
|
7
|
+
- The primary server is chosen by position in the Auto Scaling group, not by comparing hostnames ([#23](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues/23)).
|
|
8
|
+
|
|
9
|
+
### Removed
|
|
10
|
+
- `lib/capistrano/autoscaling_deploy/autoscaling_deploy.rb`, an unused file that loaded the tasks a second time. Require `capistrano/autoscaling_deploy` in your Capfile, as the README says ([#24](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues/24)).
|
|
11
|
+
|
|
12
|
+
## 2.0.0
|
|
13
|
+
|
|
14
|
+
First release since 1.6 (2017). See [Upgrading to 2.0](README.md#upgrading-to-20) before updating.
|
|
15
|
+
|
|
16
|
+
### Breaking changes
|
|
17
|
+
- Uses the current AWS SDK for Ruby (`aws-sdk-autoscaling` and `aws-sdk-ec2`) instead of the retired `aws-sdk` v2 ([#10](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues/10)).
|
|
18
|
+
- No longer depends on or loads `capistrano-bundler`. Add it to your own Gemfile and Capfile if your deploy runs `bundle install` ([#11](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues/11)).
|
|
19
|
+
- Only deploys to instances whose lifecycle state is `InService` ([#13](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues/13)).
|
|
20
|
+
- Stops the deploy with an error if the Auto Scaling group doesn't exist or has no matching instances ([#13](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues/13)).
|
|
21
|
+
- Requires Ruby 3.3 or newer.
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- Uses the AWS SDK's default credential chain (environment variables, shared config files, SSO, ECS and EC2 roles) when `aws_access_key_id` and `aws_secret_access_key` aren't set ([#12](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues/12)).
|
|
25
|
+
- `aws_profile` setting to use a named AWS profile ([#12](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues/12)).
|
|
26
|
+
- `aws_lifecycle_states` setting to choose which lifecycle states to deploy to ([#13](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues/13)).
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- With the default roles, or roles given as strings, every instance got the `db` role instead of only the first one ([#19](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues/19)).
|
|
30
|
+
- Setting only one of `aws_access_key_id` and `aws_secret_access_key` now raises a clear error instead of sending a `nil` key ([#12](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues/12)).
|
|
31
|
+
- Instances are looked up in one EC2 call instead of one call per instance ([#10](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues/10)).
|
|
32
|
+
|
|
33
|
+
### Development
|
|
34
|
+
- Real test suite using the AWS SDK's stubbed responses, run on GitHub Actions for Ruby 3.3, 3.4 and 4.0 ([#14](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues/14)).
|
|
35
|
+
- Releases are published to RubyGems from GitHub Actions with trusted publishing.
|
|
36
|
+
|
|
37
|
+
## 1.6 and earlier
|
|
38
|
+
|
|
39
|
+
See the [commit history](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/commits/master).
|
data/README.md
CHANGED
|
@@ -1,84 +1,131 @@
|
|
|
1
|
-
[](https://rubygems.org/gems/capistrano3-autoscaling-deploy)
|
|
2
|
+
[](https://github.com/marcoschicote/capistrano3-autoscaling-deploy/actions/workflows/test.yml)
|
|
3
|
+
|
|
2
4
|
# capistrano3-autoscaling-deploy
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
A lot of inspiration (and code) for how this gem was built come from https://github.com/gtforge/capistrano-autoscale-deploy
|
|
6
|
-
I've also taken suggestions from the opened PRs against such repo.
|
|
7
|
-
|
|
8
|
-
I'm mainly building this gem as the author for the gem above has dissapeared
|
|
9
|
-
and I need an updated version that uses Capistrano 3 and current version of
|
|
10
|
-
AWS CLI.
|
|
5
|
+
|
|
6
|
+
Capistrano 3 plugin that deploys to the instances of an AWS Auto Scaling group. Instead of listing servers in your stage files, the plugin asks AWS which instances are in service at deploy time and adds them as Capistrano servers.
|
|
11
7
|
|
|
12
8
|
## Requirements
|
|
13
9
|
|
|
14
|
-
*
|
|
10
|
+
* Ruby 3.3 or newer
|
|
15
11
|
* capistrano ~> 3
|
|
16
|
-
|
|
12
|
+
* aws-sdk-autoscaling ~> 1 and aws-sdk-ec2 ~> 1 (installed with the gem)
|
|
17
13
|
|
|
18
14
|
## Installation
|
|
19
15
|
|
|
20
|
-
Add
|
|
16
|
+
Add the gem to your application's Gemfile:
|
|
21
17
|
|
|
22
|
-
|
|
18
|
+
```ruby
|
|
19
|
+
gem 'capistrano3-autoscaling-deploy', '~> 2.0'
|
|
20
|
+
```
|
|
23
21
|
|
|
24
|
-
|
|
22
|
+
and run `bundle install`.
|
|
25
23
|
|
|
26
|
-
|
|
24
|
+
Then add this line to your Capfile:
|
|
27
25
|
|
|
28
|
-
|
|
26
|
+
```ruby
|
|
27
|
+
require 'capistrano/autoscaling_deploy'
|
|
28
|
+
```
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
## Usage
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
In your deploy script or stage file (for example `config/deploy/production.rb`), set the Auto Scaling group to deploy to:
|
|
33
33
|
|
|
34
34
|
```ruby
|
|
35
|
-
|
|
35
|
+
set :aws_region, 'eu-west-1'
|
|
36
|
+
set :aws_autoscaling_group_name, 'my-app-production'
|
|
37
|
+
set :aws_deploy_user, 'deploy'
|
|
36
38
|
```
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
Before each deploy starts, the plugin adds every in-service instance in that group as a server. Don't also define those servers with `server` or `role`.
|
|
41
|
+
|
|
42
|
+
### Settings
|
|
43
|
+
|
|
44
|
+
| Setting | Default | Description |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `aws_autoscaling_group_name` | none (required) | Name of the Auto Scaling group to deploy to. |
|
|
47
|
+
| `aws_region` | `'us-west-2'` | AWS region of the group. |
|
|
48
|
+
| `aws_deploy_user` | none | SSH user for the instances. If unset, Capistrano's usual SSH user applies. |
|
|
49
|
+
| `aws_deploy_roles` | `%i{web app db}` | Roles given to the instances. See [Roles](#roles). |
|
|
50
|
+
| `aws_ip_type` | `'public_dns_name'` | Address used to connect to each instance: `public_dns_name`, `public_ip_address`, `private_dns_name` or `private_ip_address`. Use a private one for instances without public addresses, for example when deploying through a bastion or from inside the VPC. |
|
|
51
|
+
| `aws_lifecycle_states` | `%w(InService)` | [Lifecycle states](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-lifecycle.html) of the instances to deploy to. |
|
|
52
|
+
| `aws_profile` | none | Named AWS profile to use. See [AWS credentials](#aws-credentials). |
|
|
53
|
+
| `aws_access_key_id`, `aws_secret_access_key` | none | Static AWS keys. See [AWS credentials](#aws-credentials). |
|
|
54
|
+
| `aws_autoscaling` | `true` | Set to `false` to turn the plugin off, for example in a stage whose servers you define yourself. |
|
|
55
|
+
|
|
56
|
+
### AWS credentials
|
|
57
|
+
|
|
58
|
+
The credentials need read access to Auto Scaling and EC2: `autoscaling:DescribeAutoScalingGroups` and `ec2:DescribeInstances`. The `AmazonEC2ReadOnlyAccess` managed policy covers both.
|
|
59
|
+
|
|
60
|
+
By default the gem uses the [AWS SDK's default credential chain](https://docs.aws.amazon.com/sdk-for-ruby/v3/developer-guide/credential-providers.html): environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`), `AWS_PROFILE` and the shared config and credentials files, AWS SSO, and ECS task or EC2 instance roles. This is the recommended setup, and it needs no settings.
|
|
61
|
+
|
|
62
|
+
To use a specific profile from your shared config:
|
|
39
63
|
|
|
40
|
-
|
|
64
|
+
```ruby
|
|
65
|
+
set :aws_profile, 'deploy'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
You can still set static keys, but don't commit them to your repository. If both are set, they take precedence over `aws_profile`:
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
set :aws_access_key_id, ENV['DEPLOY_AWS_ACCESS_KEY_ID']
|
|
72
|
+
set :aws_secret_access_key, ENV['DEPLOY_AWS_SECRET_ACCESS_KEY']
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Roles
|
|
76
|
+
|
|
77
|
+
Every instance gets the roles in `aws_deploy_roles`, except that only the **first** instance gets `:db` and `primary: true`. That way tasks meant to run once, such as database migrations, don't run on every instance at the same time.
|
|
78
|
+
|
|
79
|
+
With three instances in the group and the default roles, you end up with the same servers as if you had written:
|
|
41
80
|
|
|
42
81
|
```ruby
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
set :aws_autoscaling_group_name, 'YOUR NAME OF AUTO SCALING GROUP NAME'
|
|
47
|
-
set :aws_deploy_roles, [:app, :web, :db]
|
|
48
|
-
set :aws_deploy_user, 'USER FOR SSH CONNECTION'
|
|
49
|
-
|
|
50
|
-
# optional: defaults to 'public_dns_name'
|
|
51
|
-
# select from ['public_ip_address', 'public_dns_name', 'private_ip_address', 'private_dns_name']
|
|
52
|
-
set :aws_ip_type, 'public_dns_name'
|
|
82
|
+
server 'ip-1.example.com', roles: %i{web app db}, primary: true
|
|
83
|
+
server 'ip-2.example.com', roles: %i{web app}
|
|
84
|
+
server 'ip-3.example.com', roles: %i{web app}
|
|
53
85
|
```
|
|
54
86
|
|
|
55
|
-
|
|
87
|
+
## How it works
|
|
56
88
|
|
|
57
|
-
|
|
89
|
+
Before `deploy:starting`, the plugin:
|
|
58
90
|
|
|
59
|
-
|
|
91
|
+
1. Looks up the Auto Scaling group `aws_autoscaling_group_name`.
|
|
92
|
+
2. Keeps only the instances whose lifecycle state is in `aws_lifecycle_states`, and logs the ones it skips. Instances that are launching, on standby or being terminated are skipped by default. Health status isn't checked, so you can still deploy a fix when every instance is failing its health checks.
|
|
93
|
+
3. Reads each instance's `aws_ip_type` address from EC2.
|
|
94
|
+
4. Adds the instances as servers in the group's order, with roles as described in [Roles](#roles).
|
|
60
95
|
|
|
61
|
-
|
|
96
|
+
The deploy stops with an error if:
|
|
62
97
|
|
|
63
|
-
|
|
98
|
+
* the group doesn't exist,
|
|
99
|
+
* no instances are in the selected lifecycle states, or
|
|
100
|
+
* an instance has no address for `aws_ip_type`, for example `public_dns_name` in a private subnet.
|
|
64
101
|
|
|
65
|
-
|
|
102
|
+
## Upgrading to 2.0
|
|
66
103
|
|
|
67
|
-
|
|
104
|
+
2.0 uses the current AWS SDK for Ruby (`aws-sdk-autoscaling` and `aws-sdk-ec2`) instead of the retired `aws-sdk` v2, so it no longer installs `aws-sdk` v2. If your own deploy code uses `aws-sdk` v2, add it to your Gemfile or, better, move that code to the current SDK.
|
|
68
105
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
106
|
+
2.0 only deploys to instances whose lifecycle state is `InService`, and stops with an error if the Auto Scaling group doesn't exist or has no such instances. Before, it deployed to every instance in the group, including ones being launched or terminated, and carried on with no servers if the group was empty. To also deploy to other states, set `aws_lifecycle_states` (for example `%w(InService Standby)`).
|
|
107
|
+
|
|
108
|
+
Versions before 2.0 also loaded [capistrano-bundler](https://github.com/capistrano/bundler), which runs `bundle install` on your servers during deploy. 2.0 no longer does this. If your deploy relies on it, add `gem 'capistrano-bundler'` to your Gemfile and this line to your Capfile:
|
|
109
|
+
|
|
110
|
+
```ruby
|
|
111
|
+
require 'capistrano/bundler'
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
See [CHANGELOG.md](CHANGELOG.md) for all changes.
|
|
74
115
|
|
|
75
116
|
## Contributing
|
|
76
117
|
|
|
77
|
-
1. Fork it (
|
|
118
|
+
1. Fork it (https://github.com/marcoschicote/capistrano3-autoscaling-deploy/fork)
|
|
78
119
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
79
120
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
80
121
|
4. Push to the branch (`git push origin my-new-feature`)
|
|
81
|
-
5. Create new
|
|
122
|
+
5. Create a new pull request
|
|
123
|
+
|
|
124
|
+
Run the tests with `bundle exec rake test`. They use the AWS SDK's stubbed responses, so they don't need AWS credentials or network access.
|
|
125
|
+
|
|
126
|
+
## Releasing
|
|
127
|
+
|
|
128
|
+
Releases are published to RubyGems from GitHub Actions using [trusted publishing](https://guides.rubygems.org/trusted-publishing/), so no API key is stored anywhere.
|
|
82
129
|
|
|
83
|
-
|
|
84
|
-
`
|
|
130
|
+
1. Update the version in `lib/capistrano/autoscaling_deploy/version.rb` and add a section to `CHANGELOG.md`, and merge them to `master`.
|
|
131
|
+
2. In the repository's **Actions** tab, run the **Release** workflow on `master`. It runs the tests, builds the gem, pushes the `vX.Y.Z` tag and publishes the gem.
|
|
@@ -1,36 +1,72 @@
|
|
|
1
|
-
require 'aws-sdk'
|
|
1
|
+
require 'aws-sdk-autoscaling'
|
|
2
|
+
require 'aws-sdk-ec2'
|
|
2
3
|
|
|
3
4
|
module AwsHelper
|
|
4
5
|
IP_TYPES = %w(public_ip_address public_dns_name private_ip_address private_dns_name)
|
|
6
|
+
LIFECYCLE_STATES = %w(InService)
|
|
5
7
|
|
|
6
|
-
def get_instances(aws_region, aws_access_key_id, aws_secret_access_key, aws_autoscaling_group_name, aws_ip_type)
|
|
7
|
-
|
|
8
|
-
retrieve_ec2_instances(
|
|
8
|
+
def get_instances(aws_region, aws_access_key_id, aws_secret_access_key, aws_autoscaling_group_name, aws_ip_type, aws_profile: nil, lifecycle_states: LIFECYCLE_STATES)
|
|
9
|
+
client_options = aws_client_options(aws_region, aws_access_key_id, aws_secret_access_key, aws_profile)
|
|
10
|
+
retrieve_ec2_instances(client_options, aws_autoscaling_group_name, aws_ip_type, lifecycle_states)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Explicit keys win, then a named profile. With neither, the SDK's default
|
|
14
|
+
# credential chain is used: environment variables, shared config and
|
|
15
|
+
# credentials files, SSO, and ECS or EC2 instance roles.
|
|
16
|
+
def aws_client_options(aws_region, aws_access_key_id, aws_secret_access_key, aws_profile = nil)
|
|
17
|
+
options = { region: aws_region }
|
|
18
|
+
|
|
19
|
+
if aws_access_key_id && aws_secret_access_key
|
|
20
|
+
options[:credentials] = Aws::Credentials.new(aws_access_key_id, aws_secret_access_key)
|
|
21
|
+
elsif aws_access_key_id || aws_secret_access_key
|
|
22
|
+
raise ArgumentError, 'Set both :aws_access_key_id and :aws_secret_access_key, or neither to use the default AWS credential chain'
|
|
23
|
+
elsif aws_profile
|
|
24
|
+
options[:profile] = aws_profile
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
options
|
|
9
28
|
end
|
|
10
29
|
|
|
11
30
|
private
|
|
12
31
|
|
|
13
|
-
def retrieve_ec2_instances(
|
|
14
|
-
instances = fetch_autoscaling_group_instances(
|
|
32
|
+
def retrieve_ec2_instances(client_options, autoscaling_group_name, aws_ip_type, lifecycle_states)
|
|
33
|
+
instances = fetch_autoscaling_group_instances(client_options, autoscaling_group_name)
|
|
34
|
+
|
|
35
|
+
# Skip instances that are still launching, on standby or being terminated
|
|
36
|
+
skipped = instances.reject { |instance| lifecycle_states.include?(instance.lifecycle_state) }
|
|
37
|
+
skipped.each { |instance| puts("Skipping #{instance.instance_id} (#{instance.lifecycle_state})") }
|
|
38
|
+
instances -= skipped
|
|
15
39
|
|
|
16
40
|
if instances.empty?
|
|
17
41
|
autoscaling_dns = []
|
|
18
42
|
else
|
|
19
43
|
instance_ids = instances.map(&:instance_id)
|
|
20
|
-
ec2 = Aws::EC2::
|
|
44
|
+
ec2 = Aws::EC2::Client.new(client_options)
|
|
21
45
|
# info("Auto Scaling Group instances ids: #{instance_ids}")
|
|
22
46
|
aws_ip_type = 'public_dns_name' unless IP_TYPES.include? aws_ip_type
|
|
23
|
-
|
|
47
|
+
|
|
48
|
+
ec2_instances = ec2.describe_instances(instance_ids: instance_ids).flat_map do |page|
|
|
49
|
+
page.reservations.flat_map(&:instances)
|
|
50
|
+
end.to_h { |instance| [instance.instance_id, instance] }
|
|
51
|
+
|
|
52
|
+
# Keep the Auto Scaling group's order: the first instance gets the primary roles
|
|
24
53
|
autoscaling_dns = instance_ids.map do |instance_id|
|
|
25
|
-
|
|
54
|
+
ec2_instances.fetch(instance_id).send(aws_ip_type.to_sym)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# e.g. public_dns_name is empty for instances in a private subnet
|
|
58
|
+
blank_ids = instance_ids.zip(autoscaling_dns).select { |_, address| address.to_s.strip.empty? }.map(&:first)
|
|
59
|
+
unless blank_ids.empty?
|
|
60
|
+
raise "Instances #{blank_ids.join(', ')} have no #{aws_ip_type}. " \
|
|
61
|
+
"Set :aws_ip_type to one of #{IP_TYPES.join(', ')} (private_ip_address for instances without public addresses)"
|
|
26
62
|
end
|
|
27
63
|
end
|
|
28
64
|
|
|
29
65
|
autoscaling_dns
|
|
30
66
|
end
|
|
31
67
|
|
|
32
|
-
def fetch_autoscaling_group_instances(
|
|
33
|
-
as = Aws::AutoScaling::Client.new(
|
|
68
|
+
def fetch_autoscaling_group_instances(client_options, autoscaling_group_name)
|
|
69
|
+
as = Aws::AutoScaling::Client.new(client_options)
|
|
34
70
|
as_groups = as.describe_auto_scaling_groups(
|
|
35
71
|
auto_scaling_group_names: [autoscaling_group_name],
|
|
36
72
|
max_records: 1,
|
|
@@ -39,6 +75,7 @@ module AwsHelper
|
|
|
39
75
|
# info("Auto Scaling Groups: #{as_groups}")
|
|
40
76
|
|
|
41
77
|
as_group = as_groups[0]
|
|
78
|
+
raise "Auto Scaling group '#{autoscaling_group_name}' not found in #{client_options[:region]}" unless as_group
|
|
42
79
|
|
|
43
80
|
# info("Auto Scaling Group instances: #{as_group.instances}")
|
|
44
81
|
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
module CapHelper
|
|
2
|
+
# Role names can be given as strings (e.g. %w{web app db}); compare them as symbols
|
|
3
|
+
def symbolize_roles(roles)
|
|
4
|
+
roles.map { |role| role.is_a?(String) ? role.to_sym : role }
|
|
5
|
+
end
|
|
6
|
+
|
|
2
7
|
def sanitize_roles(roles)
|
|
3
8
|
# remove :db (for migrations), remove :primary => :true (for assets precompile)
|
|
4
|
-
roles.inject([]){|acc, role|
|
|
9
|
+
symbolize_roles(roles).inject([]){|acc, role|
|
|
5
10
|
if !role.is_a?(Hash)
|
|
6
11
|
acc << role if role != :db
|
|
7
12
|
else
|
|
@@ -5,8 +5,9 @@ namespace :load do
|
|
|
5
5
|
task :defaults do
|
|
6
6
|
set :aws_autoscaling, true
|
|
7
7
|
set :aws_region, 'us-west-2'
|
|
8
|
-
set :aws_deploy_roles, %
|
|
8
|
+
set :aws_deploy_roles, %i{web app db}
|
|
9
9
|
set :aws_ip_type, 'public_dns_name'
|
|
10
|
+
set :aws_lifecycle_states, AwsHelper::LIFECYCLE_STATES
|
|
10
11
|
end
|
|
11
12
|
end
|
|
12
13
|
|
|
@@ -23,11 +24,11 @@ namespace :autoscaling_deploy do
|
|
|
23
24
|
desc 'Add server from Auto Scaling Group.'
|
|
24
25
|
task :setup_instances do
|
|
25
26
|
ec2_instances = fetch_ec2_instances
|
|
26
|
-
aws_deploy_roles = fetch(:aws_deploy_roles)
|
|
27
|
+
aws_deploy_roles = symbolize_roles(fetch(:aws_deploy_roles))
|
|
27
28
|
aws_deploy_user = fetch(:aws_deploy_user)
|
|
28
29
|
|
|
29
|
-
ec2_instances.
|
|
30
|
-
if
|
|
30
|
+
ec2_instances.each_with_index {|instance, index|
|
|
31
|
+
if index == 0
|
|
31
32
|
server instance, user: aws_deploy_user, roles: aws_deploy_roles, primary: true
|
|
32
33
|
puts("First Server: #{instance} - #{aws_deploy_roles}")
|
|
33
34
|
else
|
|
@@ -44,8 +45,14 @@ namespace :autoscaling_deploy do
|
|
|
44
45
|
secret = fetch(:aws_secret_access_key)
|
|
45
46
|
group_name = fetch(:aws_autoscaling_group_name)
|
|
46
47
|
ip_type = fetch(:aws_ip_type)
|
|
48
|
+
profile = fetch(:aws_profile)
|
|
49
|
+
lifecycle_states = fetch(:aws_lifecycle_states)
|
|
47
50
|
|
|
48
|
-
instances = get_instances(region, key, secret, group_name, ip_type)
|
|
51
|
+
instances = get_instances(region, key, secret, group_name, ip_type, aws_profile: profile, lifecycle_states: lifecycle_states)
|
|
52
|
+
|
|
53
|
+
if instances.empty?
|
|
54
|
+
raise "No instances in Auto Scaling group '#{group_name}' with lifecycle state #{lifecycle_states.join(' or ')}"
|
|
55
|
+
end
|
|
49
56
|
|
|
50
57
|
puts("Found #{instances.count} servers (#{instances.join(',')}) for Auto Scaling Group: #{group_name} ")
|
|
51
58
|
|
metadata
CHANGED
|
@@ -1,71 +1,84 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: capistrano3-autoscaling-deploy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Marcos Chicote
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name: aws-sdk
|
|
13
|
+
name: aws-sdk-autoscaling
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
16
|
- - "~>"
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
18
|
+
version: '1'
|
|
20
19
|
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
23
|
- - "~>"
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
25
|
+
version: '1'
|
|
27
26
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
27
|
+
name: aws-sdk-ec2
|
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
|
30
29
|
requirements:
|
|
31
30
|
- - "~>"
|
|
32
31
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
32
|
+
version: '1'
|
|
34
33
|
type: :runtime
|
|
35
34
|
prerelease: false
|
|
36
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
36
|
requirements:
|
|
38
37
|
- - "~>"
|
|
39
38
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
39
|
+
version: '1'
|
|
41
40
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name: capistrano
|
|
41
|
+
name: capistrano
|
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
|
44
43
|
requirements:
|
|
45
44
|
- - "~>"
|
|
46
45
|
- !ruby/object:Gem::Version
|
|
47
|
-
version:
|
|
46
|
+
version: '3'
|
|
48
47
|
type: :runtime
|
|
49
48
|
prerelease: false
|
|
50
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
50
|
requirements:
|
|
52
51
|
- - "~>"
|
|
53
52
|
- !ruby/object:Gem::Version
|
|
54
|
-
version:
|
|
53
|
+
version: '3'
|
|
55
54
|
- !ruby/object:Gem::Dependency
|
|
56
55
|
name: bundler
|
|
57
56
|
requirement: !ruby/object:Gem::Requirement
|
|
58
57
|
requirements:
|
|
59
|
-
- - "
|
|
58
|
+
- - ">="
|
|
60
59
|
- !ruby/object:Gem::Version
|
|
61
|
-
version:
|
|
60
|
+
version: 2.2.33
|
|
62
61
|
type: :development
|
|
63
62
|
prerelease: false
|
|
64
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
64
|
requirements:
|
|
66
|
-
- - "
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: 2.2.33
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: minitest
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
67
80
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
81
|
+
version: '0'
|
|
69
82
|
- !ruby/object:Gem::Dependency
|
|
70
83
|
name: rake
|
|
71
84
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -80,35 +93,31 @@ dependencies:
|
|
|
80
93
|
- - ">="
|
|
81
94
|
- !ruby/object:Gem::Version
|
|
82
95
|
version: '0'
|
|
83
|
-
description:
|
|
84
|
-
|
|
96
|
+
description: Capistrano 3 plugin that finds the in-service instances of an AWS Auto
|
|
97
|
+
Scaling group and deploys to them.
|
|
85
98
|
email:
|
|
86
99
|
- chicotemarcos@gmail.com
|
|
87
100
|
executables: []
|
|
88
101
|
extensions: []
|
|
89
102
|
extra_rdoc_files: []
|
|
90
103
|
files:
|
|
91
|
-
-
|
|
92
|
-
- ".travis.yml"
|
|
93
|
-
- Gemfile
|
|
94
|
-
- Gemfile.lock
|
|
104
|
+
- CHANGELOG.md
|
|
95
105
|
- LICENSE
|
|
96
106
|
- README.md
|
|
97
|
-
- Rakefile
|
|
98
|
-
- capistrano3-autoscaling-deploy.gemspec
|
|
99
107
|
- lib/capistrano/autoscaling_deploy.rb
|
|
100
|
-
- lib/capistrano/autoscaling_deploy/autoscaling_deploy.rb
|
|
101
108
|
- lib/capistrano/autoscaling_deploy/version.rb
|
|
102
109
|
- lib/capistrano/helpers/aws_helper.rb
|
|
103
110
|
- lib/capistrano/helpers/cap_helper.rb
|
|
104
111
|
- lib/capistrano/tasks/autoscaling.rake
|
|
105
112
|
- lib/capistrano3-autoscaling-deploy.rb
|
|
106
|
-
|
|
107
|
-
homepage: https://github.com/mchicote/capistrano3-autoscaling-deploy
|
|
113
|
+
homepage: https://github.com/marcoschicote/capistrano3-autoscaling-deploy
|
|
108
114
|
licenses:
|
|
109
115
|
- MIT
|
|
110
|
-
metadata:
|
|
111
|
-
|
|
116
|
+
metadata:
|
|
117
|
+
source_code_uri: https://github.com/marcoschicote/capistrano3-autoscaling-deploy
|
|
118
|
+
changelog_uri: https://github.com/marcoschicote/capistrano3-autoscaling-deploy/blob/master/CHANGELOG.md
|
|
119
|
+
bug_tracker_uri: https://github.com/marcoschicote/capistrano3-autoscaling-deploy/issues
|
|
120
|
+
rubygems_mfa_required: 'true'
|
|
112
121
|
rdoc_options: []
|
|
113
122
|
require_paths:
|
|
114
123
|
- lib
|
|
@@ -116,17 +125,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
116
125
|
requirements:
|
|
117
126
|
- - ">="
|
|
118
127
|
- !ruby/object:Gem::Version
|
|
119
|
-
version: '
|
|
128
|
+
version: '3.3'
|
|
120
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
130
|
requirements:
|
|
122
131
|
- - ">="
|
|
123
132
|
- !ruby/object:Gem::Version
|
|
124
133
|
version: '0'
|
|
125
134
|
requirements: []
|
|
126
|
-
|
|
127
|
-
rubygems_version: 2.4.5
|
|
128
|
-
signing_key:
|
|
135
|
+
rubygems_version: 4.0.20
|
|
129
136
|
specification_version: 4
|
|
130
137
|
summary: Deploy to AWS Auto Scaling group.
|
|
131
|
-
test_files:
|
|
132
|
-
- test/autoscaling_test.rb
|
|
138
|
+
test_files: []
|
data/.gitignore
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
*.gem
|
|
2
|
-
*.rbc
|
|
3
|
-
/.config
|
|
4
|
-
/coverage/
|
|
5
|
-
/InstalledFiles
|
|
6
|
-
/pkg/
|
|
7
|
-
/spec/reports/
|
|
8
|
-
/spec/examples.txt
|
|
9
|
-
/test/tmp/
|
|
10
|
-
/test/version_tmp/
|
|
11
|
-
/tmp/
|
|
12
|
-
|
|
13
|
-
# Used by dotenv library to load environment variables.
|
|
14
|
-
# .env
|
|
15
|
-
|
|
16
|
-
## Specific to RubyMotion:
|
|
17
|
-
.dat*
|
|
18
|
-
.repl_history
|
|
19
|
-
build/
|
|
20
|
-
*.bridgesupport
|
|
21
|
-
build-iPhoneOS/
|
|
22
|
-
build-iPhoneSimulator/
|
|
23
|
-
|
|
24
|
-
## Specific to RubyMotion (use of CocoaPods):
|
|
25
|
-
#
|
|
26
|
-
# We recommend against adding the Pods directory to your .gitignore. However
|
|
27
|
-
# you should judge for yourself, the pros and cons are mentioned at:
|
|
28
|
-
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
|
29
|
-
#
|
|
30
|
-
# vendor/Pods/
|
|
31
|
-
|
|
32
|
-
## Documentation cache and generated files:
|
|
33
|
-
/.yardoc/
|
|
34
|
-
/_yardoc/
|
|
35
|
-
/doc/
|
|
36
|
-
/rdoc/
|
|
37
|
-
|
|
38
|
-
## Environment normalization:
|
|
39
|
-
/.bundle/
|
|
40
|
-
/vendor/bundle
|
|
41
|
-
/lib/bundler/man/
|
|
42
|
-
|
|
43
|
-
# for a library or gem, you might want to ignore these files since the code is
|
|
44
|
-
# intended to run in multiple environments; otherwise, check them in:
|
|
45
|
-
# Gemfile.lock
|
|
46
|
-
# .ruby-version
|
|
47
|
-
# .ruby-gemset
|
|
48
|
-
|
|
49
|
-
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
50
|
-
.rvmrc
|
|
51
|
-
|
|
52
|
-
# RubyMine folder
|
|
53
|
-
.idea
|
data/.travis.yml
DELETED
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
PATH
|
|
2
|
-
remote: .
|
|
3
|
-
specs:
|
|
4
|
-
capistrano3-autoscaling-deploy (1.3)
|
|
5
|
-
aws-sdk (~> 2)
|
|
6
|
-
capistrano (~> 3)
|
|
7
|
-
capistrano-bundler (~> 1.1.2)
|
|
8
|
-
|
|
9
|
-
GEM
|
|
10
|
-
remote: http://rubygems.org/
|
|
11
|
-
specs:
|
|
12
|
-
airbrussh (1.1.1)
|
|
13
|
-
sshkit (>= 1.6.1, != 1.7.0)
|
|
14
|
-
aws-sdk (2.6.10)
|
|
15
|
-
aws-sdk-resources (= 2.6.10)
|
|
16
|
-
aws-sdk-core (2.6.10)
|
|
17
|
-
jmespath (~> 1.0)
|
|
18
|
-
aws-sdk-resources (2.6.10)
|
|
19
|
-
aws-sdk-core (= 2.6.10)
|
|
20
|
-
capistrano (3.6.1)
|
|
21
|
-
airbrussh (>= 1.0.0)
|
|
22
|
-
capistrano-harrow
|
|
23
|
-
i18n
|
|
24
|
-
rake (>= 10.0.0)
|
|
25
|
-
sshkit (>= 1.9.0)
|
|
26
|
-
capistrano-bundler (1.1.4)
|
|
27
|
-
capistrano (~> 3.1)
|
|
28
|
-
sshkit (~> 1.2)
|
|
29
|
-
capistrano-harrow (0.5.3)
|
|
30
|
-
i18n (0.7.0)
|
|
31
|
-
jmespath (1.3.1)
|
|
32
|
-
net-scp (1.2.1)
|
|
33
|
-
net-ssh (>= 2.6.5)
|
|
34
|
-
net-ssh (3.2.0)
|
|
35
|
-
rake (11.1.2)
|
|
36
|
-
sshkit (1.11.3)
|
|
37
|
-
net-scp (>= 1.1.2)
|
|
38
|
-
net-ssh (>= 2.8.0)
|
|
39
|
-
|
|
40
|
-
PLATFORMS
|
|
41
|
-
ruby
|
|
42
|
-
|
|
43
|
-
DEPENDENCIES
|
|
44
|
-
bundler (~> 1.5)
|
|
45
|
-
capistrano3-autoscaling-deploy!
|
|
46
|
-
rake
|
|
47
|
-
|
|
48
|
-
BUNDLED WITH
|
|
49
|
-
1.12.5
|
data/Rakefile
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
require 'bundler/gem_tasks'
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
-
require 'capistrano/autoscaling_deploy/version'
|
|
5
|
-
|
|
6
|
-
Gem::Specification.new do |spec|
|
|
7
|
-
spec.name = 'capistrano3-autoscaling-deploy'
|
|
8
|
-
spec.version = Capistrano::AutoScalingDeploy::VERSION
|
|
9
|
-
spec.authors = ['Marcos Chicote']
|
|
10
|
-
spec.email = ['chicotemarcos@gmail.com']
|
|
11
|
-
spec.summary = %q{Deploy to AWS Auto Scaling group.}
|
|
12
|
-
spec.description = %q{Get all instances in an AutoScaling group by AutoScaling EC2 Tag and depoy.}
|
|
13
|
-
spec.homepage = 'https://github.com/mchicote/capistrano3-autoscaling-deploy'
|
|
14
|
-
spec.license = 'MIT'
|
|
15
|
-
|
|
16
|
-
spec.files = `git ls-files`.split($/)
|
|
17
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
-
spec.require_paths = ['lib']
|
|
20
|
-
|
|
21
|
-
spec.add_dependency 'aws-sdk', '~> 2'
|
|
22
|
-
spec.add_dependency 'capistrano', '~> 3'
|
|
23
|
-
spec.add_dependency 'capistrano-bundler', '~> 1.2.0'
|
|
24
|
-
spec.add_development_dependency 'bundler', '~> 1.5'
|
|
25
|
-
spec.add_development_dependency 'rake'
|
|
26
|
-
end
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
load File.expand_path('../../tasks/autoscaling.rake', __FILE__)
|
data/test/autoscaling_test.rb
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
require File.expand_path('../lib/localytics', File.dirname(__FILE__))
|
|
2
|
-
require File.expand_path('test_helper', File.dirname(__FILE__))
|
|
3
|
-
|
|
4
|
-
require 'cutest'
|
|
5
|
-
require 'mocha/api'
|
|
6
|
-
include Mocha::API
|
|
7
|
-
|
|
8
|
-
prepare do
|
|
9
|
-
# Prepare Test
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
setup do
|
|
13
|
-
# Setup test
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
test 'autoscale' do |mock|
|
|
17
|
-
# Do Test
|
|
18
|
-
end
|