Skip to content
This repository has been archived by the owner on May 6, 2022. It is now read-only.

Commit

Permalink
Add JSON and YAML output to svcat (#1944)
Browse files Browse the repository at this point in the history
* Initial WIP commit for adding JSON/YAML output to svcat

This adds JSON/YAML output to svcat, but does not currently include
the Type Metadata, so we lose the Kind/GroupVersion info.

* Adding JSON and YAML output capabilities

Note: This is not 100% complete. Right now, we do not obtain the
metav1.TypeMeta within svcat. We will need to figure out how to
populate this.

See: kubernetes/client-go#308 (comment)

Fixes: #1814

* Code review comments

* Code review comments

* Added boilerplate on json.go
  • Loading branch information
jeremyrickard authored and carolynvs committed Apr 19, 2018
1 parent c1cb328 commit 929c6e2
Show file tree
Hide file tree
Showing 36 changed files with 1,226 additions and 36 deletions.
13 changes: 9 additions & 4 deletions cmd/svcat/binding/get_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ import (

type getCmd struct {
*command.Namespaced
name string
name string
outputFormat string
}

func (c *getCmd) SetFormat(format string) {
c.outputFormat = format
}

// NewGetCmd builds a "svcat get bindings" command
Expand All @@ -45,7 +50,7 @@ func NewGetCmd(cxt *command.Context) *cobra.Command {
}

command.AddNamespaceFlags(cmd.Flags(), true)

command.AddOutputFlags(cmd.Flags())
return cmd
}

Expand All @@ -71,7 +76,7 @@ func (c *getCmd) getAll() error {
return err
}

output.WriteBindingList(c.Output, bindings.Items...)
output.WriteBindingList(c.Output, c.outputFormat, bindings)
return nil
}

Expand All @@ -81,6 +86,6 @@ func (c *getCmd) get() error {
return err
}

output.WriteBindingList(c.Output, *binding)
output.WriteBinding(c.Output, c.outputFormat, *binding)
return nil
}
13 changes: 9 additions & 4 deletions cmd/svcat/broker/get_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ import (

type getCmd struct {
*command.Context
name string
name string
outputFormat string
}

func (c *getCmd) SetFormat(format string) {
c.outputFormat = format
}

// NewGetCmd builds a "svcat get brokers" command
Expand All @@ -41,7 +46,7 @@ func NewGetCmd(cxt *command.Context) *cobra.Command {
PreRunE: command.PreRunE(getCmd),
RunE: command.RunE(getCmd),
}

command.AddOutputFlags(cmd.Flags())
return cmd
}

Expand All @@ -67,7 +72,7 @@ func (c *getCmd) getAll() error {
return err
}

output.WriteBrokerList(c.Output, brokers...)
output.WriteBrokerList(c.Output, c.outputFormat, brokers...)
return nil
}

Expand All @@ -77,6 +82,6 @@ func (c *getCmd) get() error {
return err
}

output.WriteBrokerList(c.Output, *broker)
output.WriteBroker(c.Output, c.outputFormat, *broker)
return nil
}
10 changes: 8 additions & 2 deletions cmd/svcat/class/get_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ type getCmd struct {
lookupByUUID bool
uuid string
name string
outputFormat string
}

func (c *getCmd) SetFormat(format string) {
c.outputFormat = format
}

// NewGetCmd builds a "svcat get classes" command
Expand All @@ -52,6 +57,7 @@ func NewGetCmd(cxt *command.Context) *cobra.Command {
false,
"Whether or not to get the class by UUID (the default is by name)",
)
command.AddOutputFlags(cmd.Flags())
return cmd
}

Expand Down Expand Up @@ -81,7 +87,7 @@ func (c *getCmd) getAll() error {
return err
}

output.WriteClassList(c.Output, classes...)
output.WriteClassList(c.Output, c.outputFormat, classes...)
return nil
}

Expand All @@ -98,6 +104,6 @@ func (c *getCmd) get() error {
return err
}

output.WriteClassList(c.Output, *class)
output.WriteClass(c.Output, c.outputFormat, *class)
return nil
}
42 changes: 42 additions & 0 deletions cmd/svcat/command/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ limitations under the License.
package command

import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"strings"
)

// Command represents an svcat command.
Expand All @@ -41,13 +43,27 @@ type NamespacedCommand interface {
SetNamespace(namespace string)
}

// FormattedCommand represents a command that can have it's output
// formatted
type FormattedCommand interface {
// SetFormat sets the commands output format
SetFormat(format string)
}

// PreRunE validates os args, and then saves them on the svcat command.
func PreRunE(cmd Command) func(*cobra.Command, []string) error {
return func(c *cobra.Command, args []string) error {
if nsCmd, ok := cmd.(NamespacedCommand); ok {
namespace := DetermineNamespace(c.Flags(), nsCmd.GetContext().App.CurrentNamespace)
nsCmd.SetNamespace(namespace)
}
if fmtCmd, ok := cmd.(FormattedCommand); ok {
fmtString, err := determineOutputFormat(c.Flags())
if err != nil {
return err
}
fmtCmd.SetFormat(fmtString)
}
return cmd.Validate(args)
}
}
Expand Down Expand Up @@ -93,3 +109,29 @@ func DetermineNamespace(flags *pflag.FlagSet, currentNamespace string) string {

return currentNamespace
}

// AddOutputFlags adds common output flags to a command that can have variable output formats.
func AddOutputFlags(flags *pflag.FlagSet) {
flags.StringP(
"output",
"o",
"",
"The output format to use. Valid options are table, json or yaml. If not present, defaults to table",
)
}

func determineOutputFormat(flags *pflag.FlagSet) (string, error) {
format, _ := flags.GetString("output")
format = strings.ToLower(format)

switch format {
case "", "table":
return "table", nil
case "json":
return "json", nil
case "yaml":
return "yaml", nil
default:
return "", fmt.Errorf("invalid --output format %q, allowed values are table, json and yaml", format)
}
}
13 changes: 10 additions & 3 deletions cmd/svcat/instance/get_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ import (

type getCmd struct {
*command.Namespaced
name string
name string
outputFormat string
}

func (c *getCmd) SetFormat(format string) {
c.outputFormat = format
}

// NewGetCmd builds a "svcat get instances" command
Expand All @@ -44,6 +49,7 @@ func NewGetCmd(cxt *command.Context) *cobra.Command {
RunE: command.RunE(getCmd),
}
command.AddNamespaceFlags(cmd.Flags(), true)
command.AddOutputFlags(cmd.Flags())
return cmd
}

Expand All @@ -69,7 +75,7 @@ func (c *getCmd) getAll() error {
return err
}

output.WriteInstanceList(c.Output, instances.Items...)
output.WriteInstanceList(c.Output, c.outputFormat, instances)
return nil
}

Expand All @@ -79,6 +85,7 @@ func (c *getCmd) get() error {
return err
}

output.WriteInstanceList(c.Output, *instance)
output.WriteInstance(c.Output, c.outputFormat, *instance)

return nil
}
33 changes: 29 additions & 4 deletions cmd/svcat/output/binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ func getBindingStatusFull(status v1beta1.ServiceBindingStatus) string {
return formatStatusFull(string(lastCond.Type), lastCond.Status, lastCond.Reason, lastCond.Message, lastCond.LastTransitionTime)
}

// WriteBindingList prints a list of bindings.
func WriteBindingList(w io.Writer, bindings ...v1beta1.ServiceBinding) {
func writeBindingListTable(w io.Writer, bindingList *v1beta1.ServiceBindingList) {
t := NewListTable(w)
t.SetHeader([]string{
"Name",
Expand All @@ -50,18 +49,44 @@ func WriteBindingList(w io.Writer, bindings ...v1beta1.ServiceBinding) {
"Status",
})

for _, binding := range bindings {
for _, binding := range bindingList.Items {
t.Append([]string{
binding.Name,
binding.Namespace,
binding.Spec.ServiceInstanceRef.Name,
getBindingStatusShort(binding.Status),
})
}

t.Render()
}

// WriteBindingList prints a list of bindings in the specified output format.
func WriteBindingList(w io.Writer, outputFormat string, bindingList *v1beta1.ServiceBindingList) {
switch outputFormat {
case formatJSON:
writeJSON(w, bindingList)
case formatYAML:
writeYAML(w, bindingList, 0)
case formatTable:
writeBindingListTable(w, bindingList)
}
}

// WriteBinding prints a single bindings in the specified output format.
func WriteBinding(w io.Writer, outputFormat string, binding v1beta1.ServiceBinding) {
switch outputFormat {
case formatJSON:
writeJSON(w, binding)
case formatYAML:
writeYAML(w, binding, 0)
case formatTable:
l := v1beta1.ServiceBindingList{
Items: []v1beta1.ServiceBinding{binding},
}
writeBindingListTable(w, &l)
}
}

// WriteBindingDetails prints details for a single binding.
func WriteBindingDetails(w io.Writer, binding *v1beta1.ServiceBinding) {
t := NewDetailsTable(w)
Expand Down
30 changes: 28 additions & 2 deletions cmd/svcat/output/broker.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ func getBrokerStatusFull(status v1beta1.ClusterServiceBrokerStatus) string {
return formatStatusFull(string(lastCond.Type), lastCond.Status, lastCond.Reason, lastCond.Message, lastCond.LastTransitionTime)
}

// WriteBrokerList prints a list of brokers.
func WriteBrokerList(w io.Writer, brokers ...v1beta1.ClusterServiceBroker) {
func writeBrokerListTable(w io.Writer, brokers []v1beta1.ClusterServiceBroker) {
t := NewListTable(w)
t.SetHeader([]string{
"Name",
Expand All @@ -58,6 +57,33 @@ func WriteBrokerList(w io.Writer, brokers ...v1beta1.ClusterServiceBroker) {
t.Render()
}

// WriteBrokerList prints a list of brokers in the specified output format.
func WriteBrokerList(w io.Writer, outputFormat string, brokers ...v1beta1.ClusterServiceBroker) {
l := v1beta1.ClusterServiceBrokerList{
Items: brokers,
}
switch outputFormat {
case formatJSON:
writeJSON(w, l)
case formatYAML:
writeYAML(w, l, 0)
case formatTable:
writeBrokerListTable(w, brokers)
}
}

// WriteBroker prints a broker in the specified output format.
func WriteBroker(w io.Writer, outputFormat string, broker v1beta1.ClusterServiceBroker) {
switch outputFormat {
case formatJSON:
writeJSON(w, broker)
case formatYAML:
writeYAML(w, broker, 0)
case formatTable:
writeBrokerListTable(w, []v1beta1.ClusterServiceBroker{broker})
}
}

// WriteParentBroker prints identifying information for a parent broker.
func WriteParentBroker(w io.Writer, broker *v1beta1.ClusterServiceBroker) {
fmt.Fprintln(w, "\nBroker:")
Expand Down
48 changes: 46 additions & 2 deletions cmd/svcat/output/class.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ limitations under the License.
package output

import (
"encoding/json"
"fmt"
"io"
"strings"

"github.com/ghodss/yaml"
"github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog/v1beta1"
)

Expand All @@ -31,8 +33,7 @@ func getClassStatusText(status v1beta1.ClusterServiceClassStatus) string {
return statusActive
}

// WriteClassList prints a list of classes.
func WriteClassList(w io.Writer, classes ...v1beta1.ClusterServiceClass) {
func writeClassListTable(w io.Writer, classes []v1beta1.ClusterServiceClass) {
t := NewListTable(w)
t.SetHeader([]string{
"Name",
Expand All @@ -49,6 +50,49 @@ func WriteClassList(w io.Writer, classes ...v1beta1.ClusterServiceClass) {
t.Render()
}

func writeClassListJSON(w io.Writer, classes []v1beta1.ClusterServiceClass) {
classList := v1beta1.ClusterServiceClassList{
Items: classes,
}
j, _ := json.MarshalIndent(classList, "", " ")
w.Write(j)
}

func writeClassListYAML(w io.Writer, classes []v1beta1.ClusterServiceClass) {
classList := v1beta1.ClusterServiceClassList{
Items: classes,
}
y, _ := yaml.Marshal(classList)
w.Write(y)
}

// WriteClassList prints a list of classes in the specified output format.
func WriteClassList(w io.Writer, outputFormat string, classes ...v1beta1.ClusterServiceClass) {
classList := v1beta1.ClusterServiceClassList{
Items: classes,
}
switch outputFormat {
case formatJSON:
writeJSON(w, classList)
case formatYAML:
writeYAML(w, classList, 0)
case formatTable:
writeClassListTable(w, classes)
}
}

// WriteClass prints a single class in the specified output format.
func WriteClass(w io.Writer, outputFormat string, class v1beta1.ClusterServiceClass) {
switch outputFormat {
case formatJSON:
writeJSON(w, class)
case formatYAML:
writeYAML(w, class, 0)
case formatTable:
writeClassListTable(w, []v1beta1.ClusterServiceClass{class})
}
}

// WriteParentClass prints identifying information for a parent class.
func WriteParentClass(w io.Writer, class *v1beta1.ClusterServiceClass) {
fmt.Fprintln(w, "\nClass:")
Expand Down
Loading

0 comments on commit 929c6e2

Please sign in to comment.