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 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: