22import json
33import logging
44import os
5+ import sys
56import os .path
67import shlex
78import shutil
1415
1516def _find_sonobuoy ():
1617 """find sonobuoy in PATH, but also in a fixed location at ~/.local/bin to simplify use with Ansible"""
17- result = shutil .which (' sonobuoy' )
18+ result = shutil .which (" sonobuoy" )
1819 if result :
1920 return result
20- logger .debug (' sonobuoy not in PATH, trying $HOME/.local/bin' )
21- result = os .path .join (os .path .expanduser ('~' ), ' .local' , ' bin' , ' sonobuoy' )
21+ logger .debug (" sonobuoy not in PATH, trying $HOME/.local/bin" )
22+ result = os .path .join (os .path .expanduser ("~" ), " .local" , " bin" , " sonobuoy" )
2223 if os .path .exists (result ):
2324 return result
24- logger .debug (' sonobuoy executable not found; expect errors' )
25+ logger .debug (" sonobuoy executable not found; expect errors" )
2526
2627
2728def _fmt_result (counter ):
28- return ', ' .join (f"{ counter .get (key , 0 )} { key } " for key in ('passed' , 'failed' , 'skipped' ))
29+ return ", " .join (
30+ f"{ counter .get (key , 0 )} { key } " for key in ("passed" , "failed" , "skipped" )
31+ )
2932
3033
3134class SonobuoyHandler :
@@ -69,20 +72,10 @@ def _sonobuoy_run(self):
6972 def _sonobuoy_delete (self ):
7073 self ._invoke_sonobuoy ("delete" , "--wait" )
7174
72- def _sonobuoy_status_result (self ):
73- process = self ._invoke_sonobuoy ("status" , "--json" , capture_output = True )
74- json_data = json .loads (process .stdout )
75- counter = Counter ()
76- for entry in json_data ["plugins" ]:
77- logger .debug (f"plugin { entry ['plugin' ]} : { _fmt_result (entry ['result-counts' ])} " )
78- for key , value in entry ["result-counts" ].items ():
79- counter [key ] += value
80- return counter
81-
8275 def _eval_result (self , counter ):
8376 """evaluate test results and return return code"""
8477 result_message = f"sonobuoy reports { _fmt_result (counter )} "
85- if counter [' failed' ]:
78+ if counter [" failed" ]:
8679 logger .error (result_message )
8780 return 3
8881 logger .info (result_message )
@@ -95,34 +88,21 @@ def _preflight_check(self):
9588 if not self .sonobuoy :
9689 raise RuntimeError ("sonobuoy executable not found; is it in PATH?" )
9790
98- def _sonobuoy_retrieve_result (self , plugin = ' e2e' ):
91+ def _sonobuoy_retrieve_result (self , plugin = " e2e" ):
9992 """
10093 Invoke sonobuoy to retrieve results and to store them in a subdirectory of
10194 the working directory. Analyze the results yaml file for given `plugin` and
102- log each failure as ERROR. Return summary dict like `_sonobuoy_status_result` .
95+ log each failure as ERROR. Return summary dict.
10396 """
10497 logger .debug (f"retrieving results to { self .result_dir_name } " )
10598 result_dir = os .path .join (self .working_directory , self .result_dir_name )
10699 os .makedirs (result_dir , exist_ok = True )
107100
108101 self ._invoke_sonobuoy ("retrieve" , "-x" , result_dir )
109- yaml_path = os .path .join (result_dir , ' plugins' , plugin , ' sonobuoy_results.yaml' )
102+ yaml_path = os .path .join (result_dir , " plugins" , plugin , " sonobuoy_results.yaml" )
110103 logger .debug (f"parsing results from { yaml_path } " )
111- with open (yaml_path , "r" ) as fileobj :
112- result_obj = yaml .load (fileobj .read (), yaml .SafeLoader )
113- counter = Counter ()
114- for item1 in result_obj .get ('items' , ()):
115- # file ...
116- for item2 in item1 .get ('items' , ()):
117- # suite ...
118- for item in item2 .get ('items' , ()):
119- # testcase ... or so
120- status = item .get ('status' , 'skipped' )
121- counter [status ] += 1
122- if status == 'failed' :
123- logger .error (f"FAILED: { item ['name' ]} " ) # <-- this is why this method exists!
124- logger .info (f"{ plugin } results: { _fmt_result (counter )} " )
125- return counter
104+
105+ return sonobuoy_parse_result (plugin , yaml_path )
126106
127107 def run (self ):
128108 """
@@ -132,16 +112,51 @@ def run(self):
132112 self ._preflight_check ()
133113 try :
134114 self ._sonobuoy_run ()
135- return_code = self ._eval_result (self ._sonobuoy_status_result ())
115+ counter = self ._sonobuoy_retrieve_result ()
116+ return_code = self ._eval_result (counter )
136117 print (self .check_name + ": " + ("PASS" , "FAIL" )[min (1 , return_code )])
137- try :
138- self ._sonobuoy_retrieve_result ()
139- except Exception :
140- # swallow exception for the time being
141- logger .debug ('problem retrieving results' , exc_info = True )
142118 return return_code
143119 except BaseException :
144120 logger .exception ("something went wrong" )
145121 return 112
146122 finally :
147123 self ._sonobuoy_delete ()
124+
125+
126+ def sonobuoy_parse_result (plugin , sonobuoy_results_yaml_path ):
127+ with open (sonobuoy_results_yaml_path , "r" ) as fileobj :
128+ result_obj = yaml .load (fileobj .read (), yaml .SafeLoader )
129+ counter = Counter ()
130+ for item1 in result_obj .get ("items" , ()):
131+ # file ...
132+ for item2 in item1 .get ("items" , ()):
133+ # suite ...
134+ for item in item2 .get ("items" , ()):
135+ # testcase ... or so
136+ status = item .get ("status" , "skipped" )
137+ counter [status ] += 1
138+ if status == "failed" :
139+ logger .error (f"FAILED: { item ['name' ]} " )
140+ logger .info (f"{ plugin } results: { _fmt_result (counter )} " )
141+ return counter
142+
143+
144+ def usage ():
145+ print (
146+ f"""{ sys .argv [0 ]} path-to/sonobuoy_results.yaml
147+ Read sonobuoy_results.yaml and print the results.
148+ """
149+ )
150+ sys .exit (3 )
151+
152+
153+ if __name__ == "__main__" :
154+ if len (sys .argv ) < 2 :
155+ usage ()
156+ sonobuoy_results_yaml_path = sys .argv [1 ]
157+ if not os .path .exists (sonobuoy_results_yaml_path ):
158+ print (f"{ sonobuoy_results_yaml_path } does not exist" )
159+ usage ()
160+ counter = sonobuoy_parse_result ("" , sys .argv [1 ])
161+ for key , value in counter .items ():
162+ print (f"{ key } : { value } " )
0 commit comments