elba 0.0.4
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.
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +87 -0
- data/Guardfile +5 -0
- data/LICENSE +20 -0
- data/README.md +57 -0
- data/Rakefile +9 -0
- data/bin/elba +7 -0
- data/elba.gemspec +31 -0
- data/lib/elba/cli.rb +124 -0
- data/lib/elba/client.rb +39 -0
- data/lib/elba.rb +5 -0
- data/spec/lib/elba/cli_spec.rb +212 -0
- data/spec/lib/elba/client_spec.rb +80 -0
- data/spec/spec_helper.rb +47 -0
- data/spec/support/mocks.rb +20 -0
- data/vendor/excon-0.27.6.gem +0 -0
- metadata +205 -0
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3-p385
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
elba (0.0.4)
|
5
|
+
fog
|
6
|
+
thor
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://housetripgems.herokuapp.com/
|
10
|
+
specs:
|
11
|
+
builder (3.2.2)
|
12
|
+
celluloid (0.15.2)
|
13
|
+
timers (~> 1.1.0)
|
14
|
+
coderay (1.0.9)
|
15
|
+
diff-lcs (1.2.4)
|
16
|
+
excon (0.27.6)
|
17
|
+
ffi (1.9.0)
|
18
|
+
fog (1.16.0)
|
19
|
+
builder
|
20
|
+
excon (~> 0.27.0)
|
21
|
+
formatador (~> 0.2.0)
|
22
|
+
mime-types
|
23
|
+
multi_json (~> 1.0)
|
24
|
+
net-scp (~> 1.1)
|
25
|
+
net-ssh (>= 2.1.3)
|
26
|
+
nokogiri (~> 1.5)
|
27
|
+
ruby-hmac
|
28
|
+
unicode (~> 0.4.4)
|
29
|
+
formatador (0.2.4)
|
30
|
+
guard (2.2.2)
|
31
|
+
formatador (>= 0.2.4)
|
32
|
+
listen (~> 2.1)
|
33
|
+
lumberjack (~> 1.0)
|
34
|
+
pry (>= 0.9.12)
|
35
|
+
thor (>= 0.18.1)
|
36
|
+
guard-rspec (3.0.2)
|
37
|
+
guard (>= 1.8)
|
38
|
+
rspec (~> 2.13)
|
39
|
+
listen (2.1.1)
|
40
|
+
celluloid (>= 0.15.2)
|
41
|
+
rb-fsevent (>= 0.9.3)
|
42
|
+
rb-inotify (>= 0.9)
|
43
|
+
lumberjack (1.0.4)
|
44
|
+
method_source (0.8.2)
|
45
|
+
mime-types (1.25)
|
46
|
+
mini_portile (0.5.1)
|
47
|
+
multi_json (1.8.2)
|
48
|
+
net-scp (1.1.2)
|
49
|
+
net-ssh (>= 2.6.5)
|
50
|
+
net-ssh (2.7.0)
|
51
|
+
nokogiri (1.6.0)
|
52
|
+
mini_portile (~> 0.5.0)
|
53
|
+
pry (0.9.12.2)
|
54
|
+
coderay (~> 1.0.5)
|
55
|
+
method_source (~> 0.8)
|
56
|
+
slop (~> 3.4)
|
57
|
+
pry-nav (0.2.3)
|
58
|
+
pry (~> 0.9.10)
|
59
|
+
rake (10.1.0)
|
60
|
+
rb-fsevent (0.9.3)
|
61
|
+
rb-inotify (0.9.1)
|
62
|
+
ffi (>= 0.5.0)
|
63
|
+
rspec (2.14.1)
|
64
|
+
rspec-core (~> 2.14.0)
|
65
|
+
rspec-expectations (~> 2.14.0)
|
66
|
+
rspec-mocks (~> 2.14.0)
|
67
|
+
rspec-core (2.14.6)
|
68
|
+
rspec-expectations (2.14.3)
|
69
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
70
|
+
rspec-mocks (2.14.4)
|
71
|
+
ruby-hmac (0.4.0)
|
72
|
+
slop (3.4.6)
|
73
|
+
thor (0.18.1)
|
74
|
+
timers (1.1.0)
|
75
|
+
unicode (0.4.4)
|
76
|
+
|
77
|
+
PLATFORMS
|
78
|
+
ruby
|
79
|
+
|
80
|
+
DEPENDENCIES
|
81
|
+
bundler
|
82
|
+
elba!
|
83
|
+
guard-rspec
|
84
|
+
pry
|
85
|
+
pry-nav
|
86
|
+
rake
|
87
|
+
rspec
|
data/Guardfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 HouseTrip
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Elba [](https://travis-ci.org/HouseTrip/elba)
|
2
|
+
|
3
|
+
Command-line interface for Amazon's ELB
|
4
|
+
|
5
|
+
## Getting started
|
6
|
+
|
7
|
+
Elba relies on the excellent [Fog gem](http://fog.io/) to connect to Amazon's APIs.
|
8
|
+
Start by setting up your `~/.fog`:
|
9
|
+
|
10
|
+
# ~/.fog
|
11
|
+
:default:
|
12
|
+
:aws_access_key_id: ABCDEF....
|
13
|
+
:aws_secret_access_key: 123456....
|
14
|
+
|
15
|
+
## Available Commands
|
16
|
+
|
17
|
+
elba help # prints this message
|
18
|
+
elba list # list available load balancers, pass option -i to list instances attached
|
19
|
+
elba attach [INSTANCES] # attach INSTANCES to an ELB, pass option --to to specify which one
|
20
|
+
elba detach [INSTANCES] # detach INSTANCES from their ELB
|
21
|
+
|
22
|
+
Adding or removing a server will prompt the user which load balancer they wish the server to be removed from.
|
23
|
+
Your AWS Access Key defines which environments you have access to and thus which load balancers will be listed and available.
|
24
|
+
|
25
|
+
## Examples
|
26
|
+
|
27
|
+
$ elba list
|
28
|
+
2 ELB found:
|
29
|
+
* staging
|
30
|
+
* production
|
31
|
+
|
32
|
+
$ elba list -i
|
33
|
+
2 ELB found:
|
34
|
+
* staging
|
35
|
+
- i-xxxxxxxx
|
36
|
+
- i-yyyyyyyy
|
37
|
+
* production
|
38
|
+
- i-aaaaaaaa
|
39
|
+
- i-bbbbbbbb
|
40
|
+
- i-cccccccc
|
41
|
+
|
42
|
+
$ elba attach i-xxxxxxxx --to staging
|
43
|
+
i-xxxxxxxx successfully added to staging
|
44
|
+
|
45
|
+
$ elba attach i-xxxxxxxx
|
46
|
+
More than one ELB available, pick one in the list
|
47
|
+
0 staging
|
48
|
+
1 production
|
49
|
+
Use: ["0", "1"] 0
|
50
|
+
i-xxxxxxxx is already attached to staging
|
51
|
+
|
52
|
+
$ elba detach i-xxxxxxxx
|
53
|
+
i-xxxxxxxx successfully detached from staging
|
54
|
+
|
55
|
+
$ elba detach i-xxxxxxxx
|
56
|
+
i-xxxxxxxx isn't attached to any known ELB
|
57
|
+
|
data/Rakefile
ADDED
data/bin/elba
ADDED
data/elba.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
lib = File.expand_path('lib')
|
4
|
+
$:.unshift(lib) unless $:.include?(lib)
|
5
|
+
|
6
|
+
require 'elba'
|
7
|
+
|
8
|
+
Gem::Specification.new do |s|
|
9
|
+
s.name = "elba"
|
10
|
+
s.version = Elba::VERSION
|
11
|
+
s.authors = ["Marcus Mitchell", "Mark Connell", "Thibault Gautriaud"]
|
12
|
+
s.email = ["marcusleemitchell@gmail.com", "mark@neo.com", "hubbbbb@gmail.com"]
|
13
|
+
s.homepage = "https://github.com/housetrip/elba"
|
14
|
+
s.summary = "Command-line interface for Amazon's ELB"
|
15
|
+
s.description = "Command-line interface for Amazon's ELB"
|
16
|
+
|
17
|
+
s.add_development_dependency "bundler"
|
18
|
+
s.add_development_dependency "rspec"
|
19
|
+
s.add_development_dependency "guard-rspec"
|
20
|
+
s.add_development_dependency "rake"
|
21
|
+
s.add_development_dependency "pry"
|
22
|
+
s.add_development_dependency "pry-nav"
|
23
|
+
|
24
|
+
s.add_dependency "fog"
|
25
|
+
s.add_dependency "thor"
|
26
|
+
|
27
|
+
s.files = `git ls-files`.split("\n")
|
28
|
+
s.test_files = `git ls-files -- spec/*/*_spec*`.split("\n")
|
29
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
30
|
+
s.require_path = "lib"
|
31
|
+
end
|
data/lib/elba/cli.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'thor'
|
4
|
+
require 'yaml'
|
5
|
+
require 'elba/client'
|
6
|
+
|
7
|
+
module Elba
|
8
|
+
# The Command Line Interface for Elba.
|
9
|
+
class Cli < Thor
|
10
|
+
include Thor::Actions
|
11
|
+
|
12
|
+
no_tasks do
|
13
|
+
# Parse config stored in ~/.fog
|
14
|
+
# Use :default environment
|
15
|
+
def config(env = :default)
|
16
|
+
@config ||= {}.tap do |c|
|
17
|
+
c.merge! YAML.load(File.open File.expand_path('.fog', Dir.home))[env]
|
18
|
+
c.merge! region: 'eu-west-1'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# A permanent access to a Client
|
23
|
+
def client
|
24
|
+
@client ||= Client.new config
|
25
|
+
end
|
26
|
+
|
27
|
+
# Helper method to store the ELBs
|
28
|
+
def elbs
|
29
|
+
@elbs ||= client.load_balancers
|
30
|
+
end
|
31
|
+
|
32
|
+
def elbs_names
|
33
|
+
elbs.map(&:id)
|
34
|
+
end
|
35
|
+
|
36
|
+
def elbs_with_index
|
37
|
+
elbs.map.with_index { |elb, i| [i, elb.id] }
|
38
|
+
end
|
39
|
+
|
40
|
+
def find_elb(options = {})
|
41
|
+
name = options.fetch(:name) { elbs_with_index[options[:choice]].last }
|
42
|
+
elbs.find { |elb| elb.id == name }
|
43
|
+
end
|
44
|
+
|
45
|
+
def for_choice
|
46
|
+
elbs_with_index.map(&:first).map(&:to_s)
|
47
|
+
end
|
48
|
+
|
49
|
+
def success(message = "")
|
50
|
+
say message, :green
|
51
|
+
end
|
52
|
+
|
53
|
+
def warn(message = "")
|
54
|
+
say message, :yellow
|
55
|
+
end
|
56
|
+
|
57
|
+
def error(message = "")
|
58
|
+
say message, :red
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
desc "list", "Prints the list of available load balancers"
|
64
|
+
option :instances, type: :boolean, aliases: :i, desc: "Prints instances id attached to each load balancer"
|
65
|
+
def list(with_instances = options[:instances])
|
66
|
+
say "#{elbs.size} ELB found:"
|
67
|
+
elbs.map do |elb|
|
68
|
+
say " * #{elb.id}"
|
69
|
+
elb.instances.map { |i| success " - #{i}" } if with_instances
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
desc "attach INSTANCES", "Attaches given instances ids to a load balancer"
|
75
|
+
option :to, type: :string, aliases: :t, desc: "Specifies which load balancer to use"
|
76
|
+
def attach(*instances)
|
77
|
+
elb = if options[:to]
|
78
|
+
find_elb(name: options[:to])
|
79
|
+
else
|
80
|
+
case
|
81
|
+
when elbs.size == 0
|
82
|
+
error "No load balancer available"
|
83
|
+
return
|
84
|
+
when elbs.size == 1
|
85
|
+
warn "Using default load balancer: #{elbs.first.id}"
|
86
|
+
elbs.first
|
87
|
+
when elbs.size > 1
|
88
|
+
warn "You must specify an ELB"
|
89
|
+
print_table elbs_with_index
|
90
|
+
choice = ask("Use:", :yellow, limited_to: for_choice).to_i
|
91
|
+
find_elb(choice: choice)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
instances.map do |instance|
|
96
|
+
client.attach(instance, elb,
|
97
|
+
on_success: -> { success "#{instance} successfully attached to #{elb.id}" },
|
98
|
+
on_failure: ->(reason) {
|
99
|
+
error "Unable to attach #{instance} to #{elb.id}"
|
100
|
+
warn "Reason: #{reason}"
|
101
|
+
}
|
102
|
+
)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
desc "detach INSTANCES", "Detach INSTANCES from their Load Balancer"
|
108
|
+
def detach(*instances)
|
109
|
+
elbs.reload.select { |elb| (elb.instances & instances).any? }.tap do |lbs|
|
110
|
+
warn "Unable to find any ELB to detach #{instances.join(', ')}" if lbs.empty?
|
111
|
+
lbs.map do |elb|
|
112
|
+
target_instances = elb.instances & instances
|
113
|
+
client.detach(target_instances, elb,
|
114
|
+
on_success: -> { success "#{target_instances.join(', ')} successfully detached from #{elb.id}" },
|
115
|
+
on_failure: ->(reason) {
|
116
|
+
error "Unable to detach #{target_instances.join(', ')} from #{elb.id}"
|
117
|
+
warn "Reason: #{reason}"
|
118
|
+
}
|
119
|
+
)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/lib/elba/client.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'fog'
|
4
|
+
require 'forwardable'
|
5
|
+
|
6
|
+
module Elba
|
7
|
+
class Client
|
8
|
+
extend Forwardable
|
9
|
+
attr_reader :connection
|
10
|
+
|
11
|
+
def initialize(config = {})
|
12
|
+
raise "Missing AWS credentials" unless valid_config?(config)
|
13
|
+
@connection = Fog::AWS::ELB.new(config)
|
14
|
+
end
|
15
|
+
|
16
|
+
def_delegator :connection, :load_balancers
|
17
|
+
|
18
|
+
def attach(instance, load_balancer, callbacks = {})
|
19
|
+
load_balancer = load_balancer.register_instances instance
|
20
|
+
callbacks[:on_success].call if callbacks[:on_success]
|
21
|
+
rescue Exception => ex
|
22
|
+
callbacks[:on_failure].call(ex) if callbacks[:on_failure]
|
23
|
+
end
|
24
|
+
|
25
|
+
def detach(instances, load_balancer, callbacks = {})
|
26
|
+
load_balancer = load_balancer.deregister_instances instances
|
27
|
+
callbacks[:on_success].call if callbacks[:on_success]
|
28
|
+
rescue Exception => ex
|
29
|
+
callbacks[:on_failure].call(ex) if callbacks[:on_failure]
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def valid_config?(config)
|
36
|
+
(config.keys & [:aws_secret_access_key, :aws_access_key_id, :region]).any?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/elba.rb
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'elba/cli'
|
3
|
+
|
4
|
+
describe Elba::Cli do
|
5
|
+
include Elba::Mocks
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
# Use test config
|
9
|
+
subject.stub config: test_config
|
10
|
+
|
11
|
+
# Create an ELB
|
12
|
+
subject.client.connection.create_load_balancer([test_config[:region]], 'elba-test')
|
13
|
+
end
|
14
|
+
|
15
|
+
after :each do
|
16
|
+
subject.client.load_balancers.map(&:destroy)
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:elb) { subject.elbs.first }
|
20
|
+
let(:instance1) { test_ec2_connection.servers.create region: test_config[:region] }
|
21
|
+
let(:instance2) { test_ec2_connection.servers.create region: test_config[:region] }
|
22
|
+
|
23
|
+
describe 'help' do
|
24
|
+
|
25
|
+
let(:output) { capture(:stdout) { subject.help } }
|
26
|
+
|
27
|
+
it "can list" do
|
28
|
+
output.should include "list"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "can attach" do
|
32
|
+
output.should include "attach"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "can detach" do
|
36
|
+
output.should include "detach"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'list' do
|
41
|
+
it 'prints the list of available ELB' do
|
42
|
+
output = capture(:stdout) {
|
43
|
+
subject.list
|
44
|
+
}
|
45
|
+
|
46
|
+
output.should include "1 ELB found"
|
47
|
+
output.should include " * #{elb.id}"
|
48
|
+
end
|
49
|
+
|
50
|
+
context '--instances' do
|
51
|
+
it 'prints instances attached to each load balancer' do
|
52
|
+
elb.stub instances: [instance1.id]
|
53
|
+
|
54
|
+
output = capture(:stdout) {
|
55
|
+
subject.list('--instances')
|
56
|
+
}
|
57
|
+
|
58
|
+
output.should include "1 ELB found"
|
59
|
+
output.should include " * #{elb.id}"
|
60
|
+
output.should include " - #{instance1.id}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'attach' do
|
66
|
+
shared_examples_for "asking user" do
|
67
|
+
before do
|
68
|
+
subject.client.connection.create_load_balancer([test_config[:region]], 'elba-test-2')
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'which load balancer to use' do
|
72
|
+
allow(subject).to receive(:ask).and_return("0")
|
73
|
+
|
74
|
+
output.should include "You must specify an ELB"
|
75
|
+
output.should include "successfully"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'instance1' do
|
80
|
+
let(:perform) { subject.attach instance1.id }
|
81
|
+
let(:output) { capture(:stdout) { perform } }
|
82
|
+
|
83
|
+
it 'exits if no ELB available' do
|
84
|
+
subject.stub elbs: []
|
85
|
+
|
86
|
+
output.should include "No load balancer available"
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'uses default ELB when only 1 available' do
|
90
|
+
output.should include "Using default load balancer: #{elb.id}"
|
91
|
+
output.should include "#{instance1.id} successfully attached to #{elb.id}"
|
92
|
+
end
|
93
|
+
|
94
|
+
it_should_behave_like "asking user"
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'instance1 instance2' do
|
98
|
+
let(:perform) { subject.attach instance1.id, instance2.id }
|
99
|
+
let(:output) { capture(:stdout) { perform } }
|
100
|
+
|
101
|
+
it_should_behave_like "asking user"
|
102
|
+
|
103
|
+
it 'works and reports success' do
|
104
|
+
allow(subject).to receive(:ask).and_return("0")
|
105
|
+
|
106
|
+
output.should include "#{instance1.id} successfully attached to #{elb.id}"
|
107
|
+
output.should include "#{instance2.id} successfully attached to #{elb.id}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
shared_examples_for "not asking user" do
|
112
|
+
before do
|
113
|
+
subject.client.connection.create_load_balancer([test_config[:region]], 'elba-test-2')
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'which load balancer to use' do
|
117
|
+
allow(subject).to receive(:ask)
|
118
|
+
|
119
|
+
output.should_not include "No load balancer available"
|
120
|
+
output.should_not include "Using default load balancer"
|
121
|
+
output.should_not include "You must specify an ELB"
|
122
|
+
expect(subject).to_not have_received(:ask)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context '--to elb instance1' do
|
127
|
+
let(:perform) do
|
128
|
+
subject.stub options: {to: elb.id}
|
129
|
+
subject.attach instance1.id
|
130
|
+
end
|
131
|
+
|
132
|
+
let(:output) { capture(:stdout) { perform } }
|
133
|
+
|
134
|
+
it_should_behave_like "not asking user"
|
135
|
+
|
136
|
+
it 'works and reports success' do
|
137
|
+
output.should include "#{instance1.id} successfully attached to #{elb.id}"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context '--to elb instance1 instance2' do
|
142
|
+
let(:perform) do
|
143
|
+
subject.stub options: {to: elb.id}
|
144
|
+
subject.attach instance1.id, instance2.id
|
145
|
+
end
|
146
|
+
|
147
|
+
let(:output) { capture(:stdout) { perform } }
|
148
|
+
|
149
|
+
it_should_behave_like "not asking user"
|
150
|
+
|
151
|
+
it 'works and reports success' do
|
152
|
+
output.should include "#{instance1.id} successfully attached to #{elb.id}"
|
153
|
+
output.should include "#{instance2.id} successfully attached to #{elb.id}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
describe 'detach' do
|
160
|
+
before do
|
161
|
+
silence(:stdout) { subject.client.attach(instance1.id, elb, {}) }
|
162
|
+
end
|
163
|
+
|
164
|
+
let(:output) { capture(:stdout) { perform } }
|
165
|
+
|
166
|
+
context 'instance1' do
|
167
|
+
let(:perform) { subject.detach instance1.id }
|
168
|
+
|
169
|
+
it 'works and reports success' do
|
170
|
+
output.should include "#{instance1.id} successfully detached from #{elb.id}"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context 'instance1 instance2' do
|
175
|
+
before do
|
176
|
+
silence(:stdout) { subject.client.attach(instance2.id, elb) }
|
177
|
+
end
|
178
|
+
|
179
|
+
let(:perform) { subject.detach instance1.id, instance2.id }
|
180
|
+
|
181
|
+
it 'works and reports success' do
|
182
|
+
output.should include "#{instance1.id}, #{instance2.id} successfully detached from #{elb.id}"
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'warn if instances not attached to any ELB' do
|
186
|
+
silence(:stdout) { subject.detach instance1.id, instance2.id }
|
187
|
+
output.should include "Unable to find any ELB to detach #{instance1.id}, #{instance2.id}"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context 'with 3 instances attached to 2 ELBs' do
|
192
|
+
let(:instance3) { test_ec2_connection.servers.create region: test_config[:region] }
|
193
|
+
let(:elb2) { subject.client.load_balancers.find { |lb| lb.id == 'elba-test-2' } }
|
194
|
+
|
195
|
+
describe 'detaching all instances at once' do
|
196
|
+
before do
|
197
|
+
subject.client.connection.create_load_balancer([test_config[:region]], 'elba-test-2')
|
198
|
+
silence(:stdout) { subject.client.attach(instance2.id, elb) }
|
199
|
+
silence(:stdout) { subject.client.attach(instance3.id, elb2) }
|
200
|
+
end
|
201
|
+
|
202
|
+
let(:output) { capture(:stdout) { subject.detach instance1.id, instance3.id, instance2.id } }
|
203
|
+
|
204
|
+
it 'works like a charm' do
|
205
|
+
output.should include "#{instance1.id}, #{instance2.id} successfully detached from #{elb.id}"
|
206
|
+
output.should include "#{instance3.id} successfully detached from #{elb2.id}"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'elba/client'
|
3
|
+
|
4
|
+
describe Elba::Client do
|
5
|
+
include Elba::Mocks
|
6
|
+
|
7
|
+
context '.new' do
|
8
|
+
it 'raises an error when missing credentials' do
|
9
|
+
expect { described_class.new }.to raise_error
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
describe '(an instance)' do
|
15
|
+
subject { described_class.new(test_config) }
|
16
|
+
let(:elb) { subject.load_balancers.first }
|
17
|
+
let(:ec2) { test_ec2_connection.servers.create region: test_config[:region] }
|
18
|
+
|
19
|
+
before :each do
|
20
|
+
if subject.load_balancers.empty?
|
21
|
+
subject.connection.create_load_balancer([test_config[:region]], 'elba-test')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
describe '#load_balancers' do
|
27
|
+
it 'does not raise NoMethodError' do
|
28
|
+
expect(subject).to respond_to(:load_balancers)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'is delegated to the connection' do
|
32
|
+
expect(subject.connection).to receive(:load_balancers)
|
33
|
+
subject.load_balancers
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
describe '#attach' do
|
39
|
+
let(:perform) do
|
40
|
+
subject.attach(ec2.id, elb,
|
41
|
+
on_success: -> { puts 'yay!' },
|
42
|
+
on_failure: ->(x) { puts 'doh!' }
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
it '(on success) executes success callback' do
|
47
|
+
capture(:stdout) { perform }.should include 'yay!'
|
48
|
+
end
|
49
|
+
|
50
|
+
it '(on failure) executes failure callback' do
|
51
|
+
allow(elb).to receive(:register_instances).and_raise(Exception)
|
52
|
+
capture(:stdout) { perform }.should include 'doh!'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
describe '#detach' do
|
58
|
+
before :each do
|
59
|
+
subject.attach(ec2.id, elb, {})
|
60
|
+
end
|
61
|
+
|
62
|
+
let(:perform) do
|
63
|
+
subject.detach(ec2.id, elb,
|
64
|
+
on_success: -> { puts 'yay!' },
|
65
|
+
on_failure: ->(x) { puts 'doh!' }
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
it '(on success) executes success callback' do
|
70
|
+
capture(:stdout) { perform }.should include 'yay!'
|
71
|
+
end
|
72
|
+
|
73
|
+
it '(on failure) executes failure callback' do
|
74
|
+
allow(elb).to receive(:deregister_instances).and_raise(Exception)
|
75
|
+
capture(:stdout) { perform }.should include 'doh!'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'rspec'
|
4
|
+
require 'elba'
|
5
|
+
require 'support/mocks'
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
config.before(:each) do
|
9
|
+
# Pretend we're running as 'elba'
|
10
|
+
$0 = "elba"
|
11
|
+
|
12
|
+
# Tell Fog to use mocks
|
13
|
+
Fog.mock! unless Fog.mocking?
|
14
|
+
end
|
15
|
+
|
16
|
+
# Captures the output for analysis later
|
17
|
+
#
|
18
|
+
# @example Capture `$stderr`
|
19
|
+
#
|
20
|
+
# output = capture(:stderr) { $stderr.puts "this is captured" }
|
21
|
+
#
|
22
|
+
# @param [Symbol] stream `:stdout` or `:stderr`
|
23
|
+
# @yield The block to capture stdout/stderr for.
|
24
|
+
# @return [String] The contents of $stdout or $stderr
|
25
|
+
def capture(stream)
|
26
|
+
begin
|
27
|
+
stream = stream.to_s
|
28
|
+
eval "$#{stream} = StringIO.new"
|
29
|
+
yield
|
30
|
+
result = eval("$#{stream}").string
|
31
|
+
ensure
|
32
|
+
eval("$#{stream} = #{stream.upcase}")
|
33
|
+
end
|
34
|
+
|
35
|
+
result
|
36
|
+
end
|
37
|
+
|
38
|
+
# Silences the output stream
|
39
|
+
#
|
40
|
+
# @example Silence `$stdout`
|
41
|
+
#
|
42
|
+
# silence(:stdout) { $stdout.puts "hi" }
|
43
|
+
#
|
44
|
+
# @param [IO] stream The stream to use such as $stderr or $stdout
|
45
|
+
# @return [nil]
|
46
|
+
alias :silence :capture
|
47
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Elba
|
2
|
+
module Mocks
|
3
|
+
def test_config
|
4
|
+
{
|
5
|
+
region: 'eu-west-1',
|
6
|
+
aws_access_key_id: 'JUST',
|
7
|
+
aws_secret_access_key: 'TESTING'
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_elb_connection
|
12
|
+
@connection ||= Fog::AWS::ELB.new(test_config)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_ec2_connection
|
16
|
+
@ec2 ||= Fog::Compute::AWS.new(test_config)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: elba
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Marcus Mitchell
|
9
|
+
- Mark Connell
|
10
|
+
- Thibault Gautriaud
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2014-01-10 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: bundler
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ! '>='
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '0'
|
24
|
+
type: :development
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
28
|
+
requirements:
|
29
|
+
- - ! '>='
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: '0'
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: rspec
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
35
|
+
none: false
|
36
|
+
requirements:
|
37
|
+
- - ! '>='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: guard-rspec
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: rake
|
66
|
+
requirement: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ! '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
type: :development
|
73
|
+
prerelease: false
|
74
|
+
version_requirements: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: pry
|
82
|
+
requirement: !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: pry-nav
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: fog
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
type: :runtime
|
121
|
+
prerelease: false
|
122
|
+
version_requirements: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ! '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
- !ruby/object:Gem::Dependency
|
129
|
+
name: thor
|
130
|
+
requirement: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ! '>='
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
type: :runtime
|
137
|
+
prerelease: false
|
138
|
+
version_requirements: !ruby/object:Gem::Requirement
|
139
|
+
none: false
|
140
|
+
requirements:
|
141
|
+
- - ! '>='
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
description: Command-line interface for Amazon's ELB
|
145
|
+
email:
|
146
|
+
- marcusleemitchell@gmail.com
|
147
|
+
- mark@neo.com
|
148
|
+
- hubbbbb@gmail.com
|
149
|
+
executables:
|
150
|
+
- elba
|
151
|
+
extensions: []
|
152
|
+
extra_rdoc_files: []
|
153
|
+
files:
|
154
|
+
- .gitignore
|
155
|
+
- .ruby-version
|
156
|
+
- .travis.yml
|
157
|
+
- Gemfile
|
158
|
+
- Gemfile.lock
|
159
|
+
- Guardfile
|
160
|
+
- LICENSE
|
161
|
+
- README.md
|
162
|
+
- Rakefile
|
163
|
+
- bin/elba
|
164
|
+
- elba.gemspec
|
165
|
+
- lib/elba.rb
|
166
|
+
- lib/elba/cli.rb
|
167
|
+
- lib/elba/client.rb
|
168
|
+
- spec/lib/elba/cli_spec.rb
|
169
|
+
- spec/lib/elba/client_spec.rb
|
170
|
+
- spec/spec_helper.rb
|
171
|
+
- spec/support/mocks.rb
|
172
|
+
- vendor/excon-0.27.6.gem
|
173
|
+
homepage: https://github.com/housetrip/elba
|
174
|
+
licenses: []
|
175
|
+
post_install_message:
|
176
|
+
rdoc_options: []
|
177
|
+
require_paths:
|
178
|
+
- lib
|
179
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
180
|
+
none: false
|
181
|
+
requirements:
|
182
|
+
- - ! '>='
|
183
|
+
- !ruby/object:Gem::Version
|
184
|
+
version: '0'
|
185
|
+
segments:
|
186
|
+
- 0
|
187
|
+
hash: 4477547734981746383
|
188
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
189
|
+
none: false
|
190
|
+
requirements:
|
191
|
+
- - ! '>='
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
segments:
|
195
|
+
- 0
|
196
|
+
hash: 4477547734981746383
|
197
|
+
requirements: []
|
198
|
+
rubyforge_project:
|
199
|
+
rubygems_version: 1.8.25
|
200
|
+
signing_key:
|
201
|
+
specification_version: 3
|
202
|
+
summary: Command-line interface for Amazon's ELB
|
203
|
+
test_files:
|
204
|
+
- spec/lib/elba/cli_spec.rb
|
205
|
+
- spec/lib/elba/client_spec.rb
|