#!/usr/bin/env bash # # Copyright (C) 2020, Maxim Lihachev, # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation, version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # : <<'MAN' =head1 NAME kubectl-compare allows to juxtapose kubernetes resources with any diff-like utilities. =head1 USAGE kubectl compare [-n|--namespace NAMESPACE] [-t|--type] [-e|--edit|-v|--visual] name1 name2 or kubectl compare [-e|--edit|-v|--visual] namespace/type/name1 namespace/type/name2 or kubectl compare [-e|--edit|-v|--visual] namespace/type/name1 namespace/type/name2 namespace/type/name3 ... =head1 OPTIONS -n --namespace Kubernetes namespace for search ('default' by default). -t --type Kubernetes resource's type, e.g. pod, svc, configmap, etc ('pod' by default). -e --edit, -v --visual Open diff in visual editor (e.g. vimdiff). Set B environment variable or provide its value in script's file (kubectl-compare) to specify utility which will be used. To specify main diff program set B variable (its default value is I<'diff -u --color=always'>). Use something like I to compare 3 manifests. =head1 EXAMPLE $ kubectl compare -n zookeeper -t pod zookeeper-0 zookeeper-1 $ kubectl compare -n zookeeper pod/zookeeper-0 pod/zookeeper-1 $ kubectl compare zookeeper/pod/zookeeper-0 zookeeper/pod/zookeeper-1 ^ ^ ^ [namespace]---+ | | [type]----+ | [name]--+ $ kubectl compare zookeeper/pod/zookeeper-{0,1,2} =head1 BUGS If you find a bug, please report it at B>. =head1 AUTHORS envrm B>. =cut MAN set -o pipefail if [ -z "$DIFF_CMD" ]; then DIFF_CMD="diff -u --color=always" fi if [ -z "$VISUAL_DIFF_CMD" ]; then VISUAL_DIFF_CMD="vim -d --cmd 'autocmd BufRead * set filetype=yaml'" fi # Default Kubernetes namespace NAMESPACE=default # Default Kubernetes resource TYPE=pod usage() { sed -E -n '/^.*MAN/,/^MAN$/{//!p;}; /^MAN$/q' "$0" | sed -E 's/=head. |[LIBC]<|\b>*//g; /=cut/d' exit "${1:-0}" } die() { >&2 echo "ERROR: $*" exit 1 } kubecmd() { IFS='/' read -r -a item <<< "$(sed -E 's:^/|/$::g' <<<"$1")" case ${#item[@]} in 1) kubectl_cmd="kubectl --namespace $NAMESPACE get $TYPE ${item[0]} -o yaml";; 2) kubectl_cmd="kubectl --namespace $NAMESPACE get ${item[0]} ${item[1]} -o yaml";; 3) kubectl_cmd="kubectl --namespace ${item[0]} get ${item[1]} ${item[2]} -o yaml";; *) exit 1;; esac echo "<(${kubectl_cmd[*]})" } #-------------------------------------------------------------------------- POSITIONAL=() while [[ $# -gt 0 ]]; do key="$1" case $key in -h|--help) usage;; -e|--edit|-v|--visual) DIFF_CMD=$VISUAL_DIFF_CMD; shift;; -n|--namespace) NAMESPACE="$2"; shift; shift;; -t|--type) TYPE="$2"; shift; shift;; *) POSITIONAL+=("$1"); shift;; esac done set -- "${POSITIONAL[@]}" diff_cmd=("$DIFF_CMD") if [ $# -lt 2 ]; then usage 1 fi for cmd in "$@"; do diff_cmd+=($(kubecmd "$cmd")) || die "Excessive nestedness of Kubernetes resource: $cmd" done eval "${diff_cmd[*]}"