zuora_connect 2.0.58 → 2.0.60c
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 +4 -4
- data/app/controllers/zuora_connect/static_controller.rb +83 -12
- data/app/models/zuora_connect/app_instance_base.rb +1 -1
- data/config/initializers/prometheus.rb +78 -23
- data/config/initializers/resque.rb +14 -0
- data/config/initializers/unicorn.rb +29 -1
- data/config/routes.rb +5 -0
- data/lib/middleware/metrics_middleware.rb +45 -31
- data/lib/resque/plugins/app_instance_job.rb +1 -1
- data/lib/zuora_connect/controllers/helpers.rb +195 -69
- data/lib/zuora_connect/railtie.rb +9 -5
- data/lib/zuora_connect/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8befa7a7baeaf53305dc7cca304df5e672f0702a79a466a527a0f21a5ae0ab22
|
4
|
+
data.tar.gz: 6fe3d6e3390df915df0f3d49815a2cf4326035815a9b240b945d206941cb8032
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 92604604be323a0e43faa74ece5ba4ace4c86ae79710d86164850acfeee6990ec07fdbe6c6a674e5aa9f1ab1d0a93bf2d593052cc47d5290fd04d6cf59037fc8
|
7
|
+
data.tar.gz: 6ebb61f4e49c43d426fb0bcb2dd8070d5e720ce645ded094aa132686740cd1a2706c6b6b070794fa411ce162fcb0944291091b81485c4486cb8f3bed7710b191
|
@@ -1,10 +1,11 @@
|
|
1
1
|
module ZuoraConnect
|
2
2
|
class StaticController < ApplicationController
|
3
|
-
before_action :authenticate_connect_app_request, :except => [:metrics, :health, :initialize_app]
|
4
|
-
before_action :clear_connect_app_session, :only => [:metrics, :health, :initialize_app]
|
5
|
-
after_action :persist_connect_app_session, :except => [:metrics, :health, :initialize_app]
|
6
|
-
|
7
|
-
skip_before_action :verify_authenticity_token, :only => [:initialize_app]
|
3
|
+
before_action :authenticate_connect_app_request, :except => [:metrics, :health, :initialize_app, :provision, :instance_user]
|
4
|
+
before_action :clear_connect_app_session, :only => [:metrics, :health, :initialize_app, :provision, :instance_user]
|
5
|
+
after_action :persist_connect_app_session, :except => [:metrics, :health, :initialize_app, :provision, :instance_user]
|
6
|
+
|
7
|
+
skip_before_action :verify_authenticity_token, :only => [:initialize_app, :provision]
|
8
|
+
http_basic_authenticate_with name: ENV['PROVISION_USER'], password: ENV['PROVISION_SECRET'], :only => [:provision, :instance_user]
|
8
9
|
|
9
10
|
def metrics
|
10
11
|
type = params[:type].present? ? params[:type] : "versions"
|
@@ -13,11 +14,11 @@ module ZuoraConnect
|
|
13
14
|
|
14
15
|
def health
|
15
16
|
if params[:error].present?
|
16
|
-
begin
|
17
|
+
begin
|
17
18
|
raise ZuoraConnect::Exceptions::Error.new('This is an error')
|
18
19
|
rescue => ex
|
19
20
|
case params[:error]
|
20
|
-
when 'Log'
|
21
|
+
when 'Log'
|
21
22
|
Rails.logger.error("Error in Health", ex)
|
22
23
|
when 'Exception'
|
23
24
|
raise
|
@@ -34,11 +35,13 @@ module ZuoraConnect
|
|
34
35
|
def initialize_app
|
35
36
|
begin
|
36
37
|
authenticate_connect_app_request
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
unless performed?
|
39
|
+
@appinstance.new_session(:session => @appinstance.data_lookup(:session => session))
|
40
|
+
render json: {
|
41
|
+
message: 'Success',
|
42
|
+
status: 200
|
43
|
+
}, status: 200
|
44
|
+
end
|
42
45
|
rescue => ex
|
43
46
|
Rails.logger.error("Failed to Initialize application", ex)
|
44
47
|
if performed?
|
@@ -52,6 +55,74 @@ module ZuoraConnect
|
|
52
55
|
end
|
53
56
|
end
|
54
57
|
|
58
|
+
def provision
|
59
|
+
create_new_instance
|
60
|
+
unless performed?
|
61
|
+
render json: {
|
62
|
+
status: 200,
|
63
|
+
message: 'Success',
|
64
|
+
app_instance_id: @appinstance.id
|
65
|
+
}, status: 200
|
66
|
+
end
|
67
|
+
rescue StandardError => e
|
68
|
+
message = 'Failed to provision new instance'
|
69
|
+
if performed?
|
70
|
+
Rails.logger.error("#{message}: #{performed?}", e)
|
71
|
+
else
|
72
|
+
Rails.logger.error(message, e)
|
73
|
+
render json: {
|
74
|
+
status: 500,
|
75
|
+
message: message
|
76
|
+
}, status: 500
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def instance_user
|
81
|
+
ZuoraConnect::AppInstance.read_master_db do
|
82
|
+
ZuoraConnect.logger.with_fields = {} if ZuoraConnect.logger.is_a?(Ougai::Logger)
|
83
|
+
Rails.logger.with_fields = {} if Rails.logger.is_a?(Ougai::Logger)
|
84
|
+
|
85
|
+
if defined?(ElasticAPM) && ElasticAPM.running? && ElasticAPM.respond_to?(:set_label)
|
86
|
+
ElasticAPM.set_label(:trace_id, request.uuid)
|
87
|
+
end
|
88
|
+
|
89
|
+
unless params[:id].present?
|
90
|
+
render json: {
|
91
|
+
status: 400,
|
92
|
+
message: 'No app instance id provided'
|
93
|
+
}, status: :bad_request
|
94
|
+
return
|
95
|
+
end
|
96
|
+
|
97
|
+
@appinstance = ZuoraConnect::AppInstance.find(params[:id]).new_session
|
98
|
+
end
|
99
|
+
|
100
|
+
zuora_client = @appinstance.send(ZuoraConnect::AppInstance::LOGIN_TENANT_DESTINATION).client
|
101
|
+
client_describe, = zuora_client.rest_call(
|
102
|
+
url: zuora_client.rest_endpoint('genesis/user/info').gsub('v1/', ''),
|
103
|
+
session_type: zuora_client.class == ZuoraAPI::Oauth ? :bearer : :basic
|
104
|
+
)
|
105
|
+
|
106
|
+
render json: {
|
107
|
+
status: 200,
|
108
|
+
message: 'Success',
|
109
|
+
user_id: client_describe['coreUserId'],
|
110
|
+
username: client_describe['username'],
|
111
|
+
email: client_describe['workEmail']
|
112
|
+
}, status: 200
|
113
|
+
rescue ActiveRecord::RecordNotFound
|
114
|
+
render json: {
|
115
|
+
status: 400,
|
116
|
+
message: 'No app instance found'
|
117
|
+
}, status: :bad_request
|
118
|
+
rescue StandardError => e
|
119
|
+
Rails.logger.error('Error occurred getting user details', e)
|
120
|
+
render json: {
|
121
|
+
status: 500,
|
122
|
+
message: 'Failed to get user details'
|
123
|
+
}, status: 500
|
124
|
+
end
|
125
|
+
|
55
126
|
private
|
56
127
|
|
57
128
|
def clear_connect_app_session
|
@@ -402,7 +402,7 @@ module ZuoraConnect
|
|
402
402
|
end
|
403
403
|
|
404
404
|
def self.write_to_telegraf(*args)
|
405
|
-
if ZuoraConnect.configuration.enable_metrics
|
405
|
+
if ZuoraConnect.configuration.enable_metrics && !defined?(Prometheus)
|
406
406
|
@@telegraf_host = ZuoraConnect::Telegraf.new() if @@telegraf_host == nil
|
407
407
|
unicorn_stats = self.unicorn_listener_stats() if defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
|
408
408
|
@@telegraf_host.write(direction: 'Raindrops', tags: {}, values: unicorn_stats) unless unicorn_stats.blank?
|
@@ -3,38 +3,93 @@ if defined? Prometheus
|
|
3
3
|
require "zuora_connect/version"
|
4
4
|
require "zuora_api/version"
|
5
5
|
|
6
|
+
resque_path = "#{ENV['RESQUE_EXPORTER_PATH'] || Rails.root.join('tmp/resque_exporter')}/*.prom"
|
7
|
+
prometheus_path = Rails.root.join("tmp/prometheus")
|
8
|
+
|
9
|
+
Dir[resque_path, "#{prometheus_path}/*.bin"].each do |file_path|
|
10
|
+
File.unlink(file_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'prometheus/client/data_stores/direct_file_store'
|
14
|
+
Prometheus::Client.config.data_store = Prometheus::Client::DataStores::DirectFileStore.new(
|
15
|
+
dir: prometheus_path
|
16
|
+
)
|
17
|
+
|
18
|
+
class ResqueExporter
|
19
|
+
require 'prometheus/client/formats/text'
|
20
|
+
require 'fileutils'
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@lock = Monitor.new
|
24
|
+
@registry = Prometheus::Client.registry
|
25
|
+
@path = ENV['RESQUE_EXPORTER_PATH'] || Rails.root.join('tmp/resque_exporter')
|
26
|
+
FileUtils.mkdir_p(@path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def export
|
30
|
+
filename = File.join(@path, 'resque_export.prom')
|
31
|
+
@lock.synchronize do
|
32
|
+
File.open(filename, 'w+') do |file|
|
33
|
+
file.write(Prometheus::Client::Formats::Text.marshal(@registry))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
most_recent_aggregation = {}
|
40
|
+
sum_aggregation = {}
|
41
|
+
if defined?(Unicorn)
|
42
|
+
most_recent_aggregation[:aggregation] = :most_recent
|
43
|
+
sum_aggregation[:aggregation] = :sum
|
44
|
+
end
|
45
|
+
|
6
46
|
# Create a default Prometheus registry for our metrics.
|
7
47
|
prometheus = Prometheus::Client.registry
|
8
48
|
|
9
49
|
# Create your metrics.
|
10
|
-
ZUORA_VERSION =
|
11
|
-
CONNECT_VERSION =
|
12
|
-
RAILS_VERSION =
|
13
|
-
RUBY_V =
|
50
|
+
ZUORA_VERSION = prometheus.gauge(:zuora_version, docstring: 'The current Zuora Gem version.', labels: %i(version name), preset_labels: { version: ZuoraAPI::VERSION, name: ZuoraConnect::Telegraf.app_name }, store_settings: most_recent_aggregation)
|
51
|
+
CONNECT_VERSION = prometheus.gauge(:gem_version, docstring: 'The current Connect Gem version.', labels: %i(version name), preset_labels: { version: ZuoraConnect::VERSION, name: ZuoraConnect::Telegraf.app_name }, store_settings: most_recent_aggregation)
|
52
|
+
RAILS_VERSION = prometheus.gauge(:rails_version, docstring: 'The current Rails version.', labels: %i(version name), preset_labels: { version: Rails.version, name: ZuoraConnect::Telegraf.app_name }, store_settings: most_recent_aggregation)
|
53
|
+
RUBY_V = prometheus.gauge(:ruby_version, docstring: 'The current Ruby version.', labels: %i(version name), preset_labels: { version: RUBY_VERSION, name: ZuoraConnect::Telegraf.app_name }, store_settings: most_recent_aggregation)
|
14
54
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
prometheus.register(RUBY_V);RUBY_V.set({version: RUBY_VERSION, name: ZuoraConnect::Telegraf.app_name},0)
|
55
|
+
ZUORA_VERSION.set(0)
|
56
|
+
CONNECT_VERSION.set(0)
|
57
|
+
RAILS_VERSION.set(0)
|
58
|
+
RUBY_V.set(0)
|
20
59
|
|
21
60
|
# Do they have resque jobs?
|
22
61
|
if defined? Resque.redis
|
23
|
-
REDIS_CONNECTION =
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
prometheus.register(REDIS_CONNECTION)
|
31
|
-
prometheus.register(FINISHED_JOBS)
|
32
|
-
prometheus.register(ACTIVE_WORKERS)
|
33
|
-
prometheus.register(WORKERS)
|
34
|
-
prometheus.register(FAILED_JOBS)
|
35
|
-
prometheus.register(PENDING_JOBS)
|
36
|
-
|
62
|
+
REDIS_CONNECTION = prometheus.gauge(:redis_connection, docstring: 'The status of the redis connection, 0 or 1', labels: %i(connection name), preset_labels: {connection:'redis', name: ZuoraConnect::Telegraf.app_name}, store_settings: most_recent_aggregation)
|
63
|
+
JOBS_FINISHED = prometheus.gauge(:jobs_finished, docstring: 'Done resque jobs', labels: %i(type name), preset_labels: {type:'resque', name: ZuoraConnect::Telegraf.app_name}, store_settings: most_recent_aggregation)
|
64
|
+
WORKERS_TOTAL = prometheus.gauge(:workers_total, docstring: 'Total resque workers', labels: %i(type name), preset_labels: {type:'resque', name: ZuoraConnect::Telegraf.app_name}, store_settings: most_recent_aggregation)
|
65
|
+
WORKERS_ACTIVE = prometheus.gauge(:workers_active, docstring: 'Active resque workers', labels: %i(type name), preset_labels: {type:'resque', name: ZuoraConnect::Telegraf.app_name}, store_settings: most_recent_aggregation)
|
66
|
+
JOBS_FAILED = prometheus.gauge(:jobs_failed, docstring: 'Failed resque jobs', labels: %i(type name), preset_labels: {type:'resque', name: ZuoraConnect::Telegraf.app_name}, store_settings: most_recent_aggregation)
|
67
|
+
JOBS_PENDING = prometheus.gauge(:jobs_pending, docstring: 'Pending resque jobs', labels: %i(type name), preset_labels: {type:'resque', name: ZuoraConnect::Telegraf.app_name}, store_settings: most_recent_aggregation)
|
37
68
|
end
|
38
69
|
|
70
|
+
if defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
|
71
|
+
UNICORN_KILLS = prometheus.gauge(
|
72
|
+
:unicorn_kills,
|
73
|
+
docstring: 'Unicorn Kills',
|
74
|
+
labels: %i(type name),
|
75
|
+
preset_labels: {type:'Unicorn-Killer', name: ZuoraConnect::Telegraf.app_name},
|
76
|
+
store_settings: sum_aggregation
|
77
|
+
)
|
78
|
+
|
79
|
+
ZuoraConnect::AppInstanceBase.unicorn_listener_stats.each do |key, _|
|
80
|
+
gauge_name = "unicorn_#{key}".gsub(/[^a-zA-Z0-9_]/, '_')
|
81
|
+
gauge = prometheus.gauge(
|
82
|
+
gauge_name.to_sym,
|
83
|
+
docstring: 'Unicorn Stats',
|
84
|
+
labels: %i(type name),
|
85
|
+
preset_labels: { type: 'unicorn', name: ZuoraConnect::Telegraf.app_name },
|
86
|
+
store_settings: most_recent_aggregation
|
87
|
+
)
|
88
|
+
Prometheus.const_set(
|
89
|
+
gauge_name.upcase,
|
90
|
+
gauge
|
91
|
+
)
|
92
|
+
end
|
93
|
+
end
|
39
94
|
end
|
40
95
|
end
|
@@ -5,6 +5,20 @@ if defined?(Resque::Worker)
|
|
5
5
|
Resque::Job.send(:include, Resque::SelfLookup)
|
6
6
|
end
|
7
7
|
|
8
|
+
if defined?(Resque::Job) && defined?(Prometheus)
|
9
|
+
module ResquePrometheusExtensions
|
10
|
+
EXPORTER = Prometheus::ResqueExporter.new
|
11
|
+
def perform
|
12
|
+
super
|
13
|
+
EXPORTER.export
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Resque::Job
|
18
|
+
prepend ResquePrometheusExtensions
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
8
22
|
Resque.module_eval do
|
9
23
|
# Returns a hash, mapping queue names to queue sizes
|
10
24
|
def queue_sizes
|
@@ -3,7 +3,35 @@ if defined?(Unicorn::WorkerKiller)
|
|
3
3
|
self.singleton_class.send(:alias_method, :kill_self_old, :kill_self)
|
4
4
|
def self.kill_self(logger, start_time)
|
5
5
|
self.kill_self_old(logger, start_time)
|
6
|
-
|
6
|
+
if defined?(Prometheus)
|
7
|
+
Prometheus::UNICORN_KILLS.set(1)
|
8
|
+
else
|
9
|
+
ZuoraConnect::AppInstance.write_to_telegraf(direction: 'Unicorn-Killer', tags: {app_instance: 0}, values: {kill: 1})
|
10
|
+
end
|
7
11
|
end
|
8
12
|
end
|
13
|
+
end
|
14
|
+
|
15
|
+
if defined?(Unicorn::HttpServer) && defined?(Prometheus)
|
16
|
+
module HttpServerExtensions
|
17
|
+
def kill_worker(signal, wpid)
|
18
|
+
Prometheus::UNICORN_KILLS.increment
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module WorkerExtensions
|
24
|
+
def soft_kill(sig)
|
25
|
+
Prometheus::UNICORN_KILLS.increment
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Unicorn::HttpServer
|
31
|
+
prepend HttpServerExtensions
|
32
|
+
end
|
33
|
+
|
34
|
+
class Unicorn::Worker
|
35
|
+
prepend WorkerExtensions
|
36
|
+
end
|
9
37
|
end
|
data/config/routes.rb
CHANGED
@@ -3,6 +3,11 @@ ZuoraConnect::Engine.routes.draw do
|
|
3
3
|
get '/internal/data' => 'static#metrics'
|
4
4
|
post '/initialize_app' => 'static#initialize_app'
|
5
5
|
|
6
|
+
if ENV['PROVISION_USER'].present? && ENV['PROVISION_SECRET'].present?
|
7
|
+
post '/provision' => 'static#provision'
|
8
|
+
get '/instance/:id/user' => 'static#instance_user'
|
9
|
+
end
|
10
|
+
|
6
11
|
namespace :api do
|
7
12
|
namespace :v1 do
|
8
13
|
resources :app_instance, :only => [:index], defaults: {format: :json} do
|
@@ -64,6 +64,22 @@ module ZuoraConnect
|
|
64
64
|
#Remove bad headers
|
65
65
|
@bad_headers.each { |header| env.delete(header) }
|
66
66
|
|
67
|
+
if defined?(Prometheus) && env['PATH_INFO'] == '/connect/internal/metrics'
|
68
|
+
# Prometheus Stuff
|
69
|
+
metrics = ZuoraConnect::AppInstance.get_metrics('stats')
|
70
|
+
redis_up = metrics.present? && metrics.dig(:Resque, :Workers_Total).present? ? 1 : 0
|
71
|
+
Prometheus::REDIS_CONNECTION.set(redis_up)
|
72
|
+
|
73
|
+
process_prometheus_metric(metrics: metrics)
|
74
|
+
|
75
|
+
if defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
|
76
|
+
ZuoraConnect::AppInstanceBase.unicorn_listener_stats.each do |key, value|
|
77
|
+
gauge = Prometheus.const_get("unicorn_#{key}".gsub(/[^a-zA-Z0-9_]/, '_').upcase)
|
78
|
+
gauge.set(value) if gauge.present?
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
67
83
|
#Thread.current[:appinstance] = nil
|
68
84
|
start_time = Time.now
|
69
85
|
begin
|
@@ -77,35 +93,6 @@ module ZuoraConnect
|
|
77
93
|
ZuoraConnect::AppInstanceBase.write_to_telegraf(direction: 'request-inbound-assets', tags: tags, values: values)
|
78
94
|
end
|
79
95
|
|
80
|
-
if defined? Prometheus
|
81
|
-
#Prometheus Stuff
|
82
|
-
if env['PATH_INFO'] == '/connect/internal/metrics'
|
83
|
-
|
84
|
-
#Do something before each scrape
|
85
|
-
if defined? Resque.redis
|
86
|
-
begin
|
87
|
-
|
88
|
-
Resque.redis.ping
|
89
|
-
|
90
|
-
Prometheus::REDIS_CONNECTION.set({connection:'redis',name: ZuoraConnect::Telegraf.app_name},1)
|
91
|
-
Prometheus::FINISHED_JOBS.set({type:'resque',name: ZuoraConnect::Telegraf.app_name},Resque.info[:processed])
|
92
|
-
Prometheus::PENDING_JOBS.set({type:'resque',name: ZuoraConnect::Telegraf.app_name},Resque.info[:pending])
|
93
|
-
Prometheus::ACTIVE_WORKERS.set({type:'resque',name: ZuoraConnect::Telegraf.app_name},Resque.info[:working])
|
94
|
-
Prometheus::WORKERS.set({type:'resque',name: ZuoraConnect::Telegraf.app_name},Resque.info[:workers])
|
95
|
-
Prometheus::FAILED_JOBS.set({type:'resque',name: ZuoraConnect::Telegraf.app_name},Resque.info[:failed])
|
96
|
-
|
97
|
-
rescue Redis::CannotConnectError
|
98
|
-
Prometheus::REDIS_CONNECTION.set({connection:'redis',name: ZuoraConnect::Telegraf.app_name},0)
|
99
|
-
end
|
100
|
-
|
101
|
-
if ZuoraConnect.configuration.custom_prometheus_update_block != nil
|
102
|
-
ZuoraConnect.configuration.custom_prometheus_update_block.call()
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
96
|
# Uncomment following block of code for handling engine requests/requests without controller
|
110
97
|
# else
|
111
98
|
# # Handling requests which do not have controllers (engines)
|
@@ -119,10 +106,10 @@ module ZuoraConnect
|
|
119
106
|
content_type = @headers['Content-Type'].split(';')[0] if @headers['Content-Type']
|
120
107
|
content_type = content_type.gsub('text/javascript', 'application/javascript')
|
121
108
|
tags = {status: @status, content_type: content_type}
|
122
|
-
|
109
|
+
|
123
110
|
tags = tags.merge({controller: 'ActionController'})
|
124
111
|
tags = tags.merge({action: 'RoutingError' }) if @status == 404
|
125
|
-
|
112
|
+
|
126
113
|
values = {response_time: ((Time.now - start_time)*1000).round(2) }
|
127
114
|
|
128
115
|
ZuoraConnect::AppInstanceBase.write_to_telegraf(direction: :inbound, tags: tags, values: values)
|
@@ -133,5 +120,32 @@ module ZuoraConnect
|
|
133
120
|
[@status, @headers, @response]
|
134
121
|
end
|
135
122
|
end
|
123
|
+
|
124
|
+
def process_prometheus_metric(type: 'none', metrics: {})
|
125
|
+
return if metrics.blank?
|
126
|
+
|
127
|
+
prometheus = Prometheus::Client.registry
|
128
|
+
most_recent_aggregation = {}
|
129
|
+
if Prometheus::Client.config.data_store.is_a?(Prometheus::Client::DataStores::DirectFileStore)
|
130
|
+
most_recent_aggregation[:aggregation] = :most_recent
|
131
|
+
end
|
132
|
+
metrics.each do |key, value|
|
133
|
+
next if %w[app_name url].include?(key.to_s)
|
134
|
+
|
135
|
+
if value.is_a?(Hash)
|
136
|
+
process_prometheus_metric(type: key.to_s, metrics: value)
|
137
|
+
else
|
138
|
+
gauge_name = key.to_s.downcase.gsub(/[^a-z0-9_]/, '_')
|
139
|
+
gauge = prometheus.get(gauge_name.to_sym) || prometheus.gauge(
|
140
|
+
gauge_name.to_sym,
|
141
|
+
docstring: "#{key} metric",
|
142
|
+
labels: %i(type name),
|
143
|
+
preset_labels: { type: type, name: ZuoraConnect::Telegraf.app_name },
|
144
|
+
store_settings: most_recent_aggregation
|
145
|
+
)
|
146
|
+
gauge.set(value)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
136
150
|
end
|
137
151
|
end
|
@@ -47,7 +47,7 @@ module Resque
|
|
47
47
|
raise
|
48
48
|
end
|
49
49
|
rescue PG::ConnectionBad => exception
|
50
|
-
Rails.logger.
|
50
|
+
Rails.logger.warn("Bad Connection Restart", exception)
|
51
51
|
Resque.enqueue_to(self.job.queue, self.job.payload['class'], args)
|
52
52
|
return
|
53
53
|
rescue ZuoraConnect::Exceptions::ConnectCommunicationError => exception
|
@@ -219,6 +219,80 @@ module ZuoraConnect
|
|
219
219
|
return (request.headers['ZuoraCurrentEntity'].present? || cookies['ZuoraCurrentEntity'].present?)
|
220
220
|
end
|
221
221
|
|
222
|
+
def create_new_instance
|
223
|
+
ZuoraConnect::AppInstance.read_master_db do
|
224
|
+
Thread.current[:appinstance] = nil
|
225
|
+
ZuoraConnect.logger.with_fields = {} if ZuoraConnect.logger.is_a?(Ougai::Logger)
|
226
|
+
Rails.logger.with_fields = {} if Rails.logger.is_a?(Ougai::Logger)
|
227
|
+
|
228
|
+
if defined?(ElasticAPM) && ElasticAPM.running? && ElasticAPM.respond_to?(:set_label)
|
229
|
+
ElasticAPM.set_label(:trace_id, request.uuid)
|
230
|
+
end
|
231
|
+
|
232
|
+
zuora_host = request.headers['zuora-host']
|
233
|
+
zuora_entity_id = (request.headers['zuora-entity-ids'] || '').gsub(
|
234
|
+
'-',
|
235
|
+
''
|
236
|
+
).split(',').first
|
237
|
+
|
238
|
+
# Validate host present
|
239
|
+
if zuora_host.blank?
|
240
|
+
render json: {
|
241
|
+
status: 401,
|
242
|
+
message: 'zuora-host header was not supplied.'
|
243
|
+
}, status: :unauthorized
|
244
|
+
return
|
245
|
+
end
|
246
|
+
|
247
|
+
# Validate entity-ids present
|
248
|
+
if zuora_entity_id.blank?
|
249
|
+
render json: {
|
250
|
+
status: 401,
|
251
|
+
message: 'zuora-entity-ids header was not supplied.'
|
252
|
+
}, status: :unauthorized
|
253
|
+
return
|
254
|
+
end
|
255
|
+
|
256
|
+
rest_domain = ZuoraAPI::Login.new(url: "https://#{zuora_host}").rest_domain
|
257
|
+
app_instance_id = ZuoraConnect::AppInstance.where(
|
258
|
+
'zuora_entity_ids ?& array[:entities] AND zuora_domain = :host',
|
259
|
+
entities: [zuora_entity_id],
|
260
|
+
host: rest_domain
|
261
|
+
).pluck(:id).first
|
262
|
+
|
263
|
+
if app_instance_id.present?
|
264
|
+
render json: {
|
265
|
+
status: 409,
|
266
|
+
message: 'Instance already exists.',
|
267
|
+
app_instance_id: app_instance_id
|
268
|
+
}, status: 409
|
269
|
+
else
|
270
|
+
Apartment::Tenant.switch!("public")
|
271
|
+
retry_count = 3
|
272
|
+
begin
|
273
|
+
@appinstance = new_instance(
|
274
|
+
next_instance_id,
|
275
|
+
zuora_entity_id,
|
276
|
+
rest_domain,
|
277
|
+
retry_count: retry_count
|
278
|
+
)
|
279
|
+
rescue ActiveRecord::RecordNotUnique
|
280
|
+
retry if (retry_count -= 1).positive?
|
281
|
+
return
|
282
|
+
end
|
283
|
+
|
284
|
+
app_instance_id = @appinstance.id
|
285
|
+
end
|
286
|
+
|
287
|
+
begin
|
288
|
+
Apartment::Tenant.switch!('public')
|
289
|
+
Apartment::Tenant.create(app_instance_id.to_s)
|
290
|
+
rescue Apartment::TenantExists
|
291
|
+
ZuoraConnect.logger.debug('Tenant Already Exists')
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
222
296
|
private
|
223
297
|
def setup_instance_via_prod_mode
|
224
298
|
zuora_entity_id = request.headers['ZuoraCurrentEntity'] || cookies['ZuoraCurrentEntity']
|
@@ -226,7 +300,7 @@ module ZuoraConnect
|
|
226
300
|
if zuora_entity_id.present?
|
227
301
|
zuora_tenant_id = cookies['Zuora-Tenant-Id']
|
228
302
|
zuora_user_id = cookies['Zuora-User-Id']
|
229
|
-
zuora_host = request.headers[
|
303
|
+
zuora_host = request.headers['HTTP_X_FORWARDED_HOST'] || request.headers['Zuora-Host'] || 'apisandbox.zuora.com'
|
230
304
|
|
231
305
|
zuora_details = {'host' => zuora_host, 'user_id' => zuora_user_id, 'tenant_id' => zuora_tenant_id, 'entity_id' => zuora_entity_id}
|
232
306
|
auth_headers = {}
|
@@ -272,7 +346,7 @@ module ZuoraConnect
|
|
272
346
|
##
|
273
347
|
# If the ZSession was refreshed, but it's still the same user and they aren't launching from the side bar,
|
274
348
|
# we don't need to continue
|
275
|
-
is_different_user = identity.slice("entityId", "tenantId", "userId", "userProfileId")
|
349
|
+
is_different_user = identity.slice("entityId", "tenantId", "userId", "userProfileId") != (session["ZuoraCurrentIdentity"] || {}).slice("entityId", "tenantId", "userId", "userProfileId")
|
276
350
|
zuora_details["identity"]["entityId"] = identity['entityId']
|
277
351
|
session["ZuoraCurrentIdentity"] = identity
|
278
352
|
session["ZuoraCurrentEntity"] = identity['entityId']
|
@@ -328,11 +402,13 @@ module ZuoraConnect
|
|
328
402
|
|
329
403
|
zuora_user_id = cookies['Zuora-User-Id'] || session["ZuoraCurrentIdentity"]['userId']
|
330
404
|
|
331
|
-
#One deployed instance
|
332
405
|
if appinstances.size == 1
|
333
406
|
ZuoraConnect.logger.debug("Instance is #{appinstances.to_h.keys.first}")
|
334
407
|
@appinstance = ZuoraConnect::AppInstance.find(appinstances.to_h.keys.first)
|
408
|
+
end
|
335
409
|
|
410
|
+
# One deployed instance with credentials
|
411
|
+
if defined?(@appinstance) && !@appinstance['zuora_logins'].nil?
|
336
412
|
#Add user/update
|
337
413
|
begin
|
338
414
|
@zuora_user = ZuoraConnect::ZuoraUser.where(:zuora_user_id => zuora_user_id).first
|
@@ -380,79 +456,85 @@ module ZuoraConnect
|
|
380
456
|
return
|
381
457
|
end
|
382
458
|
Apartment::Tenant.switch!("public")
|
383
|
-
|
384
|
-
|
385
|
-
|
459
|
+
retry_count = 3
|
460
|
+
task_data = {}
|
461
|
+
begin
|
462
|
+
ActiveRecord::Base.transaction do
|
463
|
+
ActiveRecord::Base.connection.execute('LOCK public.zuora_users IN ACCESS EXCLUSIVE MODE')
|
386
464
|
|
387
|
-
|
388
|
-
|
389
|
-
return
|
390
|
-
end
|
465
|
+
unless defined?(@appinstance)
|
466
|
+
appinstances = ZuoraConnect::AppInstance.where("zuora_entity_ids ?& array[:entities] = true AND zuora_domain = :host", entities: [zuora_entity_id], host: zuora_client.rest_domain).pluck(:id, :name)
|
391
467
|
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
'customAuthorities' => [],
|
398
|
-
'additionalInformation' => {
|
399
|
-
'description' => "This user is for #{user} application.",
|
400
|
-
'name' => "#{user} API User #{next_id}"
|
401
|
-
}
|
402
|
-
}
|
403
|
-
|
404
|
-
oauth_response, response = zuora_client.rest_call(
|
405
|
-
method: :post,
|
406
|
-
body: body.to_json,
|
407
|
-
url: zuora_client.rest_endpoint("genesis/clients").gsub('v1/', ''),
|
408
|
-
session_type: zuora_client.class == ZuoraAPI::Oauth ? :bearer : :basic,
|
409
|
-
headers: auth_headers
|
410
|
-
)
|
468
|
+
if appinstances.size > 0
|
469
|
+
redirect_to "https://#{zuora_host}/apps/newlogin.do?retURL=#{request.fullpath}"
|
470
|
+
return
|
471
|
+
end
|
472
|
+
end
|
411
473
|
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
474
|
+
next_id = defined?(@appinstance) ? @appinstance.id : next_instance_id
|
475
|
+
if task_data.blank?
|
476
|
+
user = (ENV['DEIS_APP'] || "Application").split('-').map(&:capitalize).join(' ')
|
477
|
+
body = {
|
478
|
+
'userId' => zuora_user_id,
|
479
|
+
'entityIds' => [zuora_entity_id.unpack("a8a4a4a4a12").join('-')],
|
480
|
+
'customAuthorities' => [],
|
481
|
+
'additionalInformation' => {
|
482
|
+
'description' => "This user is for #{user} application.",
|
483
|
+
'name' => "#{user} API User #{next_id}"
|
484
|
+
}
|
485
|
+
}
|
486
|
+
|
487
|
+
oauth_response, response = zuora_client.rest_call(
|
488
|
+
method: :post,
|
489
|
+
body: body.to_json,
|
490
|
+
url: zuora_client.rest_endpoint("genesis/clients").gsub('v1/', ''),
|
491
|
+
session_type: zuora_client.class == ZuoraAPI::Oauth ? :bearer : :basic,
|
492
|
+
headers: auth_headers
|
493
|
+
)
|
494
|
+
|
495
|
+
new_zuora_client = ZuoraAPI::Oauth.new(url: "https://#{zuora_host}", oauth_client_id: oauth_response["clientId"], oauth_secret: oauth_response["clientSecret"] )
|
496
|
+
if session["ZuoraCurrentUserInfo"].blank?
|
497
|
+
client_describe, response = new_zuora_client.rest_call(url: zuora_client.rest_endpoint("genesis/user/info").gsub('v1/', ''), session_type: :bearer)
|
498
|
+
else
|
499
|
+
client_describe = session["ZuoraCurrentUserInfo"]
|
500
|
+
end
|
418
501
|
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
rescue ActiveRecord::RecordNotUnique => ex
|
443
|
-
if (retry_count += 1) < 3
|
444
|
-
@appinstance.assign_attributes({:api_token => rand(36**64).to_s(36), :token => rand(36**64).to_s(36)})
|
445
|
-
retry
|
502
|
+
available_entities = client_describe["accessibleEntities"].select {|entity| entity['id'] == zuora_entity_id}
|
503
|
+
task_data = {
|
504
|
+
"id": next_id,
|
505
|
+
"name": client_describe["tenantName"],
|
506
|
+
"mode": "Collections",
|
507
|
+
"status": "Running",
|
508
|
+
ZuoraConnect::AppInstance::LOGIN_TENANT_DESTINATION => {
|
509
|
+
"tenant_type": "Zuora",
|
510
|
+
"username": session["ZuoraCurrentIdentity"]["username"],
|
511
|
+
"url": new_zuora_client.url,
|
512
|
+
"status": "Active",
|
513
|
+
"oauth_client_id": oauth_response['clientId'],
|
514
|
+
"oauth_secret": oauth_response['clientSecret'],
|
515
|
+
"authentication_type": "OAUTH",
|
516
|
+
"entities": available_entities.map {|e| e.merge({'displayName' => client_describe["tenantName"]})}
|
517
|
+
},
|
518
|
+
"tenant_ids": available_entities.map{|e| e['entityId']}.uniq,
|
519
|
+
}
|
520
|
+
end
|
521
|
+
|
522
|
+
if defined?(@appinstance)
|
523
|
+
@appinstance.zuora_logins = task_data
|
524
|
+
@appinstance.save(:validate => false)
|
446
525
|
else
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
:
|
452
|
-
|
453
|
-
|
526
|
+
@appinstance = new_instance(
|
527
|
+
next_id,
|
528
|
+
zuora_entity_id,
|
529
|
+
zuora_client.rest_domain,
|
530
|
+
task_data: task_data,
|
531
|
+
retry_count: retry_count
|
532
|
+
)
|
454
533
|
end
|
455
534
|
end
|
535
|
+
rescue ActiveRecord::RecordNotUnique
|
536
|
+
retry if (retry_count -= 1).positive?
|
537
|
+
return
|
456
538
|
end
|
457
539
|
|
458
540
|
Apartment::Tenant.switch!("public")
|
@@ -540,6 +622,50 @@ module ZuoraConnect
|
|
540
622
|
end
|
541
623
|
end
|
542
624
|
|
625
|
+
def next_instance_id
|
626
|
+
min_instance_id = 24_999_999
|
627
|
+
(ZuoraConnect::AppInstance.all.where("id > #{min_instance_id}").order(id: :desc).limit(1).pluck(:id).first || min_instance_id) + 1
|
628
|
+
end
|
629
|
+
|
630
|
+
def new_instance(id, zuora_entity_id, rest_domain, task_data: nil, retry_count: 0)
|
631
|
+
app_instance = ZuoraConnect::AppInstance.new(
|
632
|
+
:id => id,
|
633
|
+
:api_token => generate_token,
|
634
|
+
:token => generate_token,
|
635
|
+
:oauth_expires_at => Time.now + 1000.years,
|
636
|
+
:zuora_domain => rest_domain,
|
637
|
+
:zuora_entity_ids => [zuora_entity_id]
|
638
|
+
)
|
639
|
+
|
640
|
+
if task_data.nil?
|
641
|
+
# no encryption
|
642
|
+
app_instance['zuora_logins'] = task_data
|
643
|
+
else
|
644
|
+
# kms encrypt
|
645
|
+
app_instance.zuora_logins = task_data
|
646
|
+
end
|
647
|
+
|
648
|
+
begin
|
649
|
+
app_instance.save(:validate => false)
|
650
|
+
rescue ActiveRecord::RecordNotUnique
|
651
|
+
raise if retry_count > 1
|
652
|
+
|
653
|
+
Thread.current[:appinstance] = nil
|
654
|
+
session['appInstance'] = nil
|
655
|
+
render 'zuora_connect/static/error_handled', :locals => {
|
656
|
+
:title => 'Application could not create unique tokens.',
|
657
|
+
:message => 'Please contact support or retry launching application.'
|
658
|
+
}, :layout => false
|
659
|
+
return
|
660
|
+
end
|
661
|
+
|
662
|
+
app_instance
|
663
|
+
end
|
664
|
+
|
665
|
+
def generate_token
|
666
|
+
rand(36**64).to_s(36)
|
667
|
+
end
|
668
|
+
|
543
669
|
def setup_instance_via_dev_mode
|
544
670
|
session["appInstance"] = ZuoraConnect.configuration.dev_mode_appinstance
|
545
671
|
user = ZuoraConnect.configuration.dev_mode_user
|
@@ -28,11 +28,6 @@ module ZuoraConnect
|
|
28
28
|
::Rails.configuration.action_dispatch.x_sendfile_header = nil
|
29
29
|
end
|
30
30
|
|
31
|
-
if defined? Prometheus
|
32
|
-
initializer "prometheus.configure_rails_initialization" do |app|
|
33
|
-
app.middleware.use Prometheus::Middleware::Exporter,(options ={:path => '/connect/internal/metrics'})
|
34
|
-
end
|
35
|
-
end
|
36
31
|
initializer "zuora_connect.configure_rails_initialization" do |app|
|
37
32
|
app.middleware.insert_after Rack::Sendfile, ZuoraConnect::MetricsMiddleware
|
38
33
|
app.middleware.insert_after ActionDispatch::RequestId, ZuoraConnect::RequestIdMiddleware
|
@@ -40,6 +35,15 @@ module ZuoraConnect
|
|
40
35
|
app.config.middleware.use ZuoraConnect::JsonParseErrors
|
41
36
|
end
|
42
37
|
|
38
|
+
if defined? Prometheus
|
39
|
+
require 'rack'
|
40
|
+
require 'prometheus/middleware/exporter'
|
41
|
+
initializer "prometheus.configure_rails_initialization" do |app|
|
42
|
+
app.middleware.insert_after ZuoraConnect::MetricsMiddleware, Prometheus::Middleware::Exporter, path: '/connect/internal/metrics'
|
43
|
+
app.config.middleware.use Rack::Deflater, if: ->(env, *) { env['PATH_INFO'] == '/connect/internal/metrics' }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
43
47
|
# hook to process_action
|
44
48
|
ActiveSupport::Notifications.subscribe('process_action.action_controller', ZuoraConnect::PageRequest.new)
|
45
49
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zuora_connect
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.60c
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Connect Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: apartment
|
@@ -429,9 +429,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
429
429
|
version: '0'
|
430
430
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
431
431
|
requirements:
|
432
|
-
- - "
|
432
|
+
- - ">"
|
433
433
|
- !ruby/object:Gem::Version
|
434
|
-
version:
|
434
|
+
version: 1.3.1
|
435
435
|
requirements: []
|
436
436
|
rubygems_version: 3.0.3
|
437
437
|
signing_key:
|