rodeo_clown 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 55ed6fc33066e5ee66123312b2597ac4fc04b226
4
- data.tar.gz: ee3f47d79e71d7674403f12861b7c4af8ea4d24b
3
+ metadata.gz: a4da4d0f35035c6aa16f41273d0543ea8a3a8bc8
4
+ data.tar.gz: 4439e2e501ec29569e76a7b3c6bf3ad519b0f270
5
5
  SHA512:
6
- metadata.gz: 789a4d8928dc33a97a44b906fee0391d08444c7d61a733c4d5f7731e19a7970a8562deb033320ad12b26c1826de833cd01601021f772737c540744aad7a42973
7
- data.tar.gz: bac588d85fda57f0bc8e5649c085c5ba4cf6a3712e45b067b30c447ae28879b8ab1d00cf03c286abb50575dafb33f0badb7a4d29fc5c7c09b7f5b471552b360c
6
+ metadata.gz: a644e9d5cbe229dbf83c66e2f99df2648d2bd127c94413fa3a18a0346fee43ed41220d9c9442d297a14ba21b2c582b9cff14fba84e9394bc4ba0cd9cfa4c8ccd
7
+ data.tar.gz: e0430cb18ac6fea5c92d2b6e7250964e9d41e2b3b4ec398ddc4b1776b473642c72e46f42064d91986f508c9b3a9a20564853cfa04d340900d3d8c06e9d9c9bb6
data/Gemfile CHANGED
@@ -3,4 +3,4 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in rodeo_clown.gemspec
4
4
  gemspec
5
5
 
6
- gem "aws-sdk"
6
+ gem "mina"
data/Gemfile.lock CHANGED
@@ -1,27 +1,48 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rodeo_clown (0.0.1)
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.38.0)
11
+ aws-sdk (1.39.0)
10
12
  json (~> 1.4)
11
13
  nokogiri (>= 1.4.4)
12
- uuidtools (~> 2.1)
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
- uuidtools (2.1.4)
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
- rake
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
@@ -1,2 +1,7 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
2
7
 
data/bin/elb_rotate.rb CHANGED
@@ -34,9 +34,3 @@ end
34
34
 
35
35
  rc_elb = get_elb
36
36
  puts rc_elb.instances.map &:id
37
-
38
-
39
- #puts "rotating 'giftcards1' -> 'giftcards2'"
40
- #elb.rotate("giftcards1" => "giftcards2")
41
-
42
- #puts "done!"
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,16 @@
1
+ module RodeoClown
2
+ module Deploy
3
+
4
+ def self.on(options = {})
5
+ deploy(options)
6
+ end
7
+
8
+ private
9
+
10
+ def self.deploy(options)
11
+ strategy = DeployStrategy.by_name(options[:strategy])
12
+ strategy.do(options)
13
+ strategy
14
+ end
15
+ end
16
+ end
@@ -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
@@ -0,0 +1,9 @@
1
+ module RodeoClown
2
+ module DeployStrategy
3
+
4
+ def self.by_name name
5
+ const_get name.capitalize
6
+ end
7
+ end
8
+ end
9
+ require_relative "deploy_strategy/mina"
@@ -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
- # options: keys: [ foo... , scope: :all], [:values scope: any]
18
- #
19
- def self.filter_instances(options = {})
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
- filter_by_tag_options(filtered, options[:values], :tagged_values)
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 self.filter_by_tag_options(instances, options, filter = :tagged_values)
26
- return instances if options.nil? || options.empty?
47
+ def reboot
48
+ ec2.reboot
49
+ end
27
50
 
28
- all = options.delete(:scope) == :all
29
- vals = options.delete(:values)
51
+ def pending?
52
+ ec2.status == :pending
53
+ end
30
54
 
31
- if all
32
- vals.inject(instances) { |i, value| i.send(filter, value) }
33
- else
34
- instances.send filter, *vals
35
- end
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
@@ -1,10 +1,13 @@
1
1
  require "forwardable"
2
2
  module RodeoClown
3
- class ELB < Struct.new(:aws_elb)
4
- TIMEOUT = 10
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 :aws_elb, :availability_zones, :instances
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
- cur_instances.each do |i|
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 > TIMEOUT
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, collection = self, interval = 5)
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 = 5)
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
@@ -1,3 +1,3 @@
1
1
  module RodeoClown
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
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 File.exists?(file = File.expand_path("~") + "/.rodeo_clown.yml")
17
- YAML.load_file(file)
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/ec2"
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.rb"
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.add_runtime_dependency "aws-sdk", "~> 1.38"
22
- spec.add_development_dependency "aws-sdk", "~> 1.38"
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 "rake"
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
@@ -0,0 +1,4 @@
1
+ require "rspec"
2
+ require "rspec/mocks/standalone"
3
+
4
+ require_relative "../lib/rodeo_clown.rb"
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.1
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-04-29 00:00:00.000000000 Z
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: aws-sdk
29
+ name: rake
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ~>
32
+ - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: '1.38'
35
- type: :development
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: '1.38'
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: rake
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/instance_collection.rb
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.0.3
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: