Add --watch flag to stream unready pod changes

Adds a -w/--watch flag that keeps running after the initial list,
streaming Added/Modified pod events and printing rows without headers
for a continuous view of unready pods.
This commit is contained in:
Max Jonas Werner
2026-04-20 10:58:27 +02:00
parent 7cabca2ade
commit 7fc48f63f0

View File

@@ -11,6 +11,7 @@ import (
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/duration" "k8s.io/apimachinery/pkg/util/duration"
kwatch "k8s.io/apimachinery/pkg/watch"
"k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers" "k8s.io/cli-runtime/pkg/printers"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
@@ -19,6 +20,7 @@ import (
func NewUnreadyCmd(ctx context.Context) *cobra.Command { func NewUnreadyCmd(ctx context.Context) *cobra.Command {
var kubernetesConfigFlags *genericclioptions.ConfigFlags var kubernetesConfigFlags *genericclioptions.ConfigFlags
var allNamespacesFlag bool var allNamespacesFlag bool
var watchFlag bool
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "unready", Use: "unready",
@@ -27,7 +29,7 @@ func NewUnreadyCmd(ctx context.Context) *cobra.Command {
if kubernetesConfigFlags.Namespace == nil || *kubernetesConfigFlags.Namespace == "" { if kubernetesConfigFlags.Namespace == nil || *kubernetesConfigFlags.Namespace == "" {
kubernetesConfigFlags.Namespace = new("default") kubernetesConfigFlags.Namespace = new("default")
} }
return run(ctx, kubernetesConfigFlags, allNamespacesFlag) return run(ctx, kubernetesConfigFlags, allNamespacesFlag, watchFlag)
}, },
} }
@@ -35,13 +37,14 @@ func NewUnreadyCmd(ctx context.Context) *cobra.Command {
kubernetesConfigFlags.AddFlags(cmd.Flags()) kubernetesConfigFlags.AddFlags(cmd.Flags())
cmd.Flags().BoolVarP(&allNamespacesFlag, "all-namespaces", "A", false, "If present, list unready pods across all namespaces.") cmd.Flags().BoolVarP(&allNamespacesFlag, "all-namespaces", "A", false, "If present, list unready pods across all namespaces.")
cmd.Flags().BoolVarP(&watchFlag, "watch", "w", false, "Watch for changes to unready pods.")
cmd.AddCommand(version.NewVersionCmd(ctx)) cmd.AddCommand(version.NewVersionCmd(ctx))
return cmd return cmd
} }
func run(ctx context.Context, configFlags *genericclioptions.ConfigFlags, allNamespaces bool) error { func run(ctx context.Context, configFlags *genericclioptions.ConfigFlags, allNamespaces bool, doWatch bool) error {
config, err := configFlags.ToRESTConfig() config, err := configFlags.ToRESTConfig()
if err != nil { if err != nil {
return fmt.Errorf("failed to read kubeconfig: %w", err) return fmt.Errorf("failed to read kubeconfig: %w", err)
@@ -63,17 +66,52 @@ func run(ctx context.Context, configFlags *genericclioptions.ConfigFlags, allNam
} }
filtered := make([]corev1.Pod, 0) filtered := make([]corev1.Pod, 0)
for _, pod := range pods.Items { for _, pod := range pods.Items {
if isNotReady(pod) { if isNotReady(pod) {
filtered = append(filtered, pod) filtered = append(filtered, pod)
} }
} }
return print(filtered) if err := printPods(filtered, false); err != nil {
return err
}
if !doWatch {
return nil
}
watcher, err := clientset.CoreV1().Pods(namespace).Watch(ctx, metav1.ListOptions{
ResourceVersion: pods.ResourceVersion,
})
if err != nil {
return fmt.Errorf("failed watching Pods: %w", err)
}
defer watcher.Stop()
for {
select {
case <-ctx.Done():
return nil
case event, ok := <-watcher.ResultChan():
if !ok {
return nil
}
pod, ok := event.Object.(*corev1.Pod)
if !ok {
continue
}
if event.Type == kwatch.Added || event.Type == kwatch.Modified {
if isNotReady(*pod) {
if err := printPods([]corev1.Pod{*pod}, true); err != nil {
return err
}
}
}
}
}
} }
func print(pods []corev1.Pod) error { func printPods(pods []corev1.Pod, noHeaders bool) error {
table := metav1.Table{ table := metav1.Table{
ColumnDefinitions: []metav1.TableColumnDefinition{ ColumnDefinitions: []metav1.TableColumnDefinition{
{Name: "Namespace"}, {Name: "Namespace"},
@@ -95,7 +133,7 @@ func print(pods []corev1.Pod) error {
}) })
} }
printer := printers.NewTablePrinter(printers.PrintOptions{}) printer := printers.NewTablePrinter(printers.PrintOptions{NoHeaders: noHeaders})
return printer.PrintObj(&table, os.Stdout) return printer.PrintObj(&table, os.Stdout)
} }