diff --git a/README.md b/README.md
index aeda086..69af939 100644
--- a/README.md
+++ b/README.md
@@ -79,6 +79,7 @@ kubectl-tmux_exec --help
Flag | Usage
--- | ---
+`-V`
`--version` | Print the version information
`-l`
`--selector` | Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)
You must either use `--selector` or `--file` option.
`-f`
`--file` | Read pod names line-by-line from a file.
You must either use `--selector` or `--file` option.
`-c`
`--container` | Container name. If omitted, the first container in the pod will be chosen
@@ -87,7 +88,7 @@ Flag | Usage
`-d`
`--detach` | Make the Tmux session detached
`--remain-on-exit` | Remain Tmux window on exit
`--select-layout` | One of the five Tmux preset layouts: even-horizontal, even-vertical, main-horizontal, main-vertical, or tiled.
-`-V`
`--version` | Print the version information
+`--session-mode` | Where tmux is opened: auto, new-session, current-session
The usage of these options is also available by `--help`.
diff --git a/bin/kubectl-tmux_exec b/bin/kubectl-tmux_exec
index 4abdde8..e5ec988 100755
--- a/bin/kubectl-tmux_exec
+++ b/bin/kubectl-tmux_exec
@@ -24,9 +24,9 @@ set -euf -o pipefail
# Stack Overflow: https://stackoverflow.com/a/246128/1122665
SOURCE="${BASH_SOURCE[0]}"
while [[ -h "$SOURCE" ]]; do
- PROG_DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
- SOURCE="$(readlink "$SOURCE")"
- [[ $SOURCE != /* ]] && SOURCE="$PROG_DIR/$SOURCE"
+ PROG_DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
+ SOURCE="$(readlink "$SOURCE")"
+ [[ $SOURCE != /* ]] && SOURCE="$PROG_DIR/$SOURCE"
done
PROG_DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
@@ -63,6 +63,12 @@ declare -ra TMUX_LAYOUTS=(
'tiled'
)
+declare -ra SESSION_MODES=(
+ 'auto'
+ 'new-session'
+ 'current-session'
+)
+
function usage() {
cat << EOF
Execute a command in all containers that match the label selector using Tmux.
@@ -87,6 +93,10 @@ Options:
-l, --selector: Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)
-f, --file: Read pod names line-by-line from a file
-d, --detach=false: Make the Tmux session detached
+ --session-mode=auto: Where tmux is opened:
+ new-session (always in a new session no matter whether there is an existing or not)
+ current-session (re-use the current session)
+ auto ('current-session' if there is an existing one, otherwise 'new-session')
--remain-on-exit=false: Remain Tmux window on exit
--select-layout=tiled: One of the five Tmux preset layouts: even-horizontal, even-vertical, main-horizontal,
main-vertical, or tiled.
@@ -157,7 +167,7 @@ function array_contains() {
function main() {
local opts
opts=$(ggetopt -o hVitdc:l:f:"$(printf '%s:' "${KUBECTL_SHORT_OPTS[@]}")" --long \
- help,version,stdin,tty,detach,container:,selector:,remain-on-exit,select-layout:,file:,"$(printf '%s:,' "${KUBECTL_LONG_OPTS[@]}")","$(printf '%s,' "${KUBECTL_NOARG_LONG_OPTS[@]}")" -- "$@")
+ help,version,stdin,tty,detach,container:,selector:,remain-on-exit,select-layout:,session-mode:,file:,"$(printf '%s:,' "${KUBECTL_LONG_OPTS[@]}")","$(printf '%s,' "${KUBECTL_NOARG_LONG_OPTS[@]}")" -- "$@")
eval set -- $opts
local selector
@@ -167,6 +177,7 @@ function main() {
local tmux_layout='tiled'
local pod_list_file
local tmux_detach=0
+ local session_mode='auto'
while [[ $# -gt 0 ]]; do
local opt="$1"
case "${opt}" in
@@ -202,6 +213,10 @@ function main() {
shift
tmux_layout="$1"
;;
+ --session-mode)
+ shift
+ session_mode="$1"
+ ;;
-f|--file)
shift
pod_list_file="$1"
@@ -250,7 +265,11 @@ function main() {
if [[ -z "${tmux_layout}" ]] || ! array_contains "${tmux_layout}" "${TMUX_LAYOUTS[@]}"; then
error_and_exit "Unknown layout: ${tmux_layout}"
fi
-
+
+ if [[ -z "${session_mode}" ]] || ! array_contains "${session_mode}" "${SESSION_MODES[@]}"; then
+ error_and_exit "Unknown session mode: ${session_mode}"
+ fi
+
local commands=("$@")
local kubectl_exec_opts='-i -t'
@@ -294,10 +313,21 @@ function main() {
for pod in "${pods[@]}"; do
local cmd="kubectl ${kubectl_opts[@]:-} exec ${kubectl_exec_opts} ${pod} -- ${exec_cmd_str}"
if [[ "${#tmux_commands[@]}" -eq 0 ]]; then
+ local open_command
+ if [[ "${session_mode}" == 'new-session' ]]; then
+ open_command='new-session'
+ elif [[ "${session_mode}" == 'current-session' ]]; then
+ open_command='new-window'
+ elif [[ -z "${TMUX:-}" ]]; then
+ open_command='new-session'
+ else
+ open_command='new-window'
+ fi
+
if [[ "${tmux_detach}" -eq 0 ]]; then
- tmux_commands+=('new-session' "${cmd}" ';')
+ tmux_commands+=("${open_command}" "${cmd}" ';')
else
- tmux_commands+=('new-session' '-d' "${cmd}" ';')
+ tmux_commands+=("${open_command}" '-d' "${cmd}" ';')
fi
else
tmux_commands+=('split-window' "${cmd}" ';')
diff --git a/test/exec-one-pod.bats b/test/exec-one-pod.bats
index 2aedd10..7275422 100644
--- a/test/exec-one-pod.bats
+++ b/test/exec-one-pod.bats
@@ -2,41 +2,12 @@
load test-helper
-readonly POD_NAME='alpine'
-readonly POD_APP_LABEL='alpine'
-
function setup() {
- kubectl apply -f - << EOF
-apiVersion: v1
-kind: Pod
-metadata:
- name: ${POD_NAME}
- labels:
- app: ${POD_APP_LABEL}
-spec:
- containers:
- - name: alpine
- image: alpine
- command:
- - sleep
- - infinite
-EOF
- local pod_status=''
- local retries=30
- while [[ "${pod_status}" != 'Running' ]]; do
- sleep 1
- pod_status="$(kubectl get pods "${POD_NAME}" -o custom-columns=':status.phase' --no-headers)"
- echo "The pod status is ${pod_status}."
- (( --retries )) || {
- echo 'Timed out.'
- exit 1
- }
- done
+ setup_one_pod
}
function teardown() {
- kubectl delete pod "${POD_NAME}"
- sleep 1
+ teardown_one_pod
}
@test "Exec one pod by label" {
diff --git a/test/nested-tmux.bats b/test/nested-tmux.bats
new file mode 100644
index 0000000..4140b5a
--- /dev/null
+++ b/test/nested-tmux.bats
@@ -0,0 +1,25 @@
+#!/usr/bin/env bats
+
+load test-helper
+
+function setup() {
+ setup_one_pod
+}
+
+function teardown() {
+ teardown_one_pod
+ tmux kill-server || true
+}
+
+@test "Reuse tmux session" {
+ tmux new-session -d bin/kubectl-tmux_exec -l app="${POD_APP_LABEL}" sh
+ [ "$(tmux ls | wc -l)" -eq 1 ]
+}
+
+@test "Nest tmux session" {
+ tmux new-session -d bin/kubectl-tmux_exec -l app="${POD_APP_LABEL}" --session-mode new-session sh
+ sleep 2
+ local tmux_exit_code=0
+ tmux ls || tmux_exit_code="$?"
+ [ "${tmux_exit_code}" -eq 1 ]
+}
diff --git a/test/test-helper.bash b/test/test-helper.bash
index d55bcad..fe92963 100644
--- a/test/test-helper.bash
+++ b/test/test-helper.bash
@@ -9,4 +9,41 @@ function wait_until_no_sessions() {
}
sleep 1
done
+}
+
+readonly POD_NAME='alpine'
+readonly POD_APP_LABEL='alpine'
+
+function setup_one_pod() {
+ kubectl apply -f - << EOF
+apiVersion: v1
+kind: Pod
+metadata:
+ name: ${POD_NAME}
+ labels:
+ app: ${POD_APP_LABEL}
+spec:
+ containers:
+ - name: alpine
+ image: alpine
+ command:
+ - sleep
+ - infinite
+EOF
+ local pod_status=''
+ local retries=30
+ while [[ "${pod_status}" != 'Running' ]]; do
+ sleep 1
+ pod_status="$(kubectl get pods "${POD_NAME}" -o custom-columns=':status.phase' --no-headers)"
+ echo "The pod status is ${pod_status}."
+ (( --retries )) || {
+ echo 'Timed out.'
+ exit 1
+ }
+ done
+}
+
+function teardown_one_pod() {
+ kubectl delete pod "${POD_NAME}"
+ sleep 5
}
\ No newline at end of file