sabat-rudy 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +188 -0
- data/LICENSE.txt +19 -0
- data/README.rdoc +118 -0
- data/Rakefile +165 -0
- data/Rudyfile +184 -0
- data/bin/ird +153 -0
- data/bin/rudy +232 -0
- data/bin/rudy-ec2 +241 -0
- data/bin/rudy-s3 +79 -0
- data/bin/rudy-sdb +69 -0
- data/examples/README.md +10 -0
- data/examples/debian-sinatra-passenger/commands.rb +19 -0
- data/examples/debian-sinatra-passenger/machines.rb +32 -0
- data/examples/debian-sinatra-passenger/routines.rb +30 -0
- data/examples/debian-sinatra-thin/commands.rb +17 -0
- data/examples/debian-sinatra-thin/machines.rb +35 -0
- data/examples/debian-sinatra-thin/routines.rb +72 -0
- data/lib/rudy.rb +170 -0
- data/lib/rudy/aws.rb +75 -0
- data/lib/rudy/aws/ec2.rb +59 -0
- data/lib/rudy/aws/ec2/address.rb +157 -0
- data/lib/rudy/aws/ec2/group.rb +301 -0
- data/lib/rudy/aws/ec2/image.rb +168 -0
- data/lib/rudy/aws/ec2/instance.rb +438 -0
- data/lib/rudy/aws/ec2/keypair.rb +104 -0
- data/lib/rudy/aws/ec2/snapshot.rb +109 -0
- data/lib/rudy/aws/ec2/volume.rb +230 -0
- data/lib/rudy/aws/ec2/zone.rb +77 -0
- data/lib/rudy/aws/s3.rb +60 -0
- data/lib/rudy/aws/sdb.rb +312 -0
- data/lib/rudy/aws/sdb/error.rb +47 -0
- data/lib/rudy/cli.rb +186 -0
- data/lib/rudy/cli/aws/ec2/addresses.rb +105 -0
- data/lib/rudy/cli/aws/ec2/candy.rb +191 -0
- data/lib/rudy/cli/aws/ec2/groups.rb +118 -0
- data/lib/rudy/cli/aws/ec2/images.rb +185 -0
- data/lib/rudy/cli/aws/ec2/instances.rb +222 -0
- data/lib/rudy/cli/aws/ec2/keypairs.rb +53 -0
- data/lib/rudy/cli/aws/ec2/snapshots.rb +49 -0
- data/lib/rudy/cli/aws/ec2/volumes.rb +104 -0
- data/lib/rudy/cli/aws/ec2/zones.rb +22 -0
- data/lib/rudy/cli/aws/s3/buckets.rb +49 -0
- data/lib/rudy/cli/aws/s3/store.rb +22 -0
- data/lib/rudy/cli/aws/sdb/domains.rb +41 -0
- data/lib/rudy/cli/candy.rb +19 -0
- data/lib/rudy/cli/config.rb +81 -0
- data/lib/rudy/cli/disks.rb +58 -0
- data/lib/rudy/cli/machines.rb +114 -0
- data/lib/rudy/cli/routines.rb +108 -0
- data/lib/rudy/config.rb +116 -0
- data/lib/rudy/config/objects.rb +148 -0
- data/lib/rudy/global.rb +130 -0
- data/lib/rudy/guidelines.rb +18 -0
- data/lib/rudy/huxtable.rb +373 -0
- data/lib/rudy/machines.rb +281 -0
- data/lib/rudy/metadata.rb +51 -0
- data/lib/rudy/metadata/backup.rb +113 -0
- data/lib/rudy/metadata/backups.rb +65 -0
- data/lib/rudy/metadata/disk.rb +177 -0
- data/lib/rudy/metadata/disks.rb +67 -0
- data/lib/rudy/metadata/objectbase.rb +104 -0
- data/lib/rudy/mixins.rb +2 -0
- data/lib/rudy/mixins/hash.rb +25 -0
- data/lib/rudy/routines.rb +318 -0
- data/lib/rudy/routines/helper.rb +55 -0
- data/lib/rudy/routines/helpers/dependshelper.rb +34 -0
- data/lib/rudy/routines/helpers/diskhelper.rb +331 -0
- data/lib/rudy/routines/helpers/scmhelper.rb +39 -0
- data/lib/rudy/routines/helpers/scripthelper.rb +198 -0
- data/lib/rudy/routines/helpers/userhelper.rb +37 -0
- data/lib/rudy/routines/passthrough.rb +38 -0
- data/lib/rudy/routines/reboot.rb +75 -0
- data/lib/rudy/routines/release.rb +50 -0
- data/lib/rudy/routines/shutdown.rb +33 -0
- data/lib/rudy/routines/startup.rb +36 -0
- data/lib/rudy/scm.rb +75 -0
- data/lib/rudy/scm/git.rb +217 -0
- data/lib/rudy/scm/svn.rb +110 -0
- data/lib/rudy/utils.rb +365 -0
- data/rudy.gemspec +151 -0
- data/support/mailtest +40 -0
- data/support/randomize-root-password +45 -0
- data/support/rudy-ec2-startup +200 -0
- data/support/update-ec2-ami-tools +20 -0
- data/test/01_mixins/10_hash_test.rb +25 -0
- data/test/10_config/00_setup_test.rb +20 -0
- data/test/10_config/30_machines_test.rb +69 -0
- data/test/15_scm/00_setup_test.rb +20 -0
- data/test/15_scm/20_git_test.rb +61 -0
- data/test/20_sdb/00_setup_test.rb +16 -0
- data/test/20_sdb/10_domains_test.rb +115 -0
- data/test/25_ec2/00_setup_test.rb +29 -0
- data/test/25_ec2/10_keypairs_test.rb +41 -0
- data/test/25_ec2/20_groups_test.rb +131 -0
- data/test/25_ec2/30_addresses_test.rb +38 -0
- data/test/25_ec2/40_volumes_test.rb +49 -0
- data/test/25_ec2/50_snapshots_test.rb +74 -0
- data/test/26_ec2_instances/00_setup_test.rb +28 -0
- data/test/26_ec2_instances/10_instances_test.rb +83 -0
- data/test/26_ec2_instances/50_images_test.rb +13 -0
- data/test/30_sdb_metadata/00_setup_test.rb +21 -0
- data/test/30_sdb_metadata/10_disks_test.rb +109 -0
- data/test/30_sdb_metadata/20_backups_test.rb +102 -0
- data/test/coverage.txt +51 -0
- data/test/helper.rb +36 -0
- metadata +276 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Rudy; module CLI;
|
4
|
+
module AWS; module EC2;
|
5
|
+
|
6
|
+
class Addresses < Rudy::CLI::CommandBase
|
7
|
+
|
8
|
+
def addresses_create
|
9
|
+
radd = Rudy::AWS::EC2::Addresses.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
10
|
+
address = radd.create
|
11
|
+
puts @@global.verbose > 0 ? address.inspect : address.dump(@@global.format)
|
12
|
+
end
|
13
|
+
|
14
|
+
def addresses_destroy_valid?
|
15
|
+
raise Drydock::ArgError.new("IP address", @alias) unless @argv.ipaddress
|
16
|
+
@radd = Rudy::AWS::EC2::Addresses.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
17
|
+
raise "#{@argv.ipaddress} is not allocated to you" unless @radd.exists?(@argv.ipaddress)
|
18
|
+
raise "#{@argv.ipaddress} is associated!" if @radd.associated?(@argv.ipaddress)
|
19
|
+
true
|
20
|
+
end
|
21
|
+
def addresses_destroy
|
22
|
+
address = @radd.get(@argv.ipaddress)
|
23
|
+
raise "Could not fetch #{address.ipaddress}" unless address
|
24
|
+
|
25
|
+
puts "Destroying address: #{@argv.ipaddress}"
|
26
|
+
puts "NOTE: this IP address will become available to other EC2 customers.".bright
|
27
|
+
execute_check(:medium)
|
28
|
+
execute_action { @radd.destroy(@argv.ipaddress) }
|
29
|
+
self.addresses
|
30
|
+
end
|
31
|
+
|
32
|
+
def associate_addresses_valid?
|
33
|
+
raise Drydock::ArgError.new('IP address', @alias) if !@argv.ipaddress && !@option.newaddress
|
34
|
+
raise Drydock::OptError.new('instance ID', @alias) if !@option.instance
|
35
|
+
true
|
36
|
+
end
|
37
|
+
def associate_addresses
|
38
|
+
radd = Rudy::AWS::EC2::Addresses.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
39
|
+
rinst = Rudy::AWS::EC2::Instances.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
40
|
+
|
41
|
+
raise "Instance #{@argv.instid} does not exist!" unless rinst.exists?(@option.instance)
|
42
|
+
|
43
|
+
if @option.newaddress
|
44
|
+
print "Creating address... "
|
45
|
+
tmp = radd.create
|
46
|
+
puts "#{tmp.ipaddress}"
|
47
|
+
address = tmp.ipaddress
|
48
|
+
else
|
49
|
+
address = @argv.ipaddress
|
50
|
+
end
|
51
|
+
|
52
|
+
raise "#{address} is not allocated to you" unless radd.exists?(address)
|
53
|
+
raise "#{address} is already associated!" if radd.associated?(address)
|
54
|
+
|
55
|
+
instance = rinst.get(@option.instance)
|
56
|
+
|
57
|
+
# If an instance was recently disassoiciated, the dns_public may
|
58
|
+
# not be updated yet
|
59
|
+
instance_name = instance.dns_public
|
60
|
+
instance_name = instance.awsid if !instance_name || instance_name.empty?
|
61
|
+
|
62
|
+
puts "Associating #{address} to #{instance_name} (#{instance.groups.join(', ')})"
|
63
|
+
execute_check(:low)
|
64
|
+
execute_action { radd.associate(address, instance.awsid) }
|
65
|
+
address = radd.get(address)
|
66
|
+
puts @@global.verbose > 0 ? address.inspect : address.dump(@@global.format)
|
67
|
+
end
|
68
|
+
|
69
|
+
def disassociate_addresses_valid?
|
70
|
+
raise "You have not supplied an IP addresses" unless @argv.ipaddress
|
71
|
+
true
|
72
|
+
end
|
73
|
+
def disassociate_addresses
|
74
|
+
radd = Rudy::AWS::EC2::Addresses.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
75
|
+
rinst = Rudy::AWS::EC2::Instances.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
76
|
+
raise "#{@argv.ipaddress} is not allocated to you" unless radd.exists?(@argv.ipaddress)
|
77
|
+
raise "#{@argv.ipaddress} is not associated!" unless radd.associated?(@argv.ipaddress)
|
78
|
+
|
79
|
+
address = radd.get(@argv.ipaddress)
|
80
|
+
instance = rinst.get(address.instid)
|
81
|
+
|
82
|
+
puts "Disassociating #{address.ipaddress} from #{instance.awsid} (#{instance.groups.join(', ')})"
|
83
|
+
execute_check(:medium)
|
84
|
+
execute_action { radd.disassociate(@argv.ipaddress) }
|
85
|
+
address = radd.get(@argv.ipaddress)
|
86
|
+
puts @@global.verbose > 0 ? address.inspect : address.dump(@@global.format)
|
87
|
+
end
|
88
|
+
|
89
|
+
def addresses
|
90
|
+
radd = Rudy::AWS::EC2::Addresses.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
91
|
+
addresses = radd.list || []
|
92
|
+
|
93
|
+
addresses.each do |address|
|
94
|
+
puts @@global.verbose > 0 ? address.inspect : address.dump(@@global.format)
|
95
|
+
end
|
96
|
+
|
97
|
+
puts "No Addresses" if addresses.empty?
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end; end
|
104
|
+
end; end
|
105
|
+
|
@@ -0,0 +1,191 @@
|
|
1
|
+
|
2
|
+
module Rudy; module CLI;
|
3
|
+
module AWS; module EC2;
|
4
|
+
|
5
|
+
class Candy < Rudy::CLI::CommandBase
|
6
|
+
|
7
|
+
def status_valid?
|
8
|
+
avail = Rudy::Utils.service_available?('status.aws.amazon.com', 80, 5)
|
9
|
+
raise ServiceUnavailable, 'status.aws.amazon.com' unless @@global.offline || avail
|
10
|
+
true
|
11
|
+
end
|
12
|
+
def status
|
13
|
+
url = 'http://status.aws.amazon.com/rss/EC2.rss'
|
14
|
+
|
15
|
+
if (@@global.region || '').to_s.strip.match(/\Aeu/)
|
16
|
+
url = 'http://status.aws.amazon.com/rss/EC2EU.rss'
|
17
|
+
end
|
18
|
+
|
19
|
+
# TODO: Move to Rudy::AWS
|
20
|
+
ec2 = Rudy::Utils::RSSReader.run(url) || {}
|
21
|
+
|
22
|
+
# TODO: Create Storable object
|
23
|
+
if @@global.format == 'yaml'
|
24
|
+
puts ec2.to_yaml
|
25
|
+
elsif @@global.format == 'json'
|
26
|
+
require 'json'
|
27
|
+
puts ec2.to_json
|
28
|
+
else
|
29
|
+
puts "#{ec2[:title]}"
|
30
|
+
puts "Updated: #{ec2[:pubdate]}"
|
31
|
+
(ec2[:items] || []).each do |i|
|
32
|
+
puts
|
33
|
+
puts '%s' % i[:title]
|
34
|
+
puts ' %s: %s' % [i[:pubdate], i[:description]]
|
35
|
+
end
|
36
|
+
if ec2.empty? || ec2[:items].empty?
|
37
|
+
puts "No announcements"
|
38
|
+
return
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
def ssh_valid?
|
47
|
+
if @@global.pkey
|
48
|
+
raise "Cannot find file #{@@global.pkey}" unless File.exists?(@@global.pkey)
|
49
|
+
raise "Insecure permissions for #{@@global.pkey}" unless (File.stat(@@global.pkey).mode & 600) == 0
|
50
|
+
end
|
51
|
+
if @option.group
|
52
|
+
rgroup = Rudy::AWS::EC2::Groups.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
53
|
+
raise "Cannot supply group and instance ID" if @option.instid
|
54
|
+
raise "Group #{@option.group} does not exist" unless rgroup.exists?(@option.group)
|
55
|
+
end
|
56
|
+
if @option.instid && !Rudy::Utils.is_id?(:instance, @option.instid)
|
57
|
+
raise "#{@option.instid} is not an instance ID"
|
58
|
+
end
|
59
|
+
true
|
60
|
+
end
|
61
|
+
def ssh
|
62
|
+
opts = {}
|
63
|
+
opts[:group] = @option.group if @option.group
|
64
|
+
opts[:group] = :any if @option.all
|
65
|
+
opts[:id] = @option.instid if @option.instid
|
66
|
+
|
67
|
+
# Options to be sent to Rye::Box
|
68
|
+
ssh_opts = { :user => @global.user || Rudy.sysinfo.user, :debug => nil }
|
69
|
+
if @@global.pkey
|
70
|
+
raise "Cannot find file #{@@global.pkey}" unless File.exists?(@@global.pkey)
|
71
|
+
raise InsecureKeyPermissions, @@global.pkey unless File.stat(@@global.pkey).mode == 33152
|
72
|
+
ssh_opts[:keys] = @@global.pkey
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# The user specified a command to run. We won't create an interactive
|
77
|
+
# session so we need to prepare the command and its arguments
|
78
|
+
if @argv.first
|
79
|
+
command, command_args = @argv.shift, @argv || []
|
80
|
+
puts "#{command} #{command_args.join(' ')}" if @@global.verbose > 1
|
81
|
+
|
82
|
+
# otherwise, we'll open an ssh session or print command
|
83
|
+
else
|
84
|
+
command, command_args = :interactive_ssh, @option.print.nil?
|
85
|
+
end
|
86
|
+
|
87
|
+
checked = false
|
88
|
+
rudy = Rudy::AWS::EC2::Instances.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
89
|
+
lt = rudy.list_group(opts[:group], :running, opts[:id]) do |inst|
|
90
|
+
|
91
|
+
# Print header
|
92
|
+
if @@global.quiet
|
93
|
+
print "You are #{ssh_opts[:user].bright}. " if !checked # only the 1st
|
94
|
+
else
|
95
|
+
print "Connecting #{ssh_opts[:user].bright}@#{inst.dns_public} "
|
96
|
+
puts "(#{inst.awsid}, groups: #{inst.groups.join(', ')})"
|
97
|
+
end
|
98
|
+
|
99
|
+
# Make sure we want to run this command on all instances
|
100
|
+
if !checked && command != :interactive_ssh
|
101
|
+
execute_check(:medium) if ssh_opts[:user] == "root"
|
102
|
+
checked = true
|
103
|
+
end
|
104
|
+
|
105
|
+
# Open the connection and run the command
|
106
|
+
rbox = Rye::Box.new(inst.dns_public, ssh_opts)
|
107
|
+
ret = rbox.send(command, command_args)
|
108
|
+
puts ret unless command == :interactive_ssh
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def copy_valid?
|
113
|
+
raise "You must supply a source and a target. See rudy-ec2 #{@alias} -h" unless @argv.size >= 2
|
114
|
+
raise "You cannot download and upload at the same time" if @option.download && @alias == 'upload'
|
115
|
+
raise "You cannot download and upload at the same time" if @option.upload && @alias == 'download'
|
116
|
+
true
|
117
|
+
end
|
118
|
+
def copy
|
119
|
+
|
120
|
+
opts = {}
|
121
|
+
opts[:group] = @option.group if @option.group
|
122
|
+
opts[:group] = :any if @option.all
|
123
|
+
|
124
|
+
opts[:id] = @argv.shift if Rudy::Utils.is_id?(:instance, @argv.first)
|
125
|
+
opts[:id] &&= [opts[:id]].flatten
|
126
|
+
|
127
|
+
# Options to be sent to Net::SSH
|
128
|
+
ssh_opts = { :user => @global.user || Rudy.sysinfo.user, :debug => nil }
|
129
|
+
if @@global.pkey
|
130
|
+
raise "Cannot find file #{@@global.pkey}" unless File.exists?(@@global.pkey)
|
131
|
+
raise InsecureKeyPermissions, @@global.pkey unless File.stat(@@global.pkey).mode == 33152
|
132
|
+
ssh_opts[:keys] = @@global.pkey
|
133
|
+
end
|
134
|
+
|
135
|
+
opts[:paths] = @argv
|
136
|
+
opts[:dest] = opts[:paths].pop
|
137
|
+
|
138
|
+
opts[:task] = :download if %w(dl download).member?(@alias) || @option.download
|
139
|
+
opts[:task] = :upload if %w(ul upload).member?(@alias)
|
140
|
+
opts[:task] ||= :upload
|
141
|
+
opts[:user] = @global.user || Rudy.sysinfo.user
|
142
|
+
|
143
|
+
|
144
|
+
# Options to be sent to Rye::Box
|
145
|
+
info = @@global.quiet ? nil : STDERR
|
146
|
+
ssh_opts = { :user => @global.user || Rudy.sysinfo.user, :info => info }
|
147
|
+
if @@global.pkey
|
148
|
+
raise "Cannot find file #{@@global.pkey}" unless File.exists?(@@global.pkey)
|
149
|
+
raise InsecureKeyPermissions, @@global.pkey unless File.stat(@@global.pkey).mode == 33152
|
150
|
+
ssh_opts[:keys] = @@global.pkey
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
checked = false
|
155
|
+
rudy = Rudy::AWS::EC2::Instances.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
156
|
+
lt = rudy.list_group(opts[:group], :running, opts[:id]) do |inst|
|
157
|
+
|
158
|
+
if @option.print
|
159
|
+
Rudy::Utils.scp_command inst.dns_public, @@global.pkey, opts[:user], opts[:paths], opts[:dest], (opts[:task] == :download), false, @option.print
|
160
|
+
next
|
161
|
+
end
|
162
|
+
|
163
|
+
# Print header
|
164
|
+
if @@global.quiet
|
165
|
+
print "You are #{ssh_opts[:user].bright}. " if !checked # only the 1st
|
166
|
+
else
|
167
|
+
print "Connecting #{ssh_opts[:user].bright}@#{inst.dns_public} "
|
168
|
+
puts "(#{inst.awsid}, groups: #{inst.groups.join(', ')})"
|
169
|
+
end
|
170
|
+
|
171
|
+
# Make sure we want to run this command on all instances
|
172
|
+
if !checked
|
173
|
+
#execute_check(:medium) if opts[:user] == "root"
|
174
|
+
checked = true
|
175
|
+
end
|
176
|
+
|
177
|
+
# Open the connection and run the command
|
178
|
+
rbox = Rye::Box.new(inst.dns_public, ssh_opts)
|
179
|
+
rbox.send(opts[:task], opts[:paths], opts[:dest])
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
|
185
|
+
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
end; end
|
191
|
+
end; end
|
@@ -0,0 +1,118 @@
|
|
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
|
+
execute_action {
|
18
|
+
@rgroups.create(@argv.name, @option.description, opts[:addresses], opts[:ports], opts[:protocols])
|
19
|
+
}
|
20
|
+
@rgroups.list(@argv.name) do |group|
|
21
|
+
puts @@global.verbose > 0 ? group.inspect : group.dump(@@global.format)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def destroy_groups_valid?
|
27
|
+
@rgroups = Rudy::AWS::EC2::Groups.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
28
|
+
raise Drydock::ArgError.new('group name', @alias) unless @argv.name
|
29
|
+
raise "Group #{@argv.name} does not exist" unless @rgroups.exists?(@argv.name)
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
def destroy_groups
|
34
|
+
puts "Destroying group: #{@argv.name}"
|
35
|
+
execute_check(:medium)
|
36
|
+
execute_action { @rgroups.destroy(@argv.name) }
|
37
|
+
@argv.clear # so groups will print all other groups
|
38
|
+
groups
|
39
|
+
end
|
40
|
+
|
41
|
+
def revoke_groups_valid?; modify_group_valid?; end
|
42
|
+
def revoke_groups; modify_group(:revoke); end
|
43
|
+
|
44
|
+
def authorize_groups_valid?; modify_group_valid?; end
|
45
|
+
def authorize_groups; modify_group(:authorize); end
|
46
|
+
|
47
|
+
def groups
|
48
|
+
opts = {}
|
49
|
+
name = @option.all ? nil : @argv.name
|
50
|
+
rgroups = Rudy::AWS::EC2::Groups.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
51
|
+
rgroups.list(name).each do |group|
|
52
|
+
puts @@global.verbose > 0 ? group.inspect : group.dump(@@global.format)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def modify_group_valid?
|
59
|
+
if @option.owner == 'self'
|
60
|
+
raise "AWS_ACCOUNT_NUMBER not set" unless @@global.accountnum
|
61
|
+
@option.owner = @@global.accountnum
|
62
|
+
end
|
63
|
+
|
64
|
+
if (@option.addresses || @option.ports) && (@option.group || @option.owner)
|
65
|
+
raise Drydock::OptError.new('', @alias, "Cannot mix group and network authorization")
|
66
|
+
end
|
67
|
+
if @option.owner && !@option.group
|
68
|
+
raise Drydock::OptError.new('', @alias, "Must provide -g with -o")
|
69
|
+
end
|
70
|
+
|
71
|
+
raise Drydock::ArgError.new('group name', @alias) unless @argv.name
|
72
|
+
@groups = Rudy::AWS::EC2::Groups.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
73
|
+
end
|
74
|
+
|
75
|
+
def modify_group(action)
|
76
|
+
opts = check_options
|
77
|
+
if (@option.group || @option.owner)
|
78
|
+
g = [opts[:owner], opts[:group]].join(':')
|
79
|
+
puts "#{action.to_s.capitalize} access to #{@argv.name.bright} from #{g.bright}"
|
80
|
+
else
|
81
|
+
print "#{action.to_s.capitalize} access to #{@argv.name.bright}"
|
82
|
+
puts " from #{opts[:addresses].join(', ').bright}"
|
83
|
+
print "on #{opts[:protocols].join(', ').bright} "
|
84
|
+
puts "ports: #{opts[:ports].map { |p| "#{p.join(' to ').bright}" }.join(', ')}"
|
85
|
+
end
|
86
|
+
rgroups = Rudy::AWS::EC2::Groups.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
87
|
+
execute_check(:medium)
|
88
|
+
execute_action {
|
89
|
+
if (@option.group || @option.owner)
|
90
|
+
rgroups.send("#{action.to_s}_group", @argv.name, opts[:group], opts[:owner])
|
91
|
+
else
|
92
|
+
rgroups.send(action, @argv.name, opts[:addresses], opts[:ports], opts[:protocols])
|
93
|
+
end
|
94
|
+
}
|
95
|
+
groups # prints on the modified group b/c of @argv.name
|
96
|
+
end
|
97
|
+
|
98
|
+
def check_options
|
99
|
+
opts = {}
|
100
|
+
[:addresses, :protocols, :owner, :group, :ports].each do |opt|
|
101
|
+
opts[opt] = @option.send(opt) if @option.respond_to?(opt)
|
102
|
+
end
|
103
|
+
unless @option.group || @option.owner
|
104
|
+
opts[:ports].collect! { |port| port.split(/[:-]/) } if opts[:ports]
|
105
|
+
opts[:ports] ||= [[22,22],[80,80],[443,443]]
|
106
|
+
opts[:addresses] ||= [Rudy::Utils::external_ip_address]
|
107
|
+
opts[:protocols] ||= [:tcp]
|
108
|
+
else
|
109
|
+
opts[:owner] ||= @@global.accountnum
|
110
|
+
end
|
111
|
+
opts
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
end; end
|
118
|
+
end; end
|
@@ -0,0 +1,185 @@
|
|
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[:id] = @option.instid if @option.instid
|
42
|
+
##
|
43
|
+
## puts "This will do the following:"
|
44
|
+
## puts "- Clear bash history"
|
45
|
+
## # NOTE: We can't delete the host keys here. Otherwise we can't create the image.
|
46
|
+
## #puts "- Delete host SSH keys (this is permanent!)"
|
47
|
+
## puts ""
|
48
|
+
##
|
49
|
+
## ## TODO:
|
50
|
+
## ## ~/.rudy, /etc/motd, history -c, /etc/hosts, /var/log/rudy*
|
51
|
+
##
|
52
|
+
## execute_check(:medium)
|
53
|
+
##
|
54
|
+
##
|
55
|
+
## # Options to be sent to Net::SSH
|
56
|
+
## ssh_opts = { :user => @global.user || Rudy.sysinfo.user, :debug => STDERR }
|
57
|
+
## if @@global.pkey
|
58
|
+
## raise "Cannot find file #{@@global.pkey}" unless File.exists?(@@global.pkey)
|
59
|
+
## raise InsecureKeyPermissions, @@global.pkey unless File.stat(@@global.pkey).mode == 33152
|
60
|
+
## ssh_opts[:keys] = @@global.pkey
|
61
|
+
## end
|
62
|
+
##
|
63
|
+
##
|
64
|
+
## rudy = Rudy::AWS::EC2::Instances.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
65
|
+
## lt = rudy.list_group(nil, :running, opts[:id]) do |inst|
|
66
|
+
##
|
67
|
+
## puts "Preparing #{inst.dns_public}..."
|
68
|
+
##
|
69
|
+
## # Open the connection and run the command
|
70
|
+
## rbox = Rye::Box.new(inst.dns_public, ssh_opts)
|
71
|
+
##
|
72
|
+
## # We need to explicitly add the rm command for rbox so we
|
73
|
+
## # can delete the SSH host keys. This is will force the instance
|
74
|
+
## # to re-create it's SSH keys on first boot.
|
75
|
+
## def rbox.rm(*args); cmd('rm', args); end
|
76
|
+
## p ret = rbox.history(:c)
|
77
|
+
## p ret.exit_code
|
78
|
+
## p ret.stderr
|
79
|
+
## p ret.stdout
|
80
|
+
##
|
81
|
+
## end
|
82
|
+
##
|
83
|
+
## puts "done"
|
84
|
+
##end
|
85
|
+
|
86
|
+
def create_images_valid?
|
87
|
+
raise "No account number" unless @@global.accountnum
|
88
|
+
raise "No Amazon cert-***.pem" unless @@global.cert
|
89
|
+
raise "No Amazon pk-***.pem" unless @@global.privatekey
|
90
|
+
raise "You must supply a root keypair path" unless @@global.pkey
|
91
|
+
|
92
|
+
@rinst = Rudy::AWS::EC2::Instances.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
93
|
+
@rimages = Rudy::AWS::EC2::Images.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
94
|
+
@s3 = Rudy::AWS::S3.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
95
|
+
raise "No instances" unless @rinst.any?
|
96
|
+
raise "You must supply an S3 bucket name. See: 'rudy-s3 buckets'" unless @option.bucket
|
97
|
+
raise "You must supply an image name" unless @option.name
|
98
|
+
raise "The bucket '#{@option.bucket}' does not exist" unless @s3.bucket_exists?(@option.bucket)
|
99
|
+
true
|
100
|
+
end
|
101
|
+
|
102
|
+
def create_images
|
103
|
+
opts = {}
|
104
|
+
opts[:id] = @option.instid if @option.instid
|
105
|
+
|
106
|
+
@@global.user = 'root'
|
107
|
+
|
108
|
+
puts "You may want to run rudy-ec2 #{@alias} --prepare first".bright
|
109
|
+
puts "NOTE 1: This process is currently Linux-only"
|
110
|
+
puts "NOTE 2: If you plan to create a public machine image, there are "
|
111
|
+
puts "additional steps to take to remove any sensitive information"
|
112
|
+
puts "before creating the image. See:"
|
113
|
+
puts "http://docs.amazonwebservices.com/AWSEC2/latest/DeveloperGuide/AESDG-chapter-sharingamis.html"
|
114
|
+
exit unless Annoy.pose_question(" Continue?\a ", /yes|y|ya|sure|you bet!/i, STDERR)
|
115
|
+
|
116
|
+
# Options to be sent to Net::SSH
|
117
|
+
ssh_opts = { :user => @@global.user || Rudy.sysinfo.user, :debug => nil }
|
118
|
+
if @@global.pkey
|
119
|
+
raise "Cannot find file #{@@global.pkey}" unless File.exists?(@@global.pkey)
|
120
|
+
raise InsecureKeyPermissions, @@global.pkey unless File.stat(@@global.pkey).mode == 33152
|
121
|
+
ssh_opts[:keys] = @@global.pkey
|
122
|
+
end
|
123
|
+
|
124
|
+
lt = @rinst.list_group(nil, :running, opts[:id]) do |inst|
|
125
|
+
|
126
|
+
puts inst.to_s
|
127
|
+
|
128
|
+
# Open the connection and run the command
|
129
|
+
rbox = Rye::Box.new(inst.dns_public, ssh_opts)
|
130
|
+
def rbox.bundle_vol(*args); cmd('ec2-bundle-vol', args); end
|
131
|
+
def rbox.upload_vol(*args); cmd('ec2-upload-bundle', args); end
|
132
|
+
|
133
|
+
rbox.upload(@@global.cert, @@global.privatekey, "/mnt")
|
134
|
+
rbox.touch("/root/firstrun")
|
135
|
+
|
136
|
+
## TODO:
|
137
|
+
## We have to delete the host keys just before we run the bundle command.
|
138
|
+
## The problem is that if we lose the connection we won't be able to connect
|
139
|
+
## to the instance again. A better solution is to add the keys to the ignore
|
140
|
+
## list for the bundle command.
|
141
|
+
##ret = rbox.rm('/etc/ssh/ssh_host_*_key*')
|
142
|
+
|
143
|
+
puts "Starting bundling process..."
|
144
|
+
|
145
|
+
pkeyfile = File.basename(@@global.privatekey)
|
146
|
+
certfile = File.basename(@@global.cert)
|
147
|
+
|
148
|
+
rbox.bundle_vol(:r, "i386", :p, @option.name, :k, "/mnt/#{pkeyfile}", :c, "/mnt/#{certfile}", :u, @@global.accountnum)
|
149
|
+
rbox.upload_vol(:b, @option.bucket, :m, "/tmp/#{@option.name}.manifest.xml", :a, @@global.accesskey, :s, @@global.secretkey)
|
150
|
+
|
151
|
+
@rimages.register("#{@option.bucket}/#{@option.name}.manifest.xml")
|
152
|
+
|
153
|
+
break
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
def destroy_images_valid?
|
159
|
+
unless @argv.ami && Rudy::Utils.is_id?(:image, @argv.ami)
|
160
|
+
raise "Must supply an AMI ID (ami-XXXXXXX)"
|
161
|
+
end
|
162
|
+
@rimages = Rudy::AWS::EC2::Images.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
163
|
+
end
|
164
|
+
def destroy_images
|
165
|
+
puts @rimages.deregister(@argv.ami) ? "Done" : "Unknown error"
|
166
|
+
end
|
167
|
+
|
168
|
+
def register_images_valid?
|
169
|
+
unless @argv.first
|
170
|
+
raise "Must supply a valid manifest path (bucket/ami-name.manifest.xml)"
|
171
|
+
end
|
172
|
+
@rimages = Rudy::AWS::EC2::Images.new(@@global.accesskey, @@global.secretkey, @@global.region)
|
173
|
+
end
|
174
|
+
def register_images
|
175
|
+
puts @rimages.register(@argv.first)
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
end; end
|
183
|
+
end; end
|
184
|
+
|
185
|
+
|