Skip to content

Commit 9755653

Browse files
authored
refactor display options (#144)
1 parent e39609d commit 9755653

File tree

4 files changed

+131
-111
lines changed

4 files changed

+131
-111
lines changed

cmd/flow_capture.go

Lines changed: 13 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -34,27 +34,6 @@ var (
3434
flowsToShow = 35
3535
regexes = []string{}
3636
lastFlows = []config.GenericMap{}
37-
38-
rawDisplay = "Raw"
39-
standardDisplay = "Standard"
40-
exclusiveDisplays = []string{rawDisplay, standardDisplay}
41-
pktDropDisplay = "pktDrop"
42-
dnsDisplay = "dnsTracking"
43-
rttDisplay = "flowRTT"
44-
networkEventsDisplay = "networkEvents"
45-
displays = []string{pktDropDisplay, dnsDisplay, rttDisplay, networkEventsDisplay}
46-
display = []string{standardDisplay}
47-
48-
noEnrichment = "None"
49-
exclusiveEnrichments = []string{noEnrichment}
50-
clusterEnrichment = "Cluster"
51-
zoneEnrichment = "Zone"
52-
hostEnrichment = "Host"
53-
ownerEnrichment = "Owner"
54-
resourceEnrichment = "Resource"
55-
subnetLabelEnrichment = "SubnetLabel"
56-
enrichments = []string{clusterEnrichment, zoneEnrichment, hostEnrichment, ownerEnrichment, resourceEnrichment, subnetLabelEnrichment}
57-
enrichment = []string{resourceEnrichment}
5837
)
5938

6039
func runFlowCapture(_ *cobra.Command, _ []string) {
@@ -256,16 +235,16 @@ func updateTable() {
256235
}
257236
if strings.Contains(options, "background=true") {
258237
fmt.Printf("Showing last: %d\n", flowsToShow)
259-
fmt.Printf("Display: %s\n", toShortTitleStr(display))
260-
fmt.Printf("Enrichment: %s\n", toShortTitleStr(enrichment))
238+
fmt.Printf("Display: %s\n", display.getCurrentItem().name)
239+
fmt.Printf("Enrichment: %s\n", enrichment.getCurrentItem().name)
261240
} else {
262241
fmt.Printf("Showing last: %d Use Up / Down keyboard arrows to increase / decrease limit\n", flowsToShow)
263-
fmt.Printf("Display: %s Use Left / Right keyboard arrows to cycle views\n", toShortTitleStr(display))
264-
fmt.Printf("Enrichment: %s Use Page Up / Page Down keyboard keys to cycle enrichment scopes\n", toShortTitleStr(enrichment))
242+
fmt.Printf("Display: %s Use Left / Right keyboard arrows to cycle views\n", display.getCurrentItem().name)
243+
fmt.Printf("Enrichment: %s Use Page Up / Page Down keyboard keys to cycle enrichment scopes\n", enrichment.getCurrentItem().name)
265244
}
266245
}
267246

268-
if slices.Contains(display, rawDisplay) {
247+
if display.getCurrentItem().name == rawDisplay {
269248
fmt.Print("Raw flow logs:\n")
270249
for _, flow := range lastFlows {
271250
fmt.Printf("%v\n", flow)
@@ -282,23 +261,8 @@ func updateTable() {
282261
}
283262

284263
// enrichment fields
285-
if !slices.Contains(enrichment, noEnrichment) {
286-
for _, enr := range enrichment {
287-
var fieldMatch string
288-
if enr == resourceEnrichment {
289-
fieldMatch = "K8S_Name"
290-
} else if enr == subnetLabelEnrichment {
291-
fieldMatch = "SubnetLabel"
292-
} else {
293-
fieldMatch = fmt.Sprintf("K8S_%s", enr)
294-
}
295-
296-
for _, col := range cfg.Columns {
297-
if strings.Contains(col.Field, fieldMatch) {
298-
colIDs = append(colIDs, col.ID)
299-
}
300-
}
301-
}
264+
if enrichment.getCurrentItem().name != noOptions {
265+
colIDs = append(colIDs, enrichment.getCurrentItem().ids...)
302266
} else {
303267
// TODO: add a new flag in the config to identify these as default non enriched fields
304268
colIDs = append(colIDs,
@@ -310,16 +274,15 @@ func updateTable() {
310274
}
311275

312276
// standard / feature fields
313-
if !slices.Contains(display, standardDisplay) {
277+
if display.getCurrentItem().name != standardDisplay {
314278
for _, col := range cfg.Columns {
315-
if slices.Contains(display, col.Feature) {
279+
if slices.Contains(display.getCurrentItem().ids, col.Feature) {
316280
colIDs = append(colIDs, col.ID)
317281
}
318282
}
319283
} else {
320284
// TODO: add a new flag in the config to identify these as default feature fields
321285
colIDs = append(colIDs,
322-
"FlowDirection",
323286
"Interfaces",
324287
"Proto",
325288
"Dscp",
@@ -366,30 +329,6 @@ func updateTable() {
366329
}
367330
}
368331

369-
func cycleOption(selection []string, exclusiveOptions []string, options []string, incr int) []string {
370-
allOptions := slices.Concat(exclusiveOptions, options)
371-
372-
var index int
373-
if len(selection) == 1 {
374-
index = slices.Index(allOptions, selection[0])
375-
if index+incr < 0 || index+incr > len(allOptions)-1 {
376-
index = -1
377-
} else {
378-
index += incr
379-
}
380-
} else if incr < 0 {
381-
index = len(allOptions) - 1
382-
}
383-
384-
if index != -1 {
385-
selection = []string{allOptions[index]}
386-
} else {
387-
selection = slices.Clone(options)
388-
}
389-
390-
return selection
391-
}
392-
393332
// scanner returns true in case of normal exit (end of program execution) or false in case of error
394333
func scanner() bool {
395334
if err := keyboard.Open(); err != nil {
@@ -417,13 +356,13 @@ func scanner() bool {
417356
flowsToShow--
418357
}
419358
case key == keyboard.KeyArrowRight:
420-
display = cycleOption(display, exclusiveDisplays, displays, 1)
359+
display.next()
421360
case key == keyboard.KeyArrowLeft:
422-
display = cycleOption(display, exclusiveDisplays, displays, -1)
361+
display.prev()
423362
case key == keyboard.KeyPgup:
424-
enrichment = cycleOption(enrichment, exclusiveEnrichments, enrichments, 1)
363+
enrichment.next()
425364
case key == keyboard.KeyPgdn:
426-
enrichment = cycleOption(enrichment, exclusiveEnrichments, enrichments, -1)
365+
enrichment.prev()
427366
case key == keyboard.KeyBackspace || key == keyboard.KeyBackspace2:
428367
if len(regexes) > 0 {
429368
lastIndex := len(regexes) - 1

cmd/flow_capture_test.go

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ func TestFlowTableDefaultDisplay(t *testing.T) {
3939
rows := strings.Split(buf.String(), "\n")
4040

4141
assert.Equal(t, 4, len(rows))
42-
assert.Equal(t, `End Time Src Name Src Namespace Dst Name Dst Namespace Node Dir Interfaces L3 Layer Protocol L3 Layer DSCP Bytes Packets `, rows[0])
43-
assert.Equal(t, `17:25:28.703000 src-pod first-namespace dst-pod second-namespace Ingress f18b970c2ce8fdd TCP Standard 456B 5 `, rows[1])
44-
assert.Equal(t, `--------------- --------------- --------------- --------------- --------------- ---------- ---------- ---------- ---------- ----- ----- `, rows[2])
42+
assert.Equal(t, `End Time Src Kind Dst Kind Src Name Dst Name Src Namespace Dst Namespace Interfaces L3 Layer Protocol L3 Layer DSCP Bytes Packets `, rows[0])
43+
assert.Equal(t, `17:25:28.703000 Pod Pod src-pod dst-pod first-namespace second-namespace f18b970c2ce8fdd TCP Standard 456B 5 `, rows[1])
44+
assert.Equal(t, `--------------- ---------- ---------- --------------- --------------- --------------- --------------- ---------- ---------- ---------- ----- ----- `, rows[2])
4545
assert.Empty(t, rows[3])
4646
}
4747

@@ -53,8 +53,8 @@ func TestFlowTableMultipleFlows(t *testing.T) {
5353
setOutputBuffer(&buf)
5454

5555
// set display to standard without enrichment
56-
display = []string{standardDisplay}
57-
enrichment = []string{noEnrichment}
56+
display.current = 1
57+
enrichment.current = 0
5858

5959
// set time and bytes per flow
6060
flowTime := 1704063600000
@@ -86,16 +86,16 @@ func TestFlowTableMultipleFlows(t *testing.T) {
8686
rows := strings.Split(buf.String(), "\n")
8787
// table must display only 38 rows (35 flows + header + footer + empty line)
8888
assert.Equal(t, 38, len(rows))
89-
assert.Equal(t, `End Time Src IP Src Port Dst IP Dst Port Node Dir Interfaces L3 Layer Protocol L3 Layer DSCP Bytes Packets `, rows[0])
89+
assert.Equal(t, `End Time Src IP Src Port Dst IP Dst Port Interfaces L3 Layer Protocol L3 Layer DSCP Bytes Packets `, rows[0])
9090
// first flow is the 6th one that came to the display
91-
assert.Equal(t, `00:00:06.000000 10.0.0.5 n/a 10.0.0.6 n/a n/a n/a n/a n/a 6KB 1 `, rows[1])
92-
assert.Equal(t, `00:00:07.000000 10.0.0.5 n/a 10.0.0.6 n/a n/a n/a n/a n/a 7KB 1 `, rows[2])
93-
assert.Equal(t, `00:00:08.000000 10.0.0.5 n/a 10.0.0.6 n/a n/a n/a n/a n/a 8KB 1 `, rows[3])
94-
assert.Equal(t, `00:00:09.000000 10.0.0.5 n/a 10.0.0.6 n/a n/a n/a n/a n/a 9KB 1 `, rows[4])
95-
assert.Equal(t, `00:00:10.000000 10.0.0.5 n/a 10.0.0.6 n/a n/a n/a n/a n/a 10KB 1 `, rows[5])
91+
assert.Equal(t, `00:00:06.000000 10.0.0.5 n/a 10.0.0.6 n/a n/a n/a n/a 6KB 1 `, rows[1])
92+
assert.Equal(t, `00:00:07.000000 10.0.0.5 n/a 10.0.0.6 n/a n/a n/a n/a 7KB 1 `, rows[2])
93+
assert.Equal(t, `00:00:08.000000 10.0.0.5 n/a 10.0.0.6 n/a n/a n/a n/a 8KB 1 `, rows[3])
94+
assert.Equal(t, `00:00:09.000000 10.0.0.5 n/a 10.0.0.6 n/a n/a n/a n/a 9KB 1 `, rows[4])
95+
assert.Equal(t, `00:00:10.000000 10.0.0.5 n/a 10.0.0.6 n/a n/a n/a n/a 10KB 1 `, rows[5])
9696
// last flow is the 40th one
97-
assert.Equal(t, `00:00:40.000000 10.0.0.5 n/a 10.0.0.6 n/a n/a n/a n/a n/a 40KB 1 `, rows[35])
98-
assert.Equal(t, `--------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----- ----- `, rows[36])
97+
assert.Equal(t, `00:00:40.000000 10.0.0.5 n/a 10.0.0.6 n/a n/a n/a n/a 40KB 1 `, rows[35])
98+
assert.Equal(t, `--------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----- ----- `, rows[36])
9999
assert.Empty(t, rows[37])
100100

101101
}
@@ -108,10 +108,21 @@ func TestFlowTableAdvancedDisplay(t *testing.T) {
108108
setOutputBuffer(&buf)
109109

110110
// getRows function cleanup everything and redraw table with sample flow
111-
getRows := func(d []string, e []string) []string {
111+
getRows := func(displayName string, displayIds []string, enrichmentName string, enrichmentIds []string) []string {
112112
// prepare display options
113-
display = d
114-
enrichment = e
113+
display = option{
114+
all: []optionItem{
115+
{name: displayName, ids: displayIds},
116+
},
117+
current: 0,
118+
}
119+
120+
enrichment = option{
121+
all: []optionItem{
122+
{name: enrichmentName, ids: enrichmentIds},
123+
},
124+
current: 0,
125+
}
115126

116127
// clear filters and previous flows
117128
regexes = []string{}
@@ -127,24 +138,24 @@ func TestFlowTableAdvancedDisplay(t *testing.T) {
127138
}
128139

129140
// set display without enrichment
130-
rows := getRows([]string{pktDropDisplay, dnsDisplay, rttDisplay, networkEventsDisplay}, []string{noEnrichment})
141+
rows := getRows(allOptions, []string{pktDropFeature, dnsFeature, rttFeature, networkEventsDisplay}, noOptions, []string{})
131142
assert.Equal(t, 4, len(rows))
132143
assert.Equal(t, `End Time Src IP Src Port Dst IP Dst Port Dropped Bytes Dropped Packets Drop State Drop Cause Drop Flags DNS Id DNS Latency DNS RCode DNS Error Flow RTT Network Events `, rows[0])
133144
assert.Equal(t, `17:25:28.703000 10.128.0.29 1234 10.129.0.26 5678 32B 1 TCP_INVALID_STATE SKB_DROP_REASON_TCP_INVALID_SEQUENCE 16 31319 1ms NoError 0 10µs hello `, rows[1])
134145
assert.Equal(t, `--------------- ---------- ---------- ---------- ---------- ----- ----- ---------- ---------- ---------- ----- ----- ----- ----- ----- --------------- `, rows[2])
135146
assert.Empty(t, rows[3])
136147

137148
// set display to standard
138-
rows = getRows([]string{standardDisplay}, []string{noEnrichment})
149+
rows = getRows(standardDisplay, []string{}, noOptions, []string{})
139150

140151
assert.Equal(t, 4, len(rows))
141-
assert.Equal(t, `End Time Src IP Src Port Dst IP Dst Port Node Dir Interfaces L3 Layer Protocol L3 Layer DSCP Bytes Packets `, rows[0])
142-
assert.Equal(t, `17:25:28.703000 10.128.0.29 1234 10.129.0.26 5678 Ingress f18b970c2ce8fdd TCP Standard 456B 5 `, rows[1])
143-
assert.Equal(t, `--------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----- ----- `, rows[2])
152+
assert.Equal(t, `End Time Src IP Src Port Dst IP Dst Port Interfaces L3 Layer Protocol L3 Layer DSCP Bytes Packets `, rows[0])
153+
assert.Equal(t, `17:25:28.703000 10.128.0.29 1234 10.129.0.26 5678 f18b970c2ce8fdd TCP Standard 456B 5 `, rows[1])
154+
assert.Equal(t, `--------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----- ----- `, rows[2])
144155
assert.Empty(t, rows[3])
145156

146157
// set display to pktDrop
147-
rows = getRows([]string{pktDropDisplay}, []string{noEnrichment})
158+
rows = getRows("Packet drops", []string{pktDropFeature}, noOptions, []string{})
148159

149160
assert.Equal(t, 4, len(rows))
150161
assert.Equal(t, `End Time Src IP Src Port Dst IP Dst Port Dropped Bytes Dropped Packets Drop State Drop Cause Drop Flags `, rows[0])
@@ -153,7 +164,7 @@ func TestFlowTableAdvancedDisplay(t *testing.T) {
153164
assert.Empty(t, rows[3])
154165

155166
// set display to DNS
156-
rows = getRows([]string{dnsDisplay}, []string{noEnrichment})
167+
rows = getRows("DNS", []string{dnsFeature}, noOptions, []string{})
157168

158169
assert.Equal(t, 4, len(rows))
159170
assert.Equal(t, `End Time Src IP Src Port Dst IP Dst Port DNS Id DNS Latency DNS RCode DNS Error `, rows[0])
@@ -162,7 +173,7 @@ func TestFlowTableAdvancedDisplay(t *testing.T) {
162173
assert.Empty(t, rows[3])
163174

164175
// set display to RTT
165-
rows = getRows([]string{rttDisplay}, []string{noEnrichment})
176+
rows = getRows("RTT", []string{rttFeature}, noOptions, []string{})
166177

167178
assert.Equal(t, 4, len(rows))
168179
assert.Equal(t, `End Time Src IP Src Port Dst IP Dst Port Flow RTT `, rows[0])
@@ -171,7 +182,7 @@ func TestFlowTableAdvancedDisplay(t *testing.T) {
171182
assert.Empty(t, rows[3])
172183

173184
// set display to NetworkEvents
174-
rows = getRows([]string{networkEventsDisplay}, []string{noEnrichment})
185+
rows = getRows("Network events", []string{networkEventsDisplay}, noOptions, []string{})
175186
assert.Equal(t, 4, len(rows))
176187
assert.Equal(t, `End Time Src IP Src Port Dst IP Dst Port Network Events `, rows[0])
177188
assert.Equal(t, `17:25:28.703000 10.128.0.29 1234 10.129.0.26 5678 hello `, rows[1])

cmd/map_format.go

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -431,18 +431,6 @@ func toTimeString(genericMap config.GenericMap, fieldName string) string {
431431
return emptyText
432432
}
433433

434-
func toTitles(strs []string) []string {
435-
titleCaseStrs := []string{}
436-
for _, s := range strs {
437-
titleCaseStrs = append(titleCaseStrs, fmt.Sprintf("%s%s", strings.ToUpper(s[:1]), s[1:]))
438-
}
439-
return titleCaseStrs
440-
}
441-
442-
func toShortTitleStr(strs []string) string {
443-
return replacer.Replace(strings.Join(toTitles(strs), ","))
444-
}
445-
446434
func ToTableColName(id string) string {
447435
name := id
448436
colIndex := slices.IndexFunc(cfg.Columns, func(c *ColumnConfig) bool { return c.ID == id })

cmd/options.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package cmd
2+
3+
type option struct {
4+
all []optionItem
5+
current int
6+
}
7+
8+
type optionItem struct {
9+
name string
10+
ids []string
11+
}
12+
13+
var (
14+
allOptions = "All"
15+
noOptions = "None"
16+
17+
// displays
18+
rawDisplay = "Raw"
19+
standardDisplay = "Standard"
20+
pktDropFeature = "pktDrop"
21+
dnsFeature = "dnsTracking"
22+
rttFeature = "flowRTT"
23+
networkEventsDisplay = "networkEvents"
24+
display = option{
25+
all: []optionItem{
26+
// exclusive displays
27+
{name: rawDisplay},
28+
{name: standardDisplay},
29+
// per feature displays
30+
{name: "Packet drops", ids: []string{pktDropFeature}},
31+
{name: "DNS", ids: []string{dnsFeature}},
32+
{name: "RTT", ids: []string{rttFeature}},
33+
{name: "Network events", ids: []string{networkEventsDisplay}},
34+
// all features display
35+
{name: allOptions, ids: []string{pktDropFeature, dnsFeature, rttFeature, networkEventsDisplay}},
36+
},
37+
// standard display by default
38+
current: 1,
39+
}
40+
41+
// enrichments
42+
enrichment = option{
43+
all: []optionItem{
44+
// no enrichment
45+
{name: noOptions},
46+
// per field enrichments
47+
{name: "Cluster", ids: []string{"ClusterName"}},
48+
{name: "Zone", ids: []string{"SrcZone", "DstZone"}},
49+
{name: "Host", ids: []string{"SrcK8S_HostIP", "DstK8S_HostIP", "SrcK8S_HostName", "DstK8S_HostName", "FlowDirection"}},
50+
{name: "Namespace", ids: []string{"SrcK8S_Namespace", "DstK8S_Namespace"}},
51+
{name: "Owner", ids: []string{"SrcK8S_OwnerType", "DstK8S_OwnerType", "SrcK8S_OwnerName", "DstK8S_OwnerName", "SrcK8S_Namespace", "DstK8S_Namespace"}},
52+
{name: "Resource", ids: []string{"SrcK8S_Type", "DstK8S_Type", "SrcK8S_Name", "DstK8S_Name", "SrcK8S_Namespace", "DstK8S_Namespace"}},
53+
{name: "SubnetLabel", ids: []string{"SrcSubnetLabel", "DstSubnetLabel"}},
54+
// all fields
55+
{name: allOptions, ids: []string{
56+
"ClusterName",
57+
"SrcZone", "DstZone",
58+
"SrcK8S_HostIP", "DstK8S_HostIP", "SrcK8S_HostName", "DstK8S_HostName",
59+
"SrcK8S_Namespace", "DstK8S_Namespace",
60+
"SrcK8S_OwnerType", "DstK8S_OwnerType", "SrcK8S_OwnerName", "DstK8S_OwnerName",
61+
"SrcK8S_Type", "DstK8S_Type", "SrcK8S_Name", "DstK8S_Name",
62+
"SrcSubnetLabel", "DstSubnetLabel",
63+
}},
64+
},
65+
// resource enrichment by default
66+
current: 6,
67+
}
68+
)
69+
70+
func (opt *option) getCurrentItem() optionItem {
71+
return opt.all[opt.current]
72+
}
73+
74+
func (opt *option) prev() {
75+
opt.current += len(opt.all) - 1
76+
opt.current %= len(opt.all)
77+
}
78+
79+
func (opt *option) next() {
80+
opt.current++
81+
opt.current %= len(opt.all)
82+
}

0 commit comments

Comments
 (0)