add foreground tunnels

This commit is contained in:
Q
2025-11-29 09:38:35 +02:00
parent 73fef8cd2b
commit a05f8dd6b9

View File

@@ -11,7 +11,7 @@ from argparse import ArgumentError, ArgumentParser
import psutil import psutil
import yaml import yaml
__version__ = "2025.03.30" __version__ = "2025.11.29"
CONFDIR = os.path.expanduser("~/.config/ssh-tunnelier") CONFDIR = os.path.expanduser("~/.config/ssh-tunnelier")
CONF_OLD = os.path.join(CONFDIR, "tunnels.json") CONF_OLD = os.path.join(CONFDIR, "tunnels.json")
@@ -31,7 +31,7 @@ EXAMPLE_CONFIG = {
"remote_port": 8080, "remote_port": 8080,
"remote_address": "localhost", "remote_address": "localhost",
"reverse": False, "reverse": False,
"comment": "`comment`, `reverse` and `remote_address` are not required", "comment": "Only local_port and remote_port are required",
} }
], ],
} }
@@ -50,6 +50,13 @@ def args():
nargs="?", nargs="?",
help="Connection name to use", help="Connection name to use",
) )
parser.add_argument(
"--example",
dest="example",
default=False,
action="store_true",
help="Print example config and exit",
)
parser.add_argument( parser.add_argument(
"--kill", "--kill",
dest="kill", dest="kill",
@@ -76,7 +83,7 @@ def args():
default=None, default=None,
action="store", action="store",
type=str, type=str,
help="Instant tunnel. Syntax: sshserver:localport[:targethost][:remoteport][:options]", help="Instant tunnel. Stays foreground. Syntax: sshserver:localport[:targethost][:remoteport][:options]",
) )
parser.add_argument( parser.add_argument(
"--auto", "--auto",
@@ -85,6 +92,13 @@ def args():
action="store_true", action="store_true",
help="Run all connections with auto-connect: true", help="Run all connections with auto-connect: true",
) )
parser.add_argument(
"--fg",
dest="foreground",
default=False,
action="store_true",
help="Stay foreground.",
)
options = parser.parse_args() options = parser.parse_args()
if options.name is None and options.connect is None and not options.auto: if options.name is None and options.connect is None and not options.auto:
@@ -101,6 +115,8 @@ def check_type(d, key, expected, error_msg):
if not isinstance(d[key], expected): if not isinstance(d[key], expected):
raise ValueError(error_msg) raise ValueError(error_msg)
def print_example():
yaml.dump(EXAMPLE_CONFIG, sys.stdout, sort_keys=False)
def load_config(): def load_config():
"""Load config, check types, add defaults""" """Load config, check types, add defaults"""
@@ -115,7 +131,7 @@ def load_config():
else: else:
print("Creating example config: " + CONF) print("Creating example config: " + CONF)
with open(CONF, "w") as fp: with open(CONF, "w") as fp:
yaml.dump(EXAMPLE_CONFIG, fp) yaml.dump(EXAMPLE_CONFIG, fp, sort_keys=False)
with open(CONF, "r") as fp: with open(CONF, "r") as fp:
config = yaml.safe_load(fp) config = yaml.safe_load(fp)
@@ -171,6 +187,8 @@ def connect(name, config, foreground=False):
else [] else []
) )
cmd = ["ssh", *f_commands, "-n", *options, *tunnels, host, remote_cmd] cmd = ["ssh", *f_commands, "-n", *options, *tunnels, host, remote_cmd]
if foreground:
list_connections(config, single=name)
if not foreground: if not foreground:
kill_connection(name, config) kill_connection(name, config)
try: try:
@@ -270,6 +288,9 @@ def parse_connect(connect_string):
def main(): def main():
opts = args() opts = args()
config = load_config() config = load_config()
if opts.example:
print_example()
sys.exit(0)
if opts.edit: if opts.edit:
config_edit(opts.edit) config_edit(opts.edit)
sys.exit(0) sys.exit(0)
@@ -286,7 +307,7 @@ def main():
kill_connection(opts.name, config) kill_connection(opts.name, config)
sys.exit(0) sys.exit(0)
if opts.name: if opts.name:
connect(opts.name, config) connect(opts.name, config, foreground=opts.foreground)
if __name__ == "__main__": if __name__ == "__main__":