Skip to content

Commit 7840a3c

Browse files
committed
metrics: support 'smbstatus -L --json' format for locks
Implement locks-state parser from 'smbstatus -L --json' output json format. Signed-off-by: Shachar Sharon <[email protected]>
1 parent f648838 commit 7840a3c

File tree

2 files changed

+185
-0
lines changed

2 files changed

+185
-0
lines changed

internal/metrics/smbstatus.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,14 @@ type SmbStatusLock struct {
105105
Time string
106106
}
107107

108+
// SmbStatusJSON represents output of 'smbstatus -L --json'
109+
type SmbStatusLocksJSON struct {
110+
Timestamp string `json:"timestamp"`
111+
Version string `json:"version"`
112+
SmbConf string `json:"smb_conf"`
113+
OpenFiles map[string]SmbStatusLockedFile `json:"open_files"`
114+
}
115+
108116
// LocateSmbStatus finds the local executable of 'smbstatus' on host container.
109117
func LocateSmbStatus() (string, error) {
110118
knowns := []string{
@@ -171,6 +179,27 @@ func RunSmbStatusLocks() ([]SmbStatusLock, error) {
171179
return parseSmbStatusLocks(dat)
172180
}
173181

182+
// RunSmbStatusLocks executes 'smbstatus -L --json' on host container
183+
func RunSmbStatusLockedFiles() ([]SmbStatusLockedFile, error) {
184+
dat, err := executeSmbStatusCommand("-L --json")
185+
if err != nil {
186+
return []SmbStatusLockedFile{}, err
187+
}
188+
return parseSmbStatusLocksAsJSON(dat)
189+
}
190+
191+
func parseSmbStatusLocksAsJSON(dat string) ([]SmbStatusLockedFile, error) {
192+
lockedFiles := []SmbStatusLockedFile{}
193+
res, err := parseSmbStatusLocksJSON(dat)
194+
if err != nil {
195+
return lockedFiles, err
196+
}
197+
for _, lfile := range res.OpenFiles {
198+
lockedFiles = append(lockedFiles, lfile)
199+
}
200+
return lockedFiles, nil
201+
}
202+
174203
// RunSmbStatusProcs executes 'smbstatus -p' on host container
175204
func RunSmbStatusProcs() ([]SmbStatusProc, error) {
176205
dat, err := executeSmbStatusCommand("-p")
@@ -417,3 +446,11 @@ func parseSmbStatusJSON(data string) (*SmbStatusJSON, error) {
417446
err := json.Unmarshal([]byte(data), &res)
418447
return &res, err
419448
}
449+
450+
// parseSmbStatusJSON parses to output of 'smbstatus -L --json' into internal
451+
// representation.
452+
func parseSmbStatusLocksJSON(data string) (*SmbStatusLocksJSON, error) {
453+
res := SmbStatusLocksJSON{}
454+
err := json.Unmarshal([]byte(data), &res)
455+
return &res, err
456+
}

internal/metrics/smbstatus_test.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,142 @@ Pid User(ID) DenyMode Access R/W Oplock Share
450450
}
451451
}
452452
}
453+
`
454+
455+
outputSmbStatusLocksJSON = `
456+
{
457+
"timestamp": "2024-04-14T14:53:34.901974+0300",
458+
"version": "4.21.0pre1-GIT-58a018fb7ad",
459+
"smb_conf": "//etc/samba/smb.conf",
460+
"open_files": {
461+
"/A/A2/A6/r1": {
462+
"service_path": "/",
463+
"filename": "A/A2/A6/r1",
464+
"fileid": {
465+
"devid": 1,
466+
"inode": 61,
467+
"extid": 0
468+
},
469+
"num_pending_deletes": 0,
470+
"opens": {
471+
"1790/261": {
472+
"server_id": {
473+
"pid": "1790",
474+
"task_id": "0",
475+
"vnn": "4294967295",
476+
"unique_id": "3607086338167075363"
477+
},
478+
"uid": 2222,
479+
"share_file_id": "261",
480+
"sharemode": {
481+
"hex": "0x00000007",
482+
"READ": true,
483+
"WRITE": true,
484+
"DELETE": true,
485+
"text": "RWD"
486+
},
487+
"access_mask": {
488+
"hex": "0x00120089",
489+
"READ_DATA": true,
490+
"WRITE_DATA": false,
491+
"APPEND_DATA": false,
492+
"READ_EA": true,
493+
"WRITE_EA": false,
494+
"EXECUTE": false,
495+
"READ_ATTRIBUTES": true,
496+
"WRITE_ATTRIBUTES": false,
497+
"DELETE_CHILD": false,
498+
"DELETE": false,
499+
"READ_CONTROL": true,
500+
"WRITE_DAC": false,
501+
"SYNCHRONIZE": true,
502+
"ACCESS_SYSTEM_SECURITY": false,
503+
"text": "R"
504+
},
505+
"caching": {
506+
"READ": true,
507+
"WRITE": true,
508+
"HANDLE": false,
509+
"hex": "0x00000005",
510+
"text": "RW"
511+
},
512+
"oplock": {
513+
"EXCLUSIVE": true,
514+
"BATCH": true,
515+
"LEVEL_II": false,
516+
"LEASE": false,
517+
"text": "BATCH"
518+
},
519+
"lease": {},
520+
"opened_at": "2024-04-14T14:53:15.569085+03:00"
521+
}
522+
}
523+
},
524+
"/A/A1/r2": {
525+
"service_path": "/",
526+
"filename": "A/A1/r2",
527+
"fileid": {
528+
"devid": 2,
529+
"inode": 52,
530+
"extid": 0
531+
},
532+
"num_pending_deletes": 2,
533+
"opens": {
534+
"1790/267": {
535+
"server_id": {
536+
"pid": "1790",
537+
"task_id": "0",
538+
"vnn": "4294967295",
539+
"unique_id": "3607086338167075363"
540+
},
541+
"uid": 1111,
542+
"share_file_id": "222",
543+
"sharemode": {
544+
"hex": "0x00000007",
545+
"READ": true,
546+
"WRITE": true,
547+
"DELETE": true,
548+
"text": "RWD"
549+
},
550+
"access_mask": {
551+
"hex": "0x00120089",
552+
"READ_DATA": true,
553+
"WRITE_DATA": false,
554+
"APPEND_DATA": false,
555+
"READ_EA": true,
556+
"WRITE_EA": false,
557+
"EXECUTE": false,
558+
"READ_ATTRIBUTES": true,
559+
"WRITE_ATTRIBUTES": false,
560+
"DELETE_CHILD": false,
561+
"DELETE": false,
562+
"READ_CONTROL": true,
563+
"WRITE_DAC": false,
564+
"SYNCHRONIZE": true,
565+
"ACCESS_SYSTEM_SECURITY": false,
566+
"text": "R"
567+
},
568+
"caching": {
569+
"READ": true,
570+
"WRITE": true,
571+
"HANDLE": false,
572+
"hex": "0x00000005",
573+
"text": "RW"
574+
},
575+
"oplock": {
576+
"EXCLUSIVE": true,
577+
"BATCH": true,
578+
"LEVEL_II": false,
579+
"LEASE": false,
580+
"text": "BATCH"
581+
},
582+
"lease": {},
583+
"opened_at": "2024-04-14T14:53:32.258325+03:00"
584+
}
585+
}
586+
}
587+
}
588+
}
453589
`
454590
)
455591

@@ -539,3 +675,15 @@ func TestParseSmbStatusLocks(t *testing.T) {
539675
assert.Equal(t, lock1.DenyMode, "DENY_NONE")
540676
assert.Equal(t, lock1.RW, "RDONLY")
541677
}
678+
679+
func TestParseSmbStatusLocksJSON(t *testing.T) {
680+
locks, err := parseSmbStatusLocksAsJSON(outputSmbStatusLocksJSON)
681+
assert.NoError(t, err)
682+
assert.Equal(t, len(locks), 2)
683+
lock1 := locks[0]
684+
assert.Equal(t, lock1.FileID.Inode, int64(61))
685+
assert.Equal(t, lock1.NumPendingDeletes, 0)
686+
lock2 := locks[1]
687+
assert.Equal(t, lock2.FileID.Inode, int64(52))
688+
assert.Equal(t, lock2.NumPendingDeletes, 2)
689+
}

0 commit comments

Comments
 (0)