rodeo_clown 0.0.1 → 0.1.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 +4 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +27 -6
- data/README.md +11 -0
- data/Rakefile +5 -0
- data/bin/elb_rotate.rb +0 -6
- data/bin/lets_dance +119 -0
- data/examples/ranch_hands.yml +35 -0
- data/lib/rodeo_clown/deploy.rb +16 -0
- data/lib/rodeo_clown/deploy_strategy/mina.rb +38 -0
- data/lib/rodeo_clown/deploy_strategy.rb +9 -0
- data/lib/rodeo_clown/ec2.rb +47 -14
- data/lib/rodeo_clown/elb.rb +24 -14
- data/lib/rodeo_clown/ext/array.rb +18 -0
- data/lib/rodeo_clown/ext/aws/ec2/instance.rb +20 -0
- data/lib/rodeo_clown/ext/aws/ec2/instance_collection.rb +15 -0
- data/lib/rodeo_clown/ext/{instance_collection.rb → aws/elb/instance_collection.rb} +4 -4
- data/lib/rodeo_clown/ext/hash.rb +25 -0
- data/lib/rodeo_clown/instance_builder.rb +64 -0
- data/lib/rodeo_clown/is_port_open.rb +22 -0
- data/lib/rodeo_clown/version.rb +1 -1
- data/lib/rodeo_clown.rb +23 -4
- data/rodeo_clown.gemspec +6 -5
- data/spec/rodeo_clown/deploy_spec.rb +34 -0
- data/spec/rodeo_clown/deploy_strategy_spec.rb +24 -0
- data/spec/rodeo_clown/ec2_spec.rb +74 -0
- data/spec/spec_helper.rb +4 -0
- metadata +60 -25
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a4da4d0f35035c6aa16f41273d0543ea8a3a8bc8
|
|
4
|
+
data.tar.gz: 4439e2e501ec29569e76a7b3c6bf3ad519b0f270
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a644e9d5cbe229dbf83c66e2f99df2648d2bd127c94413fa3a18a0346fee43ed41220d9c9442d297a14ba21b2c582b9cff14fba84e9394bc4ba0cd9cfa4c8ccd
|
|
7
|
+
data.tar.gz: e0430cb18ac6fea5c92d2b6e7250964e9d41e2b3b4ec398ddc4b1776b473642c72e46f42064d91986f508c9b3a9a20564853cfa04d340900d3d8c06e9d9c9bb6
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,27 +1,48 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
rodeo_clown (0.0
|
|
4
|
+
rodeo_clown (0.1.0)
|
|
5
|
+
aws-sdk (~> 1.38)
|
|
6
|
+
rake (~> 10.2)
|
|
5
7
|
|
|
6
8
|
GEM
|
|
7
9
|
remote: https://rubygems.org/
|
|
8
10
|
specs:
|
|
9
|
-
aws-sdk (1.
|
|
11
|
+
aws-sdk (1.39.0)
|
|
10
12
|
json (~> 1.4)
|
|
11
13
|
nokogiri (>= 1.4.4)
|
|
12
|
-
|
|
14
|
+
coderay (1.1.0)
|
|
15
|
+
diff-lcs (1.2.5)
|
|
13
16
|
json (1.8.1)
|
|
17
|
+
method_source (0.8.2)
|
|
18
|
+
mina (0.3.0)
|
|
19
|
+
open4
|
|
20
|
+
rake
|
|
14
21
|
mini_portile (0.5.3)
|
|
15
22
|
nokogiri (1.6.1)
|
|
16
23
|
mini_portile (~> 0.5.0)
|
|
24
|
+
open4 (1.3.0)
|
|
25
|
+
pry (0.9.12.6)
|
|
26
|
+
coderay (~> 1.0)
|
|
27
|
+
method_source (~> 0.8)
|
|
28
|
+
slop (~> 3.4)
|
|
17
29
|
rake (10.2.2)
|
|
18
|
-
|
|
30
|
+
rspec (2.14.1)
|
|
31
|
+
rspec-core (~> 2.14.0)
|
|
32
|
+
rspec-expectations (~> 2.14.0)
|
|
33
|
+
rspec-mocks (~> 2.14.0)
|
|
34
|
+
rspec-core (2.14.8)
|
|
35
|
+
rspec-expectations (2.14.5)
|
|
36
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
|
37
|
+
rspec-mocks (2.14.6)
|
|
38
|
+
slop (3.4.7)
|
|
19
39
|
|
|
20
40
|
PLATFORMS
|
|
21
41
|
ruby
|
|
22
42
|
|
|
23
43
|
DEPENDENCIES
|
|
24
|
-
aws-sdk
|
|
25
44
|
bundler (~> 1.6)
|
|
26
|
-
|
|
45
|
+
mina
|
|
46
|
+
pry (~> 0.9)
|
|
27
47
|
rodeo_clown!
|
|
48
|
+
rspec (~> 2.14)
|
data/README.md
CHANGED
|
@@ -44,3 +44,14 @@ Rotate new instances into load balancer, with a new image
|
|
|
44
44
|
```ruby
|
|
45
45
|
elb.instances.rotate(image_id: "ami-1234567a")
|
|
46
46
|
```
|
|
47
|
+
|
|
48
|
+
Return array of ec2 instances by tags
|
|
49
|
+
```ruby
|
|
50
|
+
RodeoClown::EC2.by_tags "app" => "foo", "ver" => "1.2"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Build instances from YAML (see examples/ranch_hands.yml)
|
|
54
|
+
```
|
|
55
|
+
lets_dance /path/to/ranch_hands.yml www
|
|
56
|
+
```
|
|
57
|
+
More to come!
|
data/Rakefile
CHANGED
data/bin/elb_rotate.rb
CHANGED
data/bin/lets_dance
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
env = ENV["RACK_ENV"] ||= "development"
|
|
4
|
+
|
|
5
|
+
require "pry"
|
|
6
|
+
require "./lib/rodeo_clown"
|
|
7
|
+
|
|
8
|
+
def print_instructions
|
|
9
|
+
puts "RACK_ENV=[test] lets_dance! /path/to/yml role"
|
|
10
|
+
exit 1
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Build out instances based on options based
|
|
14
|
+
#
|
|
15
|
+
# options - AWS options to customize instance build
|
|
16
|
+
# template - Build a single instance to be used as a template (:template => true)
|
|
17
|
+
#
|
|
18
|
+
# Returns instances
|
|
19
|
+
def build_instances(options, template = nil)
|
|
20
|
+
rc = RodeoClown::EC2.new
|
|
21
|
+
rc.many_from_options(options)
|
|
22
|
+
rc.build_instances(template)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
# Generate a name based on the date, a prefix such as an app name, and an
|
|
27
|
+
# adjuster in case of name collisions
|
|
28
|
+
#
|
|
29
|
+
# Returns a string
|
|
30
|
+
def generate_name(prefix, adjuster)
|
|
31
|
+
"#{Date.today.strftime("%Y-%m-%d")}_#{prefix}.#{adjuster}"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
#
|
|
35
|
+
# Create images based off of instances
|
|
36
|
+
#
|
|
37
|
+
def create_images(instances, prefix)
|
|
38
|
+
adjuster = 0
|
|
39
|
+
images = instances.map do |instance|
|
|
40
|
+
name = nil
|
|
41
|
+
begin
|
|
42
|
+
name = generate_name(prefix, adjuster)
|
|
43
|
+
instance.create_image(name)
|
|
44
|
+
rescue AWS::EC2::Errors::InvalidAMIName::Duplicate
|
|
45
|
+
adjuster += 1
|
|
46
|
+
print "Error with image name : #{name}"
|
|
47
|
+
retry
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
puts "waiting for images to become available"
|
|
52
|
+
images.wait_for_state(:available)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# 5 Hookup-server
|
|
57
|
+
def register(app_name, elb_name)
|
|
58
|
+
elb = RodeoClown::ELB.by_name(elb_name)
|
|
59
|
+
|
|
60
|
+
instances = RodeoClown::EC2.
|
|
61
|
+
by_tags("Name" => app_name).
|
|
62
|
+
select { |x| x.status == :running }
|
|
63
|
+
|
|
64
|
+
elb.register_and_wait instances
|
|
65
|
+
rescue => bang # Timeout
|
|
66
|
+
puts bang
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def deploy(instances, deploy_opts)
|
|
70
|
+
instances.each do |instance|
|
|
71
|
+
puts "Waiting for ssh"
|
|
72
|
+
print "." until instance.ssh_open?
|
|
73
|
+
puts
|
|
74
|
+
|
|
75
|
+
RodeoClown::Deploy.on(
|
|
76
|
+
env: { "DOMAIN" => instance.dns_name, "APP" => deploy_opts["app"], },
|
|
77
|
+
setup: deploy_opts["setup"],
|
|
78
|
+
strategy: "mina",
|
|
79
|
+
)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
begin
|
|
84
|
+
role = ARGV[1]
|
|
85
|
+
|
|
86
|
+
if role.nil?
|
|
87
|
+
print_instructions
|
|
88
|
+
exit
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
options = YAML.load_file("./ranch_hands.yml")[env][role]
|
|
92
|
+
deploy_opts = options.delete "deployment"
|
|
93
|
+
|
|
94
|
+
elbs = options.delete "elbs"
|
|
95
|
+
elb_name = elbs.first
|
|
96
|
+
app_name = options["tags"]["Name"]
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Build the first one
|
|
100
|
+
instances = build_instances(options, :template)
|
|
101
|
+
|
|
102
|
+
# Deploy
|
|
103
|
+
deploy(instances, deploy_opts)
|
|
104
|
+
|
|
105
|
+
# Reboot
|
|
106
|
+
instances.each &:reboot
|
|
107
|
+
|
|
108
|
+
# Create images
|
|
109
|
+
images = create_images(instances, deploy_opts["app"])
|
|
110
|
+
|
|
111
|
+
# Create instances from image
|
|
112
|
+
new_instances = build_instances(options.merge("image_id" => images.first.id))
|
|
113
|
+
|
|
114
|
+
# Destroy original instances
|
|
115
|
+
instances.each &:stop
|
|
116
|
+
|
|
117
|
+
register(app_name, elb_name)
|
|
118
|
+
|
|
119
|
+
puts "Apps Deployed"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#
|
|
2
|
+
# [env]:
|
|
3
|
+
# [role]:
|
|
4
|
+
# ..ALL AWS instance options may be set here... seee
|
|
5
|
+
# http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/EC2/InstanceCollection.html for more info...)
|
|
6
|
+
# tags:
|
|
7
|
+
# key1: value1
|
|
8
|
+
# ...
|
|
9
|
+
# availability_zones:
|
|
10
|
+
# - us-east-1b
|
|
11
|
+
# ...
|
|
12
|
+
#
|
|
13
|
+
test:
|
|
14
|
+
www:
|
|
15
|
+
image_id: ami-ea13a422 # subject to change
|
|
16
|
+
instance_type: c3.2xlarge
|
|
17
|
+
count: 2
|
|
18
|
+
subnet: ""
|
|
19
|
+
block_device_mappings:
|
|
20
|
+
- device_name: "/dev/sda2"
|
|
21
|
+
ebs:
|
|
22
|
+
volume_size: 15, #GB
|
|
23
|
+
delete_on_termination: true
|
|
24
|
+
key_pair_name: my-key-pair
|
|
25
|
+
tags:
|
|
26
|
+
Name: "Ranch Hand 1"
|
|
27
|
+
Env: "development, then probably production"
|
|
28
|
+
security_groups:
|
|
29
|
+
- my-sec-grp-1
|
|
30
|
+
- my-sec-grp-2
|
|
31
|
+
- my-dev-grp
|
|
32
|
+
availability_zones:
|
|
33
|
+
- us-east-1a
|
|
34
|
+
- us-east-1c
|
|
35
|
+
- us-east-1d
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#
|
|
2
|
+
# I wanted to be special and use the Rakefile from Mina to deploy, alas shell
|
|
3
|
+
# scripts just work.
|
|
4
|
+
#
|
|
5
|
+
module RodeoClown
|
|
6
|
+
module DeployStrategy
|
|
7
|
+
class Mina
|
|
8
|
+
|
|
9
|
+
# :options - Hash of options for deploymentj
|
|
10
|
+
# :env - Hash of environment variables to be merged
|
|
11
|
+
# :setup - Should run s
|
|
12
|
+
#
|
|
13
|
+
# NOTE: This "first_argument" manipulation is a hack, wranglers!
|
|
14
|
+
def self.do(options)
|
|
15
|
+
if options.key?(:env)
|
|
16
|
+
options[:env].each { |k, v| ENV[k.to_s] = v }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
deploy_from_shell(options[:setup])
|
|
20
|
+
|
|
21
|
+
puts "Deployment finished.\t\t\t #{options.inspect}"
|
|
22
|
+
|
|
23
|
+
true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.deploy_from_shell(setup, deploy = true)
|
|
27
|
+
vars = %w[DOMAIN BRANCH APP].map { |v| "#{v}=#{ENV[v] || 'master'}" }.join(" ")
|
|
28
|
+
cmd = ""
|
|
29
|
+
cmd << "#{vars} mina setup -v;" if setup
|
|
30
|
+
cmd << "#{vars} mina deploy -v;" if deploy
|
|
31
|
+
|
|
32
|
+
puts "RUNNING '#{cmd}'"
|
|
33
|
+
puts "This may take some time.."
|
|
34
|
+
`#{cmd}`
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/rodeo_clown/ec2.rb
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
require "forwardable"
|
|
2
2
|
module RodeoClown
|
|
3
3
|
class EC2 < Struct.new(:ec2)
|
|
4
|
+
include InstanceBuilder
|
|
5
|
+
|
|
6
|
+
STATUS = %w[pending running shutting-down terminated stopping stopped]
|
|
7
|
+
|
|
4
8
|
def self.instances
|
|
5
9
|
ec2.instances
|
|
6
10
|
end
|
|
@@ -9,30 +13,59 @@ module RodeoClown
|
|
|
9
13
|
@ec2 ||= AWS::EC2.new
|
|
10
14
|
end
|
|
11
15
|
|
|
16
|
+
def self.create_instance(options)
|
|
17
|
+
new_instance = instances.create(options)
|
|
18
|
+
instances.wait_for_status(:running, 2, [*new_instance])
|
|
19
|
+
new_instance
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def create_instance(options)
|
|
23
|
+
self.class.create_instance(options)
|
|
24
|
+
end
|
|
25
|
+
|
|
12
26
|
def self.by_name(name)
|
|
13
27
|
new instances[name]
|
|
14
28
|
end
|
|
15
29
|
|
|
30
|
+
# Filter by had of tag values.
|
|
31
|
+
# Keys and values as strings
|
|
32
|
+
#
|
|
33
|
+
# Examples
|
|
34
|
+
# RodeoClown::EC2.by_tags("app" => "rodeo", "version" = "2.1")
|
|
35
|
+
# # => [ instance-1, instanc-2 ]
|
|
16
36
|
#
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
filtered = filter_by_tag_options(instances, options[:keys], :tagged)
|
|
37
|
+
# Returns an array of instances
|
|
38
|
+
def self.by_tags(options = {})
|
|
39
|
+
return instances if options.nil? || options.empty?
|
|
21
40
|
|
|
22
|
-
|
|
41
|
+
instances.tagged_values(options.values).select do |instance|
|
|
42
|
+
tags = instance.tags.to_h
|
|
43
|
+
(options.to_a - tags.to_a).empty?
|
|
44
|
+
end
|
|
23
45
|
end
|
|
24
46
|
|
|
25
|
-
def
|
|
26
|
-
|
|
47
|
+
def reboot
|
|
48
|
+
ec2.reboot
|
|
49
|
+
end
|
|
27
50
|
|
|
28
|
-
|
|
29
|
-
|
|
51
|
+
def pending?
|
|
52
|
+
ec2.status == :pending
|
|
53
|
+
end
|
|
30
54
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
55
|
+
def running?
|
|
56
|
+
ec2.status == :running
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def stopped?
|
|
60
|
+
ec2.status == :stopped
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def terminated?
|
|
64
|
+
ec2.status == :terminated
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def dns_name
|
|
68
|
+
ec2.dns_name
|
|
36
69
|
end
|
|
37
70
|
end
|
|
38
71
|
end
|
data/lib/rodeo_clown/elb.rb
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
require "forwardable"
|
|
2
2
|
module RodeoClown
|
|
3
|
-
class ELB < Struct.new(:
|
|
4
|
-
|
|
3
|
+
class ELB < Struct.new(:elb)
|
|
4
|
+
|
|
5
|
+
def timeout
|
|
6
|
+
@timeout ||= (ENV["TIMEOUT"] || 60).to_i
|
|
7
|
+
end
|
|
5
8
|
|
|
6
9
|
extend Forwardable
|
|
7
|
-
def_delegators :
|
|
10
|
+
def_delegators :elb, :availability_zones, :instances
|
|
8
11
|
|
|
9
12
|
def self.by_name(name)
|
|
10
13
|
new load_balancers[name]
|
|
@@ -14,15 +17,7 @@ module RodeoClown
|
|
|
14
17
|
AWS::ELB.new.load_balancers
|
|
15
18
|
end
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
# Rotate servers given
|
|
19
|
-
#
|
|
20
|
-
def rotate(hsh)
|
|
21
|
-
current_ec2, new_ec2 = hsh.first
|
|
22
|
-
|
|
23
|
-
cur_instances = EC2.filter_instances(values: { values: current_ec2.to_s})
|
|
24
|
-
new_instances = EC2.filter_instances(values: { values: new_ec2.to_s})
|
|
25
|
-
|
|
20
|
+
def register_and_wait(new_instances)
|
|
26
21
|
new_instances.each do |i|
|
|
27
22
|
begin
|
|
28
23
|
puts "...registering: #{i.id}"
|
|
@@ -33,8 +28,10 @@ module RodeoClown
|
|
|
33
28
|
end
|
|
34
29
|
|
|
35
30
|
wait_for_state(instances, "InService")
|
|
31
|
+
end
|
|
36
32
|
|
|
37
|
-
|
|
33
|
+
def deregister(ary_instances)
|
|
34
|
+
ary_instances.each do |i|
|
|
38
35
|
begin
|
|
39
36
|
puts "...deregistering: #{i.id}"
|
|
40
37
|
instances.deregister(i.id)
|
|
@@ -44,6 +41,19 @@ module RodeoClown
|
|
|
44
41
|
end
|
|
45
42
|
end
|
|
46
43
|
|
|
44
|
+
#
|
|
45
|
+
# Rotate servers given
|
|
46
|
+
#
|
|
47
|
+
def rotate(hsh)
|
|
48
|
+
current_ec2, new_ec2 = hsh.first
|
|
49
|
+
|
|
50
|
+
cur_instances = EC2.by_tags("Name" => current_ec2.to_s)
|
|
51
|
+
new_instances = EC2.by_tags("Name" => new_ec2.to_s)
|
|
52
|
+
|
|
53
|
+
register_and_wait new_instances
|
|
54
|
+
deregister cur_instances
|
|
55
|
+
end
|
|
56
|
+
|
|
47
57
|
#
|
|
48
58
|
# Wait for all the instances to become InService
|
|
49
59
|
#
|
|
@@ -60,7 +70,7 @@ module RodeoClown
|
|
|
60
70
|
exp_state == state
|
|
61
71
|
end
|
|
62
72
|
|
|
63
|
-
break if all_good || time >
|
|
73
|
+
break if all_good || time > timeout
|
|
64
74
|
|
|
65
75
|
sleep 1
|
|
66
76
|
time += 1
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Wait fo
|
|
3
|
+
#
|
|
4
|
+
class Array
|
|
5
|
+
|
|
6
|
+
def wait_for_state(state)
|
|
7
|
+
wait_for_attr_state(:state, :available)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def wait_for_attr_state(attr, state, time = 1)
|
|
11
|
+
until all? { |el| el.send(attr) == state }
|
|
12
|
+
print "."
|
|
13
|
+
sleep time
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
class AWS::EC2::Instance
|
|
2
|
+
include IsPortOpen
|
|
3
|
+
|
|
4
|
+
def port_open?(port)
|
|
5
|
+
super(dns_name, port)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def ssh_open?
|
|
9
|
+
port_open? 22
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def http_open?
|
|
13
|
+
port_open? 80
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def https_open?
|
|
17
|
+
port_open? 443
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class AWS::EC2::InstanceCollection
|
|
2
|
+
def wait_for_status(status, interval = 1, collection = self)
|
|
3
|
+
until collection.all? { |ec2| ec2.status == status }
|
|
4
|
+
puts "Waiting for ALL instances to be #{status}..."
|
|
5
|
+
collection.each { |ec2| print_status(ec2) }
|
|
6
|
+
sleep interval
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
collection
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def print_status(ec2)
|
|
13
|
+
puts "#{ec2.id}\t#{ec2.status}"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -10,7 +10,7 @@ class AWS::ELB::InstanceCollection
|
|
|
10
10
|
|
|
11
11
|
private
|
|
12
12
|
|
|
13
|
-
def wait_for_status(status,
|
|
13
|
+
def wait_for_status(status, interval = 1, collection = self)
|
|
14
14
|
until collection.all? { |ec2| ec2.status == status }
|
|
15
15
|
puts "Waiting for ALL instances to be #{status}..."
|
|
16
16
|
collection.each { |ec2| print_status(ec2) }
|
|
@@ -29,15 +29,15 @@ class AWS::ELB::InstanceCollection
|
|
|
29
29
|
create_instance(instance_attributes(instance).merge(options))
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
wait_for_status(:running, new_instances)
|
|
32
|
+
wait_for_status(:running, 3, new_instances)
|
|
33
33
|
|
|
34
34
|
new_instances
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
def stop_current_instances(interval =
|
|
37
|
+
def stop_current_instances(interval = 3)
|
|
38
38
|
old_instances = map { |instance| stop_instance(instance) }
|
|
39
39
|
|
|
40
|
-
wait_for_status(:stopped)
|
|
40
|
+
wait_for_status(:stopped, interval, old_instance)
|
|
41
41
|
old_instances
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Symbolize Keys functionality
|
|
3
|
+
#
|
|
4
|
+
class Hash
|
|
5
|
+
def symbolize_keys
|
|
6
|
+
inject({}) do |result, (key, v)|
|
|
7
|
+
key = key.to_sym rescue key
|
|
8
|
+
|
|
9
|
+
if v.is_a?(Hash)
|
|
10
|
+
result[key] = v.symbolize_keys
|
|
11
|
+
else
|
|
12
|
+
result[key] = v
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
result
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def symbolize_keys!
|
|
20
|
+
self.replace symbolize_keys
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module RodeoClown
|
|
2
|
+
module InstanceBuilder
|
|
3
|
+
attr_reader :key_pair
|
|
4
|
+
attr_accessor :tags
|
|
5
|
+
attr_reader :availability_zones
|
|
6
|
+
attr_reader :options
|
|
7
|
+
|
|
8
|
+
def many_from_options(options)
|
|
9
|
+
options = options.symbolize_keys # Create a duplicate
|
|
10
|
+
|
|
11
|
+
@key_pair_name = options.delete(:key_pair_name)
|
|
12
|
+
@tags = options.delete(:tags)
|
|
13
|
+
@availability_zones = options.delete(:availability_zones) || []
|
|
14
|
+
@options = options
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def key_pair=(key_pair_name)
|
|
18
|
+
@key_pair = AWS::EC2::KeyPair.new(key_pair_name)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def build_options
|
|
22
|
+
if availability_zones.any?
|
|
23
|
+
availability_zones.map do |zone|
|
|
24
|
+
configs.merge(availability_zone: zone)
|
|
25
|
+
end
|
|
26
|
+
else
|
|
27
|
+
[configs]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Build instances using build options
|
|
32
|
+
#
|
|
33
|
+
# if :template is passed, only build on, used as a template for a new image
|
|
34
|
+
def build_instances(template = nil)
|
|
35
|
+
build_args =
|
|
36
|
+
if template == :template
|
|
37
|
+
[build_options.first.merge(count: 1)]
|
|
38
|
+
else
|
|
39
|
+
build_options
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
build_args.map do |args|
|
|
43
|
+
instances = create_instance args
|
|
44
|
+
apply_tags(instances)
|
|
45
|
+
instances
|
|
46
|
+
end.flatten
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def apply_tags(instances)
|
|
52
|
+
rc_tags = {
|
|
53
|
+
"rc_created_by" => "Rodeo Clown #{RodeoClown::VERSION}",
|
|
54
|
+
"rc_created_at" => Time.now.to_s
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
[*instances].each {|i| i.tags.set(tags.merge(rc_tags)) }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def configs
|
|
61
|
+
options.merge(:key_pair => key_pair)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
require 'timeout'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
module IsPortOpen
|
|
6
|
+
def port_open?(ip, port = 22)
|
|
7
|
+
begin
|
|
8
|
+
Timeout::timeout(1) do
|
|
9
|
+
begin
|
|
10
|
+
s = TCPSocket.new(ip, port)
|
|
11
|
+
s.close
|
|
12
|
+
return true
|
|
13
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
|
14
|
+
return false
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
rescue Timeout::Error
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
false
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/rodeo_clown/version.rb
CHANGED
data/lib/rodeo_clown.rb
CHANGED
|
@@ -3,6 +3,16 @@ require "aws-sdk"
|
|
|
3
3
|
|
|
4
4
|
module RodeoClown
|
|
5
5
|
|
|
6
|
+
def self.configs(env = ENV["RACK_ENV"] || "development")
|
|
7
|
+
@configs ||=
|
|
8
|
+
if File.exists?(file = File.expand_path(".") + "/.rodeo_clown.yml")
|
|
9
|
+
YAML.load_file(file)
|
|
10
|
+
elsif File.exists?(file = File.expand_path("~") + "/.rodeo_clown.yml")
|
|
11
|
+
YAML.load_file(file)
|
|
12
|
+
else
|
|
13
|
+
{}
|
|
14
|
+
end[env]
|
|
15
|
+
end
|
|
6
16
|
#
|
|
7
17
|
# Set aws credentials as environment variables
|
|
8
18
|
# Set aws credentials in the ~/.rodeo_clown.yml
|
|
@@ -13,8 +23,9 @@ module RodeoClown
|
|
|
13
23
|
if ENV.key?("AWS_ACCESS_KEY") && ENV.key?("AWS_SECRET_ACCESS_KEY")
|
|
14
24
|
{ access_key_id: ENV["AWS_ACCESS_KEY"],
|
|
15
25
|
secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"], }
|
|
16
|
-
elsif
|
|
17
|
-
|
|
26
|
+
elsif configs.key?("access_key_id") && configs.key?("secret_access_key")
|
|
27
|
+
{ access_key_id: configs["access_key_id"],
|
|
28
|
+
secret_access_key: configs["secret_access_key"],}
|
|
18
29
|
else
|
|
19
30
|
raise "Please supply aws_access_key and Aws_secret_access_key"
|
|
20
31
|
end
|
|
@@ -23,6 +34,14 @@ end
|
|
|
23
34
|
|
|
24
35
|
AWS.config RodeoClown.credentials # Street cred
|
|
25
36
|
|
|
26
|
-
require_relative "rodeo_clown/
|
|
37
|
+
require_relative "rodeo_clown/ext/array"
|
|
38
|
+
require_relative "rodeo_clown/ext/hash"
|
|
39
|
+
require_relative "rodeo_clown/is_port_open"
|
|
40
|
+
require_relative "rodeo_clown/deploy"
|
|
41
|
+
require_relative "rodeo_clown/deploy_strategy"
|
|
27
42
|
require_relative "rodeo_clown/elb"
|
|
28
|
-
require_relative "rodeo_clown/ext/instance_collection
|
|
43
|
+
require_relative "rodeo_clown/ext/aws/ec2/instance_collection"
|
|
44
|
+
require_relative "rodeo_clown/ext/aws/ec2/instance"
|
|
45
|
+
require_relative "rodeo_clown/instance_builder"
|
|
46
|
+
require_relative "rodeo_clown/ext/aws/elb/instance_collection"
|
|
47
|
+
require_relative "rodeo_clown/ec2"
|
data/rodeo_clown.gemspec
CHANGED
|
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
|
8
8
|
spec.version = RodeoClown::VERSION
|
|
9
9
|
spec.authors = ["Ted Price", "Stephen Korecky"]
|
|
10
10
|
spec.email = ["ted.price@gmail.com"]
|
|
11
|
-
spec.summary = %q{Tools for AWS}
|
|
12
|
-
spec.description = %q{Tools for AWS}
|
|
11
|
+
spec.summary = %q{Tools for provision and deploying to AWS}
|
|
12
|
+
spec.description = %q{Tools for push-button deployment on an app to AWS}
|
|
13
13
|
spec.homepage = "https://github.com/pricees/rodeo_clown/blob/master/README.md"
|
|
14
14
|
spec.license = "Cowboy Code"
|
|
15
15
|
|
|
@@ -18,8 +18,9 @@ Gem::Specification.new do |spec|
|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
19
|
spec.require_paths = ["lib"]
|
|
20
20
|
|
|
21
|
-
spec.
|
|
22
|
-
spec.
|
|
21
|
+
spec.add_dependency "aws-sdk", "~> 1.38"
|
|
22
|
+
spec.add_dependency "rake", "~> 10.2"
|
|
23
23
|
spec.add_development_dependency "bundler", "~> 1.6"
|
|
24
|
-
spec.add_development_dependency "
|
|
24
|
+
spec.add_development_dependency "rspec", "~> 2.14"
|
|
25
|
+
spec.add_development_dependency "pry", "~> 0.9"
|
|
25
26
|
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe RodeoClown::Deploy do
|
|
4
|
+
|
|
5
|
+
let(:instances) do
|
|
6
|
+
double
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
context "deploying is successful" do
|
|
10
|
+
before do
|
|
11
|
+
RodeoClown::Deploy.stub(:before_deploy).and_return true
|
|
12
|
+
RodeoClown::Deploy.stub(:deploy).and_return true
|
|
13
|
+
RodeoClown::Deploy.stub(:after_deploy).and_return true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "returns true" do
|
|
17
|
+
res = RodeoClown::Deploy.on(instances)
|
|
18
|
+
|
|
19
|
+
expect(res).to be_true
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
context "deploying is failure" do
|
|
24
|
+
before do
|
|
25
|
+
RodeoClown::Deploy.stub(:before_deploy).and_return false
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "is a failure" do
|
|
29
|
+
res = RodeoClown::Deploy.on(instances)
|
|
30
|
+
|
|
31
|
+
expect(res).to be_false
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe RodeoClown::DeployStrategy do
|
|
4
|
+
describe "#tool" do
|
|
5
|
+
|
|
6
|
+
context "mina is the strategy " do
|
|
7
|
+
let(:strategy) { "mina" }
|
|
8
|
+
it "returns the mina class" do
|
|
9
|
+
res = RodeoClown::DeployStrategy.by_name(strategy)
|
|
10
|
+
|
|
11
|
+
expect(res).to eq(RodeoClown::DeployStrategy::Mina)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
context "unknown strategy " do
|
|
16
|
+
let(:strategy) { "not_mina" }
|
|
17
|
+
it "raises name error" do
|
|
18
|
+
expect {
|
|
19
|
+
RodeoClown::DeployStrategy.by_name(strategy)
|
|
20
|
+
}.to raise_error(NameError)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require_relative "../spec_helper"
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
describe RodeoClown::EC2 do
|
|
5
|
+
|
|
6
|
+
before do
|
|
7
|
+
RodeoClown::EC2.stub(:instances).
|
|
8
|
+
and_return(double(create: true, wait_for_status: true))
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "creates an image" do
|
|
12
|
+
ec2 = RodeoClown::EC2.create_instance(image_id: "foo")
|
|
13
|
+
|
|
14
|
+
expect(ec2).to_not be_nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe "#reboot" do
|
|
18
|
+
it "reboots" do
|
|
19
|
+
rc_ec2 = RodeoClown::EC2.new
|
|
20
|
+
rc_ec2.stub(:ec2).and_return(double(reboot: true))
|
|
21
|
+
|
|
22
|
+
expect(rc_ec2.reboot).to be_true
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context "status" do
|
|
27
|
+
|
|
28
|
+
it "is pending" do
|
|
29
|
+
ec2 = RodeoClown::EC2.new(double(status: :pending))
|
|
30
|
+
expect(ec2).to be_pending
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "is running" do
|
|
34
|
+
ec2 = RodeoClown::EC2.new(double(status: :running))
|
|
35
|
+
expect(ec2).to be_running
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "is stopped" do
|
|
39
|
+
ec2 = RodeoClown::EC2.new(double(status: :stopped))
|
|
40
|
+
expect(ec2).to be_stopped
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "is terminated" do
|
|
44
|
+
ec2 = RodeoClown::EC2.new(double(status: :terminated))
|
|
45
|
+
expect(ec2).to be_terminated
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe "#by_tags" do
|
|
50
|
+
let(:instance) do
|
|
51
|
+
double(tags: double(to_h: { "name" => "foo" }))
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
before do
|
|
55
|
+
RodeoClown::EC2.stub_chain(:instances, :tagged_values).
|
|
56
|
+
and_return [instance]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "returns instances with match" do
|
|
60
|
+
res = RodeoClown::EC2.by_tags "name" => "foo"
|
|
61
|
+
|
|
62
|
+
expect(res).to include(instance)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "returns empty array if no match" do
|
|
66
|
+
res = RodeoClown::EC2.by_tags "NAME" => "FOO"
|
|
67
|
+
|
|
68
|
+
expect(res).to be_empty
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rodeo_clown
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ted Price
|
|
@@ -9,85 +9,115 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2014-
|
|
12
|
+
date: 2014-06-02 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: aws-sdk
|
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
|
17
17
|
requirements:
|
|
18
|
-
- - ~>
|
|
18
|
+
- - "~>"
|
|
19
19
|
- !ruby/object:Gem::Version
|
|
20
20
|
version: '1.38'
|
|
21
21
|
type: :runtime
|
|
22
22
|
prerelease: false
|
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
|
24
24
|
requirements:
|
|
25
|
-
- - ~>
|
|
25
|
+
- - "~>"
|
|
26
26
|
- !ruby/object:Gem::Version
|
|
27
27
|
version: '1.38'
|
|
28
28
|
- !ruby/object:Gem::Dependency
|
|
29
|
-
name:
|
|
29
|
+
name: rake
|
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
|
31
31
|
requirements:
|
|
32
|
-
- - ~>
|
|
32
|
+
- - "~>"
|
|
33
33
|
- !ruby/object:Gem::Version
|
|
34
|
-
version: '
|
|
35
|
-
type: :
|
|
34
|
+
version: '10.2'
|
|
35
|
+
type: :runtime
|
|
36
36
|
prerelease: false
|
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
|
38
38
|
requirements:
|
|
39
|
-
- - ~>
|
|
39
|
+
- - "~>"
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
|
-
version: '
|
|
41
|
+
version: '10.2'
|
|
42
42
|
- !ruby/object:Gem::Dependency
|
|
43
43
|
name: bundler
|
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
|
45
45
|
requirements:
|
|
46
|
-
- - ~>
|
|
46
|
+
- - "~>"
|
|
47
47
|
- !ruby/object:Gem::Version
|
|
48
48
|
version: '1.6'
|
|
49
49
|
type: :development
|
|
50
50
|
prerelease: false
|
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
|
52
52
|
requirements:
|
|
53
|
-
- - ~>
|
|
53
|
+
- - "~>"
|
|
54
54
|
- !ruby/object:Gem::Version
|
|
55
55
|
version: '1.6'
|
|
56
56
|
- !ruby/object:Gem::Dependency
|
|
57
|
-
name:
|
|
57
|
+
name: rspec
|
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - "~>"
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '2.14'
|
|
63
|
+
type: :development
|
|
64
|
+
prerelease: false
|
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
66
|
+
requirements:
|
|
67
|
+
- - "~>"
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '2.14'
|
|
70
|
+
- !ruby/object:Gem::Dependency
|
|
71
|
+
name: pry
|
|
58
72
|
requirement: !ruby/object:Gem::Requirement
|
|
59
73
|
requirements:
|
|
60
|
-
- -
|
|
74
|
+
- - "~>"
|
|
61
75
|
- !ruby/object:Gem::Version
|
|
62
|
-
version: '0'
|
|
76
|
+
version: '0.9'
|
|
63
77
|
type: :development
|
|
64
78
|
prerelease: false
|
|
65
79
|
version_requirements: !ruby/object:Gem::Requirement
|
|
66
80
|
requirements:
|
|
67
|
-
- -
|
|
81
|
+
- - "~>"
|
|
68
82
|
- !ruby/object:Gem::Version
|
|
69
|
-
version: '0'
|
|
70
|
-
description: Tools for AWS
|
|
83
|
+
version: '0.9'
|
|
84
|
+
description: Tools for push-button deployment on an app to AWS
|
|
71
85
|
email:
|
|
72
86
|
- ted.price@gmail.com
|
|
73
87
|
executables:
|
|
74
88
|
- elb_rotate.rb
|
|
89
|
+
- lets_dance
|
|
75
90
|
extensions: []
|
|
76
91
|
extra_rdoc_files: []
|
|
77
92
|
files:
|
|
78
|
-
- .gitignore
|
|
93
|
+
- ".gitignore"
|
|
79
94
|
- Gemfile
|
|
80
95
|
- Gemfile.lock
|
|
81
96
|
- LICENSE.txt
|
|
82
97
|
- README.md
|
|
83
98
|
- Rakefile
|
|
84
99
|
- bin/elb_rotate.rb
|
|
100
|
+
- bin/lets_dance
|
|
101
|
+
- examples/ranch_hands.yml
|
|
85
102
|
- lib/rodeo_clown.rb
|
|
103
|
+
- lib/rodeo_clown/deploy.rb
|
|
104
|
+
- lib/rodeo_clown/deploy_strategy.rb
|
|
105
|
+
- lib/rodeo_clown/deploy_strategy/mina.rb
|
|
86
106
|
- lib/rodeo_clown/ec2.rb
|
|
87
107
|
- lib/rodeo_clown/elb.rb
|
|
88
|
-
- lib/rodeo_clown/ext/
|
|
108
|
+
- lib/rodeo_clown/ext/array.rb
|
|
109
|
+
- lib/rodeo_clown/ext/aws/ec2/instance.rb
|
|
110
|
+
- lib/rodeo_clown/ext/aws/ec2/instance_collection.rb
|
|
111
|
+
- lib/rodeo_clown/ext/aws/elb/instance_collection.rb
|
|
112
|
+
- lib/rodeo_clown/ext/hash.rb
|
|
113
|
+
- lib/rodeo_clown/instance_builder.rb
|
|
114
|
+
- lib/rodeo_clown/is_port_open.rb
|
|
89
115
|
- lib/rodeo_clown/version.rb
|
|
90
116
|
- rodeo_clown.gemspec
|
|
117
|
+
- spec/rodeo_clown/deploy_spec.rb
|
|
118
|
+
- spec/rodeo_clown/deploy_strategy_spec.rb
|
|
119
|
+
- spec/rodeo_clown/ec2_spec.rb
|
|
120
|
+
- spec/spec_helper.rb
|
|
91
121
|
homepage: https://github.com/pricees/rodeo_clown/blob/master/README.md
|
|
92
122
|
licenses:
|
|
93
123
|
- Cowboy Code
|
|
@@ -98,18 +128,23 @@ require_paths:
|
|
|
98
128
|
- lib
|
|
99
129
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
100
130
|
requirements:
|
|
101
|
-
- -
|
|
131
|
+
- - ">="
|
|
102
132
|
- !ruby/object:Gem::Version
|
|
103
133
|
version: '0'
|
|
104
134
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
135
|
requirements:
|
|
106
|
-
- -
|
|
136
|
+
- - ">="
|
|
107
137
|
- !ruby/object:Gem::Version
|
|
108
138
|
version: '0'
|
|
109
139
|
requirements: []
|
|
110
140
|
rubyforge_project:
|
|
111
|
-
rubygems_version: 2.
|
|
141
|
+
rubygems_version: 2.2.2
|
|
112
142
|
signing_key:
|
|
113
143
|
specification_version: 4
|
|
114
|
-
summary: Tools for AWS
|
|
115
|
-
test_files:
|
|
144
|
+
summary: Tools for provision and deploying to AWS
|
|
145
|
+
test_files:
|
|
146
|
+
- spec/rodeo_clown/deploy_spec.rb
|
|
147
|
+
- spec/rodeo_clown/deploy_strategy_spec.rb
|
|
148
|
+
- spec/rodeo_clown/ec2_spec.rb
|
|
149
|
+
- spec/spec_helper.rb
|
|
150
|
+
has_rdoc:
|