capistrano-asg 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +15 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +80 -0
  8. data/Rakefile +5 -0
  9. data/capistrano-asg.gemspec +31 -0
  10. data/lib/capistrano/asg/ami.rb +60 -0
  11. data/lib/capistrano/asg/aws/autoscaling.rb +36 -0
  12. data/lib/capistrano/asg/aws/credentials.rb +20 -0
  13. data/lib/capistrano/asg/aws/ec2.rb +28 -0
  14. data/lib/capistrano/asg/aws_resource.rb +43 -0
  15. data/lib/capistrano/asg/launch_configuration.rb +69 -0
  16. data/lib/capistrano/asg/logger.rb +9 -0
  17. data/lib/capistrano/asg/retryable.rb +18 -0
  18. data/lib/capistrano/asg/taggable.rb +12 -0
  19. data/lib/capistrano/asg/tasks/asg.rake +17 -0
  20. data/lib/capistrano/asg/version.rb +5 -0
  21. data/lib/capistrano/asg.rb +56 -0
  22. data/lib/capistrano-asg.rb +0 -0
  23. data/spec/ami_spec.rb +11 -0
  24. data/spec/asg_spec.rb +69 -0
  25. data/spec/spec_helper.rb +32 -0
  26. data/spec/support/stubs/CreateImage.200.xml +4 -0
  27. data/spec/support/stubs/CreateLaunchConfiguration.200.xml +5 -0
  28. data/spec/support/stubs/CreateTags.200.xml +4 -0
  29. data/spec/support/stubs/DeleteLaunchConfiguration.200.xml +5 -0
  30. data/spec/support/stubs/DeleteSnapshot.200.xml +4 -0
  31. data/spec/support/stubs/DeregisterImage.200.xml +4 -0
  32. data/spec/support/stubs/DescribeAutoScalingGroups.200.xml +21 -0
  33. data/spec/support/stubs/DescribeImages.200.xml +44 -0
  34. data/spec/support/stubs/DescribeInstances.200.xml +124 -0
  35. data/spec/support/stubs/DescribeLaunchConfigurations.200.xml +29 -0
  36. data/spec/support/stubs/DescribeSnapshots.200.xml +27 -0
  37. data/spec/support/stubs/DescribeTags.200.xml +17 -0
  38. data/spec/support/stubs/UpdateAutoScalingGroup.200.xml +5 -0
  39. data/spec/support/stubs/security-credentials.200.json +9 -0
  40. 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
@@ -0,0 +1,22 @@
1
+ bin/
2
+ *.gem
3
+ *.rbc
4
+ /Gemfile.lock
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ cache: bundler
3
+ rvm:
4
+ - 2.3.3
5
+ - 2.4.1
6
+ sudo: false
7
+ env:
8
+ - AWS_REGION: us-west-2
9
+ deploy:
10
+ provider: rubygems
11
+ gem:
12
+ master: capistrano-asg
13
+ on:
14
+ repo: sixfeetover/capistrano-asg
15
+ branch: master
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in capistrano-asg.gemspec
4
+ gemspec
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,5 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ task :default => :spec
5
+ RSpec::Core::RakeTask.new
@@ -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,9 @@
1
+ module Capistrano
2
+ module Asg
3
+ module Logger
4
+ def info(message)
5
+ puts "Autoscaling: #{message}"
6
+ end
7
+ end
8
+ end
9
+ 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,12 @@
1
+ module Capistrano
2
+ module Asg
3
+ # Adds tags to AWS resources
4
+ module Taggable
5
+ def tag(tags = {})
6
+ with_retry do
7
+ tags.each { |k, v| aws_counterpart.create_tags(tags: [{key: k, value: v}]) }
8
+ end
9
+ end
10
+ end
11
+ end
12
+ 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,5 @@
1
+ module Capistrano
2
+ module Asg
3
+ VERSION = '0.5.0'.freeze
4
+ end
5
+ 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
@@ -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,4 @@
1
+ <CreateImageResponse xmlns="http://ec2.amazonaws.com/doc/2014-10-01/">
2
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
3
+ <imageId>ami-4fa54026</imageId>
4
+ </CreateImageResponse>
@@ -0,0 +1,5 @@
1
+ <CreateLaunchConfigurationResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
2
+ <ResponseMetadata>
3
+ <RequestId>7c6e177f-f082-11e1-ac58-3714bEXAMPLE</RequestId>
4
+ </ResponseMetadata>
5
+ </CreateLaunchConfigurationResponse>
@@ -0,0 +1,4 @@
1
+ <CreateTagsResponse xmlns="http://ec2.amazonaws.com/doc/2014-10-01/">
2
+ <requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>
3
+ <return>true</return>
4
+ </CreateTagsResponse>
@@ -0,0 +1,5 @@
1
+ <DeleteLaunchConfigurationResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
2
+ <ResponseMetadata>
3
+ <RequestId>7347261f-97df-11e2-8756-35eEXAMPLE</RequestId>
4
+ </ResponseMetadata>
5
+ </DeleteLaunchConfigurationResponse>
@@ -0,0 +1,4 @@
1
+ <DeleteSnapshotResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
2
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
3
+ <return>true</return>
4
+ </DeleteSnapshotResponse>
@@ -0,0 +1,4 @@
1
+ <DeregisterImageResponse xmlns="http://ec2.amazonaws.com/doc/2014-10-01/">
2
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
3
+ <return>true</return>
4
+ </DeregisterImageResponse>
@@ -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>
@@ -0,0 +1,5 @@
1
+ <UpdateAutoScalingGroupResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
2
+ <ResponseMetadata>
3
+ <RequestId>adafead0-ab8a-11e2-ba13-ab0ccEXAMPLE</RequestId>
4
+ </ResponseMetadata>
5
+ </UpdateAutoScalingGroupResponse>
@@ -0,0 +1,9 @@
1
+ {
2
+ "Code" : "Success",
3
+ "LastUpdated" : "2013-11-22T20:03:48Z",
4
+ "Type" : "AWS-HMAC",
5
+ "AccessKeyId" : "akid",
6
+ "SecretAccessKey" : "secret",
7
+ "Token" : "token",
8
+ "Expiration" : "2035-02-09T21:53:57Z"
9
+ }
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