Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions sdk/config_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,10 @@ import (
const (
plusAPIDirective = "api"
stubStatusAPIDirective = "stub_status"
apiFormat = "http://%s%s"
predefinedAccessLogFormat = "$remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\""
httpClientTimeout = 1 * time.Second
httpPrefix = "http://"
httpsPrefix = "https://"
)

var readLock = sync.Mutex{}
Expand Down Expand Up @@ -698,6 +699,7 @@ func parseAddressesFromServerDirective(parent *crossplane.Directive) []string {

for _, dir := range parent.Block {
hostname := "127.0.0.1"
prefix := httpPrefix

switch dir.Directive {
case "listen":
Expand All @@ -718,14 +720,22 @@ func parseAddressesFromServerDirective(parent *crossplane.Directive) []string {
hostname = dir.Args[0]
}
}
hosts = append(hosts, hostname)

if len(dir.Args) > 1 {
secondArg := dir.Args[1]
if secondArg == "ssl" {
prefix = httpsPrefix
}
}

hosts = append(hosts, prefix+hostname)
case "server_name":
if dir.Args[0] == "_" {
// default server
continue
}
hostname = dir.Args[0]
hosts = append(hosts, hostname)
hosts = append(hosts, prefix+hostname)
}
}

Expand Down Expand Up @@ -952,11 +962,11 @@ func getUrlsForLocationDirective(parent *crossplane.Directive, current *crosspla
addresses := parseAddressesFromServerDirective(parent)

for _, address := range addresses {
path := parsePathFromLocationDirective(current)
pathFromLocationDirective := parsePathFromLocationDirective(current)

switch locChild.Directive {
case locationDirectiveName:
urls = append(urls, fmt.Sprintf(apiFormat, address, path))
urls = append(urls, address+pathFromLocationDirective)
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/core/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,9 @@ func getNginx() Nginx {
NginxClientVersion: Viper.GetInt(NginxClientVersion),
ConfigReloadMonitoringPeriod: Viper.GetDuration(NginxConfigReloadMonitoringPeriod),
TreatWarningsAsErrors: Viper.GetBool(NginxTreatWarningsAsErrors),
ApiTls: TLSConfig{
Ca: Viper.GetString(NginxApiTlsCa),
},
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/core/config/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ var (
NginxClientVersion: 7, // NGINX Plus R25+
ConfigReloadMonitoringPeriod: 10 * time.Second,
TreatWarningsAsErrors: false,
ApiTls: TLSConfig{
Ca: "",
},
},
ConfigDirs: "/etc/nginx:/usr/local/etc/nginx:/usr/share/nginx/modules:/etc/nms",
IgnoreDirectives: []string{},
Expand Down Expand Up @@ -175,6 +178,7 @@ const (
NginxClientVersion = NginxKey + agent_config.KeyDelimiter + "client_version"
NginxConfigReloadMonitoringPeriod = NginxKey + agent_config.KeyDelimiter + "config_reload_monitoring_period"
NginxTreatWarningsAsErrors = NginxKey + agent_config.KeyDelimiter + "treat_warnings_as_errors"
NginxApiTlsCa = NginxKey + agent_config.KeyDelimiter + "api_tls_ca"

// viper keys used in config
DataplaneKey = "dataplane"
Expand Down Expand Up @@ -321,6 +325,11 @@ var (
Usage: "On nginx -t, treat warnings as failures on configuration application.",
DefaultValue: Defaults.Nginx.TreatWarningsAsErrors,
},
&StringFlag{
Name: NginxApiTlsCa,
Usage: "The NGINX Plus CA certificate file location needed to call the NGINX Plus API if SSL is enabled.",
DefaultValue: Defaults.Nginx.ApiTls.Ca,
},
// Metrics
&DurationFlag{
Name: MetricsCollectionInterval,
Expand Down
17 changes: 17 additions & 0 deletions src/core/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
package config

import (
"path/filepath"
"strings"
"time"

"github.com/nginx/agent/sdk/v2/backoff"
Expand Down Expand Up @@ -90,6 +92,20 @@ func (c *Config) GetMetricsBackoffSettings() backoff.BackoffSettings {
}
}

func (c *Config) IsFileAllowed(path string) bool {
if !filepath.IsAbs(path) {
return false
}

for dir := range c.AllowedDirectoriesMap {
if strings.HasPrefix(path, dir) {
return true
}
}

return false
}

type Server struct {
Host string `mapstructure:"host" yaml:"-"`
GrpcPort int `mapstructure:"grpcPort" yaml:"-"`
Expand Down Expand Up @@ -139,6 +155,7 @@ type Nginx struct {
NginxClientVersion int `mapstructure:"client_version" yaml:"-"`
ConfigReloadMonitoringPeriod time.Duration `mapstructure:"config_reload_monitoring_period" yaml:"-"`
TreatWarningsAsErrors bool `mapstructure:"treat_warnings_as_errors" yaml:"-"`
ApiTls TLSConfig `mapstructure:"api_tls" yaml:"-"`
}

type Dataplane struct {
Expand Down
5 changes: 4 additions & 1 deletion src/core/metrics/collectors/nginx.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ func buildSources(dimensions *metrics.CommonDim, binary core.NginxBinary, collec
nginxSources = append(nginxSources, sources.NewNginxAccessLog(dimensions, sources.OSSNamespace, binary, sources.OSSNginxType, collectorConf.CollectionInterval))
nginxSources = append(nginxSources, sources.NewNginxErrorLog(dimensions, sources.OSSNamespace, binary, sources.OSSNginxType, collectorConf.CollectionInterval))
} else if collectorConf.PlusAPI != "" {
nginxSources = append(nginxSources, sources.NewNginxPlus(dimensions, sources.OSSNamespace, sources.PlusNamespace, collectorConf.PlusAPI, collectorConf.ClientVersion))
nginxPlusSource := sources.NewNginxPlus(dimensions, sources.OSSNamespace, sources.PlusNamespace, collectorConf.PlusAPI, collectorConf.ClientVersion, conf)
if nginxPlusSource != nil {
nginxSources = append(nginxSources, nginxPlusSource)
}
nginxSources = append(nginxSources, sources.NewNginxAccessLog(dimensions, sources.OSSNamespace, binary, sources.PlusNginxType, collectorConf.CollectionInterval))
nginxSources = append(nginxSources, sources.NewNginxErrorLog(dimensions, sources.OSSNamespace, binary, sources.PlusNginxType, collectorConf.CollectionInterval))
} else {
Expand Down
43 changes: 40 additions & 3 deletions src/core/metrics/sources/nginx_plus.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@ package sources

import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"math"
"net/http"
"os"
"sync"

"github.com/nginx/agent/v2/src/core/config"

"github.com/nginx/agent/sdk/v2/proto"
"github.com/nginx/agent/v2/src/core/metrics"

Expand Down Expand Up @@ -67,6 +73,7 @@ type NginxPlus struct {
init sync.Once
clientVersion int
logger *MetricSourceLogger
client *http.Client
}

type ExtendedStats struct {
Expand All @@ -75,14 +82,44 @@ type ExtendedStats struct {
streamEndpoints []string
}

func NewNginxPlus(baseDimensions *metrics.CommonDim, nginxNamespace, plusNamespace, plusAPI string, clientVersion int) *NginxPlus {
func NewNginxPlus(baseDimensions *metrics.CommonDim, nginxNamespace, plusNamespace, plusAPI string, clientVersion int, conf *config.Config) *NginxPlus {
log.Debug("Creating NGINX Plus metrics source")
return &NginxPlus{baseDimensions: baseDimensions, nginxNamespace: nginxNamespace, plusNamespace: plusNamespace, plusAPI: plusAPI, clientVersion: clientVersion, logger: NewMetricSourceLogger()}

client := http.DefaultClient

if conf.Nginx.ApiTls.Ca != "" && conf.IsFileAllowed(conf.Nginx.ApiTls.Ca) {
data, err := os.ReadFile(conf.Nginx.ApiTls.Ca)
if err != nil {
log.Errorf("Unable to collect NGINX Plus metrics. Failed to read NGINX CA certificate file: %v", err)
return nil
}

caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(data)

client = &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: caCertPool,
},
},
}
}

return &NginxPlus{
baseDimensions: baseDimensions,
nginxNamespace: nginxNamespace,
plusNamespace: plusNamespace,
plusAPI: plusAPI,
clientVersion: clientVersion,
logger: NewMetricSourceLogger(),
client: client,
}
}

func (c *NginxPlus) Collect(ctx context.Context, m chan<- *metrics.StatsEntityWrapper) {
c.init.Do(func() {
cl, err := plusclient.NewNginxClient(c.plusAPI, plusclient.WithMaxAPIVersion())
cl, err := plusclient.NewNginxClient(c.plusAPI, plusclient.WithMaxAPIVersion(), plusclient.WithHTTPClient(c.client))
if err != nil {
c.logger.Log(fmt.Sprintf("Failed to create plus metrics client: %v", err))
SendNginxDownStatus(ctx, c.baseDimensions.ToDimensions(), m)
Expand Down
4 changes: 2 additions & 2 deletions src/core/metrics/sources/nginx_plus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ func (f *FakeNginxPlus) Collect(ctx context.Context, m chan<- *metrics.StatsEnti
}

func TestNginxPlusUpdate(t *testing.T) {
nginxPlus := NewNginxPlus(&metrics.CommonDim{}, "test", PlusNamespace, "http://localhost:8080/api", 6)
nginxPlus := NewNginxPlus(&metrics.CommonDim{}, "test", PlusNamespace, "http://localhost:8080/api", 6, &config.Config{})

assert.Equal(t, "", nginxPlus.baseDimensions.InstanceTags)
assert.Equal(t, "http://localhost:8080/api", nginxPlus.plusAPI)
Expand Down Expand Up @@ -867,7 +867,7 @@ func TestNginxPlus_Collect(t *testing.T) {
for _, test := range tests {
ctx := context.TODO()

f := &FakeNginxPlus{NewNginxPlus(test.baseDimensions, "nginx", "plus", "", 6)}
f := &FakeNginxPlus{NewNginxPlus(test.baseDimensions, "nginx", "plus", "", 6, &config.Config{})}
go f.Collect(ctx, test.m)

instanceMetrics := <-test.m
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading