Skip to content

Commit 0d674c4

Browse files
committed
cmd: silence warnings in kube-controller-manager/kube-apiserver, dedupe/color warnings in kubectl
1 parent e4bb1da commit 0d674c4

File tree

5 files changed

+72
-1
lines changed

5 files changed

+72
-1
lines changed

cmd/kube-apiserver/app/server.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import (
5353
"k8s.io/apiserver/pkg/util/webhook"
5454
clientgoinformers "k8s.io/client-go/informers"
5555
clientgoclientset "k8s.io/client-go/kubernetes"
56+
"k8s.io/client-go/rest"
5657
"k8s.io/client-go/util/keyutil"
5758
cloudprovider "k8s.io/cloud-provider"
5859
cliflag "k8s.io/component-base/cli/flag"
@@ -100,6 +101,12 @@ cluster's shared state through which all other components interact.`,
100101

101102
// stop printing usage when the command errors
102103
SilenceUsage: true,
104+
PersistentPreRunE: func(*cobra.Command, []string) error {
105+
// silence client-go warnings.
106+
// kube-apiserver loopback clients should not log self-issued warnings.
107+
rest.SetDefaultWarningHandler(rest.NoWarnings{})
108+
return nil
109+
},
103110
RunE: func(cmd *cobra.Command, args []string) error {
104111
verflag.PrintAndExitIfRequested()
105112
cliflag.PrintFlags(cmd.Flags())

cmd/kube-controller-manager/app/controllermanager.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ state of the cluster through the apiserver and makes changes attempting to move
104104
current state towards the desired state. Examples of controllers that ship with
105105
Kubernetes today are the replication controller, endpoints controller, namespace
106106
controller, and serviceaccounts controller.`,
107+
PersistentPreRunE: func(*cobra.Command, []string) error {
108+
// silence client-go warnings.
109+
// kube-controller-manager generically watches APIs (including deprecated ones),
110+
// and CI ensures it works properly against matching kube-apiserver versions.
111+
restclient.SetDefaultWarningHandler(restclient.NoWarnings{})
112+
return nil
113+
},
107114
Run: func(cmd *cobra.Command, args []string) {
108115
verflag.PrintAndExitIfRequested()
109116
cliflag.PrintFlags(cmd.Flags())

pkg/kubectl/cmd/cmd.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828

2929
"github.com/spf13/cobra"
3030

31+
"k8s.io/client-go/rest"
3132
"k8s.io/client-go/tools/clientcmd"
3233
cliflag "k8s.io/component-base/cli/flag"
3334
cmdpkg "k8s.io/kubectl/pkg/cmd"
@@ -69,6 +70,7 @@ import (
6970
"k8s.io/kubectl/pkg/cmd/wait"
7071
"k8s.io/kubectl/pkg/util/i18n"
7172
"k8s.io/kubectl/pkg/util/templates"
73+
"k8s.io/kubectl/pkg/util/term"
7274
"k8s.io/kubernetes/pkg/kubectl/cmd/auth"
7375
"k8s.io/kubernetes/pkg/kubectl/cmd/convert"
7476
"k8s.io/kubernetes/pkg/kubectl/cmd/cp"
@@ -428,6 +430,9 @@ func HandlePluginCommand(pluginHandler PluginHandler, cmdArgs []string) error {
428430

429431
// NewKubectlCommand creates the `kubectl` command and its nested children.
430432
func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
433+
warningHandler := rest.NewWarningWriter(err, rest.WarningWriterOptions{Deduplicate: true, Color: term.AllowsColorOutput(err)})
434+
warningsAsErrors := false
435+
431436
// Parent command to which all subcommands are added.
432437
cmds := &cobra.Command{
433438
Use: "kubectl",
@@ -441,10 +446,25 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
441446
// Hook before and after Run initialize and write profiles to disk,
442447
// respectively.
443448
PersistentPreRunE: func(*cobra.Command, []string) error {
449+
rest.SetDefaultWarningHandler(warningHandler)
444450
return initProfiling()
445451
},
446452
PersistentPostRunE: func(*cobra.Command, []string) error {
447-
return flushProfiling()
453+
if err := flushProfiling(); err != nil {
454+
return err
455+
}
456+
if warningsAsErrors {
457+
count := warningHandler.WarningCount()
458+
switch count {
459+
case 0:
460+
// no warnings
461+
case 1:
462+
return fmt.Errorf("%d warning received", count)
463+
default:
464+
return fmt.Errorf("%d warnings received", count)
465+
}
466+
}
467+
return nil
448468
},
449469
BashCompletionFunction: bashCompletionFunc,
450470
}
@@ -458,6 +478,8 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
458478

459479
addProfilingFlags(flags)
460480

481+
flags.BoolVar(&warningsAsErrors, "warnings-as-errors", warningsAsErrors, "Treat warnings received from the server as errors and exit with a non-zero exit code")
482+
461483
kubeConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag()
462484
kubeConfigFlags.AddFlags(flags)
463485
matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags)

staging/src/k8s.io/kubectl/pkg/util/term/term.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package term
1919
import (
2020
"io"
2121
"os"
22+
"runtime"
2223

2324
"github.com/moby/term"
2425

@@ -70,6 +71,32 @@ func IsTerminal(i interface{}) bool {
7071
return terminal
7172
}
7273

74+
// AllowsColorOutput returns true if the specified writer is a terminal and
75+
// the process environment indicates color output is supported and desired.
76+
func AllowsColorOutput(w io.Writer) bool {
77+
if !IsTerminal(w) {
78+
return false
79+
}
80+
81+
// https://en.wikipedia.org/wiki/Computer_terminal#Dumb_terminals
82+
if os.Getenv("TERM") == "dumb" {
83+
return false
84+
}
85+
86+
// https://no-color.org/
87+
if _, nocolor := os.LookupEnv("NO_COLOR"); nocolor {
88+
return false
89+
}
90+
91+
// On Windows WT_SESSION is set by the modern terminal component.
92+
// Older terminals have poor support for UTF-8, VT escape codes, etc.
93+
if runtime.GOOS == "windows" && os.Getenv("WT_SESSION") == "" {
94+
return false
95+
}
96+
97+
return true
98+
}
99+
73100
// Safe invokes the provided function and will attempt to ensure that when the
74101
// function returns (or a termination signal is sent) that the terminal state
75102
// is reset to the condition it was in prior to the function being invoked. If

test/cmd/rbac.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,14 @@ run_role_tests() {
145145
create_and_use_new_namespace
146146
kube::log::status "Testing role"
147147

148+
# Test deprecated API request output
149+
# TODO(liggitt): switch this to a custom deprecated resource once CRDs support marking versions as deprecated
150+
output_message=$(kubectl get roles.v1beta1.rbac.authorization.k8s.io 2>&1 "${kube_flags[@]}")
151+
kube::test::if_has_string "${output_message}" 'Role is deprecated'
152+
output_message=$(! kubectl get roles.v1beta1.rbac.authorization.k8s.io --warnings-as-errors 2>&1 "${kube_flags[@]}")
153+
kube::test::if_has_string "${output_message}" 'Role is deprecated'
154+
kube::test::if_has_string "${output_message}" 'Error: 1 warning received'
155+
148156
# Dry-run create
149157
kubectl create "${kube_flags[@]}" role pod-admin --dry-run=client --verb=* --resource=pods
150158
kubectl create "${kube_flags[@]}" role pod-admin --dry-run=server --verb=* --resource=pods

0 commit comments

Comments
 (0)