Skip to content

Commit 9e751f0

Browse files
committed
metrics: always use '--json' format
Samba's commit 5d6ed73b38e ("smbstatus: add JSON support for smbstatus") from 2022 enables '--json' format. Following commits extended this option to all of smbstatus' major modes. In addition, the output from json format is more verbose, comprehensive and easier to parse then legacy text format. Use it exclusively. Signed-off-by: Shachar Sharon <[email protected]>
1 parent ce53a3d commit 9e751f0

File tree

3 files changed

+5
-293
lines changed

3 files changed

+5
-293
lines changed

internal/metrics/collectors.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ type smbLocksCollector struct {
119119
}
120120

121121
func (col *smbLocksCollector) Collect(ch chan<- prometheus.Metric) {
122-
locks, _ := RunSmbStatusLocks()
122+
locks, _ := RunSmbStatusLockedFiles()
123123
ch <- prometheus.MustNewConstMetric(col.dsc[0],
124124
prometheus.GaugeValue, float64(len(locks)))
125125
}

internal/metrics/smbstatus.go

Lines changed: 4 additions & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -149,19 +149,13 @@ func RunSmbStatusVersion() (string, error) {
149149
return ver, nil
150150
}
151151

152-
// RunSmbStatusShares executes 'smbstatus -S' on host container
152+
// RunSmbStatusShares executes 'smbstatus -S --json' on host container
153153
func RunSmbStatusShares() ([]SmbStatusTreeCon, error) {
154-
// Case 1: using new json output
155154
dat, err := executeSmbStatusCommand("-S --json")
156-
if err == nil {
157-
return parseSmbStatusSharesAsJSON(dat)
158-
}
159-
// Case 2: fallback to raw-text output
160-
dat, err = executeSmbStatusCommand("-S")
161-
if err == nil {
162-
return parseSmbStatusShares(dat)
155+
if err != nil {
156+
return []SmbStatusTreeCon{}, err
163157
}
164-
return []SmbStatusTreeCon{}, err
158+
return parseSmbStatusSharesAsJSON(dat)
165159
}
166160

167161
func parseSmbStatusSharesAsJSON(dat string) ([]SmbStatusTreeCon, error) {
@@ -176,15 +170,6 @@ func parseSmbStatusSharesAsJSON(dat string) ([]SmbStatusTreeCon, error) {
176170
return tcons, nil
177171
}
178172

179-
// RunSmbStatusLocks executes 'smbstatus -L' on host container
180-
func RunSmbStatusLocks() ([]SmbStatusLock, error) {
181-
dat, err := executeSmbStatusCommand("-L")
182-
if err != nil {
183-
return []SmbStatusLock{}, err
184-
}
185-
return parseSmbStatusLocks(dat)
186-
}
187-
188173
// RunSmbStatusLocks executes 'smbstatus -L --json' on host container
189174
func RunSmbStatusLockedFiles() ([]SmbStatusLockedFile, error) {
190175
dat, err := executeSmbStatusCommand("-L --json")
@@ -206,15 +191,6 @@ func parseSmbStatusLocksAsJSON(dat string) ([]SmbStatusLockedFile, error) {
206191
return lockedFiles, nil
207192
}
208193

209-
// RunSmbStatusProcs executes 'smbstatus -p' on host container
210-
func RunSmbStatusProcs() ([]SmbStatusProc, error) {
211-
dat, err := executeSmbStatusCommand("-p")
212-
if err != nil {
213-
return []SmbStatusProc{}, err
214-
}
215-
return parseSmbStatusProcs(dat)
216-
}
217-
218194
// SmbStatusSharesByMachine converts the output of RunSmbStatusShares into map
219195
// indexed by machine's host
220196
func SmbStatusSharesByMachine() (map[string][]SmbStatusTreeCon, error) {
@@ -251,185 +227,6 @@ func executeCommand(command string, arg ...string) (string, error) {
251227
return res, nil
252228
}
253229

254-
// parseSmbStatusShares parses to output of 'smbstatus -S' into internal
255-
// representation.
256-
func parseSmbStatusShares(data string) ([]SmbStatusTreeCon, error) {
257-
shares := []SmbStatusTreeCon{}
258-
serviceIndex := 0
259-
pidIndex := 0
260-
machineIndex := 0
261-
connectedAtIndex := 0
262-
encryptionIndex := 0
263-
signingIndex := 0
264-
hasDashLine := false
265-
lines := strings.Split(data, "\n")
266-
for _, line := range lines {
267-
ln := strings.TrimSpace(line)
268-
// Ignore empty and coment lines
269-
if len(ln) == 0 || ln[0] == '#' {
270-
continue
271-
}
272-
// Detect the all-dash line
273-
if strings.HasPrefix(ln, "------") {
274-
hasDashLine = true
275-
continue
276-
}
277-
// Parse header line into index of data
278-
if strings.HasPrefix(ln, "Service") {
279-
serviceIndex = strings.Index(ln, "Service")
280-
pidIndex = strings.Index(ln, "pid")
281-
machineIndex = strings.Index(ln, "Machine")
282-
connectedAtIndex = strings.Index(ln, "Connected at")
283-
encryptionIndex = strings.Index(ln, "Encryption")
284-
signingIndex = strings.Index(ln, "Signing")
285-
continue
286-
}
287-
// Ignore lines before header
288-
if !hasDashLine {
289-
continue
290-
}
291-
// Parse data into internal repr
292-
share := SmbStatusTreeCon{}
293-
share.Service = parseSubstr(ln, serviceIndex)
294-
share.ServerID.PID = parseSubstr(ln, pidIndex)
295-
share.Machine = parseSubstr(ln, machineIndex)
296-
share.ConnectedAt = parseSubstr2(ln, connectedAtIndex, encryptionIndex)
297-
share.Encryption.Cipher = parseSubstr(ln, encryptionIndex)
298-
share.Signing.Cipher = parseSubstr(ln, signingIndex)
299-
300-
// Ignore "IPC$"
301-
if share.Service == "IPC$" {
302-
continue
303-
}
304-
305-
shares = append(shares, share)
306-
}
307-
return shares, nil
308-
}
309-
310-
// parseSmbStatusProcs parses to output of 'smbstatus -p' into internal
311-
// representation.
312-
func parseSmbStatusProcs(data string) ([]SmbStatusProc, error) {
313-
procs := []SmbStatusProc{}
314-
pidIndex := 0
315-
usernameIndex := 0
316-
groupIndex := 0
317-
machineIndex := 0
318-
protocolVersionIndex := 0
319-
encryptionIndex := 0
320-
signingIndex := 0
321-
hasDashLine := false
322-
lines := strings.Split(data, "\n")
323-
for _, line := range lines {
324-
ln := strings.TrimSpace(line)
325-
// Ignore empty and coment lines
326-
if len(ln) == 0 || ln[0] == '#' {
327-
continue
328-
}
329-
// Detect the all-dash line
330-
if strings.HasPrefix(ln, "------") {
331-
hasDashLine = true
332-
continue
333-
}
334-
// Parse header line into index of data
335-
if strings.HasPrefix(ln, "PID") {
336-
pidIndex = strings.Index(ln, "PID")
337-
usernameIndex = strings.Index(ln, "Username")
338-
groupIndex = strings.Index(ln, "Group")
339-
machineIndex = strings.Index(ln, "Machine")
340-
protocolVersionIndex = strings.Index(ln, "Protocol Version")
341-
encryptionIndex = strings.Index(ln, "Encryption")
342-
signingIndex = strings.Index(ln, "Signing")
343-
continue
344-
}
345-
// Ignore lines before header
346-
if !hasDashLine {
347-
continue
348-
}
349-
// Parse data into internal repr
350-
proc := SmbStatusProc{}
351-
proc.PID = parseSubstr(ln, pidIndex)
352-
proc.Username = parseSubstr(ln, usernameIndex)
353-
proc.Group = parseSubstr(ln, groupIndex)
354-
proc.Machine = parseSubstr(ln, machineIndex)
355-
proc.ProtocolVersion = parseSubstr(ln, protocolVersionIndex)
356-
proc.Encryption = parseSubstr(ln, encryptionIndex)
357-
proc.Signing = parseSubstr(ln, signingIndex)
358-
procs = append(procs, proc)
359-
}
360-
return procs, nil
361-
}
362-
363-
// parseSmbStatusLocks parses to output of 'smbstatus -L' into internal
364-
// representation.
365-
func parseSmbStatusLocks(data string) ([]SmbStatusLock, error) {
366-
locks := []SmbStatusLock{}
367-
pidIndex := 0
368-
userIndex := 0
369-
denyModeIndex := 0
370-
accessIndex := 0
371-
rwIndex := 0
372-
oplockIndex := 0
373-
sharePathIndex := 0
374-
hasDashLine := false
375-
lines := strings.Split(data, "\n")
376-
for _, line := range lines {
377-
ln := strings.TrimSpace(line)
378-
// Ignore empty and coment lines
379-
if len(ln) == 0 || ln[0] == '#' {
380-
continue
381-
}
382-
// Detect the all-dash line
383-
if strings.HasPrefix(ln, "------") {
384-
hasDashLine = true
385-
continue
386-
}
387-
// Ignore generic-info line
388-
if strings.HasPrefix(ln, "Locked files") {
389-
continue
390-
}
391-
// Parse header line into index of data
392-
if strings.HasPrefix(ln, "Pid") {
393-
pidIndex = strings.Index(ln, "Pid")
394-
userIndex = strings.Index(ln, "User")
395-
denyModeIndex = strings.Index(ln, "DenyMode")
396-
accessIndex = strings.Index(ln, "Access")
397-
rwIndex = strings.Index(ln, "R/W")
398-
oplockIndex = strings.Index(ln, "Oplock")
399-
sharePathIndex = strings.Index(ln, "SharePath")
400-
continue
401-
}
402-
// Ignore lines before header
403-
if !hasDashLine {
404-
continue
405-
}
406-
// Parse data into internal repr
407-
lock := SmbStatusLock{}
408-
lock.PID = parseSubstr(ln, pidIndex)
409-
lock.UserID = parseSubstr(ln, userIndex)
410-
lock.DenyMode = parseSubstr(ln, denyModeIndex)
411-
lock.Access = parseSubstr(ln, accessIndex)
412-
lock.RW = parseSubstr(ln, rwIndex)
413-
lock.Oplock = parseSubstr(ln, oplockIndex)
414-
lock.SharePath = parseSubstr(ln, sharePathIndex)
415-
locks = append(locks, lock)
416-
}
417-
return locks, nil
418-
}
419-
420-
func parseSubstr(s string, startIndex int) string {
421-
sub := strings.TrimSpace(s[startIndex:])
422-
fields := strings.Fields(sub)
423-
if len(fields) == 0 {
424-
return ""
425-
}
426-
return fields[0]
427-
}
428-
429-
func parseSubstr2(s string, startIndex, endIndex int) string {
430-
return strings.TrimSpace(s[startIndex:endIndex])
431-
}
432-
433230
func ParseTime(s string) (time.Time, error) {
434231
layouts := []string{
435232
time.ANSIC,

internal/metrics/smbstatus_test.go

Lines changed: 0 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -11,44 +11,6 @@ import (
1111
//revive:disable line-length-limit
1212
//nolint:revive,lll
1313
var (
14-
outputSmbStatusS = `
15-
16-
Service pid Machine Connected at Encryption Signing
17-
----------------------------------------------------------------------------------------
18-
share_test 13668 10.66.208.149 Wed Sep 27 10:33:55 AM 2017 CST - -
19-
share_test2 13669 10.66.208.149 Wed Sep 27 10:35:56 AM 2022 CST - -
20-
IPC$ 651248 10.0.0.100 Sat Sep 4 10:37:01 AM 2020 MDT - -
21-
22-
`
23-
24-
outputSmbStatusS2 = `
25-
26-
Service pid Machine Connected at Encryption Signing
27-
---------------------------------------------------------------------------------------------
28-
samba-share 295 ::1 Thu Apr 7 14:33:19 2022 UTC - -
29-
IPC$ 295 ::1 Thu Apr 7 14:33:19 2022 UTC - -
30-
31-
`
32-
33-
outputSmbStatusp = `
34-
35-
Samba version 4.14.12
36-
PID Username Group Machine Protocol Version Encryption Signing
37-
----------------------------------------------------------------------------------------------------------------------------------------
38-
245 user user 127.0.0.1 (ipv4:127.0.0.1:55106) SMB3_11 - partial(AES-128-CMAC)
39-
9701 root wheel 10.0.0.2 (ipv4:10.0.0.2:55107) SMB3_12 - partial(AES-128-CMAC)
40-
41-
`
42-
43-
outputSmbStatusL = `
44-
45-
Locked files:
46-
Pid User(ID) DenyMode Access R/W Oplock SharePath Name Time
47-
--------------------------------------------------------------------------------------------------
48-
241 1001 DENY_NONE 0x120089 RDONLY LEASE(RWH) /mnt/514cd7ba-d858-4d3a-bed9-68e4e524493b A/a Mon Feb 21 13:07:46 2022
49-
50-
`
51-
5214
outputSmbStatusJSON = `
5315
{
5416
"timestamp": "2022-07-19T16:26:34.652845+0530",
@@ -591,26 +553,6 @@ Pid User(ID) DenyMode Access R/W Oplock Share
591553

592554
//revive:enable line-length-limit
593555

594-
func TestParseSmbStatusShares(t *testing.T) {
595-
shares, err := parseSmbStatusShares(outputSmbStatusS)
596-
assert.NoError(t, err)
597-
assert.Equal(t, len(shares), 2)
598-
share1 := shares[0]
599-
assert.Equal(t, share1.Service, "share_test")
600-
assert.Equal(t, share1.ServerID.PID, "13668")
601-
assert.Equal(t, share1.Machine, "10.66.208.149")
602-
assert.Equal(t, share1.Encryption.Cipher, "-")
603-
assert.Equal(t, share1.Signing.Cipher, "-")
604-
605-
shares, err = parseSmbStatusShares(outputSmbStatusS2)
606-
assert.NoError(t, err)
607-
assert.Equal(t, len(shares), 1)
608-
share1 = shares[0]
609-
assert.Equal(t, share1.Service, "samba-share")
610-
assert.Equal(t, share1.ServerID.PID, "295")
611-
assert.Equal(t, share1.Machine, "::1")
612-
}
613-
614556
func TestParseSmbStatusSharesJSON(t *testing.T) {
615557
dat, err := parseSmbStatusJSON(outputSmbStatusJSON)
616558
assert.NoError(t, err)
@@ -649,33 +591,6 @@ func TestParseSmbStatusAllJSON(t *testing.T) {
649591
assert.Equal(t, len(dat2.LockedFiles), 2)
650592
}
651593

652-
func TestParseSmbStatusProcs(t *testing.T) {
653-
procs, err := parseSmbStatusProcs(outputSmbStatusp)
654-
assert.NoError(t, err)
655-
assert.Equal(t, len(procs), 2)
656-
proc1 := procs[0]
657-
assert.Equal(t, proc1.PID, "245")
658-
assert.Equal(t, proc1.Username, "user")
659-
assert.Equal(t, proc1.Group, "user")
660-
assert.Equal(t, proc1.ProtocolVersion, "SMB3_11")
661-
proc2 := procs[1]
662-
assert.Equal(t, proc2.PID, "9701")
663-
assert.Equal(t, proc2.Username, "root")
664-
assert.Equal(t, proc2.Group, "wheel")
665-
assert.Equal(t, proc2.ProtocolVersion, "SMB3_12")
666-
}
667-
668-
func TestParseSmbStatusLocks(t *testing.T) {
669-
locks, err := parseSmbStatusLocks(outputSmbStatusL)
670-
assert.NoError(t, err)
671-
assert.Equal(t, len(locks), 1)
672-
lock1 := locks[0]
673-
assert.Equal(t, lock1.PID, "241")
674-
assert.Equal(t, lock1.UserID, "1001")
675-
assert.Equal(t, lock1.DenyMode, "DENY_NONE")
676-
assert.Equal(t, lock1.RW, "RDONLY")
677-
}
678-
679594
func TestParseSmbStatusLocksJSON(t *testing.T) {
680595
locks, err := parseSmbStatusLocksAsJSON(outputSmbStatusLocksJSON)
681596
assert.NoError(t, err)

0 commit comments

Comments
 (0)