awsborn 0.7.0 → 0.8.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.
- data/README.mdown +38 -4
- data/VERSION +1 -1
- data/awsborn.gemspec +80 -0
- data/lib/awsborn/aws_constants.rb +59 -0
- data/lib/awsborn/ec2.rb +2 -8
- data/lib/awsborn/elb.rb +127 -0
- data/lib/awsborn/load_balancer.rb +132 -0
- data/lib/awsborn/server.rb +5 -20
- data/lib/awsborn/server_cluster.rb +14 -2
- data/spec/aws_constants_spec.rb +82 -0
- data/spec/ec2_spec.rb +0 -8
- data/spec/elb_spec.rb +256 -0
- data/spec/load_balancer_spec.rb +288 -0
- data/spec/server_spec.rb +6 -3
- metadata +15 -11
- data/.gitignore +0 -22
data/lib/awsborn/server.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Awsborn
|
2
2
|
class Server
|
3
|
-
|
3
|
+
include Awsborn::AwsConstants
|
4
|
+
|
4
5
|
def initialize (name, options = {})
|
5
6
|
@name = name
|
6
7
|
@options = options.dup
|
@@ -106,8 +107,8 @@ module Awsborn
|
|
106
107
|
|
107
108
|
def launch_instance (key_pair)
|
108
109
|
@launch_response = ec2.launch_instance(image_id,
|
109
|
-
:instance_type =>
|
110
|
-
:availability_zone =>
|
110
|
+
:instance_type => symbol_to_aws_instance_type(instance_type),
|
111
|
+
:availability_zone => symbol_to_aws_zone(zone),
|
111
112
|
:key_name => key_pair.name,
|
112
113
|
:group_ids => security_group,
|
113
114
|
:monitoring_enabled => monitor
|
@@ -233,7 +234,7 @@ module Awsborn
|
|
233
234
|
tmp.is_a?(String) ? tmp : tmp[architecture]
|
234
235
|
end
|
235
236
|
def architecture
|
236
|
-
string =
|
237
|
+
string = symbol_to_aws_instance_type(instance_type)
|
237
238
|
case
|
238
239
|
when INSTANCE_TYPES_32_BIT.include?(string) then :i386
|
239
240
|
when INSTANCE_TYPES_64_BIT.include?(string) then :x64
|
@@ -296,22 +297,6 @@ module Awsborn
|
|
296
297
|
end
|
297
298
|
end
|
298
299
|
|
299
|
-
AVAILABILITY_ZONES = %w[
|
300
|
-
us-east-1a us-east-1b us-east-1c us-east-1d
|
301
|
-
us-west-1a us-west-1b
|
302
|
-
eu-west-1a eu-west-1b
|
303
|
-
ap-southeast-1a ap-southeast-1b
|
304
|
-
ap-northeast-1a ap-northeast-1b
|
305
|
-
]
|
306
|
-
INSTANCE_TYPES_32_BIT = %w[m1.small c1.medium t1.micro]
|
307
|
-
INSTANCE_TYPES_64_BIT = %w[m1.large m1.xlarge m2.xlarge m2.2xlarge m2.4xlarge c1.xlarge cc1.4xlarge t1.micro]
|
308
|
-
INSTANCE_TYPES = (INSTANCE_TYPES_32_BIT + INSTANCE_TYPES_64_BIT).uniq
|
309
|
-
SYMBOL_CONSTANT_MAP = (AVAILABILITY_ZONES + INSTANCE_TYPES).inject({}) { |memo,str| memo[str.tr('-.','_').to_sym] = str; memo }
|
310
|
-
|
311
|
-
def constant (symbol)
|
312
|
-
SYMBOL_CONSTANT_MAP[symbol]
|
313
|
-
end
|
314
|
-
|
315
300
|
def logger
|
316
301
|
@logger ||= self.class.logger
|
317
302
|
end
|
@@ -34,14 +34,19 @@ module Awsborn
|
|
34
34
|
@klass = klass
|
35
35
|
@name = name.to_s
|
36
36
|
@instances = []
|
37
|
+
@load_balancers = []
|
37
38
|
self.class.clusters << self
|
38
39
|
end
|
39
|
-
|
40
|
+
|
40
41
|
def domain (*args)
|
41
42
|
@domain = args.first unless args.empty?
|
42
43
|
@domain
|
43
44
|
end
|
44
|
-
|
45
|
+
|
46
|
+
def load_balancer (name, options={})
|
47
|
+
@load_balancers << Awsborn::LoadBalancer.new(name, options)
|
48
|
+
end
|
49
|
+
|
45
50
|
def server (name, options = {})
|
46
51
|
options = add_domain_to_ip(options)
|
47
52
|
instance = @klass.new name, options
|
@@ -53,6 +58,7 @@ module Awsborn
|
|
53
58
|
running, missing = requested.partition { |e| e.running? }
|
54
59
|
refresh_running(running) if running.any?
|
55
60
|
start_missing_instances(missing) if missing.any?
|
61
|
+
update_load_balancing(running) unless @load_balancers.empty?
|
56
62
|
end
|
57
63
|
|
58
64
|
def refresh_running (instances)
|
@@ -65,6 +71,12 @@ module Awsborn
|
|
65
71
|
delete_key_pair(instances)
|
66
72
|
end
|
67
73
|
|
74
|
+
def update_load_balancing(running)
|
75
|
+
@load_balancers.each do |lb|
|
76
|
+
lb.update_with(running).inspect
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
68
80
|
def generate_key_pair (instances)
|
69
81
|
@key_pair = instances.first.ec2.generate_key_pair
|
70
82
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Awsborn::AwsConstants do
|
4
|
+
include Awsborn::AwsConstants
|
5
|
+
describe "endpoint_for_zone_and_service" do
|
6
|
+
it "should have endpoints for each service and for zones in five regions" do
|
7
|
+
endpoint_for_zone_and_service(:eu_west_1a, :ec2).should == 'https://eu-west-1.ec2.amazonaws.com'
|
8
|
+
endpoint_for_zone_and_service("eu_west_1b", :ec2).should == 'https://eu-west-1.ec2.amazonaws.com'
|
9
|
+
endpoint_for_zone_and_service(:us_west_1b, :ec2).should == 'https://us-west-1.ec2.amazonaws.com'
|
10
|
+
endpoint_for_zone_and_service(:us_east_1b, :ec2).should == 'https://us-east-1.ec2.amazonaws.com'
|
11
|
+
endpoint_for_zone_and_service(:eu_west_1a, :elb).should == 'https://eu-west-1.elasticloadbalancing.amazonaws.com'
|
12
|
+
endpoint_for_zone_and_service("eu_west_1b", :elb).should == 'https://eu-west-1.elasticloadbalancing.amazonaws.com'
|
13
|
+
endpoint_for_zone_and_service(:us_west_1b, :elb).should == 'https://us-west-1.elasticloadbalancing.amazonaws.com'
|
14
|
+
endpoint_for_zone_and_service(:us_east_1b, :elb).should == 'https://us-east-1.elasticloadbalancing.amazonaws.com'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "zone_to_awz_region" do
|
19
|
+
it "accepts a zone symbol and returns its region" do
|
20
|
+
zone_to_awz_region(:eu_west_1a).should == 'eu-west-1'
|
21
|
+
end
|
22
|
+
it "accepts an aws zone symbol and returns its region" do
|
23
|
+
zone_to_awz_region('eu-west-1a').should == 'eu-west-1'
|
24
|
+
end
|
25
|
+
it "raise an error if no region found" do
|
26
|
+
expect{zone_to_awz_region('santa-northpole-2b')}.to raise_error(Awsborn::UnknownConstantError)
|
27
|
+
end
|
28
|
+
it "returns a region even when a region is given" do
|
29
|
+
zone_to_awz_region('eu-west-1').should == 'eu-west-1'
|
30
|
+
zone_to_awz_region(:eu_west_1).should == 'eu-west-1'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "symbol_to_aws_zone" do
|
35
|
+
it "accepts a zone symbol and returns its aws zone" do
|
36
|
+
symbol_to_aws_zone(:eu_west_1a).should == 'eu-west-1a'
|
37
|
+
end
|
38
|
+
it "raise an error if no matching aws zone found" do
|
39
|
+
expect{symbol_to_aws_zone(:santa_northpole_2b)}.to raise_error(Awsborn::UnknownConstantError)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "aws_zone_to_symbol" do
|
44
|
+
it "returns a symbol from aws zone" do
|
45
|
+
aws_zone_to_symbol('eu-west-1a').should == :eu_west_1a
|
46
|
+
end
|
47
|
+
it "raises an error if the zone is unknown" do
|
48
|
+
expect{aws_zone_to_symbol('santa-northpole-2a')}.to raise_error(Awsborn::UnknownConstantError)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "symbol_to_aws_instance_type" do
|
53
|
+
it "accepts an instance type symbol and returns its aws instance type" do
|
54
|
+
symbol_to_aws_instance_type(:m1_small).should == 'm1.small'
|
55
|
+
end
|
56
|
+
it "raise an error if no matching aws zone found" do
|
57
|
+
expect{symbol_to_aws_instance_type(:xx_megalarge)}.to raise_error(Awsborn::UnknownConstantError)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "aws_instance_type_to_symbol" do
|
62
|
+
it "returns a symbol from aws instance type" do
|
63
|
+
aws_instance_type_to_symbol('m1.small').should == :m1_small
|
64
|
+
end
|
65
|
+
it "raises an error if the instance type is unknown" do
|
66
|
+
expect{aws_instance_type_to_symbol('xx.megalarge')}.to raise_error(Awsborn::UnknownConstantError)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "awz_constant" do
|
71
|
+
it "should look up an availability zone" do
|
72
|
+
awz_constant(:eu_west_1a).should == "eu-west-1a"
|
73
|
+
end
|
74
|
+
it "should look up an instance type" do
|
75
|
+
awz_constant(:m1_large).should == "m1.large"
|
76
|
+
end
|
77
|
+
it "should raise an error if the symbol is unknown" do
|
78
|
+
expect{awz_constant(:unknown_constant)}.to raise_error(Awsborn::UnknownConstantError)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
data/spec/ec2_spec.rb
CHANGED
@@ -1,12 +1,4 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
3
|
describe Awsborn::Ec2 do
|
4
|
-
context ".endpoint_for_zone" do
|
5
|
-
it "should have endpoints for zones in five regions" do
|
6
|
-
Awsborn::Ec2.endpoint_for_zone(:eu_west_1a).should == 'https://eu-west-1.ec2.amazonaws.com'
|
7
|
-
Awsborn::Ec2.endpoint_for_zone("eu_west_1b").should == 'https://eu-west-1.ec2.amazonaws.com'
|
8
|
-
Awsborn::Ec2.endpoint_for_zone(:us_west_1b).should == 'https://us-west-1.ec2.amazonaws.com'
|
9
|
-
Awsborn::Ec2.endpoint_for_zone(:us_east_1b).should == 'https://us-east-1.ec2.amazonaws.com'
|
10
|
-
end
|
11
|
-
end
|
12
4
|
end
|
data/spec/elb_spec.rb
ADDED
@@ -0,0 +1,256 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Awsborn::Elb do
|
4
|
+
before do
|
5
|
+
@mock_interface = mock(:elb_interface)
|
6
|
+
RightAws::ElbInterface.stub!(:new).and_return(@mock_interface)
|
7
|
+
Awsborn.stub!(:access_key_id).and_return('access_key_id')
|
8
|
+
Awsborn.stub!(:secret_access_key).and_return('secret_access_key')
|
9
|
+
end
|
10
|
+
describe "initialize" do
|
11
|
+
it "sets a proper endpoint" do
|
12
|
+
[:eu_west_1, 'eu-west-1', :eu_west_1a, "eu_west_1b"].each do |zone|
|
13
|
+
elb = Awsborn::Elb.new(:eu_west_1)
|
14
|
+
elb.region.should == 'eu-west-1'
|
15
|
+
elb.endpoint.should == 'https://eu-west-1.elasticloadbalancing.amazonaws.com'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "connection" do
|
21
|
+
before do
|
22
|
+
@elb = Awsborn::Elb.new(:eu_west_1b)
|
23
|
+
end
|
24
|
+
it "setup a connection to a proper endpoint the first time" do
|
25
|
+
RightAws::ElbInterface.should_receive(:new).
|
26
|
+
with('access_key_id', 'secret_access_key', :logger => Awsborn.logger).
|
27
|
+
exactly(:once)
|
28
|
+
@elb.connection
|
29
|
+
@elb.connection
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "for a valid elb" do
|
34
|
+
before do
|
35
|
+
@elb = Awsborn::Elb.new(:eu_west_1b)
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "describe_load_balancer" do
|
39
|
+
it "forwards to ElbInterface" do
|
40
|
+
@mock_interface.should_receive(:describe_load_balancers).with('some-name').and_return([:description])
|
41
|
+
@elb.describe_load_balancer('some-name').should == :description
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "running?" do
|
46
|
+
it "returns true if load balancer is running" do
|
47
|
+
@mock_interface.should_receive(:describe_load_balancers).with('some-name').and_return([:description])
|
48
|
+
@elb.running?('some-name').should be_true
|
49
|
+
end
|
50
|
+
it "returns true if load balancer is not running" do
|
51
|
+
@mock_interface.should_receive(:describe_load_balancers).with('some-name').and_raise(RightAws::AwsError)
|
52
|
+
@elb.running?('some-name').should be_false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "dns_name" do
|
57
|
+
it "extracts name from description" do
|
58
|
+
@mock_interface.should_receive(:describe_load_balancers).with('some-name').and_return([{:dns_name => 'dns-name'}])
|
59
|
+
@elb.dns_name('some-name').should == 'dns-name'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "instances" do
|
64
|
+
it "extracts instances from description" do
|
65
|
+
@mock_interface.should_receive(:describe_load_balancers).with('some-name').and_return([{:instances => 'instances'}])
|
66
|
+
@elb.instances('some-name').should == 'instances'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "zones" do
|
71
|
+
it "extracts zones from description" do
|
72
|
+
@mock_interface.should_receive(:describe_load_balancers).with('some-name').and_return([{:availability_zones => 'zones'}])
|
73
|
+
@elb.zones('some-name').should == 'zones'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "create_load_balancer" do
|
78
|
+
it "forwards to ElbInterface with a temporary zone and no listeners" do
|
79
|
+
@mock_interface.should_receive(:create_load_balancer).with('some-name', ['eu-west-1a'], [])
|
80
|
+
@elb.create_load_balancer('some-name')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "set_load_balancer_listeners" do
|
85
|
+
it "sets listeners if none where set before" do
|
86
|
+
description = {
|
87
|
+
:listeners => []
|
88
|
+
}
|
89
|
+
new_listeners = [
|
90
|
+
{ :protocol => :http, :load_balancer_port => 80, :instance_port => 80 },
|
91
|
+
]
|
92
|
+
@mock_interface.should_receive(:describe_load_balancers).
|
93
|
+
with('some-name').
|
94
|
+
and_return([description])
|
95
|
+
@mock_interface.should_not_receive(:delete_load_balancer_listeners)
|
96
|
+
@mock_interface.should_receive(:create_load_balancer_listeners).with('some-name', new_listeners)
|
97
|
+
@elb.set_load_balancer_listeners('some-name', new_listeners)
|
98
|
+
end
|
99
|
+
it "updates listeners if some where set before" do
|
100
|
+
description = {
|
101
|
+
:listeners => [
|
102
|
+
{ :protocol => :http, :load_balancer_port => 11, :instance_port => 11 },
|
103
|
+
{ :protocol => :http, :load_balancer_port => 22, :instance_port => 22 },
|
104
|
+
{ :protocol => :tcp, :load_balancer_port => 33, :instance_port => 33 }
|
105
|
+
]
|
106
|
+
}
|
107
|
+
new_listeners = [
|
108
|
+
{ :protocol => :http, :load_balancer_port => 80, :instance_port => 80 },
|
109
|
+
]
|
110
|
+
@mock_interface.should_receive(:describe_load_balancers).
|
111
|
+
with('some-name').
|
112
|
+
and_return([description])
|
113
|
+
@mock_interface.should_receive(:delete_load_balancer_listeners).with('some-name', 11, 22, 33)
|
114
|
+
@mock_interface.should_receive(:create_load_balancer_listeners).with('some-name', new_listeners)
|
115
|
+
@elb.set_load_balancer_listeners('some-name', new_listeners)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "set_lb_cookie_policy" do
|
120
|
+
it "creates and sets sticky policy for each given port when the policy is missing" do
|
121
|
+
description = {
|
122
|
+
:listeners => [
|
123
|
+
{ :protocol => :http, :load_balancer_port => 11, :instance_port => 11 },
|
124
|
+
{ :protocol => :http, :load_balancer_port => 22, :instance_port => 22 },
|
125
|
+
{ :protocol => :tcp, :load_balancer_port => 33, :instance_port => 33 }
|
126
|
+
],
|
127
|
+
:lb_cookie_stickiness_policies => []
|
128
|
+
}
|
129
|
+
@mock_interface.should_receive(:describe_load_balancers).
|
130
|
+
with('some-name').
|
131
|
+
and_return([description])
|
132
|
+
@mock_interface.should_receive(:create_lb_cookie_stickiness_policy).
|
133
|
+
with('some-name', 'lb-some-name-300', 300)
|
134
|
+
@mock_interface.should_receive(:set_load_balancer_policies_of_listener).
|
135
|
+
with('some-name', 11, 'lb-some-name-300')
|
136
|
+
@mock_interface.should_receive(:set_load_balancer_policies_of_listener).
|
137
|
+
with('some-name', 22, 'lb-some-name-300')
|
138
|
+
@elb.set_lb_cookie_policy('some-name', [11, 22], 300)
|
139
|
+
end
|
140
|
+
it "does not create but sets sticky policy for each given port when the policy exists" do
|
141
|
+
description = {
|
142
|
+
:listeners => [
|
143
|
+
{ :protocol => :http, :load_balancer_port => 11, :instance_port => 11 },
|
144
|
+
{ :protocol => :http, :load_balancer_port => 22, :instance_port => 22 },
|
145
|
+
{ :protocol => :tcp, :load_balancer_port => 33, :instance_port => 33 }
|
146
|
+
],
|
147
|
+
:lb_cookie_stickiness_policies => [
|
148
|
+
{ :policy_name => 'lb-some-name-300', :expiration_period => 42 },
|
149
|
+
]
|
150
|
+
}
|
151
|
+
@mock_interface.should_receive(:describe_load_balancers).
|
152
|
+
with('some-name').
|
153
|
+
and_return([description])
|
154
|
+
@mock_interface.should_not_receive(:create_lb_cookie_stickiness_policy)
|
155
|
+
@mock_interface.should_receive(:set_load_balancer_policies_of_listener).
|
156
|
+
with('some-name', 11, 'lb-some-name-300')
|
157
|
+
@mock_interface.should_receive(:set_load_balancer_policies_of_listener).
|
158
|
+
with('some-name', 22, 'lb-some-name-300')
|
159
|
+
@elb.set_lb_cookie_policy('some-name', [11, 22], 300)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe "set_app_cookie_policy" do
|
164
|
+
it "creates and sets sticky policy for each given port when the policy is missing" do
|
165
|
+
description = {
|
166
|
+
:listeners => [
|
167
|
+
{ :protocol => :http, :load_balancer_port => 11, :instance_port => 11 },
|
168
|
+
{ :protocol => :http, :load_balancer_port => 22, :instance_port => 22 },
|
169
|
+
{ :protocol => :tcp, :load_balancer_port => 33, :instance_port => 33 }
|
170
|
+
],
|
171
|
+
:app_cookie_stickiness_policies => []
|
172
|
+
}
|
173
|
+
@mock_interface.should_receive(:describe_load_balancers).
|
174
|
+
with('some-name').
|
175
|
+
and_return([description])
|
176
|
+
@mock_interface.should_receive(:create_app_cookie_stickiness_policy).
|
177
|
+
with('some-name', 'app-some-name--some-cookie', "_some_cookie")
|
178
|
+
@mock_interface.should_receive(:set_load_balancer_policies_of_listener).
|
179
|
+
with('some-name', 11, 'app-some-name--some-cookie')
|
180
|
+
@mock_interface.should_receive(:set_load_balancer_policies_of_listener).
|
181
|
+
with('some-name', 22, 'app-some-name--some-cookie')
|
182
|
+
@elb.set_app_cookie_policy('some-name', [11, 22], "_some_cookie")
|
183
|
+
end
|
184
|
+
it "does not create but sets sticky policy for each given port when the policy exists" do
|
185
|
+
description = {
|
186
|
+
:listeners => [
|
187
|
+
{ :protocol => :http, :load_balancer_port => 11, :instance_port => 11 },
|
188
|
+
{ :protocol => :http, :load_balancer_port => 22, :instance_port => 22 },
|
189
|
+
{ :protocol => :tcp, :load_balancer_port => 33, :instance_port => 33 }
|
190
|
+
],
|
191
|
+
:app_cookie_stickiness_policies => [
|
192
|
+
{ :policy_name => 'app-some-name--some-cookie', :expiration_period => 42 },
|
193
|
+
]
|
194
|
+
}
|
195
|
+
@mock_interface.should_receive(:describe_load_balancers).
|
196
|
+
with('some-name').
|
197
|
+
and_return([description])
|
198
|
+
@mock_interface.should_not_receive(:create_app_cookie_stickiness_policy)
|
199
|
+
@mock_interface.should_receive(:set_load_balancer_policies_of_listener).
|
200
|
+
with('some-name', 11, 'app-some-name--some-cookie')
|
201
|
+
@mock_interface.should_receive(:set_load_balancer_policies_of_listener).
|
202
|
+
with('some-name', 22, 'app-some-name--some-cookie')
|
203
|
+
@elb.set_app_cookie_policy('some-name', [11, 22], "_some_cookie")
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe "remove_all_cookie_policies" do
|
208
|
+
it "removes all policies from listeners" do
|
209
|
+
description = {
|
210
|
+
:listeners => [
|
211
|
+
{ :protocol => :http, :load_balancer_port => 11, :instance_port => 11 },
|
212
|
+
{ :protocol => :http, :load_balancer_port => 22, :instance_port => 22 },
|
213
|
+
{ :protocol => :tcp, :load_balancer_port => 33, :instance_port => 33 }
|
214
|
+
],
|
215
|
+
:app_cookie_stickiness_policies => []
|
216
|
+
}
|
217
|
+
@mock_interface.should_receive(:describe_load_balancers).
|
218
|
+
with('some-name').
|
219
|
+
and_return([description])
|
220
|
+
@mock_interface.should_receive(:set_load_balancer_policies_of_listener).with('some-name', 11)
|
221
|
+
@mock_interface.should_receive(:set_load_balancer_policies_of_listener).with('some-name', 22)
|
222
|
+
@mock_interface.should_receive(:set_load_balancer_policies_of_listener).with('some-name', 33)
|
223
|
+
@elb.remove_all_cookie_policies('some-name')
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
describe "register_instances" do
|
228
|
+
it "forwards to ElbInterface" do
|
229
|
+
@mock_interface.should_receive(:register_instances_with_load_balancer).with('some-name', 'i-00000001', 'i-00000002')
|
230
|
+
@elb.register_instances('some-name', ['i-00000001', 'i-00000002'])
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
describe "deregister_instances" do
|
235
|
+
it "forwards to ElbInterface" do
|
236
|
+
@mock_interface.should_receive(:deregister_instances_with_load_balancer).with('some-name', 'i-00000001', 'i-00000002')
|
237
|
+
@elb.deregister_instances('some-name', ['i-00000001', 'i-00000002'])
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe "enable_zones" do
|
242
|
+
it "forwards to ElbInterface" do
|
243
|
+
@mock_interface.should_receive(:enable_availability_zones_for_load_balancer).with('some-name', 'eu-west-1a', 'eu-west-1b')
|
244
|
+
@elb.enable_zones('some-name', ['eu-west-1a', 'eu-west-1b'])
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
describe "disable_zones" do
|
249
|
+
it "forwards to ElbInterface" do
|
250
|
+
@mock_interface.should_receive(:disable_availability_zones_for_load_balancer).with('some-name', 'eu-west-1a', 'eu-west-1b')
|
251
|
+
@elb.disable_zones('some-name', ['eu-west-1a', 'eu-west-1b'])
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
@@ -0,0 +1,288 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Awsborn::LoadBalancer do
|
4
|
+
before do
|
5
|
+
@mocked_elb = mock(:elb,
|
6
|
+
:running? => false,
|
7
|
+
:remove_all_cookie_policies => true,
|
8
|
+
:create_load_balancer => {})
|
9
|
+
@listener_fixture = [ { :protocol => :tcp, :load_balancer_port => 123, :instance_port => 123} ]
|
10
|
+
@cookies_fixture = [ { :ports => [123], :policy => :disabled } ]
|
11
|
+
Awsborn::Elb.stub!(:new).and_return(@mocked_elb)
|
12
|
+
end
|
13
|
+
describe "initialize" do
|
14
|
+
it "requires a valid region option" do
|
15
|
+
expect { Awsborn::LoadBalancer.new('some-name') }.to raise_error
|
16
|
+
expect { Awsborn::LoadBalancer.new('some-name', :region => :blabla) }.to raise_error
|
17
|
+
end
|
18
|
+
it "launches the load balancer if not running" do
|
19
|
+
@mocked_elb.should_receive(:running?).with('some-name').and_return(false)
|
20
|
+
@mocked_elb.should_receive(:create_load_balancer).with('some-name').and_return(nil)
|
21
|
+
@balancer = Awsborn::LoadBalancer.new(
|
22
|
+
'some-name',
|
23
|
+
:region => :eu_west_1
|
24
|
+
)
|
25
|
+
end
|
26
|
+
it "does not launch the load balancer if running" do
|
27
|
+
@mocked_elb.should_receive(:running?).with('some-name').and_return(true)
|
28
|
+
@mocked_elb.should_not_receive(:create_load_balancer)
|
29
|
+
@balancer = Awsborn::LoadBalancer.new(
|
30
|
+
'some-name',
|
31
|
+
:region => :eu_west_1
|
32
|
+
)
|
33
|
+
end
|
34
|
+
describe "sets all attributes properly" do
|
35
|
+
subject do
|
36
|
+
@balancer = Awsborn::LoadBalancer.new(
|
37
|
+
'some-name',
|
38
|
+
:region => :eu_west_1a,
|
39
|
+
:only => [:server1, :server2],
|
40
|
+
:except => [:server2],
|
41
|
+
:listeners => @listener_fixture,
|
42
|
+
:sticky_cookies => @cookies_fixture
|
43
|
+
)
|
44
|
+
end
|
45
|
+
its(:name) { should == 'some-name' }
|
46
|
+
its(:region) { should == 'eu-west-1' }
|
47
|
+
its(:only) { should == [:server1, :server2] }
|
48
|
+
its(:except) { should == [:server2] }
|
49
|
+
its(:listeners) { should == @listener_fixture }
|
50
|
+
its(:sticky_cookies) { should == @cookies_fixture }
|
51
|
+
end
|
52
|
+
describe "sets proper default values" do
|
53
|
+
subject do
|
54
|
+
@balancer = Awsborn::LoadBalancer.new(
|
55
|
+
'some-name',
|
56
|
+
:region => :eu_west_1
|
57
|
+
)
|
58
|
+
end
|
59
|
+
its(:only) { should == [] }
|
60
|
+
its(:except) { should == [] }
|
61
|
+
its(:listeners) { should == Awsborn::LoadBalancer::DEFAULT_LISTENERS }
|
62
|
+
its(:sticky_cookies) { should == [] }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "dns_name" do
|
67
|
+
it "delegates to elb" do
|
68
|
+
@mocked_elb.should_receive(:dns_name).with('some-name').and_return('dns-name')
|
69
|
+
@balancer = Awsborn::LoadBalancer.new(
|
70
|
+
'some-name',
|
71
|
+
:region => :eu_west_1
|
72
|
+
).dns_name.should == 'dns-name'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
describe "instances" do
|
78
|
+
it "delegates to elb" do
|
79
|
+
@mocked_elb.should_receive(:instances).with('some-name').and_return('instances')
|
80
|
+
@balancer = Awsborn::LoadBalancer.new(
|
81
|
+
'some-name',
|
82
|
+
:region => :eu_west_1
|
83
|
+
).instances.should == 'instances'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "instances=" do
|
88
|
+
it "sets instances properly when the load balancer has no previous instances" do
|
89
|
+
@balancer = Awsborn::LoadBalancer.new(
|
90
|
+
'some-name',
|
91
|
+
:region => :eu_west_1
|
92
|
+
)
|
93
|
+
@balancer.stub!(:instances).and_return([])
|
94
|
+
@mocked_elb.should_receive(:register_instances).with('some-name', ['i-00000001', 'i-00000002'])
|
95
|
+
@mocked_elb.should_not_receive(:deregister_instances)
|
96
|
+
@balancer.instances = ['i-00000001', 'i-00000002']
|
97
|
+
end
|
98
|
+
it "does nothing if the previous instances are the same as the ones to be set" do
|
99
|
+
@balancer = Awsborn::LoadBalancer.new(
|
100
|
+
'some-name',
|
101
|
+
:region => :eu_west_1
|
102
|
+
)
|
103
|
+
@balancer.stub!(:instances).and_return(['i-00000001', 'i-00000002'])
|
104
|
+
@mocked_elb.should_not_receive(:register_instances)
|
105
|
+
@mocked_elb.should_not_receive(:deregister_instances)
|
106
|
+
@balancer.instances = ['i-00000001', 'i-00000002']
|
107
|
+
end
|
108
|
+
it "removes and adds instances accorind to previous and new state" do
|
109
|
+
@balancer = Awsborn::LoadBalancer.new(
|
110
|
+
'some-name',
|
111
|
+
:region => :eu_west_1
|
112
|
+
)
|
113
|
+
@balancer.stub!(:instances).and_return(['i-00000001', 'i-00000002'])
|
114
|
+
@mocked_elb.should_receive(:register_instances).with('some-name', ['i-00000003'])
|
115
|
+
@mocked_elb.should_receive(:deregister_instances).with('some-name', ['i-00000001'])
|
116
|
+
@balancer.instances = ['i-00000002', 'i-00000003']
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "zones" do
|
121
|
+
it "delegates to elb" do
|
122
|
+
@mocked_elb.should_receive(:zones).with('some-name').and_return('zones')
|
123
|
+
@balancer = Awsborn::LoadBalancer.new(
|
124
|
+
'some-name',
|
125
|
+
:region => :eu_west_1
|
126
|
+
).zones.should == 'zones'
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "zones=" do
|
131
|
+
it "sets zones properly when the load balancer has no previous zones" do
|
132
|
+
@balancer = Awsborn::LoadBalancer.new(
|
133
|
+
'some-name',
|
134
|
+
:region => :eu_west_1
|
135
|
+
)
|
136
|
+
@balancer.stub!(:zones).and_return([])
|
137
|
+
@mocked_elb.should_receive(:enable_zones).with('some-name', ['eu-west-1a', 'eu-west-1b'])
|
138
|
+
@mocked_elb.should_not_receive(:disable_zones)
|
139
|
+
@balancer.zones = ['eu-west-1a', 'eu-west-1b']
|
140
|
+
end
|
141
|
+
it "does nothing if the previous zones are the same as the ones to be set" do
|
142
|
+
@balancer = Awsborn::LoadBalancer.new(
|
143
|
+
'some-name',
|
144
|
+
:region => :eu_west_1
|
145
|
+
)
|
146
|
+
@balancer.stub!(:zones).and_return(['eu-west-1a', 'eu-west-1b'])
|
147
|
+
@mocked_elb.should_not_receive(:enable_zones)
|
148
|
+
@mocked_elb.should_not_receive(:disable_zones)
|
149
|
+
@balancer.zones = ['eu-west-1a', 'eu-west-1b']
|
150
|
+
end
|
151
|
+
it "removes and adds zones accordind to previous and new state" do
|
152
|
+
@balancer = Awsborn::LoadBalancer.new(
|
153
|
+
'some-name',
|
154
|
+
:region => :eu_west_1
|
155
|
+
)
|
156
|
+
@balancer.stub!(:zones).and_return(['eu-west-1a', 'eu-west-1b'])
|
157
|
+
@mocked_elb.should_receive(:enable_zones).with('some-name', ['eu-west-1c'])
|
158
|
+
@mocked_elb.should_receive(:disable_zones).with('some-name', ['eu-west-1a'])
|
159
|
+
@balancer.zones = ['eu-west-1b', 'eu-west-1c']
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe "description" do
|
164
|
+
it "delegates to elb" do
|
165
|
+
@mocked_elb.should_receive(:describe_load_balancer).with('some-name').and_return('description')
|
166
|
+
@balancer = Awsborn::LoadBalancer.new(
|
167
|
+
'some-name',
|
168
|
+
:region => :eu_west_1
|
169
|
+
).description.should == 'description'
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "launch" do
|
174
|
+
it "delegates to elb" do
|
175
|
+
@mocked_elb.should_receive(:create_load_balancer).with('some-name')
|
176
|
+
@balancer = Awsborn::LoadBalancer.new(
|
177
|
+
'some-name',
|
178
|
+
:region => :eu_west_1
|
179
|
+
).launch
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe "update_listeners" do
|
184
|
+
it "delegates to elb" do
|
185
|
+
@mocked_elb.should_receive('set_load_balancer_listeners').with('some-name', @listener_fixture)
|
186
|
+
@balancer = Awsborn::LoadBalancer.new(
|
187
|
+
'some-name',
|
188
|
+
:region => :eu_west_1,
|
189
|
+
:listeners => @listener_fixture
|
190
|
+
).update_listeners
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "update_sticky_cookies" do
|
195
|
+
it "sets proper policies" do
|
196
|
+
@balancer = Awsborn::LoadBalancer.new(
|
197
|
+
'some-name',
|
198
|
+
:region => :eu_west_1,
|
199
|
+
:sticky_cookies => [
|
200
|
+
{ :ports => [11,22], :policy => :disabled },
|
201
|
+
{ :ports => [33], :policy => :app_generated, :cookie_name => 'some_cookie' },
|
202
|
+
{ :ports => [44], :policy => :lb_generated, :expiration_period => 42 }
|
203
|
+
]
|
204
|
+
)
|
205
|
+
@mocked_elb.should_receive(:remove_all_cookie_policies).with('some-name')
|
206
|
+
@mocked_elb.should_receive(:set_app_sticky_cookie).with('some-name', [33], 'some_cookie')
|
207
|
+
@mocked_elb.should_receive(:set_lb_sticky_cookie).with('some-name', [44], 42)
|
208
|
+
|
209
|
+
@balancer.update_sticky_cookies
|
210
|
+
end
|
211
|
+
|
212
|
+
it "raises an error if a policy is missing a ports option" do
|
213
|
+
@balancer = Awsborn::LoadBalancer.new(
|
214
|
+
'some-name',
|
215
|
+
:region => :eu_west_1,
|
216
|
+
:sticky_cookies => [
|
217
|
+
{ :policy => :disabled },
|
218
|
+
]
|
219
|
+
)
|
220
|
+
expect { @balancer.update_sticky_cookies }.to raise_error
|
221
|
+
end
|
222
|
+
it "raises an error if an app sticky policy is missing a cookie name" do
|
223
|
+
@balancer = Awsborn::LoadBalancer.new(
|
224
|
+
'some-name',
|
225
|
+
:region => :eu_west_1,
|
226
|
+
:sticky_cookies => [
|
227
|
+
{ :ports => [33], :policy => :app_generated },
|
228
|
+
]
|
229
|
+
)
|
230
|
+
expect { @balancer.update_sticky_cookies }.to raise_error
|
231
|
+
end
|
232
|
+
it "raises an error if an lb sticky policy is missing an expiration period" do
|
233
|
+
@balancer = Awsborn::LoadBalancer.new(
|
234
|
+
'some-name',
|
235
|
+
:region => :eu_west_1,
|
236
|
+
:sticky_cookies => [
|
237
|
+
{ :ports => [44], :policy => :lb_generated }
|
238
|
+
]
|
239
|
+
)
|
240
|
+
expect { @balancer.update_sticky_cookies }.to raise_error
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe "update_with" do
|
245
|
+
before do
|
246
|
+
@balancer = Awsborn::LoadBalancer.new(
|
247
|
+
'some-name',
|
248
|
+
:region => :eu_west_1a,
|
249
|
+
:listeners => @listener_fixture,
|
250
|
+
:sticky_cookies => @cookies_fixture
|
251
|
+
)
|
252
|
+
@new_servers = [
|
253
|
+
mock(:server1, :name => :server1, :instance_id => 'i-00000001', :zone => :eu_west_1a),
|
254
|
+
mock(:server1, :name => :server2, :instance_id => 'i-00000002', :zone => :eu_west_1b)
|
255
|
+
]
|
256
|
+
end
|
257
|
+
it "sets new instances, sets new zones, updates listeners and updates sticky cookies" do
|
258
|
+
@balancer.should_receive(:instances=).with(['i-00000001', 'i-00000002'])
|
259
|
+
@balancer.should_receive(:zones=).with(['eu-west-1a', 'eu-west-1b'])
|
260
|
+
@balancer.should_receive(:update_listeners)
|
261
|
+
@balancer.should_receive(:update_sticky_cookies)
|
262
|
+
@balancer.should_receive(:description).and_return('description')
|
263
|
+
@balancer.update_with(@new_servers).should == 'description'
|
264
|
+
end
|
265
|
+
it "takes into account the :only option" do
|
266
|
+
@balancer.only = [:server1]
|
267
|
+
|
268
|
+
@balancer.should_receive(:instances=).with(['i-00000001'])
|
269
|
+
@balancer.should_receive(:zones=).with(['eu-west-1a'])
|
270
|
+
@balancer.should_receive(:update_listeners)
|
271
|
+
@balancer.should_receive(:update_sticky_cookies)
|
272
|
+
@balancer.should_receive(:description).and_return('description')
|
273
|
+
@balancer.update_with(@new_servers).should == 'description'
|
274
|
+
end
|
275
|
+
it "takes into account the :except option" do
|
276
|
+
@balancer.except = [:server1]
|
277
|
+
|
278
|
+
@balancer.should_receive(:instances=).with(['i-00000002'])
|
279
|
+
@balancer.should_receive(:zones=).with(['eu-west-1b'])
|
280
|
+
@balancer.should_receive(:update_listeners)
|
281
|
+
@balancer.should_receive(:update_sticky_cookies)
|
282
|
+
@balancer.should_receive(:description).and_return('description')
|
283
|
+
@balancer.update_with(@new_servers).should == 'description'
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
288
|
+
|