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:
50
cmd/cmd.go
50
cmd/cmd.go
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user