solutious-rudy 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. data/CHANGES.txt +8 -9
  2. data/README.rdoc +48 -7
  3. data/Rakefile +102 -7
  4. data/Rudyfile +28 -0
  5. data/bin/ird +162 -0
  6. data/bin/rudy +287 -93
  7. data/lib/annoy.rb +227 -0
  8. data/lib/aws_sdb/service.rb +1 -1
  9. data/lib/console.rb +20 -4
  10. data/lib/escape.rb +305 -0
  11. data/lib/rudy.rb +265 -125
  12. data/lib/rudy/aws.rb +61 -26
  13. data/lib/rudy/aws/ec2.rb +20 -296
  14. data/lib/rudy/aws/ec2/address.rb +121 -0
  15. data/lib/rudy/aws/ec2/group.rb +241 -0
  16. data/lib/rudy/aws/ec2/image.rb +46 -0
  17. data/lib/rudy/aws/ec2/instance.rb +407 -0
  18. data/lib/rudy/aws/ec2/keypair.rb +92 -0
  19. data/lib/rudy/aws/ec2/snapshot.rb +87 -0
  20. data/lib/rudy/aws/ec2/volume.rb +234 -0
  21. data/lib/rudy/aws/simpledb.rb +33 -15
  22. data/lib/rudy/cli.rb +142 -0
  23. data/lib/rudy/cli/addresses.rb +85 -0
  24. data/lib/rudy/cli/backups.rb +175 -0
  25. data/lib/rudy/{command → cli}/config.rb +18 -13
  26. data/lib/rudy/cli/deploy.rb +12 -0
  27. data/lib/rudy/cli/disks.rb +125 -0
  28. data/lib/rudy/cli/domains.rb +17 -0
  29. data/lib/rudy/cli/groups.rb +77 -0
  30. data/lib/rudy/{command → cli}/images.rb +18 -6
  31. data/lib/rudy/cli/instances.rb +142 -0
  32. data/lib/rudy/cli/keypairs.rb +47 -0
  33. data/lib/rudy/cli/manager.rb +51 -0
  34. data/lib/rudy/{command → cli}/release.rb +10 -10
  35. data/lib/rudy/cli/routines.rb +80 -0
  36. data/lib/rudy/cli/volumes.rb +121 -0
  37. data/lib/rudy/command/addresses.rb +62 -39
  38. data/lib/rudy/command/backups.rb +60 -170
  39. data/lib/rudy/command/disks-old.rb +322 -0
  40. data/lib/rudy/command/disks.rb +5 -209
  41. data/lib/rudy/command/domains.rb +34 -0
  42. data/lib/rudy/command/groups.rb +105 -48
  43. data/lib/rudy/command/instances.rb +263 -70
  44. data/lib/rudy/command/keypairs.rb +149 -0
  45. data/lib/rudy/command/manager.rb +65 -0
  46. data/lib/rudy/command/volumes.rb +110 -49
  47. data/lib/rudy/config.rb +90 -70
  48. data/lib/rudy/config/objects.rb +67 -0
  49. data/lib/rudy/huxtable.rb +253 -0
  50. data/lib/rudy/metadata/backup.rb +23 -48
  51. data/lib/rudy/metadata/disk.rb +79 -68
  52. data/lib/rudy/metadata/machine.rb +34 -0
  53. data/lib/rudy/routines.rb +54 -0
  54. data/lib/rudy/routines/disk_handler.rb +190 -0
  55. data/lib/rudy/routines/release.rb +15 -0
  56. data/lib/rudy/routines/script_runner.rb +65 -0
  57. data/lib/rudy/routines/shutdown.rb +42 -0
  58. data/lib/rudy/routines/startup.rb +48 -0
  59. data/lib/rudy/utils.rb +57 -2
  60. data/lib/storable.rb +11 -5
  61. data/lib/sysinfo.rb +274 -0
  62. data/rudy.gemspec +84 -20
  63. data/support/randomize-root-password +45 -0
  64. data/support/rudy-ec2-startup +5 -5
  65. data/support/update-ec2-ami-tools +20 -0
  66. data/test/05_config/00_setup_test.rb +24 -0
  67. data/test/05_config/30_machines_test.rb +69 -0
  68. data/test/20_sdb/00_setup_test.rb +31 -0
  69. data/test/20_sdb/10_domains_test.rb +113 -0
  70. data/test/25_ec2/00_setup_test.rb +34 -0
  71. data/test/25_ec2/10_keypairs_test.rb +33 -0
  72. data/test/25_ec2/20_groups_test.rb +139 -0
  73. data/test/25_ec2/30_addresses_test.rb +35 -0
  74. data/test/25_ec2/40_volumes_test.rb +46 -0
  75. data/test/25_ec2/50_snapshots_test.rb +69 -0
  76. data/test/26_ec2_instances/00_setup_test.rb +33 -0
  77. data/test/26_ec2_instances/10_instances_test.rb +81 -0
  78. data/test/26_ec2_instances/50_images_test.rb +13 -0
  79. data/test/30_sdb_metadata/00_setup_test.rb +28 -0
  80. data/test/30_sdb_metadata/10_disks_test.rb +99 -0
  81. data/test/30_sdb_metadata/20_backups_test.rb +102 -0
  82. data/test/50_commands/00_setup_test.rb +11 -0
  83. data/test/50_commands/10_keypairs_test.rb +79 -0
  84. data/test/50_commands/20_groups_test.rb +77 -0
  85. data/test/50_commands/40_volumes_test.rb +55 -0
  86. data/test/50_commands/50_instances_test.rb +110 -0
  87. data/test/coverage.txt +51 -0
  88. data/test/helper.rb +35 -0
  89. data/tryouts/disks.rb +55 -0
  90. data/tryouts/nested_methods.rb +36 -0
  91. data/tryouts/session_tryout.rb +48 -0
  92. metadata +94 -25
  93. data/bin/rudy-ec2 +0 -108
  94. data/lib/rudy/command/base.rb +0 -839
  95. data/lib/rudy/command/deploy.rb +0 -12
  96. data/lib/rudy/command/environment.rb +0 -74
  97. data/lib/rudy/command/machines.rb +0 -170
  98. data/lib/rudy/command/metadata.rb +0 -41
  99. data/lib/rudy/metadata.rb +0 -26
@@ -0,0 +1,34 @@
1
+
2
+
3
+ module Rudy
4
+ class Domains
5
+ include Rudy::Huxtable
6
+
7
+
8
+ def list
9
+ @@sdb.domains.list || []
10
+ end
11
+
12
+ def get(n=nil)
13
+ n = name(Rudy::RUDY_DOMAIN)
14
+ n &&= n.to_s
15
+ doms = list.select { |domain| domain == n }
16
+ doms = nil if doms.empty?
17
+ doms
18
+ end
19
+
20
+ def exists?(n=nil)
21
+ !get(n).nil?
22
+ end
23
+
24
+ def name(n=nil)
25
+ n || Rudy::RUDY_DOMAIN
26
+ end
27
+
28
+ def create(n=nil)
29
+ n = name(n)
30
+ @@sdb.domains.create(n)
31
+ end
32
+
33
+ end
34
+ end
@@ -1,61 +1,118 @@
1
1
 
2
2
 
3
-
4
3
  module Rudy
5
- module Command
6
- class Groups < Rudy::Command::Base
4
+ class Groups
5
+ include Rudy::Huxtable
6
+
7
+
8
+ def create(n=nil, description=nil, opts={})
9
+ n ||= name(n)
10
+ description ||= "Machine group #{n}"
11
+ raise "Group #{n} already exists" if @@ec2.groups.exists?(n)
12
+ @@ec2.groups.create(n, description)
13
+ authorize(n, opts)
14
+ end
15
+
16
+ def destroy(n=nil)
17
+ n ||= name(n)
18
+ raise "Group #{n} does not exist" unless @@ec2.groups.exists?(n)
19
+ @@ec2.groups.destroy(n)
20
+ end
21
+
22
+ def authorize(n=nil, opts={})
23
+ n ||= name(n)
24
+ modify_rules(:authorize, n, opts)
25
+ end
26
+ def revoke(n=nil, opts={})
27
+ n ||= name(n)
28
+ modify_rules(:revoke, n, opts)
29
+ end
30
+
31
+ def exists?(n=nil)
32
+ n ||= name(n)
33
+ @@ec2.groups.exists?(n)
34
+ end
35
+
36
+ def name(n=nil)
37
+ n || current_machine_group
38
+ end
39
+
40
+
41
+ # Do any groups exist? The default group is not considered here since it
42
+ # cannot be destroyed. We're interested in any other groups.
43
+ def any?
44
+ groups = @@ec2.groups.list_as_hash
45
+ return false unless groups
46
+ groups.reject! { |name,g| g.name == 'default' }
47
+ !groups.empty?
48
+ end
49
+
50
+ def list(n=nil, &each_object)
51
+ n &&= [n]
52
+ groups = @@ec2.groups.list(n)
53
+ groups.each { |g| each_object.call(g) } if each_object
54
+ groups
55
+ end
56
+
57
+ def get(n=nil)
58
+ n ||= name(n)
59
+ (list(n) || []).first
60
+ end
61
+
62
+ def list_as_hash(n=nil, &each_object)
63
+ n &&= [n]
64
+ groups = @@ec2.groups.list_as_hash(n)
65
+ groups.each_pair { |n,g| each_object.call(g) } if each_object
66
+ groups
67
+ end
68
+
69
+ # TODO: Consider changing the hash interface into arguments.
70
+ # with different methods for authorizing groups and addresses
71
+ def modify_rules(action, n, opts={})
72
+ n ||= name(n)
7
73
 
8
- def groups(name=@argv.first)
9
- name = machine_group if name.nil? && !@option.all
10
- @ec2.groups.list(name).each do |grp|
11
- print_group grp
12
- end
13
- end
74
+ raise "You must supply a group name" unless n
75
+ raise "Group does not exist" unless @@ec2.groups.exists?(n)
76
+ @logger.puts "#{action.to_s.capitalize} access for #{n.bright}"
14
77
 
15
- def create_groups(name=@argv.first)
16
- name ||= machine_group
17
- puts "Creating group #{name}"
18
- raise "The group #{name} already exists" if @ec2.groups.exists?(name)
19
78
 
20
- @ec2.groups.create(name)
21
-
22
- modify_groups name
23
- end
79
+ opts[:ports] ||= [[22,22],[80,80],[443,443]]
80
+ opts[:protocols] ||= ["tcp"]
81
+ opts[:addresses] ||= [Rudy::Utils::external_ip_address]
82
+
83
+ # Make sure the IP addresses have ranges
84
+ opts[:addresses].collect! { |ip| (ip.match /\/\d+/) ? ip : "#{ip}/32" }
24
85
 
25
- def modify_groups(name=@argv.first)
26
- name ||= machine_group
27
- raise "The group #{name} does not exist" unless @ec2.groups.exists?(name)
28
-
29
- @option.addresses ||= [Rudy::Utils::external_ip_address]
30
- @option.ports ||= [22,80,443]
31
- @option.protocols ||= ["tcp"]
32
-
33
- # Make sure the IP addresses have ranges
34
- @option.addresses.collect! { |ip| (ip.match /\/\d+/) ? ip : "#{ip}/32" }
35
-
36
- @option.protocols.each do |protocol|
37
- puts "Adding ports #{@option.ports.join(',')} (#{protocol}) for #{@option.addresses.join(', ')}"
38
- @option.addresses.each do |address|
39
- @option.ports.each do |port|
40
- @ec2.groups.modify(name, port, port, protocol, address)
41
- end
86
+ opts[:protocols].each do |protocol|
87
+ opts[:addresses].each do |address|
88
+ opts[:ports].each do |port|
89
+ @logger.puts "Ports #{port[0]}:#{port[1]} (#{protocol}) for #{opts[:addresses].join(', ')}"
90
+ @@ec2.groups.send(action, n, port[0].to_i, (port[1] || port[0]).to_i, protocol, address)
42
91
  end
43
92
  end
44
-
45
- groups name
46
93
  end
47
94
 
48
- def destroy_groups(name=@argv.first)
49
- name ||= machine_group
50
- puts "Destroying group #{name}"
51
- name = machine_group if name.nil?
52
- raise "The group #{name} does not exist" unless @ec2.groups.exists?(name)
53
- exit unless are_you_sure?
54
-
55
- @ec2.groups.destroy(name)
56
-
57
- end
95
+ @@ec2.groups.get(n)
96
+
97
+
58
98
  end
59
- end
60
- end
99
+
100
+ def modify_group_rules(n=nil, group=nil, owner=nil)
101
+ n ||= name(n)
102
+
103
+ owner ||= @config.accounts.aws.accountnum
104
+
105
+ raise "You must supply a group name" unless n
106
+ raise "Group does not exist" unless @@ec2.groups.exists?(n)
107
+ raise "Owner to authorize not specified" unless owner
108
+ raise "Group to authorize not specified" unless owner
109
+
110
+ @logger.puts "#{action.to_s.capitalize} access for #{n.bright}"
111
+
112
+ @@ec2.groups.send("#{action}_group", n, group, owner)
61
113
 
114
+ @@ec2.groups.get(n)
115
+ end
116
+
117
+ end
118
+ end
@@ -1,85 +1,278 @@
1
- #
2
- #
3
- #
4
- #
5
- #
6
- #
7
- #
8
- #
9
- #
10
- #
11
- #
1
+
12
2
 
13
3
  module Rudy
14
- module Command
15
- class Instances < Rudy::Command::Base
4
+ class Instances
5
+ include Rudy::Huxtable
6
+
7
+
8
+ def create(opts={}, &each_inst)
16
9
 
17
- def restart_instances_valid?
18
- raise "No instance ID provided" if @argv.filter.nil?
19
- raise "No EC2 .pem keys provided" unless has_pem_keys?
20
- raise "No SSH key provided for #{@global.user}!" unless has_keypair?
21
- raise "No SSH key provided for root!" unless has_keypair?(:root)
22
-
23
-
24
- @list = @ec2.instances.list(machine_group)
25
- raise "#{@argv.filter} is not in the current machine group" unless @list.has_key?(@argv.filter)
26
-
27
- raise "I will not help you destroy production!" if @global.environment == "prod" # TODO: use_caution?, locked?
28
-
29
- exit unless are_you_sure?(5)
30
- true
31
- end
32
- def restart_instances
33
- puts "Restarting #{@argv.filter}!"
34
- @ec2.instances.restart @argv.filter
35
- end
10
+ rgroup = Rudy::Groups.new(:config => @config, :global => @global)
36
11
 
37
- def instances
38
- filter = @argv.first
39
- filter = machine_group if filter.nil? && !@option.all
40
- if instance_id?(filter)
41
- inst = @ec2.instances.get(filter)
42
- raise "The instance #{filter} does not exist" if inst.empty?
43
- list = {inst[:aws_instance_id] => inst}
44
- else
45
- raise "The security group #{filter} does not exist" if filter && !@ec2.groups.exists?(filter)
46
- list = @ec2.instances.list(filter)
47
- if list.empty?
48
- msg = "There are no instances running"
49
- msg << " in the group #{filter}" if filter
50
- raise msg
51
- end
12
+ # TODO: Handle itype on create
13
+ opts = { :ami => current_machine_image,
14
+ :group => current_machine_group,
15
+ :user => current_user,
16
+ :size => "m1.small",
17
+ :keypair => user_keypairpath(:root), # Must be a root key
18
+ :address => current_machine_address,
19
+ :machine_data => machine_data.to_yaml }.merge(opts)
20
+
21
+ raise NoGroup.new(opts[:group]) unless rgroup.exists?(opts[:group])
22
+ raise NoRootKeyPair.new(opts[:group]) if !opts[:keypair] && !has_keypair?(:root)
23
+
24
+ keypair_name = KeyPairs.path_to_name(opts[:keypair])
25
+
26
+ instances = @@ec2.instances.create(opts[:ami], opts[:group], keypair_name, opts[:machine_data], @global.zone)
27
+
28
+
29
+ #instances = [@@ec2.instances.get("i-39009850")]
30
+ instances_with_dns = []
31
+ instances.each_with_index do |inst_tmp,index|
32
+ Rudy.bug('hs672h48') && next if inst_tmp.nil?
33
+
34
+ @logger.puts "Instance: #{inst_tmp.awsid}"
35
+ if opts[:address] && index == 0 # We currently only support assigned an address to the first machine
36
+ @logger.puts "Associating #{opts[:address]} to #{inst_tmp.awsid}"
37
+ @@ec2.addresses.associate(inst_tmp.awsid, opts[:address])
52
38
  end
53
-
54
- list.each_pair do |id, inst|
55
- print_instance inst
39
+
40
+ @logger.puts "Waiting for the instance to startup "
41
+ begin
42
+ # TODO: Puts "it's up" and :bell => 3 into waiter
43
+ Rudy.waiter(2, 120, @logger) { !@@ec2.instances.pending?(inst_tmp.awsid) }
44
+ raise Exception unless @@ec2.instances.running?(inst_tmp.awsid)
45
+ @logger.puts "It's up!"
46
+ Rudy.bell(3)
47
+ rescue Timeout::Error, Interrupt, Exception
48
+ @logger.puts "It's not up yet. Check later: " << "rudy status #{inst_tmp.awsid}".color(:blue)
49
+ next
56
50
  end
57
-
51
+
52
+ # The DNS names are now available so we need to grab that data from AWS
53
+ instance = @@ec2.instances.get(inst_tmp.awsid)
54
+ instances_with_dns << instance
55
+
56
+ @logger.puts $/, "Waiting for the SSH daemon "
57
+ begin
58
+ Rudy.waiter(1, 60, @logger) { Rudy::Utils.service_available?(instance.dns_name_public, 22) }
59
+ @logger.puts "It's up!"
60
+ Rudy.bell(2)
61
+ rescue Timeout::Error, Interrupt, Exception
62
+ @logger.puts "SSH isn't up yet. Check later: " << "rudy status #{inst_tmp.awsid}".color(:blue)
63
+ next
64
+ end
65
+
66
+
58
67
  end
59
68
 
60
- def destroy_instances_valid?
61
- filter = argv.first
62
- raise "No instance ID provided" if filter.nil?
63
- raise "I will not help you destroy production!" if @global.environment == "prod" || filter =~ /^prod/
64
- exit unless are_you_sure?
65
- true
69
+ instances_with_dns.each { |inst| each_inst.call(inst) } if each_inst
70
+ instances_with_dns
71
+ end
72
+
73
+ def destroy(group=nil, inst_id=[], &each_inst)
74
+ group ||= current_machine_group
75
+ raise "No machines running in #{group}" unless running?(group)
76
+ instances = @@ec2.instances.list_group(group, :running, inst_id)
77
+ instances &&= [instances].flatten
78
+ instances.each { |inst| each_inst.call(inst) } if each_inst
79
+ @logger.puts $/, "Terminating instances...", $/
80
+ @@ec2.instances.destroy(instances, :skip_check)
81
+ end
82
+
83
+ # * +state+ instance state (:running, :terminated, :pending, :shutting_down)
84
+ # * +group+ machine group name. The default is the current machine group
85
+ # (as determined by the globals) if none is supplied. A value of :any will
86
+ # return machines from all groups.
87
+ # * +inst_ids+ An Array of instance IDs (Strings) or Instance objects to
88
+ # filter the list by. Any instances not in the group will be ignored.
89
+ # * +each_inst+ a block to execute for every instance in the list.
90
+ # Returns an Array of Rudy::AWS::EC2::Instance objects
91
+ def list(state=nil, group=nil, inst_ids=[], &each_inst)
92
+ group ||= current_machine_group
93
+ unless group == :any
94
+ instances = @@ec2.instances.list_group(group, state, inst_ids) || []
95
+ else
96
+ instances = @@ec2.instances.list(state, inst_ids) || []
97
+ end
98
+ instances.each { |inst| each_inst.call(inst) } if each_inst
99
+ instances
100
+ end
101
+
102
+ # See Rudy::Instances#list for arguments.
103
+ # Returns a Hash of Rudy::AWS::EC2::Instance objects (the keys are instance IDs)
104
+ def list_as_hash(state=nil, group=nil, inst_ids=[], &each_inst)
105
+ group ||= current_machine_group
106
+ if group == :any
107
+ instances = @@ec2.instances.list_group_as_hash(group, state, inst_ids) || {}
108
+ else
109
+ instances = @@ec2.instances.list_as_hash(state, inst_ids) || {}
66
110
  end
111
+ instances.each_pair { |inst_id,inst| each_inst.call(inst) } if each_inst
112
+ instances
113
+ end
114
+
115
+ # System console output.
116
+ #
117
+ # NOTE: Amazon sends the console output as a Base64 encoded string. This method
118
+ # decrypts it before returning it.
119
+ #
120
+ # Returns output for the first machine in the group (if provided) or the first
121
+ # instance ID (if provided)
122
+ def console(group=nil, inst_ids=[])
123
+ group ||= current_machine_group
124
+ instances = @@ec2.instances.list_group(group, :any, inst_ids)
125
+ return if instances.nil?
126
+ output = @@ec2.instances.console_output(instances.first.awsid)
127
+ return unless output
128
+ Base64.decode64(output)
129
+ end
130
+
131
+ def connect(group=nil, cmd=nil, inst_ids=[], print_only=false)
132
+ group ||= current_machine_group
133
+ instances = @@ec2.instances.list_group(group, :running, inst_ids)
134
+ raise "No machines running" if instances.nil?
135
+ raise "No keypair configured for user #{current_user}" unless current_user_keypairpath
136
+
137
+ # TODO: If a group is supplied we need to discover the keypair.
138
+
139
+ instances.each do |inst|
140
+ msg = cmd ? %Q{"#{cmd}" on} : "Connecting to"
141
+ @logger.puts $/, "#{msg} #{inst.dns_name_public}", $/
142
+ ret = ssh_command(inst.dns_name_public, current_user_keypairpath, @global.user, cmd, print_only)
143
+ puts ret if ret # ssh command returns false with "ssh_exchange_identification: Connection closed by remote host"
144
+ end
145
+ end
146
+
147
+
148
+ # * +:recursive: recursively transfer directories (default: false)
149
+ # * +:preserve: preserve atimes and ctimes (default: false)
150
+ # * +:task+ one of: :upload (default), :download.
151
+ # * +:paths+ an array of paths to copy. The last element is the "to" path.
152
+ def copy(group=nil, inst_ids=[], opts={})
153
+ group ||= current_machine_group
154
+ instances = @@ec2.instances.list_group(group, :running, inst_ids)
155
+ raise "No machines running" if instances.nil?
156
+ raise "No keypair configured for user #{current_user}" unless current_user_keypairpath
157
+ raise "You must supply at least one source path" if !opts[:paths] || opts[:paths].empty?
158
+ raise "You must supply a destination path" unless opts[:dest]
159
+
160
+
161
+ opts = {
162
+ :task => :upload,
163
+ :recursive => false,
164
+ :preserve => false
165
+ }.merge(opts)
67
166
 
68
- def destroy_instances
69
- filter = argv.first
70
-
71
- if @ec2.groups.exists?(filter)
72
- list = @ec2.instances.list(filter)
73
- raise "The group #{filter} has no running instances" if list.empty?
74
- instance = list.keys.first
75
- else
76
- instance = filter
167
+
168
+ instances.each do |inst|
169
+ msg = opts[:task] == :upload ? "Upload to" : "Download from"
170
+ @logger.puts $/, "#{msg} #{inst.awsid}"
171
+
172
+ if opts[:print]
173
+ scp_command inst.dns_name_public, current_user_keypairpath, @global.user, opts[:paths], opts[:dest], (opts[:task] == :download), false, opts[:print]
174
+ return
77
175
  end
78
- puts "Destroying #{instance}!"
79
- @ec2.instances.destroy instance
176
+
177
+ scp_opts = {
178
+ :recursive => opts[:recursive],
179
+ :preserve => opts[:preserve],
180
+ :chunk_size => 16384
181
+ }
182
+
183
+ scp(opts[:task], inst.dns_name_public, @global.user, current_user_keypairpath, opts[:paths], opts[:dest], scp_opts)
184
+
80
185
  end
186
+
187
+ @logger.puts
188
+ end
189
+
190
+
191
+ # * +group+ machine group name
192
+ def any?(group=nil)
193
+ group ||= current_machine_group
194
+
195
+ @@ec2.instances.any_group?(group)
196
+ end
197
+
198
+ def exists?(inst_id)
199
+ @@ec2.instances.exists?(inst_id)
200
+ end
201
+
202
+ # *NOTE REGARDING THE STATUS METHODS*:
203
+ #
204
+ # We currently return true IF ANY instances are operating
205
+ # in the given state. This is faulty but we can't fix it
206
+ # until we have a way to know how many instances should be
207
+ # running in any given group.
208
+ #
209
+ # Are *any* instances in the group in the running state?
210
+ def running?(group=nil)
211
+ !list(:running, group).empty?
212
+ end
213
+
214
+ # Are *any* instances in the group in the terminated state?
215
+ def terminated?(group=nil)
216
+ !list(:terminated, group).empty?
217
+ end
218
+
219
+ # Are *any* instances in the group in the shutting-down state?
220
+ def shutting_down?(group=nil)
221
+ !list(:shutting_down, group).empty?
222
+ end
223
+
224
+ # Are *any* instances in the group in the pending state?
225
+ def pending?(group=nil)
226
+ !list(:pending, group).empty?
227
+ end
228
+
229
+ # Are *any* instances in the group in the a non-running state?
230
+ def unavailable?(group=nil)
231
+ # We go through @@ec2 so we don't reimplement the "unavailable logic"
232
+ instances = list(:any, group)
233
+ @@ec2.instances.unavailable?(instances)
234
+ end
235
+
236
+
237
+
238
+
239
+ private
81
240
 
241
+ def machine_data
242
+ data = {
243
+ # Give the machine an identity
244
+ :zone => @global.zone,
245
+ :environment => @global.environment,
246
+ :role => @global.role,
247
+ :position => @global.position,
248
+
249
+ # Add hosts to the /etc/hosts file
250
+ :hosts => {
251
+ :dbmaster => "127.0.0.1",
252
+ }
253
+ }
254
+ data.to_hash
82
255
  end
256
+
257
+
258
+
83
259
  end
84
- end
85
-
260
+ class NoGroup < RuntimeError
261
+ def initialize(group)
262
+ @group = group
263
+ end
264
+ def message
265
+ "Group #{@group} does not exist. See: rudy groups -h"
266
+ end
267
+ end
268
+
269
+ class NoRootKeyPair < RuntimeError
270
+ def initialize(group)
271
+ @group = group
272
+ end
273
+ def message
274
+ "No root keypair for #{@group}. See: rudy keypairs -h"
275
+ end
276
+ end
277
+
278
+ end