capistrano-asg 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +1 -0
- data/.travis.yml +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +80 -0
- data/Rakefile +5 -0
- data/capistrano-asg.gemspec +31 -0
- data/lib/capistrano/asg/ami.rb +60 -0
- data/lib/capistrano/asg/aws/autoscaling.rb +36 -0
- data/lib/capistrano/asg/aws/credentials.rb +20 -0
- data/lib/capistrano/asg/aws/ec2.rb +28 -0
- data/lib/capistrano/asg/aws_resource.rb +43 -0
- data/lib/capistrano/asg/launch_configuration.rb +69 -0
- data/lib/capistrano/asg/logger.rb +9 -0
- data/lib/capistrano/asg/retryable.rb +18 -0
- data/lib/capistrano/asg/taggable.rb +12 -0
- data/lib/capistrano/asg/tasks/asg.rake +17 -0
- data/lib/capistrano/asg/version.rb +5 -0
- data/lib/capistrano/asg.rb +56 -0
- data/lib/capistrano-asg.rb +0 -0
- data/spec/ami_spec.rb +11 -0
- data/spec/asg_spec.rb +69 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/stubs/CreateImage.200.xml +4 -0
- data/spec/support/stubs/CreateLaunchConfiguration.200.xml +5 -0
- data/spec/support/stubs/CreateTags.200.xml +4 -0
- data/spec/support/stubs/DeleteLaunchConfiguration.200.xml +5 -0
- data/spec/support/stubs/DeleteSnapshot.200.xml +4 -0
- data/spec/support/stubs/DeregisterImage.200.xml +4 -0
- data/spec/support/stubs/DescribeAutoScalingGroups.200.xml +21 -0
- data/spec/support/stubs/DescribeImages.200.xml +44 -0
- data/spec/support/stubs/DescribeInstances.200.xml +124 -0
- data/spec/support/stubs/DescribeLaunchConfigurations.200.xml +29 -0
- data/spec/support/stubs/DescribeSnapshots.200.xml +27 -0
- data/spec/support/stubs/DescribeTags.200.xml +17 -0
- data/spec/support/stubs/UpdateAutoScalingGroup.200.xml +5 -0
- data/spec/support/stubs/security-credentials.200.json +9 -0
- metadata +203 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 65590a9ec7bb5ea9e7989900db32e3186d113dc1
|
4
|
+
data.tar.gz: 1de9dbe90e304d5bf31a46444fbd912d0445bbce
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e7318766a16a55a0a8668e55fe0efaee988ea7e1ba7a6635fdcaf5b6b5158b01458d7617aa0dd13afc8995d891c65cae2011cb62c70177a68a3a67fa2c077f8d
|
7
|
+
data.tar.gz: d656273906059100458d400dd04ec9f539b3f5d62f4dfa2afa9e2c6250bd3482b076b4d94639fad5fbc68fad9ad8a327885ff3ff38c5269633c777cc16002b9d
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
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,80 @@
|
|
1
|
+
# capistrano-asg
|
2
|
+
|
3
|
+
This is a fork of [lserman/capistrano-elbas](https://github.com/lserman/capistrano-elbas), updated with new features and Capistrano 3 conventions.
|
4
|
+
|
5
|
+
capistrano-asg was written to ease the deployment of Rails applications to AWS AutoScale groups. capistrano-asg will:
|
6
|
+
|
7
|
+
- Deploy your code to each running instance connected to a given AutoScale group
|
8
|
+
- After deployment, create an AMI from one of the running instances
|
9
|
+
- Attach the AMI with the new code to a new AWS Launch Configuration
|
10
|
+
- Update your AutoScale group to use the new launch configuration
|
11
|
+
- Delete any old AMIs created by capistrano-asg
|
12
|
+
- Delete any old launch configurations created by capistrano-asg
|
13
|
+
|
14
|
+
This ensures that your current and future servers will be running the newly deployed code.
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
`gem 'capistrano-asg'`
|
19
|
+
|
20
|
+
Add this statement to your Capfile:
|
21
|
+
|
22
|
+
`require 'capistrano/asg'`
|
23
|
+
|
24
|
+
## Configuration
|
25
|
+
|
26
|
+
Below are the Capistrano configuration options with their defaults:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
set :aws_access_key_id, ENV['AWS_ACCESS_KEY_ID']
|
30
|
+
set :aws_secret_access_key, ENV['AWS_SECRET_ACCESS_KEY']
|
31
|
+
set :aws_region, ENV['AWS_REGION']
|
32
|
+
|
33
|
+
set :aws_no_reboot_on_create_ami, true
|
34
|
+
set :aws_autoscale_instance_size, 'm1.small'
|
35
|
+
|
36
|
+
set :aws_launch_configuration_detailed_instance_monitoring, true
|
37
|
+
set :aws_launch_configuration_associate_public_ip, true
|
38
|
+
```
|
39
|
+
|
40
|
+
## Usage
|
41
|
+
|
42
|
+
Instead of using Capistrano's `server` method, use `autoscale` instead in `deploy/production.rb` (or
|
43
|
+
whichever environment you're deploying to). Provide the name of your AutoScale group instead of a
|
44
|
+
hostname:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
autoscale 'production', user: 'apps', roles: [:app, :web, :db]
|
48
|
+
```
|
49
|
+
|
50
|
+
If you have multiple autoscaling groups to deploy to, specify each of them:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
autoscale 'asg-app', user: 'apps', roles: [:app, :web]
|
54
|
+
autoscale 'asg-db', user: 'apps', roles: [:db]
|
55
|
+
```
|
56
|
+
|
57
|
+
Similarly, if you are deploying to multiple regions:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
regions = %w(us-east-1 eu-west-1)
|
61
|
+
|
62
|
+
regions.each do |region|
|
63
|
+
set :aws_region, region
|
64
|
+
autoscale 'production', user: 'apps', roles: [:app, :web, :db]
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
That's it! Run `cap production deploy`. The following log statements are printed
|
69
|
+
during deployment:
|
70
|
+
|
71
|
+
```
|
72
|
+
Autoscaling: Adding server: ec2-XX-XX-XX-XXX.compute-1.amazonaws.com
|
73
|
+
Autoscaling: Creating EC2 AMI from i-123abcd
|
74
|
+
Autoscaling: Created AMI: ami-123456
|
75
|
+
Autoscaling: Creating an EC2 Launch Configuration for AMI: ami-123456
|
76
|
+
Autoscaling: Created Launch Configuration: cap-asg-lc-ENVIRONMENT-UNIX_TIMESTAMP
|
77
|
+
Autoscaling: Attaching Launch Configuration to AutoScale Group
|
78
|
+
Autoscaling: Deleting old launch configuration: cap-asg-lc-production-123456
|
79
|
+
Autoscaling: Deleting old image: ami-999999
|
80
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
lib = File.expand_path('../lib', __FILE__)
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
require 'capistrano/asg/version'
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = 'capistrano-asg'
|
10
|
+
spec.version = Capistrano::Asg::VERSION
|
11
|
+
spec.authors = ['Logan Serman', 'Jeff Fraser', 'Michael Martell']
|
12
|
+
spec.email = ['logan.serman@metova.com', 'jeff.fraser@veracross.com', 'michael.martell@veracross.com']
|
13
|
+
spec.summary = 'Capistrano plugin for deploying to AWS AutoScale Groups.'
|
14
|
+
spec.description = "#{spec.summary} Deploys to all instances in a group, creates a fresh AMI post-deploy, and attaches the AMI to your AutoScale Group."
|
15
|
+
spec.homepage = 'http://github.com/sixfeetover/capistrano-asg'
|
16
|
+
spec.license = 'MIT'
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0")
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ['lib']
|
22
|
+
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
24
|
+
spec.add_development_dependency 'rake'
|
25
|
+
spec.add_development_dependency 'rspec'
|
26
|
+
spec.add_development_dependency 'webmock'
|
27
|
+
|
28
|
+
spec.add_dependency 'aws-sdk', '~> 2'
|
29
|
+
spec.add_dependency 'capistrano', '> 3.0.0'
|
30
|
+
spec.add_dependency 'activesupport', '>= 4.0.0'
|
31
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Capistrano
|
2
|
+
module Asg
|
3
|
+
# Extend AWS Resource class to include AMI methods
|
4
|
+
class AMI < AWSResource
|
5
|
+
include Taggable
|
6
|
+
|
7
|
+
def self.create(&_block)
|
8
|
+
ami = new
|
9
|
+
ami.cleanup do
|
10
|
+
ami.save
|
11
|
+
ami.tag 'deployed-with' => 'cap-asg'
|
12
|
+
ami.tag 'cap-asg-deploy-group' => ami.autoscaling_group_name
|
13
|
+
yield ami
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def save
|
18
|
+
info "Creating EC2 AMI from EC2 Instance: #{base_ec2_instance.id}"
|
19
|
+
ec2_instance = ec2_resource.instance(base_ec2_instance.id)
|
20
|
+
@aws_counterpart = ec2_instance.create_image(
|
21
|
+
name: name,
|
22
|
+
no_reboot: fetch(:aws_no_reboot_on_create_ami, true)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def destroy(images = [])
|
27
|
+
images.each do |i|
|
28
|
+
info "Deleting old AMI: #{i.id}"
|
29
|
+
snapshots = snapshots_attached_to i
|
30
|
+
i.deregister
|
31
|
+
delete_snapshots snapshots
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def name
|
38
|
+
timestamp "latest-#{environment}-AMI"
|
39
|
+
end
|
40
|
+
|
41
|
+
def trash
|
42
|
+
ec2_resource.images(owners: ['self']).to_a.select do |ami|
|
43
|
+
deployed_with_asg? ami
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def snapshots_attached_to(image)
|
48
|
+
ids = image.block_device_mappings.map(&:ebs).compact.map(&:snapshot_id)
|
49
|
+
ec2_resource.snapshots(snapshot_ids: ids)
|
50
|
+
end
|
51
|
+
|
52
|
+
def delete_snapshots(snapshots)
|
53
|
+
snapshots.each do |snapshot|
|
54
|
+
info "Deleting snapshot: #{snapshot.id}"
|
55
|
+
snapshot.delete unless snapshot.nil?
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module Asg
|
5
|
+
module Aws
|
6
|
+
# Provide AutoScaling client, resource, and group information
|
7
|
+
module AutoScaling
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
include Credentials
|
10
|
+
include Capistrano::DSL
|
11
|
+
|
12
|
+
def autoscaling_client
|
13
|
+
@_autoscaling_client ||= ::Aws::AutoScaling::Client.new(credentials)
|
14
|
+
end
|
15
|
+
|
16
|
+
def autoscaling_resource
|
17
|
+
@_autoscaling_resource ||= ::Aws::AutoScaling::Resource.new(client: autoscaling_client)
|
18
|
+
end
|
19
|
+
|
20
|
+
def autoscaling_group
|
21
|
+
@_autoscaling_group ||= autoscaling_resource.group(autoscaling_group_name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def autoscaling_group_name
|
25
|
+
fetch(:aws_autoscale_group)
|
26
|
+
end
|
27
|
+
|
28
|
+
def reset_autoscaling_objects
|
29
|
+
@_autoscaling_client = nil
|
30
|
+
@_autoscaling_resource = nil
|
31
|
+
@_autoscaling_group = nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module Asg
|
5
|
+
module Aws
|
6
|
+
module Credentials
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
include Capistrano::DSL
|
9
|
+
|
10
|
+
def credentials
|
11
|
+
{
|
12
|
+
access_key_id: fetch(:aws_access_key_id, ENV['AWS_ACCESS_KEY_ID']),
|
13
|
+
secret_access_key: fetch(:aws_secret_access_key, ENV['AWS_SECRET_ACCESS_KEY']),
|
14
|
+
region: fetch(:aws_region, ENV['AWS_REGION'])
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module Asg
|
5
|
+
module Aws
|
6
|
+
# Provide EC2 client and resource information
|
7
|
+
module EC2
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
include Credentials
|
10
|
+
include Capistrano::DSL
|
11
|
+
|
12
|
+
def ec2_resource
|
13
|
+
@_ec2_resource ||= ::Aws::EC2::Resource.new(client: ec2_client)
|
14
|
+
end
|
15
|
+
|
16
|
+
def reset_ec2_objects
|
17
|
+
@_ec2_resource = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def ec2_client
|
23
|
+
::Aws::EC2::Client.new(credentials)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capistrano
|
4
|
+
module Asg
|
5
|
+
# Provides basic AWS resource methods
|
6
|
+
class AWSResource
|
7
|
+
include Capistrano::DSL
|
8
|
+
include Capistrano::Asg::Aws::AutoScaling
|
9
|
+
include Capistrano::Asg::Aws::EC2
|
10
|
+
include Capistrano::Asg::Retryable
|
11
|
+
include Logger
|
12
|
+
|
13
|
+
attr_reader :aws_counterpart
|
14
|
+
|
15
|
+
def cleanup(&_block)
|
16
|
+
items = trash || []
|
17
|
+
yield
|
18
|
+
destroy items
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def base_ec2_instance
|
25
|
+
autoscaling_group.instances[0]
|
26
|
+
end
|
27
|
+
|
28
|
+
def environment
|
29
|
+
fetch(:rails_env, 'production')
|
30
|
+
end
|
31
|
+
|
32
|
+
def timestamp(str)
|
33
|
+
"#{str}-#{Time.now.to_i}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def deployed_with_asg?(resource)
|
37
|
+
return false if resource.tags.empty?
|
38
|
+
resource.tags.any? { |k| k.key == 'deployed-with' && k.value == 'cap-asg' } &&
|
39
|
+
resource.tags.any? { |k| k.key == 'cap-asg-deploy-group' && k.value == autoscaling_group_name }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Capistrano
|
2
|
+
module Asg
|
3
|
+
# Create launch configuration
|
4
|
+
class LaunchConfiguration < AWSResource
|
5
|
+
def self.create(ami, &_block)
|
6
|
+
lc = new
|
7
|
+
lc.cleanup do
|
8
|
+
lc.save(ami)
|
9
|
+
yield lc
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def save(ami)
|
14
|
+
info "Creating an EC2 Launch Configuration for AMI: \
|
15
|
+
#{ami.aws_counterpart.id}"
|
16
|
+
ec2_instance = ec2_resource.instance(base_ec2_instance.id)
|
17
|
+
with_retry do
|
18
|
+
@aws_counterpart = autoscaling_resource.create_launch_configuration(
|
19
|
+
launch_configuration_name: name,
|
20
|
+
image_id: ami.aws_counterpart.id,
|
21
|
+
instance_type: instance_size,
|
22
|
+
security_groups: ec2_instance.security_groups.map(&:group_id),
|
23
|
+
associate_public_ip_address:
|
24
|
+
fetch(:aws_launch_configuration_associate_public_ip, true),
|
25
|
+
instance_monitoring: {
|
26
|
+
enabled: fetch(:aws_launch_configuration_detailed_instance_monitoring, true)
|
27
|
+
},
|
28
|
+
user_data: fetch(:aws_launch_configuration_user_data, nil)
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def attach_to_autoscale_group!
|
34
|
+
info "Attaching Launch Configuration #{aws_counterpart.name} \
|
35
|
+
to AutoScaling Group #{autoscaling_group.name}"
|
36
|
+
autoscaling_group.update(
|
37
|
+
launch_configuration_name: aws_counterpart.name
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def destroy(launch_configurations = [])
|
42
|
+
launch_configurations.each do |lc|
|
43
|
+
info "Deleting old Launch Configuration: #{lc.name}"
|
44
|
+
lc.delete
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def name
|
51
|
+
timestamp "cap-asg-#{environment}-#{autoscaling_group_name}-lc"
|
52
|
+
end
|
53
|
+
|
54
|
+
def instance_size
|
55
|
+
fetch(:aws_autoscale_instance_size, 'm1.small')
|
56
|
+
end
|
57
|
+
|
58
|
+
def deployed_with_asg?(lc)
|
59
|
+
lc.name.include? "cap-asg-#{environment}-#{autoscaling_group_name}-lc"
|
60
|
+
end
|
61
|
+
|
62
|
+
def trash
|
63
|
+
autoscaling_resource.launch_configurations.to_a.select do |lc|
|
64
|
+
deployed_with_asg? lc
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Capistrano
|
2
|
+
module Asg
|
3
|
+
module Retryable
|
4
|
+
def with_retry(max: fetch(:asg_retry_max, 3), delay: fetch(:asg_retry_delay, 5))
|
5
|
+
tries ||= 0
|
6
|
+
tries += 1
|
7
|
+
yield
|
8
|
+
rescue => e
|
9
|
+
puts "Rescued #{e.message}"
|
10
|
+
if tries < max
|
11
|
+
puts "Retrying in #{delay} seconds..."
|
12
|
+
sleep delay
|
13
|
+
retry
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'capistrano/asg'
|
2
|
+
|
3
|
+
namespace :asg do
|
4
|
+
task :scale do
|
5
|
+
set :aws_access_key_id, fetch(:aws_access_key_id, ENV['AWS_ACCESS_KEY_ID'])
|
6
|
+
set :aws_secret_access_key, fetch(:aws_secret_access_key, ENV['AWS_SECRET_ACCESS_KEY'])
|
7
|
+
set :aws_region, fetch(:aws_region, ENV['AWS_REGION'])
|
8
|
+
|
9
|
+
Capistrano::Asg::AMI.create do |ami|
|
10
|
+
puts "Autoscaling: Created AMI: #{ami.aws_counterpart.id}"
|
11
|
+
Capistrano::Asg::LaunchConfiguration.create(ami) do |lc|
|
12
|
+
puts "Autoscaling: Created Launch Configuration: #{lc.aws_counterpart.name}"
|
13
|
+
lc.attach_to_autoscale_group!
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'capistrano/all'
|
3
|
+
require 'active_support/concern'
|
4
|
+
|
5
|
+
require 'capistrano/asg/version'
|
6
|
+
require 'capistrano/asg/retryable'
|
7
|
+
require 'capistrano/asg/taggable'
|
8
|
+
require 'capistrano/asg/logger'
|
9
|
+
require 'capistrano/asg/aws/credentials'
|
10
|
+
require 'capistrano/asg/aws/autoscaling'
|
11
|
+
require 'capistrano/asg/aws/ec2'
|
12
|
+
require 'capistrano/asg/aws_resource'
|
13
|
+
require 'capistrano/asg/ami'
|
14
|
+
require 'capistrano/asg/launch_configuration'
|
15
|
+
|
16
|
+
module Capistrano
|
17
|
+
module Asg
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'aws-sdk'
|
22
|
+
require 'capistrano/dsl'
|
23
|
+
|
24
|
+
load File.expand_path('../asg/tasks/asg.rake', __FILE__)
|
25
|
+
|
26
|
+
def autoscale(groupname, *args)
|
27
|
+
include Capistrano::DSL
|
28
|
+
include Capistrano::Asg::Aws::AutoScaling
|
29
|
+
include Capistrano::Asg::Aws::EC2
|
30
|
+
|
31
|
+
autoscaling_group = autoscaling_resource.group(groupname)
|
32
|
+
asg_instances = autoscaling_group.instances
|
33
|
+
|
34
|
+
set :aws_autoscale_group, groupname
|
35
|
+
|
36
|
+
asg_instances.each do |asg_instance|
|
37
|
+
if asg_instance.health_status != 'Healthy'
|
38
|
+
puts "Autoscaling: Skipping unhealthy instance #{instance.id}"
|
39
|
+
else
|
40
|
+
ec2_instance = ec2_resource.instance(asg_instance.id)
|
41
|
+
hostname = ec2_instance.private_ip_address
|
42
|
+
puts "Autoscaling: Adding server #{hostname}"
|
43
|
+
server(hostname, *args)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if asg_instances.count > 0
|
48
|
+
after('deploy', 'asg:scale')
|
49
|
+
else
|
50
|
+
puts 'Autoscaling: AMI could not be created because no running instances were found.\
|
51
|
+
Is your autoscale group name correct?'
|
52
|
+
end
|
53
|
+
|
54
|
+
reset_autoscaling_objects
|
55
|
+
reset_ec2_objects
|
56
|
+
end
|
File without changes
|
data/spec/ami_spec.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
describe Capistrano::Asg::AMI do
|
2
|
+
describe '#tag' do
|
3
|
+
subject { Capistrano::Asg::AMI.new }
|
4
|
+
|
5
|
+
it 'retries the tag 3 times' do
|
6
|
+
skip
|
7
|
+
expect(subject).to receive(:aws_counterpart).exactly(3).times { raise RuntimeError }
|
8
|
+
subject.tag 'Test' => true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/spec/asg_spec.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
describe 'Capistrano::Asg' do
|
2
|
+
before do
|
3
|
+
allow_any_instance_of(Capistrano::Asg::AWSResource).to receive(:autoscaling_group_name) { 'production' }
|
4
|
+
webmock :get, /security-credentials/ => 'security-credentials.200.json'
|
5
|
+
webmock(:post, %r{autoscaling.(.*).amazonaws.com\/\z} => 'DescribeAutoScalingGroups.200.xml') { Hash[body: /Action=DescribeAutoScalingGroups/] }
|
6
|
+
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'DescribeImages.200.xml') { Hash[body: /Action=DescribeImages/] }
|
7
|
+
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'DescribeTags.200.xml') { Hash[body: /Action=DescribeTags/] }
|
8
|
+
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'DescribeInstances.200.xml') { Hash[body: /Action=DescribeInstances/] }
|
9
|
+
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'CreateImage.200.xml') { Hash[body: /Action=CreateImage/] }
|
10
|
+
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'DeregisterImage.200.xml') { Hash[body: /Action=DeregisterImage/] }
|
11
|
+
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'CreateTags.200.xml') { Hash[body: /Action=CreateTags/] }
|
12
|
+
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'DescribeSnapshots.200.xml') { Hash[body: /Action=DescribeSnapshots/] }
|
13
|
+
webmock(:post, %r{ec2.(.*).amazonaws.com\/\z} => 'DeleteSnapshot.200.xml') { Hash[body: /Action=DeleteSnapshot/] }
|
14
|
+
webmock(:post, %r{autoscaling.(.*).amazonaws.com\/\z} => 'DescribeLaunchConfigurations.200.xml') { Hash[body: /Action=DescribeLaunchConfigurations/] }
|
15
|
+
webmock(:post, %r{autoscaling.(.*).amazonaws.com\/\z} => 'CreateLaunchConfiguration.200.xml') { Hash[body: /Action=CreateLaunchConfiguration/] }
|
16
|
+
webmock(:post, %r{autoscaling.(.*).amazonaws.com\/\z} => 'DeleteLaunchConfiguration.200.xml') { Hash[body: /Action=DeleteLaunchConfiguration/] }
|
17
|
+
webmock(:post, %r{autoscaling.(.*).amazonaws.com\/\z} => 'UpdateAutoScalingGroup.200.xml') { Hash[body: /Action=UpdateAutoScalingGroup/] }
|
18
|
+
end
|
19
|
+
|
20
|
+
let!(:ami) do
|
21
|
+
_ami = nil
|
22
|
+
Capistrano::Asg::AMI.create { |ami| _ami = ami }
|
23
|
+
_ami
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'AMI creation & cleanup' do
|
27
|
+
it 'creates a new AMI on Amazon' do
|
28
|
+
expect(ami.aws_counterpart.id).to eq 'ami-4fa54026'
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'deletes any AMIs tagged with deployed-with=cap-asg' do
|
32
|
+
expect(WebMock).to have_requested(:post, /ec2.(.*).amazonaws.com\/\z/).with(body: /Action=DeregisterImage&ImageId=ami-1a2b3c4d/)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'deletes snapshots that are associated with the AMI' do
|
36
|
+
expect(WebMock).to have_requested(:post, /ec2.(.*).amazonaws.com\/\z/).with(body: /Action=DeleteSnapshot&SnapshotId=snap-1a2b3c4d/)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'tags the new AMI with deployed-with=cap-asg' do
|
40
|
+
expect(WebMock).to have_requested(:post, /ec2.(.*).amazonaws.com\/\z/).with(body: /Action=CreateTags&ResourceId.1=ami-4fa54026&Tag.1.Key=deployed-with&Tag.1.Value=cap-asg/)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'tags the new AMI with cap-asg-Deploy-group=<autoscale group name>' do
|
44
|
+
expect(WebMock).to have_requested(:post, /ec2.(.*).amazonaws.com\/\z/).with(body: /Action=CreateTags&ResourceId.1=ami-4fa54026&Tag.1.Key=cap-asg-deploy-group&Tag.1.Value=production/)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'Launch configuration creation & cleanup' do
|
49
|
+
let!(:launch_configuration) do
|
50
|
+
_lc = nil
|
51
|
+
Capistrano::Asg::LaunchConfiguration.create(ami) { |lc| _lc = lc }
|
52
|
+
_lc
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'creates a new Launch Configuration on AWS' do
|
56
|
+
expect(WebMock).to have_requested(:post, /autoscaling.(.*).amazonaws.com\/\z/).
|
57
|
+
with(body: /Action=CreateLaunchConfiguration&AssociatePublicIpAddress=true&ImageId=ami-4fa54026&InstanceMonitoring.Enabled=true&InstanceType=m1.small&LaunchConfigurationName=cap-asg-production/)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'deletes any LCs with name =~ cap-asg-production' do
|
61
|
+
expect(WebMock).to have_requested(:post, /autoscaling.(.*).amazonaws.com\/\z/).with(body: /Action=DeleteLaunchConfiguration&LaunchConfigurationName=cap-asg-production-production-lc-1234567890/)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'attaches the LC to the autoscale group' do
|
65
|
+
launch_configuration.attach_to_autoscale_group!
|
66
|
+
expect(WebMock).to have_requested(:post, /autoscaling.(.*).amazonaws.com\/\z/).with(body: /Action=UpdateAutoScalingGroup&AutoScalingGroupName=production&LaunchConfigurationName=cap-asg-production-production-lc-\d{10,}/)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'webmock'
|
2
|
+
require 'capistrano/all'
|
3
|
+
require 'capistrano/asg'
|
4
|
+
require 'webmock/rspec'
|
5
|
+
|
6
|
+
WebMock.disable_net_connect!
|
7
|
+
|
8
|
+
Dir[File.join(File.expand_path('../..', __FILE__), 'spec', 'support', '**', '*.rb')].each { |f| require f }
|
9
|
+
|
10
|
+
module WebMock
|
11
|
+
module RSpec
|
12
|
+
module Helper
|
13
|
+
|
14
|
+
def webmock(method, mocks = {})
|
15
|
+
mocks.each do |regex, filename|
|
16
|
+
status = filename[/\.(\d+)\./, 1] || 200
|
17
|
+
body = File.read File.join(File.expand_path('../..', __FILE__), 'spec', 'support', 'stubs', filename)
|
18
|
+
if block_given? && with_options = yield
|
19
|
+
WebMock.stub_request(method, regex).with(with_options).to_return status: status.to_i, body: body
|
20
|
+
else
|
21
|
+
WebMock.stub_request(method, regex).to_return status: status.to_i, body: body
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
RSpec.configure do |config|
|
31
|
+
config.include WebMock::RSpec::Helper
|
32
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<DescribeAutoScalingGroupsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
2
|
+
<ResponseMetadata>
|
3
|
+
<RequestId>7c6e177f-f082-11e1-ac58-3714bEXAMPLE</RequestId>
|
4
|
+
</ResponseMetadata>
|
5
|
+
<DescribeAutoScalingGroupsResult>
|
6
|
+
<AutoScalingGroups>
|
7
|
+
<member>
|
8
|
+
<AutoScalingGroupName>production</AutoScalingGroupName>
|
9
|
+
<Instances>
|
10
|
+
<member>
|
11
|
+
<LaunchConfigurationName>cap-asg-production-production-lc-1234567890</LaunchConfigurationName>
|
12
|
+
<LifecycleState>InService</LifecycleState>
|
13
|
+
<InstanceId>i-1a2b3c4d</InstanceId>
|
14
|
+
<ProtectedFromScaleIn>false</ProtectedFromScaleIn>
|
15
|
+
<AvailabilityZone>us-west-2a</AvailabilityZone>
|
16
|
+
</member>
|
17
|
+
</Instances>
|
18
|
+
</member>
|
19
|
+
</AutoScalingGroups>
|
20
|
+
</DescribeAutoScalingGroupsResult>
|
21
|
+
</DescribeAutoScalingGroupsResponse>
|
@@ -0,0 +1,44 @@
|
|
1
|
+
<DescribeImagesResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
|
2
|
+
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
|
3
|
+
<imagesSet>
|
4
|
+
<item>
|
5
|
+
<imageId>ami-1a2b3c4d</imageId>
|
6
|
+
<imageLocation>amazon/getting-started</imageLocation>
|
7
|
+
<imageState>available</imageState>
|
8
|
+
<imageOwnerId>123456789012</imageOwnerId>
|
9
|
+
<isPublic>true</isPublic>
|
10
|
+
<architecture>i386</architecture>
|
11
|
+
<imageType>machine</imageType>
|
12
|
+
<kernelId>aki-1a2b3c4d</kernelId>
|
13
|
+
<ramdiskId>ari-1a2b3c4d</ramdiskId>
|
14
|
+
<imageOwnerAlias>self</imageOwnerAlias>
|
15
|
+
<name>getting-started</name>
|
16
|
+
<description>Image Description</description>
|
17
|
+
<rootDeviceType>ebs</rootDeviceType>
|
18
|
+
<rootDeviceName>/dev/sda</rootDeviceName>
|
19
|
+
<blockDeviceMapping>
|
20
|
+
<item>
|
21
|
+
<deviceName>/dev/sda1</deviceName>
|
22
|
+
<ebs>
|
23
|
+
<snapshotId>snap-1a2b3c4d</snapshotId>
|
24
|
+
<volumeSize>15</volumeSize>
|
25
|
+
<deleteOnTermination>false</deleteOnTermination>
|
26
|
+
<volumeType>standard</volumeType>
|
27
|
+
</ebs>
|
28
|
+
</item>
|
29
|
+
</blockDeviceMapping>
|
30
|
+
<virtualizationType>paravirtual</virtualizationType>
|
31
|
+
<tagSet>
|
32
|
+
<item>
|
33
|
+
<key>deployed-with</key>
|
34
|
+
<value>cap-asg</value>
|
35
|
+
</item>
|
36
|
+
<item>
|
37
|
+
<key>cap-asg-deploy-group</key>
|
38
|
+
<value>production</value>
|
39
|
+
</item>
|
40
|
+
</tagSet>
|
41
|
+
<hypervisor>xen</hypervisor>
|
42
|
+
</item>
|
43
|
+
</imagesSet>
|
44
|
+
</DescribeImagesResponse>
|
@@ -0,0 +1,124 @@
|
|
1
|
+
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2014-10-01/">
|
2
|
+
<requestId>fdcdcab1-ae5c-489e-9c33-4637c5dda355</requestId>
|
3
|
+
<reservationSet>
|
4
|
+
<item>
|
5
|
+
<reservationId>r-1a2b3c4d</reservationId>
|
6
|
+
<ownerId>123456789012</ownerId>
|
7
|
+
<groupSet>
|
8
|
+
<item>
|
9
|
+
<groupId>sg-1a2b3c4d</groupId>
|
10
|
+
<groupName>my-security-group</groupName>
|
11
|
+
</item>
|
12
|
+
</groupSet>
|
13
|
+
<instancesSet>
|
14
|
+
<item>
|
15
|
+
<instanceId>i-1a2b3c4d</instanceId>
|
16
|
+
<imageId>ami-1a2b3c4d</imageId>
|
17
|
+
<instanceState>
|
18
|
+
<code>16</code>
|
19
|
+
<name>running</name>
|
20
|
+
</instanceState>
|
21
|
+
<privateDnsName/>
|
22
|
+
<dnsName/>
|
23
|
+
<reason/>
|
24
|
+
<keyName>my-key-pair</keyName>
|
25
|
+
<amiLaunchIndex>0</amiLaunchIndex>
|
26
|
+
<productCodes/>
|
27
|
+
<instanceType>c1.medium</instanceType>
|
28
|
+
<launchTime>Y2035-02-09T23:17:13Z+0000</launchTime>
|
29
|
+
<placement>
|
30
|
+
<availabilityZone>us-west-2a</availabilityZone>
|
31
|
+
<groupName/>
|
32
|
+
<tenancy>default</tenancy>
|
33
|
+
</placement>
|
34
|
+
<platform>windows</platform>
|
35
|
+
<monitoring>
|
36
|
+
<state>disabled</state>
|
37
|
+
</monitoring>
|
38
|
+
<subnetId>subnet-1a2b3c4d</subnetId>
|
39
|
+
<vpcId>vpc-1a2b3c4d</vpcId>
|
40
|
+
<privateIpAddress>10.0.0.12</privateIpAddress>
|
41
|
+
<ipAddress>46.51.219.63</ipAddress>
|
42
|
+
<sourceDestCheck>true</sourceDestCheck>
|
43
|
+
<groupSet>
|
44
|
+
<item>
|
45
|
+
<groupId>sg-1a2b3c4d</groupId>
|
46
|
+
<groupName>my-security-group</groupName>
|
47
|
+
</item>
|
48
|
+
</groupSet>
|
49
|
+
<architecture>x86_64</architecture>
|
50
|
+
<rootDeviceType>ebs</rootDeviceType>
|
51
|
+
<rootDeviceName>/dev/sda1</rootDeviceName>
|
52
|
+
<blockDeviceMapping>
|
53
|
+
<item>
|
54
|
+
<deviceName>/dev/sda1</deviceName>
|
55
|
+
<ebs>
|
56
|
+
<volumeId>vol-1a2b3c4d</volumeId>
|
57
|
+
<status>attached</status>
|
58
|
+
<attachTime>2035-02-09T23:17:13Z</attachTime>
|
59
|
+
<deleteOnTermination>true</deleteOnTermination>
|
60
|
+
</ebs>
|
61
|
+
</item>
|
62
|
+
</blockDeviceMapping>
|
63
|
+
<virtualizationType>hvm</virtualizationType>
|
64
|
+
<clientToken>ABCDE1234567890123</clientToken>
|
65
|
+
<tagSet>
|
66
|
+
<item>
|
67
|
+
<key>Name</key>
|
68
|
+
<value>Windows Instance</value>
|
69
|
+
</item>
|
70
|
+
</tagSet>
|
71
|
+
<hypervisor>xen</hypervisor>
|
72
|
+
<networkInterfaceSet>
|
73
|
+
<item>
|
74
|
+
<networkInterfaceId>eni-1a2b3c4d</networkInterfaceId>
|
75
|
+
<subnetId>subnet-1a2b3c4d</subnetId>
|
76
|
+
<vpcId>vpc-1a2b3c4d</vpcId>
|
77
|
+
<description>Primary network interface</description>
|
78
|
+
<ownerId>123456789012</ownerId>
|
79
|
+
<status>in-use</status>
|
80
|
+
<macAddress>1b:2b:3c:4d:5e:6f</macAddress>
|
81
|
+
<privateIpAddress>10.0.0.12</privateIpAddress>
|
82
|
+
<sourceDestCheck>true</sourceDestCheck>
|
83
|
+
<groupSet>
|
84
|
+
<item>
|
85
|
+
<groupId>sg-1a2b3c4d</groupId>
|
86
|
+
<groupName>my-security-group</groupName>
|
87
|
+
</item>
|
88
|
+
</groupSet>
|
89
|
+
<attachment>
|
90
|
+
<attachmentId>eni-attach-1a2b3c4d</attachmentId>
|
91
|
+
<deviceIndex>0</deviceIndex>
|
92
|
+
<status>attached</status>
|
93
|
+
<attachTime>2035-02-09T23:17:13Z</attachTime>
|
94
|
+
<deleteOnTermination>true</deleteOnTermination>
|
95
|
+
</attachment>
|
96
|
+
<association>
|
97
|
+
<publicIp>198.51.100.63</publicIp>
|
98
|
+
<ipOwnerId>123456789012</ipOwnerId>
|
99
|
+
</association>
|
100
|
+
<privateIpAddressesSet>
|
101
|
+
<item>
|
102
|
+
<privateIpAddress>10.0.0.12</privateIpAddress>
|
103
|
+
<primary>true</primary>
|
104
|
+
<association>
|
105
|
+
<publicIp>198.51.100.63</publicIp>
|
106
|
+
<ipOwnerId>123456789012</ipOwnerId>
|
107
|
+
</association>
|
108
|
+
</item>
|
109
|
+
<item>
|
110
|
+
<privateIpAddress>10.0.0.14</privateIpAddress>
|
111
|
+
<primary>false</primary>
|
112
|
+
<association>
|
113
|
+
<publicIp>198.51.100.177</publicIp>
|
114
|
+
<ipOwnerId>123456789012</ipOwnerId>
|
115
|
+
</association>
|
116
|
+
</item>
|
117
|
+
</privateIpAddressesSet>
|
118
|
+
</item>
|
119
|
+
</networkInterfaceSet>
|
120
|
+
</item>
|
121
|
+
</instancesSet>
|
122
|
+
</item>
|
123
|
+
</reservationSet>
|
124
|
+
</DescribeInstancesResponse>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<DescribeLaunchConfigurationsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
|
2
|
+
<DescribeLaunchConfigurationsResult>
|
3
|
+
<LaunchConfigurations>
|
4
|
+
<member>
|
5
|
+
<AssociatePublicIpAddress>true</AssociatePublicIpAddress>
|
6
|
+
<SecurityGroups/>
|
7
|
+
<PlacementTenancy>dedicated</PlacementTenancy>
|
8
|
+
<CreatedTime>2013-01-21T23:04:42.200Z</CreatedTime>
|
9
|
+
<KernelId/>
|
10
|
+
<LaunchConfigurationName>cap-asg-production-production-lc-1234567890</LaunchConfigurationName>
|
11
|
+
<UserData/>
|
12
|
+
<InstanceType>m1.small</InstanceType>
|
13
|
+
<LaunchConfigurationARN>arn:aws:autoscaling:us-east-1:803981987763:launchConfiguration:
|
14
|
+
9dbbbf87-6141-428a-a409-0752edbe6cad:launchConfigurationName/my-test-lc</LaunchConfigurationARN>
|
15
|
+
<BlockDeviceMappings/>
|
16
|
+
<ImageId>ami-514ac838</ImageId>
|
17
|
+
<KeyName/>
|
18
|
+
<RamdiskId/>
|
19
|
+
<InstanceMonitoring>
|
20
|
+
<Enabled>true</Enabled>
|
21
|
+
</InstanceMonitoring>
|
22
|
+
<EbsOptimized>false</EbsOptimized>
|
23
|
+
</member>
|
24
|
+
</LaunchConfigurations>
|
25
|
+
</DescribeLaunchConfigurationsResult>
|
26
|
+
<ResponseMetadata>
|
27
|
+
<RequestId>d05a22f8-b690-11e2-bf8e-2113fEXAMPLE</RequestId>
|
28
|
+
</ResponseMetadata>
|
29
|
+
</DescribeLaunchConfigurationsResponse>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<DescribeSnapshotsResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
|
2
|
+
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
|
3
|
+
<snapshotSet>
|
4
|
+
<item>
|
5
|
+
<snapshotId>snap-1a2b3c4d</snapshotId>
|
6
|
+
<volumeId>vol-1234567890abcdef0</volumeId>
|
7
|
+
<status>pending</status>
|
8
|
+
<startTime>2013-01-21T23:04:42.200Z</startTime>
|
9
|
+
<progress>80%</progress>
|
10
|
+
<ownerId>111122223333</ownerId>
|
11
|
+
<volumeSize>15</volumeSize>
|
12
|
+
<description>Daily Backup</description>
|
13
|
+
<encrypted>true</encrypted>
|
14
|
+
<kmsKeyId>arn:aws:kms:us-east-1:123456789012:key/6876fb1b-example</kmsKeyId>
|
15
|
+
<tagSet>
|
16
|
+
<item>
|
17
|
+
<key>deployed-with</key>
|
18
|
+
<value>cap-asg</value>
|
19
|
+
</item>
|
20
|
+
<item>
|
21
|
+
<key>cap-asg-deploy-group</key>
|
22
|
+
<value>production</value>
|
23
|
+
</item>
|
24
|
+
</tagSet>
|
25
|
+
</item>
|
26
|
+
</snapshotSet>
|
27
|
+
</DescribeSnapshotsResponse>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<DescribeTagsResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
|
2
|
+
<requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>
|
3
|
+
<tagSet>
|
4
|
+
<item>
|
5
|
+
<resourceId>ami-1a2b3c4d</resourceId>
|
6
|
+
<resourceType>image</resourceType>
|
7
|
+
<key>deployed-with</key>
|
8
|
+
<value>cap-asg</value>
|
9
|
+
</item>
|
10
|
+
<item>
|
11
|
+
<resourceId>ami-1a2b3c4d</resourceId>
|
12
|
+
<resourceType>image</resourceType>
|
13
|
+
<key>cap-asg-deploy-group</key>
|
14
|
+
<value>production</value>
|
15
|
+
</item>
|
16
|
+
</tagSet>
|
17
|
+
</DescribeTagsResponse>
|
metadata
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: capistrano-asg
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Logan Serman
|
8
|
+
- Jeff Fraser
|
9
|
+
- Michael Martell
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2017-08-01 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: bundler
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "~>"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.6'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '1.6'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: rake
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: rspec
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: webmock
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: aws-sdk
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - "~>"
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '2'
|
78
|
+
type: :runtime
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - "~>"
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '2'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: capistrano
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">"
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: 3.0.0
|
92
|
+
type: :runtime
|
93
|
+
prerelease: false
|
94
|
+
version_requirements: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">"
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: 3.0.0
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
name: activesupport
|
101
|
+
requirement: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: 4.0.0
|
106
|
+
type: :runtime
|
107
|
+
prerelease: false
|
108
|
+
version_requirements: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: 4.0.0
|
113
|
+
description: Capistrano plugin for deploying to AWS AutoScale Groups. Deploys to all
|
114
|
+
instances in a group, creates a fresh AMI post-deploy, and attaches the AMI to your
|
115
|
+
AutoScale Group.
|
116
|
+
email:
|
117
|
+
- logan.serman@metova.com
|
118
|
+
- jeff.fraser@veracross.com
|
119
|
+
- michael.martell@veracross.com
|
120
|
+
executables: []
|
121
|
+
extensions: []
|
122
|
+
extra_rdoc_files: []
|
123
|
+
files:
|
124
|
+
- ".gitignore"
|
125
|
+
- ".rspec"
|
126
|
+
- ".travis.yml"
|
127
|
+
- Gemfile
|
128
|
+
- LICENSE.txt
|
129
|
+
- README.md
|
130
|
+
- Rakefile
|
131
|
+
- capistrano-asg.gemspec
|
132
|
+
- lib/capistrano-asg.rb
|
133
|
+
- lib/capistrano/asg.rb
|
134
|
+
- lib/capistrano/asg/ami.rb
|
135
|
+
- lib/capistrano/asg/aws/autoscaling.rb
|
136
|
+
- lib/capistrano/asg/aws/credentials.rb
|
137
|
+
- lib/capistrano/asg/aws/ec2.rb
|
138
|
+
- lib/capistrano/asg/aws_resource.rb
|
139
|
+
- lib/capistrano/asg/launch_configuration.rb
|
140
|
+
- lib/capistrano/asg/logger.rb
|
141
|
+
- lib/capistrano/asg/retryable.rb
|
142
|
+
- lib/capistrano/asg/taggable.rb
|
143
|
+
- lib/capistrano/asg/tasks/asg.rake
|
144
|
+
- lib/capistrano/asg/version.rb
|
145
|
+
- spec/ami_spec.rb
|
146
|
+
- spec/asg_spec.rb
|
147
|
+
- spec/spec_helper.rb
|
148
|
+
- spec/support/stubs/CreateImage.200.xml
|
149
|
+
- spec/support/stubs/CreateLaunchConfiguration.200.xml
|
150
|
+
- spec/support/stubs/CreateTags.200.xml
|
151
|
+
- spec/support/stubs/DeleteLaunchConfiguration.200.xml
|
152
|
+
- spec/support/stubs/DeleteSnapshot.200.xml
|
153
|
+
- spec/support/stubs/DeregisterImage.200.xml
|
154
|
+
- spec/support/stubs/DescribeAutoScalingGroups.200.xml
|
155
|
+
- spec/support/stubs/DescribeImages.200.xml
|
156
|
+
- spec/support/stubs/DescribeInstances.200.xml
|
157
|
+
- spec/support/stubs/DescribeLaunchConfigurations.200.xml
|
158
|
+
- spec/support/stubs/DescribeSnapshots.200.xml
|
159
|
+
- spec/support/stubs/DescribeTags.200.xml
|
160
|
+
- spec/support/stubs/UpdateAutoScalingGroup.200.xml
|
161
|
+
- spec/support/stubs/security-credentials.200.json
|
162
|
+
homepage: http://github.com/sixfeetover/capistrano-asg
|
163
|
+
licenses:
|
164
|
+
- MIT
|
165
|
+
metadata: {}
|
166
|
+
post_install_message:
|
167
|
+
rdoc_options: []
|
168
|
+
require_paths:
|
169
|
+
- lib
|
170
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - ">="
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
requirements: []
|
181
|
+
rubyforge_project:
|
182
|
+
rubygems_version: 2.6.11
|
183
|
+
signing_key:
|
184
|
+
specification_version: 4
|
185
|
+
summary: Capistrano plugin for deploying to AWS AutoScale Groups.
|
186
|
+
test_files:
|
187
|
+
- spec/ami_spec.rb
|
188
|
+
- spec/asg_spec.rb
|
189
|
+
- spec/spec_helper.rb
|
190
|
+
- spec/support/stubs/CreateImage.200.xml
|
191
|
+
- spec/support/stubs/CreateLaunchConfiguration.200.xml
|
192
|
+
- spec/support/stubs/CreateTags.200.xml
|
193
|
+
- spec/support/stubs/DeleteLaunchConfiguration.200.xml
|
194
|
+
- spec/support/stubs/DeleteSnapshot.200.xml
|
195
|
+
- spec/support/stubs/DeregisterImage.200.xml
|
196
|
+
- spec/support/stubs/DescribeAutoScalingGroups.200.xml
|
197
|
+
- spec/support/stubs/DescribeImages.200.xml
|
198
|
+
- spec/support/stubs/DescribeInstances.200.xml
|
199
|
+
- spec/support/stubs/DescribeLaunchConfigurations.200.xml
|
200
|
+
- spec/support/stubs/DescribeSnapshots.200.xml
|
201
|
+
- spec/support/stubs/DescribeTags.200.xml
|
202
|
+
- spec/support/stubs/UpdateAutoScalingGroup.200.xml
|
203
|
+
- spec/support/stubs/security-credentials.200.json
|