zuora_connect 2.0.60r → 2.1.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.
- checksums.yaml +4 -4
- data/app/controllers/zuora_connect/static_controller.rb +12 -83
- data/app/models/zuora_connect/app_instance_base.rb +8 -131
- data/app/models/zuora_connect/zuora_user.rb +1 -1
- data/config/initializers/postgresql_adapter.rb +1 -71
- data/config/initializers/prometheus.rb +23 -78
- data/config/initializers/resque.rb +0 -14
- data/config/initializers/unicorn.rb +1 -29
- data/config/routes.rb +0 -5
- data/lib/middleware/json_parse_errors.rb +2 -13
- data/lib/middleware/metrics_middleware.rb +31 -45
- data/lib/resque/dynamic_queues.rb +1 -1
- data/lib/resque/plugins/app_instance_job.rb +10 -6
- data/lib/zuora_connect.rb +0 -3
- data/lib/zuora_connect/controllers/helpers.rb +73 -213
- data/lib/zuora_connect/railtie.rb +5 -24
- data/lib/zuora_connect/version.rb +1 -1
- metadata +4 -5
- data/lib/zuora_connect/zuora_audit.rb +0 -31
@@ -3,93 +3,38 @@ 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_#{Process.pid}.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
|
-
|
46
6
|
# Create a default Prometheus registry for our metrics.
|
47
7
|
prometheus = Prometheus::Client.registry
|
48
8
|
|
49
9
|
# Create your metrics.
|
50
|
-
ZUORA_VERSION =
|
51
|
-
CONNECT_VERSION =
|
52
|
-
RAILS_VERSION =
|
53
|
-
RUBY_V =
|
10
|
+
ZUORA_VERSION = Prometheus::Client::Gauge.new(:zuora_version, 'The current Zuora Gem version.')
|
11
|
+
CONNECT_VERSION = Prometheus::Client::Gauge.new(:gem_version, 'The current Connect Gem version.')
|
12
|
+
RAILS_VERSION = Prometheus::Client::Gauge.new(:rails_version, 'The current Rails version.')
|
13
|
+
RUBY_V = Prometheus::Client::Gauge.new(:ruby_version, 'The current Ruby version.')
|
54
14
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
15
|
+
# Register your metrics with the registry we previously created.
|
16
|
+
prometheus.register(ZUORA_VERSION);ZUORA_VERSION.set({version: ZuoraAPI::VERSION, name: ZuoraConnect::Telegraf.app_name},0)
|
17
|
+
prometheus.register(CONNECT_VERSION);CONNECT_VERSION.set({version: ZuoraConnect::VERSION, name: ZuoraConnect::Telegraf.app_name},0)
|
18
|
+
prometheus.register(RAILS_VERSION);RAILS_VERSION.set({version: Rails.version, name: ZuoraConnect::Telegraf.app_name},0)
|
19
|
+
prometheus.register(RUBY_V);RUBY_V.set({version: RUBY_VERSION, name: ZuoraConnect::Telegraf.app_name},0)
|
59
20
|
|
60
21
|
# Do they have resque jobs?
|
61
22
|
if defined? Resque.redis
|
62
|
-
REDIS_CONNECTION =
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
preset_labels: {type:'Unicorn-Killer', name: ZuoraConnect::Telegraf.app_name},
|
76
|
-
store_settings: sum_aggregation
|
77
|
-
)
|
23
|
+
REDIS_CONNECTION = Prometheus::Client::Gauge.new(:redis_connection, 'The status of the redis connection, 0 or 1')
|
24
|
+
FINISHED_JOBS = Prometheus::Client::Gauge.new(:finished_jobs, 'Done resque jobs')
|
25
|
+
WORKERS = Prometheus::Client::Gauge.new(:workers, 'Total resque workers')
|
26
|
+
ACTIVE_WORKERS = Prometheus::Client::Gauge.new(:active_workers, 'Active resque workers')
|
27
|
+
FAILED_JOBS = Prometheus::Client::Gauge.new(:failed_jobs, 'Failed resque jobs')
|
28
|
+
PENDING_JOBS = Prometheus::Client::Gauge.new(:pending_jobs, 'Pending resque jobs')
|
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)
|
78
36
|
|
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
37
|
end
|
38
|
+
|
94
39
|
end
|
95
40
|
end
|
@@ -5,20 +5,6 @@ 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
|
-
|
22
8
|
Resque.module_eval do
|
23
9
|
# Returns a hash, mapping queue names to queue sizes
|
24
10
|
def queue_sizes
|
@@ -3,35 +3,7 @@ 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
|
-
|
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
|
6
|
+
ZuoraConnect::AppInstance.write_to_telegraf(direction: 'Unicorn-Killer', tags: {app_instance: 0}, values: {kill: 1})
|
11
7
|
end
|
12
8
|
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
|
37
9
|
end
|
data/config/routes.rb
CHANGED
@@ -3,11 +3,6 @@ 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
|
-
|
11
6
|
namespace :api do
|
12
7
|
namespace :v1 do
|
13
8
|
resources :app_instance, :only => [:index], defaults: {format: :json} do
|
@@ -7,7 +7,7 @@ module ZuoraConnect
|
|
7
7
|
def call(env)
|
8
8
|
begin
|
9
9
|
@app.call(env)
|
10
|
-
rescue
|
10
|
+
rescue ActionDispatch::ParamsParser::ParseError => error
|
11
11
|
if env['HTTP_ACCEPT'] =~ /application\/json/ || env['CONTENT_TYPE'] =~ /application\/json/
|
12
12
|
return [
|
13
13
|
400, { "Content-Type" => "application/json" },
|
@@ -18,16 +18,5 @@ module ZuoraConnect
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
22
|
-
# Note(hartley): remove once the minimum supported version of Rails is 5.2
|
23
|
-
class DynamicRailsError < StandardError
|
24
|
-
def self.===(exception)
|
25
|
-
if Rails.version >= "5.2"
|
26
|
-
exception.is_a?(ActionDispatch::Http::Parameters::ParseError)
|
27
|
-
else
|
28
|
-
exception.is_a?(ActionDispatch::ParamsParser::ParseError)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
21
|
end
|
33
|
-
end
|
22
|
+
end
|
@@ -64,22 +64,6 @@ 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
|
-
|
83
67
|
#Thread.current[:appinstance] = nil
|
84
68
|
start_time = Time.now
|
85
69
|
begin
|
@@ -93,6 +77,35 @@ module ZuoraConnect
|
|
93
77
|
ZuoraConnect::AppInstanceBase.write_to_telegraf(direction: 'request-inbound-assets', tags: tags, values: values)
|
94
78
|
end
|
95
79
|
|
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
|
+
|
96
109
|
# Uncomment following block of code for handling engine requests/requests without controller
|
97
110
|
# else
|
98
111
|
# # Handling requests which do not have controllers (engines)
|
@@ -106,10 +119,10 @@ module ZuoraConnect
|
|
106
119
|
content_type = @headers['Content-Type'].split(';')[0] if @headers['Content-Type']
|
107
120
|
content_type = content_type.gsub('text/javascript', 'application/javascript')
|
108
121
|
tags = {status: @status, content_type: content_type}
|
109
|
-
|
122
|
+
|
110
123
|
tags = tags.merge({controller: 'ActionController'})
|
111
124
|
tags = tags.merge({action: 'RoutingError' }) if @status == 404
|
112
|
-
|
125
|
+
|
113
126
|
values = {response_time: ((Time.now - start_time)*1000).round(2) }
|
114
127
|
|
115
128
|
ZuoraConnect::AppInstanceBase.write_to_telegraf(direction: :inbound, tags: tags, values: values)
|
@@ -120,32 +133,5 @@ module ZuoraConnect
|
|
120
133
|
[@status, @headers, @response]
|
121
134
|
end
|
122
135
|
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
|
150
136
|
end
|
151
137
|
end
|
@@ -12,14 +12,14 @@ module Resque
|
|
12
12
|
when "Hash"
|
13
13
|
data = args.merge({:worker_class => self.to_s})
|
14
14
|
end
|
15
|
-
if Rails.logger.is_a?(Ougai::Logger)
|
15
|
+
if Rails.logger.is_a?(Ougai::Logger)
|
16
16
|
Rails.logger.with_fields = {job: data, trace_id: SecureRandom.uuid, name: "RailsWorker"}
|
17
17
|
end
|
18
18
|
|
19
19
|
begin
|
20
|
-
connection_count ||= 0
|
20
|
+
connection_count ||= 0
|
21
21
|
@appinstance = ZuoraConnect::AppInstance.find(args['app_instance_id'].to_i)
|
22
|
-
|
22
|
+
job_start_log(args)
|
23
23
|
|
24
24
|
@appinstance.new_session(holding_pattern: true)
|
25
25
|
rescue ActiveRecord::RecordNotFound => exception
|
@@ -52,12 +52,12 @@ module Resque
|
|
52
52
|
return
|
53
53
|
rescue ZuoraConnect::Exceptions::ConnectCommunicationError => exception
|
54
54
|
Rails.logger.warn("Enqueue Job Again ~ 2 mins", exception)
|
55
|
-
@appinstance.queue_pause(time: 2.minutes.to_i)
|
55
|
+
@appinstance.queue_pause(time: 2.minutes.to_i)
|
56
56
|
Resque.enqueue_to(self.job.queue, self.job.payload['class'], args)
|
57
57
|
return
|
58
58
|
rescue Net::ReadTimeout, Net::OpenTimeout, Errno::ECONNRESET, Errno::ECONNREFUSED, SocketError => exception
|
59
59
|
Rails.logger.warn("Enqueue Job Again ~ 2 mins", exception)
|
60
|
-
@appinstance.queue_pause(time: 2.minutes.to_i)
|
60
|
+
@appinstance.queue_pause(time: 2.minutes.to_i)
|
61
61
|
Resque.enqueue_to(self.job.queue, self.job.payload['class'], args)
|
62
62
|
return
|
63
63
|
end
|
@@ -68,6 +68,10 @@ module Resque
|
|
68
68
|
@appinstance.cache_app_instance if defined?(@appinstance)
|
69
69
|
Rails.logger.flush if Rails.logger.methods.include?(:flush)
|
70
70
|
end
|
71
|
+
|
72
|
+
def job_start_log(args)
|
73
|
+
Rails.logger.info("Starting job")
|
74
|
+
end
|
71
75
|
end
|
72
76
|
end
|
73
|
-
end
|
77
|
+
end
|
data/lib/zuora_connect.rb
CHANGED
@@ -13,9 +13,6 @@ require 'logging/connect_formatter'
|
|
13
13
|
require 'metrics/influx/point_value'
|
14
14
|
require 'metrics/net'
|
15
15
|
require 'mono_logger'
|
16
|
-
require 'zuora_connect/zuora_audit'
|
17
|
-
require 'active_record'
|
18
|
-
::ActiveRecord::Base.send :include, ZuoraConnect::ZuoraAudit
|
19
16
|
|
20
17
|
module ZuoraConnect
|
21
18
|
class << self
|
@@ -124,24 +124,14 @@ module ZuoraConnect
|
|
124
124
|
ElasticAPM.set_user(session["#{@appinstance.id}::user::email"]) if defined?(ElasticAPM) && ElasticAPM.running?
|
125
125
|
PaperTrail.whodunnit = session["#{@appinstance.id}::user::email"] if defined?(PaperTrail)
|
126
126
|
end
|
127
|
-
|
128
|
-
locale = (session["#{@appinstance.id}::user::locale"] || "").gsub("_", "-")
|
129
127
|
begin
|
128
|
+
locale = session["#{@appinstance.id}::user::locale"]
|
130
129
|
I18n.locale = locale.present? ? locale : @appinstance.locale
|
131
130
|
rescue I18n::InvalidLocale => ex
|
132
|
-
if locale.include?("-")
|
133
|
-
locale = locale.split("-").first
|
134
|
-
retry
|
135
|
-
elsif locale != session["#{@appinstance.id}::user::language"]
|
136
|
-
locale = session["#{@appinstance.id}::user::language"]
|
137
|
-
retry
|
138
|
-
end
|
139
131
|
ZuoraConnect.logger.error(ex) if !ZuoraConnect::AppInstance::IGNORED_LOCALS.include?(ex.locale.to_s.downcase)
|
140
132
|
end
|
141
133
|
begin
|
142
|
-
|
143
|
-
Time.zone = session["#{@appinstance.id}::user::timezone"] ? session["#{@appinstance.id}::user::timezone"] : @appinstance.timezone
|
144
|
-
end
|
134
|
+
Time.zone = session["#{@appinstance.id}::user::timezone"] ? session["#{@appinstance.id}::user::timezone"] : @appinstance.timezone
|
145
135
|
rescue
|
146
136
|
ZuoraConnect.logger.error(ex)
|
147
137
|
end
|
@@ -229,80 +219,6 @@ module ZuoraConnect
|
|
229
219
|
return (request.headers['ZuoraCurrentEntity'].present? || cookies['ZuoraCurrentEntity'].present?)
|
230
220
|
end
|
231
221
|
|
232
|
-
def create_new_instance
|
233
|
-
ZuoraConnect::AppInstance.read_master_db do
|
234
|
-
Thread.current[:appinstance] = nil
|
235
|
-
ZuoraConnect.logger.with_fields = {} if ZuoraConnect.logger.is_a?(Ougai::Logger)
|
236
|
-
Rails.logger.with_fields = {} if Rails.logger.is_a?(Ougai::Logger)
|
237
|
-
|
238
|
-
if defined?(ElasticAPM) && ElasticAPM.running? && ElasticAPM.respond_to?(:set_label)
|
239
|
-
ElasticAPM.set_label(:trace_id, request.uuid)
|
240
|
-
end
|
241
|
-
|
242
|
-
zuora_host = request.headers['zuora-host']
|
243
|
-
zuora_entity_id = (request.headers['zuora-entity-ids'] || '').gsub(
|
244
|
-
'-',
|
245
|
-
''
|
246
|
-
).split(',').first
|
247
|
-
|
248
|
-
# Validate host present
|
249
|
-
if zuora_host.blank?
|
250
|
-
render json: {
|
251
|
-
status: 401,
|
252
|
-
message: 'zuora-host header was not supplied.'
|
253
|
-
}, status: :unauthorized
|
254
|
-
return
|
255
|
-
end
|
256
|
-
|
257
|
-
# Validate entity-ids present
|
258
|
-
if zuora_entity_id.blank?
|
259
|
-
render json: {
|
260
|
-
status: 401,
|
261
|
-
message: 'zuora-entity-ids header was not supplied.'
|
262
|
-
}, status: :unauthorized
|
263
|
-
return
|
264
|
-
end
|
265
|
-
|
266
|
-
rest_domain = ZuoraAPI::Login.new(url: "https://#{zuora_host}").rest_domain
|
267
|
-
app_instance_id = ZuoraConnect::AppInstance.where(
|
268
|
-
'zuora_entity_ids ?& array[:entities] AND zuora_domain = :host',
|
269
|
-
entities: [zuora_entity_id],
|
270
|
-
host: rest_domain
|
271
|
-
).pluck(:id).first
|
272
|
-
|
273
|
-
if app_instance_id.present?
|
274
|
-
render json: {
|
275
|
-
status: 409,
|
276
|
-
message: 'Instance already exists.',
|
277
|
-
app_instance_id: app_instance_id
|
278
|
-
}, status: 409
|
279
|
-
else
|
280
|
-
Apartment::Tenant.switch!("public")
|
281
|
-
retry_count = 3
|
282
|
-
begin
|
283
|
-
@appinstance = new_instance(
|
284
|
-
next_instance_id,
|
285
|
-
zuora_entity_id,
|
286
|
-
rest_domain,
|
287
|
-
retry_count: retry_count
|
288
|
-
)
|
289
|
-
rescue ActiveRecord::RecordNotUnique
|
290
|
-
retry if (retry_count -= 1).positive?
|
291
|
-
return
|
292
|
-
end
|
293
|
-
|
294
|
-
app_instance_id = @appinstance.id
|
295
|
-
end
|
296
|
-
|
297
|
-
begin
|
298
|
-
Apartment::Tenant.switch!('public')
|
299
|
-
Apartment::Tenant.create(app_instance_id.to_s)
|
300
|
-
rescue Apartment::TenantExists
|
301
|
-
ZuoraConnect.logger.debug('Tenant Already Exists')
|
302
|
-
end
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
222
|
private
|
307
223
|
def setup_instance_via_prod_mode
|
308
224
|
zuora_entity_id = request.headers['ZuoraCurrentEntity'] || cookies['ZuoraCurrentEntity']
|
@@ -310,7 +226,7 @@ module ZuoraConnect
|
|
310
226
|
if zuora_entity_id.present?
|
311
227
|
zuora_tenant_id = cookies['Zuora-Tenant-Id']
|
312
228
|
zuora_user_id = cookies['Zuora-User-Id']
|
313
|
-
zuora_host = request.headers[
|
229
|
+
zuora_host = request.headers["HTTP_X_FORWARDED_HOST"] || "apisandbox.zuora.com"
|
314
230
|
|
315
231
|
zuora_details = {'host' => zuora_host, 'user_id' => zuora_user_id, 'tenant_id' => zuora_tenant_id, 'entity_id' => zuora_entity_id}
|
316
232
|
auth_headers = {}
|
@@ -412,16 +328,13 @@ module ZuoraConnect
|
|
412
328
|
|
413
329
|
zuora_user_id = cookies['Zuora-User-Id'] || session["ZuoraCurrentIdentity"]['userId']
|
414
330
|
|
331
|
+
#One deployed instance
|
415
332
|
if appinstances.size == 1
|
416
333
|
ZuoraConnect.logger.debug("Instance is #{appinstances.to_h.keys.first}")
|
417
334
|
@appinstance = ZuoraConnect::AppInstance.find(appinstances.to_h.keys.first)
|
418
|
-
end
|
419
335
|
|
420
|
-
# One deployed instance with credentials
|
421
|
-
if defined?(@appinstance) && !@appinstance['zuora_logins'].nil?
|
422
336
|
#Add user/update
|
423
337
|
begin
|
424
|
-
ZuoraConnect::ZuoraUser.reset_table_name
|
425
338
|
@zuora_user = ZuoraConnect::ZuoraUser.where(:zuora_user_id => zuora_user_id).first
|
426
339
|
rescue ActiveRecord::StatementInvalid => ex
|
427
340
|
if ex.message.include?("PG::UndefinedTable") && ex.message.include?("zuora_users")
|
@@ -442,12 +355,10 @@ module ZuoraConnect
|
|
442
355
|
@zuora_user = ZuoraConnect::ZuoraUser.create!(:zuora_user_id => zuora_user_id, :zuora_identity_response => {zuora_entity_id => session["ZuoraCurrentIdentity"]})
|
443
356
|
end
|
444
357
|
@zuora_user.session = session
|
445
|
-
ZuoraConnect::ZuoraUser.current_user_id = zuora_user_id
|
446
358
|
session["#{@appinstance.id}::user::localUserId"] = @zuora_user.id
|
447
359
|
session["#{@appinstance.id}::user::email"] = session['ZuoraCurrentIdentity']["username"]
|
448
360
|
session["#{@appinstance.id}::user::timezone"] = session['ZuoraCurrentIdentity']["timeZone"]
|
449
|
-
session["#{@appinstance.id}::user::
|
450
|
-
session["#{@appinstance.id}::user::locale"] = session['ZuoraCurrentIdentity']["locale"]
|
361
|
+
session["#{@appinstance.id}::user::locale"] = session['ZuoraCurrentIdentity']["language"]
|
451
362
|
session["appInstance"] = @appinstance.id
|
452
363
|
|
453
364
|
#We have multiple, user must pick
|
@@ -469,85 +380,79 @@ module ZuoraConnect
|
|
469
380
|
return
|
470
381
|
end
|
471
382
|
Apartment::Tenant.switch!("public")
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
ActiveRecord::Base.transaction do
|
476
|
-
ActiveRecord::Base.connection.execute('LOCK public.zuora_users IN ACCESS EXCLUSIVE MODE')
|
383
|
+
ActiveRecord::Base.transaction do
|
384
|
+
ActiveRecord::Base.connection.execute('LOCK public.zuora_users IN ACCESS EXCLUSIVE MODE')
|
385
|
+
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)
|
477
386
|
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
redirect_to "https://#{zuora_host}/apps/newlogin.do?retURL=#{request.fullpath}"
|
483
|
-
return
|
484
|
-
end
|
485
|
-
end
|
387
|
+
if appinstances.size > 0
|
388
|
+
redirect_to "https://#{zuora_host}/apps/newlogin.do?retURL=#{request.fullpath}"
|
389
|
+
return
|
390
|
+
end
|
486
391
|
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
)
|
507
|
-
|
508
|
-
new_zuora_client = ZuoraAPI::Oauth.new(url: "https://#{zuora_host}", oauth_client_id: oauth_response["clientId"], oauth_secret: oauth_response["clientSecret"] )
|
509
|
-
if session["ZuoraCurrentUserInfo"].blank?
|
510
|
-
client_describe, response = new_zuora_client.rest_call(url: zuora_client.rest_endpoint("genesis/user/info").gsub('v1/', ''), session_type: :bearer)
|
511
|
-
else
|
512
|
-
client_describe = session["ZuoraCurrentUserInfo"]
|
513
|
-
end
|
392
|
+
next_id = (ZuoraConnect::AppInstance.all.where('id > 24999999').order(id: :desc).limit(1).pluck(:id).first || 24999999) + 1
|
393
|
+
user = (ENV['DEIS_APP'] || "Application").split('-').map(&:capitalize).join(' ')
|
394
|
+
body = {
|
395
|
+
'userId' => zuora_user_id,
|
396
|
+
'entityIds' => [zuora_entity_id.unpack("a8a4a4a4a12").join('-')],
|
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
|
+
)
|
514
411
|
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
ZuoraConnect::AppInstance::LOGIN_TENANT_DESTINATION => {
|
522
|
-
"tenant_type": "Zuora",
|
523
|
-
"username": session["ZuoraCurrentIdentity"]["username"],
|
524
|
-
"url": new_zuora_client.url,
|
525
|
-
"status": "Active",
|
526
|
-
"oauth_client_id": oauth_response['clientId'],
|
527
|
-
"oauth_secret": oauth_response['clientSecret'],
|
528
|
-
"authentication_type": "OAUTH",
|
529
|
-
"entities": available_entities.map {|e| e.merge({'displayName' => client_describe["tenantName"]})}
|
530
|
-
},
|
531
|
-
"tenant_ids": available_entities.map{|e| e['entityId']}.uniq,
|
532
|
-
}
|
533
|
-
end
|
412
|
+
new_zuora_client = ZuoraAPI::Oauth.new(url: "https://#{zuora_host}", oauth_client_id: oauth_response["clientId"], oauth_secret: oauth_response["clientSecret"] )
|
413
|
+
if session["ZuoraCurrentUserInfo"].blank?
|
414
|
+
client_describe, response = new_zuora_client.rest_call(url: zuora_client.rest_endpoint("genesis/user/info").gsub('v1/', ''), session_type: :bearer)
|
415
|
+
else
|
416
|
+
client_describe = session["ZuoraCurrentUserInfo"]
|
417
|
+
end
|
534
418
|
|
535
|
-
|
536
|
-
|
537
|
-
|
419
|
+
available_entities = client_describe["accessibleEntities"].select {|entity| entity['id'] == zuora_entity_id}
|
420
|
+
task_data = {
|
421
|
+
"id": next_id,
|
422
|
+
"name": client_describe["tenantName"],
|
423
|
+
"mode": "Collections",
|
424
|
+
"status": "Running",
|
425
|
+
ZuoraConnect::AppInstance::LOGIN_TENANT_DESTINATION => {
|
426
|
+
"tenant_type": "Zuora",
|
427
|
+
"username": session["ZuoraCurrentIdentity"]["username"],
|
428
|
+
"url": new_zuora_client.url,
|
429
|
+
"status": "Active",
|
430
|
+
"oauth_client_id": oauth_response['clientId'],
|
431
|
+
"oauth_secret": oauth_response['clientSecret'],
|
432
|
+
"authentication_type": "OAUTH",
|
433
|
+
"entities": available_entities.map {|e| e.merge({'displayName' => client_describe["tenantName"]})}
|
434
|
+
},
|
435
|
+
"tenant_ids": available_entities.map{|e| e['entityId']}.uniq,
|
436
|
+
}
|
437
|
+
mapped_values = {:id => next_id, :api_token => rand(36**64).to_s(36), :token => rand(36**64).to_s(36), :zuora_logins => task_data, :oauth_expires_at => Time.now + 1000.years, :zuora_domain => zuora_client.rest_domain, :zuora_entity_ids => [zuora_entity_id]}
|
438
|
+
@appinstance = ZuoraConnect::AppInstance.new(mapped_values)
|
439
|
+
retry_count = 0
|
440
|
+
begin
|
441
|
+
@appinstance.save(:validate => false)
|
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
|
538
446
|
else
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
447
|
+
Thread.current[:appinstance] = nil
|
448
|
+
session["appInstance"] = nil
|
449
|
+
render "zuora_connect/static/error_handled", :locals => {
|
450
|
+
:title => "Application could not create unique tokens.",
|
451
|
+
:message => "Please contact support or retry launching application."
|
452
|
+
}, :layout => false
|
453
|
+
return
|
546
454
|
end
|
547
455
|
end
|
548
|
-
rescue ActiveRecord::RecordNotUnique
|
549
|
-
retry if (retry_count -= 1).positive?
|
550
|
-
return
|
551
456
|
end
|
552
457
|
|
553
458
|
Apartment::Tenant.switch!("public")
|
@@ -578,8 +483,8 @@ module ZuoraConnect
|
|
578
483
|
|
579
484
|
rescue ZuoraAPI::Exceptions::ZuoraAPIError, Exception => ex
|
580
485
|
if ex.message.include?("Referenced User resource(s) not found") && ex.class == ZuoraAPI::Exceptions::ZuoraAPIError
|
581
|
-
locals = {title: "Provisioning Error", message: "New
|
582
|
-
render "zuora_connect/static/error_handled", locals: locals, status:
|
486
|
+
locals = {title: "Provisioning Error", message: "New tenats need to be provisioned by API Gateway('#{ex.message}'). Please contact support."}
|
487
|
+
render "zuora_connect/static/error_handled", locals: locals, status: 400, layout: false
|
583
488
|
else
|
584
489
|
session.clear
|
585
490
|
if defined?(ex.response) && ex.response.present? && defined?(ex.response.body)
|
@@ -635,57 +540,12 @@ module ZuoraConnect
|
|
635
540
|
end
|
636
541
|
end
|
637
542
|
|
638
|
-
def next_instance_id
|
639
|
-
min_instance_id = 24_999_999
|
640
|
-
(ZuoraConnect::AppInstance.all.where("id > #{min_instance_id}").order(id: :desc).limit(1).pluck(:id).first || min_instance_id) + 1
|
641
|
-
end
|
642
|
-
|
643
|
-
def new_instance(id, zuora_entity_id, rest_domain, task_data: nil, retry_count: 0)
|
644
|
-
app_instance = ZuoraConnect::AppInstance.new(
|
645
|
-
:id => id,
|
646
|
-
:api_token => generate_token,
|
647
|
-
:token => generate_token,
|
648
|
-
:oauth_expires_at => Time.now + 1000.years,
|
649
|
-
:zuora_domain => rest_domain,
|
650
|
-
:zuora_entity_ids => [zuora_entity_id]
|
651
|
-
)
|
652
|
-
|
653
|
-
if task_data.nil?
|
654
|
-
# no encryption
|
655
|
-
app_instance['zuora_logins'] = task_data
|
656
|
-
else
|
657
|
-
# kms encrypt
|
658
|
-
app_instance.zuora_logins = task_data
|
659
|
-
end
|
660
|
-
|
661
|
-
begin
|
662
|
-
app_instance.save(:validate => false)
|
663
|
-
rescue ActiveRecord::RecordNotUnique
|
664
|
-
raise if retry_count > 1
|
665
|
-
|
666
|
-
Thread.current[:appinstance] = nil
|
667
|
-
session['appInstance'] = nil
|
668
|
-
render 'zuora_connect/static/error_handled', :locals => {
|
669
|
-
:title => 'Application could not create unique tokens.',
|
670
|
-
:message => 'Please contact support or retry launching application.'
|
671
|
-
}, :layout => false
|
672
|
-
return
|
673
|
-
end
|
674
|
-
|
675
|
-
app_instance
|
676
|
-
end
|
677
|
-
|
678
|
-
def generate_token
|
679
|
-
rand(36**64).to_s(36)
|
680
|
-
end
|
681
|
-
|
682
543
|
def setup_instance_via_dev_mode
|
683
544
|
session["appInstance"] = ZuoraConnect.configuration.dev_mode_appinstance
|
684
545
|
user = ZuoraConnect.configuration.dev_mode_user
|
685
546
|
key = ZuoraConnect.configuration.dev_mode_pass
|
686
547
|
values = {:user => user , :key => key, :appinstance => session["appInstance"]}
|
687
548
|
@appinstance = ZuoraConnect::AppInstance.find_by(:id => values[:appinstance].to_i)
|
688
|
-
ZuoraConnect::ZuoraUser.current_user_id = 0
|
689
549
|
if @appinstance.blank?
|
690
550
|
Apartment::Tenant.switch!("public")
|
691
551
|
begin
|