swirl 1.6.2 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +3 -0
- data/lib/swirl.rb +1 -0
- data/lib/swirl/aws.rb +154 -0
- data/lib/swirl/ec2.rb +6 -114
- data/lib/swirl/helpers.rb +2 -2
- data/test/compactor_test.rb +0 -7
- metadata +5 -5
- data/list-types +0 -36
data/README.md
CHANGED
data/lib/swirl.rb
CHANGED
data/lib/swirl/aws.rb
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'base64'
|
3
|
+
require 'net/https'
|
4
|
+
|
5
|
+
require 'crack/xml'
|
6
|
+
require 'hmac-sha2'
|
7
|
+
|
8
|
+
require 'swirl/helpers'
|
9
|
+
|
10
|
+
|
11
|
+
module Swirl
|
12
|
+
|
13
|
+
## Errors
|
14
|
+
class InvalidRequest < StandardError ; end
|
15
|
+
|
16
|
+
|
17
|
+
class AWS
|
18
|
+
include Helpers::Compactor
|
19
|
+
include Helpers::Expander
|
20
|
+
|
21
|
+
@services = {}
|
22
|
+
|
23
|
+
def self.services
|
24
|
+
# This must be modified using `service`
|
25
|
+
@services.dup
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.service(name, url, version)
|
29
|
+
@services[name] = { :url => url, :version => version }
|
30
|
+
end
|
31
|
+
|
32
|
+
# Default Services
|
33
|
+
service :ec2, "https://ec2.amazonaws.com", "2010-11-15"
|
34
|
+
|
35
|
+
|
36
|
+
def initialize(*args)
|
37
|
+
opts = args.last.is_a?(Hash) ? args.pop : Hash.new
|
38
|
+
name = args.shift
|
39
|
+
|
40
|
+
service = self.class.services[name] || {}
|
41
|
+
opts = service.merge(opts)
|
42
|
+
|
43
|
+
@url = opts[:url] ||
|
44
|
+
raise(ArgumentError, "No url given")
|
45
|
+
|
46
|
+
# Convert this here for future reference
|
47
|
+
@url = URI(@url)
|
48
|
+
|
49
|
+
@version = opts[:version] ||
|
50
|
+
raise(ArgumentError, "No version given")
|
51
|
+
|
52
|
+
@aws_access_key_id = \
|
53
|
+
ENV["AWS_ACCESS_KEY_ID"] ||
|
54
|
+
opts[:aws_access_key_id] ||
|
55
|
+
raise(ArgumentError, "No aws_access_key_id given")
|
56
|
+
|
57
|
+
@aws_secret_access_key = \
|
58
|
+
ENV["AWS_SECRET_ACCESS_KEY"] ||
|
59
|
+
opts[:aws_secret_access_key] ||
|
60
|
+
raise(ArgumentError, "No aws_secret_access_key given")
|
61
|
+
|
62
|
+
@hmac = HMAC::SHA256.new(@aws_secret_access_key)
|
63
|
+
end
|
64
|
+
|
65
|
+
def escape(value)
|
66
|
+
CGI.escape(value).gsub(/\+/, "%20")
|
67
|
+
end
|
68
|
+
|
69
|
+
def compile_sorted_form_data(query)
|
70
|
+
valid = query.reject {|_, v| v.nil? }
|
71
|
+
valid.sort.map {|k,v| [k, escape(v)] * "=" } * "&"
|
72
|
+
end
|
73
|
+
|
74
|
+
def compile_signature(method, body)
|
75
|
+
string_to_sign = [method, @url.host, "/", body] * "\n"
|
76
|
+
hmac = @hmac.update(string_to_sign)
|
77
|
+
encoded_sig = Base64.encode64(hmac.digest).chomp
|
78
|
+
escape(encoded_sig)
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Execute an EC2 command, expand the input,
|
83
|
+
# and compact the output
|
84
|
+
#
|
85
|
+
# Examples:
|
86
|
+
# ec2.call("DescribeInstances")
|
87
|
+
# ec2.call("TerminateInstances", "InstanceId" => ["i-1234", "i-993j"]
|
88
|
+
#
|
89
|
+
def call(action, query={}, &blk)
|
90
|
+
call!(action, expand(query)) do |code, data|
|
91
|
+
case code
|
92
|
+
when 200
|
93
|
+
response = compact(data)
|
94
|
+
when 400...500
|
95
|
+
messages = Array(data["Response"]["Errors"]).map {|_, e| e["Message"] }
|
96
|
+
raise InvalidRequest, messages.join(",")
|
97
|
+
else
|
98
|
+
msg = "unexpected response #{code} -> #{data.inspect}"
|
99
|
+
raise InvalidRequest, msg
|
100
|
+
end
|
101
|
+
|
102
|
+
if blk
|
103
|
+
blk.call(response)
|
104
|
+
else
|
105
|
+
response
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def call!(action, query={}, &blk)
|
111
|
+
# Hard coding this here until otherwise needed
|
112
|
+
method = "POST"
|
113
|
+
|
114
|
+
query["Action"] = action
|
115
|
+
query["AWSAccessKeyId"] = @aws_access_key_id
|
116
|
+
query["SignatureMethod"] = "HmacSHA256"
|
117
|
+
query["SignatureVersion"] = "2"
|
118
|
+
query["Timestamp"] = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
|
119
|
+
query["Version"] = @version
|
120
|
+
|
121
|
+
body = compile_sorted_form_data(query)
|
122
|
+
body += "&" + ["Signature", compile_signature(method, body)].join("=")
|
123
|
+
|
124
|
+
post(body) do |code, xml|
|
125
|
+
if ENV["SWIRL_LOG"]
|
126
|
+
puts response.body
|
127
|
+
end
|
128
|
+
|
129
|
+
data = Crack::XML.parse(xml)
|
130
|
+
blk.call(code, data)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def post(body, &blk)
|
135
|
+
headers = { "Content-Type" => "application/x-www-form-urlencoded" }
|
136
|
+
|
137
|
+
http = Net::HTTP.new(@url.host, @url.port)
|
138
|
+
http.use_ssl = true
|
139
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
140
|
+
|
141
|
+
request = Net::HTTP::Post.new(@url.request_uri, headers)
|
142
|
+
request.body = body
|
143
|
+
|
144
|
+
response = http.request(request)
|
145
|
+
blk.call(response.code.to_i, response.body)
|
146
|
+
end
|
147
|
+
|
148
|
+
def inspect
|
149
|
+
"<#{self.class.name} version: #{@version} url: #{@url} aws_access_key_id: #{@aws_access_key_id}>"
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
data/lib/swirl/ec2.rb
CHANGED
@@ -1,123 +1,15 @@
|
|
1
|
-
require '
|
2
|
-
require 'base64'
|
3
|
-
require 'net/https'
|
1
|
+
require 'swirl/aws'
|
4
2
|
|
5
|
-
|
6
|
-
require 'hmac-sha2'
|
7
|
-
|
8
|
-
require 'swirl/helpers'
|
3
|
+
$stderr.puts "WARNING: Requiring 'swirl' or 'swirl/ec2' will be deprecated. Require 'swirl/aws' instead."
|
9
4
|
|
10
5
|
module Swirl
|
11
6
|
|
12
|
-
|
13
|
-
class InvalidRequest < StandardError ; end
|
14
|
-
|
15
|
-
|
7
|
+
# Compat
|
16
8
|
class EC2
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
def initialize(options)
|
22
|
-
@aws_access_key_id =
|
23
|
-
options[:aws_access_key_id] ||
|
24
|
-
(raise ArgumentError, "no aws_access_key_id provided")
|
25
|
-
@aws_secret_access_key =
|
26
|
-
options[:aws_secret_access_key] ||
|
27
|
-
(raise ArgumentError, "no aws_secret_access_key provided")
|
28
|
-
|
29
|
-
@hmac = HMAC::SHA256.new(@aws_secret_access_key)
|
30
|
-
@version = options[:version] || "2009-11-30"
|
31
|
-
@url = URI(options[:url] || "https://ec2.amazonaws.com")
|
32
|
-
end
|
33
|
-
|
34
|
-
def escape(value)
|
35
|
-
CGI.escape(value).gsub(/\+/, "%20")
|
36
|
-
end
|
37
|
-
|
38
|
-
def compile_sorted_form_data(query)
|
39
|
-
valid = query.reject {|_, v| v.nil? }
|
40
|
-
valid.sort.map {|k,v| [k, escape(v)] * "=" } * "&"
|
41
|
-
end
|
42
|
-
|
43
|
-
def compile_signature(method, body)
|
44
|
-
string_to_sign = [method, @url.host, "/", body] * "\n"
|
45
|
-
hmac = @hmac.update(string_to_sign)
|
46
|
-
encoded_sig = Base64.encode64(hmac.digest).chomp
|
47
|
-
escape(encoded_sig)
|
48
|
-
end
|
49
|
-
|
50
|
-
##
|
51
|
-
# Execute an EC2 command, expand the input,
|
52
|
-
# and compact the output
|
53
|
-
#
|
54
|
-
# Examples:
|
55
|
-
# ec2.call("DescribeInstances")
|
56
|
-
# ec2.call("TerminateInstances", "InstanceId" => ["i-1234", "i-993j"]
|
57
|
-
#
|
58
|
-
def call(action, query={}, &blk)
|
59
|
-
call!(action, expand(query)) do |code, data|
|
60
|
-
case code
|
61
|
-
when 200
|
62
|
-
response = compact(data)
|
63
|
-
when 400...500
|
64
|
-
messages = Array(data["Response"]["Errors"]).map {|_, e| e["Message"] }
|
65
|
-
raise InvalidRequest, messages.join(",")
|
66
|
-
else
|
67
|
-
msg = "unexpected response #{code} -> #{data.inspect}"
|
68
|
-
raise InvalidRequest, msg
|
69
|
-
end
|
70
|
-
|
71
|
-
if blk
|
72
|
-
blk.call(response)
|
73
|
-
else
|
74
|
-
response
|
75
|
-
end
|
76
|
-
end
|
9
|
+
def self.new(options)
|
10
|
+
$stderr.puts "WARNING: Swirl::EC2 will be deprecated. Use Swirl::AWS.new(:ec2) instead"
|
11
|
+
return AWS.new(:ec2, options)
|
77
12
|
end
|
78
|
-
|
79
|
-
def call!(action, query={}, &blk)
|
80
|
-
# Hard coding this here until otherwise needed
|
81
|
-
method = "POST"
|
82
|
-
|
83
|
-
query["Action"] = action
|
84
|
-
query["AWSAccessKeyId"] = @aws_access_key_id
|
85
|
-
query["SignatureMethod"] = "HmacSHA256"
|
86
|
-
query["SignatureVersion"] = "2"
|
87
|
-
query["Timestamp"] = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
|
88
|
-
query["Version"] = @version
|
89
|
-
|
90
|
-
body = compile_sorted_form_data(query)
|
91
|
-
body += "&" + ["Signature", compile_signature(method, body)].join("=")
|
92
|
-
|
93
|
-
post(body) do |code, xml|
|
94
|
-
if ENV["SWIRL_LOG"]
|
95
|
-
puts response.body
|
96
|
-
end
|
97
|
-
|
98
|
-
data = Crack::XML.parse(xml)
|
99
|
-
blk.call(code, data)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def post(body, &blk)
|
104
|
-
headers = { "Content-Type" => "application/x-www-form-urlencoded" }
|
105
|
-
|
106
|
-
http = Net::HTTP.new(@url.host, @url.port)
|
107
|
-
http.use_ssl = true
|
108
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
109
|
-
|
110
|
-
request = Net::HTTP::Post.new(@url.request_uri, headers)
|
111
|
-
request.body = body
|
112
|
-
|
113
|
-
response = http.request(request)
|
114
|
-
blk.call(response.code.to_i, response.body)
|
115
|
-
end
|
116
|
-
|
117
|
-
def inspect
|
118
|
-
"<#{self.class.name} version: #{@version} url: #{@url} aws_access_key_id: #{@aws_access_key_id}>"
|
119
|
-
end
|
120
|
-
|
121
13
|
end
|
122
14
|
|
123
15
|
end
|
data/lib/swirl/helpers.rb
CHANGED
@@ -37,8 +37,8 @@ module Swirl
|
|
37
37
|
|
38
38
|
def compact!(data)
|
39
39
|
data.inject({}) do |com, (key, value)|
|
40
|
-
if
|
41
|
-
converted = if value
|
40
|
+
if value.is_a?(Hash)
|
41
|
+
converted = if value.has_key?("item")
|
42
42
|
items = value["item"]
|
43
43
|
items ||= []
|
44
44
|
items = items.is_a?(Array) ? items : [items]
|
data/test/compactor_test.rb
CHANGED
@@ -39,13 +39,6 @@ class CompactorTest < Test::Unit::TestCase
|
|
39
39
|
assert_equal expected, Compactor.compact(response)
|
40
40
|
end
|
41
41
|
|
42
|
-
test "makes value empty Array if nil" do
|
43
|
-
response = { "Foo" => { "groupSet" => nil } }
|
44
|
-
expected = { "groupSet" => [] }
|
45
|
-
|
46
|
-
assert_equal expected, Compactor.compact(response)
|
47
|
-
end
|
48
|
-
|
49
42
|
test "traverses list values and compacts" do
|
50
43
|
response = {
|
51
44
|
"Foo" => {
|
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 1.
|
8
|
+
- 7
|
9
|
+
- 0
|
10
|
+
version: 1.7.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Blake Mizerany
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-02-
|
18
|
+
date: 2011-02-28 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -78,7 +78,7 @@ extra_rdoc_files:
|
|
78
78
|
files:
|
79
79
|
- LICENSE
|
80
80
|
- README.md
|
81
|
-
-
|
81
|
+
- lib/swirl/aws.rb
|
82
82
|
- lib/swirl/ec2.rb
|
83
83
|
- lib/swirl/helpers.rb
|
84
84
|
- lib/swirl.rb
|
data/list-types
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
begin
|
4
|
-
require 'nokogiri'
|
5
|
-
rescue LoadError
|
6
|
-
abort <<-MSG
|
7
|
-
Unable to load nokogiri.
|
8
|
-
Ensure you have it installed and/or
|
9
|
-
export RUBYOPT=rubygems
|
10
|
-
MSG
|
11
|
-
end
|
12
|
-
|
13
|
-
require 'open-uri'
|
14
|
-
require 'stringio'
|
15
|
-
require 'pp'
|
16
|
-
|
17
|
-
DefaultWSDL = "http://s3.amazonaws.com/ec2-downloads/2008-02-01.ec2.wsdl"
|
18
|
-
|
19
|
-
wsdl_url = ARGV.shift || DefaultWSDL
|
20
|
-
Wsdl = Nokogiri::XML.parse(open(wsdl_url))
|
21
|
-
|
22
|
-
##__END__
|
23
|
-
|
24
|
-
list_keys = []
|
25
|
-
item_types = Wsdl.search(%Q|//xs:complexType//xs:element[@name="item"]|)
|
26
|
-
item_types.each do |item_type|
|
27
|
-
ns, name = item_type["type"].split(":")
|
28
|
-
next if ns != "tns"
|
29
|
-
complex = item_type.parent.parent
|
30
|
-
uses = Wsdl.search(%Q|//xs:element[@type="#{ns}:#{complex["name"]}"]|)
|
31
|
-
uses.each do |u|
|
32
|
-
list_keys << u["name"]
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
pp list_keys.uniq
|