jfrog-saas-log-collector 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,481 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'date'
5
+ require 'zlib'
6
+ require 'stringio'
7
+ require 'logger'
8
+
9
+ require_relative 'constants'
10
+ require_relative 'confighandler'
11
+ require_relative 'unzipper'
12
+ require_relative 'connectionmanager'
13
+
14
+ module Jfrog
15
+ module Saas
16
+ module Log
17
+ class CommonUtils
18
+ include Singleton
19
+ DELIM = '_@@_'
20
+ HTTP_GET = 'get'
21
+ HTTP_PUT = 'put'
22
+ HTTP_PATCH = 'patch'
23
+ HTTP_DELETE = 'delete'
24
+ HTTP_POST = 'post'
25
+ CONTENT_TYPE_JSON = 'application/json'
26
+ CONTENT_TYPE_TEXT = 'text/plain'
27
+ CONTENT_TYPE_HDR = 'Content-Type'
28
+ FILE_PROCESSING_LOCK = 'LOCK'
29
+ FILE_PROCESSING_SUCCESS = 'SUCCESS'
30
+ STATUS_FILE_SUFFIX = '.status.json'
31
+ LOCK_FILE_SUFFIX = '.lock'
32
+ LOG_ERROR = 'error'
33
+ LOG_WARN = 'warn'
34
+ LOG_INFO = 'info'
35
+ LOG_DEBUG = 'debug'
36
+
37
+ # STRING MANIPULATIONS AND OTHER SIMPLE UTILS - BEGIN
38
+ def get_log_url_for_date(solution, date_in_string)
39
+ log_repo_url + "/#{solution}/#{date_in_string}"
40
+ end
41
+
42
+ def audit_repo_url
43
+ ConfigHandler.instance.log_config.audit_repo_url.to_s
44
+ end
45
+
46
+ def log_repo_url
47
+ ConfigHandler.instance.log_config.log_repo_url.to_s
48
+ end
49
+
50
+ def artifactory_log_url(date)
51
+ "/#{ConfigHandler.instance.conn_config.end_point_base}/#{date}"
52
+ end
53
+
54
+ def log_ship_config_url
55
+ "/#{ConfigHandler.instance.log_config.log_ship_config}"
56
+ end
57
+
58
+ def artifactory_aql_url
59
+ "/#{ConfigHandler.instance.conn_config.end_point_base}/api/search/aql"
60
+ end
61
+
62
+ def artifactory_aql_body(solution, date_in_string)
63
+ "items.find({\"repo\": \"#{((log_repo_url).split("/"))[1]}\", \"path\" : {\"$match\":\"#{solution}/#{date_in_string}\"}, \"name\" : {\"$match\":\"*log.gz\"}})"
64
+ end
65
+
66
+ def audit_aql_body(solution, date_in_string)
67
+ "items.find({\"repo\": \"#{((audit_repo_url).split("/"))[1]}\", \"path\" : {\"$match\":\"#{solution}/#{date_in_string}\"}, \"name\" : {\"$match\":\"*log.gz#{CommonUtils::STATUS_FILE_SUFFIX}\"}})"
68
+ end
69
+
70
+ def audit_aql_locked_files_body(solution, date_in_string)
71
+ "items.find({\"repo\": \"#{((audit_repo_url).split("/"))[1]}\", \"path\" : {\"$match\":\"#{solution}/#{date_in_string}\"}, \"name\" : {\"$match\":\"*log.gz#{CommonUtils::LOCK_FILE_SUFFIX}\"}})"
72
+ end
73
+
74
+ def audit_specific_file_lock(solution, download_file_name)
75
+ "items.find({\"repo\": \"#{((audit_repo_url).split("/"))[1]}\", \"path\" : {\"$match\":\"#{solution}/*\"}, \"name\" : {\"$match\":\"#{download_file_name}#{CommonUtils::LOCK_FILE_SUFFIX}\"}})"
76
+ end
77
+
78
+ def audit_repo_create_url
79
+ "#{ConfigHandler.instance.conn_config.end_point_base}/api/repositories/#{((audit_repo_url).split("/"))[1]}"
80
+ end
81
+
82
+ def audit_repo_create_body
83
+ "{
84
+ \"key\": \"#{((audit_repo_url).split("/"))[1]}\",
85
+ \"environments\":[\"PROD\"],
86
+ \"rclass\" : \"local\",
87
+ \"packageType\": \"generic\",
88
+ \"repoLayoutRef\": \"simple-default\",
89
+ \"description\": \"This repository is for auditing the jfrog-saas-log-collector downloads and extracts\"
90
+ }"
91
+ end
92
+
93
+ def audit_repo_target_dir_url(target_dir_string, repo_only_req, full_uri_req, trailing_uri_req)
94
+ uri = ''
95
+
96
+ if repo_only_req
97
+ uri = (((audit_repo_url).split('/'))[1]).to_s
98
+ elsif full_uri_req
99
+ uri = "#{ConfigHandler.instance.conn_config.jpd_url}/#{ConfigHandler.instance.conn_config.end_point_base}/#{((audit_repo_url).split("/"))[1]}/#{target_dir_string}"
100
+ elsif !full_uri_req
101
+ uri = "#{ConfigHandler.instance.conn_config.end_point_base}/#{((audit_repo_url).split("/"))[1]}/#{target_dir_string}"
102
+ end
103
+
104
+ if trailing_uri_req
105
+ uri = "#{uri}/" # this trailing '/' is very important for directory creations, else Artifactory APIs think they are files
106
+ end
107
+
108
+ uri
109
+ end
110
+
111
+ def audit_repo_create_tgt_dir_body(target_dir_string)
112
+ "{
113
+ \"uri\": \"#{audit_repo_target_dir_url(target_dir_string, false, true, false)}\",
114
+ \"repo\": \"#{audit_repo_target_dir_url(target_dir_string, true, false, false)}\",
115
+ \"path\" : \"#{audit_repo_target_dir_url(target_dir_string, false, false, false)}\",
116
+ \"created\": \"#{DateTime.now.iso8601}\",
117
+ \"createdBy\": \"#{ConfigHandler.instance.conn_config.username}\",
118
+ \"children\": [ ]
119
+ }"
120
+ end
121
+
122
+ def audit_file_status_body(file_name, file_extract_status)
123
+ "{
124
+ \"file_name\": \"#{file_name.chomp(CommonUtils::STATUS_FILE_SUFFIX)}\",
125
+ \"download_extract_status\": \"#{file_extract_status}\",
126
+ \"event_time\": \"#{DateTime.now.iso8601}\",
127
+ \"createdBy\": \"jfrog-saas-log-collector\"
128
+ }"
129
+ end
130
+
131
+ def get_size_in_mb(bytes, return_string)
132
+ if return_string
133
+ "#{(bytes / (1024.0 * 1024.0)).round(2)} MB"
134
+ else
135
+ (bytes / (1024.0 * 1024.0)).round(2)
136
+ end
137
+ end
138
+
139
+ def generate_dates_list(solution, start_date_str, end_date_str)
140
+ dates_list = []
141
+ diff_days = 0
142
+ start_date = parse_date(solution, start_date_str)
143
+ end_date = parse_date(solution, end_date_str)
144
+ diff_days = end_date.mjd - start_date.mjd if end_date >= start_date
145
+ if !diff_days.nil? && diff_days.positive?
146
+ diff_days.times do |index|
147
+ dates_list.push(start_date + index)
148
+ end
149
+ else
150
+ dates_list.push(end_date)
151
+ end
152
+
153
+ dates_list
154
+ end
155
+
156
+ def parse_date(solution, date_in_str)
157
+ date_pattern = if ConfigHandler.instance.log_config.uri_date_pattern.nil?
158
+ '%Y-%m-%d'
159
+ else
160
+ ConfigHandler.instance.log_config.uri_date_pattern
161
+ end
162
+ Date.strptime(date_in_str, date_pattern)
163
+ rescue ArgumentError => e
164
+ MessageUtils.instance.log_message(MessageUtils::FORCE_USE_CURRENT_DATE, { "param1": e.message.to_s,
165
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_ERROR,
166
+ "#{MessageUtils::SOLUTION}": solution } )
167
+ Date.today
168
+ end
169
+
170
+ def logs_to_process_between(solution, start_date_str, end_date_str)
171
+ generate_dates_list(solution, start_date_str, end_date_str)
172
+ end
173
+ # STRING MANIPULATIONS AND OTHER SIMPLE UTILS - END
174
+
175
+ # RESOURCE RELATED - BEGIN
176
+ def check_if_resource_exists(solution, relative_url)
177
+ resource_exists = false
178
+ conn_mgr = ConnectionManager.new
179
+ headers = { CommonUtils::CONTENT_TYPE_HDR => CommonUtils::CONTENT_TYPE_JSON }
180
+ response = conn_mgr.execute(relative_url, nil, headers, nil, CommonUtils::HTTP_GET, true)
181
+ if !response.nil? && response.status >= 200 && response.status < 300
182
+ resource_exists = true
183
+ MessageUtils.instance.log_message(MessageUtils::RESOURCE_CHECK_SUCCESS, { "param1": "#{ConfigHandler.instance.conn_config.jpd_url}/#{relative_url}",
184
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_INFO,
185
+ "#{MessageUtils::SOLUTION}": solution } )
186
+ else
187
+ MessageUtils.instance.log_message(MessageUtils::RESOURCE_CHECK_FAILED_DETAIL, { "param1": "#{ConfigHandler.instance.conn_config.jpd_url}/#{relative_url}",
188
+ "param2": response.body.to_s,
189
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_ERROR,
190
+ "#{MessageUtils::SOLUTION}": solution } )
191
+ end
192
+ resource_exists
193
+ end
194
+
195
+ def log_shipping_enabled
196
+ log_shipping = false
197
+ conn_mgr = ConnectionManager.new
198
+ headers = { CommonUtils::CONTENT_TYPE_HDR => CommonUtils::CONTENT_TYPE_JSON }
199
+ response = conn_mgr.execute(log_ship_config_url, nil, headers, nil, CommonUtils::HTTP_GET, true)
200
+ if !response.nil? && response.status >= 200 && response.status < 300
201
+ log_shipping = response.body['enabled']
202
+ MessageUtils.instance.log_message(MessageUtils::LOG_SHIPPING_ENABLED, { "param1": log_shipping.to_s,
203
+ "param2": "#{ConfigHandler.instance.conn_config.jpd_url}/#{log_ship_config_url}",
204
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_INFO,
205
+ "#{MessageUtils::SOLUTION}": MessageUtils::SOLUTION_OVERRIDE_INIT } )
206
+ else
207
+ MessageUtils.instance.log_message(MessageUtils::LOG_SHIPPING_CHECK_CALL_FAIL_DETAIL, { "param1": "#{ConfigHandler.instance.conn_config.jpd_url}/#{log_ship_config_url}",
208
+ "param2": response.body.to_s,
209
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_ERROR,
210
+ "#{MessageUtils::SOLUTION}": MessageUtils::SOLUTION_OVERRIDE_INIT } )
211
+ end
212
+ log_shipping
213
+ end
214
+
215
+ def check_and_create_audit_repo
216
+ audit_log_repo_exists = check_if_resource_exists(nil, audit_repo_create_url)
217
+ unless audit_log_repo_exists
218
+ conn_mgr = ConnectionManager.new
219
+ headers = { CommonUtils::CONTENT_TYPE_HDR => CommonUtils::CONTENT_TYPE_JSON }
220
+ body = audit_repo_create_body
221
+ if ConfigHandler.instance.log_config.debug_mode
222
+ MessageUtils.instance.log_message(MessageUtils::AUDIT_REPO_CHECK_CALL_DETAIL, { "param1": audit_repo_create_url.to_s,
223
+ "param2": headers.to_s,
224
+ "param3": audit_repo_create_body.to_s,
225
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_DEBUG,
226
+ "#{MessageUtils::SOLUTION}": nil })
227
+ end
228
+ response = conn_mgr.execute(audit_repo_create_url, nil, headers, body, CommonUtils::HTTP_PUT, true)
229
+ if !response.nil? && (response.status >= 200 && response.status < 300)
230
+ MessageUtils.instance.log_message(MessageUtils::AUDIT_REPO_CREATION_SUCCESS, { "param1": "#{ConfigHandler.instance.conn_config.jpd_url}/#{CommonUtils.instance.audit_repo_url}",
231
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_INFO,
232
+ "#{MessageUtils::SOLUTION}": nil })
233
+ audit_log_repo_exists = true
234
+ else
235
+ MessageUtils.instance.log_message(MessageUtils::AUDIT_REPO_CREATION_FAILED_DETAIL, { "param1": "#{ConfigHandler.instance.conn_config.jpd_url}/#{CommonUtils.instance.audit_repo_url}",
236
+ "param2": response.body.to_s,
237
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_ERROR,
238
+ "#{MessageUtils::SOLUTION}": nil })
239
+ audit_log_repo_exists = false
240
+ end
241
+ end
242
+ audit_log_repo_exists
243
+ end
244
+
245
+
246
+ def check_create_tgt_dir(solution, tgt_dir_str)
247
+ audit_log_repo_tgt_dir_exists = check_if_resource_exists(solution, audit_repo_target_dir_url(tgt_dir_str, false, false, false))
248
+ unless audit_log_repo_tgt_dir_exists
249
+ conn_mgr = ConnectionManager.new
250
+ headers = { CommonUtils::CONTENT_TYPE_HDR => CommonUtils::CONTENT_TYPE_JSON }
251
+ body = audit_repo_create_tgt_dir_body(tgt_dir_str)
252
+ if ConfigHandler.instance.log_config.debug_mode
253
+ MessageUtils.instance.log_message(MessageUtils::AUDIT_REPO_TGT_DIR_CHECK_CALL_DETAIL, { "param1": "#{audit_repo_target_dir_url(tgt_dir_str, false, true, true)}",
254
+ "param2": headers.to_s,
255
+ "param3": audit_repo_create_tgt_dir_body(tgt_dir_str).to_s,
256
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_DEBUG,
257
+ "#{MessageUtils::SOLUTION}": solution })
258
+ end
259
+ response = conn_mgr.execute(audit_repo_target_dir_url(tgt_dir_str, false, false, true), nil, headers, body, CommonUtils::HTTP_PUT, true)
260
+ if !response.nil? && (response.status >= 200 && response.status < 300)
261
+ MessageUtils.instance.log_message(MessageUtils::AUDIT_REPO_TGT_DIR_CREATION_SUCCESS, { "param1": "#{audit_repo_target_dir_url(tgt_dir_str, false, true, false)}",
262
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_INFO,
263
+ "#{MessageUtils::SOLUTION}": nil })
264
+ audit_log_repo_tgt_dir_exists = true
265
+ else
266
+ MessageUtils.instance.log_message(MessageUtils::AUDIT_REPO_TGT_DIR_CREATION_FAILED_DETAIL, { "param1": "#{audit_repo_target_dir_url(tgt_dir_str, false, true, false)}",
267
+ "param2": response.body.to_s,
268
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_ERROR,
269
+ "#{MessageUtils::SOLUTION}": solution })
270
+ end
271
+ end
272
+ audit_log_repo_tgt_dir_exists
273
+ end
274
+
275
+ def audit_lock_file(solution, audit_file)
276
+ audit_lock_file_found = false
277
+ conn_mgr = ConnectionManager.new
278
+ body = audit_specific_file_lock(solution, audit_file)
279
+ headers = { CommonUtils::CONTENT_TYPE_HDR => CommonUtils::CONTENT_TYPE_TEXT }
280
+ if ConfigHandler.instance.log_config.debug_mode
281
+ MessageUtils.instance.log_message(MessageUtils::AUDIT_LOCK_AQL_QUERY_RESULT, { "param1": body.to_s,
282
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_DEBUG,
283
+ "#{MessageUtils::SOLUTION}": solution })
284
+ end
285
+ response = conn_mgr.execute(artifactory_aql_url, nil, headers, body, CommonUtils::HTTP_POST, false)
286
+ if !response.nil? && (response.status >= 200 && response.status < 300) && response.headers[CommonUtils::CONTENT_TYPE_HDR] == CommonUtils::CONTENT_TYPE_JSON
287
+ parsed_json = JSON.parse(response.body)
288
+ total_records = parsed_json['range']['total']
289
+ if total_records.positive?
290
+ results = parsed_json['results']
291
+ message = if ConfigHandler.instance.log_config.debug_mode
292
+ JSON.pretty_generate(results)
293
+ else
294
+ total_records
295
+ end
296
+ MessageUtils.instance.log_message(MessageUtils::SOLUTION_VS_LOCKED_FILE_DATA, { "param1": solution.to_s,
297
+ "param2": message,
298
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_INFO,
299
+ "#{MessageUtils::SOLUTION}": solution })
300
+ audit_lock_file_found = true
301
+ end
302
+ end
303
+ audit_lock_file_found
304
+ end
305
+
306
+ def handle_audit_file(solution, tgt_date_str, file_name, status, method)
307
+ status_audit_success = false
308
+ conn_mgr = ConnectionManager.new
309
+ headers = { CommonUtils::CONTENT_TYPE_HDR => CommonUtils::CONTENT_TYPE_JSON }
310
+ body = audit_file_status_body(file_name, status) if CommonUtils::HTTP_PUT == method
311
+ response = conn_mgr.execute("#{audit_repo_target_dir_url("#{solution}/#{tgt_date_str}", false, false, false)}/#{file_name}", nil, headers, body, method, true)
312
+ if !response.nil? && (response.status >= 200 && response.status < 300)
313
+ if CommonUtils::HTTP_PUT == method
314
+ MessageUtils.instance.log_message(MessageUtils::AUDIT_FILE_CREATION_SUCCESS, { "param1": "#{audit_repo_target_dir_url("#{solution}/#{tgt_date_str}", false, true, false)}/#{file_name}",
315
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_INFO,
316
+ "#{MessageUtils::SOLUTION}": solution })
317
+ elsif CommonUtils::HTTP_DELETE == method
318
+ MessageUtils.instance.log_message(MessageUtils::AUDIT_FILE_DELETE_SUCCESS, { "param1": "#{audit_repo_target_dir_url("#{solution}/#{tgt_date_str}", false, true, false)}/#{file_name}",
319
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_INFO,
320
+ "#{MessageUtils::SOLUTION}": solution })
321
+ end
322
+ status_audit_success = true
323
+ else
324
+ if CommonUtils::HTTP_PUT == method
325
+ MessageUtils.instance.log_message(MessageUtils::AUDIT_FILE_CREATION_FAILED_DETAIL, { "param1": "#{audit_repo_target_dir_url("#{solution}/#{tgt_date_str}", false, true, false)}/#{file_name}",
326
+ "param2": response.body.to_s,
327
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_ERROR,
328
+ "#{MessageUtils::SOLUTION}": solution })
329
+ elsif CommonUtils::HTTP_DELETE == method
330
+ MessageUtils.instance.log_message(MessageUtils::AUDIT_FILE_DELETE_FAILED_DETAIL, { "param1": "#{audit_repo_target_dir_url("#{solution}/#{tgt_date_str}", false, true, false)}/#{file_name}",
331
+ "param2": response.body.to_s,
332
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_ERROR,
333
+ "#{MessageUtils::SOLUTION}": solution })
334
+ end
335
+
336
+ end
337
+ status_audit_success
338
+ end
339
+
340
+ def clear_audit_locks(solution, date_in_string)
341
+ locks_cleared = []
342
+ conn_mgr = ConnectionManager.new
343
+ headers = { CommonUtils::CONTENT_TYPE_HDR => CommonUtils::CONTENT_TYPE_TEXT }
344
+ body = audit_aql_locked_files_body(solution, date_in_string)
345
+ response = conn_mgr.execute(artifactory_aql_url, nil, headers, body, CommonUtils::HTTP_POST, false)
346
+ if !response.nil? && (response.status >= 200 && response.status < 300) && response.headers[CommonUtils::CONTENT_TYPE_HDR] == CommonUtils::CONTENT_TYPE_JSON
347
+ parsed_json = JSON.parse(response.body)
348
+ total_records = parsed_json['range']['total']
349
+ if total_records.positive?
350
+ results = parsed_json['results']
351
+ results.each do |log_file_detail|
352
+ created_time = DateTime.parse(log_file_detail['created'])
353
+ diff_minutes = ((DateTime.now - created_time) * 24 * 60).to_i
354
+ if diff_minutes >= ConfigHandler.instance.proc_config.minutes_between_runs
355
+ handle_audit_file(solution, date_in_string, "#{log_file_detail['name']}", CommonUtils::FILE_PROCESSING_LOCK, CommonUtils::HTTP_DELETE)
356
+ locks_cleared.push(log_file_detail['name'])
357
+ end
358
+ end
359
+ end
360
+ end
361
+ MessageUtils.instance.log_message(MessageUtils::LOCKED_AUDIT_FILES_CLEARED_RESULT, { "param1": locks_cleared.to_s,
362
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_DEBUG,
363
+ "#{MessageUtils::SOLUTION}": solution })
364
+ locks_cleared
365
+ end
366
+
367
+ def logs_processed(solution, date_in_string)
368
+ logs_processed = []
369
+ conn_mgr = ConnectionManager.new
370
+ headers = { CommonUtils::CONTENT_TYPE_HDR => CommonUtils::CONTENT_TYPE_TEXT }
371
+ body = audit_aql_body(solution, date_in_string)
372
+ if ConfigHandler.instance.log_config.debug_mode
373
+ MessageUtils.instance.log_message(MessageUtils::PROCESSED_LOGS_AQL_QUERY_RESULT, { "param1": body.to_s,
374
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_DEBUG,
375
+ "#{MessageUtils::SOLUTION}": solution })
376
+ end
377
+ response = conn_mgr.execute(artifactory_aql_url, nil, headers, body, CommonUtils::HTTP_POST, false)
378
+ if !response.nil? && (response.status >= 200 && response.status < 300) && response.headers[CommonUtils::CONTENT_TYPE_HDR] == CommonUtils::CONTENT_TYPE_JSON
379
+ parsed_json = JSON.parse(response.body)
380
+ total_records = parsed_json['range']['total']
381
+ if total_records.positive?
382
+ results = parsed_json['results']
383
+ message = if ConfigHandler.instance.log_config.debug_mode
384
+ JSON.pretty_generate(results)
385
+ else
386
+ total_records
387
+ end
388
+ MessageUtils.instance.log_message(MessageUtils::DATE_VS_PROCESSED_LOGS_DATA, { "param1": date_in_string.to_s,
389
+ "param2": message,
390
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_INFO,
391
+ "#{MessageUtils::SOLUTION}": solution })
392
+ results.each do |log_file_detail|
393
+ logs_processed.push(log_file_detail['name'].chomp(CommonUtils::STATUS_FILE_SUFFIX))
394
+ end
395
+ end
396
+ end
397
+ logs_processed
398
+ end
399
+
400
+ def logs_to_process_hash(solution, date_in_string)
401
+ logs_processed = logs_processed(solution, date_in_string)
402
+ logs_to_process = {}
403
+ conn_mgr = ConnectionManager.new
404
+ body = artifactory_aql_body(solution, date_in_string)
405
+ headers = { CommonUtils::CONTENT_TYPE_HDR => CommonUtils::CONTENT_TYPE_TEXT }
406
+ if ConfigHandler.instance.log_config.debug_mode
407
+ MessageUtils.instance.log_message(MessageUtils::UNPROCESSED_LOGS_AQL_QUERY_RESULT, { "param1": body.to_s,
408
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_DEBUG,
409
+ "#{MessageUtils::SOLUTION}": solution })
410
+ end
411
+ response = conn_mgr.execute(artifactory_aql_url, nil, headers, body, CommonUtils::HTTP_POST, false)
412
+ if !response.nil? && (response.status >= 200 && response.status < 300) && response.headers[CommonUtils::CONTENT_TYPE_HDR] == CommonUtils::CONTENT_TYPE_JSON
413
+ parsed_json = JSON.parse(response.body)
414
+ total_records = parsed_json['range']['total']
415
+ if total_records.positive?
416
+ results = parsed_json['results']
417
+ message = if ConfigHandler.instance.log_config.debug_mode
418
+ JSON.pretty_generate(results)
419
+ else
420
+ total_records
421
+ end
422
+ MessageUtils.instance.log_message(MessageUtils::DATE_VS_LOGS_DATA, { "param1": date_in_string.to_s,
423
+ "param2": message,
424
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_INFO,
425
+ "#{MessageUtils::SOLUTION}": solution })
426
+ results.each do |log_file_detail|
427
+ if logs_processed.include? log_file_detail['name']
428
+ MessageUtils.instance.log_message(MessageUtils::LOG_PROCESSED_EXCLUDE, { "param1": log_file_detail['name'].to_s,
429
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_INFO,
430
+ "#{MessageUtils::SOLUTION}": solution })
431
+ elsif ConfigHandler.instance.log_config.log_types_enabled.any? { |log_type| log_file_detail['name'].include? log_type }
432
+ MessageUtils.instance.log_message(MessageUtils::LOG_NOT_PROCESSED_INCLUDE, { "param1": log_file_detail['name'].to_s,
433
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_INFO,
434
+ "#{MessageUtils::SOLUTION}": solution })
435
+ logs_to_process[log_file_detail['name']] = log_file_detail
436
+ end
437
+ end
438
+ else
439
+ MessageUtils.instance.log_message(MessageUtils::NO_LOGS_FOR_DATE, { "param1": date_in_string.to_s,
440
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_INFO,
441
+ "#{MessageUtils::SOLUTION}": solution })
442
+ end
443
+ end
444
+ logs_to_process
445
+ end
446
+ # RESOURCE RELATED - END
447
+
448
+ def download_and_extract_log(solution, date, target_path, file_name, relative_url)
449
+ conn_mgr = ConnectionManager.new
450
+ headers = {
451
+ CommonUtils::CONTENT_TYPE_HDR => CommonUtils::CONTENT_TYPE_TEXT,
452
+ 'Accept-Encoding' => 'gzip, deflate',
453
+ 'Accept' => 'text/plain,text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9'
454
+ }
455
+
456
+ if !audit_lock_file(solution, file_name)
457
+ handle_audit_file(solution, date, "#{file_name}#{CommonUtils::LOCK_FILE_SUFFIX}", CommonUtils::FILE_PROCESSING_LOCK, CommonUtils::HTTP_PUT)
458
+ response = conn_mgr.execute(relative_url, nil, headers, nil, CommonUtils::HTTP_GET, true)
459
+ if !response.nil? && response.status >= 200 && response.status < 300
460
+ log_file_name = file_name.chomp('.gz')
461
+ if ConfigHandler.instance.proc_config.write_logs_by_type
462
+ ConfigHandler.instance.log_config.log_types_enabled.each do |log_type|
463
+ log_file_name = "#{log_type}.log" if log_file_name.include? log_type
464
+ end
465
+ end
466
+ MessageUtils.instance.log_message(MessageUtils::DOWNLOAD_FILE_AND_EXTRACT, { "param1": relative_url.to_s,
467
+ "param2": "#{target_path}/#{solution}/#{log_file_name}",
468
+ "#{MessageUtils::LOG_LEVEL}": CommonUtils::LOG_INFO,
469
+ "#{MessageUtils::SOLUTION}": solution })
470
+ unzip = Unzip.new
471
+ unzip.extract(solution, relative_url, target_path, log_file_name, response.body)
472
+ handle_audit_file(solution, date, "#{file_name}#{CommonUtils::LOCK_FILE_SUFFIX}", CommonUtils::FILE_PROCESSING_LOCK, CommonUtils::HTTP_DELETE)
473
+ handle_audit_file(solution, date, "#{file_name}#{CommonUtils::STATUS_FILE_SUFFIX}", CommonUtils::FILE_PROCESSING_SUCCESS, CommonUtils::HTTP_PUT)
474
+ end
475
+ end
476
+ end
477
+ end
478
+ end
479
+ end
480
+ end
481
+
@@ -0,0 +1,123 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-04/schema#",
3
+ "type": "object",
4
+ "properties": {
5
+ "connection": {
6
+ "type": "object",
7
+ "properties": {
8
+ "jpd_url": {
9
+ "type": "string"
10
+ },
11
+ "end_point_base": {
12
+ "type": "string"
13
+ },
14
+ "username": {
15
+ "type": "string"
16
+ },
17
+ "access_token": {
18
+ "type": "string"
19
+ },
20
+ "open_timeout_in_secs": {
21
+ "type": "integer"
22
+ },
23
+ "read_timeout_in_secs": {
24
+ "type": "integer"
25
+ }
26
+ },
27
+ "required": [
28
+ "jpd_url",
29
+ "end_point_base",
30
+ "username",
31
+ "access_token"
32
+ ]
33
+ },
34
+ "log": {
35
+ "type": "object",
36
+ "properties": {
37
+ "log_ship_config": {
38
+ "type": "string"
39
+ },
40
+ "solutions_enabled": {
41
+ "type": "array",
42
+ "items": [
43
+ {
44
+ "type": "string"
45
+ },
46
+ {
47
+ "type": "string"
48
+ }
49
+ ]
50
+ },
51
+ "log_types_enabled": {
52
+ "type": "array",
53
+ "items": [
54
+ {
55
+ "type": "string"
56
+ },
57
+ {
58
+ "type": "string"
59
+ }
60
+ ]
61
+ },
62
+ "uri_date_pattern": {
63
+ "type": "string"
64
+ },
65
+ "audit_repo": {
66
+ "type": "string"
67
+ },
68
+ "log_repo": {
69
+ "type": "string"
70
+ },
71
+ "debug_mode": {
72
+ "type": "boolean"
73
+ },
74
+ "target_log_path": {
75
+ "type": "string"
76
+ },
77
+ "print_with_utc": {
78
+ "type": "boolean"
79
+ },
80
+ "log_file_retention_days": {
81
+ "type": "integer"
82
+ }
83
+ },
84
+ "required": [
85
+ "log_ship_config",
86
+ "solutions_enabled",
87
+ "log_types_enabled",
88
+ "uri_date_pattern",
89
+ "audit_repo",
90
+ "log_repo",
91
+ "target_log_path"
92
+ ]
93
+ },
94
+ "process": {
95
+ "type": "object",
96
+ "properties": {
97
+ "parallel_process": {
98
+ "type": "integer"
99
+ },
100
+ "parallel_downloads": {
101
+ "type": "integer"
102
+ },
103
+ "historical_log_days": {
104
+ "type": "integer"
105
+ },
106
+ "write_logs_by_type": {
107
+ "type": "boolean"
108
+ },
109
+ "minutes_between_runs": {
110
+ "type": "integer"
111
+ }
112
+ },
113
+ "required": [
114
+ "write_logs_by_type"
115
+ ]
116
+ }
117
+ },
118
+ "required": [
119
+ "connection",
120
+ "log",
121
+ "process"
122
+ ]
123
+ }
@@ -0,0 +1,27 @@
1
+ connection:
2
+ jpd_url: "<saas_jpd_url>"
3
+ end_point_base: "artifactory"
4
+ username: "<admin_user>"
5
+ access_token: "<admin_access_token>"
6
+ open_timeout_in_secs: 20
7
+ read_timeout_in_secs: 60
8
+ log:
9
+ log_ship_config: "access/api/v1/logshipping/config"
10
+ solutions_enabled: ["artifactory", "xray"]
11
+ log_types_enabled: ["access-request", "router-request"]
12
+ uri_date_pattern: "%Y-%m-%d"
13
+ audit_repo: "artifactory/jfrog-logs-audit"
14
+ log_repo: "artifactory/jfrog-logs"
15
+ debug_mode: false
16
+ target_log_path: "<path_to_extract_logs_for_artifactory>"
17
+ print_with_utc: false
18
+ log_file_retention_days: 5
19
+ process:
20
+ parallel_process: 2
21
+ parallel_downloads: 5
22
+ historical_log_days: 2
23
+ write_logs_by_type: false
24
+ minutes_between_runs: 180
25
+
26
+
27
+