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
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: onyx-awsymandias
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors: []
7
+
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-14 04:00:00 +00:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email:
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib
26
+ - lib/awsymandias.rb
27
+ has_rdoc: false
28
+ homepage:
29
+ licenses: []
30
+
31
+ post_install_message:
32
+ rdoc_options: []
33
+
34
+ require_paths:
35
+ - bin
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: "0"
42
+ version:
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: "0"
48
+ version:
49
+ requirements: []
50
+
51
+ rubyforge_project:
52
+ rubygems_version: 1.3.2
53
+ signing_key:
54
+ specification_version: 3
55
+ summary:
56
+ test_files: []
57
+
@@ -4,34 +4,18 @@
4
4
 
5
5
  Awsymandias is a library that helps you set up and tear down complicated AWS environments. In addition to offering a clean, fluent domain model for working with instances and groups of instances it allows you to persist role-to-instance-id mappings to SimpleDB, allowing you to manage your stack from multiple different machines. Eventually it will allow you to add arbitrary instance metadata and help you track instance running costs over time.
6
6
 
7
- I met a hacker from an antique land
8
- Who said: Two tall and heavy mounts of steel
9
- Lie in a basement. Near them on a stand,
10
- Recessed, a dark CRT lies, whose peel’d
11
- Cracked shell of dullest beige, and blinkenlights,
12
- Tell that its fact’ry well those old specs read
13
- Which yet survive, inked on the lifeless thing,
14
- The die that stamp’d them and the power that fed.
15
- And on the burned-in screen these words appear:
16
- “My name is Awsymandias, king of kings:
17
- Look on my racks, ye Mighty, and despair!”
18
- No bits at all remain. Not far away
19
- A data center waits, its humming air
20
- Host to a boundless cloud by th’hour to pay.
21
-
22
- (Apologies to Shelley’s original sonnet. Die-hards will please note that it scans and attempts to follow the original meter and rhyme scheme wherever possible.)
23
-
24
7
  == Example
25
8
 
26
9
  # Give the stack a name, and describe its members.
27
- stack = Awsymandias::EC2::ApplicationStack.new("test") do |s|
28
- s.role "db", :instance_type => "m1.large", ...
29
- s.role "app", :instance_type => "c1.xlarge", ...
10
+ stack = Awsymandias::EC2::ApplicationStack.define("test") do |s|
11
+ s.instance :db, :instance_type => "m1.large", ...
12
+ s.instance :app, :instance_type => "c1.xlarge", ...
13
+ s.volume :data, :volume_id => "vol-12345", :instance => :db, :unix_device => "/dev/sdj"
30
14
  end
31
15
 
32
16
  # Check if we're running by pulling stack description from SDB; if not, launch asynchronously.
33
17
  stack.launch unless stack.launched? || stack.running?
34
- until stack.running?
18
+ until stack.reload.running?
35
19
  sleep(5)
36
20
  end
37
21
 
@@ -48,6 +32,26 @@ This should allow you to re-launch and deploy that AWS stack from any one of sev
48
32
  * {Paul Gross}[http://www.pgrs.net] {github}[http://github.com/pgr0ss] {email}[mailto:pgross@gmail.com]
49
33
  * Rob Sweet (rob@ldg.net)
50
34
  * Kris Hicks (krishicks at gmail dot com)
35
+ * {Tony Pitluga}[http://tonypitluga.blogspot.com/] {github}[http://github.com/pitluga] {email}[mailto:tony.pitluga@gmail.com]
36
+
37
+ == Brief Expository Sonnet
38
+
39
+ I met a hacker from an antique land
40
+ Who said: Two tall and heavy mounts of steel
41
+ Lie in a basement. Near them on a stand,
42
+ Recessed, a dark CRT lies, whose peel’d
43
+ Cracked shell of dullest beige, and blinkenlights,
44
+ Tell that its fact’ry well those old specs read
45
+ Which yet survive, inked on the lifeless thing,
46
+ The die that stamp’d them and the power that fed.
47
+ And on the burned-in screen these words appear:
48
+ “My name is Awsymandias, king of kings:
49
+ Look on my racks, ye Mighty, and despair!”
50
+ No bits at all remain. Not far away
51
+ A data center waits, its humming air
52
+ Host to a boundless cloud by th’hour to pay.
53
+
54
+ (Apologies to Shelley’s original. Diehards will please note that it scans and attempts to follow the original meter and rhyme scheme wherever possible.)
51
55
 
52
56
  == License
53
57
 
data/Rakefile CHANGED
@@ -3,12 +3,28 @@ require 'spec/rake/spectask'
3
3
  require 'rake/gempackagetask'
4
4
  require 'jeweler'
5
5
 
6
- # task :spec
7
- Spec::Rake::SpecTask.new do |t|
8
- t.rcov = true
9
- t.rcov_opts = ["--text-summary", "--include-file lib/awsymandias", "--exclude gems,spec"]
6
+
7
+ namespace :spec do
8
+
9
+ desc "runs all the unit specs"
10
+ Spec::Rake::SpecTask.new(:unit) do |t|
11
+ t.rcov = true
12
+ t.rcov_opts = ["--text-summary", "--include-file lib/awsymandias", "--exclude gems,spec"]
13
+ t.spec_files = FileList['spec/unit/**/*_spec.rb']
14
+ end
15
+
16
+ desc "runs all the integration specs (requires AMAZON_ACCESS_KEY_ID and AMAZON_SECRET_ACCESS_KEY env variables to be set)"
17
+ Spec::Rake::SpecTask.new(:integration) do |t|
18
+ t.rcov = true
19
+ t.rcov_opts = ["--text-summary", "--include-file lib/awsymandias", "--exclude gems,spec"]
20
+ t.spec_files = FileList['spec/integration/**/*_spec.rb']
21
+ end
22
+
10
23
  end
11
24
 
25
+ desc "runs all the specs"
26
+ task :spec => [:'spec:unit', :'spec:integration']
27
+
12
28
  task :default => [:spec]
13
29
 
14
30
  desc "Open an irb session preloaded with this library"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.3.1
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{awsymandias}
5
- s.version = "0.2.1"
5
+ s.version = "0.3.1"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Brian Guthrie"]
9
- s.date = %q{2009-07-15}
9
+ s.date = %q{2009-08-11}
10
10
  s.description = %q{A library for helping you set up, track, and tear down complicated deployment configurations in Amazon EC2.}
11
11
  s.email = %q{btguthrie@gmail.com}
12
12
  s.extra_rdoc_files = [
@@ -14,20 +14,36 @@ Gem::Specification.new do |s|
14
14
  ]
15
15
  s.files = [
16
16
  ".gitignore",
17
+ ".specification",
17
18
  "README.rdoc",
18
19
  "Rakefile",
19
20
  "VERSION",
20
21
  "awsymandias.gemspec",
21
22
  "lib/awsymandias.rb",
22
- "spec/awsymandias_spec.rb",
23
- "vendor/aws-sdb/LICENSE",
24
- "vendor/aws-sdb/README",
25
- "vendor/aws-sdb/Rakefile",
26
- "vendor/aws-sdb/lib/aws_sdb.rb",
27
- "vendor/aws-sdb/lib/aws_sdb/error.rb",
28
- "vendor/aws-sdb/lib/aws_sdb/service.rb",
29
- "vendor/aws-sdb/spec/aws_sdb/service_spec.rb",
30
- "vendor/aws-sdb/spec/spec_helper.rb"
23
+ "lib/awsymandias/addons/right_elb_interface.rb",
24
+ "lib/awsymandias/ec2.rb",
25
+ "lib/awsymandias/ec2/application_stack.rb",
26
+ "lib/awsymandias/extensions/class_extension.rb",
27
+ "lib/awsymandias/extensions/net_http_extension.rb",
28
+ "lib/awsymandias/instance.rb",
29
+ "lib/awsymandias/load_balancer.rb",
30
+ "lib/awsymandias/right_aws.rb",
31
+ "lib/awsymandias/right_elb.rb",
32
+ "lib/awsymandias/simple_db.rb",
33
+ "lib/awsymandias/snapshot.rb",
34
+ "lib/awsymandias/stack_definition.rb",
35
+ "lib/awsymandias/volume.rb",
36
+ "spec/integration/instance_spec.rb",
37
+ "spec/unit/addons/right_elb_interface_spec.rb",
38
+ "spec/unit/awsymandias_spec.rb",
39
+ "spec/unit/ec2/application_stack_spec.rb",
40
+ "spec/unit/instance_spec.rb",
41
+ "spec/unit/load_balancer_spec.rb",
42
+ "spec/unit/right_aws_spec.rb",
43
+ "spec/unit/simple_db_spec.rb",
44
+ "spec/unit/snapshot_spec.rb",
45
+ "spec/unit/stack_definition_spec.rb",
46
+ "tags"
31
47
  ]
32
48
  s.has_rdoc = true
33
49
  s.homepage = %q{http://github.com/bguthrie/awsymandias}
@@ -36,7 +52,16 @@ Gem::Specification.new do |s|
36
52
  s.rubygems_version = %q{1.3.1}
37
53
  s.summary = %q{A library for helping you set up, track, and tear down complicated deployment configurations in Amazon EC2.}
38
54
  s.test_files = [
39
- "spec/awsymandias_spec.rb"
55
+ "spec/integration/instance_spec.rb",
56
+ "spec/unit/addons/right_elb_interface_spec.rb",
57
+ "spec/unit/awsymandias_spec.rb",
58
+ "spec/unit/ec2/application_stack_spec.rb",
59
+ "spec/unit/instance_spec.rb",
60
+ "spec/unit/load_balancer_spec.rb",
61
+ "spec/unit/right_aws_spec.rb",
62
+ "spec/unit/simple_db_spec.rb",
63
+ "spec/unit/snapshot_spec.rb",
64
+ "spec/unit/stack_definition_spec.rb"
40
65
  ]
41
66
 
42
67
  if s.respond_to? :specification_version then
@@ -1,352 +1,57 @@
1
- Dir[File.dirname(__FILE__) + "/../vendor/**/lib"].each { |dir| $: << dir }
1
+ unless defined?(Awsymandias)
2
+ Dir[File.dirname(__FILE__) + "/../vendor/**/lib"].each { |dir| $: << dir }
3
+ $: << File.dirname(__FILE__)
4
+
5
+ require 'right_aws'
6
+ require "sdb/right_sdb_interface"
7
+ require 'money'
8
+ require 'activesupport'
9
+ require 'activeresource'
10
+ require 'net/telnet'
2
11
 
3
- require 'EC2'
4
- require 'aws_sdb'
5
- require 'money'
6
- require 'activesupport'
7
- require 'activeresource'
8
- require 'net/telnet'
12
+ Dir[File.dirname(__FILE__) + "/awsymandias/extensions/**/*.rb"].each { |file| require file }
13
+ Dir[File.dirname(__FILE__) + "/awsymandias/**/*.rb"].each { |file| require file }
9
14
 
10
- module Awsymandias
11
- class << self
12
- attr_writer :access_key_id, :secret_access_key
13
-
14
- def access_key_id
15
- @access_key_id || AMAZON_ACCESS_KEY_ID || ENV['AMAZON_ACCESS_KEY_ID']
16
- end
17
-
18
- def secret_access_key
19
- @secret_access_key || AMAZON_SECRET_ACCESS_KEY || ENV['AMAZON_SECRET_ACCESS_KEY']
20
- end
21
- end
22
-
23
- module Support
24
- module Hash
25
- # Ganked from ActiveResource 2.3.2.
26
- def reformat_incoming_param_data(params)
27
- case params.class.to_s
28
- when "Hash"
29
- params.inject({}) do |h,(k,v)|
30
- h[k.to_s.underscore.tr("-", "_")] = reformat_incoming_param_data(v)
31
- h
32
- end
33
- when "Array"
34
- params.map { |v| reformat_incoming_param_data(v) }
35
- else
36
- params
37
- end
38
- end
39
- end
40
- end
15
+ module Awsymandias
41
16
 
42
- module EC2
43
17
  class << self
44
- # Define the values for AMAZON_ACCESS_KEY_ID and AMAZON_SECRET_ACCESS_KEY_ID to allow for automatic
45
- # connection creation.
46
- def connection
47
- @connection ||= ::EC2::Base.new(
48
- :access_key_id => Awsymandias.access_key_id || ENV['AMAZON_ACCESS_KEY_ID'],
49
- :secret_access_key => Awsymandias.secret_access_key || ENV['AMAZON_SECRET_ACCESS_KEY']
50
- )
51
- end
52
-
53
- def instance_types
54
- [
55
- Awsymandias::EC2::InstanceTypes::M1_SMALL,
56
- Awsymandias::EC2::InstanceTypes::M1_LARGE,
57
- Awsymandias::EC2::InstanceTypes::M1_XLARGE,
58
- Awsymandias::EC2::InstanceTypes::C1_MEDIUM,
59
- Awsymandias::EC2::InstanceTypes::C1_XLARGE
60
- ].index_by(&:name)
61
- end
62
- end
18
+ attr_writer :access_key_id, :secret_access_key
19
+ attr_accessor :verbose
63
20
 
64
- InstanceType = Struct.new(:name, :price_per_hour)
21
+ Awsymandias.verbose = false
65
22
 
66
- # All currently available instance types.
67
- # TODO Generate dynamically.
68
- module InstanceTypes
69
- M1_SMALL = InstanceType.new("m1.small", Money.new(10))
70
- M1_LARGE = InstanceType.new("m1.large", Money.new(40))
71
- M1_XLARGE = InstanceType.new("m1.xlarge", Money.new(80))
72
-
73
- C1_MEDIUM = InstanceType.new("c1.medium", Money.new(20))
74
- C1_XLARGE = InstanceType.new("c1.xlarge", Money.new(80))
75
- end
76
-
77
- # All currently availability zones.
78
- # TODO Generate dynamically.
79
- module AvailabilityZones
80
- US_EAST_1A = "us_east_1a"
81
- US_EAST_1B = "us_east_1b"
82
- US_EAST_1C = "us_east_1c"
83
-
84
- EU_WEST_1A = "eu_west_1a"
85
- EU_WEST_1B = "eu_west_1b"
86
- end
87
-
88
- # An instance represents an AWS instance as derived from a call to EC2's describe-instances methods.
89
- # It wraps the simple hash structures returned by the EC2 gem with a domain model.
90
- # It inherits from ARes::B in order to provide simple XML <-> domain model mapping.
91
- class Instance < ActiveResource::Base
92
- include Awsymandias::Support::Hash
93
- extend Awsymandias::Support::Hash # reformat_incoming_param_data
94
-
95
- self.site = "mu"
96
-
97
- def id; instance_id; end
98
- def public_dns; dns_name; end
99
- def private_dns; private_dns_name; end
100
-
101
- def pending?
102
- instance_state.name == "pending"
23
+ def access_key_id
24
+ @access_key_id || AMAZON_ACCESS_KEY_ID || ENV['AMAZON_ACCESS_KEY_ID']
103
25
  end
104
26
 
105
- def running?
106
- instance_state.name == "running"
107
- end
108
-
109
- def port_open?(port)
110
- Net::Telnet.new("Host" => public_dns, "Port" => port) && true rescue false
111
- end
112
-
113
- def terminated?
114
- instance_state.name == "terminated"
27
+ def secret_access_key
28
+ @secret_access_key || AMAZON_SECRET_ACCESS_KEY || ENV['AMAZON_SECRET_ACCESS_KEY']
115
29
  end
116
30
 
117
- def terminate!
118
- Awsymandias::EC2.connection.terminate_instances :instance_id => self.instance_id
119
- reload
31
+ def stack_names
32
+ Awsymandias::SimpleDB.query('application-stack', "").flatten.select { |stack_name| !stack_name.blank? }
120
33
  end
121
34
 
122
- def reload
123
- load(reformat_incoming_param_data(
124
- EC2.connection.describe_instances(:instance_id => [ self.instance_id ])["reservationSet"]["item"].
125
- first["instancesSet"]["item"].
126
- first # Good lord.
127
- ))
128
- end
129
-
130
- def to_params
131
- {
132
- :image_id => self.image_id,
133
- :key_name => self.key_name,
134
- :instance_type => self.instance_type,
135
- :availability_zone => self.placement.availability_zone
136
- }
137
- end
138
-
139
- def instance_type
140
- Awsymandias::EC2.instance_types[@attributes['instance_type']]
141
- end
142
-
143
- def launch_time
144
- Time.parse(@attributes['launch_time'])
145
- end
146
-
147
- def uptime
148
- return 0.seconds if pending?
149
- Time.now - self.launch_time
150
- end
151
-
152
- def running_cost
153
- return Money.new(0) if pending?
154
- instance_type.price_per_hour * (uptime / 1.hour).ceil
155
- end
156
-
157
- class << self
158
- def find(*args)
159
- opts = args.extract_options!
160
- what = args.first
161
-
162
- if what == :all
163
- find_all(opts[:instance_ids], opts)
164
- else
165
- find_one(what, opts)
166
- end
167
- end
168
-
169
- def find_all(ids, opts={})
170
- reservation_set = EC2.connection.describe_instances(:instance_id => ids)["reservationSet"]
171
- if reservation_set.nil?
172
- []
173
- else
174
- reservation_set["item"].sum([]) do |item_set|
175
- item_set["instancesSet"]["item"].map do |item|
176
- instantiate_record(reformat_incoming_param_data(item))
177
- end
178
- end
179
- end
35
+ def wait_for(message, refresh_seconds, &block)
36
+ print "Waiting for #{message}.." if Awsymandias.verbose
37
+ while !block.call
38
+ print "." if Awsymandias.verbose
39
+ sleep(refresh_seconds)
180
40
  end
181
-
182
- def find_one(id, opts={})
183
- reservation_set = EC2.connection.describe_instances(:instance_id => [ id ])["reservationSet"]
184
- if reservation_set.nil?
185
- raise ActiveResource::ResourceNotFound, "not found: #{id}"
186
- else
187
- reservation_set["item"].first["instancesSet"]["item"].map do |item|
188
- instantiate_record(reformat_incoming_param_data(item))
189
- end.first
190
- end
191
- end
192
-
193
- def launch(opts={})
194
- opts.assert_valid_keys! :image_id, :key_name, :instance_type, :availability_zone, :user_data
195
-
196
- opts[:instance_type] = opts[:instance_type].name if opts[:instance_type].is_a?(Awsymandias::EC2::InstanceType)
197
-
198
- response = Awsymandias::EC2.connection.run_instances opts
199
- instance_id = response["instancesSet"]["item"].map {|h| h["instanceId"]}.first
200
- find(instance_id)
201
- end
202
- end
203
- end
204
-
205
- # Goal:
206
- # stack = EC2::ApplicationStack.new do |stack|
207
- # stack.role "db", :instance_type => EC2::InstanceTypes::C1_XLARGE, :image_id => "ami-3576915c"
208
- # stack.role "app1", "app2", "app3", :instance_type => EC2::InstanceType::M1_XLARGE, :image_id => "ami-dc789fb5"
209
- # stack.role "memcache", :instance_type => EC2::InstanceType::C1_LARGE, :image_id => "ami-dc789fb5"
210
- # end
211
- # stack.app1.running?
212
- class ApplicationStack
213
- attr_reader :name, :roles, :sdb_domain
214
-
215
- DEFAULT_SDB_DOMAIN = "application-stack"
216
-
217
- class << self
218
- def find(name)
219
- returning(new(name)) do |stack|
220
- return nil unless stack.launched?
221
- end
222
- end
223
-
224
- def launch(name, opts={})
225
- returning(new(name, opts)) do |stack|
226
- stack.launch
227
- end
228
- end
229
- end
230
-
231
- def initialize(name, opts={})
232
- opts.assert_valid_keys! :roles
233
-
234
- @name = name
235
- @roles = opts[:roles] || {}
236
- @sdb_domain = opts[:sdb_domain] || DEFAULT_SDB_DOMAIN
237
- @instances = {}
238
- yield self if block_given?
41
+ verbose_output "OK!"
239
42
  end
240
43
 
241
- def role(*names)
242
- opts = names.extract_options!
243
- names.each do |name|
244
- @roles[name] = opts
245
- self.metaclass.send(:define_method, name) { @instances[name] }
246
- end
247
- end
248
-
249
- def launch
250
- @roles.each do |name, params| # TODO Optimize this for a single remote call.
251
- @instances[name] = Awsymandias::EC2::Instance.launch(params)
252
- end
253
- store_role_to_instance_id_mapping!
254
- self
255
- end
256
-
257
- def reload
258
- raise "Can't reload unless launched" unless launched?
259
- @instances.values.each(&:reload) # TODO Optimize this for a single remote call.
260
- self
261
- end
262
-
263
- def terminate!
264
- @instances.values.each(&:terminate!) # TODO Optimize this for a single remote call.
265
- remove_role_to_instance_id_mapping!
266
- self
267
- end
268
-
269
- def launched?
270
- @instances.any? || ( @instances = retrieve_role_to_instance_id_mapping ).any?
271
- end
272
-
273
- def running?
274
- launched? && @instances.values.all?(&:running?)
275
- end
276
-
277
- def port_open?(port)
278
- @instances.values.all? { |instance| instance.port_open?(port) }
279
- end
280
-
281
- def running_cost
282
- return Money.new(0) unless launched?
283
- @instances.values.sum { |instance| instance.running_cost }
284
- end
285
-
286
- def inspect
287
- ( [ "Environment #{@name}, running? #{running?}" ] + roles.map do |role_name, opts|
288
- "** #{role_name}: #{opts.inspect}"
289
- end ).join("\n")
44
+ def verbose_output(message)
45
+ puts message if Awsymandias.verbose
290
46
  end
291
47
 
292
- private
293
-
294
- def store_role_to_instance_id_mapping!
295
- Awsymandias::SimpleDB.put @sdb_domain, @name, ( returning({}) do |h|
296
- @instances.each {|role_name, instance| h[role_name] = instance.instance_id}
297
- end )
48
+ def describe_stacks
49
+ Awsymandias.stack_names.each do |stack_name|
50
+ stack = EC2::ApplicationStack.find(stack_name)
51
+ puts stack.summarize if stack
52
+ puts ""
298
53
  end
299
-
300
- def remove_role_to_instance_id_mapping!
301
- Awsymandias::SimpleDB.delete @sdb_domain, @name
302
- end
303
-
304
- def retrieve_role_to_instance_id_mapping
305
- returning(Awsymandias::SimpleDB.get(@sdb_domain, @name)) do |mapping|
306
- unless mapping.empty?
307
- live_instances = Awsymandias::EC2::Instance.find(:all, :instance_ids => mapping.values.flatten).index_by(&:instance_id)
308
- mapping.each do |role_name, instance_id|
309
- mapping[role_name] = live_instances[instance_id.first]
310
- end
311
- end
312
- end
313
- end
314
-
54
+ end
315
55
  end
316
56
  end
317
-
318
- # TODO Locate a nicer SimpleDB API and get out of the business of maintaining this one.
319
- module SimpleDB # :nodoc
320
- class << self
321
- def connection(opts={})
322
- @connection ||= ::AwsSdb::Service.new({
323
- :access_key_id => Awsymandias.access_key_id || ENV['AMAZON_ACCESS_KEY_ID'],
324
- :secret_access_key => Awsymandias.secret_access_key || ENV['AMAZON_SECRET_ACCESS_KEY'],
325
- :logger => Logger.new("/dev/null")
326
- }.merge(opts))
327
- end
328
-
329
- def put(domain, name, stuff)
330
- connection.put_attributes handle_domain(domain), name, stuff
331
- end
332
-
333
- def get(domain, name)
334
- connection.get_attributes(handle_domain(domain), name) || {}
335
- end
336
-
337
- def delete(domain, name)
338
- connection.delete_attributes handle_domain(domain), name
339
- end
340
-
341
- private
342
-
343
- def domain_exists?(domain)
344
- Awsymandias::SimpleDB.connection.list_domains[0].include?(domain)
345
- end
346
-
347
- def handle_domain(domain)
348
- returning(domain) { connection.create_domain(domain) unless domain_exists?(domain) }
349
- end
350
- end
351
- end
352
57
  end