stacker_bee 2.0.0 → 2.1.0.pre180
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +13 -5
- data/.travis.yml +13 -1
- data/README.md +134 -64
- data/bin/stacker_bee +4 -3
- data/config.default.yml +1 -1
- data/lib/stacker_bee/api.rb +2 -3
- data/lib/stacker_bee/client.rb +101 -19
- data/lib/stacker_bee/connection.rb +31 -16
- data/lib/stacker_bee/{middleware → http_middleware}/detokenizer.rb +3 -2
- data/lib/stacker_bee/http_middleware/graylog.rb +14 -0
- data/lib/stacker_bee/{middleware → http_middleware}/signed_query.rb +1 -1
- data/lib/stacker_bee/middleware/adapter.rb +16 -0
- data/lib/stacker_bee/middleware/base.rb +33 -0
- data/lib/stacker_bee/middleware/clean_response.rb +42 -0
- data/lib/stacker_bee/middleware/cloud_stack_api.rb +17 -0
- data/lib/stacker_bee/middleware/console_access.rb +38 -0
- data/lib/stacker_bee/middleware/de_namespace.rb +15 -0
- data/lib/stacker_bee/middleware/dictionary_flattener.rb +44 -0
- data/lib/stacker_bee/middleware/endpoint_normalizer.rb +23 -0
- data/lib/stacker_bee/middleware/environment.rb +23 -0
- data/lib/stacker_bee/middleware/format_keys.rb +13 -0
- data/lib/stacker_bee/middleware/format_values.rb +13 -0
- data/lib/stacker_bee/middleware/http_status.rb +14 -0
- data/lib/stacker_bee/middleware/json_body.rb +14 -0
- data/lib/stacker_bee/middleware/raise_on_http_error.rb +11 -0
- data/lib/stacker_bee/middleware/rashify_response.rb +21 -0
- data/lib/stacker_bee/middleware/remove_empty_strings.rb +11 -0
- data/lib/stacker_bee/middleware/remove_nils.rb +9 -0
- data/lib/stacker_bee/request_error.rb +8 -16
- data/lib/stacker_bee/utilities.rb +30 -0
- data/lib/stacker_bee/version.rb +1 -1
- data/lib/stacker_bee.rb +1 -1
- data/spec/cassettes/A_request_sent_to_CloudStack_for_console_access/returns_html_for_console_access.yml +33 -0
- data/spec/cassettes/A_response_to_a_request_sent_to_the_CloudStack_API/{a_request_parameter_with_a_Map → a_request_parameter_with_a_map}/can_create_an_object.yml +0 -0
- data/spec/cassettes/A_response_to_a_request_sent_to_the_CloudStack_API/a_request_that_triggers_an_error/properly_signs_the_request.yml +35 -0
- data/spec/cassettes/A_response_to_a_request_sent_to_the_CloudStack_API/middleware/a_middleware_that_doesn_t_match_the_content_type/uses_the_middleware.yml +33 -0
- data/spec/cassettes/A_response_to_a_request_sent_to_the_CloudStack_API/middleware/a_middleware_that_matches_the_content_type/uses_the_middleware.yml +33 -0
- data/spec/integration/check_spec.rb +48 -0
- data/spec/integration/configure_middleware_spec.rb +54 -16
- data/spec/integration/console_spec.rb +21 -0
- data/spec/integration/request_spec.rb +57 -2
- data/spec/spec_helper.rb +11 -1
- data/spec/units/faraday_graylog_middleware_spec.rb +1 -1
- data/spec/units/stacker_bee/client_spec.rb +47 -78
- data/spec/units/stacker_bee/connection_spec.rb +34 -11
- data/spec/units/stacker_bee/console_spec.rb +0 -0
- data/spec/units/stacker_bee/{graylog_faraday_middleware_spec.rb → http_middleware/graylog_spec.rb} +18 -2
- data/spec/units/stacker_bee/middleware/adapter_spec.rb +54 -0
- data/spec/units/stacker_bee/middleware/base_spec.rb +128 -0
- data/spec/units/stacker_bee/middleware/cloudstack_api_spec.rb +37 -0
- data/spec/units/stacker_bee/middleware/console_access_spec.rb +59 -0
- data/spec/units/stacker_bee/{dictionary_flattener_spec.rb → middleware/dictionary_flattener_spec.rb} +7 -7
- data/spec/units/stacker_bee/middleware/endpoint_normalizer_spec.rb +36 -0
- data/spec/units/stacker_bee/middleware/format_keys_spec.rb +18 -0
- data/spec/units/stacker_bee/middleware/format_values_spec.rb +15 -0
- data/spec/units/stacker_bee/middleware/http_status_spec.rb +34 -0
- data/spec/units/stacker_bee/middleware/raise_on_http_errors_spec.rb +5 -0
- data/spec/units/stacker_bee/middleware/remove_empty_strings_spec.rb +54 -0
- data/spec/units/stacker_bee/middleware/remove_nils_spec.rb +8 -0
- data/spec/units/stacker_bee/request_error_spec.rb +25 -37
- data/spec/units/stacker_bee/utilities_spec.rb +26 -0
- data/stacker_bee.gemspec +6 -2
- metadata +84 -38
- data/lib/stacker_bee/body_parser.rb +0 -23
- data/lib/stacker_bee/dictionary_flattener.rb +0 -41
- data/lib/stacker_bee/graylog_faraday_middleware.rb +0 -12
- data/lib/stacker_bee/middleware/logger.rb +0 -47
- data/lib/stacker_bee/request.rb +0 -46
- data/lib/stacker_bee/response.rb +0 -29
- data/spec/cassettes/A_response_to_a_request_sent_to_the_CloudStack_API/a_request_parameter_with_a_Map/object.yml +0 -153
- data/spec/units/stacker_bee/middleware/logger_spec.rb +0 -55
- data/spec/units/stacker_bee/request_spec.rb +0 -51
- data/spec/units/stacker_bee/response_spec.rb +0 -79
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZjM2MmUzMTI4NjMzMTkxMjUxOTAzYzk0NzBlN2ZmNGJlNDQ3NjFjYw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
Yjg3ZGM0M2E3MTU2Yzg1M2Q4YmY3NDZhZjMzNjRiYzIyOWY2ZjhmOQ==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
N2I1ODhiMTY2NWVhYmUxNzE4OWViNTVmZDY4MjgzM2QyOGI0MTkyZDdiNzY1
|
10
|
+
OTk1YjJiMGIzMDUyYmZlZDQ5NGY4OTQzYzNhMjExZjg5MDk4MDc3ZmZiNzg0
|
11
|
+
ZTEzZDAxNzdiOTcxMDM0OWM2ZmI1NGRkN2JmNzUxZWZhOGFmYjE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZGIzOWIyYWM0MjZhYTBjOTNiZjVhOWUxZGJiNDg2NDA0MTE3NTM5NDUyN2Jl
|
14
|
+
ZGU1NzFjMzRhOTUzOTRmNTg4NjQ5NmE0MDBjYWU0NDZlYmExYjk0NDdlZTQ3
|
15
|
+
MmM0OGZmNTY1MmJlMWRjNzEwOGNjNjc5OGU4OTM4ODViZTUyYzA=
|
data/.travis.yml
CHANGED
@@ -1,9 +1,21 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
+
- 2.1.0
|
3
4
|
- 2.0.0
|
4
5
|
- 1.9.3
|
5
6
|
- 1.9.2
|
6
7
|
- jruby-19mode
|
7
|
-
- rbx-19mode
|
8
8
|
- ruby-head
|
9
9
|
- jruby-head
|
10
|
+
matrix:
|
11
|
+
allow_failures:
|
12
|
+
- rvm: ruby-head
|
13
|
+
- rvm: jruby-head
|
14
|
+
deploy:
|
15
|
+
provider: rubygems
|
16
|
+
api_key:
|
17
|
+
secure: d5hC4iuoXOsrQKJRd9GSyZP2UlO2v9HsayhgNk2RlQQJFbqki6TcIlxN6j39/QER3pM3MUZyvCewtvxjrijt4f82xJGHRXaVNZvPSyD91PkGUtOuibLojc+GmwrzzRpu0d3TSEuzeKBSVag7AuJFO3oQnhEyblyZPyqWh1Ii1nM=
|
18
|
+
gem: stacker_bee
|
19
|
+
on:
|
20
|
+
repo: promptworks/stacker_bee
|
21
|
+
ruby: 2.1.0
|
data/README.md
CHANGED
@@ -13,9 +13,11 @@ You can install StackerBee with rubygems:
|
|
13
13
|
|
14
14
|
$ gem install stacker_bee
|
15
15
|
|
16
|
-
If you are using Bundler
|
16
|
+
If you are using Bundler add the following to your Gemfile:
|
17
17
|
|
18
|
-
|
18
|
+
```ruby
|
19
|
+
gem 'stacker_bee'
|
20
|
+
```
|
19
21
|
|
20
22
|
And execute:
|
21
23
|
|
@@ -24,35 +26,42 @@ And execute:
|
|
24
26
|
|
25
27
|
## Basic Usage
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
```ruby
|
30
|
+
cloud_stack = StackerBee::Client.new(
|
31
|
+
url: 'http://localhost:8080/client/api',
|
32
|
+
api_key: 'MY_API_KEY',
|
33
|
+
secret_key: 'MY_SECRET_KEY'
|
34
|
+
)
|
32
35
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
36
|
+
cloud_stack.list_virtual_machines state: 'Running'
|
37
|
+
# => [ { id: '48b91ab4...', displayName: '...', ... },
|
38
|
+
# { id: '59c02bc5...', displayName: '...', ... },
|
39
|
+
# ... ]
|
37
40
|
|
38
|
-
|
41
|
+
cloud_stack.create_volume name: 'MyVolume'
|
42
|
+
```
|
39
43
|
|
40
44
|
## Features
|
41
45
|
|
42
46
|
### Idomatic Ruby formatting for names
|
43
47
|
|
44
|
-
|
48
|
+
For example, you can use `list_virtual_machines` instead of `listVirtualMachines` and
|
45
49
|
`affinity_group_id` instead of `affinitygroupid` (if you want to).
|
46
50
|
|
47
51
|
For example:
|
48
52
|
|
49
|
-
|
50
|
-
|
53
|
+
```ruby
|
54
|
+
vm = cloud_stack.list_virtual_machines(affinity_group_id: id).first
|
55
|
+
puts vm[:iso_display_text]
|
56
|
+
```
|
51
57
|
|
52
58
|
### Handling 'map' parameters
|
53
59
|
|
54
|
-
For any endpoint requiring a map parameter,
|
55
|
-
|
60
|
+
For any endpoint requiring a map parameter, pass in a hash.
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
cloud_stack.create_tags(tags: { type: 'community' }, resource_type: "Template", resource_ids: id )
|
64
|
+
```
|
56
65
|
|
57
66
|
This will yield a request with the following query string:
|
58
67
|
|
@@ -63,7 +72,9 @@ This will yield a request with the following query string:
|
|
63
72
|
By default, StackerBee uses the CloudStack 4.2 API, but it doesn't have to.
|
64
73
|
Use a different API version by setting the `api_path` configuration option to the path of a JSON file containing the response from your CloudStack instance's `listApis` command.
|
65
74
|
|
66
|
-
|
75
|
+
```ruby
|
76
|
+
StackerBee::Client.api_path = '/path/to/your/listApis/response.json'
|
77
|
+
```
|
67
78
|
|
68
79
|
### CloudStack REPL
|
69
80
|
|
@@ -86,64 +97,106 @@ Example:
|
|
86
97
|
|
87
98
|
Configuring a client:
|
88
99
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
100
|
+
```ruby
|
101
|
+
cloud_stack = StackerBee::Client.new(
|
102
|
+
url: 'http://localhost:8080/client/api',
|
103
|
+
api_key: 'API_KEY',
|
104
|
+
secret_key: 'SECRET_KEY'
|
105
|
+
)
|
106
|
+
```
|
95
107
|
|
96
108
|
All configuration parameters set on the `StackerBee::Client` class are used as defaults for `StackerBee::Client` instances.
|
97
109
|
|
98
|
-
|
99
|
-
|
110
|
+
```ruby
|
111
|
+
StackerBee::Client.url = 'http://localhost:8080/client/api'
|
100
112
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
113
|
+
user_client = StackerBee::Client.new(
|
114
|
+
api_key: 'USER_API_KEY',
|
115
|
+
secret_key: 'USER_SECRET_KEY'
|
116
|
+
)
|
105
117
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
118
|
+
root_client = StackerBee::Client.new(
|
119
|
+
api_key: 'ROOT_API_KEY',
|
120
|
+
secret_key: 'ROOT_SECRET_KEY'
|
121
|
+
)
|
122
|
+
```
|
110
123
|
|
111
124
|
### URL
|
112
125
|
|
113
126
|
The URL of your CloudStack instance's URL.
|
114
127
|
|
115
|
-
|
128
|
+
```ruby
|
129
|
+
StackerBee::Client.url = 'http://localhost:8080/client/api'
|
130
|
+
```
|
116
131
|
|
117
132
|
Or:
|
118
133
|
|
119
|
-
|
120
|
-
|
121
|
-
|
134
|
+
```ruby
|
135
|
+
my_client = StackerBee::Client.new(
|
136
|
+
url: 'http://localhost:8080/client/api'
|
137
|
+
)
|
138
|
+
```
|
122
139
|
|
123
140
|
### Keys
|
124
141
|
|
125
142
|
Your CloudStack credentials, i.e. API key and secret key.
|
126
143
|
|
127
|
-
|
128
|
-
|
144
|
+
```ruby
|
145
|
+
StackerBee::Client.api_key = 'MY_API_KEY'
|
146
|
+
StackerBee::Client.secret_key = 'MY_SECRET_KEY'
|
147
|
+
```
|
129
148
|
|
130
149
|
Or:
|
131
150
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
151
|
+
```ruby
|
152
|
+
my_client = StackerBee::Client.new(
|
153
|
+
api_key: 'MY_API_KEY',
|
154
|
+
secret_key: 'MY_SECRET_KEY'
|
155
|
+
)
|
156
|
+
```
|
157
|
+
|
158
|
+
### Middleware
|
159
|
+
|
160
|
+
StackerBee can be configured with middleware. It uses it's own middleware stack to implement some of its functionality.
|
161
|
+
|
162
|
+
To add a middleware, use the `middlewares` configuration option. For example:
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
class StdoutLoggingMiddleware < StackerBee::Middleware::Base
|
166
|
+
def call(env)
|
167
|
+
app.call(env)
|
168
|
+
p "CloudStack call: #{env.inspect}"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
class PrependedMiddleware < StackerBee::Middleware::Base
|
173
|
+
def call(env) app.call(env) end
|
174
|
+
end
|
175
|
+
|
176
|
+
StackerBee::Client.configuration = {
|
177
|
+
middlewares: ->(builder) do
|
178
|
+
# Using `before` places the middleware before the default middlewares
|
179
|
+
builder.before PrependedMiddleware
|
180
|
+
|
181
|
+
# Using `use` places the middleware after the default middlewares,
|
182
|
+
# but before the request is sent to Faraday
|
183
|
+
builder.use StdoutLoggingMiddleware
|
184
|
+
end
|
185
|
+
}
|
186
|
+
```
|
136
187
|
|
137
188
|
### Faraday Middleware
|
138
189
|
|
139
|
-
StackerBee is built on [Faraday](https://github.com/lostisland/faraday) and
|
190
|
+
StackerBee is built on [Faraday](https://github.com/lostisland/faraday) and allows you to add Faraday middleware. Here's an example of adding your own middleware.
|
140
191
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
192
|
+
```ruby
|
193
|
+
StackerBee::Client.configuration = {
|
194
|
+
faraday_middlewares: ->(faraday) do
|
195
|
+
faraday.use Custom::LoggingMiddleware, Logger.new
|
196
|
+
faraday.use Custom::CachingMiddleware, Rails.cache
|
197
|
+
end
|
198
|
+
}
|
199
|
+
```
|
147
200
|
|
148
201
|
StackerBee itself puts some middlewares on Faraday. Any middlewares you add will be placed after these. If you want your middleware to come as the very first, you can use Faraday's builder like `faraday.builder.insert 0, MyMiddleware`.
|
149
202
|
|
@@ -155,30 +208,35 @@ Logging is best handled with Faraday middleware.
|
|
155
208
|
|
156
209
|
If you're using the Graylog2 GELF format, you're in luck because StackerBee currently ships with a Faraday middleware for that. Here's an example of logging to Graylog2:
|
157
210
|
|
158
|
-
|
211
|
+
```ruby
|
212
|
+
logger = GELF::Notifier.new("localhost", 12201)
|
159
213
|
|
160
|
-
|
161
|
-
|
162
|
-
|
214
|
+
StackerBee::Client.configuration = {
|
215
|
+
faraday_middlewares: ->(faraday) { faraday.use faraday.use StackerBee::GraylogFaradayMiddleware, logger }
|
216
|
+
}
|
217
|
+
```
|
163
218
|
|
164
219
|
#### Basic logging
|
165
220
|
|
166
221
|
To log to a file or STDOUT, Faraday has a built-in logger. You can use it like so:
|
167
222
|
|
168
|
-
|
169
|
-
|
170
|
-
|
223
|
+
```ruby
|
224
|
+
StackerBee::Client.configuration = {
|
225
|
+
faraday_middlewares: ->(faraday) { faraday.response :logger }
|
226
|
+
}
|
227
|
+
```
|
171
228
|
|
172
229
|
### Bulk Configuration
|
173
230
|
|
174
231
|
The `StackerBee::Client` class can be configured with multiple options at once.
|
175
232
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
233
|
+
```ruby
|
234
|
+
StackerBee::Client.configuration = {
|
235
|
+
url: 'http://localhost:8080/client/api',
|
236
|
+
api_key: 'API_KEY',
|
237
|
+
secret_key: 'MY_SECRET_KEY'
|
238
|
+
}
|
239
|
+
```
|
182
240
|
|
183
241
|
## Contributing
|
184
242
|
|
@@ -202,6 +260,18 @@ This project uses [Rubocop](https://github.com/bbatsov/rubocop) to enforce code
|
|
202
260
|
|
203
261
|
$ bundle exec rubocop
|
204
262
|
|
263
|
+
### Releasing
|
264
|
+
|
265
|
+
To create a release, first bump the version in `lib/stacker_bee/version.rb`, and commit. Then, build the gem and release it to Rubygems with `rake release`:
|
266
|
+
|
267
|
+
$ rake release
|
268
|
+
stacker_bee 1.2.3 built to pkg/stacker_bee-1.2.3.gem.
|
269
|
+
Tagged v1.2.3.
|
270
|
+
Pushed git commits and tags.
|
271
|
+
Pushed stacker_bee 1.2.3 to rubygems.org.
|
272
|
+
|
273
|
+
We use Bundler's gem tasks to manage releases. See the output of `rake -T` and [Bundler's Rubygems documentation](http://bundler.io/rubygems.html) for more information.
|
274
|
+
|
205
275
|
## Thanks to
|
206
276
|
|
207
277
|
- [Chip Childers](http://github.com/chipchilders) for a [reference implementation of a CloudStack client in Ruby](http://chipchilders.github.io/cloudstack_ruby_client/)
|
data/bin/stacker_bee
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
|
4
|
+
|
2
5
|
require 'optparse'
|
3
6
|
require 'stacker_bee'
|
4
7
|
require 'json'
|
@@ -54,7 +57,7 @@ begin
|
|
54
57
|
options.merge! YAML.load(hash)
|
55
58
|
end
|
56
59
|
unless (%w(api_key secret_key url) - options.keys).empty?
|
57
|
-
puts "Please specify a config file or all of the following: "
|
60
|
+
puts "Please specify a config file or all of the following: " \
|
58
61
|
"--api_key, --secret_key and --url"
|
59
62
|
exit
|
60
63
|
end
|
@@ -68,8 +71,6 @@ if verbose
|
|
68
71
|
puts "StackerBee version #{StackerBee::VERSION}"
|
69
72
|
puts "URL: #{options["url"]}"
|
70
73
|
puts "API key: #{options["api_key"]}"
|
71
|
-
else
|
72
|
-
options['logger'] = Logger.new('/dev/null')
|
73
74
|
end
|
74
75
|
|
75
76
|
client = StackerBee::Client.new(options)
|
data/config.default.yml
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
url: 'http://127.0.0.1:1234/client/api'
|
1
|
+
url: 'http://127.0.0.1:1234/client/api/'
|
2
2
|
api_key: 'MY-KEY-MY-KEY-MY-KEY-MY-KEY-MY-KEY-MY-KEY-MY-KEY-MY-KEY-MY-KEY-MY-KEY-MY-KEY-MY-KEY-MY'
|
3
3
|
secret_key: 'TOP-SECRET-TOP-SECRET-TOP-SECRET-TOP-SECRET-TOP-SECRET-TOP-SECRET-TOP-SECRET-TOP-SECRE'
|
data/lib/stacker_bee/api.rb
CHANGED
@@ -9,8 +9,7 @@ module StackerBee
|
|
9
9
|
|
10
10
|
def initialize(attrs = {})
|
11
11
|
attrs.each_pair do |key, value|
|
12
|
-
|
13
|
-
send(setter, value)
|
12
|
+
send "#{key}=", value
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
@@ -19,7 +18,7 @@ module StackerBee
|
|
19
18
|
end
|
20
19
|
|
21
20
|
def key?(key)
|
22
|
-
endpoints.key?
|
21
|
+
endpoints.key?(uncase(key))
|
23
22
|
end
|
24
23
|
|
25
24
|
protected
|
data/lib/stacker_bee/client.rb
CHANGED
@@ -2,9 +2,23 @@ require "forwardable"
|
|
2
2
|
require "stacker_bee/configuration"
|
3
3
|
require "stacker_bee/api"
|
4
4
|
require "stacker_bee/connection"
|
5
|
-
require "stacker_bee/
|
6
|
-
require "stacker_bee/
|
7
|
-
require "stacker_bee/
|
5
|
+
require "stacker_bee/middleware/environment"
|
6
|
+
require "stacker_bee/middleware/base"
|
7
|
+
require "stacker_bee/middleware/adapter"
|
8
|
+
require "stacker_bee/middleware/endpoint_normalizer"
|
9
|
+
require "stacker_bee/middleware/remove_empty_strings"
|
10
|
+
require "stacker_bee/middleware/cloud_stack_api"
|
11
|
+
require "stacker_bee/middleware/dictionary_flattener"
|
12
|
+
require "stacker_bee/middleware/remove_nils"
|
13
|
+
require "stacker_bee/middleware/format_keys"
|
14
|
+
require "stacker_bee/middleware/format_values"
|
15
|
+
require "stacker_bee/middleware/json_body"
|
16
|
+
require "stacker_bee/middleware/de_namespace"
|
17
|
+
require "stacker_bee/middleware/rashify_response"
|
18
|
+
require "stacker_bee/middleware/clean_response"
|
19
|
+
require "stacker_bee/middleware/raise_on_http_error"
|
20
|
+
require "stacker_bee/middleware/http_status"
|
21
|
+
require "stacker_bee/middleware/console_access"
|
8
22
|
|
9
23
|
module StackerBee
|
10
24
|
class Client
|
@@ -21,6 +35,58 @@ module StackerBee
|
|
21
35
|
:secret_key,
|
22
36
|
:secret_key=
|
23
37
|
|
38
|
+
def middlewares
|
39
|
+
# request
|
40
|
+
builder.use Middleware::ConsoleAccess
|
41
|
+
|
42
|
+
builder.use Middleware::EndpointNormalizer, api: self.class.api
|
43
|
+
builder.use Middleware::RemoveEmptyStrings
|
44
|
+
builder.use Middleware::CloudStackAPI, api_key: configuration.api_key
|
45
|
+
|
46
|
+
configuration.middlewares.call builder
|
47
|
+
|
48
|
+
builder.use Middleware::DictionaryFlattener
|
49
|
+
builder.use Middleware::RemoveNils
|
50
|
+
builder.use Middleware::FormatKeys
|
51
|
+
builder.use Middleware::FormatValues
|
52
|
+
|
53
|
+
# response
|
54
|
+
builder.use Middleware::RaiseOnHTTPError
|
55
|
+
builder.use Middleware::HTTPStatus
|
56
|
+
builder.use Middleware::CleanResponse
|
57
|
+
builder.use Middleware::RashifyResponse
|
58
|
+
builder.use Middleware::DeNamespace
|
59
|
+
builder.use Middleware::JSONBody
|
60
|
+
|
61
|
+
builder.use Middleware::Adapter, connection: connection
|
62
|
+
|
63
|
+
builder.build
|
64
|
+
end
|
65
|
+
|
66
|
+
def builder
|
67
|
+
@builder ||= Builder.new
|
68
|
+
end
|
69
|
+
|
70
|
+
class Builder
|
71
|
+
attr_accessor :middlewares
|
72
|
+
|
73
|
+
def middlewares
|
74
|
+
@middlewares ||= []
|
75
|
+
end
|
76
|
+
|
77
|
+
def use(*middleware_definition)
|
78
|
+
middlewares << middleware_definition
|
79
|
+
end
|
80
|
+
|
81
|
+
def before(*middleware_definition)
|
82
|
+
middlewares.unshift middleware_definition
|
83
|
+
end
|
84
|
+
|
85
|
+
def build
|
86
|
+
middlewares.map { |klass, *args| klass.new(*args) }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
24
90
|
class << self
|
25
91
|
def reset!
|
26
92
|
@api, @api_path, @default_config = nil
|
@@ -28,8 +94,8 @@ module StackerBee
|
|
28
94
|
|
29
95
|
def default_config
|
30
96
|
@default_config ||= {
|
31
|
-
|
32
|
-
middlewares:
|
97
|
+
faraday_middlewares: proc {},
|
98
|
+
middlewares: proc {}
|
33
99
|
}
|
34
100
|
end
|
35
101
|
|
@@ -65,29 +131,45 @@ module StackerBee
|
|
65
131
|
end
|
66
132
|
|
67
133
|
def request(endpoint_name, params = {})
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
134
|
+
env = Middleware::Environment.new(
|
135
|
+
endpoint_name: endpoint_name,
|
136
|
+
api_key: api_key,
|
137
|
+
params: params
|
138
|
+
)
|
139
|
+
|
140
|
+
middleware_app.call(env)
|
141
|
+
|
142
|
+
env.response.body
|
73
143
|
end
|
74
144
|
|
75
|
-
def
|
76
|
-
|
77
|
-
|
145
|
+
def middleware_app
|
146
|
+
@app ||= begin
|
147
|
+
middleware_stack = middlewares
|
148
|
+
|
149
|
+
last_middleware = nil
|
150
|
+
middleware_stack.reverse.each do |middleware|
|
151
|
+
middleware.app = last_middleware
|
152
|
+
last_middleware = middleware
|
153
|
+
end
|
154
|
+
|
155
|
+
middleware_stack.first
|
156
|
+
end
|
78
157
|
end
|
79
158
|
|
80
|
-
def method_missing(
|
81
|
-
|
82
|
-
|
83
|
-
request(endpoint, *args, &block)
|
159
|
+
def method_missing(method_name, *args, &block)
|
160
|
+
if respond_to_via_delegation?(method_name)
|
161
|
+
request(method_name, *args, &block)
|
84
162
|
else
|
85
163
|
super
|
86
164
|
end
|
87
165
|
end
|
88
166
|
|
89
|
-
def respond_to?(
|
90
|
-
|
167
|
+
def respond_to?(method_name, include_private = false)
|
168
|
+
super || respond_to_via_delegation?(method_name)
|
169
|
+
end
|
170
|
+
|
171
|
+
def respond_to_via_delegation?(method_name)
|
172
|
+
!!middleware_app.endpoint_name_for(method_name)
|
91
173
|
end
|
92
174
|
|
93
175
|
protected
|
@@ -1,8 +1,7 @@
|
|
1
1
|
require "faraday"
|
2
2
|
require "uri"
|
3
|
-
require "stacker_bee/
|
4
|
-
require "stacker_bee/
|
5
|
-
require "stacker_bee/middleware/detokenizer"
|
3
|
+
require "stacker_bee/http_middleware/signed_query"
|
4
|
+
require "stacker_bee/http_middleware/detokenizer"
|
6
5
|
|
7
6
|
module StackerBee
|
8
7
|
class ConnectionError < StandardError
|
@@ -13,26 +12,42 @@ module StackerBee
|
|
13
12
|
|
14
13
|
def initialize(configuration)
|
15
14
|
@configuration = configuration
|
16
|
-
|
17
|
-
|
15
|
+
|
16
|
+
uri = URI.parse(self.configuration.url)
|
18
17
|
uri.path = ''
|
19
18
|
fail ConnectionError, "no protocol specified" unless uri.scheme
|
20
|
-
|
19
|
+
|
20
|
+
ssl_verify = !configuration.ssl_verify.nil? ?
|
21
|
+
configuration.ssl_verify : true
|
22
|
+
|
23
|
+
initialize_faraday(url: uri.to_s,
|
24
|
+
ssl: { verify: ssl_verify })
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize_faraday(options)
|
28
|
+
@faraday = Faraday.new(options) do |faraday|
|
29
|
+
faraday.use HTTPMiddleware::Detokenizer
|
30
|
+
faraday.use HTTPMiddleware::SignedQuery, configuration.secret_key
|
31
|
+
|
32
|
+
configuration.faraday_middlewares.call faraday
|
33
|
+
|
34
|
+
unless has_adapter?(faraday.builder.handlers)
|
35
|
+
faraday.adapter Faraday.default_adapter # Net::HTTP
|
36
|
+
end
|
37
|
+
end
|
21
38
|
end
|
22
39
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
faraday.use Middleware::SignedQuery, configuration.secret_key
|
27
|
-
configuration.middlewares.call faraday
|
28
|
-
faraday.adapter Faraday.default_adapter # Net::HTTP
|
40
|
+
def has_adapter?(handlers)
|
41
|
+
handlers.detect do |handler|
|
42
|
+
handler.klass.ancestors.include?(Faraday::Adapter)
|
29
43
|
end
|
30
44
|
end
|
31
45
|
|
32
|
-
def get(
|
33
|
-
@faraday.get(
|
34
|
-
rescue Faraday::Error::ConnectionFailed
|
35
|
-
raise ConnectionError,
|
46
|
+
def get(params, path)
|
47
|
+
@faraday.get(path, params)
|
48
|
+
rescue Faraday::Error::ConnectionFailed => error
|
49
|
+
raise ConnectionError,
|
50
|
+
"Failed to connect to #{configuration.url}, #{error}"
|
36
51
|
end
|
37
52
|
end
|
38
53
|
end
|
@@ -2,7 +2,7 @@ require "faraday"
|
|
2
2
|
require "base64"
|
3
3
|
|
4
4
|
module StackerBee
|
5
|
-
module
|
5
|
+
module HTTPMiddleware
|
6
6
|
class Detokenizer < Faraday::Middleware
|
7
7
|
def call(env)
|
8
8
|
detokenize(env[:url])
|
@@ -10,7 +10,8 @@ module StackerBee
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def detokenize(uri)
|
13
|
-
uri.query =
|
13
|
+
uri.query =
|
14
|
+
StackerBee::Middleware::DictionaryFlattener.detokenize uri.query
|
14
15
|
end
|
15
16
|
end
|
16
17
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module StackerBee
|
2
|
+
module HTTPMiddleware
|
3
|
+
class Graylog < FaradayMiddleware::Graylog
|
4
|
+
def facility
|
5
|
+
'stacker-bee'
|
6
|
+
end
|
7
|
+
|
8
|
+
def short_message(env)
|
9
|
+
message = env[:url].query.scan(/&command=([^&]*)/).join(' ')
|
10
|
+
"StackerBee #{message}".strip
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module StackerBee
|
2
|
+
module Middleware
|
3
|
+
class Adapter < Base
|
4
|
+
def call(env)
|
5
|
+
params = env.request.params.to_a.sort
|
6
|
+
env.raw_response = connection.get(params, env.request.path)
|
7
|
+
env.response.content_type =
|
8
|
+
env.raw_response.env[:response_headers]["content-type"]
|
9
|
+
env.response.body = env.raw_response.body
|
10
|
+
end
|
11
|
+
|
12
|
+
def endpoint_name_for(*)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|