pisoni 1.23.1

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 (52) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +9 -0
  3. data/Gemfile +16 -0
  4. data/LICENSE +202 -0
  5. data/Makefile +73 -0
  6. data/NOTICE +15 -0
  7. data/README.md +47 -0
  8. data/Rakefile +27 -0
  9. data/lib/3scale/core/alert_limit.rb +32 -0
  10. data/lib/3scale/core/api_client/attributes.rb +56 -0
  11. data/lib/3scale/core/api_client/collection.rb +19 -0
  12. data/lib/3scale/core/api_client/operations.rb +233 -0
  13. data/lib/3scale/core/api_client/resource.rb +52 -0
  14. data/lib/3scale/core/api_client/support.rb +55 -0
  15. data/lib/3scale/core/api_client.rb +5 -0
  16. data/lib/3scale/core/application.rb +67 -0
  17. data/lib/3scale/core/application_key.rb +34 -0
  18. data/lib/3scale/core/application_referrer_filter.rb +33 -0
  19. data/lib/3scale/core/errors.rb +130 -0
  20. data/lib/3scale/core/event.rb +26 -0
  21. data/lib/3scale/core/logger.rb +12 -0
  22. data/lib/3scale/core/metric.rb +32 -0
  23. data/lib/3scale/core/service.rb +82 -0
  24. data/lib/3scale/core/service_error.rb +34 -0
  25. data/lib/3scale/core/service_token.rb +39 -0
  26. data/lib/3scale/core/transaction.rb +26 -0
  27. data/lib/3scale/core/usage_limit.rb +40 -0
  28. data/lib/3scale/core/user.rb +47 -0
  29. data/lib/3scale/core/utilization.rb +28 -0
  30. data/lib/3scale/core/version.rb +5 -0
  31. data/lib/3scale/core.rb +63 -0
  32. data/lib/3scale_core.rb +1 -0
  33. data/lib/pisoni.rb +5 -0
  34. data/pisoni.gemspec +43 -0
  35. data/spec/alert_limit_spec.rb +72 -0
  36. data/spec/application_key_spec.rb +97 -0
  37. data/spec/application_referrer_filter_spec.rb +57 -0
  38. data/spec/application_spec.rb +188 -0
  39. data/spec/event_spec.rb +82 -0
  40. data/spec/metric_spec.rb +115 -0
  41. data/spec/private_endpoints/event.rb +9 -0
  42. data/spec/private_endpoints/service_error.rb +10 -0
  43. data/spec/private_endpoints/transaction.rb +16 -0
  44. data/spec/service_error_spec.rb +128 -0
  45. data/spec/service_spec.rb +159 -0
  46. data/spec/service_token_spec.rb +121 -0
  47. data/spec/spec_helper.rb +15 -0
  48. data/spec/transaction_spec.rb +71 -0
  49. data/spec/usagelimit_spec.rb +52 -0
  50. data/spec/user_spec.rb +164 -0
  51. data/spec/utilization_spec.rb +113 -0
  52. metadata +182 -0
@@ -0,0 +1,233 @@
1
+ module ThreeScale
2
+ module Core
3
+ module APIClient
4
+ module Operations
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ base.prepend Initializer
8
+ end
9
+
10
+ private
11
+
12
+ attr_accessor :persisted
13
+
14
+ def api_save(api_options = {})
15
+ if persisted
16
+ ret = self.class.api_do_put attributes, api_options
17
+ else
18
+ ret = self.class.api_do_post attributes, api_options
19
+ self.persisted = ret[:ok]
20
+ end
21
+ if ret[:ok]
22
+ update_attributes(ret[:attributes])
23
+ self.dirty = false
24
+ true
25
+ else
26
+ false
27
+ end
28
+ end
29
+
30
+ def api_delete(api_options = {})
31
+ ok = self.class.api_delete attributes, api_options
32
+ self.persisted = false if ok
33
+ ok
34
+ end
35
+
36
+ module Initializer
37
+ def initialize(*args)
38
+ self.persisted = false
39
+ super
40
+ end
41
+ end
42
+
43
+ module ClassMethods
44
+ include ThreeScale::Core::Logger
45
+
46
+ # CRUD methods
47
+
48
+ def api_create(attributes, api_options = {}, &blk)
49
+ api_create_object :api_do_post, attributes, api_options, &blk
50
+ end
51
+ alias_method :api_save, :api_create
52
+
53
+ def api_read(attributes, api_options = {}, &blk)
54
+ api_create_object :api_do_get, attributes, api_options, &blk
55
+ end
56
+ alias_method :api_load, :api_read
57
+
58
+ def api_update(attributes, api_options = {}, &blk)
59
+ api_create_object :api_do_put, attributes, api_options, &blk
60
+ end
61
+
62
+ def api_delete(attributes, api_options = {}, &blk)
63
+ api_do_delete(attributes, api_options, &blk)[:ok]
64
+ end
65
+
66
+ # Helpers
67
+
68
+ def api_do_get(attributes, api_options = {}, &blk)
69
+ blk = filter_404 if blk.nil?
70
+ api :get, attributes, api_options, &blk
71
+ end
72
+
73
+ def api_do_put(attributes, api_options = {}, &blk)
74
+ api :put, attributes, api_options, &blk
75
+ end
76
+
77
+ def api_do_post(attributes, api_options = {}, &blk)
78
+ api :post, attributes, api_options, &blk
79
+ end
80
+
81
+ def api_do_delete(attributes, api_options = {}, &blk)
82
+ blk = filter_404 if blk.nil?
83
+ api :delete, attributes, api_options, &blk
84
+ end
85
+
86
+ def api_create_object(method, attributes, api_options = {}, &blk)
87
+ ret = send method, attributes, api_options.merge(build: true), &blk
88
+ ret[:object].send :persisted=, true if ret[:object]
89
+ ret[:object]
90
+ end
91
+
92
+ def filter_404
93
+ @filter_404_proc ||= proc do |result|
94
+ result[:response].status != 404
95
+ end
96
+ end
97
+ private :filter_404
98
+
99
+ def api_http(method, uri, attributes)
100
+ # GET, DELETE and HEAD are treated differently by Faraday. We need
101
+ # to set the body in there.
102
+ if method == :get or method == :delete
103
+ Core.faraday.send method, uri do |req|
104
+ req.body = attributes.to_json
105
+ end
106
+ else
107
+ Core.faraday.send method, uri, attributes.to_json
108
+ end
109
+ rescue Faraday::Error::ClientError, SystemCallError => e
110
+ raise ConnectionError, e
111
+ end
112
+ private :api_http
113
+
114
+ def api_parse_json(response)
115
+ raise JSONError, "unacceptable content-type #{response.headers['content-type']} (#{response.headers['server']}): #{response.body[0,512]}" unless response.headers['content-type'].include? 'json'
116
+ parse_json(response.body)
117
+ rescue JSON::ParserError => e
118
+ # you can obtain the error message with
119
+ # rescue JSONError => e
120
+ # puts(e.cause ? e.cause.message : e.message)
121
+ #
122
+ # e.message will always return a trimmed (bounded) message, while
123
+ # e.cause.message, when a cause is present, may return a long
124
+ # message including the whole response body.
125
+ raise JSONError, e
126
+ end
127
+ private :api_parse_json
128
+
129
+ # Our current HTTP client (Faraday wrapper) does not expose HTTP
130
+ # version, which would be convenient for determining whether we have
131
+ # a keep-alive connection. For that we would probably need to write a
132
+ # Faraday middleware.
133
+ #
134
+ # Anyway, in HTTP/1.0 we are not guaranteed to have a Connection:
135
+ # response field, so it does not always use Connection: close (they
136
+ # are closed by default). HTTP/1.1 OTOH does keep-alive by default, so
137
+ # it will close the connection when actually sending a Connection:
138
+ # close. So:
139
+ # HTTP/1.1: KA if no Connection field or if present and not 'close'
140
+ # HTTP/1.0: no KA unless Connection: keep-alive.
141
+ # XXX UNDEFINED: no Connection header, depends on HTTP version:
142
+ # 1.1: keep-alive
143
+ # 1.0: close
144
+ def keep_alive_response?(response)
145
+ response.headers['connection'] != 'close'
146
+ end
147
+ private :keep_alive_response?
148
+
149
+ def api_response_inspect(method, uri, response, attributes, after, before)
150
+ "<#{keep_alive_response?(response) ? '=' : '/'}= #{response.status} #{method.upcase} #{uri} [#{attributes}] (#{after - before})"
151
+ end
152
+ private :api_response_inspect
153
+
154
+ # api method - talk with the remote HTTP service
155
+ #
156
+ # method - HTTP method to use
157
+ # attributes - HTTP request body parameters
158
+ # options:
159
+ # :prefix => string/symbol - an attribute prefix, '' for none, else default_prefix
160
+ # :rprefix => string/symbol - same as above, but for parsing responses
161
+ # :uri => string - sets the uri for this particular request
162
+ # :raise => boolean - raise APIError on error, defaults to true
163
+ # :build => boolean - create a new object with response's JSON if response is ok, defaults to false
164
+ # block (optional) - receives two params: http status code and attributes
165
+ # this block if present handles error responses, invalidates :raise option,
166
+ # you should return an array of [raise (boolean), built_object (if any) or nil]
167
+ #
168
+ # returns:
169
+ # a hash consisting of:
170
+ # :response - http response
171
+ # :response_json - http response parsed JSON
172
+ # :ok - whether the response code was ok when related to the http method
173
+ # :object - nil or the object created if applicable
174
+ # :attributes - JSON parsed attributes of the response's body
175
+
176
+ def api(method, attributes, options = {})
177
+ prefix = options.fetch(:prefix, default_prefix)
178
+ attributes = { prefix => attributes } unless prefix.empty? or attributes.empty?
179
+ uri = options.fetch(:uri, default_uri)
180
+
181
+ logger.debug do
182
+ "==> #{method.upcase} #{uri} [#{attributes}]"
183
+ end
184
+
185
+ before = Time.now
186
+ response = api_http method, uri, attributes
187
+ after = Time.now
188
+
189
+ ok = status_ok? method, uri, response
190
+
191
+ response_json = begin
192
+ api_parse_json(response)
193
+ rescue JSONError => e
194
+ logger.error do
195
+ "#{api_response_inspect(method, uri, response, '', after, before)} - #{e.message}"
196
+ end
197
+ raise e
198
+ end
199
+
200
+ ret = { response: response, response_json: response_json, ok: ok }
201
+
202
+ logger.debug do
203
+ api_response_inspect(method, uri, response, response_json, after, before)
204
+ end
205
+
206
+ if ok
207
+ prefix = options.fetch(:rprefix, prefix)
208
+ attributes = response_json.fetch(prefix, nil) unless prefix.empty?
209
+
210
+ ret[:object] = if attributes and options[:build]
211
+ new attributes
212
+ else
213
+ nil
214
+ end
215
+ else
216
+ # something went wrong. let's either let the user fix it, and ask him to provide us
217
+ # with directions returned from block or just use :raise
218
+ do_raise = if block_given?
219
+ yield(ret)
220
+ else
221
+ options.fetch(:raise, true)
222
+ end
223
+ raise APIError.new(method, uri, response, response_json) if do_raise
224
+ end
225
+
226
+ ret[:attributes] = attributes
227
+ ret
228
+ end
229
+ end
230
+ end
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,52 @@
1
+ module ThreeScale
2
+ module Core
3
+ module APIClient
4
+ Error = Class.new StandardError
5
+
6
+ class APIError < Error
7
+ attr_reader :method, :uri, :response, :attributes
8
+
9
+ def initialize(method, uri, response, attributes)
10
+ @method, @uri, @response, @attributes = method, uri, response, attributes
11
+ super "#{self.class}: #{response.status} #{method.upcase} #{uri}, attributes:" \
12
+ " #{attributes.inspect}, response.body: #{response.body[0,256]}"
13
+ end
14
+ end
15
+
16
+ class APIServerError < APIError
17
+ def initialize(method, uri, response, attributes = {})
18
+ super
19
+ end
20
+ end
21
+
22
+ APIInternalServerError = Class.new APIServerError
23
+ APIBadGatewayError = Class.new APIServerError
24
+ APIServiceUnavailableError = Class.new APIServerError
25
+
26
+ class ConnectionError < Error
27
+ def initialize(error)
28
+ super "#{self.class}: #{error.message}"
29
+ end
30
+ end
31
+
32
+ class JSONError < Error
33
+ def initialize(error)
34
+ msg = error.respond_to?(:message) ? error.message : error
35
+ super "#{self.class}: #{msg[0,512]}"
36
+ end
37
+ end
38
+
39
+ class Resource
40
+
41
+ include Attributes
42
+ include Support
43
+ include Operations
44
+
45
+ def initialize(attributes)
46
+ update_attributes(attributes)
47
+ end
48
+
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,55 @@
1
+ module ThreeScale
2
+ module Core
3
+ module APIClient
4
+ module Support
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def status_ok?(method, uri, response)
11
+ status = response.status
12
+ # handle server errors here, since we will not be expecting JSON
13
+ raise internal_api_error(status).new(method, uri, response) if status >= 500
14
+ case method
15
+ when :post then [200, 201]
16
+ when :put then [200, 204, 202]
17
+ when :delete then [200, 204, 202]
18
+ else [200]
19
+ end.include? status
20
+ end
21
+
22
+ def parse_json(body)
23
+ JSON.parse(body, symbolize_names: true)
24
+ end
25
+
26
+ def default_uri(uri = nil)
27
+ return @default_uri ||= "/internal/#{self.to_s.split(':').last.downcase!}s/" unless uri
28
+ @default_uri = uri
29
+ end
30
+
31
+ def default_http_error_exception(exception = nil)
32
+ return @default_http_error_exception ||= APIError unless exception
33
+ @default_http_error_exception = exception
34
+ end
35
+
36
+ def default_prefix(prefix = nil)
37
+ return @default_prefix ||= self.to_s.split(':').last.downcase.to_sym unless prefix
38
+ @default_prefix = prefix
39
+ end
40
+
41
+ private
42
+
43
+ def internal_api_error(status)
44
+ case status
45
+ when 503 then APIServiceUnavailableError
46
+ when 502 then APIBadGatewayError
47
+ when 500 then APIInternalServerError
48
+ else APIServerError
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,5 @@
1
+ require '3scale/core/api_client/attributes'
2
+ require '3scale/core/api_client/support'
3
+ require '3scale/core/api_client/operations'
4
+ require '3scale/core/api_client/resource'
5
+ require '3scale/core/api_client/collection'
@@ -0,0 +1,67 @@
1
+ module ThreeScale
2
+ module Core
3
+ class Application < APIClient::Resource
4
+ ## added the :user_required to distinguish between types of application:
5
+ ## false is the default value, do not expect user_id or ignore it if it happends
6
+ ## true, the user_id must be defined + the user of the service (service_id#user_id),
7
+ ## user_id is typically the UUID of a cellphone, or the twitter account
8
+ attributes :service_id, :id, :state, :plan_id, :plan_name,
9
+ :redirect_url, :user_required
10
+
11
+ default_uri '/internal/services/'
12
+
13
+ def self.base_uri(service_id)
14
+ "#{default_uri}#{service_id}/applications/"
15
+ end
16
+ private_class_method :base_uri
17
+
18
+ def self.app_uri(service_id, id)
19
+ "#{base_uri(service_id)}#{id}"
20
+ end
21
+ private_class_method :app_uri
22
+
23
+ def self.key_uri(service_id, key)
24
+ "#{base_uri(service_id)}key/#{key}"
25
+ end
26
+ private_class_method :key_uri
27
+
28
+ def self.load(service_id, id)
29
+ api_read({}, uri: app_uri(service_id, id))
30
+ end
31
+
32
+ def self.save(attributes)
33
+ service_id, id = attributes.fetch(:service_id), attributes.fetch(:id)
34
+ api_update attributes, uri: app_uri(service_id, id)
35
+ end
36
+
37
+ def self.delete(service_id, id)
38
+ api_delete({}, uri: app_uri(service_id, id))
39
+ end
40
+
41
+ def save
42
+ api_save uri: self.class.send(:app_uri, service_id, id)
43
+ end
44
+
45
+ def user_required?
46
+ user_required
47
+ end
48
+
49
+ # XXX Old API. Just returns an id. DEPRECATED.
50
+ def self.load_id_by_key(service_id, user_key)
51
+ ret = api_do_get({}, uri: key_uri(service_id, user_key))
52
+ ret[:ok] ? ret[:attributes][:id] : nil
53
+ end
54
+
55
+ def self.save_id_by_key(service_id, user_key, id)
56
+ raise ApplicationHasInconsistentData.new(id, user_key) if (service_id.nil? || id.nil? || user_key.nil? || service_id=="" || id=="" || user_key=="")
57
+ ret = api_do_put({}, uri: "#{app_uri(service_id, id)}/key/#{user_key}")
58
+ ret[:ok]
59
+ end
60
+
61
+ def self.delete_id_by_key(service_id, user_key)
62
+ api_delete({}, uri: key_uri(service_id, user_key))
63
+ end
64
+
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,34 @@
1
+ module ThreeScale
2
+ module Core
3
+ class ApplicationKey < APIClient::Resource
4
+ attributes :service_id, :application_id, :value
5
+
6
+ default_uri '/internal/services/'
7
+
8
+ def self.load_all(service_id, application_id)
9
+ results = api_do_get({}, rprefix: :application_keys, uri: application_key_uri(service_id, application_id))
10
+ return [] if results[:attributes].is_a?(Hash) && results[:attributes][:error]
11
+
12
+ results[:attributes].map { |attrs| new(attrs) }
13
+ end
14
+
15
+ def self.save(service_id, application_id, value)
16
+ api_save({value: value}, uri: application_key_uri(service_id, application_id), prefix: :application_key)
17
+ end
18
+
19
+ def self.delete(service_id, application_id, value)
20
+ api_delete({}, uri: application_key_uri(service_id, application_id, value))
21
+ end
22
+
23
+ def self.base_uri(service_id, application_id)
24
+ "#{default_uri}#{service_id}/applications/#{application_id}/keys/"
25
+ end
26
+ private_class_method :base_uri
27
+
28
+ def self.application_key_uri(service_id, application_id, value = nil)
29
+ "#{base_uri(service_id, application_id)}#{value}"
30
+ end
31
+ private_class_method :application_key_uri
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,33 @@
1
+ require 'base64'
2
+
3
+ module ThreeScale
4
+ module Core
5
+ class ApplicationReferrerFilter < APIClient::Resource
6
+ default_uri '/internal/services/'
7
+
8
+ def self.load_all(service_id, application_id)
9
+ results = api_do_get({},
10
+ rprefix: :referrer_filters,
11
+ uri: base_uri(service_id, application_id))
12
+ results[:attributes]
13
+ end
14
+
15
+ def self.save(service_id, application_id, value)
16
+ result = api_do_post({ referrer_filter: value },
17
+ uri: base_uri(service_id, application_id),
18
+ prefix: '')
19
+ result[:response_json][:referrer_filter]
20
+ end
21
+
22
+ def self.delete(service_id, application_id, value)
23
+ encoded_value = Base64.urlsafe_encode64(value)
24
+ api_delete({}, uri: base_uri(service_id, application_id) + "/#{encoded_value}")
25
+ end
26
+
27
+ def self.base_uri(service_id, application_id)
28
+ "#{default_uri}#{service_id}/applications/#{application_id}/referrer_filters"
29
+ end
30
+ private_class_method :base_uri
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,130 @@
1
+ module ThreeScale
2
+ module Core
3
+ class UnknownAPIEndpoint < RuntimeError; end
4
+
5
+ class Error < RuntimeError
6
+ def to_xml(options = {})
7
+ xml = Builder::XmlMarkup.new
8
+ xml.instruct! unless options[:skip_instruct]
9
+ xml.error(message, :code => code)
10
+
11
+ xml.target!
12
+ end
13
+
14
+ def code
15
+ self.class.code
16
+ end
17
+
18
+ def self.code
19
+ underscore(name[/[^:]*$/])
20
+ end
21
+
22
+ # TODO: move this over to some utility module.
23
+ def self.underscore(string)
24
+ # Code stolen from ActiveSupport
25
+ string.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
26
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
27
+ downcase
28
+ end
29
+ end
30
+
31
+ NotFound = Class.new(Error)
32
+ Invalid = Class.new(Error)
33
+
34
+ class ApplicationHasInconsistentData < Error
35
+ def initialize(id, user_key)
36
+ super %(Application id="#{id}" with user_key="#{user_key}" has inconsistent data and could not be saved)
37
+ end
38
+ end
39
+
40
+ class ServiceRequiresDefaultUserPlan < Error
41
+ def initialize
42
+ super %(Services without the need for registered users require a default user plan)
43
+ end
44
+ end
45
+
46
+ class ServiceIsDefaultService < Error
47
+ def initialize(id = nil)
48
+ super %(Service id="#{id}" is the default service, must be removed forcefully or make it not default before removal)
49
+ end
50
+ end
51
+
52
+ class ServiceRequiresRegisteredUser < Error
53
+ def initialize(id = nil)
54
+ super %(Service id="#{id}" requires users to be registered before hand)
55
+ end
56
+ end
57
+
58
+ class UserRequiresUsername < Error
59
+ def initialize
60
+ super %(User requires username)
61
+ end
62
+ end
63
+
64
+ class UserRequiresServiceId < Error
65
+ def initialize
66
+ super %(User requires a service id)
67
+ end
68
+ end
69
+
70
+ class UserRequiresValidServiceId < Error
71
+ def initialize(id)
72
+ super %(Service id #{id} is invalid, user requires a valid id)
73
+ end
74
+ end
75
+
76
+ class UserRequiresDefinedPlan < Error
77
+ def initialize(plan_id, plan_name)
78
+ super %(User requires a defined plan, plan id: #{plan_id} plan name: #{plan_name})
79
+ end
80
+ end
81
+
82
+ class InvalidProviderKeys < Error
83
+ def initialize
84
+ super %(Provider keys are not valid, must be not nil and different)
85
+ end
86
+ end
87
+
88
+ class ProviderKeyExists < Error
89
+ def initialize(key)
90
+ super %(Provider key="#{key}" already exists)
91
+ end
92
+ end
93
+
94
+ class ProviderKeyNotFound < Error
95
+ def initialize(key)
96
+ super %(Provider key="#{key}" does not exist)
97
+ end
98
+ end
99
+
100
+ class UsageLimitInvalidPeriods < Error
101
+ def initialize(periods)
102
+ super %(UsageLimit invalid periods #{periods})
103
+ end
104
+ end
105
+
106
+ class InvalidPerPage < Error
107
+ def initialize
108
+ super %(per_page is not valid, must be positive)
109
+ end
110
+ end
111
+
112
+ class ServiceTokenRequiresServiceId < Error
113
+ def initialize
114
+ super 'ServiceToken is invalid, service ID cannot be blank'
115
+ end
116
+ end
117
+
118
+ class ServiceTokenRequiresToken < Error
119
+ def initialize
120
+ super 'ServiceToken is invalid, token cannot be blank'
121
+ end
122
+ end
123
+
124
+ class ServiceTokenMissingParameter < Error
125
+ def initialize(error_text)
126
+ super %(ServiceToken is invalid, #{error_text})
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,26 @@
1
+ module ThreeScale
2
+ module Core
3
+ class Event < APIClient::Resource
4
+ attributes :id, :type, :timestamp, :object
5
+
6
+ def self.load_all
7
+ results = api_do_get({}, rprefix: :events)
8
+ results[:attributes].map { |attrs| new attrs }
9
+ end
10
+
11
+ def self.delete(id)
12
+ api_delete({}, uri: event_uri(id))
13
+ end
14
+
15
+ def self.delete_upto(id)
16
+ results = api_do_delete({ upto_id: id }, prefix: '')
17
+ results[:response_json][:num_events]
18
+ end
19
+
20
+ def self.event_uri(id)
21
+ "#{default_uri}#{id}"
22
+ end
23
+ private_class_method :event_uri
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ require 'injectedlogger'
2
+
3
+ module ThreeScale
4
+ module Core
5
+ module Logger
6
+ InjectedLogger.use(:error, :info, :debug) {}
7
+ InjectedLogger.after_injection do |logger|
8
+ logger.prefix = '[core]' unless logger.prefix
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,32 @@
1
+ module ThreeScale
2
+ module Core
3
+ class Metric < APIClient::Resource
4
+ attributes :service_id, :id, :parent_id, :name
5
+
6
+ default_uri '/internal/services/'
7
+
8
+ def self.base_uri(service_id)
9
+ "#{default_uri}#{service_id}/metrics/"
10
+ end
11
+ private_class_method :base_uri
12
+
13
+ def self.metric_uri(service_id, id)
14
+ "#{base_uri(service_id)}#{id}"
15
+ end
16
+ private_class_method :metric_uri
17
+
18
+ def self.load(service_id, id)
19
+ api_read({}, uri: metric_uri(service_id, id))
20
+ end
21
+
22
+ def self.save(attributes)
23
+ service_id, id = attributes.fetch(:service_id), attributes.fetch(:id)
24
+ api_update attributes, uri: metric_uri(service_id, id)
25
+ end
26
+
27
+ def self.delete(service_id, id)
28
+ api_delete({}, uri: metric_uri(service_id, id))
29
+ end
30
+ end
31
+ end
32
+ end