solutious-rudy 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +19 -1
- data/README.rdoc +66 -35
- data/Rakefile +1 -0
- data/Rudyfile +97 -6
- data/bin/ird +7 -4
- data/bin/rudy +120 -212
- data/bin/rudy-ec2 +240 -0
- data/bin/rudy-s3 +76 -0
- data/bin/rudy-sdb +67 -0
- data/lib/annoy.rb +61 -18
- data/lib/console.rb +10 -5
- data/lib/rudy/aws/ec2/address.rb +76 -40
- data/lib/rudy/aws/ec2/group.rb +138 -78
- data/lib/rudy/aws/ec2/image.rb +134 -12
- data/lib/rudy/aws/ec2/instance.rb +116 -89
- data/lib/rudy/aws/ec2/keypair.rb +26 -14
- data/lib/rudy/aws/ec2/snapshot.rb +23 -12
- data/lib/rudy/aws/ec2/volume.rb +198 -202
- data/lib/rudy/aws/ec2/zone.rb +77 -0
- data/lib/rudy/aws/ec2.rb +56 -25
- data/lib/rudy/aws/s3.rb +54 -0
- data/lib/rudy/aws/sdb/error.rb +46 -0
- data/lib/rudy/aws/sdb.rb +298 -0
- data/lib/rudy/aws.rb +29 -57
- data/lib/rudy/{metadata/backup.rb → backup.rb} +8 -8
- data/lib/rudy/cli/aws/ec2/addresses.rb +105 -0
- data/lib/rudy/cli/aws/ec2/candy.rb +208 -0
- data/lib/rudy/cli/aws/ec2/groups.rb +121 -0
- data/lib/rudy/cli/aws/ec2/images.rb +196 -0
- data/lib/rudy/cli/aws/ec2/instances.rb +194 -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 +50 -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/{deploy.rb → candy.rb} +2 -6
- data/lib/rudy/cli/config.rb +25 -20
- data/lib/rudy/cli/disks.rb +18 -108
- data/lib/rudy/cli/machines.rb +94 -0
- data/lib/rudy/cli/routines.rb +47 -70
- data/lib/rudy/cli.rb +104 -89
- data/lib/rudy/config/objects.rb +5 -43
- data/lib/rudy/config.rb +8 -24
- data/lib/rudy/disks.rb +248 -0
- data/lib/rudy/global.rb +121 -0
- data/lib/rudy/huxtable.rb +232 -147
- data/lib/rudy/machines.rb +245 -0
- data/lib/rudy/metadata.rb +136 -0
- data/lib/rudy/routines/helpers/diskhelper.rb +101 -0
- data/lib/rudy/routines/helpers/scripthelper.rb +91 -0
- data/lib/rudy/routines/release.rb +27 -8
- data/lib/rudy/routines/shutdown.rb +47 -32
- data/lib/rudy/routines/startup.rb +47 -37
- data/lib/rudy/routines.rb +30 -37
- data/lib/rudy/scm/svn.rb +1 -1
- data/lib/rudy/utils.rb +262 -4
- data/lib/rudy.rb +76 -248
- data/lib/storable.rb +19 -16
- data/lib/sysinfo.rb +1 -1
- data/rudy.gemspec +88 -68
- data/support/rudy-ec2-startup +5 -5
- data/test/05_config/00_setup_test.rb +3 -7
- data/test/20_sdb/00_setup_test.rb +2 -17
- data/test/20_sdb/10_domains_test.rb +18 -16
- data/test/25_ec2/00_setup_test.rb +5 -10
- data/test/25_ec2/10_keypairs_test.rb +13 -5
- data/test/25_ec2/20_groups_test.rb +48 -56
- data/test/25_ec2/30_addresses_test.rb +13 -10
- data/test/25_ec2/40_volumes_test.rb +11 -8
- data/test/25_ec2/50_snapshots_test.rb +17 -12
- data/test/26_ec2_instances/00_setup_test.rb +3 -8
- data/test/26_ec2_instances/10_instances_test.rb +21 -19
- data/test/30_sdb_metadata/00_setup_test.rb +2 -9
- data/test/30_sdb_metadata/10_disks_test.rb +47 -37
- data/test/30_sdb_metadata/20_backups_test.rb +9 -9
- data/test/helper.rb +5 -3
- data/vendor/highline-1.5.1/CHANGELOG +222 -0
- data/vendor/highline-1.5.1/INSTALL +35 -0
- data/vendor/highline-1.5.1/LICENSE +7 -0
- data/vendor/highline-1.5.1/README +63 -0
- data/vendor/highline-1.5.1/Rakefile +82 -0
- data/vendor/highline-1.5.1/TODO +6 -0
- data/vendor/highline-1.5.1/examples/ansi_colors.rb +38 -0
- data/vendor/highline-1.5.1/examples/asking_for_arrays.rb +18 -0
- data/vendor/highline-1.5.1/examples/basic_usage.rb +75 -0
- data/vendor/highline-1.5.1/examples/color_scheme.rb +32 -0
- data/vendor/highline-1.5.1/examples/limit.rb +12 -0
- data/vendor/highline-1.5.1/examples/menus.rb +65 -0
- data/vendor/highline-1.5.1/examples/overwrite.rb +19 -0
- data/vendor/highline-1.5.1/examples/page_and_wrap.rb +322 -0
- data/vendor/highline-1.5.1/examples/password.rb +7 -0
- data/vendor/highline-1.5.1/examples/trapping_eof.rb +22 -0
- data/vendor/highline-1.5.1/examples/using_readline.rb +17 -0
- data/vendor/highline-1.5.1/lib/highline/color_scheme.rb +120 -0
- data/vendor/highline-1.5.1/lib/highline/compatibility.rb +17 -0
- data/vendor/highline-1.5.1/lib/highline/import.rb +43 -0
- data/vendor/highline-1.5.1/lib/highline/menu.rb +395 -0
- data/vendor/highline-1.5.1/lib/highline/question.rb +463 -0
- data/vendor/highline-1.5.1/lib/highline/system_extensions.rb +193 -0
- data/vendor/highline-1.5.1/lib/highline.rb +758 -0
- data/vendor/highline-1.5.1/setup.rb +1360 -0
- data/vendor/highline-1.5.1/test/tc_color_scheme.rb +56 -0
- data/vendor/highline-1.5.1/test/tc_highline.rb +823 -0
- data/vendor/highline-1.5.1/test/tc_import.rb +54 -0
- data/vendor/highline-1.5.1/test/tc_menu.rb +429 -0
- data/vendor/highline-1.5.1/test/ts_all.rb +15 -0
- metadata +81 -69
- data/lib/aws_sdb/error.rb +0 -42
- data/lib/aws_sdb/service.rb +0 -215
- data/lib/aws_sdb.rb +0 -3
- data/lib/rudy/aws/simpledb.rb +0 -71
- data/lib/rudy/cli/addresses.rb +0 -85
- data/lib/rudy/cli/backups.rb +0 -175
- data/lib/rudy/cli/domains.rb +0 -17
- data/lib/rudy/cli/groups.rb +0 -77
- data/lib/rudy/cli/images.rb +0 -111
- data/lib/rudy/cli/instances.rb +0 -142
- data/lib/rudy/cli/keypairs.rb +0 -47
- data/lib/rudy/cli/manager.rb +0 -51
- data/lib/rudy/cli/release.rb +0 -174
- data/lib/rudy/cli/volumes.rb +0 -121
- data/lib/rudy/command/addresses.rb +0 -69
- data/lib/rudy/command/backups.rb +0 -65
- data/lib/rudy/command/disks-old.rb +0 -322
- data/lib/rudy/command/disks.rb +0 -9
- data/lib/rudy/command/domains.rb +0 -34
- data/lib/rudy/command/groups.rb +0 -118
- data/lib/rudy/command/instances.rb +0 -278
- data/lib/rudy/command/keypairs.rb +0 -149
- data/lib/rudy/command/manager.rb +0 -65
- data/lib/rudy/command/volumes.rb +0 -127
- data/lib/rudy/metadata/disk.rb +0 -149
- data/lib/rudy/metadata/machine.rb +0 -34
- data/lib/rudy/routines/disk_handler.rb +0 -190
- data/lib/rudy/routines/script_runner.rb +0 -65
- data/test/50_commands/00_setup_test.rb +0 -11
- data/test/50_commands/10_keypairs_test.rb +0 -79
- data/test/50_commands/20_groups_test.rb +0 -77
- data/test/50_commands/40_volumes_test.rb +0 -55
- data/test/50_commands/50_instances_test.rb +0 -110
- data/tryouts/console_tryout.rb +0 -91
- data/tryouts/disks.rb +0 -55
- data/tryouts/nested_methods.rb +0 -36
- data/tryouts/session_tryout.rb +0 -46
@@ -0,0 +1,46 @@
|
|
1
|
+
module Rudy
|
2
|
+
module AWS
|
3
|
+
class SDB
|
4
|
+
|
5
|
+
class Error < RuntimeError ; end
|
6
|
+
|
7
|
+
class RequestError < Error
|
8
|
+
attr_reader :request_id
|
9
|
+
|
10
|
+
def initialize(message, request_id=nil)
|
11
|
+
super(message)
|
12
|
+
@request_id = request_id
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class InvalidDomainNameError < RequestError ; end
|
17
|
+
class InvalidParameterValueError < RequestError ; end
|
18
|
+
class InvalidNextTokenError < RequestError ; end
|
19
|
+
class InvalidNumberPredicatesError < RequestError ; end
|
20
|
+
class InvalidNumberValueTestsError < RequestError ; end
|
21
|
+
class InvalidQueryExpressionError < RequestError ; end
|
22
|
+
class MissingParameterError < RequestError ; end
|
23
|
+
class NoSuchDomainError < RequestError ; end
|
24
|
+
class NumberDomainsExceededError < RequestError ; end
|
25
|
+
class NumberDomainAttributesExceededError < RequestError ; end
|
26
|
+
class NumberDomainBytesExceededError < RequestError ; end
|
27
|
+
class NumberItemAttributesExceededError < RequestError ; end
|
28
|
+
class RequestTimeoutError < RequestError ; end
|
29
|
+
|
30
|
+
class FeatureDeprecatedError < RequestError ; end
|
31
|
+
|
32
|
+
class ConnectionError < Error
|
33
|
+
attr_reader :response
|
34
|
+
|
35
|
+
def initialize(response)
|
36
|
+
super(
|
37
|
+
"#{response.code} \
|
38
|
+
#{response.message if response.respond_to?(:message)}"
|
39
|
+
)
|
40
|
+
@response = response
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/rudy/aws/sdb.rb
ADDED
@@ -0,0 +1,298 @@
|
|
1
|
+
|
2
|
+
require 'time'
|
3
|
+
require 'cgi'
|
4
|
+
require 'uri'
|
5
|
+
require 'net/http'
|
6
|
+
require 'base64'
|
7
|
+
require 'openssl'
|
8
|
+
require 'rexml/document'
|
9
|
+
require 'rexml/xpath'
|
10
|
+
|
11
|
+
module Rudy
|
12
|
+
module AWS
|
13
|
+
class SDB
|
14
|
+
class NoAccessKey < RuntimeError; end
|
15
|
+
class NoSecretKey < RuntimeError; end
|
16
|
+
|
17
|
+
require 'rudy/aws/sdb/error'
|
18
|
+
|
19
|
+
def initialize(access_key=nil, secret_key=nil, region=nil, debug=nil)
|
20
|
+
raise NoAccessKey if access_key.nil? || access_key.empty?
|
21
|
+
raise NoSecretKey if secret_key.nil? || secret_key.empty?
|
22
|
+
|
23
|
+
url ||= 'http://sdb.amazonaws.com'
|
24
|
+
# There is a bug with passing :server to EC2::Base.new so
|
25
|
+
# we'll use the environment variable for now.
|
26
|
+
#if region && Rudy::AWS.valid_region?(region)
|
27
|
+
# "#{region}.sdb.amazonaws.com"
|
28
|
+
#end
|
29
|
+
|
30
|
+
@access_key_id = access_key || ENV['AWS_ACCESS_KEY']
|
31
|
+
@secret_access_key = secret_key || ENV['AWS_SECRET_KEY']
|
32
|
+
@base_url = url
|
33
|
+
@debug = debug || StringIO.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def list_domains(max = nil, token = nil)
|
37
|
+
params = { 'Action' => 'ListDomains' }
|
38
|
+
params['NextToken'] =
|
39
|
+
token unless token.nil? || token.empty?
|
40
|
+
params['MaxNumberOfDomains'] =
|
41
|
+
max.to_s unless max.nil? || max.to_i == 0
|
42
|
+
doc = call(:get, params)
|
43
|
+
results = []
|
44
|
+
REXML::XPath.each(doc, '//DomainName/text()') do |domain|
|
45
|
+
results << domain.to_s
|
46
|
+
end
|
47
|
+
#return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
|
48
|
+
results
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_domain(domain)
|
52
|
+
call(:post, { 'Action' => 'CreateDomain', 'DomainName'=> domain.to_s })
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
def destroy_domain(domain)
|
57
|
+
call(
|
58
|
+
:delete,
|
59
|
+
{ 'Action' => 'DeleteDomain', 'DomainName' => domain.to_s }
|
60
|
+
)
|
61
|
+
true
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# Takes a zipped Array or Hash of criteria.
|
66
|
+
# Returns a string suitable for a SimpleDB Select
|
67
|
+
def self.generate_select(*args)
|
68
|
+
fields, domain, args = *args
|
69
|
+
q = args.is_a?(Hash) ? args : Hash[*args.flatten]
|
70
|
+
query = []
|
71
|
+
q.each do |n,v|
|
72
|
+
query << "#{Rudy::AWS.escape n}='#{Rudy::AWS.escape v}'"
|
73
|
+
end
|
74
|
+
"select * from #{domain} where " << query.join(' and ')
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
# Takes a zipped Array or Hash of criteria.
|
79
|
+
# Returns a string suitable for a SimpleDB Query
|
80
|
+
def self.generate_query(*args)
|
81
|
+
q = args.first.is_a?(Hash)? args.first : Hash[*args.flatten]
|
82
|
+
query = []
|
83
|
+
q.each do |n,v|
|
84
|
+
query << "['#{Rudy::AWS.escape n}'='#{Rudy::AWS.escape v}']"
|
85
|
+
end
|
86
|
+
query.join(" intersection ")
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def select(select, token = nil)
|
91
|
+
params = {
|
92
|
+
'Action' => 'Select',
|
93
|
+
'SelectExpression' => select,
|
94
|
+
}
|
95
|
+
params['NextToken'] =
|
96
|
+
token unless token.nil? || token.empty?
|
97
|
+
|
98
|
+
doc = call(:get, params)
|
99
|
+
results = []
|
100
|
+
REXML::XPath.each(doc, "//Item") do |item|
|
101
|
+
name = REXML::XPath.first(item, './Name/text()').to_s
|
102
|
+
|
103
|
+
attributes = {'Name' => name}
|
104
|
+
REXML::XPath.each(item, "./Attribute") do |attr|
|
105
|
+
key = REXML::XPath.first(attr, './Name/text()').to_s
|
106
|
+
value = REXML::XPath.first(attr, './Value/text()').to_s
|
107
|
+
( attributes[key] ||= [] ) << value
|
108
|
+
end
|
109
|
+
results << attributes
|
110
|
+
end
|
111
|
+
#return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
|
112
|
+
|
113
|
+
hash_results = {}
|
114
|
+
results.each do |item|
|
115
|
+
hash_results[item.delete('Name')] = item
|
116
|
+
end
|
117
|
+
|
118
|
+
hash_results.empty? ? nil : hash_results
|
119
|
+
end
|
120
|
+
|
121
|
+
# <QueryResult><ItemName>in-c2ffrw</ItemName><ItemName>in-72yagt</ItemName><ItemName>in-52j8gj</ItemName>
|
122
|
+
def query(domain, query, max = nil, token = nil)
|
123
|
+
params = {
|
124
|
+
'Action' => 'Query',
|
125
|
+
'QueryExpression' => query,
|
126
|
+
'DomainName' => domain.to_s
|
127
|
+
}
|
128
|
+
params['NextToken'] =
|
129
|
+
token unless token.nil? || token.empty?
|
130
|
+
params['MaxNumberOfItems'] =
|
131
|
+
max.to_s unless max.nil? || max.to_i == 0
|
132
|
+
|
133
|
+
|
134
|
+
doc = call(:get, params)
|
135
|
+
results = []
|
136
|
+
REXML::XPath.each(doc, '//ItemName/text()') do |item|
|
137
|
+
results << item.to_s
|
138
|
+
end
|
139
|
+
|
140
|
+
#return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
|
141
|
+
results.empty? ? nil : results
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
|
147
|
+
# <QueryWithAttributesResult><Item><Name>in-c2ffrw</Name><Attribute><Name>code</Name><Value>in-c2ffrw</Value></Attribute><Attribute><Name>date_created</Name><Value>2008-10-31</Value></Attribute></Item><Item>
|
148
|
+
def query_with_attributes(domain, query, max = nil, token = nil)
|
149
|
+
params = {
|
150
|
+
'Action' => 'QueryWithAttributes',
|
151
|
+
'QueryExpression' => query,
|
152
|
+
'DomainName' => domain.to_s
|
153
|
+
}
|
154
|
+
params['NextToken'] =
|
155
|
+
token unless token.nil? || token.empty?
|
156
|
+
params['MaxNumberOfItems'] =
|
157
|
+
max.to_s unless max.nil? || max.to_i == 0
|
158
|
+
|
159
|
+
doc = call(:get, params)
|
160
|
+
results = []
|
161
|
+
REXML::XPath.each(doc, "//Item") do |item|
|
162
|
+
name = REXML::XPath.first(item, './Name/text()').to_s
|
163
|
+
|
164
|
+
attributes = {'Name' => name}
|
165
|
+
REXML::XPath.each(item, "./Attribute") do |attr|
|
166
|
+
key = REXML::XPath.first(attr, './Name/text()').to_s
|
167
|
+
value = REXML::XPath.first(attr, './Value/text()').to_s
|
168
|
+
( attributes[key] ||= [] ) << value
|
169
|
+
end
|
170
|
+
results << attributes
|
171
|
+
end
|
172
|
+
#return results, REXML::XPath.first(doc, '//NextToken/text()').to_s
|
173
|
+
|
174
|
+
hash_results = {}
|
175
|
+
results.each do |item|
|
176
|
+
hash_results[item.delete('Name')] = item
|
177
|
+
end
|
178
|
+
|
179
|
+
hash_results
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
def put_attributes(domain, item, attributes, replace = true)
|
185
|
+
replace = true if replace == :replace
|
186
|
+
params = {
|
187
|
+
'Action' => 'PutAttributes',
|
188
|
+
'DomainName' => domain.to_s,
|
189
|
+
'ItemName' => item.to_s
|
190
|
+
}
|
191
|
+
count = 0
|
192
|
+
|
193
|
+
attributes.each do | key, values |
|
194
|
+
([]<<values).flatten.each do |value|
|
195
|
+
params["Attribute.#{count}.Name"] = key.to_s
|
196
|
+
params["Attribute.#{count}.Value"] = value.to_s
|
197
|
+
params["Attribute.#{count}.Replace"] = replace
|
198
|
+
count += 1
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
call(:put, params)
|
203
|
+
|
204
|
+
true
|
205
|
+
end
|
206
|
+
alias :put :put_attributes
|
207
|
+
|
208
|
+
def get_attributes(domain, item)
|
209
|
+
doc = call(
|
210
|
+
:get,
|
211
|
+
{
|
212
|
+
'Action' => 'GetAttributes',
|
213
|
+
'DomainName' => domain.to_s,
|
214
|
+
'ItemName' => item.to_s
|
215
|
+
}
|
216
|
+
)
|
217
|
+
attributes = {}
|
218
|
+
REXML::XPath.each(doc, "//Attribute") do |attr|
|
219
|
+
key = REXML::XPath.first(attr, './Name/text()').to_s
|
220
|
+
value = REXML::XPath.first(attr, './Value/text()').to_s
|
221
|
+
( attributes[key] ||= [] ) << value
|
222
|
+
end
|
223
|
+
attributes = nil if attributes.empty?
|
224
|
+
attributes
|
225
|
+
end
|
226
|
+
alias :get :get_attributes
|
227
|
+
|
228
|
+
|
229
|
+
def delete_attributes(domain, item)
|
230
|
+
call(
|
231
|
+
:delete,
|
232
|
+
{
|
233
|
+
'Action' => 'DeleteAttributes',
|
234
|
+
'DomainName' => domain.to_s,
|
235
|
+
'ItemName' => item.to_s
|
236
|
+
}
|
237
|
+
)
|
238
|
+
true
|
239
|
+
end
|
240
|
+
alias :destroy :delete_attributes
|
241
|
+
|
242
|
+
|
243
|
+
|
244
|
+
protected
|
245
|
+
|
246
|
+
def call(method, params)
|
247
|
+
params.merge!( {
|
248
|
+
'Version' => '2007-11-07',
|
249
|
+
'SignatureVersion' => '1',
|
250
|
+
'AWSAccessKeyId' => @access_key_id,
|
251
|
+
'Timestamp' => Time.now.gmtime.iso8601
|
252
|
+
}
|
253
|
+
)
|
254
|
+
data = ''
|
255
|
+
query = []
|
256
|
+
|
257
|
+
params.keys.sort_by { |k| k.upcase }.each do |key|
|
258
|
+
data << "#{key}#{params[key].to_s}"
|
259
|
+
query << "#{key}=#{CGI::escape(params[key].to_s)}"
|
260
|
+
end
|
261
|
+
|
262
|
+
digest = OpenSSL::Digest::Digest.new('sha1')
|
263
|
+
hmac = OpenSSL::HMAC.digest(digest, @secret_access_key, data)
|
264
|
+
signature = Base64.encode64(hmac).strip
|
265
|
+
query << "Signature=#{CGI::escape(signature)}"
|
266
|
+
query = query.join('&')
|
267
|
+
url = "#{@base_url}?#{query}"
|
268
|
+
uri = URI.parse(url)
|
269
|
+
@debug.puts("#{url}") if @debug
|
270
|
+
|
271
|
+
response =
|
272
|
+
Net::HTTP.new(uri.host, uri.port).send_request(method, uri.request_uri)
|
273
|
+
@debug.puts("#{response.code}\n#{response.body}") if @debug
|
274
|
+
raise(ConnectionError.new(response)) unless (200..400).include?(
|
275
|
+
response.code.to_i
|
276
|
+
)
|
277
|
+
|
278
|
+
doc = REXML::Document.new(response.body)
|
279
|
+
error = doc.get_elements('*/Errors/Error')[0]
|
280
|
+
raise(
|
281
|
+
Module.class_eval(
|
282
|
+
"AwsSdb::#{error.get_elements('Code')[0].text}Error"
|
283
|
+
).new(
|
284
|
+
error.get_elements('Message')[0].text,
|
285
|
+
doc.get_elements('*/RequestID')[0].text
|
286
|
+
)
|
287
|
+
) unless error.nil?
|
288
|
+
|
289
|
+
doc
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
require 'aws_sdb/error'
|
297
|
+
require 'aws_sdb/service'
|
298
|
+
|
data/lib/rudy/aws.rb
CHANGED
@@ -1,30 +1,28 @@
|
|
1
1
|
|
2
2
|
|
3
|
-
require 'EC2'
|
4
|
-
require 'aws_sdb'
|
3
|
+
require 'EC2' # What a
|
4
|
+
require 'aws_sdb' # motley
|
5
|
+
require 'aws/s3' # crew
|
5
6
|
|
6
7
|
module Rudy
|
7
8
|
module AWS
|
8
9
|
extend self
|
9
|
-
@@ec2 = @@sdb = @@s3 = nil
|
10
10
|
|
11
|
+
unless defined?(Rudy::AWS::VALID_REGIONS)
|
12
|
+
VALID_REGIONS = ['eu-west-1', 'us-east-1'].freeze
|
13
|
+
end
|
11
14
|
|
12
|
-
def
|
13
|
-
def sdb; @@sdb; end
|
14
|
-
def s3; @@s3; end
|
15
|
+
def valid_region?(r); VALID_REGIONS.member?(r.to_s || ''); end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
#@@s3 ||= Rudy::AWS::S3.new(accesskey, secretkey)
|
17
|
+
# Modifies +str+ by removing <tt>[\0\n\r\032\\\\]</tt> and escaping <tt>[\'\"]</tt>
|
18
|
+
def escape(str)
|
19
|
+
str.to_s.tr("[\0\n\r\032\\\\]", '').gsub(/([\'\"])/, '\\1\\1')
|
20
20
|
end
|
21
|
-
|
21
|
+
def escape!(str)
|
22
|
+
str.to_s.tr!("[\0\n\r\032\\\\]", '').gsub!(/([\'\"])/, '\\1\\1')
|
23
|
+
end
|
24
|
+
|
22
25
|
module ObjectBase
|
23
|
-
attr_accessor :aws
|
24
|
-
def initialize(aws_connection)
|
25
|
-
@aws = aws_connection
|
26
|
-
end
|
27
|
-
|
28
26
|
|
29
27
|
protected
|
30
28
|
|
@@ -42,14 +40,21 @@ module Rudy
|
|
42
40
|
Timeout::timeout(timeout) do
|
43
41
|
response = request.call
|
44
42
|
end
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
43
|
+
# Raise the EC2 exceptions
|
44
|
+
rescue ::EC2::Error, ::EC2::InvalidInstanceIDMalformed => ex
|
45
|
+
raise Rudy::AWS::Error, ex.message
|
46
|
+
|
47
|
+
# NOTE: The InternalError is returned for non-existent volume IDs.
|
48
|
+
# It's probably a bug so we're ignoring it -- Dave.
|
49
|
+
rescue ::EC2::InternalError => ex
|
50
|
+
raise Rudy::AWS::Error, ex.message
|
51
|
+
|
49
52
|
rescue Timeout::Error => ex
|
50
53
|
STDERR.puts "Timeout (#{timeout}): #{ex.message}!"
|
51
54
|
rescue SocketError => ex
|
52
55
|
STDERR.puts "Socket Error. Check your Internets!"
|
56
|
+
STDERR.puts ex.message
|
57
|
+
STDERR.puts ex.backtrace
|
53
58
|
ensure
|
54
59
|
response ||= default
|
55
60
|
end
|
@@ -57,47 +62,14 @@ module Rudy
|
|
57
62
|
end
|
58
63
|
end
|
59
64
|
|
60
|
-
|
61
|
-
|
62
|
-
class S3
|
63
|
-
@@logger = StringIO.new
|
64
|
-
|
65
|
-
attr_reader :aws
|
66
|
-
|
67
|
-
def initialize(access_key, secret_key)
|
68
|
-
# @aws = RightAws::S3.new(access_key, secret_key, {:logger => Logger.new(@@logger)})
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
class SimpleDB
|
73
|
-
@@logger = StringIO.new
|
74
|
-
|
75
|
-
attr_reader :domains
|
76
|
-
attr_reader :aws
|
77
|
-
|
78
|
-
def initialize(access_key, secret_key)
|
79
|
-
@aws = AwsSdb::Service.new(:access_key_id => access_key, :secret_access_key => secret_key, :logger => Logger.new(@@logger))
|
80
|
-
@domains = Rudy::AWS::SimpleDB::Domains.new(@aws)
|
81
|
-
end
|
82
|
-
|
83
|
-
end
|
84
|
-
|
85
|
-
require 'rudy/aws/simpledb'
|
65
|
+
require 'rudy/aws/sdb'
|
86
66
|
require 'rudy/aws/ec2'
|
87
67
|
require 'rudy/aws/s3'
|
88
68
|
|
69
|
+
Rudy::Utils.require_glob(RUDY_LIB, 'rudy', 'aws', '{ec2,s3,sdb}', "*.rb")
|
70
|
+
|
71
|
+
class Error < ::EC2::Error; end
|
89
72
|
end
|
90
73
|
|
91
74
|
end
|
92
75
|
|
93
|
-
# Require EC2, S3, Simple DB class
|
94
|
-
begin
|
95
|
-
# TODO: Use autoload
|
96
|
-
Dir.glob(File.join(RUDY_LIB, 'rudy', 'aws', '{ec2,s3,sdb}', "*.rb")).each do |path|
|
97
|
-
require path
|
98
|
-
end
|
99
|
-
rescue LoadError => ex
|
100
|
-
puts "Error: #{ex.message}"
|
101
|
-
exit 1
|
102
|
-
end
|
103
|
-
|
@@ -51,7 +51,7 @@ module Rudy
|
|
51
51
|
def time_stamp
|
52
52
|
#return [@date, @time] if @date && @time
|
53
53
|
now = Time.now.utc
|
54
|
-
datetime = Backup.format_timestamp(now).split(
|
54
|
+
datetime = Backup.format_timestamp(now).split(Rudy::DELIM)
|
55
55
|
@unixtime = now.to_i
|
56
56
|
@date, @time, @second = datetime
|
57
57
|
end
|
@@ -66,7 +66,7 @@ module Rudy
|
|
66
66
|
def to_query(more=[], remove=[])
|
67
67
|
criteria = [:rtype, :zone, :environment, :role, :position, :path, :date, :time, :second, *more]
|
68
68
|
criteria -= [*remove].flatten
|
69
|
-
query = "select * from #{
|
69
|
+
query = "select * from #{Rudy::DOMAIN} where unixtime > '0' "
|
70
70
|
criteria.each do |n|
|
71
71
|
query << "and #{n} = '#{self.send(n.to_sym)}'"
|
72
72
|
end
|
@@ -88,7 +88,7 @@ module Rudy
|
|
88
88
|
# 20090224-1813-36
|
89
89
|
def Backup.format_timestamp(dat)
|
90
90
|
mon, day, hour, min, sec = [dat.mon, dat.day, dat.hour, dat.min, dat.sec].collect { |v| v.to_s.rjust(2, "0") }
|
91
|
-
[dat.year, mon, day,
|
91
|
+
[dat.year, mon, day, Rudy::DELIM, hour, min, Rudy::DELIM, sec].join
|
92
92
|
end
|
93
93
|
|
94
94
|
# Times are converted to UTC
|
@@ -99,7 +99,7 @@ module Rudy
|
|
99
99
|
dirs = pat.split sep if pat
|
100
100
|
dirs.shift while dirs && (dirs[0].nil? || dirs[0].empty?)
|
101
101
|
timestamp = Backup.format_timestamp(dat.utc)
|
102
|
-
[rtype, zon, env, rol, pos, dirs, timestamp].flatten.join(
|
102
|
+
[rtype, zon, env, rol, pos, dirs, timestamp].flatten.join(Rudy::DELIM)
|
103
103
|
end
|
104
104
|
|
105
105
|
|
@@ -110,22 +110,22 @@ module Rudy
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def save
|
113
|
-
@@sdb.store(
|
113
|
+
@@sdb.store(Rudy::DOMAIN, name, self.to_hash, :replace) # Always returns nil
|
114
114
|
true
|
115
115
|
end
|
116
116
|
|
117
117
|
def destroy
|
118
|
-
@@sdb.destroy(
|
118
|
+
@@sdb.destroy(Rudy::DOMAIN, name)
|
119
119
|
true
|
120
120
|
end
|
121
121
|
|
122
122
|
def refresh
|
123
|
-
h = @@sdb.get(
|
123
|
+
h = @@sdb.get(Rudy::DOMAIN, name) || {}
|
124
124
|
from_hash(h)
|
125
125
|
end
|
126
126
|
|
127
127
|
def Backup.get(dname)
|
128
|
-
h = @@sdb.get(
|
128
|
+
h = @@sdb.get(Rudy::DOMAIN, dname) || {}
|
129
129
|
from_hash(h)
|
130
130
|
end
|
131
131
|
|
@@ -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.".color(:blue)
|
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
|
+
|