3131import time
3232import traceback
3333import platform
34+ from pathlib import Path
3435from threading import Event
3536from subprocess import call
3637from itertools import groupby
7273if not os .path .exists (path ):
7374 os .mkdir (path )
7475
76+ _failed_reports = []
77+ _log_artifact_dir = os .environ .get ('INTEGRATION_LOG_ARTIFACT_DIR' , 'integration-test-logs' )
78+ _preserved_file_extensions = ('.conf' , '.log' , '.yaml' , '.yml' )
79+
7580cass_version = None
7681cql_version = None
7782
7883
84+ def record_failed_test_report (report ):
85+ if report .failed :
86+ _failed_reports .append (report )
87+
88+
89+ def preserve_ccm_logs_on_failure ():
90+ if not _failed_reports :
91+ return
92+
93+ ccm_root = Path (path )
94+ if not ccm_root .is_dir ():
95+ return
96+
97+ destination = Path (_log_artifact_dir ).resolve ()
98+ ccm_destination = destination / 'ccm'
99+ ccm_destination .mkdir (parents = True , exist_ok = True )
100+
101+ with (destination / 'failed-tests.txt' ).open ('w' ) as failed_tests :
102+ for report in _failed_reports :
103+ failed_tests .write ('%s %s\n ' % (report .when , report .nodeid ))
104+
105+ # Preserve CCM logs/configs before cleanup removes the cluster directories.
106+ for source_file in ccm_root .rglob ('*' ):
107+ if not source_file .is_file ():
108+ continue
109+
110+ rel_file = source_file .relative_to (ccm_root )
111+ preserve_all = bool ({'conf' , 'logs' }.intersection (rel_file .parts ))
112+ if not preserve_all and not source_file .name .endswith (_preserved_file_extensions ):
113+ continue
114+
115+ destination_file = ccm_destination / rel_file
116+ destination_file .parent .mkdir (parents = True , exist_ok = True )
117+ shutil .copy2 (source_file , destination_file )
118+
119+ log .info ("Preserved ccm logs for failed tests under %s" , destination )
120+
121+
79122def get_server_versions ():
80123 """
81124 Probe system.local table to determine Cassandra and CQL version.
@@ -383,6 +426,7 @@ def remove_cluster():
383426 tries = 0
384427 while tries < 100 :
385428 try :
429+ preserve_ccm_logs_on_failure ()
386430 CCM_CLUSTER .remove ()
387431 CCM_CLUSTER = None
388432 return
@@ -455,6 +499,7 @@ def use_cluster(cluster_name, nodes, ipformat=None, start=True, workloads=None,
455499 try :
456500 CCM_CLUSTER = CCMClusterFactory .load (path , cluster_name )
457501 log .debug ("Found existing CCM cluster, {0}; clearing." .format (cluster_name ))
502+ preserve_ccm_logs_on_failure ()
458503 CCM_CLUSTER .clear ()
459504 CCM_CLUSTER .set_install_dir (** ccm_options )
460505 CCM_CLUSTER .set_configuration_options (configuration_options )
@@ -471,6 +516,7 @@ def use_cluster(cluster_name, nodes, ipformat=None, start=True, workloads=None,
471516 # Make sure we cleanup old cluster dir if it exists
472517 cluster_path = os .path .join (path , cluster_name )
473518 if os .path .exists (cluster_path ):
519+ preserve_ccm_logs_on_failure ()
474520 shutil .rmtree (cluster_path )
475521
476522 if SCYLLA_VERSION :
@@ -553,6 +599,7 @@ def teardown_package():
553599 return
554600 # when multiple modules are run explicitly, this runs between them
555601 # need to make sure CCM_CLUSTER is properly cleared for that case
602+ preserve_ccm_logs_on_failure ()
556603 remove_cluster ()
557604 for cluster_name in [CLUSTER_NAME , MULTIDC_CLUSTER_NAME ]:
558605 try :
0 commit comments