kubectl-diff: Return non-1 errors on kubectl failures
Currently, diff AND kubectl can return 1 errors either when diff finds differences, or when kubectl fails something. It also prints an ugly error when diff finds a differences, since 1 is treated as an error. Two things this PR does: 1. If diff returns 1, then do not treat it as an error, and exit with exit code 1. It no longer prints the ugly error. 2. Kubectl errors are +1'd so that they never return 1 which shouldn't be considered an error. We need to update the documentation accordingly, to mention that `KUBECTL_EXTERNAL_DIFF` programs must also follow the convention of using one as their exit code for changes detected. Kubernetes-commit: f2b21f08d95291212ba8987aa9d446c02a96089a
This commit is contained in:
parent
b7a70f9cb8
commit
4c36396b35
|
@ -68,6 +68,15 @@ var (
|
|||
// Number of times we try to diff before giving-up
|
||||
const maxRetries = 4
|
||||
|
||||
// diffError returns the ExitError if the status code is less than 1,
|
||||
// nil otherwise.
|
||||
func diffError(err error) exec.ExitError {
|
||||
if err, ok := err.(exec.ExitError); ok && err.ExitStatus() <= 1 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DiffOptions struct {
|
||||
FilenameOptions resource.FilenameOptions
|
||||
|
||||
|
@ -109,9 +118,20 @@ func NewCmdDiff(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.C
|
|||
Long: diffLong,
|
||||
Example: diffExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(options.Complete(f, cmd))
|
||||
cmdutil.CheckErr(validateArgs(cmd, args))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
cmdutil.CheckDiffErr(options.Complete(f, cmd))
|
||||
cmdutil.CheckDiffErr(validateArgs(cmd, args))
|
||||
// `kubectl diff` propagates the error code from
|
||||
// diff or `KUBECTL_EXTERNAL_DIFF`. Also, we
|
||||
// don't want to print an error if diff returns
|
||||
// error code 1, which simply means that changes
|
||||
// were found. We also don't want kubectl to
|
||||
// return 1 if there was a problem.
|
||||
if err := options.Run(); err != nil {
|
||||
if exitErr := diffError(err); exitErr != nil {
|
||||
os.Exit(exitErr.ExitStatus())
|
||||
}
|
||||
cmdutil.CheckDiffErr(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -150,6 +170,11 @@ func (d *DiffProgram) getCommand(args ...string) (string, exec.Cmd) {
|
|||
func (d *DiffProgram) Run(from, to string) error {
|
||||
diff, cmd := d.getCommand(from, to)
|
||||
if err := cmd.Run(); err != nil {
|
||||
// Let's not wrap diff errors, or we won't be able to
|
||||
// differentiate them later.
|
||||
if diffErr := diffError(err); diffErr != nil {
|
||||
return diffErr
|
||||
}
|
||||
return fmt.Errorf("failed to run %q: %v", diff, err)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -115,6 +115,18 @@ func CheckErr(err error) {
|
|||
checkErr(err, fatalErrHandler)
|
||||
}
|
||||
|
||||
// CheckDiffErr prints a user friendly error to STDERR and exits with a
|
||||
// non-zero and non-one exit code. Unrecognized errors will be printed
|
||||
// with an "error: " prefix.
|
||||
//
|
||||
// This method is meant specifically for `kubectl diff` and may be used
|
||||
// by other commands.
|
||||
func CheckDiffErr(err error) {
|
||||
checkErr(err, func(msg string, code int) {
|
||||
fatalErrHandler(msg, code+1)
|
||||
})
|
||||
}
|
||||
|
||||
// checkErr formats a given error as a string and calls the passed handleErr
|
||||
// func with that string and an kubectl exit code.
|
||||
func checkErr(err error, handleErr func(string, int)) {
|
||||
|
|
Loading…
Reference in New Issue