Skip to content

Commit 4e1aa42

Browse files
author
Glenn Snyder
committed
fixing some bugs and adding sample to parse detect log to find and use status.json for moniting scans until they are complete
1 parent b947283 commit 4e1aa42

File tree

2 files changed

+103
-10
lines changed

2 files changed

+103
-10
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#!/usr/bin/env python
2+
3+
'''
4+
Created on Sep 2, 2020
5+
6+
@author: gsnyder
7+
8+
Parse the Synopsys Detect log to get the status.json file emitted and use status.json to monitor
9+
the scans (codelocations) and wait for the scan processing to complete
10+
'''
11+
12+
import argparse
13+
import arrow
14+
import json
15+
import logging
16+
import re
17+
import sys
18+
import time
19+
from tzlocal import get_localzone # pip install tzlocal
20+
21+
from blackduck.HubRestApi import HubInstance, object_id
22+
23+
# Ensure your PYTHONPATH includes the folder where this class is defined
24+
from wait_for_scan_results import ScanMonitor
25+
26+
27+
parser = argparse.ArgumentParser("Parse the Synopsys Detect log, load status.json, and wait for all scan processing to complete")
28+
parser.add_argument("-d", "--detect_log", help="By default, this script will read the detect log from stdin, but you can alternatively supply a detect log filename")
29+
# parser.add_argument('-m', '--max_checks', type=int, default=10, help="Set the maximum number of checks before quitting")
30+
# parser.add_argument('-t', '--time_between_checks', type=int, default=5, help="Set the number of seconds to wait in-between checks")
31+
# parser.add_argument('-s', '--snippet_scan', action='store_true', help="Select this option if you want to wait for a snippet scan to complete along with it's corresponding component scan.")
32+
args = parser.parse_args()
33+
34+
logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s', stream=sys.stderr, level=logging.DEBUG)
35+
logging.getLogger("requests").setLevel(logging.WARNING)
36+
logging.getLogger("urllib3").setLevel(logging.WARNING)
37+
38+
if args.detect_log:
39+
detect_log = open(args.detect_log, 'r')
40+
else:
41+
detect_log = sys.stdin
42+
43+
snippet_scan = False
44+
status_file_path = None
45+
start_time = None
46+
47+
for line in detect_log.readlines():
48+
if not start_time:
49+
start_time_re = re.search("(.*) INFO .*", line)
50+
if start_time_re:
51+
start_time = arrow.get(start_time_re[1], tzinfo=get_localzone())
52+
logging.debug(f"Found detect start time {start_time}")
53+
54+
cleanup_prop = re.search(".*detect.cleanup = (true|false).*", line)
55+
if cleanup_prop:
56+
if cleanup_prop[1] == 'true':
57+
logging.error("You must use --detect.cleanup=false to preserve the status.json file, exiting")
58+
sys.exit(1)
59+
60+
snippet_matching_re = re.search(".*detect.blackduck.signature.scanner.snippet.matching = (.*)", line)
61+
if snippet_matching_re:
62+
if 'SNIPPET' in snippet_matching_re[1]:
63+
snippet_scan = True
64+
logging.debug("Found snippet scanning option")
65+
66+
status_file_re = re.search(".*Creating status file: (.*)", line)
67+
if status_file_re:
68+
status_file_path = status_file_re[1]
69+
logging.debug(f"Found status.json path {status_file_path}")
70+
71+
assert start_time, "Hmm, not sure how that happened but we need a start time"
72+
73+
logging.debug(f"detect start time: {start_time}")
74+
logging.debug(f"snippet_scan: {snippet_scan}")
75+
logging.debug(f"status.json path: {status_file_path}")
76+
77+
hub = HubInstance()
78+
79+
with open(status_file_path, 'r') as status_file:
80+
status_info = json.load(status_file)
81+
82+
# Monitoring status serially cause it's simpler (i.e. than spawning multiple threads and waiting for them)
83+
for code_location in status_info['codeLocations']:
84+
logging.debug(f"Waiting for scan to finish at scan/code location {code_location['codeLocationName']}")
85+
scan_monitor = ScanMonitor(
86+
hub,
87+
start_time=start_time,
88+
scan_location_name=code_location['codeLocationName'],
89+
snippet_scan=snippet_scan)
90+
scan_monitor.wait_for_scan_completion()
91+
92+

examples/wait_for_scan_results.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
import argparse
1313
import arrow
14-
from datetime import datetime
1514
import json
1615
import logging
1716
import sys
@@ -20,25 +19,26 @@
2019
from blackduck.HubRestApi import HubInstance, object_id
2120

2221
class ScanMonitor(object):
23-
def __init__(self, hub, scan_location_name, max_checks=10, check_delay=5, snippet_scan=False):
22+
def __init__(self, hub, scan_location_name, max_checks=10, check_delay=5, snippet_scan=False, start_time = None):
2423
self.hub = hub
2524
self.scan_location_name = scan_location_name
2625
self.max_checks = max_checks
2726
self.check_delay = check_delay
2827
self.snippet_scan = snippet_scan
28+
if not start_time:
29+
self.start_time = arrow.now()
30+
else:
31+
self.start_time = start_time
2932

3033
def wait_for_scan_completion(self):
31-
now = arrow.now()
32-
33-
scan_locations = self.hub.get_codelocations(parameters={'q':f'name:{args.scan_location_name}'}).get('items', [])
34+
scan_locations = self.hub.get_codelocations(parameters={'q':f'name:{self.scan_location_name}'}).get('items', [])
3435

3536
scan_location = scan_locations[0]
3637

3738
remaining_checks = self.max_checks
3839
scans_url = self.hub.get_link(scan_location, "scans")
39-
latest_scan_url = self.hub.get_link(scan_location, "latest-scan")
4040

41-
if args.snippet_scan:
41+
if self.snippet_scan:
4242
logging.debug("Looking for snippet scan which means there will be 2 expected scans")
4343
number_expected_newer_scans = 2
4444
else:
@@ -48,7 +48,7 @@ def wait_for_scan_completion(self):
4848
while remaining_checks > 0:
4949
scans = self.hub.execute_get(scans_url).json().get('items', [])
5050

51-
newer_scans = list(filter(lambda s: arrow.get(s['createdAt']) > now, scans))
51+
newer_scans = list(filter(lambda s: arrow.get(s['createdAt']) > self.start_time, scans))
5252
logging.debug(f"Found {len(newer_scans)} newer scans")
5353

5454
expected_scans_seen = len(newer_scans) == number_expected_newer_scans
@@ -59,9 +59,10 @@ def wait_for_scan_completion(self):
5959
break
6060
else:
6161
remaining_checks -= 1
62-
logging.debug(f"Sleeping for {args.time_between_checks} seconds before checking again. {remaining_checks} remaining")
63-
time.sleep(args.time_between_checks)
62+
logging.debug(f"Sleeping for {self.check_delay} seconds before checking again. {remaining_checks} remaining")
63+
time.sleep(self.check_delay)
6464

65+
# TODO: Check for success/failure and return appropriate exit status?
6566

6667
if __name__ == "__main__":
6768
parser = argparse.ArgumentParser("Wait for scan processing to complete for a given code (scan) location/name")

0 commit comments

Comments
 (0)