11# Copyright Spack Project Developers. See COPYRIGHT file for details.
22#
33# SPDX-License-Identifier: (Apache-2.0 OR MIT)
4- import codecs
54import copy
65import json
76import os
87import re
9- import ssl
108import sys
119import time
1210from collections import deque
1311from enum import Enum
1412from typing import Dict , Generator , List , Optional , Set , Tuple
1513from urllib .parse import quote , urlencode , urlparse
16- from urllib .request import HTTPHandler , HTTPSHandler , Request , build_opener
14+ from urllib .request import Request
1715
1816import llnl .util .filesystem as fs
1917import llnl .util .tty as tty
20- from llnl .util .lang import Singleton , memoized
18+ from llnl .util .lang import memoized
2119
2220import spack .binary_distribution as bindist
2321import spack .config as cfg
3533from spack .reporters .cdash import SPACK_CDASH_TIMEOUT
3634from spack .reporters .cdash import build_stamp as cdash_build_stamp
3735
38-
39- def _urlopen ():
40- error_handler = web_util .SpackHTTPDefaultErrorHandler ()
41-
42- # One opener with HTTPS ssl enabled
43- with_ssl = build_opener (
44- HTTPHandler (), HTTPSHandler (context = web_util .ssl_create_default_context ()), error_handler
45- )
46-
47- # One opener with HTTPS ssl disabled
48- without_ssl = build_opener (
49- HTTPHandler (), HTTPSHandler (context = ssl ._create_unverified_context ()), error_handler
50- )
51-
52- # And dynamically dispatch based on the config:verify_ssl.
53- def dispatch_open (fullurl , data = None , timeout = None , verify_ssl = True ):
54- opener = with_ssl if verify_ssl else without_ssl
55- timeout = timeout or cfg .get ("config:connect_timeout" , 1 )
56- return opener .open (fullurl , data , timeout )
57-
58- return dispatch_open
59-
60-
6136IS_WINDOWS = sys .platform == "win32"
6237SPACK_RESERVED_TAGS = ["public" , "protected" , "notary" ]
63- _dyn_mapping_urlopener = Singleton (_urlopen )
38+
39+ # this exists purely for testing purposes
40+ _urlopen = web_util .urlopen
6441
6542
6643def copy_files_to_artifacts (src , artifacts_dir ):
@@ -279,26 +256,25 @@ def copy_test_results(self, source, dest):
279256 reports = fs .join_path (source , "*_Test*.xml" )
280257 copy_files_to_artifacts (reports , dest )
281258
282- def create_buildgroup (self , opener , headers , url , group_name , group_type ):
259+ def create_buildgroup (self , headers , url , group_name , group_type ):
283260 data = {"newbuildgroup" : group_name , "project" : self .project , "type" : group_type }
284261
285262 enc_data = json .dumps (data ).encode ("utf-8" )
286263
287264 request = Request (url , data = enc_data , headers = headers )
288265
289- response = opener .open (request , timeout = SPACK_CDASH_TIMEOUT )
290- response_code = response .getcode ()
291-
292- if response_code not in [200 , 201 ]:
293- msg = f"Creating buildgroup failed (response code = { response_code } )"
294- tty .warn (msg )
266+ try :
267+ response_text = _urlopen (request , timeout = SPACK_CDASH_TIMEOUT ).read ()
268+ except OSError as e :
269+ tty .warn (f"Failed to create CDash buildgroup: { e } " )
295270 return None
296271
297- response_text = response .read ()
298- response_json = json .loads (response_text )
299- build_group_id = response_json ["id" ]
300-
301- return build_group_id
272+ try :
273+ response_json = json .loads (response_text )
274+ return response_json ["id" ]
275+ except (json .JSONDecodeError , KeyError ) as e :
276+ tty .warn (f"Failed to parse CDash response: { e } " )
277+ return None
302278
303279 def populate_buildgroup (self , job_names ):
304280 url = f"{ self .url } /api/v1/buildgroup.php"
@@ -308,16 +284,11 @@ def populate_buildgroup(self, job_names):
308284 "Content-Type" : "application/json" ,
309285 }
310286
311- opener = build_opener (HTTPHandler )
312-
313- parent_group_id = self .create_buildgroup (opener , headers , url , self .build_group , "Daily" )
314- group_id = self .create_buildgroup (
315- opener , headers , url , f"Latest { self .build_group } " , "Latest"
316- )
287+ parent_group_id = self .create_buildgroup (headers , url , self .build_group , "Daily" )
288+ group_id = self .create_buildgroup (headers , url , f"Latest { self .build_group } " , "Latest" )
317289
318290 if not parent_group_id or not group_id :
319- msg = f"Failed to create or retrieve buildgroups for { self .build_group } "
320- tty .warn (msg )
291+ tty .warn (f"Failed to create or retrieve buildgroups for { self .build_group } " )
321292 return
322293
323294 data = {
@@ -329,15 +300,12 @@ def populate_buildgroup(self, job_names):
329300
330301 enc_data = json .dumps (data ).encode ("utf-8" )
331302
332- request = Request (url , data = enc_data , headers = headers )
333- request .get_method = lambda : "PUT"
303+ request = Request (url , data = enc_data , headers = headers , method = "PUT" )
334304
335- response = opener .open (request , timeout = SPACK_CDASH_TIMEOUT )
336- response_code = response .getcode ()
337-
338- if response_code != 200 :
339- msg = f"Error response code ({ response_code } ) in populate_buildgroup"
340- tty .warn (msg )
305+ try :
306+ _urlopen (request , timeout = SPACK_CDASH_TIMEOUT )
307+ except OSError as e :
308+ tty .warn (f"Failed to populate CDash buildgroup: { e } " )
341309
342310 def report_skipped (self , spec : spack .spec .Spec , report_dir : str , reason : Optional [str ]):
343311 """Explicitly report skipping testing of a spec (e.g., it's CI
@@ -735,9 +703,6 @@ def _apply_section(dest, src):
735703 for value in header .values ():
736704 value = os .path .expandvars (value )
737705
738- verify_ssl = mapping .get ("verify_ssl" , spack .config .get ("config:verify_ssl" , True ))
739- timeout = mapping .get ("timeout" , spack .config .get ("config:connect_timeout" , 1 ))
740-
741706 required = mapping .get ("require" , [])
742707 allowed = mapping .get ("allow" , [])
743708 ignored = mapping .get ("ignore" , [])
@@ -771,19 +736,15 @@ def job_query(job):
771736 endpoint_url ._replace (query = query ).geturl (), headers = header , method = "GET"
772737 )
773738 try :
774- response = _dyn_mapping_urlopener (
775- request , verify_ssl = verify_ssl , timeout = timeout
776- )
739+ response = _urlopen (request )
740+ config = json .load (response )
777741 except Exception as e :
778742 # For now just ignore any errors from dynamic mapping and continue
779743 # This is still experimental, and failures should not stop CI
780744 # from running normally
781- tty .warn (f"Failed to fetch dynamic mapping for query:\n \t { query } " )
782- tty .warn (f"{ e } " )
745+ tty .warn (f"Failed to fetch dynamic mapping for query:\n \t { query } : { e } " )
783746 continue
784747
785- config = json .load (codecs .getreader ("utf-8" )(response ))
786-
787748 # Strip ignore keys
788749 if ignored :
789750 for key in ignored :
0 commit comments