Skip to content

Commit b5cf269

Browse files
authored
Merge branch 'main' into dependabot/go_modules/github.com/spf13/cobra-1.10.2
2 parents 6635183 + 30a51bc commit b5cf269

File tree

17 files changed

+224
-42
lines changed

17 files changed

+224
-42
lines changed

.golangci.yml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,20 +167,12 @@ linters:
167167
text: variable name 'ok' is too short
168168
- path: (.+)\.go$
169169
text: Function 'setListenTLSConfig' has too many statements
170-
- path: (.+)\.go$
171-
text: Function 'ParseArgs' has too many statements
172-
- path: (.+)\.go$
173-
text: 'cyclomatic complexity 45 of func `.*\.parseArgs` is high'
174-
- path: (.+)\.go$
175-
text: Function 'parseArgs' has too many statements
176170
- path: (.+)\.go$
177171
text: Function 'parseAnyArg' has too many statements
178172
- path: (.+)\.go$
179173
text: complexity.*setListenTLSConfig
180174
- path: (.+)\.go$
181175
text: complexity.*checkFlags
182-
- path: (.+)\.go$
183-
text: complexity.*ParseArgs
184176
- path: (.+)\.go$
185177
text: Function 'readConfiguration' has too many statements
186178
- path: (.+)\.go$

Changes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ This file documents the revision history for the SNClient agent.
22

33
next
44
- change minimum golang requirement to 1.25.5
5+
- add support for recursive `script path`
6+
- add support for cyclic alias check
57

68
0.39 Tue Nov 18 14:22:01 CET 2025
79
- optionally send HSTS header in HTTP response

docs/checks/external_commands/_index.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,20 @@ restart_service = NET START "$ARG1$"
110110
111111
If your scripts are located within the `${scripts}` folder, you can specify them using relative paths, as demonstrated in the examples. SNClient will automatically obtain the absolute path for these scripts and use it for execution. Prior to running the scripts, SNClient configures the working directory to be ${shared-dir}.
112112
113+
114+
#### Script Discovery
115+
116+
```
117+
; Load all scripts in a given folder - Load all (${script path}/*) scripts in a given directory and use them as commands.
118+
; Any executable file is considered a script. They do not have end with an script like extension.
119+
; In windows, executable files cannot be discerned. It will add every file under the directory.
120+
; Links are followed, and if they end up under script path, they will be added as a script.
121+
; If path ends with ** its subdirectories will be searched as well.
122+
script path = ${scripts}/autoinclude
123+
```
124+
125+
Scripts can also be automatically discovered and added, without defining them individually. This uses the `script path` setting. There is no way to change the alias, as they will use the scripts name and extension for their alias.
126+
113127
#### Wrapped Scripts
114128
115129
Specify script templates used to define script commands. These templates are expanded by scripts located in the Wrapped Scripts section. Use `%SCRIPT%` to represent the actual script and `%ARGS%` for any provided arguments.

packaging/snclient.ini

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,11 @@ allow nasty characters = false
346346
; Script root folder - Root path where all scripts are contained (You can not upload/download scripts outside this folder).
347347
script root = ${scripts}
348348
349-
; Load all scripts in a given folder - Load all (${script path}/*.*) scripts in a given directory and use them as commands.
349+
; Load all scripts in a given folder - Load all (${script path}/*) scripts in a given directory and use them as commands.
350+
; Any executable file is considered a script. They do not have end with an script like extension.
351+
; In windows, executable files cannot be discerned. It will add every file under the directory.
352+
; Links are followed, and if they end up under script path, they will be added as a script.
353+
; If path ends with ** its subdirectories will be searched as well.
350354
script path =
351355
352356
; ignore perfdata - Do not parse performance data from the output

pkg/convert/convert.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ func Int32E(raw any) (int32, error) {
156156
return 0, fmt.Errorf("number to large for int32")
157157
}
158158

159+
if num < math.MinInt32 {
160+
return 0, fmt.Errorf("number to small for int32")
161+
}
162+
159163
return int32(num), nil
160164
}
161165
}

pkg/humanize/humanize.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,12 @@ func NumF(num int64, precision int) string {
122122
prefix = "-"
123123
}
124124

125-
return prefix + humanizeBytes(uint64(num), 1000, []string{"", "k", "M", "G", "T", "P", "E"}, precision)
125+
// useless but makes gosec G115 happy
126+
if num >= 0 {
127+
return prefix + humanizeBytes(uint64(num), 1000, []string{"", "k", "M", "G", "T", "P", "E"}, precision)
128+
}
129+
130+
return ""
126131
}
127132

128133
// Bytes(82854982) -> 83 MB

pkg/humanize/humanize_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func TestParseBytes(t *testing.T) {
3030
} else {
3131
require.NoError(t, err)
3232
}
33-
assert.Equalf(t, int64(tst.res), int64(res), "ParseBytes: %s -> %d", tst.in, res)
33+
assert.Equalf(t, tst.res, res, "ParseBytes: %s -> %d", tst.in, res)
3434
}
3535
}
3636

pkg/nrpe/nrpe.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"hash/crc32"
88
"io"
99
"strings"
10+
11+
"github.com/consol-monitoring/snclient/pkg/convert"
1012
)
1113

1214
/*
@@ -133,7 +135,11 @@ func BuildPacketV4(packetType, statusCode uint16, statusLine []byte) *Packet {
133135
binary.BigEndian.PutUint32(packet.crc32, 0)
134136
binary.BigEndian.PutUint16(packet.statusCode, statusCode)
135137
binary.BigEndian.PutUint16(packet.alignment, 0)
136-
binary.BigEndian.PutUint32(packet.dataLength, uint32(dataLength))
138+
dataLength32, err := convert.UInt32E(dataLength)
139+
if err != nil {
140+
panic("should not happen, size is checked earlier already")
141+
}
142+
binary.BigEndian.PutUint32(packet.dataLength, dataLength32)
137143

138144
copy(packet.data, statusLine)
139145
packet.data[dataLength-1] = 0 // add null byte

pkg/snclient/check_alias.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func (a *CheckAlias) Check(ctx context.Context, snc *Agent, check *CheckData, _
4242

4343
log.Debugf("command after macros expanded: %s %s", a.command, replacedStr)
4444
}
45-
statusResult, _ := snc.runCheck(ctx, a.command, cmdArgs, check.timeout, nil, true)
45+
statusResult, _ := snc.runCheck(ctx, a.command, cmdArgs, check.timeout, nil, true, true)
4646

4747
statusResult.ParsePerformanceDataFromOutputCond(a.command, a.config)
4848

pkg/snclient/check_alias_test.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ CheckExternalScripts = enabled
1313
1414
[/settings/external scripts/alias]
1515
alias_cpu = check_cpu warn=load=101 crit=load=102
16+
check_memory = check_memory -a type=physical warn="used > 100" crit="used > 100"
17+
check_uptime = check_uptime "warn=uptime > 3000d" "crit=uptime > 6000d"
1618
1719
[/settings/external scripts/alias/alias_cpu2]
1820
command = check_cpu warn=load=101 crit=load=102
@@ -37,7 +39,7 @@ allow arguments = yes
3739
`
3840
snc := StartTestAgent(t, config)
3941

40-
assert.Lenf(t, snc.runSet.cmdAliases, 6, "there should be one alias")
42+
assert.Lenf(t, snc.runSet.cmdAliases, 8, "there should be 8 alias entries")
4143

4244
res := snc.RunCheck("alias_cpu", []string{})
4345
assert.Equalf(t, CheckExitOK, res.State, "state OK")
@@ -84,5 +86,20 @@ allow arguments = yes
8486
assert.Equalf(t, CheckExitOK, res.State, "state OK")
8587
assert.Equalf(t, "test 123 456", string(res.BuildPluginOutput()), "plugin output matches")
8688

89+
// recursive memory check
90+
res = snc.RunCheck("check_memory", []string{})
91+
assert.Equalf(t, CheckExitOK, res.State, "state OK")
92+
assert.Regexpf(t, `^OK - physical =`, string(res.BuildPluginOutput()), "output matches")
93+
94+
// help from aliased check
95+
res = snc.RunCheck("check_memory", []string{"help"})
96+
assert.Equalf(t, CheckExitUnknown, res.State, "state Unknown")
97+
assert.Regexpf(t, `There are several types of memory that can be checked`, string(res.BuildPluginOutput()), "output matches")
98+
99+
// recursive uptime check
100+
res = snc.RunCheck("check_uptime", []string{})
101+
assert.Equalf(t, CheckExitOK, res.State, "state OK")
102+
assert.Regexpf(t, `^OK - uptime:`, string(res.BuildPluginOutput()), "output matches")
103+
87104
StopTestAgent(t, snc)
88105
}

0 commit comments

Comments
 (0)