Class: Swirl::AWS

Inherits:
Object
  • Object
show all
Includes:
Helpers::Compactor, Helpers::Expander
Defined in:
lib/swirl/aws.rb

Constant Summary

Constants included from Helpers::Compactor

Helpers::Compactor::Lists

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers::Expander

expand

Methods included from Helpers::Compactor

compact, compact!

Constructor Details

#initialize(*args) ⇒ AWS

Returns a new instance of AWS.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/swirl/aws.rb', line 36

def initialize(*args)
  opts = args.last.is_a?(Hash) ? args.pop : Hash.new
  name = args.shift

  service = self.class.services[name] || {}
  opts    = service.merge(opts)

  @url = opts[:url] ||
    raise(ArgumentError, "No url given")

  # Convert this here for future reference
  @url = URI(@url)

  @version = opts[:version] ||
    raise(ArgumentError, "No version given")

  @aws_access_key_id  = \
    ENV["AWS_ACCESS_KEY_ID"] ||
    opts[:aws_access_key_id] ||
    raise(ArgumentError, "No aws_access_key_id given")

  @aws_secret_access_key = \
    ENV["AWS_SECRET_ACCESS_KEY"] ||
    opts[:aws_secret_access_key] ||
    raise(ArgumentError, "No aws_secret_access_key given")

  @hmac = HMAC::SHA256.new(@aws_secret_access_key)
end

Class Method Details

.service(name, url, version) ⇒ Object



28
29
30
# File 'lib/swirl/aws.rb', line 28

def self.service(name, url, version)
  @services[name] = { :url => url, :version => version }
end

.servicesObject



23
24
25
26
# File 'lib/swirl/aws.rb', line 23

def self.services
  # This must be modified using `service`
  @services.dup
end

Instance Method Details

#call(action, query = {}, &blk) ⇒ Object

Execute an EC2 command, expand the input, and compact the output

Examples:

ec2.call("DescribeInstances")
ec2.call("TerminateInstances", "InstanceId" => ["i-1234", "i-993j"]


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/swirl/aws.rb', line 89

def call(action, query={}, &blk)
  call!(action, expand(query)) do |code, data|
    case code
    when 200
      response = compact(data)
    when 400...500
      messages = Array(data["Response"]["Errors"]).map {|_, e| e["Message"] }
      raise InvalidRequest, messages.join(",")
    else
      msg = "unexpected response #{code} -> #{data.inspect}"
      raise InvalidRequest, msg
    end

    if blk
      blk.call(response)
    else
      response
    end
  end
end

#call!(action, query = {}, &blk) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/swirl/aws.rb', line 110

def call!(action, query={}, &blk)
  # Hard coding this here until otherwise needed
  method = "POST"

  query["Action"] = action
  query["AWSAccessKeyId"] = @aws_access_key_id
  query["SignatureMethod"] = "HmacSHA256"
  query["SignatureVersion"] = "2"
  query["Timestamp"] = Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ")
  query["Version"] = @version

  body = compile_sorted_form_data(query)
  body += "&" + ["Signature", compile_signature(method, body)].join("=")

  post(body) do |code, xml|
    if ENV["SWIRL_LOG"]
      puts response.body
    end

    data = Crack::XML.parse(xml)
    blk.call(code, data)
  end
end

#compile_signature(method, body) ⇒ Object



74
75
76
77
78
79
# File 'lib/swirl/aws.rb', line 74

def compile_signature(method, body)
  string_to_sign = [method, @url.host, "/", body] * "\n"
  hmac = @hmac.update(string_to_sign)
  encoded_sig = Base64.encode64(hmac.digest).chomp
  escape(encoded_sig)
end

#compile_sorted_form_data(query) ⇒ Object



69
70
71
72
# File 'lib/swirl/aws.rb', line 69

def compile_sorted_form_data(query)
  valid = query.reject {|_, v| v.nil? }
  valid.sort.map {|k,v| [k, escape(v)] * "=" } * "&"
end

#escape(value) ⇒ Object



65
66
67
# File 'lib/swirl/aws.rb', line 65

def escape(value)
  CGI.escape(value).gsub(/\+/, "%20")
end

#inspectObject



148
149
150
# File 'lib/swirl/aws.rb', line 148

def inspect
  "<#{self.class.name} version: #{@version} url: #{@url} aws_access_key_id: #{@aws_access_key_id}>"
end

#post(body, &blk) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/swirl/aws.rb', line 134

def post(body, &blk)
  headers = { "Content-Type" => "application/x-www-form-urlencoded" }

  http = Net::HTTP.new(@url.host, @url.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE

  request = Net::HTTP::Post.new(@url.request_uri, headers)
  request.body = body

  response = http.request(request)
  blk.call(response.code.to_i, response.body)
end