rudy 0.4.0 → 0.6.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.
Files changed (135) hide show
  1. data/CHANGES.txt +54 -30
  2. data/README.rdoc +100 -12
  3. data/Rakefile +103 -8
  4. data/Rudyfile +119 -0
  5. data/bin/ird +175 -0
  6. data/bin/rudy +259 -156
  7. data/bin/rudy-ec2 +228 -95
  8. data/bin/rudy-s3 +76 -0
  9. data/bin/rudy-sdb +67 -0
  10. data/lib/annoy.rb +270 -0
  11. data/lib/console.rb +30 -9
  12. data/lib/escape.rb +305 -0
  13. data/lib/rudy.rb +151 -182
  14. data/lib/rudy/aws.rb +56 -49
  15. data/lib/rudy/aws/ec2.rb +47 -292
  16. data/lib/rudy/aws/ec2/address.rb +157 -0
  17. data/lib/rudy/aws/ec2/group.rb +301 -0
  18. data/lib/rudy/aws/ec2/image.rb +168 -0
  19. data/lib/rudy/aws/ec2/instance.rb +434 -0
  20. data/lib/rudy/aws/ec2/keypair.rb +104 -0
  21. data/lib/rudy/aws/ec2/snapshot.rb +98 -0
  22. data/lib/rudy/aws/ec2/volume.rb +230 -0
  23. data/lib/rudy/aws/ec2/zone.rb +77 -0
  24. data/lib/rudy/aws/s3.rb +54 -0
  25. data/lib/rudy/aws/sdb.rb +298 -0
  26. data/lib/rudy/aws/sdb/error.rb +46 -0
  27. data/lib/rudy/{metadata/backup.rb → backup.rb} +26 -51
  28. data/lib/rudy/cli.rb +157 -0
  29. data/lib/rudy/cli/aws/ec2/addresses.rb +105 -0
  30. data/lib/rudy/cli/aws/ec2/candy.rb +208 -0
  31. data/lib/rudy/cli/aws/ec2/groups.rb +121 -0
  32. data/lib/rudy/cli/aws/ec2/images.rb +196 -0
  33. data/lib/rudy/cli/aws/ec2/instances.rb +194 -0
  34. data/lib/rudy/cli/aws/ec2/keypairs.rb +53 -0
  35. data/lib/rudy/cli/aws/ec2/snapshots.rb +49 -0
  36. data/lib/rudy/cli/aws/ec2/volumes.rb +104 -0
  37. data/lib/rudy/cli/aws/ec2/zones.rb +22 -0
  38. data/lib/rudy/cli/aws/s3/buckets.rb +50 -0
  39. data/lib/rudy/cli/aws/s3/store.rb +22 -0
  40. data/lib/rudy/cli/aws/sdb/domains.rb +41 -0
  41. data/lib/rudy/cli/candy.rb +8 -0
  42. data/lib/rudy/{command → cli}/config.rb +34 -24
  43. data/lib/rudy/cli/disks.rb +35 -0
  44. data/lib/rudy/cli/machines.rb +94 -0
  45. data/lib/rudy/cli/routines.rb +57 -0
  46. data/lib/rudy/config.rb +77 -72
  47. data/lib/rudy/config/objects.rb +29 -0
  48. data/lib/rudy/disks.rb +248 -0
  49. data/lib/rudy/global.rb +121 -0
  50. data/lib/rudy/huxtable.rb +340 -0
  51. data/lib/rudy/machines.rb +245 -0
  52. data/lib/rudy/metadata.rb +123 -13
  53. data/lib/rudy/routines.rb +47 -0
  54. data/lib/rudy/routines/helpers/diskhelper.rb +101 -0
  55. data/lib/rudy/routines/helpers/scripthelper.rb +91 -0
  56. data/lib/rudy/routines/release.rb +34 -0
  57. data/lib/rudy/routines/shutdown.rb +57 -0
  58. data/lib/rudy/routines/startup.rb +58 -0
  59. data/lib/rudy/scm/svn.rb +1 -1
  60. data/lib/rudy/utils.rb +322 -4
  61. data/lib/storable.rb +26 -17
  62. data/lib/sysinfo.rb +274 -0
  63. data/lib/tryouts.rb +6 -13
  64. data/rudy.gemspec +128 -42
  65. data/support/randomize-root-password +45 -0
  66. data/support/rudy-ec2-startup +9 -9
  67. data/support/update-ec2-ami-tools +20 -0
  68. data/test/05_config/00_setup_test.rb +20 -0
  69. data/test/05_config/30_machines_test.rb +69 -0
  70. data/test/20_sdb/00_setup_test.rb +16 -0
  71. data/test/20_sdb/10_domains_test.rb +115 -0
  72. data/test/25_ec2/00_setup_test.rb +29 -0
  73. data/test/25_ec2/10_keypairs_test.rb +41 -0
  74. data/test/25_ec2/20_groups_test.rb +131 -0
  75. data/test/25_ec2/30_addresses_test.rb +38 -0
  76. data/test/25_ec2/40_volumes_test.rb +49 -0
  77. data/test/25_ec2/50_snapshots_test.rb +74 -0
  78. data/test/26_ec2_instances/00_setup_test.rb +28 -0
  79. data/test/26_ec2_instances/10_instances_test.rb +83 -0
  80. data/test/26_ec2_instances/50_images_test.rb +13 -0
  81. data/test/30_sdb_metadata/00_setup_test.rb +21 -0
  82. data/test/30_sdb_metadata/10_disks_test.rb +109 -0
  83. data/test/30_sdb_metadata/20_backups_test.rb +102 -0
  84. data/test/coverage.txt +51 -0
  85. data/test/helper.rb +36 -0
  86. data/vendor/highline-1.5.1/CHANGELOG +222 -0
  87. data/vendor/highline-1.5.1/INSTALL +35 -0
  88. data/vendor/highline-1.5.1/LICENSE +7 -0
  89. data/vendor/highline-1.5.1/README +63 -0
  90. data/vendor/highline-1.5.1/Rakefile +82 -0
  91. data/vendor/highline-1.5.1/TODO +6 -0
  92. data/vendor/highline-1.5.1/examples/ansi_colors.rb +38 -0
  93. data/vendor/highline-1.5.1/examples/asking_for_arrays.rb +18 -0
  94. data/vendor/highline-1.5.1/examples/basic_usage.rb +75 -0
  95. data/vendor/highline-1.5.1/examples/color_scheme.rb +32 -0
  96. data/vendor/highline-1.5.1/examples/limit.rb +12 -0
  97. data/vendor/highline-1.5.1/examples/menus.rb +65 -0
  98. data/vendor/highline-1.5.1/examples/overwrite.rb +19 -0
  99. data/vendor/highline-1.5.1/examples/page_and_wrap.rb +322 -0
  100. data/vendor/highline-1.5.1/examples/password.rb +7 -0
  101. data/vendor/highline-1.5.1/examples/trapping_eof.rb +22 -0
  102. data/vendor/highline-1.5.1/examples/using_readline.rb +17 -0
  103. data/vendor/highline-1.5.1/lib/highline.rb +758 -0
  104. data/vendor/highline-1.5.1/lib/highline/color_scheme.rb +120 -0
  105. data/vendor/highline-1.5.1/lib/highline/compatibility.rb +17 -0
  106. data/vendor/highline-1.5.1/lib/highline/import.rb +43 -0
  107. data/vendor/highline-1.5.1/lib/highline/menu.rb +395 -0
  108. data/vendor/highline-1.5.1/lib/highline/question.rb +463 -0
  109. data/vendor/highline-1.5.1/lib/highline/system_extensions.rb +193 -0
  110. data/vendor/highline-1.5.1/setup.rb +1360 -0
  111. data/vendor/highline-1.5.1/test/tc_color_scheme.rb +56 -0
  112. data/vendor/highline-1.5.1/test/tc_highline.rb +823 -0
  113. data/vendor/highline-1.5.1/test/tc_import.rb +54 -0
  114. data/vendor/highline-1.5.1/test/tc_menu.rb +429 -0
  115. data/vendor/highline-1.5.1/test/ts_all.rb +15 -0
  116. metadata +141 -38
  117. data/lib/aws_sdb.rb +0 -3
  118. data/lib/aws_sdb/error.rb +0 -42
  119. data/lib/aws_sdb/service.rb +0 -215
  120. data/lib/rudy/aws/simpledb.rb +0 -53
  121. data/lib/rudy/command/addresses.rb +0 -46
  122. data/lib/rudy/command/backups.rb +0 -175
  123. data/lib/rudy/command/base.rb +0 -841
  124. data/lib/rudy/command/deploy.rb +0 -12
  125. data/lib/rudy/command/disks.rb +0 -213
  126. data/lib/rudy/command/environment.rb +0 -73
  127. data/lib/rudy/command/groups.rb +0 -61
  128. data/lib/rudy/command/images.rb +0 -91
  129. data/lib/rudy/command/instances.rb +0 -85
  130. data/lib/rudy/command/machines.rb +0 -161
  131. data/lib/rudy/command/metadata.rb +0 -41
  132. data/lib/rudy/command/release.rb +0 -174
  133. data/lib/rudy/command/volumes.rb +0 -66
  134. data/lib/rudy/metadata/disk.rb +0 -138
  135. data/tryouts/console_tryout.rb +0 -91
@@ -0,0 +1,121 @@
1
+
2
+ module Rudy; module CLI;
3
+ module AWS; module EC2;
4
+
5
+ class Groups < Rudy::CLI::CommandBase
6
+
7
+
8
+
9
+ def create_groups_valid?
10
+ @rgroups = Rudy::AWS::EC2::Groups.new(@@global.accesskey, @@global.secretkey, @@global.region)
11
+ raise Drydock::ArgError.new('group name', @alias) unless @argv.name
12
+ raise "Group #{@argv.name} alread exists" if @rgroups.exists?(@argv.name)
13
+ true
14
+ end
15
+ def create_groups
16
+ opts = check_options
17
+ puts "Creating #{@argv.name}"
18
+
19
+ execute_action {
20
+ @rgroups.create(@argv.name, @option.description, opts[:addresses], opts[:ports], opts[:protocols])
21
+ }
22
+
23
+ @rgroups.list(@argv.name) do |group|
24
+ puts @@global.verbose > 0 ? group.inspect : group.dump(@@global.format)
25
+ end
26
+ end
27
+
28
+
29
+ def destroy_groups_valid?
30
+ @rgroups = Rudy::AWS::EC2::Groups.new(@@global.accesskey, @@global.secretkey, @@global.region)
31
+ raise Drydock::ArgError.new('group name', @alias) unless @argv.name
32
+ raise "Group #{@argv.name} does not exist" unless @rgroups.exists?(@argv.name)
33
+ true
34
+ end
35
+
36
+ def destroy_groups
37
+ puts "Destroying group: #{@argv.name}"
38
+ execute_check(:medium)
39
+ execute_action { @rgroups.destroy(@argv.name) }
40
+ @argv.clear # so groups will print all other groups
41
+ groups
42
+ end
43
+
44
+ def revoke_groups_valid?; modify_group_valid?; end
45
+ def revoke_groups; modify_group(:revoke); end
46
+
47
+ def authorize_groups_valid?; modify_group_valid?; end
48
+ def authorize_groups; modify_group(:authorize); end
49
+
50
+ def groups
51
+ opts = {}
52
+ name = @option.all ? nil : @argv.name
53
+ rgroups = Rudy::AWS::EC2::Groups.new(@@global.accesskey, @@global.secretkey, @@global.region)
54
+ rgroups.list(name).each do |group|
55
+ puts @@global.verbose > 0 ? group.inspect : group.dump(@@global.format)
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def modify_group_valid?
62
+ if @option.owner == 'self'
63
+ raise "AWS_ACCOUNT_NUMBER not set" unless @@global.accountnum
64
+ @option.owner = @@global.accountnum
65
+ end
66
+
67
+ if (@option.addresses || @option.ports) && (@option.group || @option.owner)
68
+ raise Drydock::OptError.new('', @alias, "Cannot mix group and network authorization")
69
+ end
70
+ if @option.owner && !@option.group
71
+ raise Drydock::OptError.new('', @alias, "Must provide -g with -o")
72
+ end
73
+
74
+ raise Drydock::ArgError.new('group name', @alias) unless @argv.name
75
+ @groups = Rudy::AWS::EC2::Groups.new(@@global.accesskey, @@global.secretkey, @@global.region)
76
+ end
77
+
78
+ def modify_group(action)
79
+ opts = check_options
80
+ if (@option.group || @option.owner)
81
+ g = [opts[:owner], opts[:group]].join(':')
82
+ puts "#{action.to_s.capitalize} access to #{@argv.name.bright} from #{g.bright}"
83
+ else
84
+ print "#{action.to_s.capitalize} access to #{@argv.name.bright}"
85
+ puts " from #{opts[:addresses].join(', ').bright}"
86
+ print "on #{opts[:protocols].join(', ').bright} "
87
+ puts "ports: #{opts[:ports].map { |p| "#{p.join(' to ').bright}" }.join(', ')}"
88
+ end
89
+ rgroups = Rudy::AWS::EC2::Groups.new(@@global.accesskey, @@global.secretkey, @@global.region)
90
+ execute_check(:medium)
91
+ execute_action {
92
+ if (@option.group || @option.owner)
93
+ rgroups.send("#{action.to_s}_group", @argv.name, opts[:group], opts[:owner])
94
+ else
95
+ rgroups.send(action, @argv.name, opts[:addresses], opts[:ports], opts[:protocols])
96
+ end
97
+ }
98
+ groups # prints on the modified group b/c of @argv.name
99
+ end
100
+
101
+ def check_options
102
+ opts = {}
103
+ [:addresses, :protocols, :owner, :group, :ports].each do |opt|
104
+ opts[opt] = @option.send(opt) if @option.respond_to?(opt)
105
+ end
106
+ unless @option.group || @option.owner
107
+ opts[:ports].collect! { |port| port.split(/[:-]/) } if opts[:ports]
108
+ opts[:ports] ||= [[22,22],[80,80],[443,443]]
109
+ opts[:addresses] ||= [Rudy::Utils::external_ip_address]
110
+ opts[:protocols] ||= [:tcp]
111
+ else
112
+ opts[:owner] ||= @@global.accountnum
113
+ end
114
+ opts
115
+ end
116
+
117
+ end
118
+
119
+
120
+ end; end
121
+ end; end
@@ -0,0 +1,196 @@
1
+
2
+
3
+ module Rudy; module CLI;
4
+ module AWS; module EC2;
5
+
6
+ class Images < Rudy::CLI::CommandBase
7
+
8
+ #def print_header
9
+ # puts @global.print_header, @@global.print_header
10
+ #end
11
+
12
+
13
+ def images_valid?
14
+ if @option.owner == 'self'
15
+ raise "AWS_ACCOUNT_NUMBER not set" unless @@global.accountnum
16
+ @option.owner = @@global.accountnum
17
+ end
18
+
19
+ true
20
+ end
21
+ def images
22
+
23
+ rimages = Rudy::AWS::EC2::Images.new(@@global.accesskey, @@global.secretkey, @@global.region)
24
+ unless @option.all
25
+ @option.owner ||= 'amazon'
26
+ puts "Images owned by #{@option.owner.bright}" unless @argv.awsid
27
+ end
28
+
29
+ images = rimages.list(@option.owner, @argv) || []
30
+ images.each do |img|
31
+ puts @@global.verbose > 0 ? img.inspect : img.dump(@@global.format)
32
+ end
33
+ puts "No images" if images.empty?
34
+ end
35
+
36
+ def prepare_images_valid?
37
+ true
38
+ end
39
+ def prepare_images
40
+ opts = {}
41
+ opts[:group] = @option.group if @option.group
42
+ opts[:group] = :any if @option.all
43
+ opts[:id] = @option.instid if @option.instid
44
+
45
+ puts "This will do the following:"
46
+ puts "- Clear bash history"
47
+ # NOTE: We can't delete the host keys here. Otherwise we can't create the image.
48
+ #puts "- Delete host SSH keys (this is permanent!)"
49
+ puts ""
50
+
51
+ # Options to be sent to Net::SSH
52
+ ssh_opts = { :user => @global.user || Rudy.sysinfo.user, :debug => STDERR }
53
+ if @@global.pkey
54
+ raise "Cannot find file #{@@global.pkey}" unless File.exists?(@@global.pkey)
55
+ raise InsecureKeyPermissions, @@global.pkey unless File.stat(@@global.pkey).mode == 33152
56
+ ssh_opts[:keys] = @@global.pkey
57
+ end
58
+
59
+ execute_check(:medium)
60
+
61
+ rudy = Rudy::AWS::EC2::Instances.new(@@global.accesskey, @@global.secretkey, @@global.region)
62
+ lt = rudy.list_group(opts[:group], :running, opts[:id]) do |inst|
63
+
64
+ puts "Preparing #{inst.dns_public}..."
65
+
66
+ # Open the connection and run the command
67
+ rbox = Rye::Box.new(inst.dns_public, ssh_opts)
68
+ rbox.safe = false
69
+ # We need to explicitly add the rm command for rbox so we
70
+ # can delete the SSH host keys. This is will force the instance
71
+ # to re-create it's SSH keys on first boot.
72
+ def rbox.rm(*args); cmd('rm', args); end
73
+ p ret = rbox.history(:c)
74
+ p ret.exit_code
75
+ p ret.stderr
76
+ p ret.stdout
77
+
78
+ end
79
+
80
+ puts "done"
81
+ end
82
+
83
+ def create_images_valid?
84
+ raise "No account number" unless @@global.accountnum
85
+ raise "No Amazon cert-***.pem" unless @@global.cert
86
+ raise "No Amazon pk-***.pem" unless @@global.privatekey
87
+ true
88
+ end
89
+
90
+ def create_images
91
+ opts = {}
92
+ opts[:group] = @option.group if @option.group
93
+ opts[:group] = :any if @option.all
94
+ opts[:id] = @option.instid if @option.instid
95
+
96
+ puts "You may want to run rudy-ec2 #{@alias} --prepare before this.".color(:blue)
97
+ puts "This feature is experimental. Make sure you enter the bucket"
98
+ puts "and image names correctly because if they're wrong the image"
99
+ puts "won't get created and you'll be annoyed that you waited."
100
+
101
+ # Options to be sent to Net::SSH
102
+ ssh_opts = { :user => @global.user || Rudy.sysinfo.user, :debug => STDERR }
103
+ if @@global.pkey
104
+ raise "Cannot find file #{@@global.pkey}" unless File.exists?(@@global.pkey)
105
+ raise InsecureKeyPermissions, @@global.pkey unless File.stat(@@global.pkey).mode == 33152
106
+ ssh_opts[:keys] = @@global.pkey
107
+ end
108
+
109
+ unless @option.name
110
+ print "Enter the image name: "
111
+ @option.image_name = gets.chomp
112
+ end
113
+
114
+ unless @option.bucket
115
+ print "Enter the S3 bucket that will store the image: "
116
+ @option.bucket_name = gets.chomp
117
+ end
118
+
119
+ execute_check(:medium)
120
+
121
+ rudy = Rudy::AWS::EC2::Instances.new(@@global.accesskey, @@global.secretkey, @@global.region)
122
+ lt = rudy.list_group(opts[:group], :running, opts[:id]) do |inst|
123
+
124
+ puts inst.dns_public
125
+
126
+ # Open the connection and run the command
127
+ rbox = Rye::Box.new(inst.dns_public, ssh_opts)
128
+
129
+ # ~/.rudy, /etc/motd, history -c, /etc/hosts, /var/log/rudy*
130
+ cert = File.read(@@global.cert)
131
+ pk = File.read(@@global.privatekey)
132
+ rbox.safe = false
133
+ rbox.echo("'#{cert}' > /mnt/cert-temporary.pem")
134
+ rbox.echo("'#{pk}' > /mnt/pk-temporary.pem")
135
+ rbox.safe = true
136
+ rbox.touch("/root/firstrun")
137
+
138
+ # TODO:
139
+ # We have to delete the host keys just before we run the bundle command.
140
+ # The problem is that if we lose the connection we won't be able to connect
141
+ # to the instance again. A better solution is to ass the keys to the ignore
142
+ # list for the bundle command.
143
+
144
+ #ret = rbox.rm('/etc/ssh/ssh_host_*_key*')
145
+ #puts "Starting bundling process...".bright
146
+ #puts ssh_command(machine[:dns_name], keypairpath, @global.user, "ec2-bundle-vol -r i386 -p #{@option.image_name} -k /mnt/pk-*pem -c /mnt/cert*pem -u #{@option.account}", @option.print)
147
+ #puts ssh_command(machine[:dns_name], keypairpath, @global.user, "ec2-upload-bundle -b #{@option.bucket_name} -m /tmp/#{@option.image_name}.manifest.xml -a #{@global.accesskey} -s #{@global.secretkey}", @option.print)
148
+ #
149
+ #@ec2.images.register("#{@option.bucket_name}/#{@option.image_name}.manifest.xml") unless @option.print
150
+
151
+ break
152
+ end
153
+
154
+ end
155
+
156
+ #def create_images_valid?
157
+ # puts "Make sure the machine is clean. I don't want archive no crud!"
158
+ # switch_user("root")
159
+ #
160
+ # raise "No EC2 .pem keys provided" unless has_pem_keys?
161
+ # raise "No SSH key provided for #{@global.user}!" unless has_keypair?
162
+ # raise "No SSH key provided for root!" unless has_keypair?(:root)
163
+ # true
164
+ #end
165
+ #
166
+ #
167
+ #def prepare_images
168
+ # # TODO: Avail hooks for clean an instance
169
+ # # Clean off Rudy specific crap.
170
+ #end
171
+ #
172
+ #
173
+
174
+ #
175
+ #def deregister
176
+ # ami = @argv.first
177
+ # raise "You must supply an AMI ID (ami-XXXXXXX)" unless ami
178
+ # puts "Deregistering AMI: #{ami}"
179
+ #
180
+ # exit unless Annoy.are_you_sure?
181
+ #
182
+ # if @ec2.images.deregister(ami)
183
+ # puts "Done!"
184
+ # else
185
+ # puts "There was an unknown problem!"
186
+ # end
187
+ #
188
+ #end
189
+
190
+ end
191
+
192
+
193
+ end; end
194
+ end; end
195
+
196
+
@@ -0,0 +1,194 @@
1
+
2
+
3
+ module Rudy; module CLI;
4
+ module AWS; module EC2;
5
+ class InstanceAndGroupError < Drydock::ArgError
6
+ def message; "You cannot provide a group and an instance ID"; end
7
+ end
8
+ class NoInstanceError < Drydock::ArgError
9
+ def message; "You must provide a group or instance ID"; end
10
+ end
11
+
12
+ class Instances < Rudy::CLI::CommandBase
13
+
14
+ def instances_create_valid?
15
+
16
+ raise "Cannot supply an instance ID" if @option.instid
17
+
18
+ if @option.group
19
+ rgroup = Rudy::AWS::EC2::Groups.new(@@global.accesskey, @@global.secretkey, @@global.region)
20
+ raise "Group #{@option.group} does not exist" unless rgroup.exists?(@option.group)
21
+ end
22
+
23
+ true
24
+ end
25
+
26
+ def instances_create
27
+
28
+ opts = { # Defaults
29
+ :group => 'default',
30
+ :size => 'm1.small',
31
+ :zone => @@global.zone
32
+ }
33
+
34
+ radd = Rudy::AWS::EC2::Addresses.new(@@global.accesskey, @@global.secretkey, @@global.region)
35
+ rinst = Rudy::AWS::EC2::Instances.new(@@global.accesskey, @@global.secretkey, @@global.region)
36
+
37
+ if @option.address
38
+ raise "Cannot specify both -a and -n" if @option.newaddress
39
+ raise "#{@option.address} is not allocated to you" unless radd.exists?(@option.address)
40
+ raise "#{@option.address} is already associated!" if radd.associated?(@option.address)
41
+ end
42
+
43
+ # These can be sent directly to EC2 class
44
+ [:group, :ami, :size, :keypair, :private].each do |n|
45
+ opts[n] = @option.send(n) if @option.send(n)
46
+ end
47
+
48
+ puts "Creating #{opts[:size]} instance in #{@@global.zone}"
49
+
50
+ unless opts[:keypair]
51
+ puts "You did not specify a keypair. Unless you've prepared a user account".color(:blue)
52
+ puts "on this image (#{opts[:ami]}) you will not be able to log in to it.".color(:blue)
53
+ exit unless Annoy.proceed?(:low)
54
+ end
55
+
56
+ instances = rinst.list_group(opts[:group], :running)
57
+
58
+ if instances && instances.size > 0
59
+ instance_count = (instances.size == 1) ? 'is 1 instance' : "are #{instances.size} instances"
60
+ puts "There #{instance_count} running in the #{opts[:group]} group."
61
+ exit unless Annoy.proceed?(:low)
62
+ end
63
+
64
+ if @option.newaddress
65
+ print "Creating address... "
66
+ address = radd.create
67
+ puts "#{address.ipaddress}"
68
+ @option.address = address.ipaddress
69
+ end
70
+
71
+ execute_action do
72
+ first_instance = true
73
+ rinst.create(opts) do |inst| # Rudy::AWS::EC2::Instance objects
74
+
75
+ # Assign IP address to only the first instance
76
+ if first_instance && @option.address
77
+ puts "Associating #{@option.address} to #{inst.awsid}"
78
+ radd.associate(@option.address, inst.awsid)
79
+ first_instance = false
80
+ end
81
+
82
+ puts @@global.verbose > 0 ? inst.inspect : inst.dump(@@global.format)
83
+ end
84
+ end
85
+ end
86
+
87
+ def instances_restart_valid?
88
+ raise InstanceAndGroupError.new(nil, @alias) if @option.group && @argv.instid
89
+ raise NoInstanceError.new(nil, @alias) if !@option.group && !@argv.instid
90
+
91
+ if @option.group
92
+ rgroup = Rudy::AWS::EC2::Groups.new(@@global.accesskey, @@global.secretkey, @@global.region)
93
+ raise "Group #{@option.group} does not exist" unless rgroup.exists?(@option.group)
94
+ end
95
+
96
+ if @option.private
97
+ raise Drydock::OptsError.new(nil, @alias, "Cannot allocate public IP for private instance") if @option.address || @option.newadress
98
+ end
99
+
100
+ @rinst = Rudy::AWS::EC2::Instances.new(@@global.accesskey, @@global.secretkey, @@global.region)
101
+ raise "No instances" unless @rinst.any?
102
+ true
103
+ end
104
+ alias :instances_destroy_valid? :instances_restart_valid?
105
+
106
+ def instances_destroy
107
+ instances_action :destroy
108
+ end
109
+
110
+ def instances_restart
111
+ instances_action :restart
112
+ end
113
+
114
+ def consoles_valid?
115
+ @rinst = Rudy::AWS::EC2::Instances.new(@@global.accesskey, @@global.secretkey, @@global.region)
116
+ raise "No instances" unless @rinst.any?
117
+ true
118
+ end
119
+ def consoles
120
+ opts = {}
121
+ opts[:group] = @option.group if @option.group
122
+ opts[:id] = @argv.instid if @argv.instid
123
+ opts[:id] &&= [opts[:id]].flatten
124
+
125
+ lt = @rinst.list_group(opts[:group], :any, opts[:id]) do |inst|
126
+ puts '-'*50
127
+ puts "Console for: #{inst.liner_note}", $/
128
+ console = @rinst.console(inst.awsid)
129
+ output = console ? Base64.decode64(console) : "Unavailable"
130
+ puts output.noansi # Remove color and clear, etc...
131
+ end
132
+
133
+ end
134
+
135
+ def status
136
+ opts = {}
137
+
138
+ opts[:group] = @option.group if @option.group
139
+ opts[:state] = @option.state if @option.state
140
+
141
+ # A nil value forces the @ec2.instances.list to return all instances
142
+ if @option.all
143
+ opts[:state] = :any
144
+ opts[:group] = :any
145
+ end
146
+
147
+ opts[:id] = @argv.instid if @argv.instid
148
+ opts[:id] &&= [opts[:id]].flatten
149
+
150
+ rudy = Rudy::AWS::EC2::Instances.new(@@global.accesskey, @@global.secretkey, @@global.region)
151
+ lt = rudy.list_group(opts[:group], opts[:state], opts[:id]) do |inst|
152
+ puts @@global.verbose > 0 ? inst.inspect : inst.dump(@@global.format)
153
+ end
154
+ puts "No instances running" if !lt || lt.empty?
155
+ end
156
+ alias :instances :status
157
+
158
+
159
+ private
160
+
161
+ # * +action+ is one of :destroy, :restart
162
+ def instances_action(action)
163
+ opts = {}
164
+ opts[:group] = @option.group if @option.group
165
+ opts[:id] = @argv.instid if @argv.instid
166
+ opts[:id] &&= [opts[:id]].flatten
167
+
168
+ instances = @rinst.list_group(opts[:group], :running, opts[:id])
169
+ raise "No matching instances running" if instances.nil?
170
+
171
+ inst_names = instances.collect { |inst| inst.dns_public || inst.awsid }
172
+ inst_ids = instances.collect { |inst| inst.awsid }
173
+
174
+ instance_count = (instances.size == 1) ? '1 instance' : "#{instances.size} instances"
175
+
176
+ print "#{action.to_s.capitalize} #{instance_count} (#{inst_names.join(', ')}) "
177
+ print "in #{opts[:group]}" if opts[:group]
178
+ puts
179
+ execute_check(:medium)
180
+
181
+ execute_action("#{action.to_s.capitalize} Failed") {
182
+ @rinst.send(action, inst_ids)
183
+ }
184
+ status
185
+ end
186
+
187
+
188
+ end
189
+
190
+ end; end
191
+ end; end
192
+
193
+
194
+