...

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

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

     1  // Copyright 2020 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package json
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"strings"
    10  	"time"
    11  
    12  	"k8s.io/cli-runtime/pkg/genericclioptions"
    13  	"sigs.k8s.io/cli-utils/cmd/status/printers/printer"
    14  	"sigs.k8s.io/cli-utils/pkg/apply/event"
    15  	"sigs.k8s.io/cli-utils/pkg/common"
    16  	"sigs.k8s.io/cli-utils/pkg/kstatus/polling/collector"
    17  	pollevent "sigs.k8s.io/cli-utils/pkg/kstatus/polling/event"
    18  	"sigs.k8s.io/cli-utils/pkg/object"
    19  	"sigs.k8s.io/cli-utils/pkg/print/list"
    20  	jsonprinter "sigs.k8s.io/cli-utils/pkg/printers/json"
    21  )
    22  
    23  // Printer implements the Printer interface and outputs the resource
    24  // status information as a list of events as they happen.
    25  type Printer struct {
    26  	Formatter list.Formatter
    27  	IOStreams genericclioptions.IOStreams
    28  	Data      *printer.PrintData
    29  }
    30  
    31  // NewPrinter returns a new instance of the eventPrinter.
    32  func NewPrinter(ioStreams genericclioptions.IOStreams, printData *printer.PrintData) *Printer {
    33  	return &Printer{
    34  		Formatter: jsonprinter.NewFormatter(ioStreams, common.DryRunNone),
    35  		IOStreams: ioStreams,
    36  		Data:      printData,
    37  	}
    38  }
    39  
    40  // Print takes an event channel and outputs the status events on the channel
    41  // until the channel is closed. The provided cancelFunc is consulted on
    42  // every event and is responsible for stopping the poller when appropriate.
    43  // This function will block.
    44  func (ep *Printer) Print(ch <-chan pollevent.Event, identifiers object.ObjMetadataSet,
    45  	cancelFunc collector.ObserverFunc) error {
    46  	coll := collector.NewResourceStatusCollector(identifiers)
    47  	// The actual work is done by the collector, which will invoke the
    48  	// callback on every event. In the callback we print the status
    49  	// information and call the cancelFunc which is responsible for
    50  	// stopping the poller at the correct time.
    51  	done := coll.ListenWithObserver(ch, collector.ObserverFunc(
    52  		func(statusCollector *collector.ResourceStatusCollector, e pollevent.Event) {
    53  			err := ep.printStatusEvent(e)
    54  			if err != nil {
    55  				panic(err)
    56  			}
    57  			cancelFunc(statusCollector, e)
    58  		}),
    59  	)
    60  	// Listen to the channel until it is closed.
    61  	var err error
    62  	for msg := range done {
    63  		err = msg.Err
    64  	}
    65  	return err
    66  }
    67  
    68  func (ep *Printer) printStatusEvent(se pollevent.Event) error {
    69  	switch se.Type {
    70  	case pollevent.ResourceUpdateEvent:
    71  		id := se.Resource.Identifier
    72  		var invName string
    73  		var ok bool
    74  		if invName, ok = ep.Data.InvNameMap[id]; !ok {
    75  			return fmt.Errorf("%s: resource not found", id)
    76  		}
    77  		// filter out status that are not assigned
    78  		statusString := se.Resource.Status.String()
    79  		if _, ok := ep.Data.StatusSet[strings.ToLower(statusString)]; len(ep.Data.StatusSet) != 0 && !ok {
    80  			return nil
    81  		}
    82  		eventInfo := ep.createJSONObj(id)
    83  		eventInfo["inventory-name"] = invName
    84  		eventInfo["status"] = statusString
    85  		eventInfo["message"] = se.Resource.Message
    86  		b, err := json.Marshal(eventInfo)
    87  		if err != nil {
    88  			return err
    89  		}
    90  		_, err = fmt.Fprintf(ep.IOStreams.Out, "%s\n", string(b))
    91  		return err
    92  	case pollevent.ErrorEvent:
    93  		return ep.Formatter.FormatErrorEvent(event.ErrorEvent{
    94  			Err: se.Error,
    95  		})
    96  	}
    97  	return nil
    98  }
    99  
   100  func (ep *Printer) createJSONObj(id object.ObjMetadata) map[string]interface{} {
   101  	return map[string]interface{}{
   102  		"group":     id.GroupKind.Group,
   103  		"kind":      id.GroupKind.Kind,
   104  		"namespace": id.Namespace,
   105  		"name":      id.Name,
   106  		"timestamp": time.Now().UTC().Format(time.RFC3339),
   107  		"type":      "status",
   108  	}
   109  }
   110  

View as plain text