diff --git a/config/.config/sdm-ui.yaml b/config/.config/sdm-ui.yaml index 190a147..0b1dd59 100644 Binary files a/config/.config/sdm-ui.yaml and b/config/.config/sdm-ui.yaml differ diff --git a/zsh/.config/zsh/completions.zsh b/zsh/.config/zsh/completions.zsh index ee30dc3..0790d69 100644 --- a/zsh/.config/zsh/completions.zsh +++ b/zsh/.config/zsh/completions.zsh @@ -18,7 +18,7 @@ for completion_file in ~/.local/share/zsh/*-autocomplete.zsh(N); do done if command -v eza &> /dev/null; then - compdef eza=ls + compdef _ls eza fi if command -v kubefwd &> /dev/null; then @@ -48,10 +48,9 @@ fi _kf_completion() { local -a contexts contexts=($(kubectx 2>/dev/null | sed 's/-read$//; s/-security$//' | sort -u)) - - if [[ ${#contexts[@]} -gt 0 ]]; then - _values 'cluster' "${contexts[@]}" - fi + + # Use _describe instead of _values for better compatibility + _describe 'cluster' contexts } _rmq_passwd_completion() { @@ -97,6 +96,14 @@ _yay_zsh_completion() { _describe 'yay commands' opts } +_kf_completion() { + local -a contexts + contexts=($(kubectx 2>/dev/null | sed 's/-read$//; s/-security$//' | sort -u)) + + if [[ ${#contexts[@]} -gt 0 ]]; then + _values 'cluster' "${contexts[@]}" + fi +} compdef _kf_completion kf compdef _rmq_passwd_completion rmq-passwd diff --git a/zsh/.config/zsh/functions.zsh b/zsh/.config/zsh/functions.zsh index 088aedd..a4f2392 100644 --- a/zsh/.config/zsh/functions.zsh +++ b/zsh/.config/zsh/functions.zsh @@ -293,39 +293,156 @@ alias pport="ppid" # KUBERNETES AND DEVOPS # ============================================================================= -# Kubernetes port forwarding with kubefwd +# # Kubernetes port forwarding with kubefwd +# function kf { +# if [[ "$1" == "-h" || "$1" == "--help" ]]; then +# echo "Usage: kf [service-name]" +# echo "Forward Kubernetes services using kubefwd" +# echo "Example: kf prod my-service" +# return 0 +# fi +# +# if [[ -z "$1" ]]; then +# echo "Error: Cluster name required" >&2 +# echo "Usage: kf [service-name]" >&2 +# return 1 +# fi +# +# local namespace="oc-app" +# local cluster="$1" +# local svc_filter="" +# +# if [[ -n "$2" ]]; then +# svc_filter="-l app.kubernetes.io/instance=$2" +# fi +# +# if ! command -v kubefwd >/dev/null 2>&1; then +# echo "Error: kubefwd is not installed" >&2 +# return 1 +# fi +# +# echo "Starting kubefwd for cluster: $cluster" +# kubefwd svc -n "${namespace}" -x "${cluster}" ${svc_filter} --nonsudo +# } +# + +# Forward multiple services from a given namespace + function kf { - # Show help if requested + # Show help if [[ "$1" == "-h" || "$1" == "--help" ]]; then - echo "Usage: kf [service-name]" - echo "Forward Kubernetes services using kubefwd" - echo "Example: kf prod my-service" + echo "Usage: kf [service-name[:port]] [service-name[:port]] ..." + echo "Example: kf oc-dev-internal-eks-cluster oc-activate-web" + echo "Example: kf oc-dev-internal-eks-cluster oc-activate-web:8080" + echo "Example: kf oc-dev-internal-eks-cluster oc-activate-web:8080 oc-member-dossier:8081" return 0 fi - if [[ -z "$1" ]]; then - echo "Error: Cluster name required" >&2 - echo "Usage: kf [service-name]" >&2 + local cluster="$1" + shift + + if [[ -z "$cluster" ]]; then + echo "Error: Missing cluster" >&2 + echo "Usage: kf [service-name[:port]] [service-name[:port]] ..." >&2 return 1 fi - local namespace="oc-app" - local cluster="oc-$1-eks-cluster" - local svc_filter="" - - if [[ -n "$2" ]]; then - svc_filter="-l app.kubernetes.io/instance=$2" + # Show available services if none specified + if [[ $# -eq 0 ]]; then + echo "🔌 Available services in cluster: $cluster" + kubectl --context "$cluster" -n oc-app get svc -o name | sed 's/service\// - /' + return 0 fi - if ! command -v kubefwd >/dev/null 2>&1; then - echo "Error: kubefwd is not installed" >&2 + echo "🔌 Forwarding services (cluster: $cluster)" + + # Clean up existing port-forwards + local existing_pids + existing_pids=$(pgrep -f "kubectl.*port-forward" || true) + if [[ -n "$existing_pids" ]]; then + echo "$existing_pids" | xargs kill 2>/dev/null || true + existing_pids=$(pgrep -f "kubectl.*port-forward" || true) + if [[ -n "$existing_pids" ]]; then + echo "$existing_pids" | xargs kill -9 2>/dev/null || true + sleep 0.5 + fi + fi + + local pids=() + + # Process each service + for service_spec in "$@"; do + # Parse service:port format + local service_name local_port + if [[ "$service_spec" == *":"* ]]; then + service_name="${service_spec%:*}" + local_port="${service_spec##*:}" + else + service_name="$service_spec" + local_port="" + fi + + # Find service in oc-app namespace + local svc + svc=$(kubectl --context "$cluster" -n oc-app get svc -o name | grep "^service/$service_name$" || true) + + if [[ -z "$svc" ]]; then + echo "⚠️ Service '$service_name' not found in namespace 'oc-app' - skipping" + echo " Available services:" + kubectl --context "$cluster" -n oc-app get svc -o name | sed 's/service\// - /' | head -5 + continue + fi + + local name="${svc#service/}" + local service_port + service_port=$(kubectl --context "$cluster" -n oc-app get "svc/$name" -o jsonpath='{.spec.ports[0].port}') + local forward_port="${local_port:-$service_port}" + + # Check if port is in use + local port_info + port_info=$(lsof -i :$forward_port 2>/dev/null) + if [[ -n "$port_info" ]]; then + local pid=$(echo "$port_info" | tail -n +2 | awk '{print $2}' | head -1) + local process=$(echo "$port_info" | tail -n +2 | awk '{print $1}' | head -1) + echo "⚠️ Port $forward_port in use by $process (PID: $pid) - skipping $name" + continue + fi + + # Start port-forward + if [[ -n "$local_port" ]]; then + echo "→ Forwarding $name (service port $service_port) to local port $forward_port" + else + echo "→ Forwarding $name on port $forward_port" + fi + + kubectl --context "$cluster" -n oc-app port-forward "svc/$name" "$forward_port:$service_port" >/dev/null 2>&1 & + local pid=$! + + # Verify port-forward started successfully + sleep 0.5 + if ! kill -0 $pid 2>/dev/null; then + echo "❌ Failed to start port-forward for $name on port $forward_port" + continue + fi + + pids+=($pid) + done + + if [[ ${#pids[@]} -eq 0 ]]; then + echo "❌ No port-forwards were started successfully" return 1 fi - echo "Starting kubefwd for cluster: $cluster" - sudo -E kubefwd svc -n "${namespace}" -x "${cluster}" ${svc_filter} + echo "→ All forwards running (PIDs: ${pids[*]})" + echo "→ Press Ctrl+C to stop" + + # Handle Ctrl+C cleanup + trap 'echo; echo "🛑 Stopping port-forwards..."; for pid in ${pids[*]}; do kill $pid 2>/dev/null; done; sleep 1; for pid in ${pids[*]}; do kill -9 $pid 2>/dev/null; done; wait ${pids[*]} 2>/dev/null; return 0' INT + + wait } + # ============================================================================= # SYSTEM AND UTILITY FUNCTIONS # ============================================================================= diff --git a/zsh/.config/zsh/init.zsh b/zsh/.config/zsh/init.zsh index 0aec90c..009297f 100644 --- a/zsh/.config/zsh/init.zsh +++ b/zsh/.config/zsh/init.zsh @@ -3,6 +3,7 @@ mkdir -p "$PLUGIN_DIR" # Install plugins (only if missing) plugins=( + "blimmer/zsh-aws-vault" "romkatv/zsh-defer" "zsh-users/zsh-autosuggestions" "hlissner/zsh-autopair" @@ -63,6 +64,7 @@ done source "$PLUGIN_DIR/zsh-defer/zsh-defer.plugin.zsh" # Defer heavy plugins for faster startup +source "$PLUGIN_DIR/zsh-aws-vault/zsh-aws-vault.plugin.zsh" zsh-defer source "$PLUGIN_DIR/zsh-autosuggestions/zsh-autosuggestions.zsh" zsh-defer source "$PLUGIN_DIR/zsh-autopair/autopair.zsh" zsh-defer source "$PLUGIN_DIR/zsh-history-substring-search/zsh-history-substring-search.zsh" diff --git a/zsh/.config/zsh/opts.zsh b/zsh/.config/zsh/opts.zsh index e56589b..778c467 100644 --- a/zsh/.config/zsh/opts.zsh +++ b/zsh/.config/zsh/opts.zsh @@ -27,17 +27,19 @@ if [[ ! -f "$HISTFILE" ]]; then chmod 644 "$HISTFILE" # More permissive permissions fi -# Additional history safeguards -# Backup history on each session start (only if file is significantly large) -if [[ -f "$HISTFILE" && -w "$HISTFILE" ]]; then - # Create backup if history file is large enough (> 10KB) to avoid frequent small backups - if [[ $(stat -f%z "$HISTFILE" 2>/dev/null || stat -c%s "$HISTFILE" 2>/dev/null) -gt 10240 ]]; then - cp "$HISTFILE" "${HISTFILE}.bak" 2>/dev/null || true - fi -fi +# AWS Vault configuration +export AWS_VAULT_PL_MFA=inline +export AWS_VAULT_PL_CHAR="󰅟 " + +prompt_aws_vault() { + local vault_segment + vault_segment="`prompt_aws_vault_segment`" + if [[ $vault_segment != '' ]]; then + echo -n " %F{yellow}$vault_segment%f" + fi +} -# Minimal prompt configuration MNML_INFOLN=() -MNML_PROMPT=(mnml_ssh mnml_status 'mnml_cwd 2 0' mnml_git mnml_keymap ) +MNML_PROMPT=( mnml_ssh mnml_status 'mnml_cwd 2 0' mnml_git prompt_aws_vault mnml_keymap ) MNML_RPROMPT=() MNML_NORMAL_CHAR="◉"