miasma 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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