diff --git a/lib/utils/jsontools.go b/lib/utils/jsontools.go index 951f89b34a9..c421869f460 100644 --- a/lib/utils/jsontools.go +++ b/lib/utils/jsontools.go @@ -18,6 +18,7 @@ package utils import ( "bytes" + "encoding/json" "io" "reflect" "unicode" @@ -100,6 +101,14 @@ func FastMarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { return data, nil } +// WriteJSON marshals multiple documents as a JSON list with indentation. +func WriteJSON(w io.Writer, values interface{}) error { + encoder := json.NewEncoder(w) + encoder.SetIndent("", " ") + err := encoder.Encode(values) + return trace.Wrap(err) +} + const yamlDocDelimiter = "---" // WriteYAML detects whether value is a list diff --git a/tool/tctl/common/collection.go b/tool/tctl/common/collection.go index 9b7b5977c79..d29c8e65a46 100644 --- a/tool/tctl/common/collection.go +++ b/tool/tctl/common/collection.go @@ -17,7 +17,6 @@ limitations under the License. package common import ( - "encoding/json" "fmt" "io" "sort" @@ -157,17 +156,12 @@ func (s *serverCollection) writeText(w io.Writer) error { return trace.Wrap(err) } -func (s *serverCollection) writeYaml(w io.Writer) error { +func (s *serverCollection) writeYAML(w io.Writer) error { return utils.WriteYAML(w, s.servers) } func (s *serverCollection) writeJSON(w io.Writer) error { - data, err := json.MarshalIndent(s.resources(), "", " ") - if err != nil { - return trace.Wrap(err) - } - _, err = w.Write(data) - return trace.Wrap(err) + return utils.WriteJSON(w, s.servers) } type userCollection struct { @@ -437,12 +431,7 @@ func formatLastHeartbeat(t time.Time) string { } func writeJSON(c ResourceCollection, w io.Writer) error { - data, err := json.MarshalIndent(c.resources(), "", " ") - if err != nil { - return trace.Wrap(err) - } - _, err = w.Write(data) - return trace.Wrap(err) + return utils.WriteJSON(w, c.resources()) } func writeYAML(c ResourceCollection, w io.Writer) error { @@ -506,20 +495,11 @@ func (a *appServerCollection) writeText(w io.Writer) error { } func (a *appServerCollection) writeJSON(w io.Writer) error { - data, err := json.MarshalIndent(a.toMarshal(), "", " ") - if err != nil { - return trace.Wrap(err) - } - _, err = w.Write(data) - return trace.Wrap(err) -} - -func (a *appServerCollection) toMarshal() interface{} { - return a.servers + return utils.WriteJSON(w, a.servers) } func (a *appServerCollection) writeYAML(w io.Writer) error { - return utils.WriteYAML(w, a.toMarshal()) + return utils.WriteYAML(w, a.servers) } type appCollection struct { @@ -676,20 +656,11 @@ func (c *databaseServerCollection) writeText(w io.Writer) error { } func (c *databaseServerCollection) writeJSON(w io.Writer) error { - data, err := json.MarshalIndent(c.toMarshal(), "", " ") - if err != nil { - return trace.Wrap(err) - } - _, err = w.Write(data) - return trace.Wrap(err) -} - -func (c *databaseServerCollection) toMarshal() interface{} { - return c.servers + return utils.WriteJSON(w, c.servers) } func (c *databaseServerCollection) writeYAML(w io.Writer) error { - return utils.WriteYAML(w, c.toMarshal()) + return utils.WriteYAML(w, c.servers) } type databaseCollection struct { @@ -837,12 +808,7 @@ func (c *windowsDesktopAndServiceCollection) writeYAML(w io.Writer) error { } func (c *windowsDesktopAndServiceCollection) writeJSON(w io.Writer) error { - data, err := json.MarshalIndent(c.desktops, "", " ") - if err != nil { - return trace.Wrap(err) - } - _, err = w.Write(data) - return trace.Wrap(err) + return utils.WriteJSON(w, c.desktops) } type tokenCollection struct { @@ -911,12 +877,7 @@ func (c *kubeServerCollection) writeYAML(w io.Writer) error { } func (c *kubeServerCollection) writeJSON(w io.Writer) error { - data, err := json.MarshalIndent(c.servers, "", " ") - if err != nil { - return trace.Wrap(err) - } - _, err = w.Write(data) - return trace.Wrap(err) + return utils.WriteJSON(w, c.servers) } type kubeClusterCollection struct { diff --git a/tool/tctl/common/node_command.go b/tool/tctl/common/node_command.go index 36d7431d662..9a448e176c7 100644 --- a/tool/tctl/common/node_command.go +++ b/tool/tctl/common/node_command.go @@ -208,7 +208,7 @@ func (c *NodeCommand) Invite(ctx context.Context, client auth.ClientI) error { return nil } -// ListActive retreives the list of nodes who recently sent heartbeats to +// ListActive retrieves the list of nodes who recently sent heartbeats to // to a cluster and prints it to stdout func (c *NodeCommand) ListActive(ctx context.Context, clt auth.ClientI) error { labels, err := libclient.ParseLabelSpec(c.labels) @@ -244,7 +244,7 @@ func (c *NodeCommand) ListActive(ctx context.Context, clt auth.ClientI) error { return trace.Wrap(err) } case teleport.YAML: - if err := coll.writeYaml(os.Stdout); err != nil { + if err := coll.writeYAML(os.Stdout); err != nil { return trace.Wrap(err) } case teleport.JSON: diff --git a/tool/tsh/tsh.go b/tool/tsh/tsh.go index 0847f83b90d..8c0f142ec17 100644 --- a/tool/tsh/tsh.go +++ b/tool/tsh/tsh.go @@ -1271,18 +1271,21 @@ func exportSession(cf *CLIConf) error { // when playing from a file, id is not included, this // makes the outputs otherwise identical delete(event, "id") - var e []byte - var err error - if format == teleport.JSON { - e, err = utils.FastMarshal(event) - } else { - e, err = yaml.Marshal(event) - } - if err != nil { + } + + switch format { + case teleport.JSON: + if err := utils.WriteJSON(os.Stdout, events); err != nil { return trace.Wrap(err) } - fmt.Println(string(e)) + case teleport.YAML: + if err := utils.WriteYAML(os.Stdout, events); err != nil { + return trace.Wrap(err) + } + default: + return trace.Errorf("Invalid format %s, only pty, json and yaml are supported", format) } + return nil }