bguthrie-awsymandias 0.2.1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/.specification +57 -0
  2. data/README.rdoc +25 -21
  3. data/Rakefile +20 -4
  4. data/VERSION +1 -1
  5. data/awsymandias.gemspec +37 -12
  6. data/lib/awsymandias.rb +36 -331
  7. data/lib/awsymandias/addons/right_elb_interface.rb +375 -0
  8. data/lib/awsymandias/ec2.rb +49 -0
  9. data/lib/awsymandias/ec2/application_stack.rb +261 -0
  10. data/lib/awsymandias/extensions/class_extension.rb +18 -0
  11. data/lib/awsymandias/extensions/net_http_extension.rb +9 -0
  12. data/lib/awsymandias/instance.rb +149 -0
  13. data/lib/awsymandias/load_balancer.rb +157 -0
  14. data/lib/awsymandias/right_aws.rb +73 -0
  15. data/lib/awsymandias/right_elb.rb +16 -0
  16. data/lib/awsymandias/simple_db.rb +46 -0
  17. data/lib/awsymandias/snapshot.rb +33 -0
  18. data/lib/awsymandias/stack_definition.rb +60 -0
  19. data/lib/awsymandias/volume.rb +70 -0
  20. data/spec/integration/instance_spec.rb +37 -0
  21. data/spec/unit/addons/right_elb_interface_spec.rb +45 -0
  22. data/spec/unit/awsymandias_spec.rb +61 -0
  23. data/spec/unit/ec2/application_stack_spec.rb +634 -0
  24. data/spec/unit/instance_spec.rb +365 -0
  25. data/spec/unit/load_balancer_spec.rb +250 -0
  26. data/spec/unit/right_aws_spec.rb +90 -0
  27. data/spec/unit/simple_db_spec.rb +63 -0
  28. data/spec/unit/snapshot_spec.rb +39 -0
  29. data/spec/unit/stack_definition_spec.rb +113 -0
  30. data/tags +368 -0
  31. metadata +39 -13
  32. data/spec/awsymandias_spec.rb +0 -815
  33. data/vendor/aws-sdb/LICENSE +0 -19
  34. data/vendor/aws-sdb/README +0 -1
  35. data/vendor/aws-sdb/Rakefile +0 -20
  36. data/vendor/aws-sdb/lib/aws_sdb.rb +0 -3
  37. data/vendor/aws-sdb/lib/aws_sdb/error.rb +0 -42
  38. data/vendor/aws-sdb/lib/aws_sdb/service.rb +0 -191
  39. data/vendor/aws-sdb/spec/aws_sdb/service_spec.rb +0 -183
  40. data/vendor/aws-sdb/spec/spec_helper.rb +0 -4
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bguthrie-awsymandias
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Guthrie
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-15 00:00:00 -07:00
12
+ date: 2009-08-11 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -62,22 +62,39 @@ extra_rdoc_files:
62
62
  - README.rdoc
63
63
  files:
64
64
  - .gitignore
65
+ - .specification
65
66
  - README.rdoc
66
67
  - Rakefile
67
68
  - VERSION
68
69
  - awsymandias.gemspec
69
70
  - lib/awsymandias.rb
70
- - spec/awsymandias_spec.rb
71
- - vendor/aws-sdb/LICENSE
72
- - vendor/aws-sdb/README
73
- - vendor/aws-sdb/Rakefile
74
- - vendor/aws-sdb/lib/aws_sdb.rb
75
- - vendor/aws-sdb/lib/aws_sdb/error.rb
76
- - vendor/aws-sdb/lib/aws_sdb/service.rb
77
- - vendor/aws-sdb/spec/aws_sdb/service_spec.rb
78
- - vendor/aws-sdb/spec/spec_helper.rb
71
+ - lib/awsymandias/addons/right_elb_interface.rb
72
+ - lib/awsymandias/ec2.rb
73
+ - lib/awsymandias/ec2/application_stack.rb
74
+ - lib/awsymandias/extensions/class_extension.rb
75
+ - lib/awsymandias/extensions/net_http_extension.rb
76
+ - lib/awsymandias/instance.rb
77
+ - lib/awsymandias/load_balancer.rb
78
+ - lib/awsymandias/right_aws.rb
79
+ - lib/awsymandias/right_elb.rb
80
+ - lib/awsymandias/simple_db.rb
81
+ - lib/awsymandias/snapshot.rb
82
+ - lib/awsymandias/stack_definition.rb
83
+ - lib/awsymandias/volume.rb
84
+ - spec/integration/instance_spec.rb
85
+ - spec/unit/addons/right_elb_interface_spec.rb
86
+ - spec/unit/awsymandias_spec.rb
87
+ - spec/unit/ec2/application_stack_spec.rb
88
+ - spec/unit/instance_spec.rb
89
+ - spec/unit/load_balancer_spec.rb
90
+ - spec/unit/right_aws_spec.rb
91
+ - spec/unit/simple_db_spec.rb
92
+ - spec/unit/snapshot_spec.rb
93
+ - spec/unit/stack_definition_spec.rb
94
+ - tags
79
95
  has_rdoc: true
80
96
  homepage: http://github.com/bguthrie/awsymandias
97
+ licenses:
81
98
  post_install_message:
82
99
  rdoc_options:
83
100
  - --charset=UTF-8
@@ -98,9 +115,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
115
  requirements: []
99
116
 
100
117
  rubyforge_project:
101
- rubygems_version: 1.2.0
118
+ rubygems_version: 1.3.5
102
119
  signing_key:
103
120
  specification_version: 2
104
121
  summary: A library for helping you set up, track, and tear down complicated deployment configurations in Amazon EC2.
105
122
  test_files:
106
- - spec/awsymandias_spec.rb
123
+ - spec/integration/instance_spec.rb
124
+ - spec/unit/addons/right_elb_interface_spec.rb
125
+ - spec/unit/awsymandias_spec.rb
126
+ - spec/unit/ec2/application_stack_spec.rb
127
+ - spec/unit/instance_spec.rb
128
+ - spec/unit/load_balancer_spec.rb
129
+ - spec/unit/right_aws_spec.rb
130
+ - spec/unit/simple_db_spec.rb
131
+ - spec/unit/snapshot_spec.rb
132
+ - spec/unit/stack_definition_spec.rb
@@ -1,815 +0,0 @@
1
- require 'rubygems'
2
- require 'spec'
3
- require File.dirname(__FILE__) + "/../lib/awsymandias"
4
-
5
- describe Awsymandias do
6
- describe Awsymandias::SimpleDB do
7
- describe "connection" do
8
- it "configure an instance of AwsSdb::Service" do
9
- Awsymandias.access_key_id = "configured key"
10
- Awsymandias.secret_access_key = "configured secret"
11
-
12
- ::AwsSdb::Service.should_receive(:new).
13
- with(hash_including(:access_key_id => "configured key", :secret_access_key => "configured secret")).
14
- and_return(:a_connection)
15
-
16
- Awsymandias::SimpleDB.connection.should == :a_connection
17
- end
18
- end
19
- end
20
-
21
- describe Awsymandias::EC2 do
22
- def stub_connection_with(return_value)
23
- Awsymandias::EC2.stub!(:connection).and_return stub("a connection", :describe_instances => return_value)
24
- end
25
-
26
- def zero_dollars
27
- Money.new(0)
28
- end
29
-
30
- describe "connection" do
31
- it "should configure an instance of EC2::Base" do
32
- Awsymandias.access_key_id = "configured key"
33
- Awsymandias.secret_access_key = "configured secret"
34
-
35
- ::EC2::Base.should_receive(:new).
36
- with(hash_including(:access_key_id => "configured key", :secret_access_key => "configured secret")).
37
- and_return(:a_connection)
38
-
39
- Awsymandias::EC2.connection.should == :a_connection
40
- end
41
- end
42
-
43
- describe Instance = Awsymandias::EC2::Instance do
44
-
45
- DESCRIBE_INSTANCES_NO_RESULTS_XML = {
46
- "requestId" => "7bca5c7c-1b51-473e-a930-611e55920e39",
47
- "xmlns"=>"http://ec2.amazonaws.com/doc/2008-12-01/",
48
- "reservationSet" => nil
49
- }
50
-
51
- DESCRIBE_INSTANCES_SINGLE_RESULT_PENDING_XML = {
52
- "requestId" => "7bca5c7c-1b51-473e-a930-611e55920e39",
53
- "xmlns"=>"http://ec2.amazonaws.com/doc/2008-12-01/",
54
- "reservationSet" => {
55
- "item" => [ {
56
- "reservationId" => "r-db68e3b2",
57
- "requesterId" => "058890971305",
58
- "ownerId" => "358110980006",
59
- "groupSet" => { "item" => [ { "groupId" => "default" } ] },
60
- "instancesSet" => { "item" => [ {
61
- "productCodes" => nil,
62
- "kernelId" => "aki-some-kernel",
63
- "amiLaunchIndex" => "0",
64
- "keyName" => "gsg-keypair",
65
- "ramdiskId" => "ari-b31cf9da",
66
- "launchTime" => "2009-04-20T01:30:35.000Z",
67
- "instanceType" => "m1.large",
68
- "imageId" => "ami-some-image",
69
- "privateDnsName" => nil,
70
- "reason" => nil,
71
- "placement" => {
72
- "availabilityZone" => "us-east-1c"
73
- },
74
- "dnsName" => nil,
75
- "instanceId" => "i-some-instance",
76
- "instanceState" => {
77
- "name" => "pending",
78
- "code"=>"0"
79
- } } ] } } ] }
80
- }
81
-
82
- DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML = {
83
- "requestId" => "7bca5c7c-1b51-473e-a930-611e55920e39",
84
- "xmlns"=>"http://ec2.amazonaws.com/doc/2008-12-01/",
85
- "reservationSet" => {
86
- "item" => [ {
87
- "reservationId" => "r-db68e3b2",
88
- "requesterId" => "058890971305",
89
- "ownerId" => "358110980006",
90
- "groupSet" => { "item" => [ { "groupId" => "default" } ] },
91
- "instancesSet" => { "item" => [ {
92
- "productCodes" => nil,
93
- "kernelId" => "aki-some-kernel",
94
- "amiLaunchIndex" => "0",
95
- "keyName" => "gsg-keypair",
96
- "ramdiskId" => "ari-b31cf9da",
97
- "launchTime" => "2009-04-20T01:30:35.000Z",
98
- "instanceType" => "m1.large",
99
- "imageId" => "ami-some-image",
100
- "privateDnsName" => "ip-10-244-226-239.ec2.internal",
101
- "reason" => nil,
102
- "placement" => {
103
- "availabilityZone" => "us-east-1c"
104
- },
105
- "dnsName" => "ec2-174-129-118-52.compute-1.amazonaws.com",
106
- "instanceId" => "i-some-instance",
107
- "instanceState" => {
108
- "name" => "running",
109
- "code"=>"0"
110
- } } ] } } ] }
111
- }
112
-
113
- DESCRIBE_INSTANCES_MULTIPLE_RESULTS_RUNNING_XML = {
114
- "requestId" => "7bca5c7c-1b51-473e-a930-611e55920e39",
115
- "xmlns"=>"http://ec2.amazonaws.com/doc/2008-12-01/",
116
- "reservationSet" => {
117
- "item" => [
118
- { "reservationId"=>"r-5b226e32",
119
- "ownerId"=>"423319072129",
120
- "groupSet" => { "item" => [ {"groupId"=>"default" } ] },
121
- "instancesSet" => { "item" => [
122
- { "productCodes"=>nil,
123
- "kernelId"=>"aki-some-kernel",
124
- "amiLaunchIndex"=>"0",
125
- "ramdiskId"=>"ari-b31cf9da",
126
- "launchTime"=>"2009-07-14T17:47:33.000Z",
127
- "instanceType"=>"c1.xlarge",
128
- "imageId"=>"ami-some-other-image",
129
- "privateDnsName"=>nil,
130
- "reason"=>nil,
131
- "placement" => {
132
- "availabilityZone"=>"us-east-1b"
133
- },
134
- "dnsName" => nil,
135
- "instanceId"=>"i-some-other-instance",
136
- "instanceState" => {
137
- "name"=>"running",
138
- "code"=>"16",
139
- }
140
- }
141
- ] } },
142
- { "reservationId" => "r-db68e3b2",
143
- "requesterId" => "058890971305",
144
- "ownerId" => "358110980006",
145
- "groupSet" => { "item" => [ { "groupId" => "default" } ] },
146
- "instancesSet" => { "item" => [
147
- { "productCodes" => nil,
148
- "kernelId" => "aki-some-kernel",
149
- "amiLaunchIndex" => "0",
150
- "keyName" => "gsg-keypair",
151
- "ramdiskId" => "ari-b31cf9da",
152
- "launchTime" => "2009-04-20T01:30:35.000Z",
153
- "instanceType" => "m1.large",
154
- "imageId" => "ami-some-image",
155
- "privateDnsName" => nil,
156
- "reason" => nil,
157
- "placement" => {
158
- "availabilityZone" => "us-east-1c"
159
- },
160
- "dnsName" => nil,
161
- "instanceId" => "i-some-instance",
162
- "instanceState" => {
163
- "name" => "running",
164
- "code"=>"0"
165
- } },
166
- { "productCodes" => nil,
167
- "kernelId" => "aki-some-kernel",
168
- "amiLaunchIndex" => "0",
169
- "keyName" => "gsg-keypair",
170
- "ramdiskId" => "ari-b31cf9da",
171
- "launchTime" => "2009-04-20T01:30:35.000Z",
172
- "instanceType" => "m1.large",
173
- "imageId" => "ami-some-image",
174
- "privateDnsName" => nil,
175
- "reason" => nil,
176
- "placement" => {
177
- "availabilityZone" => "us-east-1c"
178
- },
179
- "dnsName" => nil,
180
- "instanceId" => "i-another-instance",
181
- "instanceState" => {
182
- "name" => "pending",
183
- "code"=>"0"
184
- }
185
- } ] } }
186
- ]
187
- }
188
- }
189
-
190
- RUN_INSTANCES_SINGLE_RESULT_XML = {
191
- "reservationId" => "r-276ee54e",
192
- "groupSet" => { "item" => [ {
193
- "groupId" => "default"
194
- } ] },
195
- "requestId" => "a29db909-d8ef-4a14-80c1-c53157c0cd49",
196
- "instancesSet" => {
197
- "item" => [ {
198
- "kernelId" => "aki-some-kernel",
199
- "amiLaunchIndex" => "0",
200
- "keyName" => "gsg-keypair",
201
- "ramdiskId" => "ari-b31cf9da",
202
- "launchTime" => "2009-04-20T01:39:12.000Z",
203
- "instanceType" => "m1.large",
204
- "imageId" => "ami-some-image",
205
- "privateDnsName" => nil,
206
- "reason" => nil,
207
- "placement" => {
208
- "availabilityZone" => "us-east-1a"
209
- },
210
- "dnsName" => nil,
211
- "instanceId" => "i-some-instance",
212
- "instanceState" => {
213
- "name" => "pending",
214
- "code" => "0"
215
- }
216
- } ] },
217
- "ownerId"=>"358110980006",
218
- "xmlns"=>"http://ec2.amazonaws.com/doc/2008-12-01/"
219
- }
220
-
221
- TERMINATE_INSTANCES_SINGLE_RESULT_XML = {
222
- "requestId" => "c80c4770-eaab-45ce-972d-10e928e3f80c",
223
- "instancesSet" => {
224
- "item" => [ {
225
- "previousState" => {
226
- "name" => "running",
227
- "code"=>"16"
228
- },
229
- "shutdownState" => {
230
- "name" => "shutting-down",
231
- "code" => "32"
232
- },
233
- "instanceId" => "i-some-instance" } ] },
234
- "xmlns"=>"http://ec2.amazonaws.com/doc/2008-12-01/"
235
- }
236
-
237
- DESCRIBE_INSTANCES_SINGLE_RESULT_TERMINATED_XML = {
238
- "requestId" => "8b4fb505-de40-41b2-b18e-58f9bcba6f09",
239
- "reservationSet" => {
240
- "item" => [ {
241
- "reservationId" => "r-75961c1c",
242
- "groupSet" => {
243
- "item" => [ {
244
- "groupId" => "default"
245
- } ]
246
- },
247
- "instancesSet" => {
248
- "item" => [ {
249
- "productCodes" => nil,
250
- "kernelId" => "aki-some-kernel",
251
- "amiLaunchIndex" => "0",
252
- "keyName" => "gsg-keypair",
253
- "ramdiskId" => "ari-b31cf9da",
254
- "launchTime" => "2009-04-22T00:54:06.000Z",
255
- "instanceType" => "c1.xlarge",
256
- "imageId" => "ami-some-image",
257
- "privateDnsName" => nil,
258
- "reason" => "User initiated (2009-04-22 00:59:53 GMT)",
259
- "placement" => {
260
- "availabilityZone" => nil
261
- },
262
- "dnsName" => nil,
263
- "instanceId" => "i-some-instance",
264
- "instanceState" => {
265
- "name" => "terminated",
266
- "code" => "48"
267
- }
268
- } ]
269
- },
270
- "ownerId" => "358110980006"
271
- } ] },
272
- "xmlns"=>"http://ec2.amazonaws.com/doc/2008-12-01/"
273
- }
274
-
275
- describe "find" do
276
- it "should raise ActiveResource::ResourceNotFound if the given instance ID is not found" do
277
- stub_connection_with DESCRIBE_INSTANCES_NO_RESULTS_XML
278
- lambda do
279
- Instance.find("i-some-instance")
280
- end.should raise_error(ActiveResource::ResourceNotFound)
281
- end
282
-
283
- it "should return an object with the appropriate instance ID when an instance with the given ID is found" do
284
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
285
- Instance.find("i-some-instance").instance_id.should == "i-some-instance"
286
- end
287
-
288
- it "should return more than one object if multiple IDs are requested" do
289
- stub_connection_with DESCRIBE_INSTANCES_MULTIPLE_RESULTS_RUNNING_XML
290
- Instance.find(:all, :instance_ids => ["i-some-other-instance", "i-some-instance", "i-another-instance"]).map do |instance|
291
- instance.instance_id
292
- end.should == ["i-some-other-instance", "i-some-instance", "i-another-instance"]
293
- end
294
-
295
- it "should map camelized XML properties to Ruby-friendly underscored method names" do
296
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
297
- instance = Instance.find("i-some-instance")
298
- instance.image_id.should == "ami-some-image"
299
- instance.key_name.should == "gsg-keypair"
300
- instance.instance_type.should == Awsymandias::EC2.instance_types["m1.large"]
301
- instance.placement.availability_zone.should == "us-east-1c"
302
- end
303
- end
304
-
305
- describe "to_params" do
306
- it "should be able to reproduce a reasonable set of its launch params as a hash" do
307
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
308
- Instance.find("i-some-instance").to_params.should == {
309
- :image_id => "ami-some-image",
310
- :key_name => "gsg-keypair",
311
- :instance_type => Awsymandias::EC2.instance_types["m1.large"],
312
- :availability_zone => "us-east-1c"
313
- }
314
- end
315
- end
316
-
317
- describe "running?" do
318
- it "should return false if it contains an instances set with the given instance ID and its state is pending" do
319
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_PENDING_XML
320
- Instance.find("i-some-instance").should_not be_running
321
- end
322
-
323
- it "should return true if it contains an instances set with the given instance ID and its state is running" do
324
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
325
- Instance.find("i-some-instance").should be_running
326
- end
327
- end
328
-
329
- describe "reload" do
330
- it "should reload an instance without replacing the object" do
331
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_PENDING_XML
332
- instance = Instance.find("i-some-instance")
333
- instance.should_not be_running
334
-
335
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
336
- instance.reload.should be_running
337
- end
338
- end
339
-
340
- describe "launch" do
341
- it "should launch a new instance given some values" do
342
- mock_connection = mock("a connection")
343
- mock_connection.should_receive(:run_instances).with(hash_including(
344
- :image_id => "an_id",
345
- :key_name => "gsg-keypair",
346
- :instance_type => "m1.small",
347
- :availability_zone => Awsymandias::EC2::AvailabilityZones::US_EAST_1A
348
- )).and_return(RUN_INSTANCES_SINGLE_RESULT_XML)
349
-
350
- mock_connection.should_receive(:describe_instances).and_return(DESCRIBE_INSTANCES_SINGLE_RESULT_PENDING_XML)
351
-
352
- Awsymandias::EC2.stub!(:connection).and_return mock_connection
353
-
354
- Awsymandias::EC2::Instance.launch(
355
- :image_id => "an_id",
356
- :key_name => "gsg-keypair",
357
- :instance_type => Awsymandias::EC2::InstanceTypes::M1_SMALL,
358
- :availability_zone => Awsymandias::EC2::AvailabilityZones::US_EAST_1A
359
- ).instance_id.should == "i-some-instance"
360
- end
361
-
362
- it "should convert the instance type it's given to a string as needed" do
363
- mock_connection = mock("a connection")
364
- mock_connection.should_receive(:run_instances).with(hash_including(
365
- :instance_type => "m1.small"
366
- )).and_return(RUN_INSTANCES_SINGLE_RESULT_XML)
367
- mock_connection.should_receive(:describe_instances).and_return(stub("response").as_null_object)
368
- Awsymandias::EC2.stub!(:connection).and_return mock_connection
369
-
370
- Awsymandias::EC2::Instance.launch(:instance_type => Awsymandias::EC2::InstanceTypes::M1_SMALL)
371
- end
372
- end
373
-
374
- describe "terminate!" do
375
- it "should terminate a running instance" do
376
- mock_connection = mock("a connection")
377
- mock_connection.should_receive(:describe_instances).and_return(
378
- DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML,
379
- DESCRIBE_INSTANCES_SINGLE_RESULT_TERMINATED_XML
380
- )
381
- mock_connection.should_receive(:terminate_instances).and_return(
382
- TERMINATE_INSTANCES_SINGLE_RESULT_XML
383
- )
384
-
385
- Awsymandias::EC2.stub!(:connection).and_return mock_connection
386
-
387
- instance = Awsymandias::EC2::Instance.find("a result id")
388
- instance.should be_running
389
- instance.terminate!
390
- instance.should_not be_running
391
- instance.should be_terminated
392
- end
393
- end
394
-
395
- describe "instance_type" do
396
- it "should return its instance_type attribute as an InstanceType object" do
397
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
398
- Instance.find("i-some-instance").instance_type.should == Awsymandias::EC2::InstanceTypes::M1_LARGE
399
- end
400
- end
401
-
402
- describe "launch_time" do
403
- it "should return its launch_time attribute as an instance of Time" do
404
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_PENDING_XML
405
- Awsymandias::EC2::Instance.find("i-some-instance").launch_time.should == Time.parse("2009-04-20T01:30:35.000Z")
406
- end
407
- end
408
-
409
- describe "uptime" do
410
- it "should be zero seconds if it is not yet running" do
411
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_PENDING_XML
412
- Awsymandias::EC2::Instance.find("i-some-instance").uptime.should == 0.seconds
413
- end
414
-
415
- it "should calculate the uptime of a running instance in terms of its launch time" do
416
- time_now = Time.now
417
- Time.stub!(:now).and_return time_now
418
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
419
- instance = Awsymandias::EC2::Instance.find("i-some-instance")
420
- instance.uptime.should == (time_now - instance.launch_time)
421
- end
422
- end
423
-
424
- describe "public_dns" do
425
- it "should return the public dns from the xml" do
426
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
427
- Awsymandias::EC2::Instance.find("i-some-instance").public_dns.should == "ec2-174-129-118-52.compute-1.amazonaws.com"
428
- end
429
- end
430
-
431
- describe "private_dns" do
432
- it "should return the private dns from the xml" do
433
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
434
- Awsymandias::EC2::Instance.find("i-some-instance").private_dns.should == "ip-10-244-226-239.ec2.internal"
435
- end
436
- end
437
-
438
- describe "running_cost" do
439
- it "should be zero if the instance has not yet been launched" do
440
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_PENDING_XML
441
- Awsymandias::EC2::Instance.find("i-some-instance").running_cost.should == zero_dollars
442
- end
443
-
444
- it "should be a single increment if the instance was launched 5 minutes ago" do
445
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
446
- instance = Awsymandias::EC2::Instance.find("i-some-instance")
447
- instance.attributes['launch_time'] = 5.minutes.ago.to_s
448
- expected_cost = instance.instance_type.price_per_hour
449
- instance.running_cost.should == expected_cost
450
- end
451
-
452
- it "should be a single increment if the instance was launched 59 minutes ago" do
453
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
454
- instance = Awsymandias::EC2::Instance.find("i-some-instance")
455
- instance.attributes['launch_time'] = 59.minutes.ago.to_s
456
- expected_cost = instance.instance_type.price_per_hour
457
- instance.running_cost.should == expected_cost
458
- end
459
-
460
- it "should be two increments if the instance was launched 61 minutes ago" do
461
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
462
- instance = Awsymandias::EC2::Instance.find("i-some-instance")
463
- instance.attributes['launch_time'] = 61.minutes.ago.to_s
464
- expected_cost = instance.instance_type.price_per_hour * 2
465
- instance.running_cost.should == expected_cost
466
- end
467
-
468
- it "should be three increments if the instance was launched 150 minutes ago" do
469
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
470
- instance = Awsymandias::EC2::Instance.find("i-some-instance")
471
- instance.attributes['launch_time'] = 150.minutes.ago.to_s
472
- expected_cost = instance.instance_type.price_per_hour * 3
473
- instance.running_cost.should == expected_cost
474
- end
475
- end
476
-
477
- describe "port_open?" do
478
- it "should return true if telnet does not raise" do
479
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
480
- instance = Awsymandias::EC2::Instance.find("i-some-instance")
481
- Net::Telnet.should_receive(:new).with("Host" => "ec2-174-129-118-52.compute-1.amazonaws.com",
482
- "Port" => 100).and_return(true)
483
- instance.port_open?(100).should be_true
484
- end
485
-
486
- it "should return false if telnet does raise" do
487
- stub_connection_with DESCRIBE_INSTANCES_SINGLE_RESULT_RUNNING_XML
488
- instance = Awsymandias::EC2::Instance.find("i-some-instance")
489
- Net::Telnet.should_receive(:new).with("Host" => "ec2-174-129-118-52.compute-1.amazonaws.com",
490
- "Port" => 100).and_raise(Timeout::Error)
491
- instance.port_open?(100).should be_false
492
- end
493
- end
494
- end
495
-
496
- describe ApplicationStack = Awsymandias::EC2::ApplicationStack do
497
- class SimpleDBStub
498
- def initialize
499
- @store = {}
500
- end
501
-
502
- def list_domains
503
- [ @store.keys ]
504
- end
505
-
506
- def put_attributes(domain, name, attributes)
507
- @store[domain][name] = attributes
508
- end
509
-
510
- def get_attributes(domain, name)
511
- @store[domain][name]
512
- end
513
-
514
- def delete_attributes(domain, name)
515
- @store[domain][name] = nil
516
- end
517
-
518
- def create_domain(domain)
519
- @store[domain] = {}
520
- end
521
- end
522
-
523
- attr_accessor :simpledb
524
-
525
- def stub_instance(stubs={})
526
- Instance.new({:instance_id => "i-12345a3c"}.merge(stubs))
527
- end
528
-
529
- before :each do
530
- @simpledb = SimpleDBStub.new
531
- Awsymandias::SimpleDB.stub!(:connection).and_return @simpledb
532
- end
533
-
534
- it "should have a name" do
535
- ApplicationStack.new("foo").name.should == "foo"
536
- end
537
-
538
- describe "roles" do
539
- it "should be empty by default" do
540
- ApplicationStack.new("foo").roles.should be_empty
541
- end
542
-
543
- it "should be settable through the initializer" do
544
- stack = ApplicationStack.new("foo", :roles => { :app1 => {} })
545
- stack.roles[:app1].should == {}
546
- end
547
- end
548
-
549
- describe "role" do
550
- it "should allow the definition of a basic, empty role" do
551
- stack = ApplicationStack.new("foo") do |s|
552
- s.role :app1
553
- end
554
- stack.roles[:app1].should == {}
555
- end
556
-
557
- it "should use the parameters given to the role definition" do
558
- stack = ApplicationStack.new("foo") do |s|
559
- s.role :app1, :foo => "bar"
560
- end
561
- stack.roles[:app1].should == { :foo => "bar" }
562
- end
563
-
564
- it "should allow for the creation of multiple roles" do
565
- stack = ApplicationStack.new("foo") do |s|
566
- s.role :app1, :foo => "bar"
567
- s.role :app2, :foo => "baz"
568
- end
569
- stack.roles[:app1].should == { :foo => "bar" }
570
- stack.roles[:app2].should == { :foo => "baz" }
571
- end
572
-
573
- it "should map multiple roles to the same set of parameters" do
574
- stack = ApplicationStack.new("foo") do |s|
575
- s.role :app1, :app2, :foo => "bar"
576
- end
577
- stack.roles[:app1].should == { :foo => "bar" }
578
- stack.roles[:app2].should == { :foo => "bar" }
579
- end
580
-
581
- it "should create an accessor mapped to the new role, nil by default" do
582
- stack = ApplicationStack.new("foo") do |s|
583
- s.role :app1, :foo => "bar"
584
- end
585
- stack.app1.should be_nil
586
- end
587
- end
588
-
589
- describe "sdb_domain" do
590
- it "should map to ApplicationStack::DEFAULT_SDB_DOMAIN upon creation" do
591
- ApplicationStack.new("foo").sdb_domain.should == ApplicationStack::DEFAULT_SDB_DOMAIN
592
- end
593
-
594
- it "should be configurable" do
595
- ApplicationStack.new("foo", :sdb_domain => "a domain").sdb_domain.should == "a domain"
596
- end
597
- end
598
-
599
- describe "launch" do
600
- it "should launch its roles when launched" do
601
- s = ApplicationStack.new("test") do |s|
602
- s.role "db1", :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE
603
- s.role "app1", :instance_type => Awsymandias::EC2::InstanceTypes::M1_LARGE
604
- end
605
-
606
- Instance.should_receive(:launch).with({ :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE }).and_return(mock("instance1", :instance_id => "a"))
607
- Instance.should_receive(:launch).with({ :instance_type => Awsymandias::EC2::InstanceTypes::M1_LARGE }).and_return(mock("instance2", :instance_id => "b"))
608
-
609
- s.launch
610
- end
611
-
612
- it "should set the getter for the particular instance to the return value of launching the instance" do
613
- s = ApplicationStack.new("test") do |s|
614
- s.role "db1", :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE
615
- s.role "app1", :instance_type => Awsymandias::EC2::InstanceTypes::M1_LARGE
616
- end
617
-
618
- instances = [ stub_instance, stub_instance ]
619
-
620
- Instance.stub!(:launch).with({ :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE }).and_return instances.first
621
- Instance.stub!(:launch).with({ :instance_type => Awsymandias::EC2::InstanceTypes::M1_LARGE }).and_return instances.last
622
-
623
- s.db1.should be_nil
624
- s.app1.should be_nil
625
-
626
- s.launch
627
-
628
- s.db1.should == instances.first
629
- s.app1.should == instances.last
630
- end
631
-
632
- it "should store details about the newly launched instances" do
633
- Awsymandias::EC2::Instance.stub!(:launch).and_return stub_instance(:instance_id => "abc123")
634
- Awsymandias::EC2::ApplicationStack.new("test") do |s|
635
- s.role "db1", :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE
636
- end.launch
637
-
638
- simpledb.get_attributes(ApplicationStack::DEFAULT_SDB_DOMAIN, "test").should == { "db1" => "abc123" }
639
- end
640
- end
641
-
642
- describe "launched?" do
643
- it "should be false initially" do
644
- s = ApplicationStack.new("test") {|s| s.role "db1", :instance_type => Awsymandias::EC2::InstanceTypes::M1_LARGE}
645
- s.should_not be_launched
646
- end
647
-
648
- it "should be true if launched and instances are non-empty" do
649
- s = ApplicationStack.new("test") { |s| s.role "db1" }
650
- Awsymandias::EC2::Instance.stub!(:launch).and_return stub_instance
651
- s.launch
652
- s.should be_launched
653
- end
654
-
655
- it "should attempt to determine whether or not it's been previously launched" do
656
- Awsymandias::SimpleDB.put ApplicationStack::DEFAULT_SDB_DOMAIN, "test", "db1" => ["instance_id"]
657
- an_instance = stub_instance :instance_id => "instance_id"
658
- Instance.should_receive(:find).with(:all, :instance_ids => [ "instance_id" ]).and_return [ an_instance ]
659
- s = ApplicationStack.new("test") { |s| s.role "db1" }
660
- s.should be_launched
661
- s.db1.should == an_instance
662
- end
663
- end
664
-
665
- describe "running?" do
666
- it "should be false initially" do
667
- ApplicationStack.new("test") {|s| s.role "db1"}.should_not be_running
668
- end
669
-
670
- it "should be false if launched but all instances are pended" do
671
- Instance.stub!(:launch).and_return stub_instance(:instance_state => { :name => "pending" })
672
- ApplicationStack.new("test") {|s| s.role "db1"}.launch.should_not be_running
673
- end
674
-
675
- it "should be false if launched and some instances are pended" do
676
- s = ApplicationStack.new("test") do |s|
677
- s.role "db1", :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE
678
- s.role "app1", :instance_type => Awsymandias::EC2::InstanceTypes::M1_LARGE
679
- end
680
-
681
- Instance.stub!(:launch).
682
- with({ :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE }).
683
- and_return stub_instance(:instance_state => { :name => "pending" })
684
-
685
- Instance.stub!(:launch).
686
- with({ :instance_type => Awsymandias::EC2::InstanceTypes::M1_LARGE }).
687
- and_return stub_instance(:instance_state => { :name => "running" })
688
-
689
- s.launch
690
- s.should_not be_running
691
- end
692
-
693
- it "should be true if launched and all instances are running" do
694
- s = ApplicationStack.new("test") do |s|
695
- s.role "db1", :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE
696
- s.role "app1", :instance_type => Awsymandias::EC2::InstanceTypes::M1_LARGE
697
- end
698
-
699
- Instance.stub!(:launch).
700
- with({ :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE }).
701
- and_return stub_instance(:instance_state => { :name => "running" })
702
-
703
- Instance.stub!(:launch).
704
- with({ :instance_type => Awsymandias::EC2::InstanceTypes::M1_LARGE }).
705
- and_return stub_instance(:instance_state => { :name => "running" })
706
-
707
- s.launch
708
- s.should be_running
709
- end
710
- end
711
-
712
- describe "port_open?" do
713
- it "should return true if there is one instance with the port open" do
714
- s = ApplicationStack.new("test") do |s|
715
- s.role "app1", :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE
716
- end
717
-
718
- instance = stub_instance
719
- instance.should_receive(:port_open?).with(100).and_return(true)
720
- Instance.stub!(:launch).and_return(instance)
721
-
722
- s.launch
723
- s.port_open?(100).should be_true
724
- end
725
-
726
- it "should return false if there is one instance with the port closed" do
727
- s = ApplicationStack.new("test") do |s|
728
- s.role "app1", :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE
729
- end
730
-
731
- instance = stub_instance
732
- instance.should_receive(:port_open?).with(100).and_return(false)
733
- Instance.stub!(:launch).and_return(instance)
734
-
735
- s.launch
736
- s.port_open?(100).should be_false
737
- end
738
-
739
- it "should return true if there are multiple instances all with the port open" do
740
- s = ApplicationStack.new("test") do |s|
741
- s.role "app1", :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE
742
- s.role "app2", :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE
743
- end
744
-
745
- instance1, instance2 = [stub_instance, stub_instance]
746
- instance1.should_receive(:port_open?).with(100).and_return(true)
747
- instance2.should_receive(:port_open?).with(100).and_return(true)
748
- Instance.stub!(:launch).and_return(instance1, instance2)
749
-
750
- s.launch
751
- s.port_open?(100).should be_true
752
- end
753
-
754
- it "should return false if there are multiple instances with at least one port closed" do
755
- s = ApplicationStack.new("test") do |s|
756
- s.role "app1", :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE
757
- s.role "app2", :instance_type => Awsymandias::EC2::InstanceTypes::C1_XLARGE
758
- end
759
-
760
- instance1, instance2 = [stub_instance, stub_instance]
761
- instance1.should_receive(:port_open?).with(100).and_return(true)
762
- instance2.should_receive(:port_open?).with(100).and_return(false)
763
- Instance.stub!(:launch).and_return(instance1, instance2)
764
-
765
- s.launch
766
- s.port_open?(100).should be_false
767
- end
768
-
769
- end
770
-
771
- describe "terminate!" do
772
- it "should not do anything if not running" do
773
- s = ApplicationStack.new("test") { |s| s.role "db1" }
774
- Awsymandias::EC2.should_receive(:connection).never
775
- s.terminate!
776
- end
777
-
778
- it "should terminate all instances if running" do
779
- s = ApplicationStack.new("test") { |s| s.role "db1" }
780
- mock_instance = mock("an_instance", :instance_id => "i-foo")
781
- mock_instance.should_receive(:terminate!)
782
- Instance.stub!(:launch).and_return(mock_instance)
783
- s.launch
784
- s.terminate!
785
- end
786
-
787
- it "should remove any stored role name mappings" do
788
- Awsymandias::SimpleDB.put ApplicationStack::DEFAULT_SDB_DOMAIN, "test", "db1" => ["instance_id"]
789
- s = ApplicationStack.new("test") { |s| s.role "db1" }
790
- Instance.stub!(:launch).and_return stub('stub').as_null_object
791
- s.launch
792
- s.terminate!
793
- Awsymandias::SimpleDB.get(ApplicationStack::DEFAULT_SDB_DOMAIN, "test").should be_blank
794
- end
795
- end
796
-
797
- describe "running_cost" do
798
- it "should be zero if the stack has not been launched" do
799
- s = ApplicationStack.new("test") {|s| s.role "db1", :instance_type => Awsymandias::EC2::InstanceTypes::M1_LARGE}
800
- s.running_cost.should == zero_dollars
801
- end
802
-
803
- it "should be the sum total of the running cost of its constituent instances" do
804
- stack = ApplicationStack.new "test"
805
- stack.should_receive(:retrieve_role_to_instance_id_mapping).and_return({
806
- :db => mock(:instance, :running_cost => Money.new(10)),
807
- :app => mock(:instance, :running_cost => Money.new(20))
808
- })
809
-
810
- stack.running_cost.should == Money.new(30)
811
- end
812
- end
813
- end
814
- end
815
- end