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

Commit 929c6e2

Browse files
jeremyrickardcarolynvs
authored andcommitted
Add JSON and YAML output to svcat (#1944)
* 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
1 parent c1cb328 commit 929c6e2

36 files changed

+1226
-36
lines changed

cmd/svcat/binding/get_cmd.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ import (
2424

2525
type getCmd struct {
2626
*command.Namespaced
27-
name string
27+
name string
28+
outputFormat string
29+
}
30+
31+
func (c *getCmd) SetFormat(format string) {
32+
c.outputFormat = format
2833
}
2934

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

4752
command.AddNamespaceFlags(cmd.Flags(), true)
48-
53+
command.AddOutputFlags(cmd.Flags())
4954
return cmd
5055
}
5156

@@ -71,7 +76,7 @@ func (c *getCmd) getAll() error {
7176
return err
7277
}
7378

74-
output.WriteBindingList(c.Output, bindings.Items...)
79+
output.WriteBindingList(c.Output, c.outputFormat, bindings)
7580
return nil
7681
}
7782

@@ -81,6 +86,6 @@ func (c *getCmd) get() error {
8186
return err
8287
}
8388

84-
output.WriteBindingList(c.Output, *binding)
89+
output.WriteBinding(c.Output, c.outputFormat, *binding)
8590
return nil
8691
}

cmd/svcat/broker/get_cmd.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ import (
2424

2525
type getCmd struct {
2626
*command.Context
27-
name string
27+
name string
28+
outputFormat string
29+
}
30+
31+
func (c *getCmd) SetFormat(format string) {
32+
c.outputFormat = format
2833
}
2934

3035
// NewGetCmd builds a "svcat get brokers" command
@@ -41,7 +46,7 @@ func NewGetCmd(cxt *command.Context) *cobra.Command {
4146
PreRunE: command.PreRunE(getCmd),
4247
RunE: command.RunE(getCmd),
4348
}
44-
49+
command.AddOutputFlags(cmd.Flags())
4550
return cmd
4651
}
4752

@@ -67,7 +72,7 @@ func (c *getCmd) getAll() error {
6772
return err
6873
}
6974

70-
output.WriteBrokerList(c.Output, brokers...)
75+
output.WriteBrokerList(c.Output, c.outputFormat, brokers...)
7176
return nil
7277
}
7378

@@ -77,6 +82,6 @@ func (c *getCmd) get() error {
7782
return err
7883
}
7984

80-
output.WriteBrokerList(c.Output, *broker)
85+
output.WriteBroker(c.Output, c.outputFormat, *broker)
8186
return nil
8287
}

cmd/svcat/class/get_cmd.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ type getCmd struct {
2828
lookupByUUID bool
2929
uuid string
3030
name string
31+
outputFormat string
32+
}
33+
34+
func (c *getCmd) SetFormat(format string) {
35+
c.outputFormat = format
3136
}
3237

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

@@ -81,7 +87,7 @@ func (c *getCmd) getAll() error {
8187
return err
8288
}
8389

84-
output.WriteClassList(c.Output, classes...)
90+
output.WriteClassList(c.Output, c.outputFormat, classes...)
8591
return nil
8692
}
8793

@@ -98,6 +104,6 @@ func (c *getCmd) get() error {
98104
return err
99105
}
100106

101-
output.WriteClassList(c.Output, *class)
107+
output.WriteClass(c.Output, c.outputFormat, *class)
102108
return nil
103109
}

cmd/svcat/command/command.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ limitations under the License.
1717
package command
1818

1919
import (
20+
"fmt"
2021
"github.com/spf13/cobra"
2122
"github.com/spf13/pflag"
23+
"strings"
2224
)
2325

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

46+
// FormattedCommand represents a command that can have it's output
47+
// formatted
48+
type FormattedCommand interface {
49+
// SetFormat sets the commands output format
50+
SetFormat(format string)
51+
}
52+
4453
// PreRunE validates os args, and then saves them on the svcat command.
4554
func PreRunE(cmd Command) func(*cobra.Command, []string) error {
4655
return func(c *cobra.Command, args []string) error {
4756
if nsCmd, ok := cmd.(NamespacedCommand); ok {
4857
namespace := DetermineNamespace(c.Flags(), nsCmd.GetContext().App.CurrentNamespace)
4958
nsCmd.SetNamespace(namespace)
5059
}
60+
if fmtCmd, ok := cmd.(FormattedCommand); ok {
61+
fmtString, err := determineOutputFormat(c.Flags())
62+
if err != nil {
63+
return err
64+
}
65+
fmtCmd.SetFormat(fmtString)
66+
}
5167
return cmd.Validate(args)
5268
}
5369
}
@@ -93,3 +109,29 @@ func DetermineNamespace(flags *pflag.FlagSet, currentNamespace string) string {
93109

94110
return currentNamespace
95111
}
112+
113+
// AddOutputFlags adds common output flags to a command that can have variable output formats.
114+
func AddOutputFlags(flags *pflag.FlagSet) {
115+
flags.StringP(
116+
"output",
117+
"o",
118+
"",
119+
"The output format to use. Valid options are table, json or yaml. If not present, defaults to table",
120+
)
121+
}
122+
123+
func determineOutputFormat(flags *pflag.FlagSet) (string, error) {
124+
format, _ := flags.GetString("output")
125+
format = strings.ToLower(format)
126+
127+
switch format {
128+
case "", "table":
129+
return "table", nil
130+
case "json":
131+
return "json", nil
132+
case "yaml":
133+
return "yaml", nil
134+
default:
135+
return "", fmt.Errorf("invalid --output format %q, allowed values are table, json and yaml", format)
136+
}
137+
}

cmd/svcat/instance/get_cmd.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ import (
2424

2525
type getCmd struct {
2626
*command.Namespaced
27-
name string
27+
name string
28+
outputFormat string
29+
}
30+
31+
func (c *getCmd) SetFormat(format string) {
32+
c.outputFormat = format
2833
}
2934

3035
// NewGetCmd builds a "svcat get instances" command
@@ -44,6 +49,7 @@ func NewGetCmd(cxt *command.Context) *cobra.Command {
4449
RunE: command.RunE(getCmd),
4550
}
4651
command.AddNamespaceFlags(cmd.Flags(), true)
52+
command.AddOutputFlags(cmd.Flags())
4753
return cmd
4854
}
4955

@@ -69,7 +75,7 @@ func (c *getCmd) getAll() error {
6975
return err
7076
}
7177

72-
output.WriteInstanceList(c.Output, instances.Items...)
78+
output.WriteInstanceList(c.Output, c.outputFormat, instances)
7379
return nil
7480
}
7581

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

82-
output.WriteInstanceList(c.Output, *instance)
88+
output.WriteInstance(c.Output, c.outputFormat, *instance)
89+
8390
return nil
8491
}

cmd/svcat/output/binding.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ func getBindingStatusFull(status v1beta1.ServiceBindingStatus) string {
4040
return formatStatusFull(string(lastCond.Type), lastCond.Status, lastCond.Reason, lastCond.Message, lastCond.LastTransitionTime)
4141
}
4242

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

53-
for _, binding := range bindings {
52+
for _, binding := range bindingList.Items {
5453
t.Append([]string{
5554
binding.Name,
5655
binding.Namespace,
5756
binding.Spec.ServiceInstanceRef.Name,
5857
getBindingStatusShort(binding.Status),
5958
})
6059
}
61-
6260
t.Render()
6361
}
6462

63+
// WriteBindingList prints a list of bindings in the specified output format.
64+
func WriteBindingList(w io.Writer, outputFormat string, bindingList *v1beta1.ServiceBindingList) {
65+
switch outputFormat {
66+
case formatJSON:
67+
writeJSON(w, bindingList)
68+
case formatYAML:
69+
writeYAML(w, bindingList, 0)
70+
case formatTable:
71+
writeBindingListTable(w, bindingList)
72+
}
73+
}
74+
75+
// WriteBinding prints a single bindings in the specified output format.
76+
func WriteBinding(w io.Writer, outputFormat string, binding v1beta1.ServiceBinding) {
77+
switch outputFormat {
78+
case formatJSON:
79+
writeJSON(w, binding)
80+
case formatYAML:
81+
writeYAML(w, binding, 0)
82+
case formatTable:
83+
l := v1beta1.ServiceBindingList{
84+
Items: []v1beta1.ServiceBinding{binding},
85+
}
86+
writeBindingListTable(w, &l)
87+
}
88+
}
89+
6590
// WriteBindingDetails prints details for a single binding.
6691
func WriteBindingDetails(w io.Writer, binding *v1beta1.ServiceBinding) {
6792
t := NewDetailsTable(w)

cmd/svcat/output/broker.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ func getBrokerStatusFull(status v1beta1.ClusterServiceBrokerStatus) string {
4040
return formatStatusFull(string(lastCond.Type), lastCond.Status, lastCond.Reason, lastCond.Message, lastCond.LastTransitionTime)
4141
}
4242

43-
// WriteBrokerList prints a list of brokers.
44-
func WriteBrokerList(w io.Writer, brokers ...v1beta1.ClusterServiceBroker) {
43+
func writeBrokerListTable(w io.Writer, brokers []v1beta1.ClusterServiceBroker) {
4544
t := NewListTable(w)
4645
t.SetHeader([]string{
4746
"Name",
@@ -58,6 +57,33 @@ func WriteBrokerList(w io.Writer, brokers ...v1beta1.ClusterServiceBroker) {
5857
t.Render()
5958
}
6059

60+
// WriteBrokerList prints a list of brokers in the specified output format.
61+
func WriteBrokerList(w io.Writer, outputFormat string, brokers ...v1beta1.ClusterServiceBroker) {
62+
l := v1beta1.ClusterServiceBrokerList{
63+
Items: brokers,
64+
}
65+
switch outputFormat {
66+
case formatJSON:
67+
writeJSON(w, l)
68+
case formatYAML:
69+
writeYAML(w, l, 0)
70+
case formatTable:
71+
writeBrokerListTable(w, brokers)
72+
}
73+
}
74+
75+
// WriteBroker prints a broker in the specified output format.
76+
func WriteBroker(w io.Writer, outputFormat string, broker v1beta1.ClusterServiceBroker) {
77+
switch outputFormat {
78+
case formatJSON:
79+
writeJSON(w, broker)
80+
case formatYAML:
81+
writeYAML(w, broker, 0)
82+
case formatTable:
83+
writeBrokerListTable(w, []v1beta1.ClusterServiceBroker{broker})
84+
}
85+
}
86+
6187
// WriteParentBroker prints identifying information for a parent broker.
6288
func WriteParentBroker(w io.Writer, broker *v1beta1.ClusterServiceBroker) {
6389
fmt.Fprintln(w, "\nBroker:")

cmd/svcat/output/class.go

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ limitations under the License.
1717
package output
1818

1919
import (
20+
"encoding/json"
2021
"fmt"
2122
"io"
2223
"strings"
2324

25+
"github.com/ghodss/yaml"
2426
"github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog/v1beta1"
2527
)
2628

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

34-
// WriteClassList prints a list of classes.
35-
func WriteClassList(w io.Writer, classes ...v1beta1.ClusterServiceClass) {
36+
func writeClassListTable(w io.Writer, classes []v1beta1.ClusterServiceClass) {
3637
t := NewListTable(w)
3738
t.SetHeader([]string{
3839
"Name",
@@ -49,6 +50,49 @@ func WriteClassList(w io.Writer, classes ...v1beta1.ClusterServiceClass) {
4950
t.Render()
5051
}
5152

53+
func writeClassListJSON(w io.Writer, classes []v1beta1.ClusterServiceClass) {
54+
classList := v1beta1.ClusterServiceClassList{
55+
Items: classes,
56+
}
57+
j, _ := json.MarshalIndent(classList, "", " ")
58+
w.Write(j)
59+
}
60+
61+
func writeClassListYAML(w io.Writer, classes []v1beta1.ClusterServiceClass) {
62+
classList := v1beta1.ClusterServiceClassList{
63+
Items: classes,
64+
}
65+
y, _ := yaml.Marshal(classList)
66+
w.Write(y)
67+
}
68+
69+
// WriteClassList prints a list of classes in the specified output format.
70+
func WriteClassList(w io.Writer, outputFormat string, classes ...v1beta1.ClusterServiceClass) {
71+
classList := v1beta1.ClusterServiceClassList{
72+
Items: classes,
73+
}
74+
switch outputFormat {
75+
case formatJSON:
76+
writeJSON(w, classList)
77+
case formatYAML:
78+
writeYAML(w, classList, 0)
79+
case formatTable:
80+
writeClassListTable(w, classes)
81+
}
82+
}
83+
84+
// WriteClass prints a single class in the specified output format.
85+
func WriteClass(w io.Writer, outputFormat string, class v1beta1.ClusterServiceClass) {
86+
switch outputFormat {
87+
case formatJSON:
88+
writeJSON(w, class)
89+
case formatYAML:
90+
writeYAML(w, class, 0)
91+
case formatTable:
92+
writeClassListTable(w, []v1beta1.ClusterServiceClass{class})
93+
}
94+
}
95+
5296
// WriteParentClass prints identifying information for a parent class.
5397
func WriteParentClass(w io.Writer, class *v1beta1.ClusterServiceClass) {
5498
fmt.Fprintln(w, "\nClass:")

0 commit comments

Comments
 (0)