cli-utils/cmd/printers/json/formatter.go

162 lines
4.5 KiB
Go

// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package json
import (
"encoding/json"
"fmt"
"time"
"k8s.io/cli-runtime/pkg/genericclioptions"
"sigs.k8s.io/cli-utils/pkg/apply/event"
"sigs.k8s.io/cli-utils/pkg/common"
"sigs.k8s.io/cli-utils/pkg/object"
"sigs.k8s.io/cli-utils/pkg/print/list"
)
func NewFormatter(ioStreams genericclioptions.IOStreams,
previewStrategy common.DryRunStrategy) list.Formatter {
return &formatter{
ioStreams: ioStreams,
previewStrategy: previewStrategy,
}
}
type formatter struct {
previewStrategy common.DryRunStrategy
ioStreams genericclioptions.IOStreams
}
func (jf *formatter) FormatApplyEvent(ae event.ApplyEvent, as *list.ApplyStats, c list.Collector) error {
switch ae.Type {
case event.ApplyEventCompleted:
if err := jf.printEvent("apply", "completed", map[string]interface{}{
"count": as.Sum(),
"createdCount": as.Created,
"unchangedCount": as.Unchanged,
"configuredCount": as.Configured,
"serverSideCount": as.ServersideApplied,
"failedCount": as.Failed,
}); err != nil {
return err
}
for id, se := range c.LatestStatus() {
if err := jf.printResourceStatus(id, se); err != nil {
return err
}
}
case event.ApplyEventResourceUpdate:
gk := ae.Identifier.GroupKind
return jf.printEvent("apply", "resourceApplied", map[string]interface{}{
"group": gk.Group,
"kind": gk.Kind,
"namespace": ae.Identifier.Namespace,
"name": ae.Identifier.Name,
"operation": ae.Operation.String(),
})
}
return nil
}
func (jf *formatter) FormatStatusEvent(se event.StatusEvent, _ list.Collector) error {
if se.Type == event.StatusEventResourceUpdate {
id := se.Resource.Identifier
return jf.printResourceStatus(id, se)
}
return nil
}
func (jf *formatter) printResourceStatus(id object.ObjMetadata, se event.StatusEvent) error {
return jf.printEvent("status", "resourceStatus",
map[string]interface{}{
"group": id.GroupKind.Group,
"kind": id.GroupKind.Kind,
"namespace": id.Namespace,
"name": id.Name,
"status": se.Resource.Status.String(),
"message": se.Resource.Message,
})
}
func (jf *formatter) FormatPruneEvent(pe event.PruneEvent, ps *list.PruneStats) error {
switch pe.Type {
case event.PruneEventCompleted:
return jf.printEvent("prune", "completed", map[string]interface{}{
"pruned": ps.Pruned,
"skipped": ps.Skipped,
})
case event.PruneEventResourceUpdate:
gk := pe.Identifier.GroupKind
return jf.printEvent("prune", "resourcePruned", map[string]interface{}{
"group": gk.Group,
"kind": gk.Kind,
"namespace": pe.Identifier.Namespace,
"name": pe.Identifier.Name,
"operation": pe.Operation.String(),
})
case event.PruneEventFailed:
gk := pe.Identifier.GroupKind
return jf.printEvent("prune", "resourceFailed", map[string]interface{}{
"group": gk.Group,
"kind": gk.Kind,
"namespace": pe.Identifier.Namespace,
"name": pe.Identifier.Name,
"error": pe.Error.Error(),
})
}
return nil
}
func (jf *formatter) FormatDeleteEvent(de event.DeleteEvent, ds *list.DeleteStats) error {
switch de.Type {
case event.DeleteEventCompleted:
return jf.printEvent("delete", "completed", map[string]interface{}{
"deleted": ds.Deleted,
"skipped": ds.Skipped,
})
case event.DeleteEventResourceUpdate:
gk := de.Identifier.GroupKind
return jf.printEvent("delete", "resourceDeleted", map[string]interface{}{
"group": gk.Group,
"kind": gk.Kind,
"namespace": de.Identifier.Namespace,
"name": de.Identifier.Name,
"operation": de.Operation.String(),
})
case event.DeleteEventFailed:
gk := de.Identifier.GroupKind
return jf.printEvent("delete", "resourceFailed", map[string]interface{}{
"group": gk.Group,
"kind": gk.Kind,
"namespace": de.Identifier.Namespace,
"name": de.Identifier.Name,
"error": de.Error.Error(),
})
}
return nil
}
func (jf *formatter) FormatErrorEvent(ee event.ErrorEvent) error {
return jf.printEvent("error", "error", map[string]interface{}{
"error": ee.Err.Error(),
})
}
func (jf *formatter) printEvent(t, eventType string, content map[string]interface{}) error {
m := make(map[string]interface{})
m["timestamp"] = time.Now().UTC().Format(time.RFC3339)
m["type"] = t
m["eventType"] = eventType
for key, val := range content {
m[key] = val
}
b, err := json.Marshal(m)
if err != nil {
return err
}
_, err = fmt.Fprint(jf.ioStreams.Out, string(b)+"\n")
return err
}