@@ -29,6 +29,7 @@ import (
2929 "github.com/cea-hpc/sshproxy/pkg/utils"
3030
3131 "github.com/olekukonko/tablewriter"
32+ "github.com/olekukonko/tablewriter/tw"
3233)
3334
3435var (
@@ -76,12 +77,18 @@ func displayJSON(objs interface{}) {
7677 }
7778}
7879
79- func displayTable (headers []string , rows [][]string ) {
80+ func displayTable (headers []string , rows [][]string , footers [] string ) {
8081 table := tablewriter .NewTable (os .Stdout ,
8182 tablewriter .WithConfig (tablewriter.Config {
8283 MaxWidth : 200 ,
84+ Row : tw.CellConfig {
85+ Formatting : tw.CellFormatting {
86+ Alignment : tw .AlignRight ,
87+ },
88+ },
8389 }))
8490 table .Header (headers )
91+ table .Footer (footers )
8592 table .Bulk (rows )
8693 table .Render ()
8794}
@@ -98,28 +105,42 @@ type aggConnection struct {
98105
99106type aggregatedConnections []* aggConnection
100107
101- func (ac aggregatedConnections ) toRows (passthrough bool ) [][]string {
108+ func (ac aggregatedConnections ) toRows (passthrough bool ) ( [][]string , map [ string ] string ) {
102109 rows := make ([][]string , len (ac ))
110+ totalConnections := 0
111+ totalIn := 0
112+ totalOut := 0
103113
104114 for i , c := range ac {
105115 rows [i ] = []string {
106116 c .User ,
107117 c .Service ,
108118 c .Dest ,
109- strconv . Itoa ( c .N ),
119+ fmt . Sprintf ( "%d" , c .N ),
110120 c .Last .Format ("2006-01-02 15:04:05" ),
111121 byteToHuman (c .BwIn , passthrough ),
112122 byteToHuman (c .BwOut , passthrough ),
113123 }
124+ totalConnections += c .N
125+ totalIn += c .BwIn
126+ totalOut += c .BwOut
127+ }
128+ footer := map [string ]string {
129+ "connections" : fmt .Sprintf ("%d" , totalConnections ),
130+ "in" : byteToHuman (totalIn , passthrough ),
131+ "out" : byteToHuman (totalOut , passthrough ),
114132 }
115133
116- return rows
134+ return rows , footer
117135}
118136
119137type flatConnections []* utils.FlatConnection
120138
121- func (fc flatConnections ) getAllConnections (passthrough bool ) [][]string {
139+ func (fc flatConnections ) getAllConnections (passthrough bool ) ( [][]string , map [ string ] string ) {
122140 rows := make ([][]string , len (fc ))
141+ totalConnections := 0
142+ totalIn := 0
143+ totalOut := 0
123144
124145 for i , c := range fc {
125146 rows [i ] = []string {
@@ -131,9 +152,17 @@ func (fc flatConnections) getAllConnections(passthrough bool) [][]string {
131152 byteToHuman (c .BwIn , passthrough ),
132153 byteToHuman (c .BwOut , passthrough ),
133154 }
155+ totalConnections += 1
156+ totalIn += c .BwIn
157+ totalOut += c .BwOut
158+ }
159+ footer := map [string ]string {
160+ "connections" : fmt .Sprintf ("%d" , totalConnections ),
161+ "in" : byteToHuman (totalIn , passthrough ),
162+ "out" : byteToHuman (totalOut , passthrough ),
134163 }
135164
136- return rows
165+ return rows , footer
137166}
138167
139168func (fc flatConnections ) getAggregatedConnections () aggregatedConnections {
@@ -203,9 +232,9 @@ func (fc flatConnections) displayCSV(allFlag bool) {
203232 var rows [][]string
204233
205234 if allFlag {
206- rows = fc .getAllConnections (true )
235+ rows , _ = fc .getAllConnections (true )
207236 } else {
208- rows = fc .getAggregatedConnections ().toRows (true )
237+ rows , _ = fc .getAggregatedConnections ().toRows (true )
209238 }
210239
211240 displayCSV (rows )
@@ -225,21 +254,25 @@ func (fc flatConnections) displayJSON(allFlag bool) {
225254
226255func (fc flatConnections ) displayTable (allFlag bool ) {
227256 var rows [][]string
257+ var footer map [string ]string
228258
229259 if allFlag {
230- rows = fc .getAllConnections (false )
260+ rows , footer = fc .getAllConnections (false )
231261 } else {
232- rows = fc .getAggregatedConnections ().toRows (false )
262+ rows , footer = fc .getAggregatedConnections ().toRows (false )
233263 }
234264
235265 var headers []string
266+ var footers []string
236267 if allFlag {
237268 headers = []string {"User" , "Service" , "From" , "Destination" , "Start time" , "Bw in" , "Bw out" }
269+ footers = []string {"" , "" , "" , "Totals" , footer ["connections" ], footer ["in" ], footer ["out" ]}
238270 } else {
239271 headers = []string {"User" , "Service" , "Destination" , "# of conns" , "Last connection" , "Bw in" , "Bw out" }
272+ footers = []string {"" , "" , "Totals" , footer ["connections" ], "" , footer ["in" ], footer ["out" ]}
240273 }
241274
242- displayTable (headers , rows )
275+ displayTable (headers , rows , footers )
243276}
244277
245278func showConnections (configFile string , csvFlag bool , jsonFlag bool , allFlag bool ) {
@@ -271,8 +304,12 @@ type flatUserLight struct {
271304
272305type flatUsers []* utils.FlatUser
273306
274- func (fu flatUsers ) getAllUsers (allFlag bool , passthrough bool ) [][]string {
307+ func (fu flatUsers ) getAllUsers (allFlag bool , passthrough bool ) ( [][]string , map [ string ] string ) {
275308 rows := make ([][]string , len (fu ))
309+ totalConnections := 0
310+ totalIn := 0
311+ totalOut := 0
312+
276313 for i , v := range fu {
277314 if allFlag {
278315 rows [i ] = []string {
@@ -294,6 +331,9 @@ func (fu flatUsers) getAllUsers(allFlag bool, passthrough bool) [][]string {
294331 byteToHuman (v .BwOut , passthrough ),
295332 }
296333 }
334+ totalConnections += v .N
335+ totalIn += v .BwIn
336+ totalOut += v .BwOut
297337 }
298338
299339 sort .Slice (rows , func (i , j int ) bool {
@@ -303,8 +343,13 @@ func (fu flatUsers) getAllUsers(allFlag bool, passthrough bool) [][]string {
303343 return rows [i ][0 ] < rows [j ][0 ]
304344 }
305345 })
346+ footer := map [string ]string {
347+ "connections" : fmt .Sprintf ("%d" , totalConnections ),
348+ "in" : byteToHuman (totalIn , passthrough ),
349+ "out" : byteToHuman (totalOut , passthrough ),
350+ }
306351
307- return rows
352+ return rows , footer
308353}
309354
310355func (fu flatUsers ) displayJSON (allFlag bool ) {
@@ -326,22 +371,25 @@ func (fu flatUsers) displayJSON(allFlag bool) {
326371}
327372
328373func (fu flatUsers ) displayCSV (allFlag bool ) {
329- rows := fu .getAllUsers (allFlag , true )
374+ rows , _ := fu .getAllUsers (allFlag , true )
330375
331376 displayCSV (rows )
332377}
333378
334379func (fu flatUsers ) displayTable (allFlag bool ) {
335- rows := fu .getAllUsers (allFlag , false )
380+ rows , footer := fu .getAllUsers (allFlag , false )
336381
337382 var headers []string
383+ var footers []string
338384 if allFlag {
339385 headers = []string {"User" , "Service" , "Groups" , "# of conns" , "Bw in" , "Bw out" , "Persist to" , "Persist TTL" }
386+ footers = []string {"" , "" , "Totals" , footer ["connections" ], footer ["in" ], footer ["out" ], "" , "" }
340387 } else {
341388 headers = []string {"User" , "Groups" , "# of conns" , "Bw in" , "Bw out" }
389+ footers = []string {"" , "Totals" , footer ["connections" ], footer ["in" ], footer ["out" ]}
342390 }
343391
344- displayTable (headers , rows )
392+ displayTable (headers , rows , footers )
345393}
346394
347395func showUsers (configFile string , csvFlag bool , jsonFlag bool , allFlag bool ) {
@@ -431,13 +479,14 @@ func (fg flatGroups) displayTable(allFlag bool) {
431479 rows := fg .getAllGroups (allFlag , false )
432480
433481 var headers []string
482+ var footers []string
434483 if allFlag {
435484 headers = []string {"Group" , "Service" , "Users" , "# of conns" , "Bw in" , "Bw out" }
436485 } else {
437486 headers = []string {"Group" , "Users" , "# of conns" , "Bw in" , "Bw out" }
438487 }
439488
440- displayTable (headers , rows )
489+ displayTable (headers , rows , footers )
441490}
442491
443492func showGroups (configFile string , csvFlag bool , jsonFlag bool , allFlag bool ) {
@@ -474,6 +523,10 @@ func showHosts(configFile string, csvFlag bool, jsonFlag bool) {
474523 }
475524
476525 rows := make ([][]string , len (hosts ))
526+ totalConns := 0
527+ totalIn := 0
528+ totalOut := 0
529+ totalPersist := 0
477530
478531 for i , h := range hosts {
479532 rows [i ] = []string {
@@ -485,12 +538,34 @@ func showHosts(configFile string, csvFlag bool, jsonFlag bool) {
485538 byteToHuman (h .BwOut , csvFlag ),
486539 fmt .Sprintf ("%d" , h .HistoryN ),
487540 }
541+ totalConns += h .N
542+ totalIn += h .BwIn
543+ totalOut += h .BwOut
544+ totalPersist += h .HistoryN
488545 }
489546
490547 if csvFlag {
491548 displayCSV (rows )
492549 } else {
493- displayTable ([]string {"Host" , "State" , "Last check" , "# of conns" , "Bw in" , "Bw out" , "# persist" }, rows )
550+ headers := []string {
551+ "Host" ,
552+ "State" ,
553+ "Last check" ,
554+ "# of conns" ,
555+ "Bw in" ,
556+ "Bw out" ,
557+ "# persist" ,
558+ }
559+ footers := []string {
560+ "" ,
561+ "" ,
562+ "Totals" ,
563+ fmt .Sprintf ("%d" , totalConns ),
564+ byteToHuman (totalIn , false ),
565+ byteToHuman (totalOut , false ),
566+ fmt .Sprintf ("%d" , totalPersist ),
567+ }
568+ displayTable (headers , rows , footers )
494569 }
495570}
496571
0 commit comments