insights-api-common 4.0.3 → 4.1.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 972f294824d5a600f98ee785b45a310d83b2b056d1bc9e8fee4af2afd1d43f9c
4
- data.tar.gz: 93f294e0f183debaa844c4ff4272c4fa921a8aef51269d0caffbe8a630a84de7
3
+ metadata.gz: ce10f1b7fbf9b54ce62a4df70d74d36576b5aaf27edc46e7876ab9b8dc3b858d
4
+ data.tar.gz: 8d8396b33c3a823d38afce61af976daa07806c4c71373f03f21b738541dd611c
5
5
  SHA512:
6
- metadata.gz: 7f12eb12ddd1bd97b486d88e09463c5ac29f95350ad5431c1ff292df6eb222700628d9a8e0cc055ec7942a0e5a8814aad7249edfd4603f691d6426d85faceef1
7
- data.tar.gz: df4bbc507ad58eb38b94e8bddebd3dd3060a3f4eff33d807b85a88cfd5d9fa33ade8239db2dbae7197b56548fec1fbf456a953fa57226be2b9da1b709f04c0ca
6
+ metadata.gz: cd95076ae1ad48ccf33eb2fa9fcedc044c70c1f2ad995fbbc29d3a98cc3fd680620a1828d69a9b0dad213cc91f1c58ecc80c2a066d1018f35d24ec9719b3aad3
7
+ data.tar.gz: 196b69377f50c94460c5a2a564cf6786352e3962a5cac8d5cf6b69656415bc06420af8f78552758ddb9b3b1dbde3badbd02613e0ade3ae0e8d3264b5e52e46c6
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Insights::API::Common
2
2
 
3
3
  [![Build Status](https://travis-ci.org/RedHatInsights/insights-api-common-rails.svg)](https://travis-ci.org/RedHatInsights/insights-api-common-rails)
4
- [![Maintainability](https://api.codeclimate.com/v1/badges/790ea6c77d82da6be68a/maintainability)](https://codeclimate.com/github/RedHatInsights/insights-api-common-rails/maintainability)
5
- [![Test Coverage](https://api.codeclimate.com/v1/badges/790ea6c77d82da6be68a/test_coverage)](https://codeclimate.com/github/RedHatInsights/insights-api-common-rails/test_coverage)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/8ec8a19165383fdaed47/maintainability)](https://codeclimate.com/github/RedHatInsights/insights-api-common-rails/maintainability)
5
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/8ec8a19165383fdaed47/test_coverage)](https://codeclimate.com/github/RedHatInsights/insights-api-common-rails/test_coverage)
6
6
  [![Security](https://hakiri.io/github/RedHatInsights/insights-api-common-rails/master.svg)](https://hakiri.io/github/RedHatInsights/insights-api-common-rails/master)
7
7
 
8
8
  Header, Encryption, RBAC, Serialization, Pagination and other common behavior for Insights microservices built with Rails
@@ -1,3 +1,4 @@
1
+ require "insights/api/common/custom_exceptions"
1
2
  require "insights/api/common/engine"
2
3
  require "insights/api/common/entitlement"
3
4
  require "insights/api/common/error_document"
@@ -7,19 +7,28 @@ module Insights
7
7
 
8
8
  def self.included(other)
9
9
  other.rescue_from(StandardError, RuntimeError) do |exception|
10
- logger.error("#{exception.class.name}: #{exception.message}\n#{exception.backtrace.join("\n")}")
11
- errors = Insights::API::Common::ErrorDocument.new.tap do |error_document|
12
- exception_list_from(exception).each do |exc|
13
- if api_client_exception?(exc)
14
- api_client_errors(exc, error_document)
15
- else
16
- error_document.add(error_code_from_class(exc).to_s, "#{exc.class}: #{exc.message}")
17
- end
18
- end
10
+ rescue_from_handler(exception) do |error_document, exc|
11
+ error_document.add(error_code_from_class(exc).to_s, "#{exc.class}: #{exc.message}")
19
12
  end
13
+ end
14
+ end
20
15
 
21
- render :json => errors.to_h, :status => error_code_from_class(exception)
16
+ def rescue_from_handler(exception)
17
+ logger.error("#{exception.class.name}: #{exception.message}\n#{exception.backtrace.join("\n")}")
18
+ errors = Insights::API::Common::ErrorDocument.new.tap do |error_document|
19
+ exception_list_from(exception).each do |exc|
20
+ if api_client_exception?(exc)
21
+ api_client_errors(exc, error_document)
22
+ elsif custom_exception?(exc)
23
+ message = fetch_custom_message(exc)
24
+ error_document.add(error_code_from_class(exc).to_s, message)
25
+ else
26
+ yield error_document, exc
27
+ end
28
+ end
22
29
  end
30
+
31
+ render :json => errors.to_h, :status => error_code_from_class(exception)
23
32
  end
24
33
 
25
34
  def exception_list_from(exception)
@@ -31,6 +40,14 @@ module Insights
31
40
  end
32
41
  end
33
42
 
43
+ def custom_exception?(exception)
44
+ Insights::API::Common::CustomExceptions::CUSTOM_EXCEPTION_LIST.include?(exception.class.to_s)
45
+ end
46
+
47
+ def fetch_custom_message(exception)
48
+ Insights::API::Common::CustomExceptions.custom_message(exception)
49
+ end
50
+
34
51
  def error_code_from_class(exception)
35
52
  if ActionDispatch::ExceptionWrapper.rescue_responses.key?(exception.class.to_s)
36
53
  Rack::Utils.status_code(ActionDispatch::ExceptionWrapper.rescue_responses[exception.class.to_s])
@@ -45,7 +62,7 @@ module Insights
45
62
  end
46
63
 
47
64
  def api_client_errors(exc, error_document)
48
- body = JSON.parse(exc.response_body)
65
+ body = json_parsed_body(exc)
49
66
  if body.is_a?(Hash) && body.key?('errors') && body['errors'].is_a?(Array)
50
67
  body['errors'].each do |error|
51
68
  next unless error.key?('status') && error.key?('detail')
@@ -56,6 +73,12 @@ module Insights
56
73
  error_document.add(exc.code.to_s, exc.message )
57
74
  end
58
75
  end
76
+
77
+ def json_parsed_body(exc)
78
+ JSON.parse(exc.response_body)
79
+ rescue StandardError
80
+ nil
81
+ end
59
82
  end
60
83
  end
61
84
  end
@@ -0,0 +1,16 @@
1
+ module Insights
2
+ module API
3
+ module Common
4
+ class CustomExceptions
5
+ CUSTOM_EXCEPTION_LIST = %w[Pundit::NotAuthorizedError].freeze
6
+
7
+ def self.custom_message(exception)
8
+ case exception.class.to_s
9
+ when "Pundit::NotAuthorizedError"
10
+ "You are not authorized to #{exception.query.to_s.delete_suffix('?')} this #{exception.record.model_name.human.downcase}"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -6,18 +6,21 @@ module Insights
6
6
  require 'prometheus_exporter'
7
7
  require 'prometheus_exporter/client'
8
8
 
9
+ setup_custom_metrics(args[:custom_metrics])
10
+
11
+ return if metrics_port == 0
12
+
9
13
  ensure_exporter_server
10
14
  enable_in_process_metrics
11
15
  enable_web_server_metrics(prefix)
12
- setup_custom_metrics(args[:custom_metrics])
13
16
  end
14
17
 
15
18
  private_class_method def self.ensure_exporter_server
16
19
  require 'socket'
17
- TCPSocket.open("localhost", 9394) {}
20
+ TCPSocket.open("localhost", metrics_port) {}
18
21
  rescue Errno::ECONNREFUSED
19
22
  require 'prometheus_exporter/server'
20
- server = PrometheusExporter::Server::WebServer.new(port: 9394)
23
+ server = PrometheusExporter::Server::WebServer.new(port: metrics_port)
21
24
  server.start
22
25
 
23
26
  PrometheusExporter::Client.default = PrometheusExporter::LocalClient.new(collector: server.collector)
@@ -39,18 +42,26 @@ module Insights
39
42
  return if custom_metrics.nil?
40
43
 
41
44
  custom_metrics.each do |metric|
42
- instance_variable_set("@#{metric[:name]}_#{metric[:type]}", PrometheusExporter::Client.default.register(metric[:type], metric[:name], metric[:description]))
43
-
44
- define_singleton_method(metric[:name]) do
45
- case metric[:type]
46
- when :counter
47
- instance_variable_get("@#{metric[:name]}_#{metric[:type]}")&.observe(1)
48
- else
49
- "Metric of type #{metric[:type]} unsupported, implement it in Insights::API::Common::Metrics#L45"
45
+ if metrics_port == 0
46
+ define_singleton_method(metric[:name]) {}
47
+ else
48
+ instance_variable_set("@#{metric[:name]}_#{metric[:type]}", PrometheusExporter::Client.default.register(metric[:type], metric[:name], metric[:description]))
49
+
50
+ define_singleton_method(metric[:name]) do
51
+ case metric[:type]
52
+ when :counter
53
+ instance_variable_get("@#{metric[:name]}_#{metric[:type]}")&.observe(1)
54
+ else
55
+ "Metric of type #{metric[:type]} unsupported, implement it in Insights::API::Common::Metrics#L45"
56
+ end
50
57
  end
51
58
  end
52
59
  end
53
60
  end
61
+
62
+ private_class_method def self.metrics_port
63
+ @metrics_port ||= (ENV['METRICS_PORT']&.to_i || 9394)
64
+ end
54
65
  end
55
66
  end
56
67
  end
@@ -1,2 +1,3 @@
1
1
  require "insights/api/common/open_api/docs"
2
+ require "insights/api/common/open_api/version_from_prefix"
2
3
  require "insights/api/common/open_api/serializer"
@@ -441,7 +441,7 @@ module Insights
441
441
  end
442
442
 
443
443
  # Take existing attrs, that we won't generate
444
- ['example', 'format', 'readOnly', 'title', 'description'].each do |property_key|
444
+ ['example', 'format', 'nullable', 'readOnly', 'title', 'description'].each do |property_key|
445
445
  property_value = openapi_contents.dig(*path_parts(SCHEMAS_PATH), klass_name, "properties", key, property_key)
446
446
  properties_value[property_key] = property_value if property_value
447
447
  end
@@ -3,27 +3,40 @@ module Insights
3
3
  module Common
4
4
  module OpenApi
5
5
  module Serializer
6
+ include VersionFromPrefix
7
+
6
8
  def as_json(arg = {})
7
- previous = super
9
+ previous = super(:except => _excluded_attributes(arg))
10
+
8
11
  encrypted_columns_set = (self.class.try(:encrypted_columns) || []).to_set
9
12
  encryption_filtered = previous.except(*encrypted_columns_set)
10
13
  return encryption_filtered unless arg.key?(:prefixes)
11
- version = api_version_from_prefix(arg[:prefixes].first)
12
- presentation_name = self.class.try(:presentation_name) || self.class.name
13
- schema = ::Insights::API::Common::OpenApi::Docs.instance[version].definitions[presentation_name]
14
- attrs = encryption_filtered.slice(*schema["properties"].keys)
15
- schema["properties"].keys.each do |name|
14
+
15
+ attrs = encryption_filtered.slice(*_schema_properties(arg).keys)
16
+ _schema_properties(arg).keys.each do |name|
16
17
  next if attrs[name].nil?
17
18
  attrs[name] = attrs[name].iso8601 if attrs[name].kind_of?(Time)
18
19
  attrs[name] = attrs[name].to_s if name.ends_with?("_id") || name == "id"
19
- attrs[name] = self.public_send(name) if !attrs.key?(name) && !encrypted_columns_set.include?(name)
20
20
  end
21
21
  attrs.compact
22
22
  end
23
23
 
24
- def api_version_from_prefix(prefix)
25
- /\/?\w+\/v(?<major>\d+)[x\.]?(?<minor>\d+)?\// =~ prefix
26
- [major, minor].compact.join(".")
24
+ private
25
+
26
+ def _excluded_attributes(arg)
27
+ return [] unless arg.key?(:prefixes)
28
+
29
+ self.attributes.keys - _schema_properties(arg).keys
30
+ end
31
+
32
+ def _schema_properties(arg)
33
+ @schema_properties ||= _schema(arg)["properties"]
34
+ end
35
+
36
+ def _schema(arg)
37
+ version = api_version_from_prefix(arg[:prefixes].first)
38
+ presentation_name = self.class.try(:presentation_name) || self.class.name
39
+ ::Insights::API::Common::OpenApi::Docs.instance[version].definitions[presentation_name]
27
40
  end
28
41
  end
29
42
  end
@@ -0,0 +1,14 @@
1
+ module Insights
2
+ module API
3
+ module Common
4
+ module OpenApi
5
+ module VersionFromPrefix
6
+ def api_version_from_prefix(prefix)
7
+ /\/?\w+\/v(?<major>\d+)[x\.]?(?<minor>\d+)?\// =~ prefix
8
+ [major, minor].compact.join(".")
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -8,7 +8,7 @@ module Insights
8
8
  @route_mapper = route_mapper
9
9
  end
10
10
 
11
- def redirect_major_version(version, prefix, via: [:delete, :get, :options, :patch, :post])
11
+ def redirect_major_version(version, prefix, via: [:delete, :get, :options])
12
12
  route_mapper.match(
13
13
  "/#{version.split('.').first}/*path(.:format)",
14
14
  :format => false,
@@ -1,7 +1,7 @@
1
1
  module Insights
2
2
  module API
3
3
  module Common
4
- VERSION = "4.0.3".freeze
4
+ VERSION = "4.1.4".freeze
5
5
  end
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: insights-api-common
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.3
4
+ version: 4.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Insights Authors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-13 00:00:00.000000000 Z
11
+ date: 2020-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: acts_as_tenant
@@ -58,20 +58,20 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '5.2'
61
+ version: 5.2.2
62
62
  - - ">="
63
63
  - !ruby/object:Gem::Version
64
- version: 5.2.1.1
64
+ version: 5.2.2.1
65
65
  type: :runtime
66
66
  prerelease: false
67
67
  version_requirements: !ruby/object:Gem::Requirement
68
68
  requirements:
69
69
  - - "~>"
70
70
  - !ruby/object:Gem::Version
71
- version: '5.2'
71
+ version: 5.2.2
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
- version: 5.2.1.1
74
+ version: 5.2.2.1
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: manageiq-loggers
77
77
  requirement: !ruby/object:Gem::Requirement
@@ -92,14 +92,14 @@ dependencies:
92
92
  requirements:
93
93
  - - "~>"
94
94
  - !ruby/object:Gem::Version
95
- version: '0.2'
95
+ version: 0.2.1
96
96
  type: :runtime
97
97
  prerelease: false
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
- version: '0.2'
102
+ version: 0.2.1
103
103
  - !ruby/object:Gem::Dependency
104
104
  name: prometheus_exporter
105
105
  requirement: !ruby/object:Gem::Requirement
@@ -236,16 +236,16 @@ dependencies:
236
236
  name: rake
237
237
  requirement: !ruby/object:Gem::Requirement
238
238
  requirements:
239
- - - "~>"
239
+ - - ">="
240
240
  - !ruby/object:Gem::Version
241
- version: '10.0'
241
+ version: 12.3.3
242
242
  type: :development
243
243
  prerelease: false
244
244
  version_requirements: !ruby/object:Gem::Requirement
245
245
  requirements:
246
- - - "~>"
246
+ - - ">="
247
247
  - !ruby/object:Gem::Version
248
- version: '10.0'
248
+ version: 12.3.3
249
249
  - !ruby/object:Gem::Dependency
250
250
  name: rspec
251
251
  requirement: !ruby/object:Gem::Requirement
@@ -292,16 +292,16 @@ dependencies:
292
292
  name: simplecov
293
293
  requirement: !ruby/object:Gem::Requirement
294
294
  requirements:
295
- - - ">="
295
+ - - "~>"
296
296
  - !ruby/object:Gem::Version
297
- version: '0'
297
+ version: 0.17.1
298
298
  type: :development
299
299
  prerelease: false
300
300
  version_requirements: !ruby/object:Gem::Requirement
301
301
  requirements:
302
- - - ">="
302
+ - - "~>"
303
303
  - !ruby/object:Gem::Version
304
- version: '0'
304
+ version: 0.17.1
305
305
  - !ruby/object:Gem::Dependency
306
306
  name: webmock
307
307
  requirement: !ruby/object:Gem::Requirement
@@ -345,6 +345,7 @@ files:
345
345
  - lib/insights/api/common/application_controller_mixins/request_body_validation.rb
346
346
  - lib/insights/api/common/application_controller_mixins/request_parameter_validation.rb
347
347
  - lib/insights/api/common/application_controller_mixins/request_path.rb
348
+ - lib/insights/api/common/custom_exceptions.rb
348
349
  - lib/insights/api/common/engine.rb
349
350
  - lib/insights/api/common/entitlement.rb
350
351
  - lib/insights/api/common/error_document.rb
@@ -371,6 +372,7 @@ files:
371
372
  - lib/insights/api/common/open_api/docs/object_definition.rb
372
373
  - lib/insights/api/common/open_api/generator.rb
373
374
  - lib/insights/api/common/open_api/serializer.rb
375
+ - lib/insights/api/common/open_api/version_from_prefix.rb
374
376
  - lib/insights/api/common/option_redirect_enhancements.rb
375
377
  - lib/insights/api/common/paginated_response.rb
376
378
  - lib/insights/api/common/paginated_response_v2.rb