Skip to content

Commit 99e7598

Browse files
authored
Add NGINX Agent config validation (#1039)
1 parent d13a27c commit 99e7598

17 files changed

+239
-182
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
github.com/docker/docker v27.3.1+incompatible
1212
github.com/fsnotify/fsnotify v1.8.0
1313
github.com/go-resty/resty/v2 v2.16.2
14+
github.com/goccy/go-yaml v1.17.1
1415
github.com/google/go-cmp v0.6.0
1516
github.com/google/uuid v1.6.0
1617
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
179179
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
180180
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
181181
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
182+
github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
183+
github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
182184
github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0=
183185
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
184186
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=

internal/collector/otel_collector_plugin_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ func TestCollector_ProcessResourceUpdateTopic(t *testing.T) {
324324
Server: &config.ServerConfig{
325325
Host: "",
326326
Port: 0,
327-
Type: 0,
327+
Type: config.Grpc,
328328
},
329329
TLS: &config.TLSConfig{
330330
Cert: "",
@@ -408,7 +408,7 @@ func TestCollector_ProcessResourceUpdateTopicFails(t *testing.T) {
408408
Server: &config.ServerConfig{
409409
Host: "",
410410
Port: 0,
411-
Type: 0,
411+
Type: config.Grpc,
412412
},
413413
TLS: &config.TLSConfig{
414414
Cert: "",

internal/collector/otelcol.tmpl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ receivers:
3737
{{- range $index, $otlpReceiver := .Receivers.OtlpReceivers }}
3838
otlp/{{$index}}:
3939
protocols:
40-
{{- if eq .Server.Type 0 }}
41-
grpc:
42-
endpoint: "{{ .Server.Host }}:{{ .Server.Port }}"
43-
{{- if and .OtlpTLSConfig (or (gt (len .OtlpTLSConfig.Key) 0) (gt (len .OtlpTLSConfig.Cert) 0) (gt (len .OtlpTLSConfig.Key) 0)) }}
40+
{{- if eq .Server.Type "http" }}
41+
http:
42+
endpoint: "{{- .Server.Host -}}:{{- .Server.Port -}}"
43+
{{- if .OtlpTLSConfig }}
4444
tls:
4545
{{ if gt (len .OtlpTLSConfig.Cert) 0 -}}
4646
cert_file: {{ .OtlpTLSConfig.Cert }}
@@ -53,9 +53,9 @@ receivers:
5353
{{- end }}
5454
{{- end }}
5555
{{- else }}
56-
http:
57-
endpoint: "{{- .Server.Host -}}:{{- .Server.Port -}}"
58-
{{- if .OtlpTLSConfig }}
56+
grpc:
57+
endpoint: "{{ .Server.Host }}:{{ .Server.Port }}"
58+
{{- if and .OtlpTLSConfig (or (gt (len .OtlpTLSConfig.Key) 0) (gt (len .OtlpTLSConfig.Cert) 0) (gt (len .OtlpTLSConfig.Key) 0)) }}
5959
tls:
6060
{{ if gt (len .OtlpTLSConfig.Cert) 0 -}}
6161
cert_file: {{ .OtlpTLSConfig.Cert }}

internal/collector/settings_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func TestTemplateWrite(t *testing.T) {
6868
Server: &config.ServerConfig{
6969
Host: "localhost",
7070
Port: 9876,
71-
Type: 0,
71+
Type: config.Grpc,
7272
},
7373
TLS: nil,
7474
}
@@ -106,7 +106,7 @@ func TestTemplateWrite(t *testing.T) {
106106
Server: &config.ServerConfig{
107107
Host: "localhost",
108108
Port: 4317,
109-
Type: 0,
109+
Type: config.Grpc,
110110
},
111111
OtlpTLSConfig: &config.OtlpTLSConfig{
112112
Cert: "/tmp/cert.pem",

internal/config/config.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package config
77

88
import (
9+
"bytes"
910
"context"
1011
"encoding/json"
1112
"errors"
@@ -20,6 +21,7 @@ import (
2021

2122
"github.com/nginx/agent/v3/internal/datasource/file"
2223

24+
"github.com/goccy/go-yaml"
2325
uuidLibrary "github.com/nginx/agent/v3/pkg/id"
2426
selfsignedcerts "github.com/nginx/agent/v3/pkg/tls"
2527
"github.com/spf13/cobra"
@@ -523,6 +525,11 @@ func getConfigFilePaths() []string {
523525
}
524526

525527
func loadPropertiesFromFile(cfg string) error {
528+
validationError := validateYamlFile(cfg)
529+
if validationError != nil {
530+
return validationError
531+
}
532+
526533
viperInstance.SetConfigFile(cfg)
527534
viperInstance.SetConfigType("yaml")
528535
err := viperInstance.MergeInConfig()
@@ -533,6 +540,20 @@ func loadPropertiesFromFile(cfg string) error {
533540
return nil
534541
}
535542

543+
func validateYamlFile(filePath string) error {
544+
fileContents, readError := os.ReadFile(filePath)
545+
if readError != nil {
546+
return fmt.Errorf("failed to read file %s: %w", filePath, readError)
547+
}
548+
549+
decoder := yaml.NewDecoder(bytes.NewReader(fileContents), yaml.DisallowUnknownField())
550+
if err := decoder.Decode(&Config{}); err != nil {
551+
return errors.New(yaml.FormatError(err, false, false))
552+
}
553+
554+
return nil
555+
}
556+
536557
func normalizeFunc(f *flag.FlagSet, name string) flag.NormalizedName {
537558
from := []string{"_", "."}
538559
to := "-"

internal/config/config_test.go

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package config
66

77
import (
8+
"errors"
89
"os"
910
"path"
1011
"strings"
@@ -29,6 +30,9 @@ func TestRegisterConfigFile(t *testing.T) {
2930
require.NoError(t, err)
3031
defer helpers.RemoveFileWithErrorCheck(t, file.Name())
3132

33+
_, err = file.WriteString("log:")
34+
require.NoError(t, err)
35+
3236
currentDirectory, err := os.Getwd()
3337
require.NoError(t, err)
3438

@@ -596,6 +600,37 @@ func TestParseJSON(t *testing.T) {
596600
}
597601
}
598602

603+
func TestValidateYamlFile(t *testing.T) {
604+
tests := []struct {
605+
expected error
606+
name string
607+
input string
608+
}{
609+
{
610+
name: "Test 1: Valid NGINX Agent config file",
611+
input: "testdata/nginx-agent.conf",
612+
expected: nil,
613+
},
614+
{
615+
name: "Test 2: Invalid format NGINX Agent config file",
616+
input: "testdata/invalid-format-nginx-agent.conf",
617+
expected: errors.New("[2:1] unknown field \"level\""),
618+
},
619+
{
620+
name: "Test 3: Unknown field in NGINX Agent config file",
621+
input: "testdata/unknown-field-nginx-agent.conf",
622+
expected: errors.New("[5:1] unknown field \"unknown_field\""),
623+
},
624+
}
625+
626+
for _, tt := range tests {
627+
t.Run(tt.name, func(t *testing.T) {
628+
result := validateYamlFile(tt.input)
629+
assert.Equal(t, tt.expected, result)
630+
})
631+
}
632+
}
633+
599634
func getAgentConfig() *Config {
600635
return &Config{
601636
UUID: "",
@@ -636,6 +671,7 @@ func getAgentConfig() *Config {
636671
Server: &ServerConfig{
637672
Host: "127.0.0.1",
638673
Port: 1234,
674+
Type: Grpc,
639675
},
640676
TLS: &TLSConfig{
641677
Cert: "/path/to/server-cert.pem",
@@ -660,7 +696,7 @@ func getAgentConfig() *Config {
660696
Server: &ServerConfig{
661697
Host: "localhost",
662698
Port: 4317,
663-
Type: 0,
699+
Type: Grpc,
664700
},
665701
Auth: &AuthConfig{
666702
Token: "even-secreter-token",
@@ -696,7 +732,6 @@ func getAgentConfig() *Config {
696732
Server: &ServerConfig{
697733
Host: "localhost",
698734
Port: 1337,
699-
Type: 0,
700735
},
701736
Path: "/",
702737
},

internal/config/mapper.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ func FromCommandProto(config *mpi.CommandServer) *Command {
2121
Host: config.GetServer().GetHost(),
2222
Port: int(config.GetServer().GetPort()),
2323
}
24-
if config.GetServer().GetType() != mpi.ServerSettings_SERVER_SETTINGS_TYPE_UNDEFINED {
25-
cmd.Server.Type = ServerType(config.GetServer().GetType())
24+
if config.GetServer().GetType() == mpi.ServerSettings_SERVER_SETTINGS_TYPE_GRPC {
25+
cmd.Server.Type = Grpc
2626
}
2727
} else {
2828
cmd.Server = nil
@@ -55,10 +55,15 @@ func ToCommandProto(cmd *Command) *mpi.CommandServer {
5555

5656
// Map ServerConfig to the ServerSettings
5757
if cmd.Server != nil {
58+
protoServerType := mpi.ServerSettings_SERVER_SETTINGS_TYPE_UNDEFINED
59+
if cmd.Server.Type == Grpc {
60+
protoServerType = mpi.ServerSettings_SERVER_SETTINGS_TYPE_GRPC
61+
}
62+
5863
protoConfig.Server = &mpi.ServerSettings{
5964
Host: cmd.Server.Host,
6065
Port: int32(cmd.Server.Port),
61-
Type: mpi.ServerSettings_ServerType(cmd.Server.Type + 1),
66+
Type: protoServerType,
6267
}
6368
}
6469

internal/config/mapper_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func TestFromCommandProto(t *testing.T) {
2323
Server: &mpi.ServerSettings{
2424
Host: getAgentConfig().Command.Server.Host,
2525
Port: int32(getAgentConfig().Command.Server.Port),
26-
Type: 1,
26+
Type: mpi.ServerSettings_SERVER_SETTINGS_TYPE_GRPC,
2727
},
2828
Auth: &mpi.AuthSettings{},
2929
Tls: &mpi.TLSSettings{
@@ -64,7 +64,7 @@ func TestFromCommandProto(t *testing.T) {
6464
Server: &mpi.ServerSettings{
6565
Host: getAgentConfig().Command.Server.Host,
6666
Port: int32(getAgentConfig().Command.Server.Port),
67-
Type: 1, // gRPC
67+
Type: mpi.ServerSettings_SERVER_SETTINGS_TYPE_GRPC,
6868
},
6969
Tls: &mpi.TLSSettings{
7070
Cert: getAgentConfig().Command.TLS.Cert,
@@ -86,7 +86,7 @@ func TestFromCommandProto(t *testing.T) {
8686
Server: &mpi.ServerSettings{
8787
Host: getAgentConfig().Command.Server.Host,
8888
Port: int32(getAgentConfig().Command.Server.Port),
89-
Type: 1, // Change to HTTP when supported
89+
Type: mpi.ServerSettings_SERVER_SETTINGS_TYPE_GRPC,
9090
},
9191
Auth: &mpi.AuthSettings{},
9292
},
@@ -132,7 +132,7 @@ func TestToCommandProto(t *testing.T) {
132132
Server: &mpi.ServerSettings{
133133
Host: getAgentConfig().Command.Server.Host,
134134
Port: int32(getAgentConfig().Command.Server.Port),
135-
Type: 2,
135+
Type: mpi.ServerSettings_SERVER_SETTINGS_TYPE_GRPC,
136136
},
137137
Auth: &mpi.AuthSettings{},
138138
Tls: &mpi.TLSSettings{
@@ -174,7 +174,7 @@ func TestToCommandProto(t *testing.T) {
174174
Server: &mpi.ServerSettings{
175175
Host: getAgentConfig().Command.Server.Host,
176176
Port: int32(getAgentConfig().Command.Server.Port),
177-
Type: 2, // gRPC
177+
Type: mpi.ServerSettings_SERVER_SETTINGS_TYPE_GRPC,
178178
},
179179
Tls: &mpi.TLSSettings{
180180
Cert: getAgentConfig().Command.TLS.Cert,
@@ -196,7 +196,7 @@ func TestToCommandProto(t *testing.T) {
196196
Server: &mpi.ServerSettings{
197197
Host: getAgentConfig().Command.Server.Host,
198198
Port: int32(getAgentConfig().Command.Server.Port),
199-
Type: 2,
199+
Type: mpi.ServerSettings_SERVER_SETTINGS_TYPE_GRPC,
200200
},
201201
Auth: &mpi.AuthSettings{},
202202
},
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
log:
2+
level: debug
3+

0 commit comments

Comments
 (0)