kong-client 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.hound.yml +2 -0
  4. data/.rubocop.yml +360 -0
  5. data/.travis.yml +11 -0
  6. data/CHANGELOG.md +37 -0
  7. data/Gemfile +8 -0
  8. data/LICENSE +191 -0
  9. data/README.md +295 -0
  10. data/Rakefile +5 -0
  11. data/kong.gemspec +24 -0
  12. data/lib/kong/acl.rb +8 -0
  13. data/lib/kong/api.rb +19 -0
  14. data/lib/kong/base.rb +180 -0
  15. data/lib/kong/basic_auth.rb +8 -0
  16. data/lib/kong/belongs_to_api.rb +30 -0
  17. data/lib/kong/belongs_to_consumer.rb +30 -0
  18. data/lib/kong/client.rb +232 -0
  19. data/lib/kong/consumer.rb +103 -0
  20. data/lib/kong/error.rb +10 -0
  21. data/lib/kong/hmac_auth.rb +9 -0
  22. data/lib/kong/jwt.rb +8 -0
  23. data/lib/kong/key_auth.rb +8 -0
  24. data/lib/kong/oauth2_token.rb +14 -0
  25. data/lib/kong/oauth_app.rb +8 -0
  26. data/lib/kong/plugin.rb +31 -0
  27. data/lib/kong/server.rb +23 -0
  28. data/lib/kong/target.rb +61 -0
  29. data/lib/kong/upstream.rb +24 -0
  30. data/lib/kong/util.rb +16 -0
  31. data/lib/kong/version.rb +3 -0
  32. data/lib/kong.rb +20 -0
  33. data/spec/kong/acl_spec.rb +19 -0
  34. data/spec/kong/api_spec.rb +32 -0
  35. data/spec/kong/base_spec.rb +169 -0
  36. data/spec/kong/basic_auth_spec.rb +26 -0
  37. data/spec/kong/client_spec.rb +297 -0
  38. data/spec/kong/consumer_spec.rb +72 -0
  39. data/spec/kong/error_spec.rb +23 -0
  40. data/spec/kong/hmac_auth_spec.rb +26 -0
  41. data/spec/kong/key_auth_spec.rb +26 -0
  42. data/spec/kong/oauth2_token_spec.rb +19 -0
  43. data/spec/kong/oauth_app_spec.rb +19 -0
  44. data/spec/kong/plugin_spec.rb +62 -0
  45. data/spec/kong/server_spec.rb +39 -0
  46. data/spec/kong/target_spec.rb +53 -0
  47. data/spec/kong/upstream_spec.rb +37 -0
  48. data/spec/kong/util_spec.rb +29 -0
  49. data/spec/spec_helper.rb +19 -0
  50. data/tasks/rspec.rake +5 -0
  51. metadata +153 -0
data/README.md ADDED
@@ -0,0 +1,295 @@
1
+ # Kong Client for Ruby
2
+
3
+ [Kong](http://getkong.org) API client for Ruby
4
+
5
+ [![Build Status](https://travis-ci.org/kontena/kong-client-ruby.svg?branch=master)](https://travis-ci.org/kontena/kong-client-ruby)
6
+ [![Gem Version](https://badge.fury.io/rb/kong.svg)](https://badge.fury.io/rb/kong)
7
+
8
+ ## Installation
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'kong'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install kong
20
+
21
+ ## Usage
22
+
23
+ By default Kong client tries to connect `http://localhost:8001` or address provided by environment variable: `KONG_URI='http://your-kong-url:8001'`.
24
+
25
+ You can set it also in your code:
26
+ ```ruby
27
+ require 'kong'
28
+ Kong::Client.api_url = 'http://your-kong-url:8001'
29
+ ```
30
+
31
+ ### Design
32
+
33
+ Kong client follows a design of resoures as Plain Old Ruby objects(tm). For examples to create a new Consumer resource you can do it like this:
34
+
35
+ ```ruby
36
+ consumer = Kong::Consumer.create({ username: 'testuser', custom_id: 'custom_id' })
37
+ ```
38
+
39
+ OR
40
+
41
+ ```ruby
42
+ consumer = Kong::Consumer.new({ username: 'testuser'})
43
+ consumer.custom_id = '12345'
44
+ consumer.save
45
+ ```
46
+
47
+ To find existing consumer:
48
+
49
+ ```ruby
50
+ consumer = Kong::Consumer.find_by_username('testuser')
51
+ consumer = Kong::Consumer.find_by_custom_id('custom_id')
52
+ ```
53
+
54
+ ### All Resources and Actions
55
+
56
+ To see the complete Kong Admin API documentation, please visit: https://getkong.org/docs/0.11.x/admin-api/
57
+
58
+ #### Consumer
59
+
60
+ ```ruby
61
+ Kong::Consumer.list(filters)
62
+ Kong::Consumer.all()
63
+ Kong::Consumer.find(id)
64
+ Kong::Consumer.find_by_*(value)
65
+ Kong::Consumer.find_all_by_*(value)
66
+ Kong::Consumer.create(attributes)
67
+
68
+ consumer = Kong::Consumer.new({ username: 'test-user' })
69
+ consumer.get # reloads resource
70
+ consumer.create
71
+ consumer.update
72
+ consumer.save # requests create_or_update action
73
+ consumer.delete
74
+
75
+ consumer.plugins
76
+ consumer.oauth_apps
77
+ consumer.key_auths
78
+ consumer.basic_auths
79
+ consumer.oauth2_tokens
80
+ ```
81
+
82
+ #### API
83
+
84
+ ```ruby
85
+ Kong::Api.list(filters)
86
+ Kong::Api.all()
87
+ Kong::Api.find(id)
88
+ Kong::Api.find_by_*(value)
89
+ Kong::Api.create(attributes)
90
+
91
+ api = Kong::Api.new({
92
+ name: 'Mockbin',
93
+ hosts: ['example.com'],
94
+ uris: ['/someservice'],
95
+ methods: ['GET'],
96
+ strip_uri: false,
97
+ preserve_host: false,
98
+ upstream_url: 'https://mockbin.com'
99
+ })
100
+ api.get # reloads resource
101
+ api.create
102
+ api.update
103
+ api.save # requests create_or_update action
104
+ api.delete
105
+
106
+ api.plugins
107
+ ```
108
+
109
+ #### Plugin
110
+
111
+ ```ruby
112
+ Kong::Plugin.list(filters)
113
+ Kong::Plugin.all()
114
+ Kong::Plugin.find(id)
115
+ Kong::Plugin.find_by_*(value)
116
+ Kong::Plugin.create(attributes)
117
+
118
+ plugin = Kong::Plugin.new({
119
+ api_id: '5fd1z584-1adb-40a5-c042-63b19db49x21',
120
+ consumer_id: 'a3dX2dh2-1adb-40a5-c042-63b19dbx83hF4',
121
+ name: 'rate-limiting',
122
+ config: {
123
+ minute: 20,
124
+ hour: 500
125
+ }
126
+ })
127
+
128
+ plugin.get # reloads resource
129
+ plugin.create
130
+ plugin.update
131
+ plugin.save # requests create_or_update action
132
+ plugin.delete
133
+ ```
134
+
135
+ #### Upstream and Targets (for load-balanced APIs)
136
+
137
+ ```ruby
138
+ Kong::Upstream.list(filters)
139
+ Kong::Upstream.all()
140
+ Kong::Upstream.find(id)
141
+ Kong::Upstream.find_by_*(value)
142
+ Kong::Upstream.create(attributes)
143
+
144
+ upstream = Kong::Upstream.new({ name: 'myservice' })
145
+
146
+ upstream.get # reloads resource
147
+ upstream.create
148
+ upstream.update
149
+ upstream.save # requests create_or_update action
150
+ upstream.delete
151
+
152
+ upstream.targets # lists active targets
153
+
154
+ # Add targets
155
+ Kong::Target.new({ upstream_id: upstream.id, target: 'appserver1:80' }).save
156
+ Kong::Target.new({ upstream_id: upstream.id, target: 'appserver2:80' }).save
157
+
158
+ # Add the API
159
+ Kong::Api.new({
160
+ ...
161
+ upstream_url: 'http://myservice'
162
+ }).save
163
+ ```
164
+
165
+ #### OAuthApp
166
+
167
+ ```ruby
168
+ Kong::OAuthApp.list(filters)
169
+ Kong::OAuthApp.all()
170
+ Kong::OAuthApp.find(consumer_id)
171
+ Kong::OAuthApp.find_by_*(value)
172
+ Kong::OAuthApp.create(attributes)
173
+
174
+ app = Kong::OAuthApp.new({
175
+ consumer_id: 'a3dX2dh2-1adb-40a5-c042-63b19dbx83hF4',
176
+ redirect_uri: 'http://some-domain/endpoint/'
177
+ })
178
+
179
+ app.create
180
+ app.get # reloads resource
181
+ app.update
182
+ app.save # requests create_or_update action
183
+ app.delete
184
+ ```
185
+
186
+ #### KeyAuth
187
+
188
+ ```ruby
189
+ Kong::KeyAuth.create(attributes)
190
+
191
+ auth = Kong::KeyAuth.new({
192
+ consumer_id: 'a3dX2dh2-1adb-40a5-c042-63b19dbx83hF4',
193
+ })
194
+
195
+ auth.create
196
+ auth.get # reloads resource
197
+ auth.update
198
+ auth.save # requests create_or_update action
199
+ auth.delete
200
+ ```
201
+
202
+ #### BasicAuth
203
+
204
+ ```ruby
205
+ Kong::BasicAuth.create(attributes)
206
+
207
+ auth = Kong::BasicAuth.new({
208
+ consumer_id: 'a3dX2dh2-1adb-40a5-c042-63b19dbx83hF4',
209
+ username: 'user123',
210
+ password: 'secret'
211
+ })
212
+
213
+ auth.create
214
+ auth.get # reloads resource
215
+ auth.update
216
+ auth.save # requests create_or_update action
217
+ auth.delete
218
+ ```
219
+
220
+ #### OAuth2Token
221
+
222
+ ```ruby
223
+ token = Kong::OAuth2Token.find_by_access_token('SOME-TOKEN')
224
+
225
+ token = Kong::OAuth2Token.new({
226
+ credential_id: 'KONG-APPLICATION-ID',
227
+ token_type: 'bearer',
228
+ access_token: 'SOME-TOKEN',
229
+ refresh_token: 'SOME-TOKEN',
230
+ expires_in: 3600
231
+ })
232
+
233
+ token.create
234
+ token.update
235
+ token.save # requests create_or_update action
236
+ token.delete
237
+
238
+ token.oauth_app
239
+ ```
240
+
241
+ #### JWT
242
+
243
+ ```ruby
244
+
245
+ jwt = Kong::JWT.new({
246
+ consumer_id: 'a3dX2dh2-1adb-40a5-c042-63b19dbx83hF4',
247
+ key: 'a36c3049b36249a3c9f8891cb127243c',
248
+ secret: 'e71829c351aa4242c2719cbfbe671c09'
249
+ })
250
+
251
+ jwt.create
252
+ jwt.update
253
+ jwt.save # requests create_or_update action
254
+ jwt.delete
255
+
256
+ consumer = Kong::Consumer.find_by_username('testuser')
257
+ consumer.jwts
258
+ ```
259
+
260
+ #### ACL
261
+
262
+ ```ruby
263
+
264
+ acl = Kong::Acl.new({
265
+ consumer_id: 'a3dX2dh2-1adb-40a5-c042-63b19dbx83hF4',
266
+ group: 'group1',
267
+ tags: ["tag1", "tag2"]
268
+ })
269
+
270
+ acl.create
271
+ acl.update
272
+ acl.save # requests create_or_update action
273
+ acl.delete
274
+
275
+ consumer = Kong::Consumer.find_by_username('testuser')
276
+ consumer.acls
277
+ ```
278
+
279
+ #### Server Information
280
+
281
+ ```ruby
282
+ Kong::Server.info
283
+ Kong::Server.version
284
+ Kong::Server.status
285
+ Kong::Server.cluster
286
+ Kong::Server.remove_node(node_name)
287
+ ```
288
+
289
+ ## Contributing
290
+
291
+ 1. Fork it ( https://github.com/ResultadosDigitais/kong-client-ruby/fork )
292
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
293
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
294
+ 4. Push to the branch (`git push origin my-new-feature`)
295
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ Dir.glob('tasks/*.rake').each { |r| import r }
4
+
5
+ task :default => :spec
data/kong.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kong/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "kong-client"
8
+ spec.version = Kong::VERSION
9
+ spec.authors = ["Ecosystem API Team"]
10
+ spec.email = ["ecosystem-apis@rdstation.com", "renan.porto@rdstation.com", "rogerio.angeliski@rdstation.com"]
11
+ spec.summary = %q{A Ruby client for the Kong API }
12
+ spec.description = %q{A Ruby client for the Kong API}
13
+ spec.homepage = "https://github.com/ResultadosDigitais/kong-client-ruby"
14
+ spec.license = "Apache-2.0"
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.required_ruby_version = ">= 2.0.0"
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.17"
22
+ spec.add_development_dependency "rake", "~> 12.0"
23
+ spec.add_runtime_dependency "excon"
24
+ end
data/lib/kong/acl.rb ADDED
@@ -0,0 +1,8 @@
1
+ module Kong
2
+ class Acl
3
+ include Base
4
+ include BelongsToConsumer
5
+ ATTRIBUTE_NAMES = %w(id group tags consumer_id).freeze
6
+ API_END_POINT = "/acls/".freeze
7
+ end
8
+ end
data/lib/kong/api.rb ADDED
@@ -0,0 +1,19 @@
1
+ module Kong
2
+ class Api
3
+ include Base
4
+
5
+ ATTRIBUTE_NAMES = %w(
6
+ id name request_host request_path strip_request_path
7
+ hosts uris strip_uri preserve_host upstream_url retries
8
+ upstream_connect_timeout upstream_send_timeout upstream_read_timeout
9
+ https_only http_if_terminated methods
10
+ ).freeze
11
+ API_END_POINT = '/apis/'.freeze
12
+
13
+ ##
14
+ # @return [Array<Kong::Plugin>]
15
+ def plugins
16
+ Plugin.list({ api_id: self.id })
17
+ end
18
+ end
19
+ end
data/lib/kong/base.rb ADDED
@@ -0,0 +1,180 @@
1
+ module Kong
2
+ module Base
3
+ module ClassMethods
4
+
5
+ # List resources
6
+ # @return [Array]
7
+ def list(params = {})
8
+ result = []
9
+ json_data = Client.instance.get(self::API_END_POINT, params)
10
+ if json_data['data']
11
+ json_data['data'].each do |instance|
12
+ result << self.new(instance)
13
+ end
14
+ end
15
+ result
16
+ end
17
+
18
+ alias_method :all, :list
19
+
20
+ # Create resource
21
+ # @param [Hash] attributes
22
+ def create(attributes = {})
23
+ self.new(attributes).create
24
+ end
25
+
26
+ # Find resource
27
+ # @param [String] id
28
+ def find(id)
29
+ self.new.get(id)
30
+ end
31
+
32
+ def method_missing(method, *arguments, &block)
33
+ if method.to_s.start_with?('find_by_')
34
+ attribute = method.to_s.sub('find_by_', '')
35
+ if self.attribute_names.include?(attribute)
36
+ self.list({ attribute => arguments[0] })[0]
37
+ else
38
+ super
39
+ end
40
+ elsif method.to_s.start_with?('find_all_by_')
41
+ attribute = method.to_s.sub('find_all_by_', '')
42
+ if self.attribute_names.include?(attribute)
43
+ self.list({ attribute => arguments[0] })
44
+ else
45
+ super
46
+ end
47
+ else
48
+ super
49
+ end
50
+ end
51
+
52
+ def respond_to?(method, include_private = false)
53
+ if method.to_s.start_with?('find_by_')
54
+ attribute = method.to_s.sub('find_by_', '')
55
+ if self.attribute_names.include?(attribute)
56
+ return true
57
+ else
58
+ super
59
+ end
60
+ elsif method.to_s.start_with?('find_all_by_')
61
+ attribute = method.to_s.sub('find_all_by_', '')
62
+ if self.attribute_names.include?(attribute)
63
+ return true
64
+ else
65
+ super
66
+ end
67
+ else
68
+ super
69
+ end
70
+ end
71
+ end
72
+
73
+ attr_accessor :attributes, :api_end_point
74
+
75
+ def self.included(base)
76
+ base.extend(ClassMethods)
77
+
78
+ base.send(:define_singleton_method, :attribute_names) do
79
+ base::ATTRIBUTE_NAMES
80
+ end
81
+
82
+ base.send(:define_method, :init_api_end_point) do
83
+ @api_end_point = base::API_END_POINT
84
+ end
85
+ end
86
+
87
+ ##
88
+ # @param [Hash] attributes
89
+ def initialize(attributes = {})
90
+ init_api_end_point
91
+ init_attributes(attributes)
92
+ end
93
+
94
+ # Get Kong API client
95
+ # @return [Kong::Client]
96
+ def client
97
+ Client.instance
98
+ end
99
+
100
+ # Get resource
101
+ # @param [String] key
102
+ def get(key = nil)
103
+ key = self.id if key.nil?
104
+ path = @api_end_point + key
105
+ response = client.get(path) rescue nil
106
+ return nil if response.nil?
107
+ init_attributes(response)
108
+ self
109
+ end
110
+
111
+ # Delete resource
112
+ def delete
113
+ client.delete("#{@api_end_point}#{self.id}")
114
+ end
115
+
116
+ def new?
117
+ self.id.nil?
118
+ end
119
+
120
+ # Save resource to Kong
121
+ def save
122
+ create_or_update
123
+ end
124
+
125
+ # Create resource
126
+ def create
127
+ headers = { 'Content-Type' => 'application/json' }
128
+ response = client.post(@api_end_point, attributes, nil, headers)
129
+ init_attributes(response)
130
+ self
131
+ end
132
+
133
+ # Create or update resource
134
+ # Data is sent to Kong in JSON format and HTTP PUT request is used
135
+ def create_or_update
136
+ headers = { 'Content-Type' => 'application/json' }
137
+ response = client.put(@api_end_point, attributes, nil, headers)
138
+ init_attributes(response)
139
+ self
140
+ end
141
+
142
+ # Update resource
143
+ def update
144
+ headers = { 'Content-Type' => 'application/json' }
145
+ response = client.patch("#{@api_end_point}#{self.id}", attributes, nil, headers)
146
+ init_attributes(response)
147
+ self
148
+ end
149
+
150
+ def method_missing(method, *arguments, &block)
151
+ if self.class.attribute_names.include?(method.to_s)
152
+ @attributes[method.to_s]
153
+ elsif method.to_s.end_with?('=') && self.class.attribute_names.include?(attribute = method.to_s.split('=').first)
154
+ @attributes[attribute] = arguments[0]
155
+ else
156
+ super
157
+ end
158
+ end
159
+
160
+ def respond_to?(method, include_private = false)
161
+ if self.class.attribute_names.include?(method.to_s.split('=')[0])
162
+ true
163
+ else
164
+ super
165
+ end
166
+ end
167
+
168
+ private
169
+
170
+ def init_attributes(attributes)
171
+ @attributes = {}
172
+ attributes.each do |key, value|
173
+ @attributes[key.to_s] = value
174
+ end
175
+ use_consumer_end_point if respond_to?(:use_consumer_end_point)
176
+ use_api_end_point if respond_to?(:use_api_end_point)
177
+ use_upstream_end_point if respond_to?(:use_upstream_end_point)
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,8 @@
1
+ module Kong
2
+ class BasicAuth
3
+ include Base
4
+ include BelongsToConsumer
5
+ ATTRIBUTE_NAMES = %w(id username password consumer_id).freeze
6
+ API_END_POINT = "/basic-auth/".freeze
7
+ end
8
+ end
@@ -0,0 +1,30 @@
1
+ module Kong
2
+ module BelongsToApi
3
+ attr_accessor :api
4
+
5
+ # Convert API end point relative to Kong API resource
6
+ def use_api_end_point
7
+ self.api_end_point = "/apis/#{self.api_id}#{self.class::API_END_POINT}" if self.api_id
8
+ end
9
+
10
+ # Get Api resource
11
+ # @return [Kong::Api]
12
+ def api
13
+ @api ||= Api.find(self.api_id)
14
+ end
15
+
16
+ # Set Api resource
17
+ # @param [Kong::Api] api
18
+ def api=(api)
19
+ @api = api
20
+ self.api_id = api.id
21
+ end
22
+
23
+ # Set Api id
24
+ # @param [String] id
25
+ def api_id=(id)
26
+ super(id)
27
+ use_api_end_point
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ module Kong
2
+ module BelongsToConsumer
3
+ attr_accessor :consumer
4
+
5
+ # Convert API end point relative to Kong Consumer resource
6
+ def use_consumer_end_point
7
+ self.api_end_point = "/consumers/#{self.consumer_id}#{self.class::API_END_POINT}" if self.consumer_id
8
+ end
9
+
10
+ # Get Consumer resource
11
+ # @return [Kong::Consumer]
12
+ def consumer
13
+ @consumer ||= Consumer.find(self.consumer_id)
14
+ end
15
+
16
+ # Set Consumer resource
17
+ # @param [Kong::Consumer] consumer
18
+ def consumer=(consumer)
19
+ @consumer = consumer
20
+ self.consumer_id = consumer.id
21
+ end
22
+
23
+ # Set Consumer id
24
+ # @param [String] id
25
+ def consumer_id=(id)
26
+ super(id)
27
+ use_consumer_end_point
28
+ end
29
+ end
30
+ end