@@ -448,6 +448,39 @@ def start_cluster(
448448 # Copy TLS certificates back to local machine if using defaults
449449 if tls and not (tls_cert_file or tls_key_file or tls_ca_cert_file ):
450450 logging .info ("Copying generated TLS certificates from remote..." )
451+
452+ # Copy and verify certificates
453+ local_cert_files = {
454+ "ca.crt" : "ca_cert_local.pem" ,
455+ "server.crt" : "server_cert_local.pem" ,
456+ "server.key" : "server_key_local.pem"
457+ }
458+
459+ for remote_name , local_name in local_cert_files .items ():
460+ remote_path = f"{ self .remote_repo_path } /utils/tls_crts/{ remote_name } "
461+ if self ._copy_file_from_remote (remote_path , local_name ):
462+ logging .info (f"Copied { remote_name } to { local_name } " )
463+
464+ # Print certificate content for debugging
465+ try :
466+ with open (local_name , 'rb' ) as f :
467+ cert_content = f .read ()
468+ logging .info (f"Certificate { remote_name } length: { len (cert_content )} bytes" )
469+ logging .info (f"Certificate { remote_name } first 100 bytes: { cert_content [:100 ]} " )
470+
471+ # Verify it's valid PEM
472+ if b'-----BEGIN' in cert_content and b'-----END' in cert_content :
473+ logging .info (f"Certificate { remote_name } appears to be valid PEM format" )
474+ else :
475+ logging .warning (f"Certificate { remote_name } does NOT appear to be valid PEM format" )
476+
477+ except Exception as e :
478+ logging .error (f"Failed to read copied certificate { local_name } : { e } " )
479+ else :
480+ logging .error (f"Failed to copy { remote_name } " )
481+
482+ # Test certificate on Linux server side
483+ self .test_certificates_on_server (endpoints )
451484
452485 # Create local tls_crts directory
453486 import os
@@ -901,6 +934,78 @@ def _copy_file_from_remote(self, remote_path: str, local_path: str) -> bool:
901934 return False
902935
903936
937+ def test_certificates_on_server (self , endpoints : List [str ]) -> None :
938+ """Test certificates entirely on the Linux server side"""
939+ if not endpoints :
940+ return
941+
942+ logging .info ("=== SERVER-SIDE CERTIFICATE TEST ===" )
943+
944+ # Test with valkey-cli on server
945+ first_endpoint = endpoints [0 ]
946+ host , port = first_endpoint .split (':' )
947+
948+ # Test basic TLS connection
949+ test_cmd = f"cd { self .remote_repo_path } /utils && export PATH={ self .engine_path } /src:$PATH && echo 'PING' | valkey-cli -h { host } -p { port } --tls --cert tls_crts/server.crt --key tls_crts/server.key --cacert tls_crts/ca.crt"
950+ returncode , stdout , stderr = self ._execute_remote_command (test_cmd , timeout = 10 )
951+
952+ if returncode == 0 and 'PONG' in stdout :
953+ logging .info ("SUCCESS - Server-side valkey-cli TLS connection works" )
954+ else :
955+ logging .warning (f"FAILED - Server-side valkey-cli TLS connection failed: { stderr } " )
956+
957+ # Print certificate details on server
958+ cert_info_cmd = f"cd { self .remote_repo_path } /utils && openssl x509 -in tls_crts/ca.crt -text -noout | head -20"
959+ returncode , stdout , stderr = self ._execute_remote_command (cert_info_cmd , timeout = 5 )
960+
961+ if returncode == 0 :
962+ logging .info ("Server certificate info:" )
963+ for line in stdout .split ('\n ' )[:10 ]: # First 10 lines
964+ if line .strip ():
965+ logging .info (f" { line } " )
966+
967+ # Test with a simple Rust program on server
968+ rust_test_program = '''
969+ use std::fs;
970+ use std::process::Command;
971+
972+ fn main() {
973+ println!("Testing certificate files on server...");
974+
975+ let cert_files = ["tls_crts/ca.crt", "tls_crts/server.crt", "tls_crts/server.key"];
976+
977+ for file in &cert_files {
978+ match fs::read(file) {
979+ Ok(content) => {
980+ println!("File {}: {} bytes", file, content.len());
981+ println!("First 50 bytes: {:?}", content.iter().take(50).collect::<Vec<_>>());
982+ }
983+ Err(e) => println!("Failed to read {}: {}", file, e),
984+ }
985+ }
986+ }
987+ '''
988+
989+ # Write and run the test program on server
990+ write_test_cmd = f"cd { self .remote_repo_path } /utils && cat > cert_test.rs << 'EOF'\n { rust_test_program } \n EOF"
991+ self ._execute_remote_command (write_test_cmd , timeout = 5 )
992+
993+ compile_cmd = f"cd { self .remote_repo_path } /utils && rustc cert_test.rs -o cert_test"
994+ returncode , stdout , stderr = self ._execute_remote_command (compile_cmd , timeout = 10 )
995+
996+ if returncode == 0 :
997+ run_cmd = f"cd { self .remote_repo_path } /utils && ./cert_test"
998+ returncode , stdout , stderr = self ._execute_remote_command (run_cmd , timeout = 5 )
999+
1000+ if returncode == 0 :
1001+ logging .info ("Server-side certificate test output:" )
1002+ for line in stdout .split ('\n ' ):
1003+ if line .strip ():
1004+ logging .info (f" { line } " )
1005+
1006+ logging .info ("=== END SERVER-SIDE CERTIFICATE TEST ===" )
1007+
1008+
9041009def main ():
9051010 logfile = "./cluster_manager.log"
9061011 init_logger (logfile )
0 commit comments