capistrano-autoscaling 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +60 -0
- data/Rakefile +1 -0
- data/capistrano-autoscaling.gemspec +22 -0
- data/lib/capistrano-autoscaling.rb +602 -0
- data/lib/capistrano-autoscaling/version.rb +5 -0
- metadata +87 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Yamashita Yuu
|
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,60 @@
|
|
1
|
+
# capistrano-autoscaling
|
2
|
+
|
3
|
+
A Capistrano recipe that configures [AutoScaling](http://aws.amazon.com/autoscaling/) on [Amazon Web Services](http://aws.amazon.com/) infrastructure for your application.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'capistrano-autoscaling'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install capistrano-autoscaling
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
This recipe will try to setup AutoScaling for your appliction. The following actions are prepared to be invoked from Capistrano.
|
22
|
+
|
23
|
+
* Create ELB for your application
|
24
|
+
* Create AMI from EC2 instances behind your ELB
|
25
|
+
* Create launch configurations from AMI of your application
|
26
|
+
* Create auto scaling group for your application
|
27
|
+
|
28
|
+
To enable this recipe, add following in your `config/deploy.rb`.
|
29
|
+
|
30
|
+
# in "config/deploy.rb"
|
31
|
+
require "capistrano-autoscaling"
|
32
|
+
set(:autoscaling_region, "ap-northeast-1")
|
33
|
+
set(:autoscaling_access_key_id, "PUTYOURAWSACCESSKEYIDHERE")
|
34
|
+
set(:autoscaling_secret_access_key, "PUTYOURAWSSECRETACCESSKEYHERE")
|
35
|
+
set(:autoscaling_instance_type, "m1.small")
|
36
|
+
set(:autoscaling_security_groups, %w(default))
|
37
|
+
set(:autoscaling_min_size, 2)
|
38
|
+
set(:autoscaling_max_size, 10)
|
39
|
+
after "deploy:setup", "autoscaling:setup"
|
40
|
+
after "deploy", "autoscaling:update"
|
41
|
+
|
42
|
+
TODO: Write usage instructions here
|
43
|
+
|
44
|
+
|
45
|
+
## Contributing
|
46
|
+
|
47
|
+
1. Fork it
|
48
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
49
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
50
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
51
|
+
5. Create new Pull Request
|
52
|
+
|
53
|
+
## Author
|
54
|
+
|
55
|
+
- YAMASHITA Yuu (https://github.com/yyuu)
|
56
|
+
- Geisha Tokyo Entertainment Inc. (http://www.geishatokyo.com/)
|
57
|
+
|
58
|
+
## License
|
59
|
+
|
60
|
+
MIT
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'capistrano-autoscaling/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "capistrano-autoscaling"
|
8
|
+
gem.version = Capistrano::AutoScaling::VERSION
|
9
|
+
gem.authors = ["Yamashita Yuu"]
|
10
|
+
gem.email = ["yamashita@geishatokyo.com"]
|
11
|
+
gem.description = %q{A Capistrano recipe that configures AutoScaling on Amazon Web Services infrastructure for your application.}
|
12
|
+
gem.summary = %q{A Capistrano recipe that configures AutoScaling on Amazon Web Services infrastructure for your application.}
|
13
|
+
gem.homepage = "https://github.com/yyuu/capistrano-autoscaling"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency("capistrano")
|
21
|
+
gem.add_dependency("aws-sdk", ">= 1.5.4")
|
22
|
+
end
|
@@ -0,0 +1,602 @@
|
|
1
|
+
require "aws"
|
2
|
+
require "capistrano-autoscaling/version"
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
module Capistrano
|
6
|
+
module AutoScaling
|
7
|
+
def self.extended(configuration)
|
8
|
+
configuration.load {
|
9
|
+
namespace(:autoscaling) {
|
10
|
+
## AWS
|
11
|
+
_cset(:autoscaling_region, nil)
|
12
|
+
_cset(:autoscaling_autoscaling_endpoint) {
|
13
|
+
case autoscaling_region
|
14
|
+
when "us-east-1" then "autoscaling.us-east-1.amazonaws.com"
|
15
|
+
when "us-west-1" then "autoscaling.us-west-1.amazonaws.com"
|
16
|
+
when "us-west-2" then "autoscaling.us-west-2.amazonaws.com"
|
17
|
+
when "sa-east-1" then "autoscaling.sa-east-1.amazonaws.com"
|
18
|
+
when "eu-west-1" then "autoscaling.eu-west-1.amazonaws.com"
|
19
|
+
when "ap-southeast-1" then "autoscaling.ap-southeast-1.amazonaws.com"
|
20
|
+
when "ap-southeast-2" then "autoscaling.ap-southeast-2.amazonaws.com"
|
21
|
+
when "ap-northeast-1" then "autoscaling.ap-northeast-1.amazonaws.com"
|
22
|
+
end
|
23
|
+
}
|
24
|
+
_cset(:autoscaling_cloudwatch_endpoint) {
|
25
|
+
case autoscaling_region
|
26
|
+
when "us-east-1" then "monitoring.us-east-1.amazonaws.com"
|
27
|
+
when "us-west-1" then "monitoring.us-west-1.amazonaws.com"
|
28
|
+
when "us-west-2" then "monitoring.us-west-2.amazonaws.com"
|
29
|
+
when "sa-east-1" then "monitoring.sa-east-1.amazonaws.com"
|
30
|
+
when "eu-west-1" then "monitoring.eu-west-1.amazonaws.com"
|
31
|
+
when "ap-southeast-1" then "monitoring.ap-southeast-1.amazonaws.com"
|
32
|
+
when "ap-southeast-2" then "monitoring.ap-southeast-2.amazonaws.com"
|
33
|
+
when "ap-northeast-1" then "monitoring.ap-northeast-1.amazonaws.com"
|
34
|
+
end
|
35
|
+
}
|
36
|
+
_cset(:autoscaling_ec2_endpoint) {
|
37
|
+
case autoscaling_region
|
38
|
+
when "us-east-1" then "ec2.us-east-1.amazonaws.com"
|
39
|
+
when "us-west-1" then "ec2.us-west-1.amazonaws.com"
|
40
|
+
when "us-west-2" then "ec2.us-west-2.amazonaws.com"
|
41
|
+
when "sa-east-1" then "ec2.sa-east-1.amazonaws.com"
|
42
|
+
when "eu-west-1" then "ec2.eu-west-1.amazonaws.com"
|
43
|
+
when "ap-southeast-1" then "ec2.ap-southeast-1.amazonaws.com"
|
44
|
+
when "ap-southeast-2" then "ec2.ap-southeast-2.amazonaws.com"
|
45
|
+
when "ap-northeast-1" then "ec2.ap-northeast-1.amazonaws.com"
|
46
|
+
end
|
47
|
+
}
|
48
|
+
_cset(:autoscaling_elb_endpoint) {
|
49
|
+
case autoscaling_region
|
50
|
+
when "us-east-1" then "elasticloadbalancing.us-east-1.amazonaws.com"
|
51
|
+
when "us-west-1" then "elasticloadbalancing.us-west-1.amazonaws.com"
|
52
|
+
when "us-west-2" then "elasticloadbalancing.us-west-2.amazonaws.com"
|
53
|
+
when "sa-east-1" then "elasticloadbalancing.sa-east-1.amazonaws.com"
|
54
|
+
when "eu-west-1" then "elasticloadbalancing.eu-west-1.amazonaws.com"
|
55
|
+
when "ap-southeast-1" then "elasticloadbalancing.ap-southeast-1.amazonaws.com"
|
56
|
+
when "ap-southeast-2" then "elasticloadbalancing.ap-southeast-2.amazonaws.com"
|
57
|
+
when "ap-northeast-1" then "elasticloadbalancing.ap-northeast-1.amazonaws.com"
|
58
|
+
end
|
59
|
+
}
|
60
|
+
_cset(:autoscaling_access_key_id) {
|
61
|
+
fetch(:aws_access_key_id, ENV["AWS_ACCESS_KEY_ID"]) or abort("AWS_ACCESS_KEY_ID is not set")
|
62
|
+
}
|
63
|
+
_cset(:autoscaling_secret_access_key) {
|
64
|
+
fetch(:aws_secret_access_key, ENV["AWS_SECRET_ACCESS_KEY"]) or abort("AWS_SECRET_ACCESS_KEY is not set")
|
65
|
+
}
|
66
|
+
_cset(:autoscaling_aws_options) {
|
67
|
+
{
|
68
|
+
:access_key_id => autoscaling_access_key_id,
|
69
|
+
:secret_access_key => autoscaling_secret_access_key,
|
70
|
+
:log_level => fetch(:autoscaling_log_level, :debug),
|
71
|
+
:auto_scaling_endpoint => autoscaling_autoscaling_endpoint,
|
72
|
+
:cloud_watch_endpoint => autoscaling_cloudwatch_endpoint,
|
73
|
+
:ec2_endpoint => autoscaling_ec2_endpoint,
|
74
|
+
:elb_endpoint => autoscaling_elb_endpoint,
|
75
|
+
}.merge(fetch(:autoscaling_aws_extra_options, {}))
|
76
|
+
}
|
77
|
+
_cset(:autoscaling_autoscaling_client) { AWS::AutoScaling.new(fetch(:autoscaling_autoscaling_aws_options, autoscaling_aws_options)) }
|
78
|
+
_cset(:autoscaling_cloudwatch_client) { AWS::CloudWatch.new(fetch(:autoscaling_cloudwatch_options, autoscaling_aws_options)) }
|
79
|
+
_cset(:autoscaling_ec2_client) { AWS::EC2.new(fetch(:autoscaling_ec2_options, autoscaling_aws_options)) }
|
80
|
+
_cset(:autoscaling_elb_client) { AWS::ELB.new(fetch(:autoscaling_elb_options, autoscaling_aws_options)) }
|
81
|
+
|
82
|
+
def autoscaling_name_mangling(s)
|
83
|
+
s.to_s.gsub(/[^0-9A-Za-z]/, "-")
|
84
|
+
end
|
85
|
+
|
86
|
+
## general
|
87
|
+
_cset(:autoscaling_application) { autoscaling_name_mangling(application) }
|
88
|
+
_cset(:autoscaling_timestamp) { Time.now.strftime("%Y%m%d%H%M%S") }
|
89
|
+
_cset(:autoscaling_availability_zones) { autoscaling_ec2_client.availability_zones.to_a.map { |az| az.name } }
|
90
|
+
_cset(:autoscaling_wait_interval, 1.0)
|
91
|
+
_cset(:autoscaling_keep_images, 2)
|
92
|
+
_cset(:autoscaling_instance_type, "t1.micro")
|
93
|
+
_cset(:autoscaling_security_groups, %w(default))
|
94
|
+
_cset(:autoscaling_min_size, 1)
|
95
|
+
_cset(:autoscaling_max_size) { autoscaling_min_size }
|
96
|
+
|
97
|
+
## behaviour
|
98
|
+
_cset(:autoscaling_create_elb, true)
|
99
|
+
_cset(:autoscaling_create_image, true)
|
100
|
+
_cset(:autoscaling_create_launch_configuration) {
|
101
|
+
autoscaling_create_image or ( autoscaling_image and autoscaling_image.exists? )
|
102
|
+
}
|
103
|
+
_cset(:autoscaling_create_group) {
|
104
|
+
( autoscaling_create_elb or ( autoscaling_elb_instance and autoscaling_elb_instance.exists? ) ) and
|
105
|
+
autoscaling_create_launch_configuration
|
106
|
+
}
|
107
|
+
_cset(:autoscaling_create_policy) { autoscaling_create_group }
|
108
|
+
_cset(:autoscaling_create_alarm) { autoscaling_create_policy }
|
109
|
+
|
110
|
+
## ELB
|
111
|
+
_cset(:autoscaling_elb_instance_name_prefix, "elb-")
|
112
|
+
_cset(:autoscaling_elb_instance_name) { "#{autoscaling_elb_instance_name_prefix}#{autoscaling_application}" }
|
113
|
+
_cset(:autoscaling_elb_instance) { autoscaling_elb_client.load_balancers[autoscaling_elb_instance_name] }
|
114
|
+
_cset(:autoscaling_elb_listeners) {
|
115
|
+
[
|
116
|
+
{
|
117
|
+
:port => fetch(:autoscaling_elb_port, 80),
|
118
|
+
:protocol => fetch(:autoscaling_elb_protocol, :http),
|
119
|
+
:instance_port => fetch(:autoscaling_elb_instance_port, 80),
|
120
|
+
:instance_protocol => fetch(:autoscaling_elb_instance_protocol, :http),
|
121
|
+
},
|
122
|
+
]
|
123
|
+
}
|
124
|
+
_cset(:autoscaling_elb_instance_options) {
|
125
|
+
{
|
126
|
+
:availability_zones => fetch(:autoscaling_elb_availability_zones, autoscaling_availability_zones),
|
127
|
+
:listeners => autoscaling_elb_listeners,
|
128
|
+
}.merge(fetch(:autoscaling_elb_instance_extra_options, {}))
|
129
|
+
}
|
130
|
+
_cset(:autoscaling_elb_health_check_target_path, "/")
|
131
|
+
_cset(:autoscaling_elb_health_check_target) {
|
132
|
+
autoscaling_elb_listeners.map { |listener|
|
133
|
+
if /^https?$/i =~ listener[:instance_protocol]
|
134
|
+
"#{listener[:instance_protocol].to_s.upcase}:#{listener[:instance_port]}#{autoscaling_elb_health_check_target_path}"
|
135
|
+
else
|
136
|
+
"#{listener[:instance_protocol].to_s.upcase}:#{listener[:instance_port]}"
|
137
|
+
end
|
138
|
+
}.first
|
139
|
+
}
|
140
|
+
_cset(:autoscaling_elb_health_check_options) {
|
141
|
+
{
|
142
|
+
:healthy_threshold => fetch(:autoscaling_elb_healthy_threshold, 10).to_i,
|
143
|
+
:unhealthy_threshold => fetch(:autoscaling_elb_unhealthy_threshold, 2).to_i,
|
144
|
+
:interval => fetch(:autoscaling_elb_health_check_interval, 30).to_i,
|
145
|
+
:timeout => fetch(:autoscaling_elb_health_check_timeout, 5).to_i,
|
146
|
+
:target => autoscaling_elb_health_check_target,
|
147
|
+
}.merge(fetch(:autoscaling_elb_health_check_extra_options, {}))
|
148
|
+
}
|
149
|
+
|
150
|
+
## EC2
|
151
|
+
_cset(:autoscaling_ec2_instance_name) { autoscaling_application }
|
152
|
+
_cset(:autoscaling_ec2_instances) {
|
153
|
+
if autoscaling_elb_instance and autoscaling_elb_instance.exists?
|
154
|
+
autoscaling_elb_instance.instances.to_a
|
155
|
+
else
|
156
|
+
abort("ELB is not ready: #{autoscaling_elb_instance_name}")
|
157
|
+
end
|
158
|
+
}
|
159
|
+
_cset(:autoscaling_ec2_instance_dns_names) { autoscaling_ec2_instances.map { |instance| instance.dns_name } }
|
160
|
+
_cset(:autoscaling_ec2_instance_private_dns_names) { autoscaling_ec2_instances.map { |instance| instance.private_dns_name } }
|
161
|
+
|
162
|
+
## AMI
|
163
|
+
_cset(:autoscaling_image_name) { "#{autoscaling_ec2_instance_name}/#{autoscaling_timestamp}" }
|
164
|
+
_cset(:autoscaling_image_instance) {
|
165
|
+
if 0 < autoscaling_ec2_instances.length
|
166
|
+
autoscaling_ec2_instances.reject { |instance| instance.root_device_type != :ebs }.last
|
167
|
+
else
|
168
|
+
abort("No EC2 instances are ready to create AMI.")
|
169
|
+
end
|
170
|
+
}
|
171
|
+
_cset(:autoscaling_image_options) {
|
172
|
+
{ :no_reboot => true }.merge(fetch(:autoscaling_image_extra_options, {}))
|
173
|
+
}
|
174
|
+
_cset(:autoscaling_image_tag_name) { autoscaling_application }
|
175
|
+
_cset(:autoscaling_image) {
|
176
|
+
autoscaling_ec2_client.images.with_owner("self").tagged("Name").tagged_values(autoscaling_image_name).to_a.first
|
177
|
+
}
|
178
|
+
_cset(:autoscaling_images) {
|
179
|
+
autoscaling_ec2_client.images.with_owner("self").tagged(autoscaling_image_tag_name).reject { |image| image.state != :available }
|
180
|
+
}
|
181
|
+
|
182
|
+
## LaunchConfiguration
|
183
|
+
_cset(:autoscaling_launch_configuration) {
|
184
|
+
autoscaling_autoscaling_client.launch_configurations[autoscaling_launch_configuration_name]
|
185
|
+
}
|
186
|
+
_cset(:autoscaling_launch_configuration_name_prefix, "lc-")
|
187
|
+
_cset(:autoscaling_launch_configuration_name) { "#{autoscaling_launch_configuration_name_prefix}#{autoscaling_image_name}" }
|
188
|
+
_cset(:autoscaling_launch_configuration_instance_type) { autoscaling_instance_type }
|
189
|
+
_cset(:autoscaling_launch_configuration_options) {
|
190
|
+
{
|
191
|
+
:security_groups => fetch(:autoscaling_launch_configuration_security_groups, autoscaling_security_groups),
|
192
|
+
}.merge(fetch(:autoscaling_launch_configuration_extra_options, {}))
|
193
|
+
}
|
194
|
+
|
195
|
+
## AutoScalingGroup
|
196
|
+
_cset(:autoscaling_group_name_prefix, "asg-")
|
197
|
+
_cset(:autoscaling_group_name) { "#{autoscaling_group_name_prefix}#{autoscaling_application}" }
|
198
|
+
_cset(:autoscaling_group_options) {
|
199
|
+
{
|
200
|
+
:availability_zones => fetch(:autoscaling_group_availability_zones, autoscaling_availability_zones),
|
201
|
+
:min_size => fetch(:autoscaling_group_min_size, autoscaling_min_size),
|
202
|
+
:max_size => fetch(:autoscaling_group_max_size, autoscaling_max_size),
|
203
|
+
}.merge(fetch(:autoscaling_group_extra_options, {}))
|
204
|
+
}
|
205
|
+
_cset(:autoscaling_group) { autoscaling_autoscaling_client.groups[autoscaling_group_name] }
|
206
|
+
|
207
|
+
## ScalingPolicy
|
208
|
+
_cset(:autoscaling_expand_policy_name_prefix, "expand-")
|
209
|
+
_cset(:autoscaling_shrink_policy_name_prefix, "shrink-")
|
210
|
+
_cset(:autoscaling_expand_policy_name) { "#{autoscaling_expand_policy_name_prefix}#{autoscaling_application}" }
|
211
|
+
_cset(:autoscaling_shrink_policy_name) { "#{autoscaling_shrink_policy_name_prefix}#{autoscaling_application}" }
|
212
|
+
_cset(:autoscaling_expand_policy_options) {{
|
213
|
+
:adjustment => fetch(:autoscaling_expand_policy_adjustment, 1),
|
214
|
+
:cooldown => fetch(:autoscaling_expand_policy_cooldown, 300),
|
215
|
+
:type => fetch(:autoscaling_expand_policy_type, "ChangeInCapacity"),
|
216
|
+
}}
|
217
|
+
_cset(:autoscaling_shrink_policy_options) {
|
218
|
+
{
|
219
|
+
:adjustment => fetch(:autoscaling_shrink_policy_adjustment, -1),
|
220
|
+
:cooldown => fetch(:autoscaling_shrink_policy_cooldown, 300),
|
221
|
+
:type => fetch(:autoscaling_shrink_policy_type, "ChangeInCapacity"),
|
222
|
+
}.merge(fetch(:autoscaling_shrink_policy_extra_options, {}))
|
223
|
+
}
|
224
|
+
_cset(:autoscaling_expand_policy) { autoscaling_group.scaling_policies[autoscaling_expand_policy_name] }
|
225
|
+
_cset(:autoscaling_shrink_policy) { autoscaling_group.scaling_policies[autoscaling_shrink_policy_name] }
|
226
|
+
|
227
|
+
## Alarm
|
228
|
+
_cset(:autoscaling_expand_alarm_options) {
|
229
|
+
{
|
230
|
+
:period => fetch(:autoscaling_expand_alarm_period, 60),
|
231
|
+
:evaluation_periods => fetch(:autoscaling_expand_alarm_evaluation_periods, 1),
|
232
|
+
}.merge(fetch(:autoscaling_expand_alarm_extra_options, {}))
|
233
|
+
}
|
234
|
+
_cset(:autoscaling_shrink_alarm_options) {
|
235
|
+
{
|
236
|
+
:period => fetch(:autoscaling_shrink_alarm_period, 60),
|
237
|
+
:evaluation_periods => fetch(:autoscaling_shrink_alarm_evaluation_periods, 1),
|
238
|
+
}.merge(fetch(:autoscaling_shrink_alarm_extra_options, {}))
|
239
|
+
}
|
240
|
+
_cset(:autoscaling_expand_alarm_name_prefix, "alarm-expand-")
|
241
|
+
_cset(:autoscaling_shrink_alarm_name_prefix, "alarm-shrink-")
|
242
|
+
_cset(:autoscaling_expand_alarm_name) { "#{autoscaling_expand_alarm_name_prefix}#{autoscaling_application}" }
|
243
|
+
_cset(:autoscaling_shrink_alarm_name) { "#{autoscaling_shrink_alarm_name_prefix}#{autoscaling_application}" }
|
244
|
+
_cset(:autoscaling_expand_alarm_definitions) {{
|
245
|
+
autoscaling_expand_alarm_name => {
|
246
|
+
:statistic => fetch(:autoscaling_expand_alarm_evaluation_statistic, "Average"),
|
247
|
+
:namespace => fetch(:autoscaling_expand_alarm_namespace, "AWS/EC2"),
|
248
|
+
:metric_name => fetch(:autoscaling_expand_alarm_metric_name, "CPUUtilization"),
|
249
|
+
:comparison_operator => fetch(:autoscaling_expand_alarm_comparison_operator, "LessThanThreshold"),
|
250
|
+
:threshold => fetch(:autoscaling_expand_alarm_threshold, 30),
|
251
|
+
},
|
252
|
+
}}
|
253
|
+
_cset(:autoscaling_shrink_alarm_definitions) {{
|
254
|
+
autoscaling_shrink_alarm_name => {
|
255
|
+
:statistic => fetch(:autoscaling_shrink_alarm_evaluation_statistic, "Average"),
|
256
|
+
:namespace => fetch(:autoscaling_shrink_alarm_namespace, "AWS/EC2"),
|
257
|
+
:metric_name => fetch(:autoscaling_shrink_alarm_metric_name, "CPUUtilization"),
|
258
|
+
:comparison_operator => fetch(:autoscaling_shrink_alarm_comparison_operator, "LessThanThreshold"),
|
259
|
+
:threshold => fetch(:autoscaling_shrink_alarm_threshold, 30),
|
260
|
+
},
|
261
|
+
}}
|
262
|
+
|
263
|
+
desc("Setup AutoScaling.")
|
264
|
+
task(:setup, :roles => :app, :except => { :no_release => true }) {
|
265
|
+
setup_elb
|
266
|
+
}
|
267
|
+
|
268
|
+
task(:setup_elb, :roles => :app, :except => { :no_release => true }) {
|
269
|
+
if autoscaling_create_elb
|
270
|
+
if autoscaling_elb_instance and autoscaling_elb_instance.exists?
|
271
|
+
logger.debug("Found ELB: #{autoscaling_elb_instance.name}")
|
272
|
+
autoscaling_elb_listeners.each do |listener|
|
273
|
+
autoscaling_elb_instance.listeners.create(listener)
|
274
|
+
end
|
275
|
+
else
|
276
|
+
logger.debug("Creating ELB instance: #{autoscaling_elb_instance_name}")
|
277
|
+
set(:autoscaling_elb_instance, autoscling_elb_client.load_balancers.create(
|
278
|
+
autoscaling_elb_instance_name, autoscaling_elb_instance_options))
|
279
|
+
sleep(autoscaling_wait_interval) unless autoscaling_elb_instance.exists?
|
280
|
+
logger.debug("Created ELB instance: #{autoscaling_elb_instance.name}")
|
281
|
+
logger.info("You must setup EC2 instance(s) behind the ELB manually: #{autoscaling_elb_instance_name}")
|
282
|
+
end
|
283
|
+
logger.debug("Configuring ELB health check: #{autoscaling_elb_instance_name}")
|
284
|
+
autoscaling_elb_instance.configure_health_check(autoscaling_elb_health_check_options)
|
285
|
+
else
|
286
|
+
logger.info("Skip creating ELB instance: #{autoscaling_elb_instance_name}")
|
287
|
+
end
|
288
|
+
}
|
289
|
+
|
290
|
+
desc("Remove AutoScaling settings.")
|
291
|
+
task(:destroy, :roles => :app, :except => { :no_release => true }) {
|
292
|
+
abort("FIXME: Not yet implemented.")
|
293
|
+
}
|
294
|
+
|
295
|
+
desc("Register current instance for AutoScaling.")
|
296
|
+
task(:update, :roles => :app, :except => { :no_release => true }) {
|
297
|
+
suspend
|
298
|
+
update_image
|
299
|
+
update_launch_configuration
|
300
|
+
update_group
|
301
|
+
update_policy
|
302
|
+
resume
|
303
|
+
}
|
304
|
+
|
305
|
+
task(:update_image, :roles => :app, :except => { :no_release => true }) {
|
306
|
+
if autoscaling_create_image
|
307
|
+
if autoscaling_image and autoscaling_image.exists?
|
308
|
+
logger.debug("Found AMI: #{autoscaling_image.name} (#{autoscaling_image.id})")
|
309
|
+
else
|
310
|
+
logger.debug("Creating AMI: #{autoscaling_image_name}")
|
311
|
+
run("sync; sync; sync") # force flushing to disk
|
312
|
+
set(:autoscaling_image, autoscaling_ec2_client.images.create(
|
313
|
+
autoscaling_image_options.merge(:name => autoscaling_image_name, :instance_id => autoscaling_image_instance.id)))
|
314
|
+
sleep(autoscaling_wait_interval) until autoscaling_image.exists?
|
315
|
+
logger.debug("Created AMI: #{autoscaling_image.name} (#{autoscaling_image.id})")
|
316
|
+
[["Name", {:value => autoscaling_image_name}], [autoscaling_image_tag_name]].each do |tag_name, tag_options|
|
317
|
+
begin
|
318
|
+
if tag_options
|
319
|
+
autoscaling_image.add_tag(tag_name, tag_options)
|
320
|
+
else
|
321
|
+
autoscaling_image.add_tag(tag_name)
|
322
|
+
end
|
323
|
+
rescue AWS::EC2::Errors::InvalidAMIID::NotFound => error
|
324
|
+
logger.info("[ERROR] " + error.inspect)
|
325
|
+
sleep(autoscaling_wait_interval)
|
326
|
+
retry
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
else
|
331
|
+
logger.info("Skip creating AMI: #{autoscaling_image_name}")
|
332
|
+
end
|
333
|
+
}
|
334
|
+
|
335
|
+
task(:update_launch_configuration, :roles => :app, :except => { :no_release => true }) {
|
336
|
+
if autoscaling_create_launch_configuration
|
337
|
+
if autoscaling_launch_configuration.exists?
|
338
|
+
logger.debug("Found LaunchConfiguration: #{autoscaling_launch_configuration.name} (#{autoscaling_launch_configuration.image_id})")
|
339
|
+
else
|
340
|
+
logger.debug("Creating LaunchConfiguration: #{autoscaling_launch_configuration_name} (#{autoscaling_image.id})")
|
341
|
+
set(:autoscaling_launch_configuration, autoscaling_autoscaling_client.launch_configurations.create(
|
342
|
+
autoscaling_launch_configuration_name, autoscaling_image.id, autoscaling_launch_configuration_instance_type,
|
343
|
+
autoscaling_launch_configuration_options))
|
344
|
+
sleep(autoscaling_wait_interval) unless autoscaling_launch_configuration.exists?
|
345
|
+
logger.debug("Created LaunchConfiguration: #{autoscaling_launch_configuration.name} (#{autoscaling_launch_configuration.image_id})")
|
346
|
+
end
|
347
|
+
else
|
348
|
+
logger.info("Skip creating LaunchConfiguration: #{autoscaling_launch_configuration_name}")
|
349
|
+
end
|
350
|
+
}
|
351
|
+
|
352
|
+
task(:update_group, :roles => :app, :except => { :no_release => true }) {
|
353
|
+
if autoscaling_create_group
|
354
|
+
if autoscaling_group and autoscaling_group.exists?
|
355
|
+
logger.debug("Found AutoScalingGroup: #{autoscaling_group.name} (#{autoscaling_group.launch_configuration_name})")
|
356
|
+
autoscaling_group.update(autoscaling_group_options.merge(:launch_configuration => autoscaling_launch_configuration))
|
357
|
+
else
|
358
|
+
if autoscaling_elb_instance.exists? and autoscaling_launch_configuration.exists?
|
359
|
+
logger.debug("Creating AutoScalingGroup: #{autoscaling_group_name} (#{autoscaling_launch_configuration.name})")
|
360
|
+
set(:autoscaling_group, autoscaling_autoscaling_client.groups.create(autoscaling_group_name,
|
361
|
+
autoscaling_group_options.merge(:launch_configuration => autoscaling_launch_configuration,
|
362
|
+
:load_balancers => [ autoscaling_elb_instance ])))
|
363
|
+
logger.debug("Created AutoScalingGroup: #{autoscaling_group.name} (#{autoscaling_group.launch_configuration_name})")
|
364
|
+
else
|
365
|
+
logger.info("Skip creating AutoScalingGroup: #{autoscaling_group_name} (#{autoscaling_launch_configuration_name})")
|
366
|
+
end
|
367
|
+
end
|
368
|
+
else
|
369
|
+
logger.info("Skip creating AutoScalingGroup: #{autoscaling_group_name}")
|
370
|
+
end
|
371
|
+
}
|
372
|
+
|
373
|
+
task(:update_policy, :roles => :app, :except => { :no_release => true }) {
|
374
|
+
if autoscaling_create_policy
|
375
|
+
if autoscaling_expand_policy and autoscaling_expand_policy.exists?
|
376
|
+
logger.debug("Found ScalingPolicy for expansion: #{autoscaling_expand_policy.name}")
|
377
|
+
else
|
378
|
+
logger.debug("Createing ScalingPolicy for expansion: #{autoscaling_expand_policy_name}")
|
379
|
+
set(:autoscaling_expand_policy, autoscaling_group.scaling_policies.create(autoscaling_expand_policy_name,
|
380
|
+
autoscaling_expand_policy_options))
|
381
|
+
sleep(autoscaling_wait_interval) unless autoscaling_expand_policy.exists?
|
382
|
+
logger.debug("Created ScalingPolicy for expansion: #{autoscaling_expand_policy.name}")
|
383
|
+
end
|
384
|
+
else
|
385
|
+
logger.info("Skip creating ScalingPolicy for expansion: #{autoscaling_expand_policy_name}")
|
386
|
+
end
|
387
|
+
|
388
|
+
if autoscaling_create_policy
|
389
|
+
if autoscaling_shrink_policy and autoscaling_shrink_policy.exists?
|
390
|
+
logger.debug("Found ScalingPolicy for shrinking: #{autoscaling_shrink_policy.name}")
|
391
|
+
else
|
392
|
+
logger.debug("Createing ScalingPolicy for shrinking: #{autoscaling_shrink_policy_name}")
|
393
|
+
set(:autoscaling_shrink_policy, autoscaling_group.scaling_policies.create(autoscaling_shrink_policy_name,
|
394
|
+
autoscaling_shrink_policy_options))
|
395
|
+
sleep(autoscaling_wait_interval) unless autoscaling_shrink_policy.exists?
|
396
|
+
logger.debug("Created ScalingPolicy for shrinking: #{autoscaling_shrink_policy.name}")
|
397
|
+
end
|
398
|
+
else
|
399
|
+
logger.info("Skip creating ScalingPolicy for shrinking: #{autoscaling_shrink_policy_name}")
|
400
|
+
end
|
401
|
+
}
|
402
|
+
|
403
|
+
def autoscaling_default_alarm_dimensions(namespace)
|
404
|
+
case namespace
|
405
|
+
when %r{AWS/EC2}i
|
406
|
+
[{"Name" => "AutoScalingGroupName", "Value" => autoscaling_group_name}]
|
407
|
+
when %r{AWS/ELB}i
|
408
|
+
[{"Name" => "LoadBalancerName", "Value" => autoscaling_elb_instance_name}]
|
409
|
+
else
|
410
|
+
abort("Unknown metric namespace to generate dimensions: #{namespace}")
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
task(:update_alarm, :roles => :app, :except => { :no_release => true }) {
|
415
|
+
if autoscaling_create_alarm
|
416
|
+
autoscaling_expand_alarm_definitions.each do |alarm_name, alarm_options|
|
417
|
+
alarm = autoscaling_cloudwatch_client.alarms[alarm_name]
|
418
|
+
if alarm and alarm.exists?
|
419
|
+
logger.debug("Found Alarm for expansion: #{alarm.name}")
|
420
|
+
else
|
421
|
+
logger.debug("Creating Alarm for expansion: #{alarm_name}")
|
422
|
+
options = autoscaling_expand_alarm_options.merge(alarm_options)
|
423
|
+
options[:alarm_actions] = [ autoscaling_expand_policy.arn ] unless options.has_key?(:alarm_actions)
|
424
|
+
options[:dimensions] = autoscaling_default_alarm_dimensions(options[:namespace]) unless options.has_key?(:dimensions)
|
425
|
+
alarm = autoscaling_cloudwatch_client.alarms.create(alarm_name, options)
|
426
|
+
logger.debug("Created Alarm for expansion: #{alarm.name}")
|
427
|
+
end
|
428
|
+
end
|
429
|
+
else
|
430
|
+
logger.info("Skip creating Alarm for expansion")
|
431
|
+
end
|
432
|
+
|
433
|
+
if autoscaling_create_alarm
|
434
|
+
autoscaling_shrink_alarm_definitions.each do |alarm_name, alarm_options|
|
435
|
+
alarm = autoscaling_cloudwatch_client.alarms[alarm_name]
|
436
|
+
if alarm and alarm.exists?
|
437
|
+
logger.debug("Found Alarm for shrinking: #{alarm.name}")
|
438
|
+
else
|
439
|
+
logger.debug("Creating Alarm for shrinking: #{alarm_name}")
|
440
|
+
options = autoscaling_shrink_alarm_options.merge(alarm_options)
|
441
|
+
options[:alarm_actions] = [ autoscaling_shrink_policy.arn ] unless options.has_key?(:alarm_actions)
|
442
|
+
options[:dimensions] = autoscaling_default_alarm_dimensions(options[:namespace]) unless options.has_key?(:dimensions)
|
443
|
+
alarm = autoscaling_cloudwatch_client.alarms.create(alarm_name, options)
|
444
|
+
logger.debug("Created Alarm for shrinking: #{alarm.name}")
|
445
|
+
end
|
446
|
+
end
|
447
|
+
else
|
448
|
+
logger.info("Skip creating Alarm for shrinking")
|
449
|
+
end
|
450
|
+
}
|
451
|
+
|
452
|
+
desc("Suspend AutoScaling processes.")
|
453
|
+
task(:suspend, :roles => :app, :except => { :no_release => true }) {
|
454
|
+
if autoscaling_group and autoscaling_group.exists?
|
455
|
+
logger.info("Suspending Group: #{autoscaling_group.name}")
|
456
|
+
autoscaling_group.suspend_all_processes
|
457
|
+
else
|
458
|
+
logger.info("Skip suspending AutoScalingGroup: #{autoscaling_group_name}")
|
459
|
+
end
|
460
|
+
}
|
461
|
+
|
462
|
+
desc("Resume AutoScaling processes.")
|
463
|
+
task(:resume, :roles => :app, :except => { :no_release => true }) {
|
464
|
+
if autoscaling_group and autoscaling_group.exists?
|
465
|
+
logger.info("Resuming Group: #{autoscaling_group.name}")
|
466
|
+
autoscaling_group.resume_all_processes
|
467
|
+
else
|
468
|
+
logger.info("Skip resuming AutoScalingGroup: #{autoscaling_group_name}")
|
469
|
+
end
|
470
|
+
}
|
471
|
+
|
472
|
+
desc("Show AutoScaling status.")
|
473
|
+
task(:status, :roles => :app, :except => { :no_release => true }) {
|
474
|
+
if autoscaling_group and autoscaling_group.exists?
|
475
|
+
STDOUT.puts({
|
476
|
+
:availability_zone_names => autoscaling_group.availability_zone_names.to_a,
|
477
|
+
:desired_capacity => autoscaling_group.desired_capacity,
|
478
|
+
:launch_configuration => {
|
479
|
+
:iam_instance_profile => autoscaling_group.launch_configuration.iam_instance_profile,
|
480
|
+
:image => {
|
481
|
+
:id => autoscaling_group.launch_configuration.image.id,
|
482
|
+
:name => autoscaling_group.launch_configuration.image.name,
|
483
|
+
:state => autoscaling_group.launch_configuration.image.state,
|
484
|
+
},
|
485
|
+
:instance_type => autoscaling_group.launch_configuration.instance_type,
|
486
|
+
:name => autoscaling_group.launch_configuration.name,
|
487
|
+
:security_groups => autoscaling_group.launch_configuration.security_groups.map { |sg| sg.name },
|
488
|
+
},
|
489
|
+
:load_balancers => autoscaling_group.load_balancers.to_a.map { |lb|
|
490
|
+
{
|
491
|
+
:availability_zone_names => lb.availability_zone_names.to_a,
|
492
|
+
:dns_name => lb.dns_name,
|
493
|
+
:instances => lb.instances.map { |i|
|
494
|
+
{
|
495
|
+
:dns_name => i.dns_name,
|
496
|
+
:id => i.id,
|
497
|
+
:private_dns_name => i.private_dns_name,
|
498
|
+
:status => i.status,
|
499
|
+
}
|
500
|
+
},
|
501
|
+
:name => lb.name,
|
502
|
+
}
|
503
|
+
},
|
504
|
+
:max_size => autoscaling_group.max_size,
|
505
|
+
:min_size => autoscaling_group.min_size,
|
506
|
+
:name => autoscaling_group.name,
|
507
|
+
:scaling_policies => autoscaling_group.scaling_policies.map { |policy|
|
508
|
+
{
|
509
|
+
:adjustment_type => policy.adjustment_type,
|
510
|
+
:alarms => policy.alarms.to_hash.keys,
|
511
|
+
:cooldown => policy.cooldown,
|
512
|
+
:name => policy.name,
|
513
|
+
:scaling_adjustment => policy.scaling_adjustment,
|
514
|
+
}
|
515
|
+
},
|
516
|
+
:scheduled_actions => autoscaling_group.scheduled_actions.map { |action|
|
517
|
+
{
|
518
|
+
:desired_capacity => action.desired_capacity,
|
519
|
+
:end_time => action.end_time,
|
520
|
+
:max_size => action.max_size,
|
521
|
+
:min_size => action.min_size,
|
522
|
+
:name => action.name,
|
523
|
+
:start_time => action.start_time,
|
524
|
+
}
|
525
|
+
},
|
526
|
+
:suspended_processes => autoscaling_group.suspended_processes.to_hash,
|
527
|
+
}.to_yaml)
|
528
|
+
end
|
529
|
+
}
|
530
|
+
|
531
|
+
desc("Show AutoScaling history.")
|
532
|
+
task(:history, :roles => :app, :except => { :no_release => true }) {
|
533
|
+
if autoscaling_group and autoscaling_group.exists?
|
534
|
+
autoscaling_group.scaling_policies.each do |policy|
|
535
|
+
policy.alarms.each do |alarm_name, alarm_arn|
|
536
|
+
alarm = autoscaling_cloudwatch_client.alarms[alarm_name]
|
537
|
+
start_date = Time.now - fetch(:autoscaling_history_days, 3) * 86400
|
538
|
+
history_items = alarm.history_items.with_start_date(start_date)
|
539
|
+
|
540
|
+
STDOUT.puts("--")
|
541
|
+
STDOUT.puts("Alarm: #{alarm_name} (ScalingPolicy: #{policy.name})")
|
542
|
+
history_items.each do |hi|
|
543
|
+
STDOUT.puts("#{hi.timestamp}: #{hi.type}: #{hi.summary}")
|
544
|
+
end
|
545
|
+
end
|
546
|
+
end
|
547
|
+
else
|
548
|
+
abort("AutoScalingGroup is not ready: #{autoscaling_group_name}")
|
549
|
+
end
|
550
|
+
|
551
|
+
}
|
552
|
+
|
553
|
+
desc("Delete old AMIs.")
|
554
|
+
task(:cleanup, :roles => :app, :except => { :no_release => true }) {
|
555
|
+
images = autoscaling_images.sort { |x, y| x.name <=> y.name }.reject { |image|
|
556
|
+
autoscaling_group.launch_configuration.image_id == image.id
|
557
|
+
}
|
558
|
+
(images - images.last(autoscaling_keep_images-1)).each do |image|
|
559
|
+
if autoscaling_create_image and ( image and image.exists? )
|
560
|
+
snapshots = image.block_device_mappings.map { |device, block_device| block_device.snapshot_id }
|
561
|
+
logger.debug("Deregistering AMI: #{image.id}")
|
562
|
+
image.deregister()
|
563
|
+
sleep(autoscaling_wait_interval) unless image.exists?
|
564
|
+
|
565
|
+
snapshots.each do |id|
|
566
|
+
snapshot = autoscaling_ec2_client.snapshots[id]
|
567
|
+
if snapshot and snapshot.exists?
|
568
|
+
logger.debug("Deleting EBS snapshot: #{snapshot.id}")
|
569
|
+
begin
|
570
|
+
snapshot.delete()
|
571
|
+
rescue AWS::EC2::Errors::InvalidSnapshot::InUse => error
|
572
|
+
logger.info("[ERROR] " + error.inspect)
|
573
|
+
sleep(autoscaling_wait_interval)
|
574
|
+
retry
|
575
|
+
end
|
576
|
+
end
|
577
|
+
end
|
578
|
+
else
|
579
|
+
logger.info("Skip deleting AMI: #{image.name} (#{image.id})")
|
580
|
+
end
|
581
|
+
|
582
|
+
launch_configuration_name = "#{autoscaling_launch_configuration_name_prefix}#{image.name}"
|
583
|
+
launch_configuration = autoscaling_autoscaling_client.launch_configurations[launch_configuration_name]
|
584
|
+
if autoscaling_create_launch_configuration and ( launch_configuration and launch_configuration.exists? )
|
585
|
+
logger.debug("Deleting LaunchConfiguration: #{launch_configuration.name}")
|
586
|
+
launch_configuration.delete()
|
587
|
+
else
|
588
|
+
logger.info("Skip deleting LaunchConfiguration: #{launch_configuration_name}")
|
589
|
+
end
|
590
|
+
end
|
591
|
+
}
|
592
|
+
}
|
593
|
+
}
|
594
|
+
end
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
if Capistrano::Configuration.instance
|
599
|
+
Capistrano::Configuration.instance.extend(Capistrano::AutoScaling)
|
600
|
+
end
|
601
|
+
|
602
|
+
# vim:set ft=ruby ts=2 sw=2 :
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: capistrano-autoscaling
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Yamashita Yuu
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: capistrano
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: aws-sdk
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.5.4
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.5.4
|
46
|
+
description: A Capistrano recipe that configures AutoScaling on Amazon Web Services
|
47
|
+
infrastructure for your application.
|
48
|
+
email:
|
49
|
+
- yamashita@geishatokyo.com
|
50
|
+
executables: []
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- .gitignore
|
55
|
+
- Gemfile
|
56
|
+
- LICENSE.txt
|
57
|
+
- README.md
|
58
|
+
- Rakefile
|
59
|
+
- capistrano-autoscaling.gemspec
|
60
|
+
- lib/capistrano-autoscaling.rb
|
61
|
+
- lib/capistrano-autoscaling/version.rb
|
62
|
+
homepage: https://github.com/yyuu/capistrano-autoscaling
|
63
|
+
licenses: []
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.8.23
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: A Capistrano recipe that configures AutoScaling on Amazon Web Services infrastructure
|
86
|
+
for your application.
|
87
|
+
test_files: []
|