miasma 0.0.1 → 0.1.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2 -0
  3. data/README.md +179 -0
  4. data/lib/miasma.rb +52 -0
  5. data/lib/miasma/contrib/aws.rb +390 -0
  6. data/lib/miasma/contrib/aws/auto_scale.rb +85 -0
  7. data/lib/miasma/contrib/aws/compute.rb +112 -0
  8. data/lib/miasma/contrib/aws/load_balancer.rb +185 -0
  9. data/lib/miasma/contrib/aws/orchestration.rb +338 -0
  10. data/lib/miasma/contrib/rackspace.rb +164 -0
  11. data/lib/miasma/contrib/rackspace/auto_scale.rb +84 -0
  12. data/lib/miasma/contrib/rackspace/compute.rb +104 -0
  13. data/lib/miasma/contrib/rackspace/load_balancer.rb +117 -0
  14. data/lib/miasma/contrib/rackspace/orchestration.rb +255 -0
  15. data/lib/miasma/error.rb +89 -0
  16. data/lib/miasma/models.rb +14 -0
  17. data/lib/miasma/models/auto_scale.rb +55 -0
  18. data/lib/miasma/models/auto_scale/group.rb +64 -0
  19. data/lib/miasma/models/auto_scale/groups.rb +34 -0
  20. data/lib/miasma/models/block_storage.rb +0 -0
  21. data/lib/miasma/models/compute.rb +70 -0
  22. data/lib/miasma/models/compute/server.rb +71 -0
  23. data/lib/miasma/models/compute/servers.rb +35 -0
  24. data/lib/miasma/models/dns.rb +0 -0
  25. data/lib/miasma/models/load_balancer.rb +55 -0
  26. data/lib/miasma/models/load_balancer/balancer.rb +72 -0
  27. data/lib/miasma/models/load_balancer/balancers.rb +34 -0
  28. data/lib/miasma/models/monitoring.rb +0 -0
  29. data/lib/miasma/models/orchestration.rb +127 -0
  30. data/lib/miasma/models/orchestration/event.rb +38 -0
  31. data/lib/miasma/models/orchestration/events.rb +64 -0
  32. data/lib/miasma/models/orchestration/resource.rb +79 -0
  33. data/lib/miasma/models/orchestration/resources.rb +55 -0
  34. data/lib/miasma/models/orchestration/stack.rb +144 -0
  35. data/lib/miasma/models/orchestration/stacks.rb +46 -0
  36. data/lib/miasma/models/queues.rb +0 -0
  37. data/lib/miasma/models/storage.rb +60 -0
  38. data/lib/miasma/models/storage/bucket.rb +36 -0
  39. data/lib/miasma/models/storage/buckets.rb +41 -0
  40. data/lib/miasma/models/storage/file.rb +45 -0
  41. data/lib/miasma/models/storage/files.rb +52 -0
  42. data/lib/miasma/types.rb +13 -0
  43. data/lib/miasma/types/api.rb +145 -0
  44. data/lib/miasma/types/collection.rb +116 -0
  45. data/lib/miasma/types/data.rb +53 -0
  46. data/lib/miasma/types/model.rb +118 -0
  47. data/lib/miasma/types/thin_model.rb +76 -0
  48. data/lib/miasma/utils.rb +12 -0
  49. data/lib/miasma/utils/animal_strings.rb +29 -0
  50. data/lib/miasma/utils/immutable.rb +36 -0
  51. data/lib/miasma/utils/lazy.rb +231 -0
  52. data/lib/miasma/utils/memoization.rb +55 -0
  53. data/lib/miasma/utils/smash.rb +149 -0
  54. data/lib/miasma/version.rb +4 -0
  55. data/miasma.gemspec +18 -0
  56. metadata +57 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c544e3078336270c349d518f50150e8d12ef47e4
4
- data.tar.gz: 77800023eef8143ba2e034e7f82fc81867594c38
3
+ metadata.gz: 8f4c2fc901adb9940a31de3c3379646e1225eea6
4
+ data.tar.gz: c45a82a7de2a1004a51a6c1a3b5fb10c60028088
5
5
  SHA512:
6
- metadata.gz: 9fc5475434b79aca7f66361ea5b8f75b37640a083fc143645557b60c89348e60e0f970b5571484b15219808a53a44ce289b9e0f3b0c8e2adb56c46282b0a2193
7
- data.tar.gz: 947c6d050bf0dccae728ab7dba3754c9a1dc70c7b2d08cf680b195e3a1f72fe93741434750bcbd58e8a4737724825fc57c4f557ddadf70edae43f99cf3ac5cd8
6
+ metadata.gz: 0e0147bc6672e477a407ff627ea6e37839cae93bc16c6f26499cd5f57a4069358a2e6849062d153bfd1b9940b23fe0568f0e5c6cf40b561be0bdfcd4476ff461
7
+ data.tar.gz: cdec65223d5ede929aad74fdf520b1a99c9a67a5d63a4559fff2cf414c5bad11eba6342da21fe9a5f27b89ff2f2b71488452e65123da99cac6a7add616902e74
@@ -0,0 +1,2 @@
1
+ # v0.1.0
2
+ * Initial release
@@ -0,0 +1,179 @@
1
+ ```
2
+ ███▄ ▄███▓ ██▓ ▄▄▄ ██████ ███▄ ▄███▓ ▄▄▄
3
+ ▓██▒▀█▀ ██▒▓██▒▒████▄ ▒██ ▒ ▓██▒▀█▀ ██▒▒████▄
4
+ ▓██ ▓██░▒██▒▒██ ▀█▄ ░ ▓██▄ ▓██ ▓██░▒██ ▀█▄
5
+ ▒██ ▒██ ░██░░██▄▄▄▄██ ▒ ██▒▒██ ▒██ ░██▄▄▄▄██
6
+ ▒██▒ ░██▒░██░ ▓█ ▓██▒▒██████▒▒▒██▒ ░██▒ ▓█ ▓██▒
7
+ ░ ▒░ ░ ░░▓ ▒▒ ▓▒█░▒ ▒▓▒ ▒ ░░ ▒░ ░ ░ ▒▒ ▓▒█░
8
+ ░ ░ ░ ▒ ░ ▒ ▒▒ ░░ ░▒ ░ ░░ ░ ░ ▒ ▒▒ ░
9
+ ░ ░ ▒ ░ ░ ▒ ░ ░ ░ ░ ░ ░ ▒
10
+ ░ ░ ░ ░ ░ ░ ░ ░
11
+ ```
12
+
13
+ ## Overview
14
+
15
+ Miasma is YACACL (Yet Another Cloud API Client Library). Instead of
16
+ attempting to cover all the functionalities of all the different
17
+ cloud and virt APIs, miasma is focused on providing a common modeling
18
+ that will "just work". This means there may be many things that seem
19
+ to be missing, but that's probably okay. Consistency is more important
20
+ than overall completeness. Miasma isn't trying to be a replacement
21
+ for libraries like fog, rather it's attempting to supplement those
22
+ libraries by providing a consistent modeling API.
23
+
24
+ ## Usage
25
+
26
+ ### Example
27
+
28
+ Lets have a look at using the compute model:
29
+
30
+ ```ruby
31
+ compute = Miasma.api(
32
+ :type => :compute,
33
+ :provider => :aws,
34
+ :credentials => {
35
+ :aws_secret_access_key => 'SECRET',
36
+ :aws_access_key_id => 'KEY_ID',
37
+ :aws_region => 'us-west-2'
38
+ }
39
+ )
40
+ ```
41
+
42
+ With this we can now list existing servers:
43
+
44
+ ```ruby
45
+ compute.servers.all
46
+ ```
47
+
48
+ This will provide an array of `Miasma::Models::Compute::Server`
49
+ instances. It will also cache the result so subsequent calls
50
+ will not require another API call. The list can be refreshed
51
+ by requesting a reload:
52
+
53
+ ```ruby
54
+ compute.servers.reload
55
+ ```
56
+
57
+ ### Switching providers
58
+
59
+ Switching providers requires modification to the API parameters:
60
+
61
+ ```ruby
62
+ compute = Miasma.api(
63
+ :provider => :rackspace,
64
+ :credentials => {
65
+ :rackspace_username => 'USER',
66
+ :rackspace_api_key => 'KEY',
67
+ :rackspace_region => 'REGION'
68
+ }
69
+ )
70
+ ```
71
+
72
+ The `compute` API will act exactly the same as before, now using
73
+ Rackspace instead of AWS.
74
+
75
+ ## Design Objectives
76
+
77
+ This library is following a few simple objectives:
78
+
79
+ * Light weight
80
+ * Consistent API
81
+
82
+ The availabile API is defined first via the models,
83
+ then concrete implementations are built via available
84
+ provider interfaces. This means the provider code is
85
+ structured to support the models instead of the models
86
+ being built around specific providers. The result is
87
+ a clean model interface providing consistency regardless
88
+ of the provider backend.
89
+
90
+ The "weight" of the library is kept light by using a
91
+ few simple approaches. All code is lazy loaded, so nothing
92
+ will be loaded into the runtime until it is actually required.
93
+ Dependencies are also kept very light, to reduce the number
94
+ of required libraries needing to be loaded. Parser wrapping
95
+ libraries are also used (`multi_json` and `multi_xml`) allowing
96
+ a choice of actual parsing backends in use. This removes
97
+ dependencies on nokogiri unless it's actually desired and
98
+ increases installation speeds.
99
+
100
+ ## Features
101
+
102
+ ### Thin Models
103
+
104
+ Thin models are a stripped down model that provides a subset
105
+ of information that an actual instance of the model may
106
+ contain. For instance, an `AutoScale::Group` may contain
107
+ a list of `Compute::Server`s. The collection provided within
108
+ the `AutoScale::Group` will be created via the resulting
109
+ API information on the group itself. However, since
110
+ we can provide expected mappings to what API provides
111
+ `Compute` and know these instances will be within the
112
+ `servers` collection, we can use the `#expand` helper to
113
+ automatically load the full instance:
114
+
115
+ ```ruby
116
+ auto_scale = Miasma.api(:type => :auto_scale, :provider ...)
117
+ group = auto_scale.groups.first
118
+
119
+ # this list will provide the `ThinModel` instances:
120
+ p group.servers.all
121
+
122
+ # this list will provide the full instances:
123
+ p group.servers.all.map(&:expand)
124
+ ```
125
+
126
+ ### Automatic API switching
127
+
128
+ Resources within a specific provider can span multiple
129
+ API endpoints. To deal with this, the provider API
130
+ implemenetations provide an `#api_for` method which
131
+ will automatically build a new API instance. This
132
+ allows Miasma to hop APIs under the hood to expand
133
+ `ThinModels` as shown above.
134
+
135
+ ## Current status
136
+
137
+ Miasma is currently under active development and is
138
+ in a beta state. Models are still being implemented
139
+ and spec coverage is following closely behind the
140
+ model completions.
141
+
142
+ ### Currently Supported Providers
143
+
144
+ * AWS
145
+ * Rackspace
146
+
147
+ ### Models
148
+
149
+ #### AWS
150
+
151
+ |Model |Create|Read|Update|Delete|
152
+ |--------------|------|----|------|------|
153
+ |AutoScale | X | | | |
154
+ |BlockStorage | | | | |
155
+ |Compute | X | X | | X |
156
+ |DNS | | | | |
157
+ |LoadBalancer | X | X | X | X |
158
+ |Network | | | | |
159
+ |Orchestration | X | X | X | X |
160
+ |Queues | | | | |
161
+ |Storage | | | | |
162
+
163
+ #### Rackspace
164
+
165
+ |Model |Create|Read|Update|Delete|
166
+ |--------------|------|----|------|------|
167
+ |AutoScale | X | | | |
168
+ |BlockStorage | | | | |
169
+ |Compute | X | X | | X |
170
+ |DNS | | | | |
171
+ |LoadBalancer | | X | | |
172
+ |Network | | | | |
173
+ |Orchestration | X | X | X | X |
174
+ |Queues | | | | |
175
+ |Storage | | | | |
176
+
177
+ ## Info
178
+
179
+ * Repository: https://github.com/chrisroberts/miasma
@@ -0,0 +1,52 @@
1
+ # Load in dependencies
2
+ require 'http'
3
+ require 'multi_json'
4
+ require 'multi_xml'
5
+
6
+ # Make version available
7
+ require 'miasma/version'
8
+
9
+ module Miasma
10
+ autoload :Error, 'miasma/error'
11
+ autoload :Models, 'miasma/models'
12
+ autoload :Types, 'miasma/types'
13
+ autoload :Utils, 'miasma/utils'
14
+
15
+ # Generate and API connection
16
+ #
17
+ # @param args [Hash]
18
+ # @option args [String, Symbol] :type API type (:compute, :dns, etc)
19
+ # @option args [String, Symbol] :provider Service provider
20
+ # @option args [Hash] :credentials Service provider credentials
21
+ def self.api(args={})
22
+ args = Utils::Smash.new(args)
23
+ [:type, :provider, :credentials].each do |key|
24
+ unless(args[key])
25
+ raise ArgumentError.new "Missing required api argument `#{key.inspect}`!"
26
+ end
27
+ end
28
+ args[:type] = Utils.camel(args[:type].to_s).to_sym
29
+ args[:provider] = Utils.camel(args[:provider].to_s).to_sym
30
+ begin
31
+ require "miasma/contrib/#{Utils.snake(args[:provider])}"
32
+ rescue LoadError
33
+ # just ignore
34
+ end
35
+ base_klass = Models.const_get(args[:type])
36
+ begin
37
+ if(base_klass)
38
+ api_klass = base_klass.const_get(args[:provider])
39
+ if(api_klass)
40
+ api_klass.new(args[:credentials].to_smash)
41
+ else
42
+ raise Error.new "Failed to locate #{args[:type]} API for #{args[:provider].inspect}"
43
+ end
44
+ else
45
+ raise Error.new "Failed to locate request API type #{args[:type].inspect}"
46
+ end
47
+ rescue NameError
48
+ raise Error.new "Failed to locate request API type #{args[:type].inspect}"
49
+ end
50
+ end
51
+
52
+ end
@@ -0,0 +1,390 @@
1
+ require 'miasma'
2
+ require 'miasma/utils/smash'
3
+
4
+ require 'time'
5
+ require 'openssl'
6
+
7
+ module Miasma
8
+ module Contrib
9
+ # Core API for AWS access
10
+ class AwsApiCore
11
+
12
+ module RequestUtils
13
+
14
+ # Fetch all results when tokens are being used
15
+ # for paging results
16
+ #
17
+ # @param next_token [String]
18
+ # @param result_key [Array<String, Symbol>] path to result
19
+ # @yield block to perform request
20
+ # @yieldparam options [Hash] request parameters (token information)
21
+ # @return [Array]
22
+ def all_result_pages(next_token, *result_key, &block)
23
+ list = []
24
+ options = next_token ? Smash.new('NextToken' => next_token) : Smash.new
25
+ result = block.call(options)
26
+ content = result.get(*result_key.dup)
27
+ if(content.is_a?(Array))
28
+ list += content
29
+ else
30
+ list << content
31
+ end
32
+ if(token = result.get(:body, 'NextToken'))
33
+ list += all_result_pages(token, *result_key, &block)
34
+ end
35
+ list.compact
36
+ end
37
+
38
+ end
39
+
40
+ # @return [String] current time ISO8601 format
41
+ def self.time_iso8601
42
+ Time.now.utc.strftime('%Y%m%dT%H%M%SZ')
43
+ end
44
+
45
+ # HMAC helper class
46
+ class Hmac
47
+
48
+ # @return [OpenSSL::Digest]
49
+ attr_reader :digest
50
+ # @return [String] secret key
51
+ attr_reader :key
52
+
53
+ # Create new HMAC helper
54
+ #
55
+ # @param kind [String] digest type (sha1, sha256, sha512, etc)
56
+ # @param key [String] secret key
57
+ # @return [self]
58
+ def initialize(kind, key)
59
+ @digest = OpenSSL::Digest.new(kind)
60
+ @key = key
61
+ end
62
+
63
+ # @return [String]
64
+ def to_s
65
+ "Hmac#{digest.name}"
66
+ end
67
+
68
+ # Generate the hexdigest of the content
69
+ #
70
+ # @param content [String] content to digest
71
+ # @return [String] hashed result
72
+ def hexdigest_of(content)
73
+ digest << content
74
+ hash = digest.hexdigest
75
+ digest.reset
76
+ hash
77
+ end
78
+
79
+ # Sign the given data
80
+ #
81
+ # @param data [String]
82
+ # @param key_override [Object]
83
+ # @return [Object] signature
84
+ def sign(data, key_override=nil)
85
+ result = OpenSSL::HMAC.digest(digest, key_override || key, data)
86
+ digest.reset
87
+ result
88
+ end
89
+
90
+ # Sign the given data and return hexdigest
91
+ #
92
+ # @param data [String]
93
+ # @param key_override [Object]
94
+ # @return [String] hex encoded signature
95
+ def hex_sign(data, key_override=nil)
96
+ result = OpenSSL::HMAC.hexdigest(digest, key_override || key, data)
97
+ digest.reset
98
+ result
99
+ end
100
+
101
+ end
102
+
103
+ # Base signature class
104
+ class Signature
105
+
106
+ # Create new instance
107
+ def initialize(*args)
108
+ raise NotImplementedError.new 'This class should not be used directly!'
109
+ end
110
+
111
+ # Generate the signature
112
+ #
113
+ # @param http_method [Symbol] HTTP request method
114
+ # @param path [String] request path
115
+ # @param opts [Hash] request options
116
+ # @return [String] signature
117
+ def generate(http_method, path, opts={})
118
+ raise NotImplementedError
119
+ end
120
+
121
+ # URL string escape compatible with AWS requirements
122
+ #
123
+ # @param string [String] string to escape
124
+ # @return [String] escaped string
125
+ def safe_escape(string)
126
+ string.to_s.gsub(/([^a-zA-Z0-9_.\-~])/) do
127
+ '%' << $1.unpack('H2' * $1.bytesize).join('%').upcase
128
+ end
129
+ end
130
+
131
+ end
132
+
133
+ # AWS signature version 4
134
+ class SignatureV4 < Signature
135
+
136
+ # @return [Hmac]
137
+ attr_reader :hmac
138
+ # @return [String] access key
139
+ attr_reader :access_key
140
+ # @return [String] region
141
+ attr_reader :region
142
+ # @return [String] service
143
+ attr_reader :service
144
+
145
+ # Create new signature generator
146
+ #
147
+ # @param access_key [String]
148
+ # @param secret_key [String]
149
+ # @param region [String]
150
+ # @param service [String]
151
+ # @return [self]
152
+ def initialize(access_key, secret_key, region, service)
153
+ @hmac = Hmac.new('sha256', secret_key)
154
+ @access_key = access_key
155
+ @region = region
156
+ @service = service
157
+ end
158
+
159
+ # Generate the signature
160
+ #
161
+ # @param http_method [Symbol] HTTP request method
162
+ # @param path [String] request path
163
+ # @param opts [Hash] request options
164
+ # @return [String] signature
165
+ def generate(http_method, path, opts)
166
+ to_sign = [
167
+ algorithm,
168
+ AwsApiCore.time_iso8601,
169
+ credential_scope,
170
+ hashed_canonical_request(
171
+ build_canonical_request(http_method, path, opts)
172
+ )
173
+ ].join("\n")
174
+ signature = sign_request(to_sign)
175
+ "#{algorithm} Credential=#{access_key}/#{credential_scope}, SignedHeaders=#{signed_headers(opts[:headers])}, Signature=#{signature}"
176
+ end
177
+
178
+ # Sign the request
179
+ #
180
+ # @param request [String] request to sign
181
+ # @return [String] signature
182
+ def sign_request(request)
183
+ key = hmac.sign(
184
+ 'aws4_request',
185
+ hmac.sign(
186
+ service,
187
+ hmac.sign(
188
+ region,
189
+ hmac.sign(
190
+ Time.now.utc.strftime('%Y%m%d'),
191
+ "AWS4#{hmac.key}"
192
+ )
193
+ )
194
+ )
195
+ )
196
+ hmac.hex_sign(request, key)
197
+ end
198
+
199
+ # @return [String] signature algorithm
200
+ def algorithm
201
+ 'AWS4-HMAC-SHA256'
202
+ end
203
+
204
+ # @return [String] credential scope for request
205
+ def credential_scope
206
+ [
207
+ Time.now.utc.strftime('%Y%m%d'),
208
+ region,
209
+ service,
210
+ 'aws4_request'
211
+ ].join('/')
212
+ end
213
+
214
+ # Generate the hash of the canonical request
215
+ #
216
+ # @param request [String] canonical request string
217
+ # @return [String] hashed canonical request
218
+ def hashed_canonical_request(request)
219
+ hmac.hexdigest_of(request)
220
+ end
221
+
222
+ # Build the canonical request string used for signing
223
+ #
224
+ # @param http_method [Symbol] HTTP request method
225
+ # @param path [String] request path
226
+ # @param opts [Hash] request options
227
+ # @return [String] canonical request string
228
+ def build_canonical_request(http_method, path, opts)
229
+ [
230
+ http_method.to_s.upcase,
231
+ path,
232
+ canonical_query(opts[:params]),
233
+ canonical_headers(opts[:headers]),
234
+ signed_headers(opts[:headers]),
235
+ canonical_payload(opts)
236
+ ].join("\n")
237
+ end
238
+
239
+ # Build the canonical query string used for signing
240
+ #
241
+ # @param params [Hash] query params
242
+ # @return [String] canonical query string
243
+ def canonical_query(params)
244
+ params ||= {}
245
+ params = Hash[params.sort_by(&:first)]
246
+ query = params.map do |key, value|
247
+ "#{safe_escape(key)}=#{safe_escape(value)}"
248
+ end.join('&')
249
+ end
250
+
251
+ # Build the canonical header string used for signing
252
+ #
253
+ # @param headers [Hash] request headers
254
+ # @return [String] canonical headers string
255
+ def canonical_headers(headers)
256
+ headers ||= {}
257
+ headers = Hash[headers.sort_by(&:first)]
258
+ headers.map do |key, value|
259
+ [key.downcase, value.chomp].join(':')
260
+ end.join("\n") << "\n"
261
+ end
262
+
263
+ # List of headers included in signature
264
+ #
265
+ # @param headers [Hash] request headers
266
+ # @return [String] header list
267
+ def signed_headers(headers)
268
+ headers ||= {}
269
+ headers.sort_by(&:first).map(&:first).
270
+ map(&:downcase).join(';')
271
+ end
272
+
273
+ # Build the canonical payload string used for signing
274
+ #
275
+ # @param options [Hash] request options
276
+ # @return [String] body checksum
277
+ def canonical_payload(options)
278
+ body = options.fetch(:body, '')
279
+ if(options[:json])
280
+ body = MultiJson.dump(options[:json])
281
+ elsif(options[:form])
282
+ body = URI.encode_www_form(options[:form])
283
+ end
284
+ hmac.hexdigest_of(body)
285
+ end
286
+
287
+ end
288
+
289
+ module ApiCommon
290
+
291
+ def self.included(klass)
292
+ klass.class_eval do
293
+ attribute :aws_access_key_id, String, :required => true
294
+ attribute :aws_secret_access_key, String, :required => true
295
+ attribute :aws_region, String, :required => true
296
+ attribute :aws_host, String
297
+
298
+ # @return [Contrib::AwsApiCore::SignatureV4]
299
+ attr_reader :signer
300
+ end
301
+ end
302
+
303
+ # Build new API for specified type using current provider / creds
304
+ #
305
+ # @param type [Symbol] api type
306
+ # @return [Api]
307
+ def api_for(type)
308
+ memoize(type) do
309
+ creds = attributes.dup
310
+ creds.delete(:aws_host)
311
+ Miasma.api(
312
+ Smash.new(
313
+ :type => type,
314
+ :provider => provider,
315
+ :credentials => creds
316
+ )
317
+ )
318
+ end
319
+ end
320
+
321
+ # Setup for API connections
322
+ def connect
323
+ unless(aws_host)
324
+ self.aws_host = [
325
+ self.class::API_SERVICE.downcase,
326
+ aws_region,
327
+ 'amazonaws.com'
328
+ ].join('.')
329
+ end
330
+ @signer = Contrib::AwsApiCore::SignatureV4.new(
331
+ aws_access_key_id, aws_secret_access_key, aws_region, self.class::API_SERVICE
332
+ )
333
+ end
334
+
335
+ # @return [HTTP] connection for requests (forces headers)
336
+ def connection
337
+ super.with_headers(
338
+ 'Host' => aws_host,
339
+ 'X-Amz-Date' => Contrib::AwsApiCore.time_iso8601
340
+ )
341
+ end
342
+
343
+ # @return [String] endpoint for request
344
+ def endpoint
345
+ "https://#{aws_host}"
346
+ end
347
+
348
+ # Override to inject signature
349
+ #
350
+ # @param connection [HTTP]
351
+ # @param http_method [Symbol]
352
+ # @param request_args [Array]
353
+ # @return [HTTP::Response]
354
+ # @note if http_method is :post, params will be automatically
355
+ # removed and placed into :form
356
+ def make_request(connection, http_method, request_args)
357
+ dest, options = request_args
358
+ path = URI.parse(dest).path
359
+ options = options.to_smash
360
+ options[:params] = options.fetch(:params, Smash.new).to_smash.deep_merge('Version' => self.class::API_VERSION)
361
+ if(http_method.to_sym == :post)
362
+ if(options[:form])
363
+ options[:form].merge(options.delete(:params))
364
+ else
365
+ options[:form] = options.delete(:params)
366
+ end
367
+ end
368
+ signature = signer.generate(
369
+ http_method, path, options.merge(
370
+ Smash.new(
371
+ :headers => Smash[
372
+ connection.default_headers.to_a
373
+ ]
374
+ )
375
+ )
376
+ )
377
+ options = Hash[options.map{|k,v|[k.to_sym,v]}]
378
+ connection.auth(signature).send(http_method, dest, options)
379
+ end
380
+
381
+ end
382
+
383
+ end
384
+ end
385
+
386
+ Models::Compute.autoload :Aws, 'miasma/contrib/aws/compute'
387
+ Models::LoadBalancer.autoload :Aws, 'miasma/contrib/aws/load_balancer'
388
+ Models::AutoScale.autoload :Aws, 'miasma/contrib/aws/auto_scale'
389
+ Models::Orchestration.autoload :Aws, 'miasma/contrib/aws/orchestration'
390
+ end