...

Source file src/sigs.k8s.io/cli-utils/cmd/status/printers/table/printer.go

Documentation: sigs.k8s.io/cli-utils/cmd/status/printers/table

     1  // Copyright 2020 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package table
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"time"
    10  
    11  	"k8s.io/cli-runtime/pkg/genericclioptions"
    12  	"sigs.k8s.io/cli-utils/cmd/status/printers/printer"
    13  	"sigs.k8s.io/cli-utils/pkg/kstatus/polling/collector"
    14  	"sigs.k8s.io/cli-utils/pkg/kstatus/polling/event"
    15  	"sigs.k8s.io/cli-utils/pkg/object"
    16  	"sigs.k8s.io/cli-utils/pkg/print/table"
    17  )
    18  
    19  const (
    20  	// updateInterval defines how often the printer will update the UI.
    21  	updateInterval = 1 * time.Second
    22  )
    23  
    24  // Printer is an implementation of the Printer interface that outputs
    25  // status information about resources in a table format with in-place updates.
    26  type Printer struct {
    27  	IOStreams genericclioptions.IOStreams
    28  	PrintData *printer.PrintData
    29  }
    30  
    31  // NewPrinter returns a new instance of the tablePrinter.
    32  func NewPrinter(ioStreams genericclioptions.IOStreams, printData *printer.PrintData) *Printer {
    33  	return &Printer{
    34  		IOStreams: ioStreams,
    35  		PrintData: printData,
    36  	}
    37  }
    38  
    39  // Print take an event channel and outputs the status events on the channel
    40  // until the channel is closed .
    41  func (t *Printer) Print(ch <-chan event.Event, identifiers object.ObjMetadataSet,
    42  	cancelFunc collector.ObserverFunc) error {
    43  	coll := collector.NewResourceStatusCollector(identifiers)
    44  	stop := make(chan struct{})
    45  
    46  	// Start the goroutine that is responsible for
    47  	// printing the latest state on a regular cadence.
    48  	printCompleted := t.runPrintLoop(&CollectorAdapter{
    49  		collector:  coll,
    50  		invNameMap: t.PrintData.InvNameMap,
    51  		statusSet:  t.PrintData.StatusSet,
    52  	}, stop)
    53  
    54  	// Make the collector start listening on the eventChannel.
    55  	done := coll.ListenWithObserver(ch, cancelFunc)
    56  
    57  	// Block until all the collector has shut down. This means the
    58  	// eventChannel has been closed and all events have been processed.
    59  	var err error
    60  	for msg := range done {
    61  		err = msg.Err
    62  	}
    63  
    64  	// Close the stop channel to notify the print goroutine that it should
    65  	// shut down.
    66  	close(stop)
    67  
    68  	// Wait until the printCompleted channel is closed. This means
    69  	// the printer has updated the UI with the latest state and
    70  	// exited from the goroutine.
    71  	<-printCompleted
    72  	return err
    73  }
    74  
    75  var invNameColumn = table.ColumnDef{
    76  	ColumnName:   "inventory_name",
    77  	ColumnHeader: "INVENTORY_NAME",
    78  	ColumnWidth:  30,
    79  	PrintResourceFunc: func(w io.Writer, width int, r table.Resource) (int, error) {
    80  		group := r.(*ResourceInfo).invName
    81  		if len(group) > width {
    82  			group = group[:width]
    83  		}
    84  		_, err := fmt.Fprint(w, group)
    85  		return len(group), err
    86  	},
    87  }
    88  
    89  var columns = []table.ColumnDefinition{
    90  	table.MustColumn("namespace"),
    91  	table.MustColumn("resource"),
    92  	table.MustColumn("status"),
    93  	table.MustColumn("conditions"),
    94  	table.MustColumn("age"),
    95  	table.MustColumn("message"),
    96  	invNameColumn,
    97  }
    98  
    99  // Print prints the table of resources with their statuses until the
   100  // provided stop channel is closed.
   101  func (t *Printer) runPrintLoop(coll *CollectorAdapter, stop <-chan struct{}) <-chan struct{} {
   102  	finished := make(chan struct{})
   103  
   104  	baseTablePrinter := table.BaseTablePrinter{
   105  		IOStreams: t.IOStreams,
   106  		Columns:   columns,
   107  	}
   108  
   109  	linesPrinted := baseTablePrinter.PrintTable(coll.LatestStatus(), 0)
   110  
   111  	go func() {
   112  		defer close(finished)
   113  		ticker := time.NewTicker(updateInterval)
   114  		for {
   115  			select {
   116  			case <-stop:
   117  				ticker.Stop()
   118  				linesPrinted = baseTablePrinter.PrintTable(
   119  					coll.LatestStatus(), linesPrinted)
   120  				return
   121  			case <-ticker.C:
   122  				linesPrinted = baseTablePrinter.PrintTable(
   123  					coll.LatestStatus(), linesPrinted)
   124  			}
   125  		}
   126  	}()
   127  
   128  	return finished
   129  }
   130  

View as plain text