zuora_connect 1.8.71s → 2.0.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 +13 -0
- data/app/models/zuora_connect/app_instance_base.rb +65 -26
- data/config/initializers/resque.rb +2 -2
- data/config/initializers/unicorn.rb +1 -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/lib/logging/connect_formatter.rb +39 -0
- data/lib/metrics/net.rb +1 -1
- data/lib/middleware/metrics_middleware.rb +5 -2
- data/lib/middleware/request_id_middleware.rb +16 -0
- data/lib/resque/plugins/custom_logger.rb +5 -23
- data/lib/zuora_connect.rb +59 -17
- data/lib/zuora_connect/controllers/helpers.rb +6 -7
- data/lib/zuora_connect/railtie.rb +20 -14
- data/lib/zuora_connect/version.rb +1 -1
- metadata +37 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f0a05ee8e03bf92f69dfa82546fb5a917d9bdd3cc9350b7ddc688462789a7a5
|
4
|
+
data.tar.gz: a5a85a0db4bb49697aaeb408337e5dca8c860ba9f3f45153a98d8ad545e96a5d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66f02578165cd4da25089c786090ec3c63a8d312c127c943a8cd939abc74fbdb7c696490a9f5955d41818e43852720bb93da449e0a217076b22ac7899204d594
|
7
|
+
data.tar.gz: f9899bd76b9111abd1ff2d3256f94b87e3660f12c8412382b758adaec6b480a74cbaf817108a4da95e6dce5e39735c04440194101ff768295503d723c13bc261
|
@@ -26,6 +26,19 @@ module ZuoraConnect
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def health
|
29
|
+
if params[:error].present?
|
30
|
+
begin
|
31
|
+
raise ZuoraConnect::Exceptions::Error.new('This is an error')
|
32
|
+
rescue => ex
|
33
|
+
case params[:error]
|
34
|
+
when 'Log'
|
35
|
+
Rails.logger.error(ex)
|
36
|
+
when 'Exception'
|
37
|
+
raise
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
29
42
|
render json: {
|
30
43
|
message: "Alive",
|
31
44
|
status: 200
|
@@ -16,6 +16,7 @@ module ZuoraConnect
|
|
16
16
|
BLANK_OBJECT_ID_LOOKUP = 'BlankValueSupplied'
|
17
17
|
HOLDING_PATTERN_SLEEP = 5.seconds
|
18
18
|
CONNECT_COMMUNICATION_SLEEP= 5.seconds
|
19
|
+
IGNORED_LOCALS = ['fr', 'ja', 'sp']
|
19
20
|
|
20
21
|
def init
|
21
22
|
self.connect_user = 'Nobody'
|
@@ -29,7 +30,7 @@ module ZuoraConnect
|
|
29
30
|
PaperTrail.whodunnit = "Backend" if defined?(PaperTrail)
|
30
31
|
if defined?(ElasticAPM) && ElasticAPM.running?
|
31
32
|
ElasticAPM.set_user("Backend")
|
32
|
-
ElasticAPM.set_tag(:app_instance, self.id)
|
33
|
+
ElasticAPM.set_tag(:app_instance, self.id)
|
33
34
|
end
|
34
35
|
|
35
36
|
if INSTANCE_REFRESH_WINDOW > INSTANCE_REDIS_CACHE_PERIOD
|
@@ -60,13 +61,13 @@ module ZuoraConnect
|
|
60
61
|
Resque.redis.zrem("PauseQueue", id)
|
61
62
|
end
|
62
63
|
return true
|
63
|
-
end
|
64
|
+
end
|
64
65
|
|
65
66
|
def apartment_switch(method = nil, migrate = false)
|
66
67
|
switch_count ||= 0
|
67
68
|
if self.persisted?
|
68
69
|
begin
|
69
|
-
Apartment::Tenant.switch!(self.id)
|
70
|
+
Apartment::Tenant.switch!(self.id)
|
70
71
|
rescue Apartment::TenantNotFound => ex
|
71
72
|
sleep(2)
|
72
73
|
begin
|
@@ -74,9 +75,9 @@ module ZuoraConnect
|
|
74
75
|
rescue Apartment::TenantExists => ex
|
75
76
|
end
|
76
77
|
if (switch_count += 1) < 2
|
77
|
-
retry
|
78
|
+
retry
|
78
79
|
else
|
79
|
-
raise
|
80
|
+
raise
|
80
81
|
end
|
81
82
|
end
|
82
83
|
if migrate && ActiveRecord::Migrator.needs_migration?
|
@@ -159,7 +160,7 @@ module ZuoraConnect
|
|
159
160
|
ZuoraConnect.logger.add(log_level, self.new_session_message)
|
160
161
|
self.build_task(task_data: session["#{self.id}::task_data"], session: session)
|
161
162
|
end
|
162
|
-
end
|
163
|
+
end
|
163
164
|
return self
|
164
165
|
rescue ZuoraConnect::Exceptions::HoldingPattern => ex
|
165
166
|
while self.marked_for_refresh?
|
@@ -169,9 +170,9 @@ module ZuoraConnect
|
|
169
170
|
self.reload_attributes([:refresh_token, :oauth_expires_at, :access_token])
|
170
171
|
session = self.data_lookup(session: session)
|
171
172
|
retry
|
172
|
-
rescue => ex
|
173
|
+
rescue => ex
|
173
174
|
if recoverable_session
|
174
|
-
ZuoraConnect.logger.
|
175
|
+
ZuoraConnect.logger.warn("REBUILDING - Using backup expired cache")
|
175
176
|
self.build_task(task_data: session["#{self.id}::task_data"], session: session)
|
176
177
|
return self
|
177
178
|
else
|
@@ -181,7 +182,7 @@ module ZuoraConnect
|
|
181
182
|
begin
|
182
183
|
I18n.locale = self.locale
|
183
184
|
rescue I18n::InvalidLocale => ex
|
184
|
-
ZuoraConnect.logger.
|
185
|
+
ZuoraConnect.logger.error(ex) if !IGNORED_LOCALS.include?(ex.locale.to_s.downcase)
|
185
186
|
end
|
186
187
|
Time.zone = self.timezone
|
187
188
|
tenants = self.task_data.dig('tenant_ids') || []
|
@@ -191,7 +192,7 @@ module ZuoraConnect
|
|
191
192
|
ElasticAPM.set_tag(:organization, organizations.first)
|
192
193
|
end
|
193
194
|
self.logitem(item: {tenant_ids: tenants, organization: organizations})
|
194
|
-
self.update_column(:name, self.task_data.dig('name')) if ZuoraConnect::AppInstance.column_names.include?('name') && self.task_data.dig('name') != self.name
|
195
|
+
self.update_column(:name, self.task_data.dig('name')) if ZuoraConnect::AppInstance.column_names.include?('name') && self.task_data.dig('name') != self.name
|
195
196
|
end
|
196
197
|
|
197
198
|
def refresh(session: {}, session_fallback: false)
|
@@ -207,7 +208,6 @@ module ZuoraConnect
|
|
207
208
|
self.cache_app_instance
|
208
209
|
self.reset_mark_for_refresh
|
209
210
|
else
|
210
|
-
ZuoraConnect.logger.fatal("[#{self.id}] REFRESH TASK - Failed Code #{response.code}")
|
211
211
|
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Communicating with Connect", response.body, response.code)
|
212
212
|
end
|
213
213
|
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS).concat(ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
@@ -220,13 +220,15 @@ module ZuoraConnect
|
|
220
220
|
end
|
221
221
|
rescue ZuoraConnect::Exceptions::ConnectCommunicationError => ex
|
222
222
|
if (refresh_count += 1) < 3
|
223
|
-
ZuoraConnect.logger.info("[#{self.id}] REFRESH TASK - Failed Retrying(#{refresh_count})")
|
224
223
|
if ex.code == 401
|
224
|
+
ZuoraConnect.logger.info("[#{self.id}] REFRESH TASK - Failed #{ex.code} - Retrying(#{refresh_count})")
|
225
225
|
self.refresh_oauth
|
226
|
+
else
|
227
|
+
ZuoraConnect.logger.warn("[#{self.id}] REFRESH TASK - Failed #{ex.code} - Retrying(#{refresh_count})")
|
226
228
|
end
|
227
229
|
retry
|
228
230
|
else
|
229
|
-
ZuoraConnect.logger.fatal("[#{self.id}] REFRESH TASK - Failed #{refresh_count}x")
|
231
|
+
ZuoraConnect.logger.fatal("[#{self.id}] REFRESH TASK - Failed #{ex.code} - #{refresh_count}x")
|
230
232
|
raise
|
231
233
|
end
|
232
234
|
end
|
@@ -243,10 +245,45 @@ module ZuoraConnect
|
|
243
245
|
def self.write_to_telegraf(*args)
|
244
246
|
if ZuoraConnect.configuration.enable_metrics
|
245
247
|
@@telegraf_host = ZuoraConnect::Telegraf.new() if @@telegraf_host == nil
|
248
|
+
unicorn_stats = self.unicorn_listener_stats() if defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
|
249
|
+
@@telegraf_host.write(direction: 'Raindrops', tags: {}, values: unicorn_stats) unless unicorn_stats.blank?
|
246
250
|
return @@telegraf_host.write(*args)
|
247
251
|
end
|
248
252
|
end
|
249
253
|
|
254
|
+
def self.unicorn_listener_stats ()
|
255
|
+
stats_hash = {}
|
256
|
+
stats_hash["total_active"] = 0
|
257
|
+
stats_hash["total_queued"] = 0
|
258
|
+
|
259
|
+
begin
|
260
|
+
tmp = Unicorn.listener_names
|
261
|
+
unix = tmp.grep(%r{\A/})
|
262
|
+
tcp = tmp.grep(/\A.+:\d+\z/)
|
263
|
+
tcp = nil if tcp.empty?
|
264
|
+
unix = nil if unix.empty?
|
265
|
+
|
266
|
+
|
267
|
+
Raindrops::Linux.tcp_listener_stats(tcp).each do |addr,stats|
|
268
|
+
stats_hash["active_#{addr}"] = stats.active
|
269
|
+
stats_hash["queued_#{addr}"] = stats.queued
|
270
|
+
stats_hash["total_active"] = stats.active + stats_hash["total_active"]
|
271
|
+
stats_hash["total_queued"] = stats.queued + stats_hash["total_queued"]
|
272
|
+
end if tcp
|
273
|
+
|
274
|
+
Raindrops::Linux.unix_listener_stats(unix).each do |addr,stats|
|
275
|
+
stats_hash["active_#{addr}"] = stats.active
|
276
|
+
stats_hash["queued_#{addr}"] = stats.queued
|
277
|
+
stats_hash["total_active"] = stats.active + stats_hash["total_active"]
|
278
|
+
stats_hash["total_queued"] = stats.queued + stats_hash["total_queued"]
|
279
|
+
end if unix
|
280
|
+
rescue IOError => ex
|
281
|
+
rescue => ex
|
282
|
+
ZuoraConnect.logger.error(ex)
|
283
|
+
end
|
284
|
+
return stats_hash
|
285
|
+
end
|
286
|
+
|
250
287
|
def self.get_metrics(type)
|
251
288
|
@data = {}
|
252
289
|
|
@@ -301,7 +338,7 @@ module ZuoraConnect
|
|
301
338
|
else
|
302
339
|
tmp.client.current_session = session["#{self.id}::#{k}:current_session"] if session["#{self.id}::#{k}:current_session"]
|
303
340
|
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)
|
341
|
+
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
342
|
end
|
306
343
|
end
|
307
344
|
self.logins[k] = tmp
|
@@ -317,7 +354,10 @@ module ZuoraConnect
|
|
317
354
|
end
|
318
355
|
rescue => ex
|
319
356
|
ZuoraConnect.logger.error("Task Data: #{task_data}") if task_data.present?
|
320
|
-
|
357
|
+
if session.present?
|
358
|
+
ZuoraConnect.logger.error("Task Session: #{session.to_h}") if session.methods.include?(:to_h)
|
359
|
+
ZuoraConnect.logger.error("Task Session: #{session.to_hash}") if session.methods.include?(:to_hash)
|
360
|
+
end
|
321
361
|
raise
|
322
362
|
end
|
323
363
|
|
@@ -422,8 +462,7 @@ module ZuoraConnect
|
|
422
462
|
self.oauth_expires_at = Time.at(response_body["created_at"].to_i) + response_body["expires_in"].seconds
|
423
463
|
self.save(:validate => false)
|
424
464
|
else
|
425
|
-
ZuoraConnect.
|
426
|
-
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Refreshing Access Token", response.body, response.code)
|
465
|
+
raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Refreshing Access Token for #{self.id}", response.body, response.code)
|
427
466
|
end
|
428
467
|
rescue *(ZuoraAPI::Login::CONNECTION_EXCEPTIONS).concat(ZuoraAPI::Login::CONNECTION_READ_EXCEPTIONS) => ex
|
429
468
|
if (refresh_oauth_count += 1) < 3
|
@@ -441,10 +480,10 @@ module ZuoraConnect
|
|
441
480
|
return if !self.oauth_expired?
|
442
481
|
|
443
482
|
if (refresh_oauth_count += 1) < 3
|
444
|
-
ZuoraConnect.logger.info("[#{self.id}] REFRESH OAUTH - Failed Retrying(#{refresh_oauth_count})")
|
483
|
+
ZuoraConnect.logger.info("[#{self.id}] REFRESH OAUTH - Failed #{ex.code} - Retrying(#{refresh_oauth_count})")
|
445
484
|
retry
|
446
485
|
else
|
447
|
-
ZuoraConnect.logger.fatal("[#{self.id}] REFRESH OAUTH - Failed #{refresh_oauth_count}x")
|
486
|
+
ZuoraConnect.logger.fatal("[#{self.id}] REFRESH OAUTH - Failed #{ex.code} - #{refresh_oauth_count}x")
|
448
487
|
raise
|
449
488
|
end
|
450
489
|
end
|
@@ -561,16 +600,16 @@ module ZuoraConnect
|
|
561
600
|
def decrypt_data(data: nil, rescue_return: nil, log_fatal: true)
|
562
601
|
return data if data.blank?
|
563
602
|
if Rails.env == 'development'
|
564
|
-
begin
|
603
|
+
begin
|
565
604
|
return JSON.parse(data)
|
566
605
|
rescue JSON::ParserError => ex
|
567
606
|
return data
|
568
607
|
end
|
569
608
|
else
|
570
|
-
begin
|
609
|
+
begin
|
571
610
|
return JSON.parse(encryptor.decrypt_and_verify(CGI::unescape(data)))
|
572
611
|
rescue ActiveSupport::MessageVerifier::InvalidSignature => ex
|
573
|
-
ZuoraConnect.logger.add(Logger::
|
612
|
+
ZuoraConnect.logger.add(Logger::ERROR, "Error Decrypting for #{self.id}") if log_fatal
|
574
613
|
return rescue_return
|
575
614
|
rescue JSON::ParserError => ex
|
576
615
|
return encryptor.decrypt_and_verify(CGI::unescape(data))
|
@@ -622,7 +661,7 @@ module ZuoraConnect
|
|
622
661
|
if paused_user == current_user || paused_user.blank?
|
623
662
|
Resque.redis.zrem("PauseQueue", "#{self.id}__#{paused_user}")
|
624
663
|
else
|
625
|
-
raise "Can only unpause for user #{paused_user}."
|
664
|
+
raise "Can only unpause for user #{paused_user}."
|
626
665
|
end
|
627
666
|
end
|
628
667
|
### END Resque Helping Methods ####
|
@@ -836,7 +875,7 @@ module ZuoraConnect
|
|
836
875
|
if cache
|
837
876
|
Redis.current.sadd("Catalog:#{self.id}:Keys", ["Catalog:#{self.id}:#{object_id}:Hierarchy", "Catalog:#{self.id}:#{object_id}:Children:#{child_objects}"])
|
838
877
|
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))
|
878
|
+
Redis.current.set("Catalog:#{self.id}:#{object_id}:Children:#{child_objects}", encrypt_data(data: stub_catalog))
|
840
879
|
else
|
841
880
|
Redis.current.sadd("Catalog:#{self.id}:Keys", ["Catalog:#{self.id}:#{object_id}:Hierarchy"])
|
842
881
|
Redis.current.set("Catalog:#{self.id}:#{object_id}:Hierarchy", encrypt_data(data: object_hierarchy))
|
@@ -875,7 +914,7 @@ module ZuoraConnect
|
|
875
914
|
self.update_functions
|
876
915
|
if index_table
|
877
916
|
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
|
917
|
+
else
|
879
918
|
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
919
|
end
|
881
920
|
end
|
@@ -949,4 +988,4 @@ module ZuoraConnect
|
|
949
988
|
method_hook :refresh, :updateOption, :update_logins, :before => :check_oauth_state
|
950
989
|
method_hook :new_session, :refresh, :build_task, :after => :apartment_switch
|
951
990
|
end
|
952
|
-
end
|
991
|
+
end
|
@@ -22,10 +22,10 @@ Resque.module_eval do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
if defined?(Resque)
|
25
|
-
Resque.logger = ZuoraConnect.custom_logger(name: "Resque")
|
25
|
+
Resque.logger = ZuoraConnect.custom_logger(name: "Resque", type: 'Monologger', level: MonoLogger::INFO)
|
26
26
|
Resque::Scheduler.logger = ZuoraConnect.custom_logger(name: "ResqueScheduler") if defined?(Resque::Scheduler)
|
27
27
|
end
|
28
28
|
|
29
29
|
Makara::Logging::Logger.logger = ZuoraConnect.custom_logger(name: "Makara") if defined?(Makara)
|
30
30
|
ElasticAPM.agent.config.logger = ZuoraConnect.custom_logger(name: "ElasticAPM", level: MonoLogger::WARN) if defined?(ElasticAPM) && ElasticAPM.running?
|
31
|
-
ActionMailer::Base.logger = ZuoraConnect.custom_logger(name: "ActionMailer") if defined?(ActionMailer)
|
31
|
+
ActionMailer::Base.logger = ZuoraConnect.custom_logger(name: "ActionMailer", type: 'Monologger') if defined?(ActionMailer)
|
@@ -2,8 +2,7 @@ if defined?(Unicorn::WorkerKiller)
|
|
2
2
|
Unicorn::WorkerKiller.module_eval do
|
3
3
|
self.singleton_class.send(:alias_method, :kill_self_old, :kill_self)
|
4
4
|
def self.kill_self(logger, start_time)
|
5
|
-
|
6
|
-
self.kill_self_old(@unicorn_logger, start_time)
|
5
|
+
self.kill_self_old(logger, start_time)
|
7
6
|
ZuoraConnect::AppInstance.write_to_telegraf(direction: 'Unicorn-Killer', tags: {app_instance: 0}, values: {kill: 1})
|
8
7
|
end
|
9
8
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class AddTokensToAppInstance < ActiveRecord::Migration
|
1
|
+
class AddTokensToAppInstance < ActiveRecord::Migration[4.2]
|
2
2
|
def change
|
3
3
|
add_column :zuora_connect_app_instances, :access_token, :string unless column_exists? :zuora_connect_app_instances, :access_token
|
4
4
|
add_column :zuora_connect_app_instances, :refresh_token, :string unless column_exists? :zuora_connect_app_instances, :refresh_token
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class AddExpirationToAppInstance < ActiveRecord::Migration
|
1
|
+
class AddExpirationToAppInstance < ActiveRecord::Migration[4.2]
|
2
2
|
def change
|
3
3
|
add_column :zuora_connect_app_instances, :oauth_expires_at, :datetime unless column_exists? :zuora_connect_app_instances, :oauth_expires_at
|
4
4
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class AddCatalogDataToAppInstance < ActiveRecord::Migration
|
1
|
+
class AddCatalogDataToAppInstance < ActiveRecord::Migration[4.2]
|
2
2
|
def change
|
3
3
|
add_column :zuora_connect_app_instances, :catalog_updated_at, :datetime unless column_exists? :zuora_connect_app_instances, :catalog_updated_at
|
4
4
|
add_column :zuora_connect_app_instances, :catalog, :jsonb, default: {} unless column_exists? :zuora_connect_app_instances, :catalog
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class AddCatalogMappingsToAppInstance < ActiveRecord::Migration
|
1
|
+
class AddCatalogMappingsToAppInstance < ActiveRecord::Migration[4.2]
|
2
2
|
def change
|
3
3
|
add_column :zuora_connect_app_instances, :catalog_mapping, :jsonb, default: {} unless column_exists? :zuora_connect_app_instances, :catalog_mapping
|
4
4
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class AddCatalogAttemptedAt < ActiveRecord::Migration
|
1
|
+
class AddCatalogAttemptedAt < ActiveRecord::Migration[4.2]
|
2
2
|
def change
|
3
3
|
add_column :zuora_connect_app_instances, :catalog_update_attempt_at, :datetime unless column_exists? :zuora_connect_app_instances, :catalog_update_attempt_at
|
4
4
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class AddZuoraUserTableAndAlterAppInstanceIdTable < ActiveRecord::Migration[5.0]
|
2
|
+
def change
|
3
|
+
if !ActiveRecord::Base.connection.table_exists?('zuora_users')
|
4
|
+
create_table :zuora_users do |t|
|
5
|
+
t.string :zuora_user_id
|
6
|
+
t.jsonb :zuora_identity_response, default: {}
|
7
|
+
t.jsonb :app_permissions, default: {}
|
8
|
+
t.integer :scope, default: 0
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
add_column :zuora_connect_app_instances, :zuora_domain, :text, default: "" unless column_exists? :zuora_connect_app_instances, :zuora_domain
|
14
|
+
add_column :zuora_connect_app_instances, :zuora_entity_ids, :jsonb, default: [] unless column_exists? :zuora_connect_app_instances, :zuora_entity_ids
|
15
|
+
add_column :zuora_connect_app_instances, :zuora_tenant_ids, :jsonb, default: [] unless column_exists? :zuora_connect_app_instances, :zuora_tenant_ids
|
16
|
+
add_column :zuora_connect_app_instances, :zuora_logins, :text, default: "" unless column_exists? :zuora_connect_app_instances, :zuora_logins
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'ougai/formatters/base'
|
2
|
+
require 'ougai/formatters/for_json'
|
3
|
+
|
4
|
+
module Ougai
|
5
|
+
module Formatters
|
6
|
+
# A JSON formatter compatible with node-bunyan
|
7
|
+
class ConnectFormatter < Base
|
8
|
+
include ForJson
|
9
|
+
|
10
|
+
# Intialize a formatter
|
11
|
+
# @param [String] app_name application name (execution program name if nil)
|
12
|
+
# @param [String] hostname hostname (hostname if nil)
|
13
|
+
# @param [Hash] opts the initial values of attributes
|
14
|
+
# @option opts [String] :trace_indent (2) the value of trace_indent attribute
|
15
|
+
# @option opts [String] :trace_max_lines (100) the value of trace_max_lines attribute
|
16
|
+
# @option opts [String] :serialize_backtrace (true) the value of serialize_backtrace attribute
|
17
|
+
# @option opts [String] :jsonize (true) the value of jsonize attribute
|
18
|
+
# @option opts [String] :with_newline (true) the value of with_newline attribute
|
19
|
+
def initialize(app_name = nil, hostname = nil, opts = {})
|
20
|
+
aname, hname, opts = Base.parse_new_params([app_name, hostname, opts])
|
21
|
+
super(aname, hname, opts)
|
22
|
+
init_opts_for_json(opts)
|
23
|
+
end
|
24
|
+
|
25
|
+
def _call(severity, time, progname, data)
|
26
|
+
dump({
|
27
|
+
name: progname || @app_name,
|
28
|
+
pid: $$,
|
29
|
+
level: severity,
|
30
|
+
timestamp: time.utc.strftime('%FT%T.%6NZ'),
|
31
|
+
}.merge(data.merge({message: data.delete(:msg)})))
|
32
|
+
end
|
33
|
+
|
34
|
+
def convert_time(data)
|
35
|
+
#data[:timestamp] = format_datetime(data[:time])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/metrics/net.rb
CHANGED
@@ -162,7 +162,7 @@ class HttpLogger
|
|
162
162
|
end
|
163
163
|
|
164
164
|
def format_log_entry(message, dump = nil)
|
165
|
-
if self.class.colorize
|
165
|
+
if self.class.colorize && Rails.configuration.colorize_logging
|
166
166
|
message_color, dump_color = "4;32;1", "0;1"
|
167
167
|
log_entry = " \e[#{message_color}m#{message}\e[0m "
|
168
168
|
log_entry << "\e[#{dump_color}m%#{String === dump ? 's' : 'p'}\e[0m" % dump if dump
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module
|
1
|
+
module ZuoraConnect
|
2
2
|
require 'uri'
|
3
3
|
|
4
4
|
# Object of this class is passed to the ActiveSupport::Notification hook
|
@@ -53,7 +53,10 @@ module Middleware
|
|
53
53
|
env['REQUEST_PATH'] = env['REQUEST_PATH'].gsub(Thread.current[:isHallway], '')
|
54
54
|
|
55
55
|
#We need the forwarded host header to identify location of tenant
|
56
|
-
|
56
|
+
whitelist = Regexp.new(".*[\.]zuora[\.]com$|^zuora[\.]com$")
|
57
|
+
if whitelist.match(env['HTTP_X_FORWARDED_HOST']).present?
|
58
|
+
@bad_headers.delete('HTTP_X_FORWARDED_HOST')
|
59
|
+
end
|
57
60
|
else
|
58
61
|
Thread.current[:isHallway] = nil
|
59
62
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ZuoraConnect
|
2
|
+
class RequestIdMiddleware
|
3
|
+
mattr_accessor :request_id
|
4
|
+
mattr_accessor :zuora_request_id
|
5
|
+
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
self.request_id = env['action_dispatch.request_id']
|
12
|
+
self.zuora_request_id = env["HTTP_ZUORA_REQUEST_ID"]
|
13
|
+
@app.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -7,27 +7,7 @@ module Resque
|
|
7
7
|
module Plugins
|
8
8
|
module CustomLogger
|
9
9
|
def before_perform(*args)
|
10
|
-
|
11
|
-
|
12
|
-
logger = MonoLogger.new(STDOUT)
|
13
|
-
logger.level = Rails.application.config.log_level
|
14
|
-
logger.formatter = proc do |serverity, datetime, progname, msg|
|
15
|
-
begin
|
16
|
-
msg = JSON.parse(msg)
|
17
|
-
rescue JSON::ParserError => ex
|
18
|
-
end
|
19
|
-
|
20
|
-
require 'json'
|
21
|
-
JSON.dump(
|
22
|
-
trace_id: marker,
|
23
|
-
level: serverity,
|
24
|
-
timestamp: datetime.strftime('%FT%T.%6N'),
|
25
|
-
pid: Process.pid,
|
26
|
-
msg: msg
|
27
|
-
) + "\n"
|
28
|
-
end
|
29
|
-
|
30
|
-
Rails.logger = logger
|
10
|
+
Rails.logger.with_fields = { trace_id: SecureRandom.uuid, name: "RailsWorker"} if Rails.logger.class.to_s == 'Ougai::Logger'
|
31
11
|
case args.class.to_s
|
32
12
|
when "Array"
|
33
13
|
if args.first.class == Hash
|
@@ -38,8 +18,10 @@ module Resque
|
|
38
18
|
when "Hash"
|
39
19
|
data = args.merge({:worker_class => self.to_s})
|
40
20
|
end
|
41
|
-
|
21
|
+
data = {:msg => 'Starting job', :job => data}
|
22
|
+
data.merge!({:app_instance_id => data.dig(:job, 'app_instance_id')}) if data.dig(:job, 'app_instance_id').present?
|
23
|
+
Rails.logger.info(data) if data.present?
|
42
24
|
end
|
43
25
|
end
|
44
26
|
end
|
45
|
-
end
|
27
|
+
end
|
data/lib/zuora_connect.rb
CHANGED
@@ -9,6 +9,7 @@ require 'resque/dynamic_queues'
|
|
9
9
|
require 'resque/silence_done'
|
10
10
|
require 'resque/self_lookup'
|
11
11
|
require 'resque/plugins/custom_logger'
|
12
|
+
require 'logging/connect_formatter'
|
12
13
|
require 'metrics/influx/point_value'
|
13
14
|
require 'metrics/net'
|
14
15
|
|
@@ -18,26 +19,66 @@ module ZuoraConnect
|
|
18
19
|
attr_writer :logger
|
19
20
|
|
20
21
|
def logger
|
21
|
-
|
22
|
-
|
22
|
+
case Rails.env.to_s
|
23
|
+
when 'development'
|
24
|
+
Rails.logger
|
25
|
+
else
|
26
|
+
@logger ||= custom_logger(name: "Connect", level: Rails.logger.level)
|
27
|
+
end
|
28
|
+
end
|
23
29
|
|
24
|
-
def custom_logger(name: "", level: Rails.logger.level)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
30
|
+
def custom_logger(name: "", level: Rails.logger.present? ? Rails.logger.level : MonoLogger::INFO, type: :ougai)
|
31
|
+
#puts name + ' - ' + {Logger::WARN => 'Logger::WARN', Logger::ERROR => 'Logger::ERROR', Logger::DEBUG => 'Logger::DEBUG', Logger::INFO => 'Logger::INFO' }[level] + ' - '
|
32
|
+
if type == :ougai
|
33
|
+
require 'ougai'
|
34
|
+
#logger = Ougai::Logger.new(MonoLogger.new(STDOUT))
|
35
|
+
logger = Ougai::Logger.new(STDOUT)
|
36
|
+
logger.formatter = Ougai::Formatters::ConnectFormatter.new(name)
|
37
|
+
logger.level = level
|
38
|
+
logger.before_log = lambda do |data|
|
39
|
+
data[:trace_id] = ZuoraConnect::RequestIdMiddleware.request_id if ZuoraConnect::RequestIdMiddleware.request_id.present?
|
40
|
+
data[:zuora_trace_id] = ZuoraConnect::RequestIdMiddleware.zuora_request_id if ZuoraConnect::RequestIdMiddleware.zuora_request_id.present?
|
41
|
+
#data[:traces] = {amazon_id: data[:trace_id], zuora_id: data[:zuora_trace_id]}
|
42
|
+
if !['ElasticAPM', 'ResqueScheduler', 'ResquePool', 'Resque', 'Makara'].include?(name)
|
43
|
+
if Thread.current[:appinstance].present?
|
44
|
+
data[:app_instance_id] = Thread.current[:appinstance].id
|
45
|
+
logitems = Thread.current[:appinstance].logitems
|
46
|
+
if logitems.present? && logitems.class == Hash
|
47
|
+
data[:tenant_ids] = logitems[:tenant_ids] if logitems[:tenant_ids].present?
|
48
|
+
data[:organization] = logitems[:organization] if logitems[:organization].present?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
31
52
|
end
|
53
|
+
else
|
54
|
+
logger = MonoLogger.new(STDOUT)
|
55
|
+
logger.level = level
|
56
|
+
logger.formatter = proc do |serverity, datetime, progname, msg|
|
57
|
+
begin
|
58
|
+
msg = JSON.parse(msg)
|
59
|
+
rescue JSON::ParserError => ex
|
60
|
+
end
|
32
61
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
62
|
+
require 'json'
|
63
|
+
store = {
|
64
|
+
name: name,
|
65
|
+
level: serverity,
|
66
|
+
timestamp: datetime.strftime('%FT%T.%6NZ'),
|
67
|
+
pid: Process.pid,
|
68
|
+
message: name == "ActionMailer" ? msg.strip : msg
|
69
|
+
}
|
70
|
+
if !['ElasticAPM', 'ResqueScheduler', 'ResquePool','Resque', 'Makara'].include?(name)
|
71
|
+
if Thread.current[:appinstance].present?
|
72
|
+
store[:app_instance_id] = Thread.current[:appinstance].id
|
73
|
+
logitems = Thread.current[:appinstance].logitems
|
74
|
+
if logitems.present? && logitems.class == Hash
|
75
|
+
store[:tenant_ids] = logitems[:tenant_ids] if logitems[:tenant_ids].present?
|
76
|
+
store[:organization] = logitems[:organization] if logitems[:organization].present?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
JSON.dump(store) + "\n"
|
81
|
+
end
|
41
82
|
end
|
42
83
|
return logger
|
43
84
|
end
|
@@ -94,6 +135,7 @@ module ZuoraConnect
|
|
94
135
|
end
|
95
136
|
|
96
137
|
defaults.merge!({
|
138
|
+
disable_start_message: true,
|
97
139
|
pool_size: 1,
|
98
140
|
transaction_max_spans: 500,
|
99
141
|
ignore_url_patterns: ['^\/admin\/resque.*', '^\/admin\/redis.*', '^\/admin\/peek.*', '^\/peek.*'],
|
@@ -86,7 +86,7 @@ module ZuoraConnect
|
|
86
86
|
@appinstance.cache_app_instance
|
87
87
|
session["appInstance"] = app_instance_ids[0]
|
88
88
|
else
|
89
|
-
ZuoraConnect.logger.
|
89
|
+
ZuoraConnect.logger.error("Launch Error: Param Instance didnt match session data")
|
90
90
|
render "zuora_connect/static/invalid_launch_request"
|
91
91
|
return
|
92
92
|
end
|
@@ -95,7 +95,7 @@ module ZuoraConnect
|
|
95
95
|
return
|
96
96
|
end
|
97
97
|
rescue => ex
|
98
|
-
ZuoraConnect.logger.
|
98
|
+
ZuoraConnect.logger.error(ex)
|
99
99
|
render "zuora_connect/static/invalid_launch_request"
|
100
100
|
return
|
101
101
|
end
|
@@ -113,7 +113,7 @@ module ZuoraConnect
|
|
113
113
|
return
|
114
114
|
end
|
115
115
|
rescue => ex
|
116
|
-
ZuoraConnect.logger.
|
116
|
+
ZuoraConnect.logger.error(ex)
|
117
117
|
render "zuora_connect/static/invalid_launch_request"
|
118
118
|
return
|
119
119
|
end
|
@@ -142,7 +142,7 @@ module ZuoraConnect
|
|
142
142
|
begin
|
143
143
|
I18n.locale = session["#{@appinstance.id}::user::locale"] ? session["#{@appinstance.id}::user::locale"] : @appinstance.locale
|
144
144
|
rescue I18n::InvalidLocale => ex
|
145
|
-
ZuoraConnect.logger.error(
|
145
|
+
ZuoraConnect.logger.error(ex) if !ZuoraConnect::AppInstance::IGNORED_LOCALS.include?(ex.locale.to_s.downcase)
|
146
146
|
end
|
147
147
|
Time.zone = session["#{@appinstance.id}::user::timezone"] ? session["#{@appinstance.id}::user::timezone"] : @appinstance.timezone
|
148
148
|
ZuoraConnect.logger.debug("[#{@appinstance.blank? ? "N/A" : @appinstance.id}] Authenticate App Request Completed In - #{(Time.now - start_time).round(2)}s")
|
@@ -170,7 +170,6 @@ module ZuoraConnect
|
|
170
170
|
def setup_instance_via_data
|
171
171
|
session.clear
|
172
172
|
values = JSON.parse(ZuoraConnect::AppInstance.decrypt_response(Base64.urlsafe_decode64(request["data"])))
|
173
|
-
ZuoraConnect.logger.debug("Data: #{values.to_json}")
|
174
173
|
if values["param_data"]
|
175
174
|
values["param_data"].each do |k ,v|
|
176
175
|
params[k] = v
|
@@ -185,7 +184,7 @@ module ZuoraConnect
|
|
185
184
|
session["#{values["appInstance"]}::user::email"] = values["current_user"]["email"]
|
186
185
|
end
|
187
186
|
|
188
|
-
ZuoraConnect.logger.debug(
|
187
|
+
ZuoraConnect.logger.debug({msg: 'Setup values', connect: values}) if Rails.env != "production"
|
189
188
|
|
190
189
|
@appinstance = ZuoraConnect::AppInstance.where(:id => values["appInstance"].to_i).first
|
191
190
|
if @appinstance.blank?
|
@@ -253,7 +252,7 @@ module ZuoraConnect
|
|
253
252
|
ElasticAPM.set_user("API User") if defined?(ElasticAPM) && ElasticAPM.running?
|
254
253
|
return true
|
255
254
|
else
|
256
|
-
render
|
255
|
+
render plain: "Access Denied", status: :unauthorized
|
257
256
|
end
|
258
257
|
end
|
259
258
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'middleware/metrics_middleware'
|
2
|
+
require 'middleware/request_id_middleware'
|
2
3
|
|
3
4
|
module ZuoraConnect
|
4
5
|
class Railtie < Rails::Railtie
|
@@ -22,33 +23,38 @@ module ZuoraConnect
|
|
22
23
|
end
|
23
24
|
end
|
24
25
|
initializer "zuora_connect.configure_rails_initialization" do |app|
|
25
|
-
app.middleware.insert_after Rack::Sendfile,
|
26
|
+
app.middleware.insert_after Rack::Sendfile, ZuoraConnect::MetricsMiddleware
|
27
|
+
app.middleware.insert_after ActionDispatch::RequestId, ZuoraConnect::RequestIdMiddleware
|
26
28
|
end
|
27
29
|
|
28
30
|
# hook to process_action
|
29
|
-
ActiveSupport::Notifications.subscribe('process_action.action_controller',
|
31
|
+
ActiveSupport::Notifications.subscribe('process_action.action_controller', ZuoraConnect::PageRequest.new)
|
30
32
|
|
31
33
|
initializer(:rails_stdout_logging, before: :initialize_logger) do
|
32
34
|
if Rails.env != 'development' && !ENV['DEIS_APP'].blank?
|
33
35
|
require 'lograge'
|
34
|
-
|
35
|
-
logger
|
36
|
-
|
37
|
-
# {severity: severity, time: datetime.strftime('%FT%T.%6N'), process_id: Process.pid, message: msg }.to_json
|
38
|
-
# end
|
39
|
-
Rails.configuration.logger = ActiveSupport::TaggedLogging.new(logger)
|
40
|
-
Rails.configuration.log_tags = [:uuid]
|
36
|
+
|
37
|
+
Rails.configuration.logger = ZuoraConnect.custom_logger(name: "Rails")
|
38
|
+
|
41
39
|
Rails.configuration.lograge.enabled = true
|
42
|
-
Rails.configuration.
|
40
|
+
Rails.configuration.colorize_logging = false
|
41
|
+
if Rails.configuration.logger.class.to_s == 'Ougai::Logger'
|
42
|
+
Rails.configuration.lograge.formatter = Class.new do |fmt|
|
43
|
+
def fmt.call(data)
|
44
|
+
{ msg: 'Rails Request', request: data }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
#Rails.configuration.lograge.formatter = Lograge::Formatters::Json.new
|
43
49
|
Rails.configuration.lograge.custom_options = lambda do |event|
|
44
50
|
exceptions = %w(controller action format id)
|
45
51
|
items = {
|
46
52
|
#time: event.time.strftime('%FT%T.%6N'),
|
47
|
-
params: event.payload[:params].except(*exceptions)
|
48
|
-
exception: event.payload[:exception],
|
49
|
-
exception_object: event.payload[:exception_object],
|
50
|
-
process_id: Process.pid
|
53
|
+
params: event.payload[:params].except(*exceptions).to_json.to_s
|
51
54
|
}
|
55
|
+
items.merge!({exception_object: event.payload[:exception_object]}) if event.payload[:exception_object].present?
|
56
|
+
items.merge!({exception: event.payload[:exception]}) if event.payload[:exception].present?
|
57
|
+
|
52
58
|
if Thread.current[:appinstance].present?
|
53
59
|
items.merge!({appinstance_id: Thread.current[:appinstance].id, connect_user: Thread.current[:appinstance].connect_user, new_session: Thread.current[:appinstance].new_session_message})
|
54
60
|
if Thread.current[:appinstance].logitems.present? && Thread.current[:appinstance].logitems.class == Hash
|
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:
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Connect Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-05-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: apartment
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: ougai
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: zuora_api
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,7 +143,7 @@ dependencies:
|
|
129
143
|
version: 4.1.0
|
130
144
|
- - "<"
|
131
145
|
- !ruby/object:Gem::Version
|
132
|
-
version: '5.
|
146
|
+
version: '5.3'
|
133
147
|
type: :runtime
|
134
148
|
prerelease: false
|
135
149
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -139,7 +153,21 @@ dependencies:
|
|
139
153
|
version: 4.1.0
|
140
154
|
- - "<"
|
141
155
|
- !ruby/object:Gem::Version
|
142
|
-
version: '5.
|
156
|
+
version: '5.3'
|
157
|
+
- !ruby/object:Gem::Dependency
|
158
|
+
name: raindrops
|
159
|
+
requirement: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - ">="
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0'
|
164
|
+
type: :runtime
|
165
|
+
prerelease: false
|
166
|
+
version_requirements: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '0'
|
143
171
|
- !ruby/object:Gem::Dependency
|
144
172
|
name: rspec
|
145
173
|
requirement: !ruby/object:Gem::Requirement
|
@@ -304,9 +332,12 @@ files:
|
|
304
332
|
- db/migrate/20110503003604_catalog_default.rb
|
305
333
|
- db/migrate/20180301052853_add_catalog_attempted_at.rb
|
306
334
|
- db/migrate/20181206162339_add_fields_to_instance.rb
|
335
|
+
- db/migrate/20190520232221_add_zuora_user_table_and_alter_app_instance_id_table.rb
|
336
|
+
- lib/logging/connect_formatter.rb
|
307
337
|
- lib/metrics/influx/point_value.rb
|
308
338
|
- lib/metrics/net.rb
|
309
339
|
- lib/middleware/metrics_middleware.rb
|
340
|
+
- lib/middleware/request_id_middleware.rb
|
310
341
|
- lib/resque/additions.rb
|
311
342
|
- lib/resque/dynamic_queues.rb
|
312
343
|
- lib/resque/plugins/custom_logger.rb
|
@@ -376,9 +407,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
376
407
|
version: '0'
|
377
408
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
378
409
|
requirements:
|
379
|
-
- - "
|
410
|
+
- - ">="
|
380
411
|
- !ruby/object:Gem::Version
|
381
|
-
version:
|
412
|
+
version: '0'
|
382
413
|
requirements: []
|
383
414
|
rubygems_version: 3.0.3
|
384
415
|
signing_key:
|