Knowing if a remote port forward was successful?
Try adding -o ExitOnForwardFailure=yes
The full command will be something like:
ssh -N -R [port_XX]:localhost:22 -o ExitOnForwardFailure=yes user@host
(-N
is useful to just forward port, without opening a remote shell; you can also add -f
to send process in background, no need if you are running under screen, though..)
How to make SSH remote port forward that listens 0.0.0.0
Enable GatewayPorts
in sshd_config (by default it is disabled). Enabling it will instruct sshd to allow remote port forwardings to bind to a non-loopback address. AskUbuntu has a similar question about Reverse Port Tunneling that goes into more details.
kubectl - determine local port used when port-forwarding on random local port?
I couldn't get any other approach to work, so I ended writing a script that dynamically finds a free port, and sets up a forward, then returns the port. If a matching port forward already exists, it can return that instead. Sample usage below. Note that currently I use another script to determine a free local port, and then use that port number to setup the port forward, and could've instead parsed the output from the generic port-forward command I mentioned in the question, but this approach is less fragile, and more re-usable, I believe.
$ kpf help
kubernetes port forward helper
* helps you transparently ensure a port forward is setup for a service.
usage: kpf [require|get|create|remove|remove_all] {SERVICEI} {REMOTE_PORT} {EXTRA_ARGS}
e.g.
# get or create a port forward for your-service on remote port 8080
# returns the port if successful, or fails and shows an error message
kpf require service/your-service 8080
# return any existing port forwards for your-service on remote port 8080, or nothing
kpf get service/your-service 8080
# create a new local port forward for your-service on remote port 8080, returning port used
kpf create service/your-service 8080
# remove any port forwards found to your-service on remote port 8080
kpf remove service/your-service 8080
# remove ALL port forwards to any kubernetes remote ports
kpf remove_all
kpf
#!/usr/bin/env bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"; PATH="$DIR:$PATH"
ME=$(basename "$0")
function show_help()
{
IT=$(cat <<EOF
kubernetes port forward helper
* helps you transparently ensure a port forward is setup for a service.
usage: $ME [require|get|create|remove|remove_all] {SERVICE} {REMOTE_PORT} {EXTRA_ARGS}
e.g.
# get or create a port forward for your-service on remote port 8080
# returns the port if successful, or fails and shows an error message
$ME require service/your-service 8080
# return any existing port forwards for your-service on remote port 8080, or nothing
$ME get service/your-service 8080
# create a new local port forward for your-service on remote port 8080, returning port used
$ME create service/your-service 8080
# remove any port forwards found to your-service on remote port 8080
$ME remove service/your-service 8080
# remove ALL port forwards to any kubernetes remote ports
$ME remove_all
# create a port forward on local port 4569, for localstack, in namespace localstack
$ME create svc/localstack 4569:4569 --namespace localstack
EOF
)
echo "$IT"
echo
exit
}
if [ -z "$1" ]
then
show_help
fi
if [ "$1" = "help" ] || [ "$1" = '?' ] || [ "$1" = "--help" ] || [ "$1" = "h" ]; then
show_help
fi
OP=$1
SERVICE=$2
REMOTE_PORT=$3
if [ -n "$4" ]
then
shift;
shift;
shift;
EXTRA_ARGS="$@"
fi
LOG_FILE_DIR="/tmp/__${ME}"
function getExistingPortForward(){
listPortForwards | grep "$SERVICE" | grep -e ":$REMOTE_PORT" | head -n1
}
function coln(){
COL=$1
DELIM=${2:-' '}
awk -F"$DELIM" -v col="$COL" '{print $col}' | sort | uniq
}
function err(){
echo "$@" >&2;
}
function isNumeric(){
INPUT=$*
case ${INPUT#[-+]} in
*[!0-9]* ) echo NO ;;
* ) echo YES ;;
esac
}
function getPid(){
local INFO=$(getExistingPortForward | awk '{print $2}')
if [ "$(isNumeric "$INFO")" == "YES" ]; then
echo "$INFO"
fi
}
function getLocalPort(){
local INFO=$(getExistingPortForward)
INFO=$(echo "$INFO" | awk -F ":$REMOTE_PORT" '{print $1}' | awk '{print $NF}')
if [ "$(isNumeric "$INFO")" == "YES" ]; then
echo "$INFO"
fi
}
function removePortForward(){
local PID=$(getPid)
if [ -z "$PID" ]
then
return;
fi
set -x
kill "$PID"
}
function portForward(){
local LOCAL_PORT=$1
local FILE=$2
kubectl port-forward "$SERVICE" "$LOCAL_PORT":"$REMOTE_PORT" $EXTRA_ARGS > $FILE 2>&1 &
}
function failIfFileContains(){
local FILE=$1
local SUBSTR=$2
local MSG=$3
if grep -iq "$SUBSTR" "$FILE"; then
cat "$FILE" >&2
err "Failed: $MSG"
err "Service:$SERVICE, $REMOTE_PORT $EXTRA_ARGS"
err
exit 1
fi
}
function getTargetLocalPort(){
local RESULT
if [[ $REMOTE_PORT == *":"* ]]; then
RESULT=$(echo $REMOTE_PORT | coln 1 ':')
REMOTE_PORT=$(echo $REMOTE_PORT | coln 2 ':')
else
RESULT=$(port_find_free_local_port)
fi
echo "$RESULT"
}
function createPortForward(){
local LOCAL_PORT=$(getTargetLocalPort)
local LOG_FILE="${LOG_FILE_DIR}/${LOCAL_PORT}_log.txt"
mkdir -p "$LOG_FILE_DIR"
rm -f "$LOG_FILE"
portForward "$LOCAL_PORT" "$LOG_FILE"
# wait for the log file to indicate success or failure
while true
do
sleep 0.5
failIfFileContains "$LOG_FILE" "address already" "Port $LOCAL_PORT already in use"
failIfFileContains "$LOG_FILE" "must be logged" "Please set some PCSK variables, and try again"
failIfFileContains "$LOG_FILE" "Failed" "Please review the above log, and try again"
failIfFileContains "$LOG_FILE" "Error" "Please review the above log, and try again"
if grep -q Forwarding "$LOG_FILE"; then
# port forward successful
echo "$LOCAL_PORT"
break
fi
done
}
function getOrCreatePortForward(){
local PORT=$(getLocalPort)
if [ -n "$PORT" ]
then
echo "$PORT"
exit;
fi
createPortForward
}
function listPortForwards(){
ps aux | grep kubectl | grep port-forward | sort
}
function removeAll(){
listPortForwards | awk '{print $2}' | xargs kill -9
rm -fr "$LOG_FILE_DIR"
}
function require3Args(){
if [ -z "$REMOTE_PORT" ]
then
show_help
fi
}
if [ "$OP" = "get" ]; then
require3Args
getLocalPort
elif [ "$OP" = "create" ]; then
require3Args
createPortForward
elif [ "$OP" = "require" ]; then
require3Args
getOrCreatePortForward
elif [ "$OP" = "remove" ]; then
require3Args
removePortForward
elif [ "$OP" = "list" ]; then
listPortForwards
elif [ "$OP" = "remove_all" ]; then
removeAll
else
show_help
fi
port_find_free_local_port
#!/usr/bin/env python
# https://stackoverflow.com/a/45690594/26510
import socket
from contextlib import closing
def find_free_port():
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
s.bind(('', 0))
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
return s.getsockname()[1]
print(find_free_port())
Related Topics
How to Feed Awk Input from Both Pipe and File
How to Ask Bash for the Current Options
How to Properly Quote This Bash Pipeline for Watch
Random Alphanumeric String Linux Swift 3
Start Docker-Compose Automatically on Ec2 Startup
Libreoffice Command Line Conversion - No Output File
Adding Timestamps to Packet Payload with Tcpreplay
Commands Will Not Pass to Cli After Logging into New User with Sudo Su - User
How to Get Around the Linux "Too Many Arguments" Limit
Linking a Dynamically Linked Executable with Ld
Replace Bash Variables in Template File
How to Make .Gitignore Configurable Based on Environment Variables
Perf Top Result About Nested Functions
How to Configure Acpi *.Asl for a Virtual Mdio-Gpio Device Connected to a I2C Gpio Expander
Find Files with a Certain Extension That Exceeds a Certain File Size