zuora_connect 0 → 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/assets/javascripts/hallway_wrapper/after.js +22 -3
- data/app/controllers/zuora_connect/static_controller.rb +27 -22
- data/app/helpers/zuora_connect/application_helper.rb +10 -0
- data/app/models/zuora_connect/app_instance_base.rb +419 -136
- data/app/models/zuora_connect/login.rb +1 -0
- data/app/models/zuora_connect/telegraf.rb +11 -7
- data/app/models/zuora_connect/zuora_user.rb +7 -0
- data/app/views/sql/refresh_aggregate_table.txt +3 -2
- data/app/views/zuora_connect/static/error_handled.html.erb +76 -0
- data/app/views/zuora_connect/static/error_handled.js.erb +1 -0
- data/app/views/zuora_connect/static/error_unhandled.erb +85 -0
- data/app/views/zuora_connect/static/error_unhandled.js.erb +1 -0
- data/app/views/zuora_connect/static/launch.html.erb +71 -76
- data/config/initializers/patches.rb +9 -0
- data/config/initializers/redis.rb +24 -5
- data/config/initializers/resque.rb +13 -1
- data/config/routes.rb +0 -2
- data/db/migrate/20100718151733_create_connect_app_instances.rb +1 -1
- data/db/migrate/20101024162319_add_tokens_to_app_instance.rb +1 -1
- data/db/migrate/20101024220705_add_token_to_app_instance.rb +1 -1
- data/db/migrate/20110131211919_add_sessions_table.rb +1 -1
- data/db/migrate/20110411200303_add_expiration_to_app_instance.rb +1 -1
- data/db/migrate/20110413191512_add_new_api_token.rb +1 -1
- data/db/migrate/20110503003602_add_catalog_data_to_app_instance.rb +1 -1
- data/db/migrate/20110503003603_add_catalog_mappings_to_app_instance.rb +1 -1
- data/db/migrate/20110503003604_catalog_default.rb +1 -1
- data/db/migrate/20180301052853_add_catalog_attempted_at.rb +1 -1
- data/db/migrate/20181206162339_add_fields_to_instance.rb +1 -1
- data/db/migrate/20190520232221_add_zuora_user_table_and_alter_app_instance_id_table.rb +18 -0
- data/db/migrate/20190520232222_add_unique_index.rb +6 -0
- data/db/migrate/20190520232223_add_provisioning_fields.rb +6 -0
- data/db/migrate/20190520232224_add_environment_fields.rb +13 -0
- data/lib/logging/connect_formatter.rb +44 -0
- data/lib/metrics/net.rb +2 -2
- data/lib/middleware/bad_multipart_form_data_sanitizer.rb +21 -0
- data/lib/middleware/json_parse_errors.rb +22 -0
- data/lib/middleware/metrics_middleware.rb +5 -2
- data/lib/middleware/request_id_middleware.rb +17 -0
- data/lib/resque/dynamic_queues.rb +34 -12
- data/lib/resque/plugins/app_instance_job.rb +77 -0
- data/lib/resque/plugins/custom_logger.rb +10 -24
- data/lib/zuora_connect.rb +116 -5
- data/lib/zuora_connect/configuration.rb +4 -3
- data/lib/zuora_connect/controllers/helpers.rb +483 -176
- data/lib/zuora_connect/engine.rb +8 -5
- data/lib/zuora_connect/exceptions.rb +4 -2
- data/lib/zuora_connect/railtie.rb +50 -19
- data/lib/zuora_connect/version.rb +2 -2
- metadata +98 -60
- data/app/views/zuora_connect/static/invalid_app_instance_error.html.erb +0 -65
- data/app/views/zuora_connect/static/invalid_launch_request.html +0 -65
- data/app/views/zuora_connect/static/session_error.html.erb +0 -63
- data/config/initializers/elastic_apm.rb +0 -25
- data/lib/zuora_connect/views/helpers.rb +0 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0342c5ac7396b4e8ba75aff8dbab5d579fa6d0ad04a421b7d1d809ab3abbd90a
|
|
4
|
+
data.tar.gz: 70f7277a93fec8e481f63e56f85e466b5e0b4d1307e2413e4f8da9497e980be2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: eb6497a343dde2b4a3edfe470c8e5a44eb37ff99b75ed434138c280e8ac25bf36806d58fbb477772182596917f1c37c0e237bd55e88f646e149743477fba2f15
|
|
7
|
+
data.tar.gz: f0b1f8b6f647f204ce8c4bfed7a8e77b49f3aada0faf6a0c31fc47675f5bfca67feb464692006bcb490977a577d1d5a3feab53886815f4c6472023e9ade6823b
|
|
@@ -4,12 +4,31 @@ window.define = previousDefine;
|
|
|
4
4
|
if (isHallway()) {
|
|
5
5
|
$( document ).ajaxError(function( event, jqxhr, settings, thrownError ) {
|
|
6
6
|
if ( jqxhr.status === 401) {
|
|
7
|
-
window.location.
|
|
7
|
+
fetch("https://" + window.location.host + "/apps/v1/navigation").then(response => {
|
|
8
|
+
if (response.status === 401) {
|
|
9
|
+
deleteAllCookies();
|
|
10
|
+
window.location.href = '/apps/newlogin.do?retURL=' + window.location.pathname;
|
|
11
|
+
}
|
|
12
|
+
});
|
|
8
13
|
}
|
|
9
14
|
});
|
|
10
15
|
}
|
|
11
16
|
|
|
12
17
|
function isHallway() {
|
|
13
|
-
var regex = new RegExp("
|
|
14
|
-
|
|
18
|
+
var regex = new RegExp("(?<=\\/)services\\/.*");
|
|
19
|
+
if (regex.test(window.location.pathname)) {
|
|
20
|
+
return window.location.pathname.match(regex)[0]
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function deleteAllCookies() {
|
|
26
|
+
var cookies = document.cookie.split(";");
|
|
27
|
+
|
|
28
|
+
for (var i = 0; i < cookies.length; i++) {
|
|
29
|
+
var cookie = cookies[i];
|
|
30
|
+
var eqPos = cookie.indexOf("=");
|
|
31
|
+
var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
|
|
32
|
+
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/";
|
|
33
|
+
}
|
|
15
34
|
}
|
|
@@ -1,31 +1,30 @@
|
|
|
1
1
|
module ZuoraConnect
|
|
2
2
|
class StaticController < ApplicationController
|
|
3
|
-
before_action :authenticate_connect_app_request, :except => [:metrics, :health, :
|
|
4
|
-
before_action :clear_connect_app_session, :only => [:metrics, :health, :
|
|
5
|
-
after_action :persist_connect_app_session, :except => [:metrics, :health, :
|
|
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
6
|
|
|
7
7
|
skip_before_action :verify_authenticity_token, :only => [:initialize_app]
|
|
8
8
|
|
|
9
|
-
def session_error
|
|
10
|
-
respond_to do |format|
|
|
11
|
-
format.html
|
|
12
|
-
format.json { render json: { message: "Session Error", status: 500 }, status: 500 }
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def invalid_app_instance_error
|
|
17
|
-
respond_to do |format|
|
|
18
|
-
format.html
|
|
19
|
-
format.json {render json: { message: "Invalid App Instance", status: 500 }, status: 500 }
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
9
|
def metrics
|
|
24
10
|
type = params[:type].present? ? params[:type] : "versions"
|
|
25
11
|
render json: ZuoraConnect::AppInstance.get_metrics(type).to_json, status: 200
|
|
26
12
|
end
|
|
27
13
|
|
|
28
14
|
def health
|
|
15
|
+
if params[:error].present?
|
|
16
|
+
begin
|
|
17
|
+
raise ZuoraConnect::Exceptions::Error.new('This is an error')
|
|
18
|
+
rescue => ex
|
|
19
|
+
case params[:error]
|
|
20
|
+
when 'Log'
|
|
21
|
+
Rails.logger.error("Error in Health", ex)
|
|
22
|
+
when 'Exception'
|
|
23
|
+
raise
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
29
28
|
render json: {
|
|
30
29
|
message: "Alive",
|
|
31
30
|
status: 200
|
|
@@ -35,15 +34,21 @@ module ZuoraConnect
|
|
|
35
34
|
def initialize_app
|
|
36
35
|
begin
|
|
37
36
|
authenticate_connect_app_request
|
|
37
|
+
@appinstance.new_session(:session => @appinstance.data_lookup(:session => session))
|
|
38
38
|
render json: {
|
|
39
39
|
message: "Success",
|
|
40
40
|
status: 200
|
|
41
41
|
}, status: 200
|
|
42
|
-
rescue
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
rescue => ex
|
|
43
|
+
Rails.logger.error("Failed to Initialize application", ex)
|
|
44
|
+
if performed?
|
|
45
|
+
Rails.logger.error("Failed to Initialize application #{performed?}", ex)
|
|
46
|
+
else
|
|
47
|
+
render json: {
|
|
48
|
+
message: "Failure initializing app instance",
|
|
49
|
+
status: 500
|
|
50
|
+
}, status: 500
|
|
51
|
+
end
|
|
47
52
|
end
|
|
48
53
|
end
|
|
49
54
|
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
module ZuoraConnect
|
|
2
2
|
module ApplicationHelper
|
|
3
|
+
def is_app_admin?
|
|
4
|
+
return @appinstance.blank? ? false : session["#{@appinstance.id}::admin"]
|
|
5
|
+
end
|
|
3
6
|
|
|
7
|
+
def zuora_user
|
|
8
|
+
return @zuora_user
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def connect_meta_tags
|
|
12
|
+
"<meta name=\"z-hallway-prefix\" content=\"#{ Thread.current[:isHallway] }\">".html_safe
|
|
13
|
+
end
|
|
4
14
|
end
|
|
5
15
|
end
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
module ZuoraConnect
|
|
2
2
|
require "uri"
|
|
3
|
+
require 'aws-sigv4'
|
|
4
|
+
require 'aws-sdk-s3'
|
|
5
|
+
require 'aws-sdk-ses'
|
|
6
|
+
require 'aws-sdk-kms'
|
|
3
7
|
class AppInstanceBase < ActiveRecord::Base
|
|
4
8
|
default_scope {select(ZuoraConnect::AppInstance.column_names.delete_if {|x| ["catalog_mapping", "catalog"].include?(x) }) }
|
|
5
9
|
after_initialize :init
|
|
6
|
-
after_create :
|
|
10
|
+
after_create :initialize_redis_placeholders
|
|
7
11
|
before_destroy :prune_data
|
|
8
12
|
|
|
9
13
|
self.table_name = "zuora_connect_app_instances"
|
|
@@ -15,7 +19,19 @@ module ZuoraConnect
|
|
|
15
19
|
API_LIMIT_TIMEOUT = 2.minutes #Used to set the default for expiring timeout when api rate limiting is in effect
|
|
16
20
|
BLANK_OBJECT_ID_LOOKUP = 'BlankValueSupplied'
|
|
17
21
|
HOLDING_PATTERN_SLEEP = 5.seconds
|
|
18
|
-
|
|
22
|
+
CONNECT_APPLICATION_ID = 0
|
|
23
|
+
CONNECT_COMMUNICATION_SLEEP = Rails.env.test? ? 0.seconds : 5.seconds
|
|
24
|
+
IGNORED_LOCALS = ['fr', 'ja', 'es', 'zh', 'de']
|
|
25
|
+
INTERNAL_HOSTS = []
|
|
26
|
+
LOGIN_TENANT_DESTINATION = 'target_login'
|
|
27
|
+
AWS_AUTH_ERRORS = [
|
|
28
|
+
Aws::Sigv4::Errors::MissingCredentialsError,
|
|
29
|
+
Aws::Errors::MissingCredentialsError,
|
|
30
|
+
Aws::S3::Errors::AccessDenied,
|
|
31
|
+
Aws::SES::Errors::AccessDenied,
|
|
32
|
+
Aws::KMS::Errors::AccessDeniedException
|
|
33
|
+
].freeze
|
|
34
|
+
AWS_AUTH_ERRORS_MSG = "AWS Auth Errors".freeze
|
|
19
35
|
|
|
20
36
|
def init
|
|
21
37
|
self.connect_user = 'Nobody'
|
|
@@ -27,46 +43,73 @@ module ZuoraConnect
|
|
|
27
43
|
self.attr_builder("timezone", ZuoraConnect.configuration.default_time_zone)
|
|
28
44
|
self.attr_builder("locale", ZuoraConnect.configuration.default_locale)
|
|
29
45
|
PaperTrail.whodunnit = "Backend" if defined?(PaperTrail)
|
|
30
|
-
if defined?(ElasticAPM)
|
|
46
|
+
if defined?(ElasticAPM) && ElasticAPM.running?
|
|
31
47
|
ElasticAPM.set_user("Backend")
|
|
32
|
-
ElasticAPM.
|
|
48
|
+
if ElasticAPM.respond_to?(:set_label)
|
|
49
|
+
ElasticAPM.set_label(:app_instance, self.id)
|
|
50
|
+
else
|
|
51
|
+
ElasticAPM.set_label(:app_instance, self.id)
|
|
52
|
+
end
|
|
33
53
|
end
|
|
34
54
|
|
|
35
55
|
if INSTANCE_REFRESH_WINDOW > INSTANCE_REDIS_CACHE_PERIOD
|
|
36
56
|
raise "The instance refresh window cannot be greater than the instance cache period"
|
|
37
57
|
end
|
|
38
58
|
self.apartment_switch(nil, false)
|
|
59
|
+
|
|
60
|
+
if ZuoraConnect.logger.is_a?(Ougai::Logger)
|
|
61
|
+
ZuoraConnect.logger.with_fields.merge!(default_ougai_items)
|
|
62
|
+
end
|
|
63
|
+
if Rails.logger.is_a?(Ougai::Logger)
|
|
64
|
+
Rails.logger.with_fields.merge!(default_ougai_items)
|
|
65
|
+
end
|
|
39
66
|
end
|
|
40
67
|
|
|
41
|
-
def
|
|
68
|
+
def initialize_redis_placeholders
|
|
42
69
|
if defined?(Redis.current)
|
|
43
|
-
Redis.current.
|
|
44
|
-
|
|
45
|
-
|
|
70
|
+
unless Redis.current.zscore("AppInstance:Deleted", "placeholder").present? # O(1)
|
|
71
|
+
Redis.current.zadd("AppInstance:Deleted", 9_999_999_999, "placeholder") # O(log(N))
|
|
72
|
+
end
|
|
73
|
+
if self.id.present?
|
|
74
|
+
if Redis.current.zscore("AppInstance:Deleted", self.id).present? # O(1)
|
|
75
|
+
Redis.current.zrem("AppInstance:Deleted", self.id) # O(log(N))
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
unless Redis.current.zscore("APILimits", "placeholder").present? # O(1)
|
|
79
|
+
Redis.current.zadd("APILimits", 9_999_999_999, "placeholder") # O(log(N))
|
|
80
|
+
end
|
|
81
|
+
unless Redis.current.zscore("InstanceRefreshing", "placeholder").present? # O(1)
|
|
82
|
+
Redis.current.zadd("InstanceRefreshing", 9_999_999_999, "placeholder") # O(log(N))
|
|
83
|
+
end
|
|
46
84
|
end
|
|
47
85
|
if defined?(Resque.redis)
|
|
48
|
-
Resque.redis.
|
|
86
|
+
unless Resque.redis.zscore("PauseQueue", "placeholder").present? # O(1)
|
|
87
|
+
Resque.redis.zadd("PauseQueue", 9_999_999_999, "placeholder") # O(log(N))
|
|
88
|
+
end
|
|
49
89
|
end
|
|
90
|
+
true
|
|
50
91
|
end
|
|
51
92
|
|
|
52
|
-
def prune_data
|
|
93
|
+
def prune_data
|
|
53
94
|
if defined?(Redis.current)
|
|
54
|
-
Redis.current.zadd("AppInstance:Deleted", Time.now.to_i, id)
|
|
55
|
-
Redis.current.del("AppInstance:#{id}")
|
|
56
|
-
Redis.current.zrem("APILimits", id)
|
|
57
|
-
Redis.current.zrem("InstanceRefreshing", id)
|
|
95
|
+
Redis.current.zadd("AppInstance:Deleted", Time.now.to_i, self.id)
|
|
96
|
+
Redis.current.del("AppInstance:#{self.id}")
|
|
97
|
+
Redis.current.zrem("APILimits", self.id)
|
|
98
|
+
Redis.current.zrem("InstanceRefreshing", self.id)
|
|
58
99
|
end
|
|
59
100
|
if defined?(Resque.redis)
|
|
60
|
-
Resque.redis.
|
|
101
|
+
Resque.redis.zrange("PauseQueue", 0, -1).each do |key|
|
|
102
|
+
Resque.redis.zrem("PauseQueue", key) if key.split("__").first.to_i == self.id
|
|
103
|
+
end
|
|
61
104
|
end
|
|
62
105
|
return true
|
|
63
|
-
end
|
|
106
|
+
end
|
|
64
107
|
|
|
65
108
|
def apartment_switch(method = nil, migrate = false)
|
|
66
109
|
switch_count ||= 0
|
|
67
110
|
if self.persisted?
|
|
68
111
|
begin
|
|
69
|
-
Apartment::Tenant.switch!(self.id)
|
|
112
|
+
Apartment::Tenant.switch!(self.id)
|
|
70
113
|
rescue Apartment::TenantNotFound => ex
|
|
71
114
|
sleep(2)
|
|
72
115
|
begin
|
|
@@ -74,9 +117,9 @@ module ZuoraConnect
|
|
|
74
117
|
rescue Apartment::TenantExists => ex
|
|
75
118
|
end
|
|
76
119
|
if (switch_count += 1) < 2
|
|
77
|
-
retry
|
|
120
|
+
retry
|
|
78
121
|
else
|
|
79
|
-
raise
|
|
122
|
+
raise
|
|
80
123
|
end
|
|
81
124
|
end
|
|
82
125
|
if migrate && ActiveRecord::Migrator.needs_migration?
|
|
@@ -86,19 +129,24 @@ module ZuoraConnect
|
|
|
86
129
|
Thread.current[:appinstance] = self
|
|
87
130
|
end
|
|
88
131
|
|
|
89
|
-
def
|
|
132
|
+
def default_ougai_items
|
|
133
|
+
return {app_instance_id: self.id, tenant_ids: self.zuora_tenant_ids, organization: self.organizations, environment: self.environment}
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def new_session(session: self.data_lookup, username: self.access_token, password: self.refresh_token, holding_pattern: false, **args)
|
|
90
137
|
self.api_version = "v2"
|
|
91
138
|
self.username = username
|
|
92
139
|
self.password = password
|
|
93
140
|
self.last_refresh = session["#{self.id}::last_refresh"]
|
|
94
141
|
self.connect_user = session["#{self.id}::user::email"] if session["#{self.id}::user::email"].present?
|
|
95
142
|
PaperTrail.whodunnit = self.connect_user if defined?(PaperTrail)
|
|
96
|
-
ElasticAPM.set_user(self.connect_user) if defined?(ElasticAPM)
|
|
143
|
+
ElasticAPM.set_user(self.connect_user) if defined?(ElasticAPM) && ElasticAPM.running?
|
|
97
144
|
recoverable_session = false
|
|
98
145
|
|
|
99
146
|
## DEV MODE TASK DATA MOCKUP
|
|
100
147
|
if ZuoraConnect.configuration.mode != "Production"
|
|
101
148
|
mock_task_data = {
|
|
149
|
+
"id" => ZuoraConnect.configuration.dev_mode_appinstance,
|
|
102
150
|
"mode" => ZuoraConnect.configuration.dev_mode_mode
|
|
103
151
|
}
|
|
104
152
|
|
|
@@ -115,31 +163,32 @@ module ZuoraConnect
|
|
|
115
163
|
end
|
|
116
164
|
|
|
117
165
|
self.build_task(task_data: mock_task_data, session: session)
|
|
166
|
+
self.last_refresh = Time.now.to_i
|
|
118
167
|
else
|
|
119
168
|
time_expire = (session["#{self.id}::last_refresh"] || Time.now).to_i - INSTANCE_REFRESH_WINDOW.ago.to_i
|
|
120
169
|
|
|
121
170
|
if session.empty?
|
|
122
171
|
self.new_session_message = "REFRESHING - Session Empty"
|
|
123
|
-
|
|
172
|
+
ZuoraConnect.logger.debug(self.new_session_message)
|
|
124
173
|
raise ZuoraConnect::Exceptions::HoldingPattern if holding_pattern && !self.mark_for_refresh
|
|
125
174
|
self.refresh(session: session)
|
|
126
175
|
|
|
127
176
|
elsif (self.id != session["appInstance"].to_i)
|
|
128
177
|
self.new_session_message = "REFRESHING - AppInstance ID(#{self.id}) does not match session id(#{session["appInstance"].to_i})"
|
|
129
|
-
|
|
178
|
+
ZuoraConnect.logger.debug(self.new_session_message)
|
|
130
179
|
raise ZuoraConnect::Exceptions::HoldingPattern if holding_pattern && !self.mark_for_refresh
|
|
131
180
|
self.refresh(session: session)
|
|
132
181
|
|
|
133
182
|
elsif session["#{self.id}::task_data"].blank?
|
|
134
183
|
self.new_session_message = "REFRESHING - Task Data Blank"
|
|
135
|
-
|
|
184
|
+
ZuoraConnect.logger.debug(self.new_session_message)
|
|
136
185
|
raise ZuoraConnect::Exceptions::HoldingPattern if holding_pattern && !self.mark_for_refresh
|
|
137
186
|
self.refresh(session: session)
|
|
138
187
|
|
|
139
188
|
elsif session["#{self.id}::last_refresh"].blank?
|
|
140
189
|
self.new_session_message = "REFRESHING - No Time on Cookie"
|
|
141
190
|
recoverable_session = true
|
|
142
|
-
|
|
191
|
+
ZuoraConnect.logger.debug(self.new_session_message)
|
|
143
192
|
raise ZuoraConnect::Exceptions::HoldingPattern if holding_pattern && !self.mark_for_refresh
|
|
144
193
|
self.refresh(session: session)
|
|
145
194
|
|
|
@@ -147,7 +196,7 @@ module ZuoraConnect
|
|
|
147
196
|
elsif (session["#{self.id}::last_refresh"].to_i < INSTANCE_REFRESH_WINDOW.ago.to_i) && self.mark_for_refresh
|
|
148
197
|
self.new_session_message = "REFRESHING - Session Old by #{time_expire.abs} second"
|
|
149
198
|
recoverable_session = true
|
|
150
|
-
|
|
199
|
+
ZuoraConnect.logger.debug(self.new_session_message)
|
|
151
200
|
self.refresh(session: session)
|
|
152
201
|
|
|
153
202
|
else
|
|
@@ -156,82 +205,194 @@ module ZuoraConnect
|
|
|
156
205
|
else
|
|
157
206
|
self.new_session_message = "REBUILDING - Expires in #{time_expire} seconds"
|
|
158
207
|
end
|
|
159
|
-
|
|
208
|
+
ZuoraConnect.logger.debug(self.new_session_message, self.default_ougai_items)
|
|
160
209
|
self.build_task(task_data: session["#{self.id}::task_data"], session: session)
|
|
161
210
|
end
|
|
162
|
-
end
|
|
211
|
+
end
|
|
163
212
|
return self
|
|
164
213
|
rescue ZuoraConnect::Exceptions::HoldingPattern => ex
|
|
165
214
|
while self.marked_for_refresh?
|
|
166
|
-
|
|
215
|
+
ZuoraConnect.logger.info("Holding - Expires in #{self.reset_mark_expires_at}. '#{self.new_session_message}'", self.default_ougai_items)
|
|
167
216
|
sleep(HOLDING_PATTERN_SLEEP)
|
|
168
217
|
end
|
|
169
218
|
self.reload_attributes([:refresh_token, :oauth_expires_at, :access_token])
|
|
170
219
|
session = self.data_lookup(session: session)
|
|
171
220
|
retry
|
|
172
|
-
rescue => ex
|
|
221
|
+
rescue ZuoraConnect::Exceptions::MissMatch => ex
|
|
222
|
+
self.delete_app_instance
|
|
223
|
+
session = {}
|
|
224
|
+
ZuoraConnect.logger.error(ex, self.default_ougai_items.merge({app_instance_id_new: self.task_data['id']}))
|
|
225
|
+
retry
|
|
226
|
+
rescue ZuoraConnect::Exceptions::InvalidCredentialSet => ex
|
|
227
|
+
raise
|
|
228
|
+
rescue => ex
|
|
173
229
|
if recoverable_session
|
|
174
|
-
|
|
230
|
+
ZuoraConnect.logger.warn("REBUILDING - Using backup expired cache", ex, self.default_ougai_items)
|
|
175
231
|
self.build_task(task_data: session["#{self.id}::task_data"], session: session)
|
|
176
232
|
return self
|
|
177
233
|
else
|
|
234
|
+
ZuoraConnect.logger.error("Failed new session", ex, self.default_ougai_items)
|
|
178
235
|
raise
|
|
179
236
|
end
|
|
180
237
|
ensure
|
|
181
238
|
begin
|
|
182
239
|
I18n.locale = self.locale
|
|
183
240
|
rescue I18n::InvalidLocale => ex
|
|
184
|
-
|
|
241
|
+
ZuoraConnect.logger.error(ex) if !IGNORED_LOCALS.include?(ex.locale.to_s.downcase)
|
|
185
242
|
end
|
|
186
243
|
Time.zone = self.timezone
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
ElasticAPM
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
244
|
+
if self.task_data.present?
|
|
245
|
+
tenants = self.task_data.fetch('tenant_ids', [])
|
|
246
|
+
organizations = self.task_data.fetch('organizations', [])
|
|
247
|
+
if defined?(ElasticAPM) && ElasticAPM.running?
|
|
248
|
+
if ElasticAPM.respond_to?(:set_label)
|
|
249
|
+
ElasticAPM.set_label(:tenant_id, tenants.first)
|
|
250
|
+
ElasticAPM.set_label(:organization, organizations.first)
|
|
251
|
+
else
|
|
252
|
+
ElasticAPM.set_label(:tenant_id, tenants.first)
|
|
253
|
+
ElasticAPM.set_label(:organization, organizations.first)
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
params = {
|
|
258
|
+
name: self.task_data.dig('name'),
|
|
259
|
+
zuora_entity_ids: (self.task_data.dig(LOGIN_TENANT_DESTINATION,'entities') || []).map{|e| e['id']}.uniq,
|
|
260
|
+
zuora_tenant_ids: tenants.map(&:to_s).uniq,
|
|
261
|
+
organizations: organizations
|
|
262
|
+
}
|
|
263
|
+
if self.methods.include?(LOGIN_TENANT_DESTINATION.to_sym)
|
|
264
|
+
client = self.send(LOGIN_TENANT_DESTINATION).client
|
|
265
|
+
if defined?(client.rest_domain)
|
|
266
|
+
ZuoraConnect::RequestIdMiddleware.zuora_rest_domain = client.rest_domain
|
|
267
|
+
params.merge!({zuora_domain: client.rest_domain, environment: client.environment })
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
params = params.reject{|k,v| !self.attributes.keys.member?(k.to_s) || self[k] == v}
|
|
271
|
+
self.update_columns(params) if params.present?
|
|
272
|
+
end
|
|
195
273
|
end
|
|
196
274
|
|
|
197
|
-
def refresh(session: {}
|
|
275
|
+
def refresh(session: {})
|
|
198
276
|
refresh_count ||= 0
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
277
|
+
skip_connect ||= false
|
|
278
|
+
begin
|
|
279
|
+
#Check how app was deployed
|
|
280
|
+
if self.id < 25000000 && !skip_connect
|
|
281
|
+
self.check_oauth_state
|
|
282
|
+
response = HTTParty.get(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/tasks/#{self.id}.json",:body => {:access_token => self.access_token})
|
|
283
|
+
|
|
284
|
+
if response.code == 200
|
|
285
|
+
begin
|
|
286
|
+
parsed_json = JSON.parse(response.body)
|
|
287
|
+
rescue JSON::ParserError => ex
|
|
288
|
+
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("JSON parse error", response.body, response.code)
|
|
289
|
+
end
|
|
202
290
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
291
|
+
self.build_task(task_data: parsed_json, session: session)
|
|
292
|
+
if self.kms_key.present? && self.kms_key.match(/^arn:aws:.*/)
|
|
293
|
+
begin
|
|
294
|
+
self.zuora_logins = self.strip_cache_data(object: parsed_json.dup, keys: ['applications', 'tokens', 'user_settings'])
|
|
295
|
+
self.save(:validate => false)
|
|
296
|
+
rescue Aws::KMS::Errors::ValidationException, *AWS_AUTH_ERRORS => ex
|
|
297
|
+
Rails.logger.warn(AWS_AUTH_ERRORS_MSG, ex)
|
|
298
|
+
rescue => ex
|
|
299
|
+
Rails.logger.error(AWS_AUTH_ERRORS_MSG, ex)
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
else
|
|
303
|
+
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Communicating with Connect", response.body, response.code)
|
|
304
|
+
end
|
|
305
|
+
else
|
|
306
|
+
self.build_task(task_data: self.zuora_logins, session: session)
|
|
307
|
+
end
|
|
206
308
|
self.last_refresh = Time.now.to_i
|
|
207
309
|
self.cache_app_instance
|
|
208
310
|
self.reset_mark_for_refresh
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
311
|
+
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS + ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
|
312
|
+
refresh_count += 1
|
|
313
|
+
if refresh_count < 3
|
|
314
|
+
sleep(10)
|
|
315
|
+
ZuoraConnect.logger.debug("REFRESH TASK - Connection Failure Retrying(#{refresh_count})", ex, self.default_ougai_items)
|
|
316
|
+
retry
|
|
317
|
+
else
|
|
318
|
+
ZuoraConnect.logger.fatal("REFRESH TASK - Connection Failed", ex)
|
|
319
|
+
raise
|
|
320
|
+
end
|
|
321
|
+
rescue ZuoraConnect::Exceptions::ConnectCommunicationError => ex
|
|
322
|
+
refresh_count += 1
|
|
323
|
+
if refresh_count < 3
|
|
324
|
+
ZuoraConnect.logger.debug("REFRESH TASK - Communication Failure Retrying(#{refresh_count})", ex, self.default_ougai_items)
|
|
325
|
+
self.refresh_oauth if ex.code == 401
|
|
326
|
+
retry
|
|
327
|
+
else
|
|
328
|
+
ZuoraConnect.logger.fatal("REFRESH TASK - Communication Failed #{ex.code}", ex, self.default_ougai_items)
|
|
329
|
+
raise
|
|
330
|
+
end
|
|
212
331
|
end
|
|
213
|
-
rescue
|
|
214
|
-
if
|
|
215
|
-
|
|
332
|
+
rescue => ex
|
|
333
|
+
if self['zuora_logins'].present?
|
|
334
|
+
ZuoraConnect.logger.warn("REFRESH TASK - Fallback to local encrypted store", ex, self.default_ougai_items)
|
|
335
|
+
skip_connect = true
|
|
216
336
|
retry
|
|
217
|
-
else
|
|
218
|
-
Rails.logger.fatal("[#{self.id}] REFRESH TASK - #{ex.class} Failed #{refresh_count}x")
|
|
219
|
-
raise
|
|
220
337
|
end
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
338
|
+
raise
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
#### START KMS ENCRYPTION Methods ####
|
|
342
|
+
def zuora_logins=(val)
|
|
343
|
+
write_attribute(:zuora_logins, kms_encrypt(val.to_json))
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def zuora_logins
|
|
347
|
+
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Zuora Logins is blank, cannot decrypt.") if super.blank?
|
|
348
|
+
return JSON.parse(kms_decrypt(super))
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def kms_decrypt(value)
|
|
352
|
+
kms_tries ||= 0
|
|
353
|
+
kms_client = Aws::KMS::Client.new({region: Rails.application.secrets.aws['AWS_REGION'], credentials: self.aws_auth_client}.delete_if { |k, v| v.blank? })
|
|
354
|
+
resp = kms_client.decrypt({ciphertext_blob: [value].pack("H*") })
|
|
355
|
+
return resp.plaintext
|
|
356
|
+
rescue *AWS_AUTH_ERRORS => ex
|
|
357
|
+
if (kms_tries += 1) < 3
|
|
358
|
+
Rails.logger.warn(AWS_AUTH_ERRORS_MSG, ex)
|
|
359
|
+
retry
|
|
360
|
+
else
|
|
361
|
+
Rails.logger.error(AWS_AUTH_ERRORS_MSG, ex)
|
|
362
|
+
raise
|
|
226
363
|
end
|
|
227
|
-
retry
|
|
228
|
-
else
|
|
229
|
-
Rails.logger.fatal("[#{self.id}] REFRESH TASK - Failed #{refresh_count}x")
|
|
230
|
-
raise
|
|
231
364
|
end
|
|
232
|
-
end
|
|
233
365
|
|
|
234
|
-
|
|
366
|
+
def kms_encrypt(value)
|
|
367
|
+
kms_tries ||= 0
|
|
368
|
+
kms_client = Aws::KMS::Client.new({region: Rails.application.secrets.aws['AWS_REGION'], credentials: self.aws_auth_client}.delete_if {|k,v| v.blank? })
|
|
369
|
+
|
|
370
|
+
resp = kms_client.encrypt({key_id: kms_key, plaintext: value})
|
|
371
|
+
return resp.ciphertext_blob.unpack('H*').first
|
|
372
|
+
rescue *AWS_AUTH_ERRORS => ex
|
|
373
|
+
if (kms_tries += 1) < 3
|
|
374
|
+
Rails.logger.warn(AWS_AUTH_ERRORS_MSG, ex)
|
|
375
|
+
retry
|
|
376
|
+
else
|
|
377
|
+
Rails.logger.error(AWS_AUTH_ERRORS_MSG, ex)
|
|
378
|
+
raise
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def kms_key
|
|
383
|
+
return ENV['AWS_KMS_ARN'] || Rails.application.secrets.dig(:aws,'AWS_KMS_ARN')
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def aws_auth_client
|
|
387
|
+
if Rails.env.to_s == 'development'
|
|
388
|
+
return Aws::Credentials.new(Rails.application.secrets.aws['AWS_ACCESS_KEY_ID'], Rails.application.secrets.aws['AWS_SECRET_ACCESS_KEY'])
|
|
389
|
+
else
|
|
390
|
+
return nil
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
#### END KMS ENCRYPTION Methods ####
|
|
394
|
+
|
|
395
|
+
#### START Metrics Methods ####
|
|
235
396
|
def logitem(item: {}, reset: false)
|
|
236
397
|
self.logitems = {} if self.logitems.class != Hash
|
|
237
398
|
if item.class == Hash
|
|
@@ -243,10 +404,45 @@ module ZuoraConnect
|
|
|
243
404
|
def self.write_to_telegraf(*args)
|
|
244
405
|
if ZuoraConnect.configuration.enable_metrics
|
|
245
406
|
@@telegraf_host = ZuoraConnect::Telegraf.new() if @@telegraf_host == nil
|
|
407
|
+
unicorn_stats = self.unicorn_listener_stats() if defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
|
|
408
|
+
@@telegraf_host.write(direction: 'Raindrops', tags: {}, values: unicorn_stats) unless unicorn_stats.blank?
|
|
246
409
|
return @@telegraf_host.write(*args)
|
|
247
410
|
end
|
|
248
411
|
end
|
|
249
412
|
|
|
413
|
+
def self.unicorn_listener_stats ()
|
|
414
|
+
stats_hash = {}
|
|
415
|
+
stats_hash["total_active"] = 0
|
|
416
|
+
stats_hash["total_queued"] = 0
|
|
417
|
+
|
|
418
|
+
begin
|
|
419
|
+
tmp = Unicorn.listener_names
|
|
420
|
+
unix = tmp.grep(%r{\A/})
|
|
421
|
+
tcp = tmp.grep(/\A.+:\d+\z/)
|
|
422
|
+
tcp = nil if tcp.empty?
|
|
423
|
+
unix = nil if unix.empty?
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
Raindrops::Linux.tcp_listener_stats(tcp).each do |addr,stats|
|
|
427
|
+
stats_hash["active_#{addr}"] = stats.active
|
|
428
|
+
stats_hash["queued_#{addr}"] = stats.queued
|
|
429
|
+
stats_hash["total_active"] = stats.active + stats_hash["total_active"]
|
|
430
|
+
stats_hash["total_queued"] = stats.queued + stats_hash["total_queued"]
|
|
431
|
+
end if tcp
|
|
432
|
+
|
|
433
|
+
Raindrops::Linux.unix_listener_stats(unix).each do |addr,stats|
|
|
434
|
+
stats_hash["active_#{addr}"] = stats.active
|
|
435
|
+
stats_hash["queued_#{addr}"] = stats.queued
|
|
436
|
+
stats_hash["total_active"] = stats.active + stats_hash["total_active"]
|
|
437
|
+
stats_hash["total_queued"] = stats.queued + stats_hash["total_queued"]
|
|
438
|
+
end if unix
|
|
439
|
+
rescue IOError => ex
|
|
440
|
+
rescue => ex
|
|
441
|
+
ZuoraConnect.logger.error(ex)
|
|
442
|
+
end
|
|
443
|
+
return stats_hash
|
|
444
|
+
end
|
|
445
|
+
|
|
250
446
|
def self.get_metrics(type)
|
|
251
447
|
@data = {}
|
|
252
448
|
|
|
@@ -280,13 +476,18 @@ module ZuoraConnect
|
|
|
280
476
|
end
|
|
281
477
|
return @data
|
|
282
478
|
end
|
|
283
|
-
#### END Task
|
|
479
|
+
#### END Task Methods ####
|
|
284
480
|
|
|
285
|
-
#### START Task
|
|
481
|
+
#### START Task Methods ####
|
|
286
482
|
def build_task(task_data: {}, session: {})
|
|
287
483
|
session = {} if session.blank?
|
|
288
484
|
self.task_data = task_data
|
|
289
485
|
self.mode = self.task_data["mode"]
|
|
486
|
+
|
|
487
|
+
if task_data['id'].to_s != self.id.to_s
|
|
488
|
+
raise ZuoraConnect::Exceptions::MissMatch.new("Wrong Instance Identifier/Lookup")
|
|
489
|
+
end
|
|
490
|
+
|
|
290
491
|
self.task_data.each do |k,v|
|
|
291
492
|
if k.match(/^(.*)_login$/)
|
|
292
493
|
tmp = ZuoraConnect::Login.new(v)
|
|
@@ -301,7 +502,7 @@ module ZuoraConnect
|
|
|
301
502
|
else
|
|
302
503
|
tmp.client.current_session = session["#{self.id}::#{k}:current_session"] if session["#{self.id}::#{k}:current_session"]
|
|
303
504
|
tmp.client.bearer_token = session["#{self.id}::#{k}:bearer_token"] if session["#{self.id}::#{k}:bearer_token"] && tmp.client.respond_to?(:bearer_token) ## need incase session id goes from basic to aouth in same redis store
|
|
304
|
-
tmp.client.oauth_session_expires_at = session["#{self.id}::#{k}:oauth_session_expires_at"] if session["#{self.id}::#{k}:oauth_session_expires_at"] && tmp.client.respond_to?(:oauth_session_expires_at)
|
|
505
|
+
tmp.client.oauth_session_expires_at = session["#{self.id}::#{k}:oauth_session_expires_at"] if session["#{self.id}::#{k}:oauth_session_expires_at"] && tmp.client.respond_to?(:oauth_session_expires_at)
|
|
305
506
|
end
|
|
306
507
|
end
|
|
307
508
|
self.logins[k] = tmp
|
|
@@ -315,9 +516,17 @@ module ZuoraConnect
|
|
|
315
516
|
self.locale = v["local"]
|
|
316
517
|
end
|
|
317
518
|
end
|
|
519
|
+
rescue ZuoraConnect::Exceptions::MissMatch => ex
|
|
520
|
+
raise
|
|
521
|
+
rescue ZuoraConnect::Exceptions::InvalidCredentialSet => ex
|
|
522
|
+
raise
|
|
318
523
|
rescue => ex
|
|
319
|
-
|
|
320
|
-
|
|
524
|
+
ZuoraConnect.logger.error("Build Task Error", ex)
|
|
525
|
+
ZuoraConnect.logger.error("Task Data: #{task_data}") if task_data.present?
|
|
526
|
+
if session.present?
|
|
527
|
+
ZuoraConnect.logger.error("Task Session: #{session.to_h}") if session.methods.include?(:to_h)
|
|
528
|
+
ZuoraConnect.logger.error("Task Session: #{session.to_hash}") if session.methods.include?(:to_hash)
|
|
529
|
+
end
|
|
321
530
|
raise
|
|
322
531
|
end
|
|
323
532
|
|
|
@@ -339,11 +548,11 @@ module ZuoraConnect
|
|
|
339
548
|
end
|
|
340
549
|
return parsed_json
|
|
341
550
|
elsif response.code == 400
|
|
342
|
-
raise ZuoraConnect::Exceptions::APIError.new(message: parsed_json['errors'].join(' '), response: response
|
|
551
|
+
raise ZuoraConnect::Exceptions::APIError.new(message: parsed_json['errors'].join(' '), response: response)
|
|
343
552
|
else
|
|
344
553
|
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Communicating with Connect", response.body, response.code)
|
|
345
554
|
end
|
|
346
|
-
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS
|
|
555
|
+
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS + ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
|
347
556
|
if (update_login_count += 1) < 3
|
|
348
557
|
retry
|
|
349
558
|
else
|
|
@@ -360,6 +569,47 @@ module ZuoraConnect
|
|
|
360
569
|
end
|
|
361
570
|
end
|
|
362
571
|
|
|
572
|
+
def fetch_org_details(debug: false)
|
|
573
|
+
details_count ||= 0
|
|
574
|
+
self.refresh if !defined?(self.target_login)
|
|
575
|
+
|
|
576
|
+
response = HTTParty.get("#{ZuoraConnect.configuration.url}/api/#{self.api_version}/tenants/search?hostname=#{self.target_login.client.hostname}&node_id=#{self.zuora_entity_ids.first}")
|
|
577
|
+
|
|
578
|
+
if response.success?
|
|
579
|
+
parsed_json = JSON.parse(response.body)
|
|
580
|
+
|
|
581
|
+
#Set Org
|
|
582
|
+
if self.id >= 25000000 && parsed_json['organization'].present?
|
|
583
|
+
login_cache = self.zuora_logins
|
|
584
|
+
login_cache.delete('organization')
|
|
585
|
+
self.zuora_logins = login_cache.merge({'organizations' => [parsed_json['organization']]})
|
|
586
|
+
end
|
|
587
|
+
if defined?(ZuoraConnect::AppInstance::CONNECT_APPLICATION_ID)
|
|
588
|
+
downloads = parsed_json.fetch('downloads',[]).select{|a| a['applicationId'] == ZuoraConnect::AppInstance::CONNECT_APPLICATION_ID }.map { |h| h.slice('Name', 'provisionState') }
|
|
589
|
+
Rails.logger.info("Instance Downloads: #{downloads.to_s}") if debug
|
|
590
|
+
if downloads.size > 1
|
|
591
|
+
self.provision_status = 'MultipleProvisioningRecords'
|
|
592
|
+
self.provisioned_app = downloads.map {|d| d['Name']}.to_s
|
|
593
|
+
elsif downloads.size == 1
|
|
594
|
+
self.provision_status = downloads.first['provisionState']
|
|
595
|
+
self.provisioned_app = downloads.first['Name']
|
|
596
|
+
else
|
|
597
|
+
self.provision_status = 'NoProvisioningRecords'
|
|
598
|
+
self.provisioned_app = nil
|
|
599
|
+
end
|
|
600
|
+
end
|
|
601
|
+
self.save(:validate => false)
|
|
602
|
+
|
|
603
|
+
return parsed_json
|
|
604
|
+
end
|
|
605
|
+
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS + ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
|
606
|
+
if (details_count += 1) < 3
|
|
607
|
+
retry
|
|
608
|
+
else
|
|
609
|
+
raise
|
|
610
|
+
end
|
|
611
|
+
end
|
|
612
|
+
|
|
363
613
|
def update_task(options)
|
|
364
614
|
update_task_count ||= 0
|
|
365
615
|
response = HTTParty.post(ZuoraConnect.configuration.url + "/api/#{self.api_version}/tools/tasks/#{self.id}/update_task",:body => {:access_token => self.username}.merge(options))
|
|
@@ -367,11 +617,11 @@ module ZuoraConnect
|
|
|
367
617
|
if response.code == 200
|
|
368
618
|
return parsed_json
|
|
369
619
|
elsif response.code == 400
|
|
370
|
-
raise ZuoraConnect::Exceptions::APIError.new(message: parsed_json['errors'].join(' '), response: response
|
|
620
|
+
raise ZuoraConnect::Exceptions::APIError.new(message: parsed_json['errors'].join(' '), response: response)
|
|
371
621
|
else
|
|
372
622
|
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Communicating with Connect", response.body, response.code)
|
|
373
623
|
end
|
|
374
|
-
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS
|
|
624
|
+
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS + ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
|
375
625
|
if (update_task_count += 1) < 3
|
|
376
626
|
retry
|
|
377
627
|
else
|
|
@@ -387,13 +637,13 @@ module ZuoraConnect
|
|
|
387
637
|
raise
|
|
388
638
|
end
|
|
389
639
|
end
|
|
390
|
-
#### END Task
|
|
640
|
+
#### END Task Methods ####
|
|
391
641
|
|
|
392
|
-
#### START Connect OAUTH
|
|
393
|
-
def check_oauth_state(method)
|
|
642
|
+
#### START Connect OAUTH Methods ####
|
|
643
|
+
def check_oauth_state(method=nil)
|
|
394
644
|
#Refresh token if already expired
|
|
395
645
|
if self.oauth_expired?
|
|
396
|
-
|
|
646
|
+
ZuoraConnect.logger.debug("Before '#{method}' method, Oauth expired")
|
|
397
647
|
self.refresh_oauth
|
|
398
648
|
end
|
|
399
649
|
end
|
|
@@ -403,16 +653,12 @@ module ZuoraConnect
|
|
|
403
653
|
end
|
|
404
654
|
|
|
405
655
|
def refresh_oauth
|
|
406
|
-
refresh_oauth_count ||= 0
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
413
|
-
response = HTTParty.post("#{ZuoraConnect.configuration.url}/oauth/token",:body => params)
|
|
414
|
-
response_time = Time.now - start
|
|
415
|
-
Rails.logger.info("[#{self.id}] REFRESH OAUTH - In #{response_time.round(2).to_s}")
|
|
656
|
+
refresh_oauth_count ||= 0
|
|
657
|
+
response = HTTParty.post("#{ZuoraConnect.configuration.url}/oauth/token", body: {
|
|
658
|
+
:grant_type => "refresh_token",
|
|
659
|
+
:redirect_uri => ZuoraConnect.configuration.oauth_client_redirect_uri,
|
|
660
|
+
:refresh_token => self.refresh_token
|
|
661
|
+
})
|
|
416
662
|
|
|
417
663
|
if response.code == 200
|
|
418
664
|
response_body = JSON.parse(response.body)
|
|
@@ -422,15 +668,15 @@ module ZuoraConnect
|
|
|
422
668
|
self.oauth_expires_at = Time.at(response_body["created_at"].to_i) + response_body["expires_in"].seconds
|
|
423
669
|
self.save(:validate => false)
|
|
424
670
|
else
|
|
425
|
-
Rails.logger.fatal("[#{self.id}] REFRESH OAUTH - Failed Code #{response.code}")
|
|
426
671
|
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Refreshing Access Token", response.body, response.code)
|
|
427
672
|
end
|
|
428
|
-
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS
|
|
673
|
+
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS + ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
|
429
674
|
if (refresh_oauth_count += 1) < 3
|
|
430
|
-
|
|
675
|
+
sleep(CONNECT_COMMUNICATION_SLEEP)
|
|
676
|
+
ZuoraConnect.logger.debug("REFRESH OAUTH - Connection Failure Retrying(#{refresh_oauth_count})", ex, self.default_ougai_items)
|
|
431
677
|
retry
|
|
432
678
|
else
|
|
433
|
-
Rails.logger.fatal("
|
|
679
|
+
Rails.logger.fatal("REFRESH OAUTH - Connection Failed", ex, self.default_ougai_items)
|
|
434
680
|
raise
|
|
435
681
|
end
|
|
436
682
|
rescue ZuoraConnect::Exceptions::ConnectCommunicationError => ex
|
|
@@ -441,14 +687,14 @@ module ZuoraConnect
|
|
|
441
687
|
return if !self.oauth_expired?
|
|
442
688
|
|
|
443
689
|
if (refresh_oauth_count += 1) < 3
|
|
444
|
-
|
|
690
|
+
ZuoraConnect.logger.debug("REFRESH OAUTH - Communication Failure Retrying(#{refresh_oauth_count})", ex, self.default_ougai_items)
|
|
445
691
|
retry
|
|
446
692
|
else
|
|
447
|
-
|
|
693
|
+
ZuoraConnect.logger.fatal("REFRESH OAUTH - Communication Failed #{ex.code}", ex, self.default_ougai_items)
|
|
448
694
|
raise
|
|
449
695
|
end
|
|
450
696
|
end
|
|
451
|
-
#### END Connect OAUTH
|
|
697
|
+
#### END Connect OAUTH Methods ####
|
|
452
698
|
|
|
453
699
|
#### START AppInstance Temporary Persistance Methods ####
|
|
454
700
|
def marked_for_refresh?
|
|
@@ -486,7 +732,7 @@ module ZuoraConnect
|
|
|
486
732
|
begin
|
|
487
733
|
redis_get_command ||= 0
|
|
488
734
|
cached_instance = Redis.current.get("AppInstance:#{self.id}")
|
|
489
|
-
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS
|
|
735
|
+
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS + ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
|
490
736
|
if (redis_get_command += 1) < 3
|
|
491
737
|
retry
|
|
492
738
|
else
|
|
@@ -494,10 +740,10 @@ module ZuoraConnect
|
|
|
494
740
|
end
|
|
495
741
|
end
|
|
496
742
|
if cached_instance.blank?
|
|
497
|
-
|
|
743
|
+
ZuoraConnect.logger.debug("Cached AppInstance Missing", self.default_ougai_items)
|
|
498
744
|
return session
|
|
499
745
|
else
|
|
500
|
-
|
|
746
|
+
ZuoraConnect.logger.debug("Cached AppInstance Found", self.default_ougai_items)
|
|
501
747
|
return decrypt_data(data: cached_instance, rescue_return: session).merge(session)
|
|
502
748
|
end
|
|
503
749
|
else
|
|
@@ -505,11 +751,15 @@ module ZuoraConnect
|
|
|
505
751
|
end
|
|
506
752
|
end
|
|
507
753
|
|
|
754
|
+
def delete_app_instance
|
|
755
|
+
Redis.current.del("AppInstance:#{self.id}")
|
|
756
|
+
end
|
|
757
|
+
|
|
508
758
|
def cache_app_instance
|
|
509
759
|
if defined?(Redis.current)
|
|
510
760
|
#Task data must be present and the last refresh cannot be old. We dont want to overwite new cache data with old
|
|
511
761
|
if self.task_data.present? && (self.last_refresh.to_i > INSTANCE_REFRESH_WINDOW.ago.to_i)
|
|
512
|
-
|
|
762
|
+
ZuoraConnect.logger.debug("Caching AppInstance", self.default_ougai_items)
|
|
513
763
|
Redis.current.setex("AppInstance:#{self.id}", INSTANCE_REDIS_CACHE_PERIOD.to_i, self.encrypt_data(data: self.save_data))
|
|
514
764
|
end
|
|
515
765
|
end
|
|
@@ -536,12 +786,7 @@ module ZuoraConnect
|
|
|
536
786
|
|
|
537
787
|
#Redis is not defined strip out old data
|
|
538
788
|
if !defined?(Redis.current)
|
|
539
|
-
session["#{self.id}::task_data"]
|
|
540
|
-
session["#{self.id}::task_data"].delete('tenant_ids')
|
|
541
|
-
session["#{self.id}::task_data"].delete('organizations')
|
|
542
|
-
session["#{self.id}::task_data"].select {|k,v| k.include?('login') && v['tenant_type'] == 'Zuora'}.each do |login_key, login_data|
|
|
543
|
-
session["#{self.id}::task_data"][login_key]['entities'] = (login_data.dig('entities') || []).map {|entity| entity.slice('id', 'tenantId')}
|
|
544
|
-
end
|
|
789
|
+
strip_cache_data(object: session["#{self.id}::task_data"])
|
|
545
790
|
end
|
|
546
791
|
|
|
547
792
|
session["#{self.id}::last_refresh"] = self.last_refresh
|
|
@@ -549,6 +794,14 @@ module ZuoraConnect
|
|
|
549
794
|
return session
|
|
550
795
|
end
|
|
551
796
|
|
|
797
|
+
def strip_cache_data(object: {}, keys: ['applications', 'tokens','tenant_ids', 'organizations','user_settings'] )
|
|
798
|
+
keys.each {|key| object.delete(key) }
|
|
799
|
+
object.select {|k,v| k.include?('login') && v['tenant_type'] == 'Zuora'}.each do |login_key, login_data|
|
|
800
|
+
object[login_key]['entities'] = login_data.fetch('entities',[]).map {|entity| entity.slice('id', 'tenantId', 'entityId', 'displayName')}
|
|
801
|
+
end
|
|
802
|
+
return object
|
|
803
|
+
end
|
|
804
|
+
|
|
552
805
|
def encryptor
|
|
553
806
|
# Default values for Rails 4 apps
|
|
554
807
|
key_iter_num, key_size, salt, signed_salt = [1000, 64, "encrypted cookie", "signed encrypted cookie"]
|
|
@@ -561,18 +814,19 @@ module ZuoraConnect
|
|
|
561
814
|
def decrypt_data(data: nil, rescue_return: nil, log_fatal: true)
|
|
562
815
|
return data if data.blank?
|
|
563
816
|
if Rails.env == 'development'
|
|
564
|
-
begin
|
|
817
|
+
begin
|
|
565
818
|
return JSON.parse(data)
|
|
566
819
|
rescue JSON::ParserError => ex
|
|
567
820
|
return data
|
|
568
821
|
end
|
|
569
822
|
else
|
|
570
|
-
begin
|
|
823
|
+
begin
|
|
571
824
|
return JSON.parse(encryptor.decrypt_and_verify(CGI::unescape(data)))
|
|
572
825
|
rescue ActiveSupport::MessageVerifier::InvalidSignature => ex
|
|
573
|
-
|
|
826
|
+
ZuoraConnect.logger.error("Error Decrypting", ex, self.default_ougai_items) if log_fatal
|
|
574
827
|
return rescue_return
|
|
575
828
|
rescue JSON::ParserError => ex
|
|
829
|
+
ZuoraConnect.logger.error("JSON Parse Error", ex, self.default_ougai_items) if log_fatal
|
|
576
830
|
return encryptor.decrypt_and_verify(CGI::unescape(data))
|
|
577
831
|
end
|
|
578
832
|
end
|
|
@@ -622,7 +876,7 @@ module ZuoraConnect
|
|
|
622
876
|
if paused_user == current_user || paused_user.blank?
|
|
623
877
|
Resque.redis.zrem("PauseQueue", "#{self.id}__#{paused_user}")
|
|
624
878
|
else
|
|
625
|
-
raise "Can only unpause for user #{paused_user}."
|
|
879
|
+
raise "Can only unpause for user #{paused_user}."
|
|
626
880
|
end
|
|
627
881
|
end
|
|
628
882
|
### END Resque Helping Methods ####
|
|
@@ -632,10 +886,10 @@ module ZuoraConnect
|
|
|
632
886
|
self.update_column(:catalog_update_attempt_at, Time.now.utc)
|
|
633
887
|
|
|
634
888
|
entity_reference = entity_id.blank? ? 'Default' : entity_id
|
|
635
|
-
|
|
636
|
-
|
|
889
|
+
ZuoraConnect.logger.debug("Fetch Catalog")
|
|
890
|
+
ZuoraConnect.logger.debug("Zuora Entity: #{entity_id.blank? ? 'default' : entity_id}")
|
|
637
891
|
|
|
638
|
-
login = zuora_login.client(
|
|
892
|
+
login = zuora_login.client(entity_id)
|
|
639
893
|
|
|
640
894
|
old_logger = ActiveRecord::Base.logger
|
|
641
895
|
ActiveRecord::Base.logger = nil
|
|
@@ -644,14 +898,8 @@ module ZuoraConnect
|
|
|
644
898
|
response = {'nextPage' => login.rest_endpoint("catalog/products?pageSize=#{page_size}")}
|
|
645
899
|
while !response["nextPage"].blank?
|
|
646
900
|
url = login.rest_endpoint(response["nextPage"].split('/v1/').last)
|
|
647
|
-
|
|
648
|
-
output_json, response = login.rest_call(:debug => false, :url => url, :
|
|
649
|
-
Rails.logger.debug("Fetch Catalog Response Code #{response.code}")
|
|
650
|
-
|
|
651
|
-
if !output_json['success'] =~ (/(true|t|yes|y|1)$/i) || output_json['success'].class != TrueClass
|
|
652
|
-
Rails.logger.error("Fetch Catalog DATA #{output_json.to_json}")
|
|
653
|
-
raise ZuoraAPI::Exceptions::ZuoraAPIError.new("Error Getting Catalog: #{output_json}")
|
|
654
|
-
end
|
|
901
|
+
ZuoraConnect.logger.debug("Fetch Catalog URL #{url}")
|
|
902
|
+
output_json, response = login.rest_call(:debug => false, :url => url, :timeout_retry => true)
|
|
655
903
|
|
|
656
904
|
output_json["products"].each do |product|
|
|
657
905
|
ActiveRecord::Base.connection.execute('UPDATE "public"."zuora_connect_app_instances" SET "catalog_mapping" = jsonb_set("catalog_mapping", \'{tmp, %s}\', \'%s\') where "id" = %s' % [product["id"], {"productId" => product["id"]}.to_json.gsub("'", "''"), self.id])
|
|
@@ -836,7 +1084,7 @@ module ZuoraConnect
|
|
|
836
1084
|
if cache
|
|
837
1085
|
Redis.current.sadd("Catalog:#{self.id}:Keys", ["Catalog:#{self.id}:#{object_id}:Hierarchy", "Catalog:#{self.id}:#{object_id}:Children:#{child_objects}"])
|
|
838
1086
|
Redis.current.set("Catalog:#{self.id}:#{object_id}:Hierarchy", encrypt_data(data: object_hierarchy))
|
|
839
|
-
Redis.current.set("Catalog:#{self.id}:#{object_id}:Children:#{child_objects}", encrypt_data(data: stub_catalog))
|
|
1087
|
+
Redis.current.set("Catalog:#{self.id}:#{object_id}:Children:#{child_objects}", encrypt_data(data: stub_catalog))
|
|
840
1088
|
else
|
|
841
1089
|
Redis.current.sadd("Catalog:#{self.id}:Keys", ["Catalog:#{self.id}:#{object_id}:Hierarchy"])
|
|
842
1090
|
Redis.current.set("Catalog:#{self.id}:#{object_id}:Hierarchy", encrypt_data(data: object_hierarchy))
|
|
@@ -871,17 +1119,32 @@ module ZuoraConnect
|
|
|
871
1119
|
### END S3 Helping Methods #####
|
|
872
1120
|
|
|
873
1121
|
### START Aggregate Grouping Helping Methods ####
|
|
874
|
-
|
|
1122
|
+
# Traverse entire database and run a query on table(table_name) with where clause(where_clause)
|
|
1123
|
+
# Data from each schema will be loaded into table(aggregate_name) into the public schema
|
|
1124
|
+
def self.refresh_aggregate_table(aggregate_name: 'all_tasks_processing', table_name: 'tasks', where_clause: "where status in ('Processing', 'Queued')", index_table: true, ignore_indexes: [])
|
|
875
1125
|
self.update_functions
|
|
1126
|
+
|
|
1127
|
+
sql_result = ActiveRecord::Base.connection.execute <<-eos
|
|
1128
|
+
SELECT pid, relname, mode
|
|
1129
|
+
FROM pg_locks l
|
|
1130
|
+
JOIN pg_class t ON l.relation = t.oid AND t.relkind = 'r'
|
|
1131
|
+
WHERE t.relname = '#{aggregate_name}' AND l.mode ='AccessExclusiveLock';
|
|
1132
|
+
eos
|
|
1133
|
+
raise ZuoraConnect::Exceptions::Error.new("An existing lock detected while dropping table '#{aggregate_name}'") if sql_result.count > 0
|
|
1134
|
+
|
|
876
1135
|
if index_table
|
|
877
|
-
ActiveRecord::Base.connection.execute('SELECT "shared_extensions".refresh_aggregate_table(\'%s\', \'%s\', %s, \'Index\');' % [aggregate_name, table_name, ActiveRecord::Base.connection.quote(where_clause)])
|
|
878
|
-
else
|
|
879
|
-
ActiveRecord::Base.connection.execute('SELECT "shared_extensions".refresh_aggregate_table(\'%s\', \'%s\', %s, \'NO\');' % [aggregate_name, table_name, ActiveRecord::Base.connection.quote(where_clause)])
|
|
1136
|
+
ActiveRecord::Base.connection.execute('SELECT "shared_extensions".refresh_aggregate_table(\'%s\', \'%s\', %s, \'Index\', \'{%s}\');' % [aggregate_name, table_name, ActiveRecord::Base.connection.quote(where_clause), ignore_indexes.map { |index| "\"#{index}\"" }.join(',')])
|
|
1137
|
+
else
|
|
1138
|
+
ActiveRecord::Base.connection.execute('SELECT "shared_extensions".refresh_aggregate_table(\'%s\', \'%s\', %s, \'NO\',\'{}\');' % [aggregate_name, table_name, ActiveRecord::Base.connection.quote(where_clause)])
|
|
880
1139
|
end
|
|
881
1140
|
end
|
|
882
1141
|
|
|
1142
|
+
# Load a psql script as a function in a transaction lock
|
|
883
1143
|
def self.update_functions
|
|
884
|
-
ActiveRecord::Base.
|
|
1144
|
+
ActiveRecord::Base.transaction do
|
|
1145
|
+
ActiveRecord::Base.connection.execute("SELECT pg_advisory_xact_lock(#{Zlib.crc32('refresh_aggregate_table')})")
|
|
1146
|
+
ActiveRecord::Base.connection.execute(File.read("#{Gem.loaded_specs["zuora_connect"].gem_dir}/app/views/sql/refresh_aggregate_table.txt"))
|
|
1147
|
+
end
|
|
885
1148
|
end
|
|
886
1149
|
### END Aggregate Grouping Helping Methods #####
|
|
887
1150
|
|
|
@@ -904,13 +1167,15 @@ module ZuoraConnect
|
|
|
904
1167
|
end
|
|
905
1168
|
|
|
906
1169
|
def reload_attributes(selected_attributes)
|
|
907
|
-
raise "Attibutes must be array"
|
|
908
|
-
|
|
1170
|
+
raise "Attibutes must be array" unless selected_attributes.is_a?(Array)
|
|
1171
|
+
selected_attributes.push(:organizations, :environment, :zuora_tenant_ids)
|
|
1172
|
+
selected_attributes.uniq!
|
|
1173
|
+
value_attributes = self.class.unscoped.where(id: id).select(selected_attributes).first.attributes
|
|
909
1174
|
value_attributes.each do |key, value|
|
|
910
1175
|
next if key == "id" && value.blank?
|
|
911
1176
|
self.send(:write_attribute, key, value)
|
|
912
1177
|
end
|
|
913
|
-
|
|
1178
|
+
self
|
|
914
1179
|
end
|
|
915
1180
|
|
|
916
1181
|
def instance_failure(failure)
|
|
@@ -939,14 +1204,32 @@ module ZuoraConnect
|
|
|
939
1204
|
|
|
940
1205
|
def method_missing(method_sym, *arguments, &block)
|
|
941
1206
|
if method_sym.to_s.include?("login")
|
|
942
|
-
|
|
943
|
-
Rails.logger.fatal("Instance Data: #{self.task_data}")
|
|
944
|
-
Rails.logger.fatal("Instance Logins: #{self.logins}")
|
|
1207
|
+
ZuoraConnect.logger.fatal("Method Missing #{method_sym}. Instance Data: #{self.task_data} Instance Logins: #{self.logins}")
|
|
945
1208
|
end
|
|
946
1209
|
super
|
|
947
1210
|
end
|
|
948
1211
|
|
|
949
|
-
|
|
1212
|
+
def self.read_master_db
|
|
1213
|
+
if self.connection.respond_to?(:stick_to_master!)
|
|
1214
|
+
self.connection.stick_to_master!(false)
|
|
1215
|
+
yield
|
|
1216
|
+
Makara::Context.release_all
|
|
1217
|
+
else
|
|
1218
|
+
yield
|
|
1219
|
+
end
|
|
1220
|
+
end
|
|
1221
|
+
|
|
1222
|
+
def self.without_sticking
|
|
1223
|
+
if self.connection.respond_to?(:without_sticking)
|
|
1224
|
+
self.connection.without_sticking do
|
|
1225
|
+
yield
|
|
1226
|
+
end
|
|
1227
|
+
else
|
|
1228
|
+
yield
|
|
1229
|
+
end
|
|
1230
|
+
end
|
|
1231
|
+
|
|
1232
|
+
method_hook :updateOption, :update_logins, :before => :check_oauth_state
|
|
950
1233
|
method_hook :new_session, :refresh, :build_task, :after => :apartment_switch
|
|
951
1234
|
end
|
|
952
|
-
end
|
|
1235
|
+
end
|