Skip to content

Commit 30a51bc

Browse files
committed
add support for cyclic alias check
1 parent f516f64 commit 30a51bc

File tree

9 files changed

+43
-21
lines changed

9 files changed

+43
-21
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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ This file documents the revision history for the SNClient agent.
33
next
44
- change minimum golang requirement to 1.25.5
55
- add support for recursive `script path`
6+
- add support for cyclic alias check
67

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

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
}

pkg/snclient/checkdata.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,8 @@ func (cd *CheckData) parseStateString(state string) int64 {
599599

600600
// parseArgs parses check arguments into the CheckData struct
601601
// and returns all unknown options
602+
//
603+
//nolint:funlen,gocyclo // it is not complex, it is just a long list of options
602604
func (cd *CheckData) parseArgs(args []string) (argList []Argument, err error) {
603605
cd.rawArgs = args
604606
cd.hasArgsSupplied = map[string]bool{}
@@ -730,6 +732,8 @@ func (cd *CheckData) parseArgs(args []string) (argList []Argument, err error) {
730732
argList = append(argList, Argument{key: keyword, value: argValue})
731733
case keyword == "-h", keyword == "--help":
732734
cd.showHelp = PluginHelp
735+
case keyword == "-a":
736+
// ignore -a for legacy compatibility
733737
default:
734738
return nil, fmt.Errorf("unknown argument: %s", keyword)
735739
}

pkg/snclient/inventory.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func (snc *Agent) buildInventory(ctx context.Context, modules []string) *Invento
111111
sort.Strings(keys)
112112

113113
for _, k := range keys {
114-
check, _ := snc.getCheck(k)
114+
check, _ := snc.getCheck(k, false)
115115
handler := check.Handler()
116116
meta := handler.Build()
117117
if !meta.isImplemented(runtime.GOOS) {

pkg/snclient/listen_nrpe.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func (l *HandlerNRPE) ServeTCP(snc *Agent, con net.Conn) {
116116
cmd = "check_snclient_version"
117117
args = []string{}
118118
}
119-
statusResult := snc.RunCheckWithContext(context.TODO(), cmd, args, 0, l.conf)
119+
statusResult := snc.RunCheckWithContext(context.TODO(), cmd, args, 0, l.conf, false)
120120

121121
output := statusResult.BuildPluginOutput()
122122
state, err2 := convert.UInt16E(statusResult.State)

pkg/snclient/listen_web.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ func (l *HandlerWeb) runCheck(req *http.Request, command string) (result *CheckR
363363
}
364364
}
365365

366-
return l.snc.RunCheckWithContext(req.Context(), command, args, timeoutSeconds, l.conf)
366+
return l.snc.RunCheckWithContext(req.Context(), command, args, timeoutSeconds, l.conf, false)
367367
}
368368

369369
type HandlerWebLegacy struct {

pkg/snclient/snclient.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -734,13 +734,13 @@ func (snc *Agent) logPanicRecover() {
734734

735735
// RunCheck calls check by name and returns the check result.
736736
func (snc *Agent) RunCheck(name string, args []string) *CheckResult {
737-
return snc.RunCheckWithContext(context.TODO(), name, args, 0, nil)
737+
return snc.RunCheckWithContext(context.TODO(), name, args, 0, nil, false)
738738
}
739739

740740
// RunCheckWithContext calls check by name and returns the check result.
741741
// secCon configuration section will be used to check for nasty characters and allowed arguments.
742-
func (snc *Agent) RunCheckWithContext(ctx context.Context, name string, args []string, timeoutOverride float64, transportConf *ConfigSection) *CheckResult {
743-
res, chk := snc.runCheck(ctx, name, args, timeoutOverride, transportConf, false)
742+
func (snc *Agent) RunCheckWithContext(ctx context.Context, name string, args []string, timeoutOverride float64, transportConf *ConfigSection, skipAlias bool) *CheckResult {
743+
res, chk := snc.runCheck(ctx, name, args, timeoutOverride, transportConf, false, skipAlias)
744744
if res.Raw == nil || res.Raw.showHelp == 0 {
745745
if chk != nil {
746746
res.Finalize(chk.timezone)
@@ -752,13 +752,13 @@ func (snc *Agent) RunCheckWithContext(ctx context.Context, name string, args []s
752752
return res
753753
}
754754

755-
func (snc *Agent) runCheck(ctx context.Context, name string, args []string, timeoutOverride float64, transportConf *ConfigSection, skipAllowedCheck bool) (*CheckResult, *CheckData) {
755+
func (snc *Agent) runCheck(ctx context.Context, name string, args []string, timeoutOverride float64, transportConf *ConfigSection, skipAllowedCheck, skipAlias bool) (*CheckResult, *CheckData) {
756756
log.Tracef("command: %s", name)
757757
log.Tracef("args: %#v", args)
758758
if deadline, ok := ctx.Deadline(); ok {
759759
log.Tracef("ctx deadline: %s", time.Until(deadline).String())
760760
}
761-
check, ok := snc.getCheck(name)
761+
check, ok := snc.getCheck(name, skipAlias)
762762
if !ok {
763763
return &CheckResult{
764764
State: CheckExitUnknown,
@@ -857,6 +857,12 @@ func (snc *Agent) runHelp(ctx context.Context, chk *CheckData, handler CheckHand
857857
switch builtin := handler.(type) {
858858
case *CheckBuiltin:
859859
help = builtin.Help(ctx, snc, chk, chk.showHelp)
860+
case *CheckAlias:
861+
alias, ok := snc.getCheck(builtin.command, true)
862+
if ok {
863+
realChk := alias.Handler().Build()
864+
help = realChk.Help(chk.showHelp)
865+
}
860866
default:
861867
help = chk.Help(chk.showHelp)
862868
}
@@ -868,10 +874,12 @@ func (snc *Agent) runHelp(ctx context.Context, chk *CheckData, handler CheckHand
868874
}
869875
}
870876

871-
func (snc *Agent) getCheck(name string) (_ *CheckEntry, ok bool) {
877+
func (snc *Agent) getCheck(name string, skipAlias bool) (_ *CheckEntry, ok bool) {
872878
if snc.runSet != nil {
873-
if chk, ok := snc.runSet.cmdAliases[name]; ok {
874-
return &chk, ok
879+
if !skipAlias {
880+
if chk, ok := snc.runSet.cmdAliases[name]; ok {
881+
return &chk, ok
882+
}
875883
}
876884
if chk, ok := snc.runSet.cmdWraps[name]; ok {
877885
return &chk, ok

0 commit comments

Comments
 (0)