From e2196ec8db69c2c9b7dda80c2e98d09d983af336 Mon Sep 17 00:00:00 2001 From: Ahmet Oeztuerk Date: Wed, 19 Nov 2025 13:30:02 +0100 Subject: [PATCH 1/7] - add error types to the helper functions of check_drivesize - use error types and typecasting to see if no drives are found - return OK state if no drives are found - write non-existent drive tests for check_drivesize - also test customizing empty state result using empty-state= argument --- docs/checks/commands/check_drivesize.md | 2 +- pkg/snclient/check_drivesize.go | 34 ++++++++++++++++++++-- pkg/snclient/check_drivesize_other.go | 7 +++-- pkg/snclient/check_drivesize_test.go | 38 ++++++++++++++++++++++--- 4 files changed, 72 insertions(+), 9 deletions(-) diff --git a/docs/checks/commands/check_drivesize.md b/docs/checks/commands/check_drivesize.md index 7d53468a..41877204 100644 --- a/docs/checks/commands/check_drivesize.md +++ b/docs/checks/commands/check_drivesize.md @@ -56,7 +56,7 @@ Naemon Config | filter | fstype not in ('autofs', 'bdev', 'binfmt_misc', 'bpf', 'cgroup', 'cgroup2', 'configfs', 'cpuset', 'debugfs', 'devpts', 'devtmpfs', 'efivarfs', 'fuse.portal', 'fusectl', 'hugetlbfs', 'mqueue', 'nsfs', 'overlay', 'pipefs', 'proc', 'pstore', 'ramfs', 'rpc_pipefs', 'securityfs', 'selinuxfs', 'sockfs', 'sysfs', 'tracefs') | | warning | used_pct > 80 | | critical | used_pct > 90 | -| empty-state | 3 (UNKNOWN) | +| empty-state | 0 (OK) | | empty-syntax | %(status) - No drives found | | top-syntax | %(status) - \${problem_list} | | ok-syntax | %(status) - All %(count) drive(s) are ok | diff --git a/pkg/snclient/check_drivesize.go b/pkg/snclient/check_drivesize.go index 03f97c80..049b98b6 100644 --- a/pkg/snclient/check_drivesize.go +++ b/pkg/snclient/check_drivesize.go @@ -2,6 +2,7 @@ package snclient import ( "context" + "errors" "fmt" "maps" "sort" @@ -104,7 +105,7 @@ func (l *CheckDrivesize) Build() *CheckData { okSyntax: "%(status) - All %(count) drive(s) are ok", detailSyntax: "%(drive_or_name) %(used)/%(size) (%(used_pct | fmt=%.1f )%)", topSyntax: "%(status) - ${problem_list}", - emptyState: CheckExitUnknown, + emptyState: CheckExitOK, emptySyntax: "%(status) - No drives found", attributes: []CheckAttribute{ {name: "drive", description: "Technical name of drive"}, @@ -164,12 +165,24 @@ func (l *CheckDrivesize) Check(ctx context.Context, snc *Agent, check *CheckData } requiredDisks := map[string]map[string]string{} drives, err := l.getRequiredDisks(l.drives, false) - if err != nil { + var notFoundErr *PartitionNotFoundError + var notMountedErr *PartitionNotMountedError + switch { + case errors.As(err, ¬FoundErr): + log.Debugf("check_drivesize, drive is not found : %s, continuing with empty disks", notFoundErr.Error()) + case errors.As(err, ¬MountedErr): + // no special handling of mount errors + return nil, err + case err != nil: return nil, err + default: + break } maps.Copy(requiredDisks, drives) + // when checking for folders and their mountpoints, set parentFallback to true folders, err := l.getRequiredDisks(l.folders, true) + // handle folder search errors as well? if err != nil { return nil, err } @@ -417,3 +430,20 @@ func (l *CheckDrivesize) getFlagNames(drive map[string]string) []string { return flags } + +// have to define the error variables here, this file builds on all platforms +type PartitionNotFoundError struct { + Path string +} + +func (e *PartitionNotFoundError) Error() string { + return fmt.Sprintf("partition not found for path: %s", e.Path) +} + +type PartitionNotMountedError struct { + Path string +} + +func (e *PartitionNotMountedError) Error() string { + return fmt.Sprintf("partition not mounted for path: %s", e.Path) +} diff --git a/pkg/snclient/check_drivesize_other.go b/pkg/snclient/check_drivesize_other.go index 1ada75dd..35dd5da9 100644 --- a/pkg/snclient/check_drivesize_other.go +++ b/pkg/snclient/check_drivesize_other.go @@ -33,6 +33,7 @@ Check folder, no matter if its a mountpoint itself or not: ` } +// if parentFallback is true, try to find a parent folder that is a mountpoint. If its false, only the exact matches are checked for mountpoints. func (l *CheckDrivesize) getRequiredDisks(drives []string, parentFallback bool) (requiredDisks map[string]map[string]string, err error) { // create map of required disks/volumes with "drive_or_id" as primary key requiredDisks = map[string]map[string]string{} @@ -58,6 +59,7 @@ func (l *CheckDrivesize) getRequiredDisks(drives []string, parentFallback bool) return requiredDisks, nil } +// setDisks fills the requiredDisks map with all available disks/partitions func (l *CheckDrivesize) setDisks(requiredDisks map[string]map[string]string) (err error) { partitions, err := disk.Partitions(true) if err != nil { @@ -86,7 +88,7 @@ func (l *CheckDrivesize) setCustomPath(drive string, requiredDisks map[string]ma if err != nil && os.IsNotExist(err) { log.Debugf("%s: %s", drive, err.Error()) - return fmt.Errorf("failed to find disk partition: %s", err.Error()) + return &PartitionNotFoundError{Path: drive} } // try to find closest matching mount @@ -100,6 +102,7 @@ func (l *CheckDrivesize) setCustomPath(drive string, requiredDisks map[string]ma for i := range availMounts { vol := availMounts[i] if parentFallback && vol["drive"] != "" && strings.HasPrefix(drive, vol["drive"]) { + // try to find the longest matching parent path, that is a mountpoint if match == nil || len((*match)["drive"]) < len(vol["drive"]) { match = &vol } @@ -120,7 +123,7 @@ func (l *CheckDrivesize) setCustomPath(drive string, requiredDisks map[string]ma // add anyway to generate an error later with more default values filled in entry := l.driveEntry(drive) - entry["_error"] = fmt.Sprintf("%s not mounted", drive) + entry["_error"] = (&PartitionNotMountedError{Path: drive}).Error() requiredDisks[drive] = entry return nil diff --git a/pkg/snclient/check_drivesize_test.go b/pkg/snclient/check_drivesize_test.go index a198fadd..2a469562 100644 --- a/pkg/snclient/check_drivesize_test.go +++ b/pkg/snclient/check_drivesize_test.go @@ -37,10 +37,6 @@ func TestCheckDrivesize(t *testing.T) { assert.Contains(t, string(res.BuildPluginOutput()), "/ free", "output matches") assert.Contains(t, string(res.BuildPluginOutput()), ";0;;0;100", "output matches") - res = snc.RunCheck("check_drivesize", []string{"drive=k"}) - assert.Equalf(t, CheckExitUnknown, res.State, "state unknown") - assert.Contains(t, string(res.BuildPluginOutput()), "UNKNOWN - failed to find disk partition", "output matches") - // must not work, folder is not a mountpoint tmpFolder := t.TempDir() res = snc.RunCheck("check_drivesize", []string{"warn=inodes>100%", "crit=inodes>100%", "drive=" + tmpFolder}) @@ -55,3 +51,37 @@ func TestCheckDrivesize(t *testing.T) { StopTestAgent(t, snc) } + +func TestNonexistingDrive(t *testing.T) { + snc := StartTestAgent(t, "") + + res := snc.RunCheck("check_drivesize", []string{"drive=/dev/sdxyz999"}) + assert.Equalf(t, CheckExitOK, res.State, "state OK") + assert.Contains(t, string(res.BuildPluginOutput()), "OK - No drives found", "output matches") + + res = snc.RunCheck("check_drivesize", []string{"drive=k"}) + assert.Equalf(t, CheckExitOK, res.State, "state OK") + assert.Contains(t, string(res.BuildPluginOutput()), "OK - No drives found", "output matches") + + res = snc.RunCheck("check_drivesize", []string{"drive=/dev/sdxyz999", "empty-state=ok"}) + assert.Equalf(t, CheckExitOK, res.State, "state OK") + assert.Contains(t, string(res.BuildPluginOutput()), "OK - No drives found", "output matches") + + res = snc.RunCheck("check_drivesize", []string{"drive=/dev/sdxyz999", "empty-state=warn"}) + assert.Equalf(t, CheckExitWarning, res.State, "state OK") + assert.Contains(t, string(res.BuildPluginOutput()), "WARNING - No drives found", "output matches") + + res = snc.RunCheck("check_drivesize", []string{"drive=/dev/sdxyz999", "empty-state=warning"}) + assert.Equalf(t, CheckExitWarning, res.State, "state OK") + assert.Contains(t, string(res.BuildPluginOutput()), "WARNING - No drives found", "output matches") + + res = snc.RunCheck("check_drivesize", []string{"drive=/dev/sdxyz999", "empty-state=1"}) + assert.Equalf(t, CheckExitWarning, res.State, "state OK") + assert.Contains(t, string(res.BuildPluginOutput()), "WARNING - No drives found", "output matches") + + res = snc.RunCheck("check_drivesize", []string{"drive=/dev/sdxyz999", "empty-state=crit"}) + assert.Equalf(t, CheckExitCritical, res.State, "state OK") + assert.Contains(t, string(res.BuildPluginOutput()), "CRITICAL - No drives found", "output matches") + + StopTestAgent(t, snc) +} From 0a85a8b9612047fa94719de6b8c7e207129d6bbe Mon Sep 17 00:00:00 2001 From: inqrphl Date: Wed, 19 Nov 2025 16:53:42 +0100 Subject: [PATCH 2/7] - added new errors for the windows helper files - also report ok for windows partition not found errors - add more tests for windows --- pkg/snclient/check_drivesize.go | 20 ++++++++++++--- pkg/snclient/check_drivesize_other.go | 4 +-- pkg/snclient/check_drivesize_test.go | 4 --- pkg/snclient/check_drivesize_windows.go | 7 ++++-- pkg/snclient/check_drivesize_windows_test.go | 26 ++++++++++++++++++++ 5 files changed, 50 insertions(+), 11 deletions(-) diff --git a/pkg/snclient/check_drivesize.go b/pkg/snclient/check_drivesize.go index 049b98b6..a9ab682e 100644 --- a/pkg/snclient/check_drivesize.go +++ b/pkg/snclient/check_drivesize.go @@ -167,12 +167,16 @@ func (l *CheckDrivesize) Check(ctx context.Context, snc *Agent, check *CheckData drives, err := l.getRequiredDisks(l.drives, false) var notFoundErr *PartitionNotFoundError var notMountedErr *PartitionNotMountedError + var partitionDiscoveryErr *PartitionDiscoveryError switch { case errors.As(err, ¬FoundErr): - log.Debugf("check_drivesize, drive is not found : %s, continuing with empty disks", notFoundErr.Error()) + log.Debugf("check_drivesize, drive is not found : %s, continuing check with empty disks", notFoundErr.Error()) case errors.As(err, ¬MountedErr): // no special handling of mount errors return nil, err + case errors.As(err, &partitionDiscoveryErr): + // no special handling of discovery errors + return nil, err case err != nil: return nil, err default: @@ -434,16 +438,26 @@ func (l *CheckDrivesize) getFlagNames(drive map[string]string) []string { // have to define the error variables here, this file builds on all platforms type PartitionNotFoundError struct { Path string + err error } func (e *PartitionNotFoundError) Error() string { - return fmt.Sprintf("partition not found for path: %s", e.Path) + return fmt.Sprintf("partition not found for path: %s , error: %s", e.Path, e.err.Error()) } type PartitionNotMountedError struct { Path string + err error } func (e *PartitionNotMountedError) Error() string { - return fmt.Sprintf("partition not mounted for path: %s", e.Path) + return fmt.Sprintf("partition not mounted for path: %s , error: %s", e.Path, e.err.Error()) +} + +type PartitionDiscoveryError struct { + err error +} + +func (e *PartitionDiscoveryError) Error() string { + return fmt.Sprintf("error on disk.partitions call: %s", e.err.Error()) } diff --git a/pkg/snclient/check_drivesize_other.go b/pkg/snclient/check_drivesize_other.go index 35dd5da9..5dd24374 100644 --- a/pkg/snclient/check_drivesize_other.go +++ b/pkg/snclient/check_drivesize_other.go @@ -88,7 +88,7 @@ func (l *CheckDrivesize) setCustomPath(drive string, requiredDisks map[string]ma if err != nil && os.IsNotExist(err) { log.Debugf("%s: %s", drive, err.Error()) - return &PartitionNotFoundError{Path: drive} + return &PartitionNotFoundError{Path: drive, err: err} } // try to find closest matching mount @@ -123,7 +123,7 @@ func (l *CheckDrivesize) setCustomPath(drive string, requiredDisks map[string]ma // add anyway to generate an error later with more default values filled in entry := l.driveEntry(drive) - entry["_error"] = (&PartitionNotMountedError{Path: drive}).Error() + entry["_error"] = (&PartitionNotMountedError{Path: drive, err: fmt.Errorf("")}).Error() requiredDisks[drive] = entry return nil diff --git a/pkg/snclient/check_drivesize_test.go b/pkg/snclient/check_drivesize_test.go index 2a469562..99cdee88 100644 --- a/pkg/snclient/check_drivesize_test.go +++ b/pkg/snclient/check_drivesize_test.go @@ -59,10 +59,6 @@ func TestNonexistingDrive(t *testing.T) { assert.Equalf(t, CheckExitOK, res.State, "state OK") assert.Contains(t, string(res.BuildPluginOutput()), "OK - No drives found", "output matches") - res = snc.RunCheck("check_drivesize", []string{"drive=k"}) - assert.Equalf(t, CheckExitOK, res.State, "state OK") - assert.Contains(t, string(res.BuildPluginOutput()), "OK - No drives found", "output matches") - res = snc.RunCheck("check_drivesize", []string{"drive=/dev/sdxyz999", "empty-state=ok"}) assert.Equalf(t, CheckExitOK, res.State, "state OK") assert.Contains(t, string(res.BuildPluginOutput()), "OK - No drives found", "output matches") diff --git a/pkg/snclient/check_drivesize_windows.go b/pkg/snclient/check_drivesize_windows.go index dbba5d92..6ac16ef3 100644 --- a/pkg/snclient/check_drivesize_windows.go +++ b/pkg/snclient/check_drivesize_windows.go @@ -66,6 +66,9 @@ func (l *CheckDrivesize) getRequiredDisks(drives []string, parentFallback bool) case "all-volumes": l.setVolumes(requiredDisks) default: + // drives are like block devices c: -> /dev/sda + // partition is written into the disk in a partition table. it exists independently of volumes -> /dev/sdb3 + // volumes are accessible storage areas where a filesystem is made onto a partition. it can be mounted and have files -> / , /tmp/ , /home // "c" or "c:"" will use the drive c // "c:\" will use the volume // "c:\path" will use the best matching volume @@ -318,7 +321,7 @@ func (l *CheckDrivesize) setDisks(requiredDisks map[string]map[string]string) (e // "This drive is locked by BitLocker Drive Encryption. You must unlock this drive from Control Panel" // but there can still be valid elements in partitions, // so abort here only if partitions is empty. - return fmt.Errorf("disk partitions failed: %s", err.Error()) + return &PartitionDiscoveryError{err: err} } for _, partition := range partitions { drive := strings.TrimSuffix(partition.Device, "\\") + "\\" @@ -443,7 +446,7 @@ func (l *CheckDrivesize) setCustomPath(drive string, requiredDisks map[string]ma if err != nil && os.IsNotExist(err) { log.Debugf("%s: %s", drive, err.Error()) - return fmt.Errorf("failed to find disk partition: %s", err.Error()) + return &PartitionNotFoundError{Path: drive, err: err} } // try to find closes matching volume diff --git a/pkg/snclient/check_drivesize_windows_test.go b/pkg/snclient/check_drivesize_windows_test.go index 967896ad..9274bc14 100644 --- a/pkg/snclient/check_drivesize_windows_test.go +++ b/pkg/snclient/check_drivesize_windows_test.go @@ -68,3 +68,29 @@ func TestCheckDrivesize(t *testing.T) { StopTestAgent(t, snc) } + +func TestNonexistingDrive(t *testing.T) { + snc := StartTestAgent(t, "") + + res := snc.RunCheck("check_drivesize", []string{"drive=X"}) + assert.Equalf(t, CheckExitOK, res.State, "state OK") + assert.Contains(t, string(res.BuildPluginOutput()), "OK - No drives found", "output matches") + + res = snc.RunCheck("check_drivesize", []string{"drive=X:", "empty-state=warn"}) + assert.Equalf(t, CheckExitWarning, res.State, "state OK") + assert.Contains(t, string(res.BuildPluginOutput()), "WARNING - No drives found", "output matches") + + res = snc.RunCheck("check_drivesize", []string{"drive=X:\\", "empty-state=warn"}) + assert.Equalf(t, CheckExitWarning, res.State, "state OK") + assert.Contains(t, string(res.BuildPluginOutput()), "WARNING - No drives found", "output matches") + + res = snc.RunCheck("check_drivesize", []string{"drive=X", "empty-state=warn"}) + assert.Equalf(t, CheckExitWarning, res.State, "state OK") + assert.Contains(t, string(res.BuildPluginOutput()), "WARNING - No drives found", "output matches") + + res = snc.RunCheck("check_drivesize", []string{"drive=X", "empty-state=crit"}) + assert.Equalf(t, CheckExitCritical, res.State, "state OK") + assert.Contains(t, string(res.BuildPluginOutput()), "CRITICAL - No drives found", "output matches") + + StopTestAgent(t, snc) +} From a8d1ed365a381393aa4ffe4dc27f978fda5ff3ff Mon Sep 17 00:00:00 2001 From: inqrphl Date: Wed, 19 Nov 2025 17:12:17 +0100 Subject: [PATCH 3/7] - remove the faulty test for non-existing drive --- pkg/snclient/check_drivesize_windows_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/snclient/check_drivesize_windows_test.go b/pkg/snclient/check_drivesize_windows_test.go index 9274bc14..776c7d03 100644 --- a/pkg/snclient/check_drivesize_windows_test.go +++ b/pkg/snclient/check_drivesize_windows_test.go @@ -27,10 +27,6 @@ func TestCheckDrivesize(t *testing.T) { assert.Contains(t, string(res.BuildPluginOutput()), "C:\\ free", "output matches") assert.Contains(t, string(res.BuildPluginOutput()), ";0;;0;100", "output matches") - res = snc.RunCheck("check_drivesize", []string{"drive=k"}) - assert.Equalf(t, CheckExitUnknown, res.State, "state unknown") - assert.Contains(t, string(res.BuildPluginOutput()), "UNKNOWN - failed to find disk partition", "output matches") - res = snc.RunCheck("check_drivesize", []string{ "warning=used > 99", "crit=used > 99.5", From 2c449a87c649b6c3e26221fb2f571509941aa511 Mon Sep 17 00:00:00 2001 From: Ahmet Oeztuerk Date: Thu, 20 Nov 2025 16:33:31 +0100 Subject: [PATCH 4/7] revert the default state for empty output to Unknown --- docs/checks/commands/check_drivesize.md | 2 +- pkg/snclient/check_drivesize.go | 2 +- pkg/snclient/check_drivesize_test.go | 4 ++-- pkg/snclient/check_drivesize_windows_test.go | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/checks/commands/check_drivesize.md b/docs/checks/commands/check_drivesize.md index 41877204..7d53468a 100644 --- a/docs/checks/commands/check_drivesize.md +++ b/docs/checks/commands/check_drivesize.md @@ -56,7 +56,7 @@ Naemon Config | filter | fstype not in ('autofs', 'bdev', 'binfmt_misc', 'bpf', 'cgroup', 'cgroup2', 'configfs', 'cpuset', 'debugfs', 'devpts', 'devtmpfs', 'efivarfs', 'fuse.portal', 'fusectl', 'hugetlbfs', 'mqueue', 'nsfs', 'overlay', 'pipefs', 'proc', 'pstore', 'ramfs', 'rpc_pipefs', 'securityfs', 'selinuxfs', 'sockfs', 'sysfs', 'tracefs') | | warning | used_pct > 80 | | critical | used_pct > 90 | -| empty-state | 0 (OK) | +| empty-state | 3 (UNKNOWN) | | empty-syntax | %(status) - No drives found | | top-syntax | %(status) - \${problem_list} | | ok-syntax | %(status) - All %(count) drive(s) are ok | diff --git a/pkg/snclient/check_drivesize.go b/pkg/snclient/check_drivesize.go index a9ab682e..6205e392 100644 --- a/pkg/snclient/check_drivesize.go +++ b/pkg/snclient/check_drivesize.go @@ -105,7 +105,7 @@ func (l *CheckDrivesize) Build() *CheckData { okSyntax: "%(status) - All %(count) drive(s) are ok", detailSyntax: "%(drive_or_name) %(used)/%(size) (%(used_pct | fmt=%.1f )%)", topSyntax: "%(status) - ${problem_list}", - emptyState: CheckExitOK, + emptyState: CheckExitUnknown, emptySyntax: "%(status) - No drives found", attributes: []CheckAttribute{ {name: "drive", description: "Technical name of drive"}, diff --git a/pkg/snclient/check_drivesize_test.go b/pkg/snclient/check_drivesize_test.go index 99cdee88..4d03de95 100644 --- a/pkg/snclient/check_drivesize_test.go +++ b/pkg/snclient/check_drivesize_test.go @@ -56,8 +56,8 @@ func TestNonexistingDrive(t *testing.T) { snc := StartTestAgent(t, "") res := snc.RunCheck("check_drivesize", []string{"drive=/dev/sdxyz999"}) - assert.Equalf(t, CheckExitOK, res.State, "state OK") - assert.Contains(t, string(res.BuildPluginOutput()), "OK - No drives found", "output matches") + assert.Equalf(t, CheckExitUnknown, res.State, "state OK") + assert.Contains(t, string(res.BuildPluginOutput()), "UNKNOWN - No drives found", "output matches") res = snc.RunCheck("check_drivesize", []string{"drive=/dev/sdxyz999", "empty-state=ok"}) assert.Equalf(t, CheckExitOK, res.State, "state OK") diff --git a/pkg/snclient/check_drivesize_windows_test.go b/pkg/snclient/check_drivesize_windows_test.go index 776c7d03..bfb9f214 100644 --- a/pkg/snclient/check_drivesize_windows_test.go +++ b/pkg/snclient/check_drivesize_windows_test.go @@ -69,8 +69,8 @@ func TestNonexistingDrive(t *testing.T) { snc := StartTestAgent(t, "") res := snc.RunCheck("check_drivesize", []string{"drive=X"}) - assert.Equalf(t, CheckExitOK, res.State, "state OK") - assert.Contains(t, string(res.BuildPluginOutput()), "OK - No drives found", "output matches") + assert.Equalf(t, CheckExitUnknown, res.State, "state OK") + assert.Contains(t, string(res.BuildPluginOutput()), "UNKNOWN - No drives found", "output matches") res = snc.RunCheck("check_drivesize", []string{"drive=X:", "empty-state=warn"}) assert.Equalf(t, CheckExitWarning, res.State, "state OK") From 8401f53d892e445e2339da79f6d8bdfdeba4d94d Mon Sep 17 00:00:00 2001 From: Ahmet Oeztuerk Date: Thu, 4 Dec 2025 17:50:58 +0100 Subject: [PATCH 5/7] improve logging and add explanations to errors --- pkg/snclient/check_drivesize.go | 10 +++++++++- pkg/snclient/check_drivesize_other.go | 23 ++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/pkg/snclient/check_drivesize.go b/pkg/snclient/check_drivesize.go index 6205e392..b0e516e4 100644 --- a/pkg/snclient/check_drivesize.go +++ b/pkg/snclient/check_drivesize.go @@ -170,14 +170,22 @@ func (l *CheckDrivesize) Check(ctx context.Context, snc *Agent, check *CheckData var partitionDiscoveryErr *PartitionDiscoveryError switch { case errors.As(err, ¬FoundErr): - log.Debugf("check_drivesize, drive is not found : %s, continuing check with empty disks", notFoundErr.Error()) + log.Debugf("check_drivesize, drive is not found : %s, stopping check", notFoundErr.Error()) + + // do not return (nil,err) the drives will be empty, then the empty-state override can work when defined case errors.As(err, ¬MountedErr): // no special handling of mount errors + log.Debugf("check_drivesize, mounting error : %s, stopping check", notMountedErr.Error()) + return nil, err case errors.As(err, &partitionDiscoveryErr): // no special handling of discovery errors + log.Debugf("check_drivesize partition discovery error : %s, stopping check", partitionDiscoveryErr.Error()) + return nil, err case err != nil: + log.Debugf("check_drivesize error of unspecialized type : %s", err.Error()) + return nil, err default: break diff --git a/pkg/snclient/check_drivesize_other.go b/pkg/snclient/check_drivesize_other.go index 5dd24374..3dddf424 100644 --- a/pkg/snclient/check_drivesize_other.go +++ b/pkg/snclient/check_drivesize_other.go @@ -82,13 +82,13 @@ func (l *CheckDrivesize) setDisks(requiredDisks map[string]map[string]string) (e return nil } -func (l *CheckDrivesize) setCustomPath(drive string, requiredDisks map[string]map[string]string, parentFallback bool) (err error) { +func (l *CheckDrivesize) setCustomPath(path string, requiredDisks map[string]map[string]string, parentFallback bool) (err error) { // make sure path exists - _, err = os.Stat(drive) + _, err = os.Stat(path) if err != nil && os.IsNotExist(err) { - log.Debugf("%s: %s", drive, err.Error()) + log.Debugf("%s: %s", path, err.Error()) - return &PartitionNotFoundError{Path: drive, err: err} + return &PartitionNotFoundError{Path: path, err: err} } // try to find closest matching mount @@ -101,30 +101,31 @@ func (l *CheckDrivesize) setCustomPath(drive string, requiredDisks map[string]ma var match *map[string]string for i := range availMounts { vol := availMounts[i] - if parentFallback && vol["drive"] != "" && strings.HasPrefix(drive, vol["drive"]) { + if parentFallback && vol["drive"] != "" && strings.HasPrefix(path, vol["drive"]) { // try to find the longest matching parent path, that is a mountpoint if match == nil || len((*match)["drive"]) < len(vol["drive"]) { match = &vol } } // direct match, no need to search further - if drive == vol["drive"] { + if path == vol["drive"] { match = &vol break } } + if match != nil { - requiredDisks[drive] = utils.CloneStringMap(*match) - requiredDisks[drive]["drive"] = drive + requiredDisks[path] = utils.CloneStringMap(*match) + requiredDisks[path]["drive"] = path return nil } // add anyway to generate an error later with more default values filled in - entry := l.driveEntry(drive) - entry["_error"] = (&PartitionNotMountedError{Path: drive, err: fmt.Errorf("")}).Error() - requiredDisks[drive] = entry + entry := l.driveEntry(path) + entry["_error"] = (&PartitionNotMountedError{Path: path, err: fmt.Errorf("path :%s does exist, but could not match it to a drive. its likely that the partition is not mounted", path)}).Error() + requiredDisks[path] = entry return nil } From 24d7da00f2193f7e7936dde660a9632acada7f53 Mon Sep 17 00:00:00 2001 From: Ahmet Oeztuerk Date: Thu, 11 Dec 2025 17:53:33 +0100 Subject: [PATCH 6/7] check_drivesize ignore errors if empty-state is set fix the misunderstood condition about how drive/directory discovery errors are handled. previously, if the drive was not found the errors were always ignored, the check would not have any items in its list and the empty-state override would function since the list is empty corrected it so that the errors are ignored only when empty-state is set. if empty-state is set, it will ignore discovery errors, produce and empty list and the override will function. but if its not, it returns the error just as before. --- pkg/snclient/check_drivesize.go | 57 ++++++++++++++++----------- pkg/snclient/check_drivesize_other.go | 4 +- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/pkg/snclient/check_drivesize.go b/pkg/snclient/check_drivesize.go index b0e516e4..0dd9b8ec 100644 --- a/pkg/snclient/check_drivesize.go +++ b/pkg/snclient/check_drivesize.go @@ -168,35 +168,46 @@ func (l *CheckDrivesize) Check(ctx context.Context, snc *Agent, check *CheckData var notFoundErr *PartitionNotFoundError var notMountedErr *PartitionNotMountedError var partitionDiscoveryErr *PartitionDiscoveryError - switch { - case errors.As(err, ¬FoundErr): - log.Debugf("check_drivesize, drive is not found : %s, stopping check", notFoundErr.Error()) - // do not return (nil,err) the drives will be empty, then the empty-state override can work when defined - case errors.As(err, ¬MountedErr): - // no special handling of mount errors - log.Debugf("check_drivesize, mounting error : %s, stopping check", notMountedErr.Error()) - - return nil, err - case errors.As(err, &partitionDiscoveryErr): - // no special handling of discovery errors - log.Debugf("check_drivesize partition discovery error : %s, stopping check", partitionDiscoveryErr.Error()) - - return nil, err - case err != nil: - log.Debugf("check_drivesize error of unspecialized type : %s", err.Error()) - - return nil, err - default: - break + // if empty-state is overridden with the filter, emptyStateSet is true + // only handle the errors and return nil if its not overridden + if !check.emptyStateSet { + switch { + case errors.As(err, ¬FoundErr): + log.Debugf("check_drivesize, drive is not found : %s, stopping check", notFoundErr.Error()) + // do not return (nil,err), finalize the check wihtout entries to check.listData + // we want the empty-state override to work if its specified + case errors.As(err, ¬MountedErr): + // no special handling of mount errors + log.Debugf("check_drivesize, mounting error : %s, stopping check", notMountedErr.Error()) + + return nil, err + case errors.As(err, &partitionDiscoveryErr): + // no special handling of discovery errors + log.Debugf("check_drivesize partition discovery error : %s, stopping check", partitionDiscoveryErr.Error()) + + return nil, err + case err != nil: + log.Debugf("check_drivesize error of unspecialized type : %s", err.Error()) + + return nil, err + default: + break + } + } else { + log.Debugf("check_drivesize, ignoring errors relating to drive discovery due to empty-state being set.") } maps.Copy(requiredDisks, drives) // when checking for folders and their mountpoints, set parentFallback to true folders, err := l.getRequiredDisks(l.folders, true) - // handle folder search errors as well? - if err != nil { - return nil, err + // ignore errors if emptyState set is true, just like the drives + if !check.emptyStateSet { + if err != nil { + return nil, err + } + } else { + log.Debugf("check_drivesize, ignoring errors relating to directory discovery due to empty-state being set.") } maps.Copy(requiredDisks, folders) diff --git a/pkg/snclient/check_drivesize_other.go b/pkg/snclient/check_drivesize_other.go index 3dddf424..6e65317d 100644 --- a/pkg/snclient/check_drivesize_other.go +++ b/pkg/snclient/check_drivesize_other.go @@ -124,7 +124,9 @@ func (l *CheckDrivesize) setCustomPath(path string, requiredDisks map[string]map // add anyway to generate an error later with more default values filled in entry := l.driveEntry(path) - entry["_error"] = (&PartitionNotMountedError{Path: path, err: fmt.Errorf("path :%s does exist, but could not match it to a drive. its likely that the partition is not mounted", path)}).Error() + entry["_error"] = (&PartitionNotMountedError{ + Path: path, err: fmt.Errorf("path :%s does exist, but could not match it to a drive. its likely that the partition is not mounted", path), + }).Error() requiredDisks[path] = entry return nil From b601b8d62c7460712325e5738f235154d3ab1701 Mon Sep 17 00:00:00 2001 From: Ahmet Oeztuerk Date: Tue, 13 Jan 2026 13:37:31 +0100 Subject: [PATCH 7/7] linter: ignore function length --- pkg/snclient/check_drivesize.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/snclient/check_drivesize.go b/pkg/snclient/check_drivesize.go index 0dd9b8ec..277f973d 100644 --- a/pkg/snclient/check_drivesize.go +++ b/pkg/snclient/check_drivesize.go @@ -152,6 +152,7 @@ func (l *CheckDrivesize) Build() *CheckData { } } +//nolint:funlen // no need to split the function, it is simple as is func (l *CheckDrivesize) Check(ctx context.Context, snc *Agent, check *CheckData, _ []Argument) (*CheckResult, error) { enabled, _, _ := snc.config.Section("/modules").GetBool("CheckDisk") if !enabled {