solutious-rudy 0.4.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.
- data/CHANGES.txt +75 -0
- data/LICENSE.txt +19 -0
- data/README.rdoc +36 -0
- data/Rakefile +68 -0
- data/bin/rudy +175 -0
- data/bin/rudy-ec2 +108 -0
- data/lib/aws_sdb.rb +3 -0
- data/lib/aws_sdb/error.rb +42 -0
- data/lib/aws_sdb/service.rb +215 -0
- data/lib/console.rb +385 -0
- data/lib/rudy.rb +210 -0
- data/lib/rudy/aws.rb +68 -0
- data/lib/rudy/aws/ec2.rb +304 -0
- data/lib/rudy/aws/s3.rb +3 -0
- data/lib/rudy/aws/simpledb.rb +53 -0
- data/lib/rudy/command/addresses.rb +46 -0
- data/lib/rudy/command/backups.rb +175 -0
- data/lib/rudy/command/base.rb +839 -0
- data/lib/rudy/command/config.rb +77 -0
- data/lib/rudy/command/deploy.rb +12 -0
- data/lib/rudy/command/disks.rb +213 -0
- data/lib/rudy/command/environment.rb +74 -0
- data/lib/rudy/command/groups.rb +61 -0
- data/lib/rudy/command/images.rb +99 -0
- data/lib/rudy/command/instances.rb +85 -0
- data/lib/rudy/command/machines.rb +170 -0
- data/lib/rudy/command/metadata.rb +41 -0
- data/lib/rudy/command/release.rb +174 -0
- data/lib/rudy/command/volumes.rb +66 -0
- data/lib/rudy/config.rb +93 -0
- data/lib/rudy/metadata.rb +26 -0
- data/lib/rudy/metadata/backup.rb +160 -0
- data/lib/rudy/metadata/disk.rb +138 -0
- data/lib/rudy/scm/svn.rb +68 -0
- data/lib/rudy/utils.rb +64 -0
- data/lib/storable.rb +280 -0
- data/lib/tryouts.rb +40 -0
- data/rudy.gemspec +76 -0
- data/support/mailtest +40 -0
- data/support/rudy-ec2-startup +200 -0
- data/tryouts/console_tryout.rb +91 -0
- metadata +188 -0
data/lib/rudy.rb
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# No Ruby 1.9.1 support. Only 1.8.x for now :[
|
4
|
+
unless RUBY_VERSION < "1.9"
|
5
|
+
puts "Sorry! We're using the right_aws gem and it doesn't support Ruby 1.9 (md5 error)."
|
6
|
+
exit 1
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
begin
|
11
|
+
require 'digest/md5'
|
12
|
+
require 'right_aws'
|
13
|
+
require 'stringio'
|
14
|
+
require 'ostruct'
|
15
|
+
require 'yaml'
|
16
|
+
require 'socket'
|
17
|
+
require 'tempfile'
|
18
|
+
|
19
|
+
require 'console'
|
20
|
+
require 'storable'
|
21
|
+
|
22
|
+
require 'net/ssh'
|
23
|
+
require 'net/ssh/gateway'
|
24
|
+
require 'net/ssh/multi'
|
25
|
+
require 'net/scp'
|
26
|
+
|
27
|
+
rescue LoadError => ex
|
28
|
+
puts "Problem requiring: #{ex.message}"
|
29
|
+
exit 1
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
module Rudy #:nodoc:
|
35
|
+
RUDY_DOMAIN = "rudy_state"
|
36
|
+
RUDY_DELIM = '-'
|
37
|
+
|
38
|
+
RUDY_CONFIG_DIR = File.join(ENV['HOME'] || ENV['USERPROFILE'], '.rudy')
|
39
|
+
RUDY_CONFIG_FILE = File.join(RUDY_CONFIG_DIR, 'config')
|
40
|
+
|
41
|
+
DEFAULT_REGION = 'us-east-1'
|
42
|
+
DEFAULT_ZONE = 'us-east-1b'
|
43
|
+
DEFAULT_ENVIRONMENT = 'stage'
|
44
|
+
DEFAULT_ROLE = 'app'
|
45
|
+
DEFAULT_POSITION = '01'
|
46
|
+
|
47
|
+
DEFAULT_USER = 'rudy'
|
48
|
+
|
49
|
+
SUPPORTED_SCM_NAMES = [:svn, :git]
|
50
|
+
|
51
|
+
module VERSION #:nodoc:
|
52
|
+
MAJOR = 0.freeze unless defined? MAJOR
|
53
|
+
MINOR = 4.freeze unless defined? MINOR
|
54
|
+
TINY = 0.freeze unless defined? TINY
|
55
|
+
def self.to_s
|
56
|
+
[MAJOR, MINOR, TINY].join('.')
|
57
|
+
end
|
58
|
+
def self.to_f
|
59
|
+
self.to_s.to_f
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Determine if we're running directly on EC2 or
|
64
|
+
# "some other machine". We do this by checking if
|
65
|
+
# the file /etc/ec2/instance-id exists. This
|
66
|
+
# file is written by /etc/init.d/rudy-ec2-startup.
|
67
|
+
# NOTE: Is there a way to know definitively that this is EC2?
|
68
|
+
# We could make a request to the metadata IP addresses.
|
69
|
+
def self.in_situ?
|
70
|
+
File.exists?('/etc/ec2/instance-id')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
require 'rudy/aws'
|
75
|
+
require 'rudy/config'
|
76
|
+
require 'rudy/metadata'
|
77
|
+
require 'rudy/utils'
|
78
|
+
require 'rudy/command/base'
|
79
|
+
|
80
|
+
# Require Command, MetaData, and SCM classes
|
81
|
+
begin
|
82
|
+
# TODO: Use autoload
|
83
|
+
Dir.glob(File.join(RUDY_LIB, 'rudy', '{command,metadata,scm}', "*.rb")).each do |path|
|
84
|
+
require path
|
85
|
+
end
|
86
|
+
rescue LoadError => ex
|
87
|
+
puts "Error: #{ex.message}"
|
88
|
+
exit 1
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# Capture STDOUT or STDERR to prevent it from being printed.
|
93
|
+
#
|
94
|
+
# capture(:stdout) do
|
95
|
+
# ...
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
def capture(stream)
|
99
|
+
#raise "We can only capture STDOUT or STDERR" unless stream == :stdout || stream == :stderr
|
100
|
+
|
101
|
+
# I'm using this to trap the annoying right_aws "peer certificate" warning.
|
102
|
+
# TODO: discover source of annoying right_aws warning and give it a hiding.
|
103
|
+
begin
|
104
|
+
stream = stream.to_s
|
105
|
+
eval "$#{stream} = StringIO.new"
|
106
|
+
yield
|
107
|
+
result = eval("$#{stream}").read
|
108
|
+
ensure
|
109
|
+
eval("$#{stream} = #{stream.upcase}")
|
110
|
+
end
|
111
|
+
|
112
|
+
result
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def write_to_file(filename, content, type)
|
117
|
+
type = (type == :append) ? 'a' : 'w'
|
118
|
+
f = File.open(filename,type)
|
119
|
+
f.puts content
|
120
|
+
f.close
|
121
|
+
end
|
122
|
+
|
123
|
+
def are_you_sure?(len=3)
|
124
|
+
if Drydock.debug?
|
125
|
+
puts 'DEBUG: skipping "are you sure" check'
|
126
|
+
return true
|
127
|
+
end
|
128
|
+
|
129
|
+
if STDIN.tty? # Only ask a question if there's a human
|
130
|
+
challenge = strand len
|
131
|
+
STDOUT.print "Are you sure? To continue type \"#{challenge}\": "
|
132
|
+
STDOUT.flush
|
133
|
+
if ((STDIN.gets || "").gsub(/["']/, '') =~ /^#{challenge}$/)
|
134
|
+
true
|
135
|
+
else
|
136
|
+
puts "Nothing changed"
|
137
|
+
exit 0
|
138
|
+
end
|
139
|
+
else
|
140
|
+
true
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
# Generates a string of random alphanumeric characters
|
146
|
+
# These are used as IDs throughout the system
|
147
|
+
def strand( len=8, safe=true )
|
148
|
+
chars = ("a".."z").to_a + ("0".."9").to_a
|
149
|
+
chars = [("a".."h").to_a, "j", "k", "m", "n", ("p".."z").to_a, ("2".."9").to_a].flatten if safe
|
150
|
+
newpass = ""
|
151
|
+
1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
|
152
|
+
newpass
|
153
|
+
end
|
154
|
+
|
155
|
+
def sh(command, chdir=false, verbose=false)
|
156
|
+
prevdir = Dir.pwd
|
157
|
+
Dir.chdir chdir if chdir
|
158
|
+
puts command if verbose
|
159
|
+
system(command)
|
160
|
+
Dir.chdir prevdir if chdir
|
161
|
+
end
|
162
|
+
|
163
|
+
def ssh_command(host, keypair, user, command=false, printonly=false, verbose=false)
|
164
|
+
#puts "CONNECTING TO #{host}..."
|
165
|
+
cmd = "ssh -i #{keypair} #{user}@#{host} "
|
166
|
+
cmd += " '#{command}'" if command
|
167
|
+
puts cmd if verbose
|
168
|
+
return cmd if printonly
|
169
|
+
# backticks returns STDOUT
|
170
|
+
# exec replaces current process (it's just like running ssh)
|
171
|
+
# -- UPDATE -- Some problem with exec. "Operation not supported"
|
172
|
+
# using system (http://www.mail-archive.com/mongrel-users@rubyforge.org/msg02018.html)
|
173
|
+
(command) ? `#{cmd}` : Kernel.system(cmd)
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
def scp_command(host, keypair, user, paths, to_path, to_local=false, verbose=false, printonly=false)
|
178
|
+
|
179
|
+
paths = [paths] unless paths.is_a?(Array)
|
180
|
+
from_paths = ""
|
181
|
+
if to_local
|
182
|
+
paths.each do |path|
|
183
|
+
from_paths << "#{user}@#{host}:#{path} "
|
184
|
+
end
|
185
|
+
puts "Copying FROM remote TO this machine", $/
|
186
|
+
|
187
|
+
else
|
188
|
+
to_path = "#{user}@#{host}:#{to_path}"
|
189
|
+
from_paths = paths.join(' ')
|
190
|
+
puts "Copying FROM this machine TO remote", $/
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
cmd = "scp -r -i #{keypair} #{from_paths} #{to_path}"
|
195
|
+
|
196
|
+
puts cmd if verbose
|
197
|
+
printonly ? (puts cmd) : system(cmd)
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
# Returns +str+ with the average leading indentation removed.
|
202
|
+
# Useful for keeping inline codeblocks spaced with code.
|
203
|
+
def without_indent(str)
|
204
|
+
lines = str.split($/)
|
205
|
+
lspaces = (lines.inject(0) {|total,line| total += (line.scan(/^\s+/).first || '').size } / lines.size) + 1
|
206
|
+
lines.collect { |line| line.gsub(/^\s{#{lspaces}}/, '') }.join($/)
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
|
data/lib/rudy/aws.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
module Rudy
|
6
|
+
module AWS
|
7
|
+
|
8
|
+
module ObjectBase
|
9
|
+
attr_accessor :aws
|
10
|
+
def initialize(aws_connection)
|
11
|
+
@aws = aws_connection
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class EC2
|
16
|
+
@@logger = StringIO.new
|
17
|
+
|
18
|
+
attr_reader :instances
|
19
|
+
attr_reader :images
|
20
|
+
attr_reader :addresses
|
21
|
+
attr_reader :groups
|
22
|
+
attr_reader :volumes
|
23
|
+
attr_reader :snapshots
|
24
|
+
attr_reader :aws
|
25
|
+
|
26
|
+
def initialize(access_key, secret_key)
|
27
|
+
@aws = RightAws::Ec2.new(access_key, secret_key, {:logger => Logger.new(@@logger)})
|
28
|
+
@instances = Rudy::AWS::EC2::Instances.new(@aws)
|
29
|
+
@images = Rudy::AWS::EC2::Images.new(@aws)
|
30
|
+
@groups = Rudy::AWS::EC2::Groups.new(@aws)
|
31
|
+
@addresses = Rudy::AWS::EC2::Addresses.new(@aws)
|
32
|
+
@snapshots = Rudy::AWS::EC2::Snapshots.new(@aws)
|
33
|
+
@volumes = Rudy::AWS::EC2::Volumes.new(@aws)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
class S3
|
39
|
+
@@logger = StringIO.new
|
40
|
+
|
41
|
+
attr_reader :aws
|
42
|
+
|
43
|
+
def initialize(access_key, secret_key)
|
44
|
+
@aws = RightAws::S3.new(access_key, secret_key, {:logger => Logger.new(@@logger)})
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class SimpleDB
|
49
|
+
@@logger = StringIO.new
|
50
|
+
|
51
|
+
attr_reader :domains
|
52
|
+
attr_reader :aws
|
53
|
+
|
54
|
+
def initialize(access_key, secret_key)
|
55
|
+
@aws = RightAws::SdbInterface.new(access_key, secret_key, {:logger => Logger.new(@@logger)})
|
56
|
+
@aws2 = AwsSdb::Service.new(:access_key_id => access_key, :secret_access_key => secret_key, :logger => Logger.new(@@logger))
|
57
|
+
@domains = Rudy::AWS::SimpleDB::Domains.new(@aws)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
require 'rudy/aws/simpledb'
|
63
|
+
require 'rudy/aws/ec2'
|
64
|
+
require 'rudy/aws/s3'
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
data/lib/rudy/aws/ec2.rb
ADDED
@@ -0,0 +1,304 @@
|
|
1
|
+
|
2
|
+
module Rudy::AWS
|
3
|
+
|
4
|
+
class EC2
|
5
|
+
class UserData
|
6
|
+
|
7
|
+
end
|
8
|
+
|
9
|
+
class Images
|
10
|
+
include Rudy::AWS::ObjectBase
|
11
|
+
|
12
|
+
# Returns an array of hashes:
|
13
|
+
# {:aws_architecture=>"i386", :aws_owner=>"105148267242", :aws_id=>"ami-6fe40dd5",
|
14
|
+
# :aws_image_type=>"machine", :aws_location=>"bucket-name/your-image.manifest.xml",
|
15
|
+
# :aws_kernel_id=>"aki-a71cf9ce", :aws_state=>"available", :aws_ramdisk_id=>"ari-a51cf9cc",
|
16
|
+
# :aws_is_public=>false}
|
17
|
+
def list
|
18
|
+
@aws.describe_images_by_owner('self') || []
|
19
|
+
end
|
20
|
+
|
21
|
+
# +id+ AMI ID to deregister (ami-XXXXXXX)
|
22
|
+
# Returns true when successful. Otherwise throws an exception.
|
23
|
+
def deregister(id)
|
24
|
+
@aws.deregister_image(id)
|
25
|
+
end
|
26
|
+
|
27
|
+
# +path+ the S3 path to the manifest (bucket/file.manifest.xml)
|
28
|
+
# Returns the AMI ID when successful, otherwise throws an exception.
|
29
|
+
def register(path)
|
30
|
+
@aws.register_image(path)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
class Snapshots
|
34
|
+
include Rudy::AWS::ObjectBase
|
35
|
+
|
36
|
+
def list
|
37
|
+
@aws.describe_snapshots || []
|
38
|
+
end
|
39
|
+
|
40
|
+
def create(vol_id)
|
41
|
+
@aws.create_snapshot(vol_id)
|
42
|
+
end
|
43
|
+
|
44
|
+
def destroy(snap_id)
|
45
|
+
@aws.delete_snapshot(snap_id)
|
46
|
+
end
|
47
|
+
|
48
|
+
def exists?(id)
|
49
|
+
list.each do |v|
|
50
|
+
return true if v[:aws_id] === id
|
51
|
+
end
|
52
|
+
false
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
class Volumes
|
58
|
+
include Rudy::AWS::ObjectBase
|
59
|
+
|
60
|
+
# [{:aws_device=>"/dev/sdr",
|
61
|
+
# :aws_attachment_status=>"attached",
|
62
|
+
# :snapshot_id=>nil,
|
63
|
+
# :aws_id=>"vol-6811f601",
|
64
|
+
# :aws_attached_at=>Wed Mar 11 07:06:44 UTC 2009,
|
65
|
+
# :aws_status=>"in-use",
|
66
|
+
# :aws_instance_id=>"i-0b2ab662",
|
67
|
+
# :aws_created_at=>Tue Mar 10 18:55:18 UTC 2009,
|
68
|
+
# :zone=>"us-east-1b",
|
69
|
+
# :aws_size=>10}]
|
70
|
+
def list
|
71
|
+
list = @aws.describe_volumes() || []
|
72
|
+
list.select { |v| v[:aws_status] != "deleting" }
|
73
|
+
end
|
74
|
+
|
75
|
+
def attach(inst_id, vol_id, device)
|
76
|
+
@aws.attach_volume(vol_id, inst_id, device)
|
77
|
+
end
|
78
|
+
|
79
|
+
def detach(vol_id)
|
80
|
+
@aws.detach_volume(vol_id)
|
81
|
+
end
|
82
|
+
|
83
|
+
def create(zone, size, snapshot=nil)
|
84
|
+
@aws.create_volume(snapshot, size, zone)
|
85
|
+
end
|
86
|
+
|
87
|
+
def destroy(vol_id)
|
88
|
+
@aws.delete_volume(vol_id)
|
89
|
+
end
|
90
|
+
|
91
|
+
def exists?(id)
|
92
|
+
list.each do |v|
|
93
|
+
return true if v[:aws_id] === id
|
94
|
+
end
|
95
|
+
false
|
96
|
+
end
|
97
|
+
|
98
|
+
def get(vol_id)
|
99
|
+
list = @aws.describe_volumes(vol_id) || []
|
100
|
+
list.first
|
101
|
+
end
|
102
|
+
|
103
|
+
def deleting?(vol_id)
|
104
|
+
return false unless vol_id
|
105
|
+
vol = get(vol_id)
|
106
|
+
(vol && vol[:aws_status] == "deleting")
|
107
|
+
end
|
108
|
+
|
109
|
+
def available?(vol_id)
|
110
|
+
return false unless vol_id
|
111
|
+
vol = get(vol_id)
|
112
|
+
(vol && vol[:aws_status] == "available")
|
113
|
+
end
|
114
|
+
|
115
|
+
def attached?(vol_id)
|
116
|
+
return false unless vol_id
|
117
|
+
vol = get(vol_id)
|
118
|
+
(vol && vol[:aws_status] == "in-use")
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
class Instances
|
124
|
+
include Rudy::AWS::ObjectBase
|
125
|
+
|
126
|
+
def destroy(*list)
|
127
|
+
begin
|
128
|
+
@aws.terminate_instances(list.flatten)
|
129
|
+
#rescue RightAws::AwsError => ex
|
130
|
+
# raise UnknownInstance.new
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def restart(*list)
|
135
|
+
@aws.reboot_instances(list.flatten)
|
136
|
+
end
|
137
|
+
|
138
|
+
def attached_volume?(id, device)
|
139
|
+
list = volumes(id)
|
140
|
+
list.each do |v|
|
141
|
+
return true if v[:aws_device] == device
|
142
|
+
end
|
143
|
+
false
|
144
|
+
end
|
145
|
+
|
146
|
+
def volumes(id)
|
147
|
+
list = @aws.describe_volumes() || []
|
148
|
+
list.select { |v| v[:aws_status] != "deleting" && v[:aws_instance_id] === id }
|
149
|
+
end
|
150
|
+
|
151
|
+
def device_volume(id, device)
|
152
|
+
volumes.select { |v| v[:aws_device] === device }
|
153
|
+
end
|
154
|
+
|
155
|
+
def create(ami, group, keypair_name, user_data, zone)
|
156
|
+
@aws.run_instances(ami, 1, 1, [group], keypair_name, user_data, 'public', nil, nil, nil, zone)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Creates a list of running instance IDs which are in a security group
|
160
|
+
# that matches +filter+.
|
161
|
+
# Returns a hash. The keys are instance IDs and the values are a hash
|
162
|
+
# of attributes associated to that instance.
|
163
|
+
# {:aws_state_code=>"16",
|
164
|
+
# :private_dns_name=>"domU-12-31-38-00-51-F1.compute-1.internal",
|
165
|
+
# :aws_instance_type=>"m1.small",
|
166
|
+
# :aws_reason=>"",
|
167
|
+
# :ami_launch_index=>"0",
|
168
|
+
# :aws_owner=>"207436219441",
|
169
|
+
# :aws_launch_time=>"2009-03-11T06:55:00.000Z",
|
170
|
+
# :aws_kernel_id=>"aki-a71cf9ce",
|
171
|
+
# :ssh_key_name=>"rilli-sexytime",
|
172
|
+
# :aws_reservation_id=>"r-66f5710f",
|
173
|
+
# :aws_state=>"running",
|
174
|
+
# :aws_ramdisk_id=>"ari-a51cf9cc",
|
175
|
+
# :aws_instance_id=>"i-0b2ab662",
|
176
|
+
# :aws_groups=>["rudydev-app"],
|
177
|
+
# :aws_availability_zone=>"us-east-1b",
|
178
|
+
# :aws_image_id=>"ami-daca2db3",
|
179
|
+
# :aws_product_codes=>[],
|
180
|
+
# :dns_name=>"ec2-67-202-9-30.compute-1.amazonaws.com"}
|
181
|
+
def list(filter='.')
|
182
|
+
filter = filter.to_s.downcase.tr('_|-', '.') # treat dashes, underscores as one
|
183
|
+
# Returns an array of hashes with the following keys:
|
184
|
+
# :aws_image_id, :aws_reason, :aws_state_code, :aws_owner, :aws_instance_id, :aws_reservation_id
|
185
|
+
# :aws_state, :dns_name, :ssh_key_name, :aws_groups, :private_dns_name, :aws_instance_type,
|
186
|
+
# :aws_launch_time, :aws_availability_zone :aws_kernel_id, :aws_ramdisk_id
|
187
|
+
instances = @aws.describe_instances || []
|
188
|
+
running_instances = {}
|
189
|
+
instances.each do |inst|
|
190
|
+
if inst[:aws_state] != "terminated" && (inst[:aws_groups].to_s =~ /#{filter}/)
|
191
|
+
running_instances[inst[:aws_instance_id]] = inst
|
192
|
+
end
|
193
|
+
end
|
194
|
+
running_instances
|
195
|
+
end
|
196
|
+
|
197
|
+
def get(inst_id)
|
198
|
+
# This is ridiculous. Send inst_id to describe volumes
|
199
|
+
instance = {}
|
200
|
+
list.each_pair do |id, hash|
|
201
|
+
next unless inst_id == id
|
202
|
+
instance = hash
|
203
|
+
end
|
204
|
+
instance
|
205
|
+
end
|
206
|
+
|
207
|
+
def running?(inst_id)
|
208
|
+
inst = get(inst_id)
|
209
|
+
(inst && inst[:aws_state] == "running")
|
210
|
+
end
|
211
|
+
|
212
|
+
def pending?(inst_id)
|
213
|
+
inst = get(inst_id)
|
214
|
+
(inst && inst[:aws_state] == "pending")
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
class Groups
|
219
|
+
include Rudy::AWS::ObjectBase
|
220
|
+
|
221
|
+
|
222
|
+
# +list+ is a list of security groups to look for. If it's empty, all groups
|
223
|
+
# associated to the account will be returned.
|
224
|
+
# right_aws returns an array of hashes
|
225
|
+
# :aws_group_name => "default-1",
|
226
|
+
# :aws_owner => "000000000888",
|
227
|
+
# :aws_description => "Default allowing SSH, HTTP, and HTTPS ingress",
|
228
|
+
# :aws_perms => [{:owner => "000000000888", :group => "default"},
|
229
|
+
# {:owner => "000000000888", :group => "default-1"},
|
230
|
+
# {:to_port => "-1", :protocol => "icmp", :from_port => "-1", :cidr_ips => "0.0.0.0/0"}]
|
231
|
+
# ]
|
232
|
+
def list(list=[])
|
233
|
+
glist = @aws.describe_security_groups(list) || []
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
# Create a new EC2 security group
|
238
|
+
# Returns true/false whether successful
|
239
|
+
def create(name, desc=nil)
|
240
|
+
@aws.create_security_group(name, desc || "Group #{name}")
|
241
|
+
end
|
242
|
+
|
243
|
+
# Delete an EC2 security group
|
244
|
+
# Returns true/false whether successful
|
245
|
+
def destroy(name)
|
246
|
+
@aws.delete_security_group(name)
|
247
|
+
end
|
248
|
+
|
249
|
+
# Modify an EC2 security group
|
250
|
+
# Returns true/false whether successful
|
251
|
+
def modify(name, from_port, to_port, protocol='tcp', ipa='0.0.0.0/0')
|
252
|
+
@aws.authorize_security_group_IP_ingress(name, from_port, to_port, protocol, ipa)
|
253
|
+
end
|
254
|
+
|
255
|
+
|
256
|
+
# Does the security group +name+ exist?
|
257
|
+
def exists?(name)
|
258
|
+
begin
|
259
|
+
g = list([name.to_s])
|
260
|
+
|
261
|
+
rescue RightAws::AwsError => ex
|
262
|
+
# Ignore (it raises an exception when the list contains an unknown group name)
|
263
|
+
ensure
|
264
|
+
g ||= []
|
265
|
+
end
|
266
|
+
|
267
|
+
!g.empty?
|
268
|
+
end
|
269
|
+
|
270
|
+
end
|
271
|
+
|
272
|
+
class Addresses
|
273
|
+
include Rudy::AWS::ObjectBase
|
274
|
+
|
275
|
+
# Returns and array of hashes:
|
276
|
+
# [{:instance_id=>"i-d630cbbf", :public_ip=>"75.101.1.140"},
|
277
|
+
# {:instance_id=>nil, :public_ip=>"75.101.1.141"}]
|
278
|
+
def list
|
279
|
+
@aws.describe_addresses || []
|
280
|
+
end
|
281
|
+
|
282
|
+
|
283
|
+
# Associate an elastic IP to an instance
|
284
|
+
def associate(instance, address)
|
285
|
+
@aws.associate_address(instance, address)
|
286
|
+
end
|
287
|
+
|
288
|
+
def valid?(address)
|
289
|
+
list.each do |a|
|
290
|
+
return true if a[:public_ip] == address
|
291
|
+
end
|
292
|
+
false
|
293
|
+
end
|
294
|
+
|
295
|
+
def associated?(address)
|
296
|
+
list.each do |a|
|
297
|
+
return true if a[:public_ip] == address && a[:instance_id]
|
298
|
+
end
|
299
|
+
false
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
end
|