Skip to content

Commit a556452

Browse files
authored
Merge pull request #2 from bigcommerce/INFRA-6309
INFRA-6309: Add ability to output into json
2 parents e479d17 + 81d87fd commit a556452

20 files changed

Lines changed: 654 additions & 227 deletions

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ The changelog for Bonvoy
22

33
## Pending Release
44

5+
* Add `-o json` to output data into a JSON output format
56
* Adjust `server restart` to restart the Nomad allocation rather than killing Envoy.
67
This allows for a more graceful degradation of traffic to the service.
78
* Add cluster filter to `clusters list` to only show a specific cluster

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ Connect and Nomad environment.
1010
There are various commands you can run. Usually you are required to pass the
1111
name of the service you want to query the sidecar for.
1212

13+
All commands have the ability to output in JSON format with: `-o json`
14+
1315
### Listeners
1416

1517
List all listeners:
1618
```bash
17-
bonvoy listeners auth-grpc
19+
bonvoy listeners list auth-grpc
1820
```
1921

2022
### Clusters

commands/certificates.go

Lines changed: 107 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ import (
44
"bonvoy/consul"
55
"bonvoy/envoy"
66
"fmt"
7-
"github.com/fatih/color"
87
"github.com/olekukonko/tablewriter"
98
"github.com/spf13/cast"
109
"github.com/spf13/cobra"
11-
"os"
10+
"strings"
1211
)
1312

1413
type Certificates struct {
@@ -27,6 +26,10 @@ func (r *Registry) Certificates() *Certificates {
2726
}
2827
}
2928

29+
/***********************************************************************************************************************
30+
* certificates list [service]
31+
**********************************************************************************************************************/
32+
3033
func (r *Registry) BuildCertificatesListCommand() *cobra.Command {
3134
return &cobra.Command{
3235
Use: "list",
@@ -38,7 +41,10 @@ func (r *Registry) BuildCertificatesListCommand() *cobra.Command {
3841
ServiceName: args[0],
3942
Consul: consul.NewClient(),
4043
}
41-
return controller.Run()
44+
o, cErr := controller.Run()
45+
if cErr != nil { return cErr }
46+
47+
return r.Output(o)
4248
},
4349
}
4450
}
@@ -48,35 +54,53 @@ type CertificatesListController struct {
4854
Consul consul.Client
4955
}
5056

51-
func (c *CertificatesListController) Run() error {
57+
func (c *CertificatesListController) Run() (ListCertificatesResponse, error) {
58+
resp := ListCertificatesResponse{
59+
ServiceName: c.ServiceName,
60+
}
5261
e, err := envoy.NewFromServiceName(c.ServiceName)
53-
if err != nil { return err }
62+
if err != nil { return resp, err }
63+
64+
resp.Envoy = &e
5465

5566
certs, cErr := e.Certificates().Get()
56-
if cErr != nil { return cErr }
67+
if cErr != nil { return resp, cErr }
5768

58-
_, _ = color.New(color.FgGreen).Add(color.Bold).Println(c.ServiceName + " Envoy (PID " + cast.ToString(e.Pid) + ")")
59-
color.Green("-----------------------------------------------------------")
69+
var certificateChains []envoy.Certificate
70+
var caCertificates []envoy.Certificate
6071

6172
for _, r := range certs.Certificates {
62-
// Certs
63-
color.Green("CertificateChain")
64-
color.Green("--------------------------------")
65-
err = c.DisplayCertificateList(r.CertificateChain)
66-
if err != nil { return err }
67-
68-
// CA certs
69-
fmt.Println("")
70-
color.Green("CA Certificates")
71-
color.Green("-------------------------------")
72-
err = c.DisplayCertificateList(r.CaCertificates)
73-
if err != nil { return err }
73+
certificateChains = append(certificateChains, r.CertificateChain...)
74+
caCertificates = append(caCertificates, r.CaCertificates...)
7475
}
75-
return nil
76+
resp.CertificateChains = certificateChains
77+
resp.CaCertificates = caCertificates
78+
return resp, nil
79+
}
80+
81+
type ListCertificatesResponse struct {
82+
ServiceName string `json:"service"`
83+
Envoy *envoy.Instance `json:"envoy"`
84+
CertificateChains []envoy.Certificate`json:"certificate_chains"`
85+
CaCertificates []envoy.Certificate`json:"ca_certificates"`
86+
}
87+
88+
func (r ListCertificatesResponse) String() string {
89+
o := ""
90+
o += Ok("----------------------------------------------------------------------------")
91+
o += Ok(r.ServiceName + " Envoy (PID " + cast.ToString(r.Envoy.Pid) + ")")
92+
o += Ok("----------------------------------------------------------------------------")
93+
o += Info("Certificate Chains:")
94+
o += r.DisplayCertificateList(r.CertificateChains)
95+
o += Info("")
96+
o += Info("CA Certificates:")
97+
o += r.DisplayCertificateList(r.CaCertificates)
98+
return o
7699
}
77100

78-
func (c * CertificatesListController) DisplayCertificateList(certs []envoy.Certificate) error {
79-
table := tablewriter.NewWriter(os.Stdout)
101+
func (r *ListCertificatesResponse) DisplayCertificateList(certs []envoy.Certificate) string {
102+
tableString := &strings.Builder{}
103+
table := tablewriter.NewWriter(tableString)
80104
table.SetHeader([]string{
81105
"SAN",
82106
"Serial #",
@@ -106,11 +130,12 @@ func (c * CertificatesListController) DisplayCertificateList(certs []envoy.Certi
106130
table.AppendBulk(car)
107131
table.SetAlignment(tablewriter.ALIGN_LEFT)
108132
table.Render()
109-
return nil
133+
return tableString.String()
110134
}
111135

112-
// certificates expired
113-
136+
/***********************************************************************************************************************
137+
* certificates expired [service]
138+
**********************************************************************************************************************/
114139
func (r *Registry) BuildCertificatesExpiredCommand() *cobra.Command {
115140
cmd := &cobra.Command{
116141
Use: "expired",
@@ -125,7 +150,10 @@ func (r *Registry) BuildCertificatesExpiredCommand() *cobra.Command {
125150
restart, err := cmd.Flags().GetBool("restart")
126151
if err != nil { return err }
127152

128-
return controller.Run(restart)
153+
o, cErr := controller.Run(restart)
154+
if cErr != nil { return cErr }
155+
156+
return r.Output(o)
129157
},
130158
}
131159
cmd.Flags().BoolP("restart", "r", false, "If passed, will restart all sidecars that have expired certificates")
@@ -137,45 +165,83 @@ type CertificatesExpiredController struct {
137165
Consul consul.Client
138166
}
139167

140-
func (c *CertificatesExpiredController) Run(restart bool) error {
168+
type FindExpiredCertificatesResponse struct {
169+
ExpiredCertificates []envoy.ExpiredCertificate `json:"expiredCertificates"`
170+
restart bool
171+
}
172+
173+
func (r FindExpiredCertificatesResponse) String() string {
174+
tableString := &strings.Builder{}
175+
table := tablewriter.NewWriter(tableString)
176+
table.SetHeader([]string{
177+
"Service",
178+
"PID",
179+
"Envoy Expiry",
180+
"Days Left",
181+
"Consul Leaf Expiry",
182+
"Restarted",
183+
})
184+
restartStr := "NO"
185+
if r.restart { restartStr = "YES" }
186+
187+
var d [][]string
188+
for _, e := range r.ExpiredCertificates {
189+
d = append(d, []string{
190+
e.ServiceName,
191+
fmt.Sprintf("%d", e.Pid),
192+
e.EnvoyExpiration,
193+
fmt.Sprintf("%d", e.EnvoyDaysUntilExpiration),
194+
e.ConsulExpiration,
195+
restartStr,
196+
})
197+
}
198+
199+
table.SetBorder(false)
200+
table.SetTablePadding("\t")
201+
table.AppendBulk(d)
202+
table.SetAlignment(tablewriter.ALIGN_RIGHT)
203+
table.Render()
204+
return tableString.String()
205+
}
206+
207+
func (c *CertificatesExpiredController) Run(restart bool) (FindExpiredCertificatesResponse, error) {
141208
var expiredCerts []envoy.ExpiredCertificate
142209
var sidecars []envoy.Instance
210+
runResp := FindExpiredCertificatesResponse{
211+
restart: restart,
212+
}
143213

144214
if c.ServiceName != "all" {
145215
e, err := envoy.NewFromServiceName(c.ServiceName)
146-
if err != nil { return err }
216+
if err != nil { return runResp, err }
147217

148218
sidecars = append(sidecars, e)
149219
} else {
150220
sideResp, err := envoy.AllSidecars()
151221
if err != nil {
152-
return err
222+
return runResp, err
153223
}
154224

155225
sidecars = append(sidecars, sideResp...)
156226
}
157227

158228
for _, e := range sidecars {
159229
resp, lErr := e.Certificates().FindExpired()
160-
if lErr != nil { return lErr }
230+
if lErr != nil { return runResp, lErr }
161231

162232
expiredCerts = append(expiredCerts, resp...)
163233
}
164234

165-
for _, e := range expiredCerts {
166-
color.Green(e.ServiceName)
167-
fmt.Println(" Envoy Process ID:", e.Pid)
168-
fmt.Printf(" Envoy Certificate Expiry: %s (%d days)\n", e.EnvoyExpiration, e.EnvoyDaysUntilExpiration)
169-
fmt.Println(" Consul Agent Certificate Expiry: ", e.ConsulExpiration)
235+
runResp.ExpiredCertificates = expiredCerts
170236

237+
for _, e := range expiredCerts {
171238
if restart == true {
172-
color.Green(" Restarting " + e.ServiceName + " Envoy...")
173239
err := e.Envoy.Restart()
174-
if err != nil { return err }
175-
176-
color.Green(" ...done.")
240+
if err != nil {
241+
return runResp, err
242+
}
177243
}
178244
}
179245

180-
return nil
246+
return runResp, nil
181247
}

commands/clusters.go

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"github.com/olekukonko/tablewriter"
88
"github.com/spf13/cast"
99
"github.com/spf13/cobra"
10-
"os"
10+
"strings"
1111
)
1212

1313
type Clusters struct {
@@ -43,7 +43,10 @@ func (r *Registry) BuildListClustersCommand() *cobra.Command {
4343
Cluster: cluster,
4444
Consul: consul.NewClient(),
4545
}
46-
return controller.Run()
46+
o, cErr := controller.Run()
47+
if cErr != nil { return cErr }
48+
49+
return r.Output(o)
4750
},
4851
}
4952
cmd.Flags().String("cluster", "", "Filter to a specific cluster")
@@ -56,23 +59,34 @@ type ListClustersController struct {
5659
Consul consul.Client
5760
}
5861

59-
func (c *ListClustersController) Run() error {
62+
func (c *ListClustersController) Run() (ListClustersResponse, error) {
63+
resp := ListClustersResponse{
64+
ServiceName: c.ServiceName,
65+
}
6066
e, err := envoy.NewFromServiceName(c.ServiceName)
61-
if err != nil { return err }
67+
if err != nil { return resp, err }
68+
69+
resp.Envoy = &e
6270

6371
stats, gErr := e.Clusters().GetStatistics(c.Cluster)
64-
if gErr != nil { return gErr }
72+
if gErr != nil { return resp, gErr }
6573

66-
c.DisplayOutput(stats)
74+
resp.ClusterStatistics = stats
75+
return resp, nil
76+
}
6777

68-
return nil
78+
type ListClustersResponse struct {
79+
ServiceName string `json:"service"`
80+
Envoy *envoy.Instance `json:"envoy"`
81+
ClusterStatistics map[string]envoy.ClusterStatistics `json:"clusters"`
6982
}
7083

71-
func (c *ListClustersController) DisplayOutput(clusters map[string]envoy.ClusterStatistics) {
72-
for _, stats := range clusters {
73-
color.Green("")
74-
_, _ = color.New(color.FgGreen).Add(color.Bold).Println(stats.Host)
75-
color.Green("------------------------------------------------------------------------------------------------------------")
84+
func (r ListClustersResponse) String() string {
85+
o := ""
86+
for _, stats := range r.ClusterStatistics {
87+
o += Ok("")
88+
o += Ok(color.New(color.FgGreen).Add(color.Bold).Sprint(stats.Host))
89+
o += Ok("------------------------------------------------------------------------------------------------------------")
7690
d := [][]string{
7791
{
7892
"Outlier: Success Rate", stats.Outlier.SuccessRateAverage,
@@ -99,20 +113,23 @@ func (c *ListClustersController) DisplayOutput(clusters map[string]envoy.Cluster
99113
"High Priority - Max Requests", cast.ToString(stats.HighPriority.MaxRequests),
100114
},
101115
}
102-
table := tablewriter.NewWriter(os.Stdout)
116+
tableString := strings.Builder{}
117+
table := tablewriter.NewWriter(&tableString)
103118
table.SetBorder(false)
104119
table.SetTablePadding("\t")
105120
table.AppendBulk(d)
106121
table.SetAlignment(tablewriter.ALIGN_LEFT)
107122
table.Render()
123+
o += tableString.String()
108124

109125
if len(stats.Instances) > 0 {
110-
color.Green("")
111-
color.Green("---------------------")
112-
color.Green("- Cluster Instances -")
113-
color.Green("---------------------")
126+
o += Ok("")
127+
o += Ok("---------------------")
128+
o += Ok("- Cluster Instances -")
129+
o += Ok("---------------------")
114130

115-
table = tablewriter.NewWriter(os.Stdout)
131+
tableString = strings.Builder{}
132+
table = tablewriter.NewWriter(&tableString)
116133
table.SetHeader([]string{
117134
"Host",
118135
"Cx Active",
@@ -158,6 +175,8 @@ func (c *ListClustersController) DisplayOutput(clusters map[string]envoy.Cluster
158175
table.AppendBulk(d)
159176
table.SetAlignment(tablewriter.ALIGN_RIGHT)
160177
table.Render()
178+
o += tableString.String()
161179
}
162180
}
181+
return o
163182
}

0 commit comments

Comments
 (0)