Class: Swirl::EC2

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

Constant Summary

Constants included from Helpers::Compactor

Helpers::Compactor::Lists

Instance Method Summary collapse

Methods included from Helpers::Expander

expand

Methods included from Helpers::Compactor

compact, compact!

Constructor Details

#initialize(options) ⇒ EC2

Returns a new instance of EC2.



21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/swirl/ec2.rb', line 21

def initialize(options)
  @aws_access_key_id =
    options[:aws_access_key_id] ||
    (raise ArgumentError, "no aws_access_key_id provided")
  @aws_secret_access_key =
    options[:aws_secret_access_key] ||
    (raise ArgumentError, "no aws_secret_access_key provided")

  @hmac = HMAC::SHA256.new(@aws_secret_access_key)
  @version = options[:version] || "2009-11-30"
  @url = URI(options[:url] || "https://ec2.amazonaws.com")
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"]


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/swirl/ec2.rb', line 58

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



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/swirl/ec2.rb', line 79

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



43
44
45
46
47
48
# File 'lib/swirl/ec2.rb', line 43

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



38
39
40
41
# File 'lib/swirl/ec2.rb', line 38

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

#escape(value) ⇒ Object



34
35
36
# File 'lib/swirl/ec2.rb', line 34

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

#inspectObject



117
118
119
# File 'lib/swirl/ec2.rb', line 117

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

#post(body, &blk) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/swirl/ec2.rb', line 103

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