mirror of
https://github.com/ahmetb/kubectx.git
synced 2026-03-09 23:42:13 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10c9bd58ca | ||
|
|
b6e918b084 | ||
|
|
402cc2c4b9 | ||
|
|
df557e4fa7 | ||
|
|
b584d14f90 | ||
|
|
acbf324464 | ||
|
|
845f3b690b | ||
|
|
2b5bf4e429 | ||
|
|
4a7d7cf025 |
9
.travis.yml
Normal file
9
.travis.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
before_install:
|
||||
- sudo add-apt-repository ppa:duggan/bats --yes
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq bats
|
||||
- sudo curl -fsSL -o /usr/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/v1.13.1/bin/linux/amd64/kubectl
|
||||
- sudo chmod +x /usr/bin/kubectl
|
||||
script:
|
||||
- bats test/kubectx.bats
|
||||
- bats test/kubens.bats
|
||||
13
README.md
13
README.md
@@ -83,10 +83,6 @@ Active namespace is "default".
|
||||
|
||||
This command will set up bash/zsh/fish completion scripts automatically.
|
||||
|
||||
|
||||
- Running `brew install` with `--with-short-names` will install tools with names
|
||||
`kctx` and `kns` to prevent prefix collision with `kubectl` name.
|
||||
|
||||
- If you like to add context/namespace info to your shell prompt (`$PS1`),
|
||||
I recommend trying out [kube-ps1](https://github.com/jonmosco/kube-ps1).
|
||||
|
||||
@@ -127,8 +123,13 @@ them to any POSIX environment that has Bash installed.
|
||||
export PATH=~/.kubectx:\$PATH
|
||||
FOE
|
||||
```
|
||||
- For fish: Figure out how to install completion scripts and please document here
|
||||
|
||||
- For fish:
|
||||
```fish
|
||||
mkdir -p ~/.config/fish/completions
|
||||
ln -s /opt/kubectx/completion/kubectx.fish ~/.config/fish/completions/
|
||||
ln -s /opt/kubectx/completion/kubens.fish ~/.config/fish/completions/
|
||||
```
|
||||
|
||||
Example installation steps:
|
||||
|
||||
``` bash
|
||||
|
||||
14
kubectx
14
kubectx
@@ -69,8 +69,14 @@ list_contexts() {
|
||||
cur_ctx_bg=${KUBECTX_CURRENT_BGCOLOR:-$darkbg}
|
||||
|
||||
for c in $ctx_list; do
|
||||
if [[ -t 1 && -z "${NO_COLOR:-}" && "${c}" = "${cur}" ]]; then
|
||||
echo "${cur_ctx_bg}${cur_ctx_fg}${c}${normal}"
|
||||
if [[ -n "${_KUBECTX_FORCE_COLOR:-}" || \
|
||||
-t 1 && -z "${NO_COLOR:-}" ]]; then
|
||||
# colored output mode
|
||||
if [[ "${c}" = "${cur}" ]]; then
|
||||
echo "${cur_ctx_bg}${cur_ctx_fg}${c}${normal}"
|
||||
else
|
||||
echo "${c}"
|
||||
fi
|
||||
else
|
||||
echo "${c}"
|
||||
fi
|
||||
@@ -98,7 +104,9 @@ switch_context() {
|
||||
|
||||
choose_context_interactive() {
|
||||
local choice
|
||||
choice="$(FZF_DEFAULT_COMMAND="${SELF_CMD}" fzf --ansi || true)"
|
||||
choice="$(_KUBECTX_FORCE_COLOR=1 \
|
||||
FZF_DEFAULT_COMMAND="${SELF_CMD}" \
|
||||
fzf --ansi || true)"
|
||||
if [[ -z "${choice}" ]]; then
|
||||
echo 2>&1 "error: you did not choose any of the options"
|
||||
exit 1
|
||||
|
||||
30
kubens
30
kubens
@@ -54,7 +54,7 @@ current_namespace() {
|
||||
}
|
||||
|
||||
current_context() {
|
||||
$KUBECTL config view -o=jsonpath='{.current-context}'
|
||||
$KUBECTL config current-context
|
||||
}
|
||||
|
||||
get_namespaces() {
|
||||
@@ -104,7 +104,9 @@ choose_namespace_interactive() {
|
||||
fi
|
||||
|
||||
local choice
|
||||
choice="$(FZF_DEFAULT_COMMAND="${SELF_CMD}" fzf --ansi || true)"
|
||||
choice="$(_KUBECTX_FORCE_COLOR=1 \
|
||||
FZF_DEFAULT_COMMAND="${SELF_CMD}" \
|
||||
fzf --ansi || true)"
|
||||
if [[ -z "${choice}" ]]; then
|
||||
echo 2>&1 "error: you did not choose any of the options"
|
||||
exit 1
|
||||
@@ -145,11 +147,17 @@ list_namespaces() {
|
||||
ns_list=$(get_namespaces) || exit_err "error getting namespace list"
|
||||
|
||||
for c in $ns_list; do
|
||||
if [[ -t 1 && -z "${NO_COLOR:-}" && "${c}" = "${cur}" ]]; then
|
||||
if [[ -n "${_KUBECTX_FORCE_COLOR:-}" || \
|
||||
-t 1 && -z "${NO_COLOR:-}" ]]; then
|
||||
# colored output mode
|
||||
if [[ "${c}" = "${cur}" ]]; then
|
||||
echo "${cur_ctx_bg}${cur_ctx_fg}${c}${normal}"
|
||||
else
|
||||
echo "${c}"
|
||||
fi
|
||||
else
|
||||
echo "${c}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
@@ -165,13 +173,15 @@ swap_namespace() {
|
||||
}
|
||||
|
||||
main() {
|
||||
if hash kubectl 2>/dev/null; then
|
||||
KUBECTL=kubectl
|
||||
elif hash kubectl.exe 2>/dev/null; then
|
||||
KUBECTL=kubectl.exe
|
||||
else
|
||||
echo >&2 "kubectl is not installed"
|
||||
exit 1
|
||||
if [[ -z "${KUBECTL:-}" ]]; then
|
||||
if hash kubectl 2>/dev/null; then
|
||||
KUBECTL=kubectl
|
||||
elif hash kubectl.exe 2>/dev/null; then
|
||||
KUBECTL=kubectl.exe
|
||||
else
|
||||
echo >&2 "kubectl is not installed"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$#" -eq 0 ]]; then
|
||||
|
||||
30
test/common.bash
Normal file
30
test/common.bash
Normal file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
# bats setup function
|
||||
setup() {
|
||||
export XDG_CACHE_HOME="$(mktemp -d)"
|
||||
export KUBECONFIG="${XDG_CACHE_HOME}/config"
|
||||
}
|
||||
|
||||
# bats teardown function
|
||||
teardown() {
|
||||
rm -rf "$XDG_CACHE_HOME"
|
||||
}
|
||||
|
||||
use_config() {
|
||||
cp "$BATS_TEST_DIRNAME/testdata/$1" $KUBECONFIG
|
||||
}
|
||||
|
||||
# wrappers around "kubectl config" command
|
||||
|
||||
get_namespace() {
|
||||
kubectl config view -o=jsonpath="{.contexts[?(@.name==\"$(get_context)\")].context.namespace}"
|
||||
}
|
||||
|
||||
get_context() {
|
||||
kubectl config current-context
|
||||
}
|
||||
|
||||
switch_context() {
|
||||
kubectl config use-context "${1}"
|
||||
}
|
||||
214
test/kubectx.bats
Normal file
214
test/kubectx.bats
Normal file
@@ -0,0 +1,214 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
COMMAND="$BATS_TEST_DIRNAME/../kubectx"
|
||||
|
||||
load common
|
||||
|
||||
@test "no kubectl detected" {
|
||||
OLDPATH="$PATH"
|
||||
PATH=/bin
|
||||
run ${COMMAND}
|
||||
echo "$output"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" = "kubectl is not installed" ]]
|
||||
PATH="$OLDPATH"
|
||||
}
|
||||
|
||||
@test "--help should not fail" {
|
||||
run ${COMMAND} --help
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "-h should not fail" {
|
||||
run ${COMMAND} -h
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "switch to previous context when no one exists" {
|
||||
use_config config1
|
||||
|
||||
run ${COMMAND} -
|
||||
echo "$output"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" = "error: No previous context found." ]]
|
||||
}
|
||||
|
||||
@test "list contexts when no kubeconfig exists" {
|
||||
run ${COMMAND}
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" = "" ]]
|
||||
}
|
||||
|
||||
@test "get one context and list contexts" {
|
||||
use_config config1
|
||||
|
||||
run ${COMMAND}
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" = "user1@cluster1" ]]
|
||||
}
|
||||
|
||||
@test "get two contexts and list contexts" {
|
||||
use_config config2
|
||||
|
||||
run ${COMMAND}
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" = *"user1@cluster1"* ]]
|
||||
[[ "$output" = *"user2@cluster1"* ]]
|
||||
}
|
||||
|
||||
@test "get two contexts and select contexts" {
|
||||
use_config config2
|
||||
|
||||
run ${COMMAND} user1@cluster1
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$(get_context)"
|
||||
[[ "$(get_context)" = "user1@cluster1" ]]
|
||||
|
||||
run ${COMMAND} user2@cluster1
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$(get_context)"
|
||||
[[ "$(get_context)" = "user2@cluster1" ]]
|
||||
}
|
||||
|
||||
@test "get two contexts and switch between contexts" {
|
||||
use_config config2
|
||||
|
||||
run ${COMMAND} user1@cluster1
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$(get_context)"
|
||||
[[ "$(get_context)" = "user1@cluster1" ]]
|
||||
|
||||
run ${COMMAND} user2@cluster1
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$(get_context)"
|
||||
[[ "$(get_context)" = "user2@cluster1" ]]
|
||||
|
||||
run ${COMMAND} -
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$(get_context)"
|
||||
[[ "$(get_context)" = "user1@cluster1" ]]
|
||||
|
||||
run ${COMMAND} -
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$(get_context)"
|
||||
[[ "$(get_context)" = "user2@cluster1" ]]
|
||||
}
|
||||
|
||||
@test "get one context and switch to non existent context" {
|
||||
use_config config1
|
||||
|
||||
run ${COMMAND} "unknown-context"
|
||||
echo "$output"
|
||||
[ "$status" -eq 1 ]
|
||||
}
|
||||
|
||||
@test "rename context" {
|
||||
use_config config2
|
||||
|
||||
run ${COMMAND} "new-context=user1@cluster1"
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run ${COMMAND}
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ ! "$output" = *"user1@cluster1"* ]]
|
||||
[[ "$output" = *"new-context"* ]]
|
||||
[[ "$output" = *"user2@cluster1"* ]]
|
||||
}
|
||||
|
||||
@test "rename current context" {
|
||||
use_config config2
|
||||
|
||||
run ${COMMAND} user2@cluster1
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run ${COMMAND} new-context=.
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run ${COMMAND}
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ ! "$output" = *"user2@cluster1"* ]]
|
||||
[[ "$output" = *"user1@cluster1"* ]]
|
||||
[[ "$output" = *"new-context"* ]]
|
||||
}
|
||||
|
||||
@test "delete context" {
|
||||
use_config config2
|
||||
|
||||
run ${COMMAND} -d "user1@cluster1"
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run ${COMMAND}
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ ! "$output" = "user1@cluster1" ]]
|
||||
[[ "$output" = "user2@cluster1" ]]
|
||||
}
|
||||
|
||||
@test "delete current context" {
|
||||
use_config config2
|
||||
|
||||
run ${COMMAND} user2@cluster1
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run ${COMMAND} -d .
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run ${COMMAND}
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ ! "$output" = "user2@cluster1" ]]
|
||||
[[ "$output" = "user1@cluster1" ]]
|
||||
}
|
||||
|
||||
@test "delete non existent context" {
|
||||
use_config config1
|
||||
|
||||
run ${COMMAND} -d "unknown-context"
|
||||
echo "$output"
|
||||
[ "$status" -eq 1 ]
|
||||
}
|
||||
|
||||
@test "delete several contexts" {
|
||||
use_config config2
|
||||
|
||||
run ${COMMAND} -d "user1@cluster1" "user2@cluster1"
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
run ${COMMAND}
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" = "" ]]
|
||||
}
|
||||
|
||||
@test "delete several contexts including a non existent one" {
|
||||
use_config config2
|
||||
|
||||
run ${COMMAND} -d "user1@cluster1" "non-existent" "user2@cluster1"
|
||||
echo "$output"
|
||||
[ "$status" -eq 1 ]
|
||||
|
||||
run ${COMMAND}
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" = "user2@cluster1" ]]
|
||||
}
|
||||
104
test/kubens.bats
Normal file
104
test/kubens.bats
Normal file
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
COMMAND="${BATS_TEST_DIRNAME}/../kubens"
|
||||
export KUBECTL="$BATS_TEST_DIRNAME/../test/mock-kubectl"
|
||||
|
||||
load common
|
||||
|
||||
@test "--help should not fail" {
|
||||
run ${COMMAND} --help
|
||||
echo "$output">&2
|
||||
[[ "$status" -eq 0 ]]
|
||||
}
|
||||
|
||||
@test "-h should not fail" {
|
||||
run ${COMMAND} -h
|
||||
echo "$output">&2
|
||||
[[ "$status" -eq 0 ]]
|
||||
}
|
||||
|
||||
@test "list namespaces when no kubeconfig exists" {
|
||||
run ${COMMAND}
|
||||
echo "$output"
|
||||
[[ "$status" -eq 1 ]]
|
||||
[[ "$output" = *"current-context is not set"* ]]
|
||||
}
|
||||
|
||||
@test "list namespaces" {
|
||||
use_config config1
|
||||
switch_context user1@cluster1
|
||||
|
||||
run ${COMMAND}
|
||||
echo "$output"
|
||||
[[ "$status" -eq 0 ]]
|
||||
[[ "$output" = *"ns1"* ]]
|
||||
[[ "$output" = *"ns2"* ]]
|
||||
}
|
||||
|
||||
@test "switch to existing namespace" {
|
||||
use_config config1
|
||||
switch_context user1@cluster1
|
||||
|
||||
run ${COMMAND} "ns1"
|
||||
echo "$output"
|
||||
[[ "$status" -eq 0 ]]
|
||||
[[ "$output" = *'Active namespace is "ns1"'* ]]
|
||||
}
|
||||
|
||||
@test "switch to non-existing namespace" {
|
||||
use_config config1
|
||||
switch_context user1@cluster1
|
||||
|
||||
run ${COMMAND} "unknown-namespace"
|
||||
echo "$output"
|
||||
[[ "$status" -eq 1 ]]
|
||||
[[ "$output" = *'no namespace exists with name "unknown-namespace"'* ]]
|
||||
}
|
||||
|
||||
@test "switch between namespaces" {
|
||||
use_config config1
|
||||
switch_context user1@cluster1
|
||||
|
||||
run ${COMMAND} ns1
|
||||
echo "$output"
|
||||
[[ "$status" -eq 0 ]]
|
||||
echo "$(get_namespace)"
|
||||
[[ "$(get_namespace)" = "ns1" ]]
|
||||
|
||||
run ${COMMAND} ns2
|
||||
echo "$output"
|
||||
[[ "$status" -eq 0 ]]
|
||||
echo "$(get_namespace)"
|
||||
[[ "$(get_namespace)" = "ns2" ]]
|
||||
|
||||
run ${COMMAND} -
|
||||
echo "$output"
|
||||
[[ "$status" -eq 0 ]]
|
||||
echo "$(get_namespace)"
|
||||
[[ "$(get_namespace)" = "ns1" ]]
|
||||
|
||||
run ${COMMAND} -
|
||||
echo "$output"
|
||||
[[ "$status" -eq 0 ]]
|
||||
echo "$(get_namespace)"
|
||||
[[ "$(get_namespace)" = "ns2" ]]
|
||||
}
|
||||
|
||||
@test "switch to previous namespace when none exists" {
|
||||
use_config config1
|
||||
switch_context user1@cluster1
|
||||
|
||||
run ${COMMAND} -
|
||||
echo "$output"
|
||||
[[ "$status" -eq 1 ]]
|
||||
[[ "$output" = *"No previous namespace found for current context"* ]]
|
||||
}
|
||||
|
||||
@test "switch to namespace when current context is empty" {
|
||||
use_config config1
|
||||
|
||||
run ${COMMAND} -
|
||||
echo "$output"
|
||||
[[ "$status" -eq 1 ]]
|
||||
[[ "$output" = *"current-context is not set"* ]]
|
||||
}
|
||||
12
test/mock-kubectl
Executable file
12
test/mock-kubectl
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
[[ -n $DEBUG ]] && set -x
|
||||
|
||||
set -eou pipefail
|
||||
|
||||
if [[ $@ == *'get namespaces'* ]]; then
|
||||
echo "ns1"
|
||||
echo "ns2"
|
||||
else
|
||||
kubectl $@
|
||||
fi
|
||||
18
test/testdata/config1
vendored
Normal file
18
test/testdata/config1
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
# config with one context
|
||||
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: ""
|
||||
name: cluster1
|
||||
contexts:
|
||||
- context:
|
||||
cluster: cluster1
|
||||
user: user1
|
||||
name: user1@cluster1
|
||||
current-context: ""
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: user1
|
||||
user: {}
|
||||
24
test/testdata/config2
vendored
Normal file
24
test/testdata/config2
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# config with two contexts
|
||||
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
server: ""
|
||||
name: cluster1
|
||||
contexts:
|
||||
- context:
|
||||
cluster: cluster1
|
||||
user: user1
|
||||
name: user1@cluster1
|
||||
- context:
|
||||
cluster: cluster1
|
||||
user: user2
|
||||
name: user2@cluster1
|
||||
current-context: ""
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: user1
|
||||
user: {}
|
||||
- name: user2
|
||||
user: {}
|
||||
Reference in New Issue
Block a user