capistrano-asg 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|