@@ -386,7 +386,7 @@ def connect(self, database='', user='', passwd='', host='', port='',
386386 if port or host :
387387 socket = ''
388388 else :
389- socket = socket or cnf ['socket' ]
389+ socket = socket or cnf ['socket' ] or guess_socket_location ()
390390 user = user or cnf ['user' ] or os .getenv ('USER' )
391391 host = host or cnf ['host' ]
392392 port = port or cnf ['port' ]
@@ -430,27 +430,13 @@ def _connect():
430430 else :
431431 raise e
432432
433- def _fallback_to_tcp_ip ():
434- self .echo (
435- 'Retrying over TCP/IP' , err = True )
436-
437- # Else fall back to TCP/IP localhost
438- nonlocal socket , host , port
439- socket = ""
440- host = 'localhost'
441- port = 3306
442- _connect ()
443-
444433 try :
445- if (host is None ) and not WIN :
446- # Try a sensible default socket first (simplifies auth)
447- # If we get a connection error, try tcp/ip localhost
434+ if not WIN and socket :
435+ socket_owner = getpwuid (os .stat (socket ).st_uid ).pw_name
436+ self .echo (
437+ f"Connecting to socket { socket } , owned by user { socket_owner } " )
448438 try :
449- socket = socket or guess_socket_location ()
450439 _connect ()
451- except FileNotFoundError :
452- self .echo ('Failed to find socket file at default locations' )
453- _fallback_to_tcp_ip ()
454440 except OperationalError as e :
455441 # These are "Can't open socket" and 2x "Can't connect"
456442 if [code for code in (2001 , 2002 , 2003 ) if code == e .args [0 ]]:
@@ -461,15 +447,16 @@ def _fallback_to_tcp_ip():
461447 self .echo (
462448 "Failed to connect to local MySQL server through socket '{}':" .format (socket ))
463449 self .echo (str (e ), err = True )
464- _fallback_to_tcp_ip ()
450+ self .echo (
451+ 'Retrying over TCP/IP' , err = True )
452+
453+ # Else fall back to TCP/IP localhost
454+ socket = ""
455+ host = 'localhost'
456+ port = 3306
457+ _connect ()
465458 else :
466459 raise e
467- else :
468- socket_owner = getpwuid (os .stat (socket ).st_uid ).pw_name
469- self .echo (
470- "Using socket {}, owned by user {}" .format (
471- socket , socket_owner )
472- )
473460 else :
474461 host = host or 'localhost'
475462 port = port or 3306
@@ -1009,6 +996,9 @@ def get_last_query(self):
1009996@click .option ('--ssh-port' , default = 22 , help = 'Port to connect to ssh server.' )
1010997@click .option ('--ssh-password' , help = 'Password to connect to ssh server.' )
1011998@click .option ('--ssh-key-filename' , help = 'Private key filename (identify file) for the ssh connection.' )
999+ @click .option ('--ssh-config-path' , help = 'Path to ssh configuration.' ,
1000+ default = os .path .expanduser ('~' ) + '/.ssh/config' )
1001+ @click .option ('--ssh-config-host' , help = 'Host to connect to ssh server reading from ssh configuration.' )
10121002@click .option ('--ssl-ca' , help = 'CA file in PEM format.' ,
10131003 type = click .Path (exists = True ))
10141004@click .option ('--ssl-capath' , help = 'CA directory.' )
@@ -1030,6 +1020,8 @@ def get_last_query(self):
10301020 help = 'Use DSN configured into the [alias_dsn] section of myclirc file.' )
10311021@click .option ('--list-dsn' , 'list_dsn' , is_flag = True ,
10321022 help = 'list of DSN configured into the [alias_dsn] section of myclirc file.' )
1023+ @click .option ('--list-ssh-config' , 'list_ssh_config' , is_flag = True ,
1024+ help = 'list ssh configurations in the ssh config (requires paramiko).' )
10331025@click .option ('-R' , '--prompt' , 'prompt' ,
10341026 help = 'Prompt format (Default: "{0}").' .format (
10351027 MyCli .default_prompt ))
@@ -1062,7 +1054,7 @@ def cli(database, user, host, port, socket, password, dbname,
10621054 ssl_ca , ssl_capath , ssl_cert , ssl_key , ssl_cipher ,
10631055 ssl_verify_server_cert , table , csv , warn , execute , myclirc , dsn ,
10641056 list_dsn , ssh_user , ssh_host , ssh_port , ssh_password ,
1065- ssh_key_filename ):
1057+ ssh_key_filename , list_ssh_config , ssh_config_path , ssh_config_host ):
10661058 """A MySQL terminal client with auto-completion and syntax highlighting.
10671059
10681060 \b
@@ -1099,6 +1091,31 @@ def cli(database, user, host, port, socket, password, dbname,
10991091 else :
11001092 click .secho (alias )
11011093 sys .exit (0 )
1094+ if list_ssh_config :
1095+ if not paramiko :
1096+ click .secho (
1097+ "This features requires paramiko. Please install paramiko and try again." ,
1098+ err = True , fg = 'red'
1099+ )
1100+ exit (1 )
1101+ try :
1102+ ssh_config = paramiko .config .SSHConfig ().from_path (ssh_config_path )
1103+ except paramiko .ssh_exception .ConfigParseError as err :
1104+ click .secho ('Invalid SSH configuration file. '
1105+ 'Please check the SSH configuration file.' ,
1106+ err = True , fg = 'red' )
1107+ exit (1 )
1108+ except FileNotFoundError as e :
1109+ click .secho (str (e ), err = True , fg = 'red' )
1110+ exit (1 )
1111+ for host in ssh_config .get_hostnames ():
1112+ if verbose :
1113+ host_config = ssh_config .lookup (host )
1114+ click .secho ("{} : {}" .format (
1115+ host , host_config .get ('hostname' )))
1116+ else :
1117+ click .secho (host )
1118+ sys .exit (0 )
11021119 # Choose which ever one has a valid value.
11031120 database = dbname or database
11041121
@@ -1149,6 +1166,32 @@ def cli(database, user, host, port, socket, password, dbname,
11491166 if not port :
11501167 port = uri .port
11511168
1169+ if ssh_config_host :
1170+ if not paramiko :
1171+ click .secho (
1172+ "This features requires paramiko. Please install paramiko and try again." ,
1173+ err = True , fg = 'red'
1174+ )
1175+ exit (1 )
1176+ try :
1177+ ssh_config = paramiko .config .SSHConfig ().from_path (ssh_config_path )
1178+ except paramiko .ssh_exception .ConfigParseError as err :
1179+ click .secho ('Invalid SSH configuration file. '
1180+ 'Please check the SSH configuration file.' ,
1181+ err = True , fg = 'red' )
1182+ exit (1 )
1183+ except FileNotFoundError as e :
1184+ click .secho (str (e ), err = True , fg = 'red' )
1185+ exit (1 )
1186+ ssh_config = ssh_config .lookup (ssh_config_host )
1187+ ssh_host = ssh_host if ssh_host else ssh_config .get ('hostname' )
1188+ ssh_user = ssh_user if ssh_user else ssh_config .get ('user' )
1189+ if ssh_config .get ('port' ) and ssh_port == 22 :
1190+ # port has a default value, overwrite it if it's in the config
1191+ ssh_port = int (ssh_config .get ('port' ))
1192+ ssh_key_filename = ssh_key_filename if ssh_key_filename else ssh_config .get (
1193+ 'identityfile' , ['' ])[0 ]
1194+
11521195 if not paramiko and ssh_host :
11531196 click .secho (
11541197 "Cannot use SSH transport because paramiko isn't installed, "
0 commit comments