From 13d2e194850626c91df571a194c9fc49554ea334 Mon Sep 17 00:00:00 2001 From: Christopher van de Sande Date: Wed, 21 Aug 2024 18:02:49 +0100 Subject: [PATCH 01/22] feat: WIP add gencert function --- Makefile.containers | 4 +- internal/collector/otel_collector_plugin.go | 8 + internal/collector/otelcol.tmpl | 27 ++- internal/config/config.go | 42 ++++ internal/config/config_test.go | 2 +- internal/config/defaults.go | 6 +- internal/config/testdata/nginx-agent.conf | 5 +- internal/config/types.go | 16 +- pkg/tls/self_signed_cert.go | 203 +++++++++++++++++ pkg/tls/self_signed_cert_test.go | 227 ++++++++++++++++++++ 10 files changed, 529 insertions(+), 11 deletions(-) create mode 100644 pkg/tls/self_signed_cert.go create mode 100644 pkg/tls/self_signed_cert_test.go diff --git a/Makefile.containers b/Makefile.containers index 6063fd10ca..4d1d52f1f1 100644 --- a/Makefile.containers +++ b/Makefile.containers @@ -10,8 +10,8 @@ endif ifeq ($(CONTAINER_CLITOOL), docker) CONTAINER_BUILDENV ?= DOCKER_BUILDKIT=1 BUILDKIT_PROGRESS=plain -ifeq ($(shell docker-compose -v >/dev/null 2>&1 || echo FAIL),) -CONTAINER_COMPOSE = docker-compose +ifeq ($(shell docker -v >/dev/null 2>&1 || echo FAIL),) +CONTAINER_COMPOSE = docker compose endif else ifeq ($(CONTAINER_CLITOOL), podman) ifeq ($(shell podman-compose -v >/dev/null 2>&1 || echo FAIL),) diff --git a/internal/collector/otel_collector_plugin.go b/internal/collector/otel_collector_plugin.go index b3358656a8..02724a827d 100644 --- a/internal/collector/otel_collector_plugin.go +++ b/internal/collector/otel_collector_plugin.go @@ -66,6 +66,14 @@ func (oc *Collector) Init(ctx context.Context, mp bus.MessagePipeInterface) erro return fmt.Errorf("write OTel Collector config: %w", err) } + if oc.config.Collector.Receivers.OtlpReceivers != nil { + for _, receiver := range oc.config.Collector.Receivers.OtlpReceivers { + if receiver.OtlpTLSConfig != nil && receiver.OtlpTLSConfig.GenerateSelfSignedCert { + slog.Warn("Self-signed certificate for OTEL receiver in use") + } + } + } + bootErr := oc.bootup(runCtx) if bootErr != nil { slog.ErrorContext(runCtx, "Unable to start OTel Collector", "error", bootErr) diff --git a/internal/collector/otelcol.tmpl b/internal/collector/otelcol.tmpl index 726d81bf44..b754a947db 100644 --- a/internal/collector/otelcol.tmpl +++ b/internal/collector/otelcol.tmpl @@ -19,10 +19,35 @@ receivers: protocols: {{- if eq .Server.Type 0 }} grpc: + endpoint: "{{ .Server.Host }}:{{ .Server.Port }}" + {{- if and .OtlpTLSConfig (or (gt (len .OtlpTLSConfig.Key) 0) (gt (len .OtlpTLSConfig.Cert) 0) (gt (len .OtlpTLSConfig.Key) 0)) }} + tls: + {{ if gt (len .OtlpTLSConfig.Cert) 0 -}} + cert_file: {{ .OtlpTLSConfig.Cert }} + {{- end }} + {{ if gt (len .OtlpTLSConfig.Key) 0 -}} + key_file: {{ .OtlpTLSConfig.Key }} + {{- end }} + {{ if gt (len .OtlpTLSConfig.Ca) 0 -}} + ca_file: {{ .OtlpTLSConfig.Ca }} + {{- end }} + {{- end }} {{- else }} http: - {{- end }} endpoint: "{{- .Server.Host -}}:{{- .Server.Port -}}" + {{- if .OtlpTLSConfig }} + tls: + {{ if gt (len .OtlpTLSConfig.Cert) 0 -}} + cert_file: {{ .OtlpTLSConfig.Cert }} + {{- end }} + {{ if gt (len .OtlpTLSConfig.Key) 0 -}} + key_file: {{ .OtlpTLSConfig.Key }} + {{- end }} + {{ if gt (len .OtlpTLSConfig.Ca) 0 -}} + ca_file: {{ .OtlpTLSConfig.Ca }} + {{- end }} + {{- end }} + {{- end }} {{- end }} {{- range .Receivers.NginxReceivers }} nginx/{{- .InstanceID -}}: diff --git a/internal/config/config.go b/internal/config/config.go index 60677235b6..a1b51df353 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -12,9 +12,11 @@ import ( "log/slog" "os" "path/filepath" + "slices" "strings" "time" + selfsignedcerts "github.com/nginx/agent/v3/pkg/tls" uuidLibrary "github.com/nginx/agent/v3/pkg/uuid" "github.com/spf13/cobra" flag "github.com/spf13/pflag" @@ -326,6 +328,11 @@ func resolveCollector(allowedDirs []string) (*Collector, error) { Health: &healthCheck, } + // Check for self-signed certificate true in Agent conf + if err = handleSelfSignedCertificates(col); err != nil { + return nil, err + } + err = col.Validate(allowedDirs) if err != nil { return nil, fmt.Errorf("collector config: %w", err) @@ -334,6 +341,41 @@ func resolveCollector(allowedDirs []string) (*Collector, error) { return col, nil } +// generate self-signed certificate for OTEL receiver +// nolint: revive +func handleSelfSignedCertificates(col *Collector) error { + sanNames := []string{"127.0.0.1", "::1", "localhost"} + + if col.Receivers.OtlpReceivers != nil { + for _, receiver := range col.Receivers.OtlpReceivers { + if receiver.OtlpTLSConfig != nil && receiver.OtlpTLSConfig.GenerateSelfSignedCert { + if !slices.Contains(sanNames, receiver.Server.Host) { + sanNames = append(sanNames, receiver.Server.Host) + } + + // Update viper's TLS paths with defaults + receiver.OtlpTLSConfig.Ca = DefCollectorTLSCAPath + receiver.OtlpTLSConfig.Cert = DefCollectorTLSCertPath + receiver.OtlpTLSConfig.Key = DefCollectorTLSKeyPath + } + } + } + + if len(sanNames) > 0 { + err := selfsignedcerts.GenerateServerCert( + sanNames, + DefCollectorTLSCAPath, + DefCollectorTLSCertPath, + DefCollectorTLSKeyPath, + ) + if err != nil { + return fmt.Errorf("failed to generate self-signed certificate: %w", err) + } + } + + return nil +} + func resolveCommand() *Command { if !viperInstance.IsSet(CommandRootKey) { return nil diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 6995ff783a..ee0447f42a 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -333,7 +333,7 @@ func getAgentConfig() *Config { Auth: &AuthConfig{ Token: "even-secreter-token", }, - TLS: &TLSConfig{ + OtlpTLSConfig: &OtlpTLSConfig{ Cert: "/path/to/server-cert.pem", Key: "/path/to/server-cert.pem", Ca: "/path/to/server-cert.pem", diff --git a/internal/config/defaults.go b/internal/config/defaults.go index 649fde8812..83a134780f 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -13,7 +13,11 @@ const ( DefNginxReloadMonitoringPeriod = 10 * time.Second DefTreatErrorsAsWarnings = true - DefCollectorConfigPath = "/var/run/nginx-agent/otelcol.yaml" + DefCollectorConfigPath = "/var/run/nginx-agent/otelcol.yaml" + DefCollectorTLSGenSelfSignedCert = false + DefCollectorTLSCertPath = "/var/lib/nginx-agent/cert.pem" + DefCollectorTLSKeyPath = "/var/lib/nginx-agent/key.pem" + DefCollectorTLSCAPath = "/var/lib/nginx-agent/ca.pem" DefCommandServerHostKey = "" DefCommandServerPortKey = 0 diff --git a/internal/config/testdata/nginx-agent.conf b/internal/config/testdata/nginx-agent.conf index 9aea099a21..41c92e7337 100644 --- a/internal/config/testdata/nginx-agent.conf +++ b/internal/config/testdata/nginx-agent.conf @@ -27,10 +27,9 @@ collector: Token: "secret-receiver-token" tls: server_name: "test-local-server" - skip_verify: false - cert: /path/to/server-cert.pem - key: /path/to/server-key.pem ca: /path/to/server-cert.pem + cert: /var/lib/nginx-agent/cert.pem + key: /var/lib/nginx-agent/key.pem processors: - type: batch exporters: diff --git a/internal/config/types.go b/internal/config/types.go index c5b60c2a26..3657808e3c 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -105,9 +105,9 @@ type ( } OtlpReceiver struct { - Server *ServerConfig `yaml:"-" mapstructure:"server"` - Auth *AuthConfig `yaml:"-" mapstructure:"auth"` - TLS *TLSConfig `yaml:"-" mapstructure:"tls"` + Server *ServerConfig `yaml:"-" mapstructure:"server"` + Auth *AuthConfig `yaml:"-" mapstructure:"auth"` + OtlpTLSConfig *OtlpTLSConfig `yaml:"-" mapstructure:"tls"` } NginxReceiver struct { @@ -156,6 +156,16 @@ type ( SkipVerify bool `yaml:"-" mapstructure:"skip_verify"` } + // Specialized TLS configuration for OtlpReceiver with self-signed cert generation. + OtlpTLSConfig struct { + Cert string `yaml:"-" mapstructure:"cert"` + Key string `yaml:"-" mapstructure:"key"` + Ca string `yaml:"-" mapstructure:"ca"` + ServerName string `yaml:"-" mapstructure:"server_name"` + SkipVerify bool `yaml:"-" mapstructure:"skip_verify"` + GenerateSelfSignedCert bool `yaml:"-" mapstructure:"generate_self_signed_cert"` + } + File struct { Location string `yaml:"-" mapstructure:"location"` } diff --git a/pkg/tls/self_signed_cert.go b/pkg/tls/self_signed_cert.go new file mode 100644 index 0000000000..5855f041f5 --- /dev/null +++ b/pkg/tls/self_signed_cert.go @@ -0,0 +1,203 @@ +// Copyright (c) F5, Inc. +// +// This source code is licensed under the Apache License, Version 2.0 license found in the +// LICENSE file in the root directory of this source tree. + +// Package gencert generates self-signed TLS certificates. +package tls + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "errors" + "fmt" + "log/slog" + "math/big" + "os" + "time" +) + +const ( + caOrganization = "F5 Inc. CA" + certOrganization = "F5 Inc." + certFilePermissions = 0o600 + keyFilePermissions = 0o600 +) + +type certReq struct { + template *x509.Certificate + parent *x509.Certificate + publicKey *ecdsa.PublicKey + privateKey *ecdsa.PrivateKey +} + +func genCert(req *certReq) (*x509.Certificate, []byte) { + certBytes, createCertErr := x509.CreateCertificate( + rand.Reader, + req.template, + req.parent, + req.publicKey, + req.privateKey, + ) + + if createCertErr != nil { + slog.Error("Failed to generate certificate", "error", createCertErr) + return &x509.Certificate{}, []byte{} + } + + cert, parseCertErr := x509.ParseCertificate(certBytes) + if parseCertErr != nil { + slog.Error("Failed to parse certificate") + return &x509.Certificate{}, []byte{} + } + + b := pem.Block{Type: "CERTIFICATE", Bytes: certBytes} + certPEM := pem.EncodeToMemory(&b) + + return cert, certPEM +} + +func GenerateCA(now time.Time, caCertPath string) (*x509.Certificate, *ecdsa.PrivateKey, error) { + // Generate key pair for the CA + caKeyPair, caKeyErr := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if caKeyErr != nil { + return &x509.Certificate{}, &ecdsa.PrivateKey{}, fmt.Errorf("failed to generate CA private key: %w", caKeyErr) + } + + // Create CA certificate template + caTemplate := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{Organization: []string{certOrganization}}, + NotBefore: now.Add(-time.Minute), + NotAfter: now.AddDate(1, 0, 0), // 1 year + KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + IsCA: true, + MaxPathLen: 1, + } + + // CA is self signed + caRequest := certReq{ + template: &caTemplate, + parent: &caTemplate, + publicKey: &caKeyPair.PublicKey, + privateKey: caKeyPair, + } + + caCert, caCertPEM := genCert(&caRequest) + if len(caCertPEM) == 0 { + slog.Error("Error generating certificate authority") + } + + // Write the CA certificate to a file + slog.Debug("About to write CA file", "path", caCertPath) + writeCAErr := os.WriteFile(caCertPath, caCertPEM, certFilePermissions) + if writeCAErr != nil { + return &x509.Certificate{}, &ecdsa.PrivateKey{}, fmt.Errorf( + "failed to write ca file: %w", + writeCAErr, + ) + } + + return caCert, caKeyPair, nil +} + +// nolint: revive +func GenerateServerCert(hostnames []string, caPath, certPath, keyPath string) error { + // Check for and return existing cert if it already exists + existingCertErr := ReturnExistingCert(certPath) + if existingCertErr != nil { + return fmt.Errorf("error reading existing certificate data: %w", existingCertErr) + } + + // Get the local time zone + location_currentzone, locErr := time.LoadLocation("Local") + if locErr != nil { + return fmt.Errorf("error detecting local timezone: %w", locErr) + } + now := time.Now().In(location_currentzone) + + // Create CA first + caCert, caKeyPair, caErr := GenerateCA(now, caPath) + if caErr != nil { + return fmt.Errorf("error generating certificate authority: %w", caErr) + } + + // Generate key pair for the server certficate + servKeyPair, servKeyErr := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if servKeyErr != nil { + return fmt.Errorf("failed to generate server keypair: %w", servKeyErr) + } + + servTemplate := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{caOrganization}, + }, + NotBefore: now.Add(-time.Minute), + NotAfter: now.AddDate(1, 0, 0), // 1 year + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + DNSNames: hostnames, + } + + servRequest := certReq{ + template: &servTemplate, + parent: caCert, + publicKey: &servKeyPair.PublicKey, + privateKey: caKeyPair, + } + + // Generate server certficated signed by the CA + _, servCertPEM := genCert(&servRequest) + if len(servCertPEM) == 0 { + return errors.New("error generating server certificate") + } + + // Write the certificate to a file + writeCertErr := os.WriteFile(certPath, servCertPEM, certFilePermissions) + if writeCertErr != nil { + return fmt.Errorf("failed to write certificate file: %w", writeCertErr) + } + + // Write the private key to a file + servKeyBytes, marshalErr := x509.MarshalECPrivateKey(servKeyPair) + if marshalErr != nil { + return fmt.Errorf("failed to marshal private key file: %w", marshalErr) + } + b := pem.Block{Type: "EC PRIVATE KEY", Bytes: servKeyBytes} + servKeyPEM := pem.EncodeToMemory(&b) + writeKeyErr := os.WriteFile(keyPath, servKeyPEM, keyFilePermissions) + if writeKeyErr != nil { + return fmt.Errorf("failed to write key file: %w", writeKeyErr) + } + + return nil +} + +func ReturnExistingCert(certPath string) error { + if _, certErr := os.Stat(certPath); certErr == nil { + certBytes, certReadErr := os.ReadFile(certPath) + if certReadErr != nil { + return fmt.Errorf("error reading existing certificate file") + } + certPEM, _ := pem.Decode(certBytes) + if certPEM == nil { + return errors.New("error decoding certificate PEM block") + } + _, parseErr := x509.ParseCertificate(certPEM.Bytes) + if parseErr == nil { + slog.Warn("Certificate file already exists, skipping self-signed certificate generation") + return nil + } + + return fmt.Errorf("error parsing existing certificate: %w", parseErr) + } + + return nil +} diff --git a/pkg/tls/self_signed_cert_test.go b/pkg/tls/self_signed_cert_test.go new file mode 100644 index 0000000000..e22d8df532 --- /dev/null +++ b/pkg/tls/self_signed_cert_test.go @@ -0,0 +1,227 @@ +// Copyright (c) F5, Inc. +// +// This source code is licensed under the Apache License, Version 2.0 license found in the +// LICENSE file in the root directory of this source tree. + +// Package gencert generates self-signed TLS certificates. +package tls + +import ( + "encoding/pem" + "os" + "testing" + + "github.com/nginx/agent/v3/test/helpers" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// nolint: revive,gocognit +func TestGenerateSelfSignedCert(t *testing.T) { + // Setup temp file paths + caPath := "/tmp/test_ca.pem" + certPath := "/tmp/test_cert.pem" + keyPath := "/tmp/test_key.pem" + hostNames := []string{"localhost", "::1", "127.0.0.1"} + + // Cleanup any pre-existing files from previous tests + defer os.Remove(caPath) + defer os.Remove(certPath) + defer os.Remove(keyPath) + + // Define a struct for test cases + type testCase struct { + name string + caPath string + certPath string + keyPath string + expectedError string + setup func() error + hostNames []string + } + + tests := []testCase{ + { + name: "Test 1: CA, Cert and key file exist", + setup: func() error { + // Ensure no cert files exist + os.Remove(caPath) + os.Remove(certPath) + os.Remove(keyPath) + + // Create valid PEM files + keyBytes, certBytes := helpers.GenerateSelfSignedCert(t) + caPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes}) + certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes}) + keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: keyBytes}) + if caErr := os.WriteFile(caPath, caPEM, 0o600); caErr != nil { + return caErr + } + if certErr := os.WriteFile(certPath, certPEM, 0o600); certErr != nil { + return certErr + } + + return os.WriteFile(keyPath, keyPEM, 0o600) + }, + caPath: caPath, + certPath: certPath, + keyPath: keyPath, + hostNames: hostNames, + expectedError: "", + }, + { + name: "Test 2: Invalid cert data", + setup: func() error { + // Ensure no cert or key files exist + os.Remove(caPath) + os.Remove(certPath) + os.Remove(keyPath) + // Create dummy cert files + if caErr := os.WriteFile(caPath, []byte("dummy ca"), 0o600); caErr != nil { + return caErr + } + if certErr := os.WriteFile(certPath, []byte("dummy cert"), 0o600); certErr != nil { + return certErr + } + + return os.WriteFile(keyPath, []byte("dummy key"), 0o600) + }, + caPath: caPath, + certPath: certPath, + keyPath: keyPath, + hostNames: hostNames, + expectedError: "error decoding certificate PEM block", + }, + { + name: "Test 3: Error writing certificate file", + setup: func() error { + // Ensure no cert or key files exist + os.Remove(caPath) + os.Remove(certPath) + os.Remove(keyPath) + + return nil + }, + caPath: caPath, + certPath: "/dev/null/cert.pem", // Path that is guaranteed to fail + keyPath: keyPath, + hostNames: hostNames, + expectedError: "failed to write certificate file", + }, + { + name: "Test 4: Error writing key file", + setup: func() error { + return nil + }, + caPath: caPath, + certPath: certPath, + keyPath: "/dev/null/key/pem", // Path that is guaranteed to fail + hostNames: hostNames, + expectedError: "failed to write key file", + }, + { + name: "Test 5: Successful certificate generation", + setup: func() error { + // Ensure no cert or key files exist + os.Remove(caPath) + os.Remove(certPath) + os.Remove(keyPath) + + return nil + }, + caPath: caPath, + certPath: certPath, + keyPath: keyPath, + hostNames: hostNames, + expectedError: "", + }, + { + name: "Test case 6: Error reading existing certificate file", + setup: func() error { + // Ensure no cert or key files exist + os.Remove(caPath) + os.Remove(certPath) + os.Remove(keyPath) + + // No read/write permissions + if certErr := os.WriteFile(certPath, []byte("dummy cert"), 0o000); certErr != nil { + return certErr + } + + return os.WriteFile(keyPath, []byte("dummy key"), 0o600) + }, + caPath: caPath, + certPath: certPath, + keyPath: keyPath, + hostNames: hostNames, + expectedError: "error reading existing certificate file", + }, + { + name: "Test case 7: Error reading existing key file", + setup: func() error { + // Ensure no cert or key files exist + os.Remove(caPath) + os.Remove(certPath) + os.Remove(keyPath) + + if certErr := os.WriteFile(certPath, []byte("dummy cert"), 0o600); certErr != nil { + return certErr + } + + return os.WriteFile(keyPath, []byte("dummy key"), 0o000) + }, + caPath: caPath, + certPath: certPath, + keyPath: keyPath, + hostNames: hostNames, + expectedError: "error decoding certificate PEM block", + }, + { + name: "Test case 8: Error parsing TLS key pair", + setup: func() error { + // Ensure no cert or key files exist + os.Remove(caPath) + os.Remove(certPath) + os.Remove(keyPath) + + // Write invalid PEM data to simulate parsing error + err := os.WriteFile(certPath, []byte("invalid cert data"), 0o600) + if err != nil { + return err + } + err = os.WriteFile(keyPath, []byte("invalid key data"), 0o600) + if err != nil { + return err + } + + return nil + }, + caPath: caPath, + certPath: certPath, + keyPath: keyPath, + hostNames: hostNames, + expectedError: "error decoding certificate PEM block", + }, + } + // Iterate over the test cases + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + err := tc.setup() + require.NoError(t, err) + + genCertErr := GenerateServerCert(tc.hostNames, tc.caPath, tc.certPath, tc.keyPath) + + // Check the results + if tc.expectedError != "" { + require.Error(t, genCertErr) + assert.Contains(t, genCertErr.Error(), tc.expectedError) + } else { + require.NoError(t, genCertErr) + _, err = os.Stat(tc.certPath) + require.NoError(t, err) + _, err = os.Stat(tc.keyPath) + require.NoError(t, err) + } + }) + } +} From b6f83fd93d5219e94e7dcdcf21309c899eac232f Mon Sep 17 00:00:00 2001 From: Christopher van de Sande Date: Wed, 18 Sep 2024 13:47:41 +0100 Subject: [PATCH 02/22] add template test --- internal/collector/settings_test.go | 14 ++++++++++++++ internal/config/defaults.go | 6 +++--- pkg/tls/self_signed_cert_test.go | 2 +- .../test-opentelemetry-collector-agent.yaml | 6 +++++- test/types/config.go | 2 +- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/internal/collector/settings_test.go b/internal/collector/settings_test.go index caa84f9e1c..1cf282af63 100644 --- a/internal/collector/settings_test.go +++ b/internal/collector/settings_test.go @@ -90,6 +90,20 @@ func TestTemplateWrite(t *testing.T) { }, }, }) + // Clear default config and test collector with TLS enabled + cfg.Collector.Receivers.OtlpReceivers = []config.OtlpReceiver{} + cfg.Collector.Receivers.OtlpReceivers = append(cfg.Collector.Receivers.OtlpReceivers, config.OtlpReceiver{ + Server: &config.ServerConfig{ + Host: "localhost", + Port: 4317, + Type: 0, + }, + OtlpTLSConfig: &config.OtlpTLSConfig{ + Cert: "/tmp/cert.pem", + Key: "/tmp/key.pem", + Ca: "/tmp/ca.pem", + }, + }) require.NotNil(t, cfg) diff --git a/internal/config/defaults.go b/internal/config/defaults.go index de16a32ffc..1be57d62cb 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -16,9 +16,9 @@ const ( DefCollectorConfigPath = "/var/run/nginx-agent/opentelemetry-collector-agent.yaml" DefCollectorTLSGenSelfSignedCert = false - DefCollectorLogLevel = "INFO" - DefCollectorLogPath = "/var/log/nginx-agent/opentelemetry-collector-agent.log" - DefConfigDirectories = "/etc/nginx:/usr/local/etc/nginx:/usr/share/nginx/modules" + DefCollectorLogLevel = "INFO" + DefCollectorLogPath = "/var/log/nginx-agent/opentelemetry-collector-agent.log" + DefConfigDirectories = "/etc/nginx:/usr/local/etc/nginx:/usr/share/nginx/modules" DefCollectorTLSCertPath = "/var/lib/nginx-agent/cert.pem" DefCollectorTLSKeyPath = "/var/lib/nginx-agent/key.pem" DefCollectorTLSCAPath = "/var/lib/nginx-agent/ca.pem" diff --git a/pkg/tls/self_signed_cert_test.go b/pkg/tls/self_signed_cert_test.go index e22d8df532..307d956984 100644 --- a/pkg/tls/self_signed_cert_test.go +++ b/pkg/tls/self_signed_cert_test.go @@ -154,7 +154,7 @@ func TestGenerateSelfSignedCert(t *testing.T) { certPath: certPath, keyPath: keyPath, hostNames: hostNames, - expectedError: "error reading existing certificate file", + expectedError: "error decoding certificate PEM block", }, { name: "Test case 7: Error reading existing key file", diff --git a/test/config/collector/test-opentelemetry-collector-agent.yaml b/test/config/collector/test-opentelemetry-collector-agent.yaml index be6aacfa1a..9deb5be556 100644 --- a/test/config/collector/test-opentelemetry-collector-agent.yaml +++ b/test/config/collector/test-opentelemetry-collector-agent.yaml @@ -11,7 +11,11 @@ receivers: otlp/0: protocols: grpc: - endpoint: "localhost:4321" + endpoint: "localhost:4317" + tls: + cert_file: /tmp/cert.pem + key_file: /tmp/key.pem + ca_file: /tmp/ca.pem nginx/123: endpoint: "http://localhost:80/status" collection_interval: 10s diff --git a/test/types/config.go b/test/types/config.go index fefaa1964b..68f8830cf4 100644 --- a/test/types/config.go +++ b/test/types/config.go @@ -31,7 +31,7 @@ const ( reloadMonitoringPeriod = 400 * time.Millisecond randomPort1 = 1234 - randomPort2 = 4321 + randomPort2 = 4317 randomPort3 = 1337 ) From a7a0045cdef13bcbb4d5bcc0fca1d9fcbbf29d04 Mon Sep 17 00:00:00 2001 From: Christopher van de Sande Date: Wed, 18 Sep 2024 23:34:49 +0100 Subject: [PATCH 03/22] Update test data --- internal/config/config.go | 37 +++++++++++++++-------- internal/config/config_test.go | 13 ++++---- internal/config/testdata/nginx-agent.conf | 7 +++-- pkg/tls/self_signed_cert.go | 4 +-- pkg/tls/self_signed_cert_test.go | 2 +- 5 files changed, 39 insertions(+), 24 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 86f5df9d38..88624b1644 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -407,29 +407,42 @@ func resolveCollector(allowedDirs []string) (*Collector, error) { // generate self-signed certificate for OTEL receiver // nolint: revive func handleSelfSignedCertificates(col *Collector) error { - sanNames := []string{"127.0.0.1", "::1", "localhost"} - if col.Receivers.OtlpReceivers != nil { for _, receiver := range col.Receivers.OtlpReceivers { if receiver.OtlpTLSConfig != nil && receiver.OtlpTLSConfig.GenerateSelfSignedCert { - if !slices.Contains(sanNames, receiver.Server.Host) { - sanNames = append(sanNames, receiver.Server.Host) + err := processOtlpReceivers(receiver.OtlpTLSConfig) + if err != nil { + return fmt.Errorf("failed to generate self-signed certificate: %w", err) } - - // Update viper's TLS paths with defaults - receiver.OtlpTLSConfig.Ca = DefCollectorTLSCAPath - receiver.OtlpTLSConfig.Cert = DefCollectorTLSCertPath - receiver.OtlpTLSConfig.Key = DefCollectorTLSKeyPath } } } + return nil +} + +func processOtlpReceivers(tlsConfig *OtlpTLSConfig) error { + sanNames := []string{"127.0.0.1", "::1", "localhost"} + + if tlsConfig.Ca == "" { + tlsConfig.Ca = DefCollectorTLSCAPath + } + if tlsConfig.Cert == "" { + tlsConfig.Cert = DefCollectorTLSCertPath + } + if tlsConfig.Key == "" { + tlsConfig.Key = DefCollectorTLSKeyPath + } + + if !slices.Contains(sanNames, tlsConfig.ServerName) { + sanNames = append(sanNames, tlsConfig.ServerName) + } if len(sanNames) > 0 { err := selfsignedcerts.GenerateServerCert( sanNames, - DefCollectorTLSCAPath, - DefCollectorTLSCertPath, - DefCollectorTLSKeyPath, + tlsConfig.Ca, + tlsConfig.Cert, + tlsConfig.Key, ) if err != nil { return fmt.Errorf("failed to generate self-signed certificate: %w", err) diff --git a/internal/config/config_test.go b/internal/config/config_test.go index ff067fea54..3daec1c292 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -367,18 +367,19 @@ func getAgentConfig() *Config { { Server: &ServerConfig{ Host: "localhost", - Port: 4321, + Port: 4317, Type: 0, }, Auth: &AuthConfig{ Token: "even-secreter-token", }, OtlpTLSConfig: &OtlpTLSConfig{ - Cert: "/path/to/server-cert.pem", - Key: "/path/to/server-cert.pem", - Ca: "/path/to/server-cert.pem", - SkipVerify: true, - ServerName: "local-dataa-plane-server", + GenerateSelfSignedCert: false, + Cert: "/path/to/server-cert.pem", + Key: "/path/to/server-cert.pem", + Ca: "/path/to/server-cert.pem", + SkipVerify: true, + ServerName: "local-data-plane-server", }, }, }, diff --git a/internal/config/testdata/nginx-agent.conf b/internal/config/testdata/nginx-agent.conf index c0e3d51e8b..81ed647b37 100644 --- a/internal/config/testdata/nginx-agent.conf +++ b/internal/config/testdata/nginx-agent.conf @@ -29,10 +29,11 @@ collector: auth: Token: "secret-receiver-token" tls: + generate_self_signed_cert: false server_name: "test-local-server" - ca: /path/to/server-cert.pem - cert: /var/lib/nginx-agent/cert.pem - key: /var/lib/nginx-agent/key.pem + ca: /tmp/ca.pem + cert: /tmp/cert.pem + key: /tmp/key.pem nginx_receivers: - instance_id: cd7b8911-c2c5-4daf-b311-dbead151d938 stub_status: "http://localhost:4321/status" diff --git a/pkg/tls/self_signed_cert.go b/pkg/tls/self_signed_cert.go index 5855f041f5..35ef72c741 100644 --- a/pkg/tls/self_signed_cert.go +++ b/pkg/tls/self_signed_cert.go @@ -116,11 +116,11 @@ func GenerateServerCert(hostnames []string, caPath, certPath, keyPath string) er } // Get the local time zone - location_currentzone, locErr := time.LoadLocation("Local") + locationCurrentzone, locErr := time.LoadLocation("Local") if locErr != nil { return fmt.Errorf("error detecting local timezone: %w", locErr) } - now := time.Now().In(location_currentzone) + now := time.Now().In(locationCurrentzone) // Create CA first caCert, caKeyPair, caErr := GenerateCA(now, caPath) diff --git a/pkg/tls/self_signed_cert_test.go b/pkg/tls/self_signed_cert_test.go index 307d956984..f9a43eb445 100644 --- a/pkg/tls/self_signed_cert_test.go +++ b/pkg/tls/self_signed_cert_test.go @@ -154,7 +154,7 @@ func TestGenerateSelfSignedCert(t *testing.T) { certPath: certPath, keyPath: keyPath, hostNames: hostNames, - expectedError: "error decoding certificate PEM block", + expectedError: "error reading existing certificate data", }, { name: "Test case 7: Error reading existing key file", From 986dcf076c54aaa7f05549ea0842197f23c0b55b Mon Sep 17 00:00:00 2001 From: Christopher van de Sande Date: Thu, 19 Sep 2024 16:10:13 +0100 Subject: [PATCH 04/22] address PR test comments --- internal/collector/otel_collector_plugin.go | 9 ++++- internal/config/config.go | 5 ++- internal/config/types.go | 1 + pkg/tls/self_signed_cert.go | 38 +++++++++++---------- pkg/tls/self_signed_cert_test.go | 16 ++++++++- 5 files changed, 48 insertions(+), 21 deletions(-) diff --git a/internal/collector/otel_collector_plugin.go b/internal/collector/otel_collector_plugin.go index c635af82d4..628547abc3 100644 --- a/internal/collector/otel_collector_plugin.go +++ b/internal/collector/otel_collector_plugin.go @@ -67,6 +67,7 @@ func New(conf *config.Config) (*Collector, error) { } // Init initializes and starts the plugin +// nolint: revive func (oc *Collector) Init(ctx context.Context, mp bus.MessagePipeInterface) error { slog.InfoContext(ctx, "Starting OTel Collector plugin") @@ -81,7 +82,13 @@ func (oc *Collector) Init(ctx context.Context, mp bus.MessagePipeInterface) erro if oc.config.Collector.Receivers.OtlpReceivers != nil { for _, receiver := range oc.config.Collector.Receivers.OtlpReceivers { if receiver.OtlpTLSConfig != nil && receiver.OtlpTLSConfig.GenerateSelfSignedCert { - slog.Warn("Self-signed certificate for OTEL receiver in use") + slog.WarnContext(ctx, "Self-signed certificate for OTEL receiver requested") + if receiver.OtlpTLSConfig.ExistingCert { + slog.WarnContext( + ctx, + "Certificate file already exists, skipping self-signed certificate generation", + ) + } } } } diff --git a/internal/config/config.go b/internal/config/config.go index 88624b1644..2f7c0979fe 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -438,7 +438,7 @@ func processOtlpReceivers(tlsConfig *OtlpTLSConfig) error { sanNames = append(sanNames, tlsConfig.ServerName) } if len(sanNames) > 0 { - err := selfsignedcerts.GenerateServerCert( + existingCert, err := selfsignedcerts.GenerateServerCert( sanNames, tlsConfig.Ca, tlsConfig.Cert, @@ -447,6 +447,9 @@ func processOtlpReceivers(tlsConfig *OtlpTLSConfig) error { if err != nil { return fmt.Errorf("failed to generate self-signed certificate: %w", err) } + if existingCert { + tlsConfig.ExistingCert = true + } } return nil diff --git a/internal/config/types.go b/internal/config/types.go index 0d7c19329a..7c29e24ca0 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -192,6 +192,7 @@ type ( Key string `yaml:"-" mapstructure:"key"` Ca string `yaml:"-" mapstructure:"ca"` ServerName string `yaml:"-" mapstructure:"server_name"` + ExistingCert bool `yaml:"-"` SkipVerify bool `yaml:"-" mapstructure:"skip_verify"` GenerateSelfSignedCert bool `yaml:"-" mapstructure:"generate_self_signed_cert"` } diff --git a/pkg/tls/self_signed_cert.go b/pkg/tls/self_signed_cert.go index 35ef72c741..5befc9685f 100644 --- a/pkg/tls/self_signed_cert.go +++ b/pkg/tls/self_signed_cert.go @@ -108,30 +108,33 @@ func GenerateCA(now time.Time, caCertPath string) (*x509.Certificate, *ecdsa.Pri } // nolint: revive -func GenerateServerCert(hostnames []string, caPath, certPath, keyPath string) error { +func GenerateServerCert(hostnames []string, caPath, certPath, keyPath string) (existingCert bool, err error) { // Check for and return existing cert if it already exists - existingCertErr := ReturnExistingCert(certPath) + existingCert, existingCertErr := ReturnExistingCert(certPath) if existingCertErr != nil { - return fmt.Errorf("error reading existing certificate data: %w", existingCertErr) + return false, fmt.Errorf("error reading existing certificate data: %w", existingCertErr) + } + if existingCert { + return true, nil } // Get the local time zone locationCurrentzone, locErr := time.LoadLocation("Local") if locErr != nil { - return fmt.Errorf("error detecting local timezone: %w", locErr) + return false, fmt.Errorf("error detecting local timezone: %w", locErr) } now := time.Now().In(locationCurrentzone) // Create CA first caCert, caKeyPair, caErr := GenerateCA(now, caPath) if caErr != nil { - return fmt.Errorf("error generating certificate authority: %w", caErr) + return false, fmt.Errorf("error generating certificate authority: %w", caErr) } // Generate key pair for the server certficate servKeyPair, servKeyErr := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if servKeyErr != nil { - return fmt.Errorf("failed to generate server keypair: %w", servKeyErr) + return false, fmt.Errorf("failed to generate server keypair: %w", servKeyErr) } servTemplate := x509.Certificate{ @@ -156,48 +159,47 @@ func GenerateServerCert(hostnames []string, caPath, certPath, keyPath string) er // Generate server certficated signed by the CA _, servCertPEM := genCert(&servRequest) if len(servCertPEM) == 0 { - return errors.New("error generating server certificate") + return false, errors.New("error generating server certificate") } // Write the certificate to a file writeCertErr := os.WriteFile(certPath, servCertPEM, certFilePermissions) if writeCertErr != nil { - return fmt.Errorf("failed to write certificate file: %w", writeCertErr) + return false, fmt.Errorf("failed to write certificate file: %w", writeCertErr) } // Write the private key to a file servKeyBytes, marshalErr := x509.MarshalECPrivateKey(servKeyPair) if marshalErr != nil { - return fmt.Errorf("failed to marshal private key file: %w", marshalErr) + return false, fmt.Errorf("failed to marshal private key file: %w", marshalErr) } b := pem.Block{Type: "EC PRIVATE KEY", Bytes: servKeyBytes} servKeyPEM := pem.EncodeToMemory(&b) writeKeyErr := os.WriteFile(keyPath, servKeyPEM, keyFilePermissions) if writeKeyErr != nil { - return fmt.Errorf("failed to write key file: %w", writeKeyErr) + return false, fmt.Errorf("failed to write key file: %w", writeKeyErr) } - return nil + return false, nil } -func ReturnExistingCert(certPath string) error { +func ReturnExistingCert(certPath string) (bool, error) { if _, certErr := os.Stat(certPath); certErr == nil { certBytes, certReadErr := os.ReadFile(certPath) if certReadErr != nil { - return fmt.Errorf("error reading existing certificate file") + return false, fmt.Errorf("error reading existing certificate file") } certPEM, _ := pem.Decode(certBytes) if certPEM == nil { - return errors.New("error decoding certificate PEM block") + return false, errors.New("error decoding certificate PEM block") } _, parseErr := x509.ParseCertificate(certPEM.Bytes) if parseErr == nil { - slog.Warn("Certificate file already exists, skipping self-signed certificate generation") - return nil + return true, nil } - return fmt.Errorf("error parsing existing certificate: %w", parseErr) + return false, fmt.Errorf("error parsing existing certificate: %w", parseErr) } - return nil + return false, nil } diff --git a/pkg/tls/self_signed_cert_test.go b/pkg/tls/self_signed_cert_test.go index f9a43eb445..f5e4ae82a2 100644 --- a/pkg/tls/self_signed_cert_test.go +++ b/pkg/tls/self_signed_cert_test.go @@ -8,6 +8,7 @@ package tls import ( "encoding/pem" + "fmt" "os" "testing" @@ -38,6 +39,7 @@ func TestGenerateSelfSignedCert(t *testing.T) { expectedError string setup func() error hostNames []string + existingCert bool } tests := []testCase{ @@ -67,6 +69,7 @@ func TestGenerateSelfSignedCert(t *testing.T) { certPath: certPath, keyPath: keyPath, hostNames: hostNames, + existingCert: true, expectedError: "", }, { @@ -90,6 +93,7 @@ func TestGenerateSelfSignedCert(t *testing.T) { certPath: certPath, keyPath: keyPath, hostNames: hostNames, + existingCert: false, expectedError: "error decoding certificate PEM block", }, { @@ -106,6 +110,7 @@ func TestGenerateSelfSignedCert(t *testing.T) { certPath: "/dev/null/cert.pem", // Path that is guaranteed to fail keyPath: keyPath, hostNames: hostNames, + existingCert: false, expectedError: "failed to write certificate file", }, { @@ -117,6 +122,7 @@ func TestGenerateSelfSignedCert(t *testing.T) { certPath: certPath, keyPath: "/dev/null/key/pem", // Path that is guaranteed to fail hostNames: hostNames, + existingCert: false, expectedError: "failed to write key file", }, { @@ -133,6 +139,7 @@ func TestGenerateSelfSignedCert(t *testing.T) { certPath: certPath, keyPath: keyPath, hostNames: hostNames, + existingCert: false, expectedError: "", }, { @@ -154,6 +161,7 @@ func TestGenerateSelfSignedCert(t *testing.T) { certPath: certPath, keyPath: keyPath, hostNames: hostNames, + existingCert: false, expectedError: "error reading existing certificate data", }, { @@ -174,6 +182,7 @@ func TestGenerateSelfSignedCert(t *testing.T) { certPath: certPath, keyPath: keyPath, hostNames: hostNames, + existingCert: false, expectedError: "error decoding certificate PEM block", }, { @@ -200,6 +209,7 @@ func TestGenerateSelfSignedCert(t *testing.T) { certPath: certPath, keyPath: keyPath, hostNames: hostNames, + existingCert: false, expectedError: "error decoding certificate PEM block", }, } @@ -209,7 +219,7 @@ func TestGenerateSelfSignedCert(t *testing.T) { err := tc.setup() require.NoError(t, err) - genCertErr := GenerateServerCert(tc.hostNames, tc.caPath, tc.certPath, tc.keyPath) + existingCert, genCertErr := GenerateServerCert(tc.hostNames, tc.caPath, tc.certPath, tc.keyPath) // Check the results if tc.expectedError != "" { @@ -222,6 +232,10 @@ func TestGenerateSelfSignedCert(t *testing.T) { _, err = os.Stat(tc.keyPath) require.NoError(t, err) } + fmt.Printf("tc.ExistingCert is %t\n", tc.existingCert) + if tc.existingCert { + require.True(t, existingCert) + } }) } } From ba506e50a91832fce05d7028a4de3a9643b498eb Mon Sep 17 00:00:00 2001 From: Christopher van de Sande Date: Thu, 19 Sep 2024 16:23:34 +0100 Subject: [PATCH 05/22] Enable otel collector in mock server --- test/mock/collector/nginx-agent.conf | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/mock/collector/nginx-agent.conf b/test/mock/collector/nginx-agent.conf index 4b8c58e696..de55b87475 100644 --- a/test/mock/collector/nginx-agent.conf +++ b/test/mock/collector/nginx-agent.conf @@ -37,6 +37,19 @@ collector: disk: {} network: {} filesystem: {} + otlp_receivers: + - server: + host: "127.0.0.1" + port: 4317 + type: 0 + auth: + Token: "secret-receiver-token" + tls: + server_name: "test-local-server" + ca: /tmp/ca.pem + cert: /tmp/cert.pem + key: /tmp/key.pem + generate_self_signed_cert: true processors: - type: batch exporters: From dfd1fcd9543f5628a170be92c2caeb5e3e96c840 Mon Sep 17 00:00:00 2001 From: Christopher van de Sande Date: Thu, 19 Sep 2024 17:14:05 +0100 Subject: [PATCH 06/22] Address comments in PR --- internal/collector/otel_collector_plugin.go | 5 ++- internal/config/config.go | 4 +-- internal/config/defaults.go | 1 + pkg/tls/self_signed_cert.go | 36 +++++++++++---------- pkg/tls/self_signed_cert_test.go | 2 +- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/internal/collector/otel_collector_plugin.go b/internal/collector/otel_collector_plugin.go index 628547abc3..b0ae1a8240 100644 --- a/internal/collector/otel_collector_plugin.go +++ b/internal/collector/otel_collector_plugin.go @@ -82,7 +82,10 @@ func (oc *Collector) Init(ctx context.Context, mp bus.MessagePipeInterface) erro if oc.config.Collector.Receivers.OtlpReceivers != nil { for _, receiver := range oc.config.Collector.Receivers.OtlpReceivers { if receiver.OtlpTLSConfig != nil && receiver.OtlpTLSConfig.GenerateSelfSignedCert { - slog.WarnContext(ctx, "Self-signed certificate for OTEL receiver requested") + slog.WarnContext(ctx, + "Self-signed certificate for OTEL receiver requested, "+ + "this is not recommended for production environments.", + ) if receiver.OtlpTLSConfig.ExistingCert { slog.WarnContext( ctx, diff --git a/internal/config/config.go b/internal/config/config.go index 2f7c0979fe..faddd11d3a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -422,7 +422,7 @@ func handleSelfSignedCertificates(col *Collector) error { } func processOtlpReceivers(tlsConfig *OtlpTLSConfig) error { - sanNames := []string{"127.0.0.1", "::1", "localhost"} + sanNames := strings.Split(DefCollectorTLSSANNames, ",") if tlsConfig.Ca == "" { tlsConfig.Ca = DefCollectorTLSCAPath @@ -438,7 +438,7 @@ func processOtlpReceivers(tlsConfig *OtlpTLSConfig) error { sanNames = append(sanNames, tlsConfig.ServerName) } if len(sanNames) > 0 { - existingCert, err := selfsignedcerts.GenerateServerCert( + existingCert, err := selfsignedcerts.GenerateServerCerts( sanNames, tlsConfig.Ca, tlsConfig.Cert, diff --git a/internal/config/defaults.go b/internal/config/defaults.go index 1be57d62cb..40030c5020 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -22,6 +22,7 @@ const ( DefCollectorTLSCertPath = "/var/lib/nginx-agent/cert.pem" DefCollectorTLSKeyPath = "/var/lib/nginx-agent/key.pem" DefCollectorTLSCAPath = "/var/lib/nginx-agent/ca.pem" + DefCollectorTLSSANNames = "127.0.0.1, ::1, localhost" DefCommandServerHostKey = "" DefCommandServerPortKey = 0 diff --git a/pkg/tls/self_signed_cert.go b/pkg/tls/self_signed_cert.go index 5befc9685f..65e57c4402 100644 --- a/pkg/tls/self_signed_cert.go +++ b/pkg/tls/self_signed_cert.go @@ -15,7 +15,6 @@ import ( "encoding/pem" "errors" "fmt" - "log/slog" "math/big" "os" "time" @@ -35,7 +34,8 @@ type certReq struct { privateKey *ecdsa.PrivateKey } -func genCert(req *certReq) (*x509.Certificate, []byte) { +// Returns x509 Certificate object and bytes in PEM format +func genCert(req *certReq) (*x509.Certificate, []byte, error) { certBytes, createCertErr := x509.CreateCertificate( rand.Reader, req.template, @@ -45,22 +45,21 @@ func genCert(req *certReq) (*x509.Certificate, []byte) { ) if createCertErr != nil { - slog.Error("Failed to generate certificate", "error", createCertErr) - return &x509.Certificate{}, []byte{} + return &x509.Certificate{}, []byte{}, fmt.Errorf("error generating certificate: %w", createCertErr) } cert, parseCertErr := x509.ParseCertificate(certBytes) if parseCertErr != nil { - slog.Error("Failed to parse certificate") - return &x509.Certificate{}, []byte{} + return &x509.Certificate{}, []byte{}, fmt.Errorf("error parsing certificate: %w", parseCertErr) } b := pem.Block{Type: "CERTIFICATE", Bytes: certBytes} certPEM := pem.EncodeToMemory(&b) - return cert, certPEM + return cert, certPEM, nil } +// Generates a CA, returns x509 Certificate and private key for signing server certificates func GenerateCA(now time.Time, caCertPath string) (*x509.Certificate, *ecdsa.PrivateKey, error) { // Generate key pair for the CA caKeyPair, caKeyErr := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) @@ -89,13 +88,14 @@ func GenerateCA(now time.Time, caCertPath string) (*x509.Certificate, *ecdsa.Pri privateKey: caKeyPair, } - caCert, caCertPEM := genCert(&caRequest) - if len(caCertPEM) == 0 { - slog.Error("Error generating certificate authority") + caCert, caCertPEM, caErr := genCert(&caRequest) + if caErr != nil { + return &x509.Certificate{}, &ecdsa.PrivateKey{}, fmt.Errorf( + "error generating certificate authority: %w", + caErr) } // Write the CA certificate to a file - slog.Debug("About to write CA file", "path", caCertPath) writeCAErr := os.WriteFile(caCertPath, caCertPEM, certFilePermissions) if writeCAErr != nil { return &x509.Certificate{}, &ecdsa.PrivateKey{}, fmt.Errorf( @@ -107,10 +107,11 @@ func GenerateCA(now time.Time, caCertPath string) (*x509.Certificate, *ecdsa.Pri return caCert, caKeyPair, nil } +// Writes CA, Cert, Key to specified destinations. If cert files are already present, does nothing, returns true // nolint: revive -func GenerateServerCert(hostnames []string, caPath, certPath, keyPath string) (existingCert bool, err error) { +func GenerateServerCerts(hostnames []string, caPath, certPath, keyPath string) (existingCert bool, err error) { // Check for and return existing cert if it already exists - existingCert, existingCertErr := ReturnExistingCert(certPath) + existingCert, existingCertErr := DoesCertAlreadyExist(certPath) if existingCertErr != nil { return false, fmt.Errorf("error reading existing certificate data: %w", existingCertErr) } @@ -157,9 +158,9 @@ func GenerateServerCert(hostnames []string, caPath, certPath, keyPath string) (e } // Generate server certficated signed by the CA - _, servCertPEM := genCert(&servRequest) - if len(servCertPEM) == 0 { - return false, errors.New("error generating server certificate") + _, servCertPEM, servCertErr := genCert(&servRequest) + if servCertErr != nil { + return false, fmt.Errorf("error generating server certificate: %w", servCertErr) } // Write the certificate to a file @@ -183,7 +184,8 @@ func GenerateServerCert(hostnames []string, caPath, certPath, keyPath string) (e return false, nil } -func ReturnExistingCert(certPath string) (bool, error) { +// Returns true if a valid certificate is found at certPath +func DoesCertAlreadyExist(certPath string) (bool, error) { if _, certErr := os.Stat(certPath); certErr == nil { certBytes, certReadErr := os.ReadFile(certPath) if certReadErr != nil { diff --git a/pkg/tls/self_signed_cert_test.go b/pkg/tls/self_signed_cert_test.go index f5e4ae82a2..64911d77aa 100644 --- a/pkg/tls/self_signed_cert_test.go +++ b/pkg/tls/self_signed_cert_test.go @@ -219,7 +219,7 @@ func TestGenerateSelfSignedCert(t *testing.T) { err := tc.setup() require.NoError(t, err) - existingCert, genCertErr := GenerateServerCert(tc.hostNames, tc.caPath, tc.certPath, tc.keyPath) + existingCert, genCertErr := GenerateServerCerts(tc.hostNames, tc.caPath, tc.certPath, tc.keyPath) // Check the results if tc.expectedError != "" { From 1b22853485057bbe0c27d68ef20128d9272e7f9c Mon Sep 17 00:00:00 2001 From: Christopher van de Sande Date: Fri, 20 Sep 2024 12:17:07 +0100 Subject: [PATCH 07/22] fix mock config syntax --- test/mock/collector/nginx-agent.conf | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/mock/collector/nginx-agent.conf b/test/mock/collector/nginx-agent.conf index de55b87475..b2e16388d1 100644 --- a/test/mock/collector/nginx-agent.conf +++ b/test/mock/collector/nginx-agent.conf @@ -42,14 +42,14 @@ collector: host: "127.0.0.1" port: 4317 type: 0 - auth: - Token: "secret-receiver-token" - tls: - server_name: "test-local-server" - ca: /tmp/ca.pem - cert: /tmp/cert.pem - key: /tmp/key.pem - generate_self_signed_cert: true + auth: + Token: secret-receiver-token + tls: + server_name: test-local-server + ca: /tmp/ca.pem + cert: /tmp/cert.pem + key: /tmp/key.pem + generate_self_signed_cert: true processors: - type: batch exporters: From 1bdedf5762a3e3c867a16336208ee0a638c4fb7a Mon Sep 17 00:00:00 2001 From: Christopher van de Sande Date: Fri, 20 Sep 2024 13:06:15 +0100 Subject: [PATCH 08/22] address test comments --- internal/collector/otel_collector_plugin.go | 29 ++++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/internal/collector/otel_collector_plugin.go b/internal/collector/otel_collector_plugin.go index b0ae1a8240..7286c9ae3f 100644 --- a/internal/collector/otel_collector_plugin.go +++ b/internal/collector/otel_collector_plugin.go @@ -67,7 +67,6 @@ func New(conf *config.Config) (*Collector, error) { } // Init initializes and starts the plugin -// nolint: revive func (oc *Collector) Init(ctx context.Context, mp bus.MessagePipeInterface) error { slog.InfoContext(ctx, "Starting OTel Collector plugin") @@ -80,8 +79,23 @@ func (oc *Collector) Init(ctx context.Context, mp bus.MessagePipeInterface) erro } if oc.config.Collector.Receivers.OtlpReceivers != nil { - for _, receiver := range oc.config.Collector.Receivers.OtlpReceivers { - if receiver.OtlpTLSConfig != nil && receiver.OtlpTLSConfig.GenerateSelfSignedCert { + oc.processReceivers(ctx, oc.config.Collector.Receivers.OtlpReceivers) + } + + bootErr := oc.bootup(runCtx) + if bootErr != nil { + slog.ErrorContext(runCtx, "Unable to start OTel Collector", "error", bootErr) + } + + return nil +} + +// Process receivers and log warning for sub-optimal configurations +// nolint: revive +func (oc *Collector) processReceivers(ctx context.Context, receivers []config.OtlpReceiver) { + for _, receiver := range receivers { + if receiver.OtlpTLSConfig != nil { + if receiver.OtlpTLSConfig.GenerateSelfSignedCert { slog.WarnContext(ctx, "Self-signed certificate for OTEL receiver requested, "+ "this is not recommended for production environments.", @@ -93,15 +107,10 @@ func (oc *Collector) Init(ctx context.Context, mp bus.MessagePipeInterface) erro ) } } + } else { + slog.WarnContext(ctx, "OTEL receiver is configured without TLS. Connections are unencrypted.") } } - - bootErr := oc.bootup(runCtx) - if bootErr != nil { - slog.ErrorContext(runCtx, "Unable to start OTel Collector", "error", bootErr) - } - - return nil } func (oc *Collector) bootup(ctx context.Context) error { From 3e13ace0a9f52c51cf3c3c155cbeccbc6839f097 Mon Sep 17 00:00:00 2001 From: Christopher van de Sande Date: Fri, 20 Sep 2024 18:49:40 +0100 Subject: [PATCH 09/22] remove spaces from names --- internal/collector/otel_collector_plugin.go | 24 +++++++++++---------- internal/config/defaults.go | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/internal/collector/otel_collector_plugin.go b/internal/collector/otel_collector_plugin.go index 7286c9ae3f..160ec3e113 100644 --- a/internal/collector/otel_collector_plugin.go +++ b/internal/collector/otel_collector_plugin.go @@ -91,21 +91,23 @@ func (oc *Collector) Init(ctx context.Context, mp bus.MessagePipeInterface) erro } // Process receivers and log warning for sub-optimal configurations -// nolint: revive func (oc *Collector) processReceivers(ctx context.Context, receivers []config.OtlpReceiver) { for _, receiver := range receivers { - if receiver.OtlpTLSConfig != nil { - if receiver.OtlpTLSConfig.GenerateSelfSignedCert { + if receiver.OtlpTLSConfig == nil { + slog.WarnContext(ctx, "OTEL receiver is configured without TLS. Connections are unencrypted.") + continue + } + + if receiver.OtlpTLSConfig.GenerateSelfSignedCert { + slog.WarnContext(ctx, + "Self-signed certificate for OTEL receiver requested, "+ + "this is not recommended for production environments.", + ) + + if receiver.OtlpTLSConfig.ExistingCert { slog.WarnContext(ctx, - "Self-signed certificate for OTEL receiver requested, "+ - "this is not recommended for production environments.", + "Certificate file already exists, skipping self-signed certificate generation", ) - if receiver.OtlpTLSConfig.ExistingCert { - slog.WarnContext( - ctx, - "Certificate file already exists, skipping self-signed certificate generation", - ) - } } } else { slog.WarnContext(ctx, "OTEL receiver is configured without TLS. Connections are unencrypted.") diff --git a/internal/config/defaults.go b/internal/config/defaults.go index 40030c5020..5a2b6b7f4b 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -22,7 +22,7 @@ const ( DefCollectorTLSCertPath = "/var/lib/nginx-agent/cert.pem" DefCollectorTLSKeyPath = "/var/lib/nginx-agent/key.pem" DefCollectorTLSCAPath = "/var/lib/nginx-agent/ca.pem" - DefCollectorTLSSANNames = "127.0.0.1, ::1, localhost" + DefCollectorTLSSANNames = "127.0.0.1,::1,localhost" DefCommandServerHostKey = "" DefCommandServerPortKey = 0 From 4bc86f337d5e297dea6a50ce65310e3466224ee2 Mon Sep 17 00:00:00 2001 From: oliveromahony Date: Mon, 23 Sep 2024 15:02:21 +0100 Subject: [PATCH 10/22] agent log to standard out as well as a file (#858) * agent log to standard out as well as a file --- internal/logger/logger.go | 5 ++++- internal/logger/logger_test.go | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/internal/logger/logger.go b/internal/logger/logger.go index 3f416b1555..cc0728996b 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -89,7 +89,10 @@ func getLogWriter(logFile string) io.Writer { return os.Stderr } - return logFileHandle + // Use io.MultiWriter to log to both Stdout and the file + multiWriter := io.MultiWriter(os.Stdout, logFileHandle) + + return multiWriter } return os.Stderr diff --git a/internal/logger/logger_test.go b/internal/logger/logger_test.go index 6b4f16274b..1eefdf1750 100644 --- a/internal/logger/logger_test.go +++ b/internal/logger/logger_test.go @@ -90,12 +90,12 @@ func TestGetLogWriter(t *testing.T) { { name: "Test 3: Log file exists", input: file.Name(), - expected: &os.File{}, + expected: io.MultiWriter(), }, { name: "Test 4: Log directory", input: ".", - expected: &os.File{}, + expected: io.MultiWriter(), }, } From 7285e27167e0413e35fe60482c6d2de644945de6 Mon Sep 17 00:00:00 2001 From: aphralG <108004222+aphralG@users.noreply.github.com> Date: Mon, 23 Sep 2024 15:58:26 +0100 Subject: [PATCH 11/22] Move Dockerfiles to test (#855) * move dockerfiles to test --- Makefile | 12 ++++++------ .../internal/metadata/generated_status.go | 3 +-- .../internal/metadata/generated_status.go | 3 +-- {scripts => test}/docker/entrypoint.sh | 0 .../{oss => nginx-official-image}/apk/Dockerfile | 0 .../{oss => nginx-official-image}/deb/Dockerfile | 0 {scripts => test}/docker/nginx-oss/apk/Dockerfile | 0 {scripts => test}/docker/nginx-oss/deb/Dockerfile | 0 {scripts => test}/docker/nginx-oss/rpm/Dockerfile | 0 {scripts => test}/docker/nginx-plus/deb/Dockerfile | 0 test/helpers/test_containers_utils.go | 2 +- 11 files changed, 9 insertions(+), 11 deletions(-) rename {scripts => test}/docker/entrypoint.sh (100%) rename test/docker/{oss => nginx-official-image}/apk/Dockerfile (100%) rename test/docker/{oss => nginx-official-image}/deb/Dockerfile (100%) rename {scripts => test}/docker/nginx-oss/apk/Dockerfile (100%) rename {scripts => test}/docker/nginx-oss/deb/Dockerfile (100%) rename {scripts => test}/docker/nginx-oss/rpm/Dockerfile (100%) rename {scripts => test}/docker/nginx-plus/deb/Dockerfile (100%) diff --git a/Makefile b/Makefile index f97e2fd4f5..091981fda5 100644 --- a/Makefile +++ b/Makefile @@ -31,8 +31,8 @@ OS_RELEASE ?= ubuntu OS_VERSION ?= 22.04 BASE_IMAGE = "docker.io/$(OS_RELEASE):$(OS_VERSION)" IMAGE_TAG = "agent_$(OS_RELEASE)_$(OS_VERSION)" -DOCKERFILE_PATH = "./scripts/docker/nginx-oss/$(CONTAINER_OS_TYPE)/Dockerfile" -OFFICIAL_IMAGE_DOCKERFILE_PATH = "./test/docker/oss/$(CONTAINER_OS_TYPE)/Dockerfile" +DOCKERFILE_PATH = "./test/docker/nginx-oss/$(CONTAINER_OS_TYPE)/Dockerfile" +OFFICIAL_IMAGE_DOCKERFILE_PATH = "./test/docker/nginx-official-image/$(CONTAINER_OS_TYPE)/Dockerfile" IMAGE_PATH ?= "/nginx/agent" TAG ?= "" @@ -190,23 +190,23 @@ run-mock-management-grpc-server: ## Run mock management plane gRPC server .PHONY: build-test-plus-image build-test-plus-image: $(CONTAINER_BUILDENV) $(CONTAINER_CLITOOL) build -t nginx_plus_$(IMAGE_TAG) . \ - --no-cache -f ./scripts/docker/nginx-plus/deb/Dockerfile \ + --no-cache -f ./test/docker/nginx-plus/deb/Dockerfile \ --secret id=nginx-crt,src=$(CERTS_DIR)/nginx-repo.crt \ --secret id=nginx-key,src=$(CERTS_DIR)/nginx-repo.key \ --build-arg PACKAGE_NAME=$(PACKAGE_NAME) \ --build-arg PACKAGES_REPO=$(OSS_PACKAGES_REPO) \ --build-arg BASE_IMAGE=$(BASE_IMAGE) \ - --build-arg ENTRY_POINT=./scripts/docker/entrypoint.sh + --build-arg ENTRY_POINT=./test/docker/entrypoint.sh .PHONY: build-test-oss-image build-test-oss-image: $(CONTAINER_BUILDENV) $(CONTAINER_CLITOOL) build -t nginx_oss_$(IMAGE_TAG) . \ - --no-cache -f ./scripts/docker/nginx-oss/deb/Dockerfile \ + --no-cache -f ./test/docker/nginx-oss/deb/Dockerfile \ --target install-agent-local \ --build-arg PACKAGE_NAME=$(PACKAGE_NAME) \ --build-arg PACKAGES_REPO=$(OSS_PACKAGES_REPO) \ --build-arg BASE_IMAGE=$(BASE_IMAGE) \ - --build-arg ENTRY_POINT=./scripts/docker/entrypoint.sh + --build-arg ENTRY_POINT=./test/docker/entrypoint.sh .PHONY: run-mock-management-otel-collector run-mock-management-otel-collector: ## Run mock management plane OTel collector diff --git a/internal/collector/nginxossreceiver/internal/metadata/generated_status.go b/internal/collector/nginxossreceiver/internal/metadata/generated_status.go index 3eb166a1ad..f4cd74a5e4 100644 --- a/internal/collector/nginxossreceiver/internal/metadata/generated_status.go +++ b/internal/collector/nginxossreceiver/internal/metadata/generated_status.go @@ -7,8 +7,7 @@ import ( ) var ( - Type = component.MustNewType("nginx") - ScopeName = "otelcol/nginxreceiver" + Type = component.MustNewType("nginx") ) const ( diff --git a/internal/collector/nginxplusreceiver/internal/metadata/generated_status.go b/internal/collector/nginxplusreceiver/internal/metadata/generated_status.go index 96f453b98a..feb047ea22 100644 --- a/internal/collector/nginxplusreceiver/internal/metadata/generated_status.go +++ b/internal/collector/nginxplusreceiver/internal/metadata/generated_status.go @@ -7,8 +7,7 @@ import ( ) var ( - Type = component.MustNewType("nginxplus") - ScopeName = "otelcol/nginxplusreceiver" + Type = component.MustNewType("nginxplus") ) const ( diff --git a/scripts/docker/entrypoint.sh b/test/docker/entrypoint.sh similarity index 100% rename from scripts/docker/entrypoint.sh rename to test/docker/entrypoint.sh diff --git a/test/docker/oss/apk/Dockerfile b/test/docker/nginx-official-image/apk/Dockerfile similarity index 100% rename from test/docker/oss/apk/Dockerfile rename to test/docker/nginx-official-image/apk/Dockerfile diff --git a/test/docker/oss/deb/Dockerfile b/test/docker/nginx-official-image/deb/Dockerfile similarity index 100% rename from test/docker/oss/deb/Dockerfile rename to test/docker/nginx-official-image/deb/Dockerfile diff --git a/scripts/docker/nginx-oss/apk/Dockerfile b/test/docker/nginx-oss/apk/Dockerfile similarity index 100% rename from scripts/docker/nginx-oss/apk/Dockerfile rename to test/docker/nginx-oss/apk/Dockerfile diff --git a/scripts/docker/nginx-oss/deb/Dockerfile b/test/docker/nginx-oss/deb/Dockerfile similarity index 100% rename from scripts/docker/nginx-oss/deb/Dockerfile rename to test/docker/nginx-oss/deb/Dockerfile diff --git a/scripts/docker/nginx-oss/rpm/Dockerfile b/test/docker/nginx-oss/rpm/Dockerfile similarity index 100% rename from scripts/docker/nginx-oss/rpm/Dockerfile rename to test/docker/nginx-oss/rpm/Dockerfile diff --git a/scripts/docker/nginx-plus/deb/Dockerfile b/test/docker/nginx-plus/deb/Dockerfile similarity index 100% rename from scripts/docker/nginx-plus/deb/Dockerfile rename to test/docker/nginx-plus/deb/Dockerfile diff --git a/test/helpers/test_containers_utils.go b/test/helpers/test_containers_utils.go index b86b7e7607..485c0d954f 100644 --- a/test/helpers/test_containers_utils.go +++ b/test/helpers/test_containers_utils.go @@ -56,7 +56,7 @@ func StartContainer( "BASE_IMAGE": ToPtr(baseImage), "OS_RELEASE": ToPtr(osRelease), "OS_VERSION": ToPtr(osVersion), - "ENTRY_POINT": ToPtr("./scripts/docker/entrypoint.sh"), + "ENTRY_POINT": ToPtr("./test/docker/entrypoint.sh"), "CONTAINER_NGINX_IMAGE_REGISTRY": ToPtr(containerRegistry), "IMAGE_PATH": ToPtr(imagePath), "TAG": ToPtr(tag), From 8d039f16a82e832f59e5c62cff4f94005b120a82 Mon Sep 17 00:00:00 2001 From: aphralG <108004222+aphralG@users.noreply.github.com> Date: Wed, 25 Sep 2024 10:06:51 +0100 Subject: [PATCH 12/22] Change connection created message log level (#864) * change log level of connection log --- .../generated_component_test.go | 12 +-- .../internal/metadata/generated_metrics.go | 54 ++++++++----- .../metadata/generated_metrics_test.go | 18 ++--- .../internal/metadata/generated_status.go | 3 +- .../generated_component_test.go | 12 +-- .../internal/metadata/generated_metrics.go | 54 ++++++++----- .../metadata/generated_metrics_test.go | 76 +++++++++---------- .../internal/metadata/generated_status.go | 3 +- internal/command/command_service.go | 4 +- 9 files changed, 135 insertions(+), 101 deletions(-) diff --git a/internal/collector/nginxossreceiver/generated_component_test.go b/internal/collector/nginxossreceiver/generated_component_test.go index 3007dc92b4..60de562050 100644 --- a/internal/collector/nginxossreceiver/generated_component_test.go +++ b/internal/collector/nginxossreceiver/generated_component_test.go @@ -46,21 +46,21 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) - for _, test := range tests { - t.Run(test.name+"-shutdown", func(t *testing.T) { - c, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + for _, tt := range tests { + t.Run(tt.name+"-shutdown", func(t *testing.T) { + c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) - t.Run(test.name+"-lifecycle", func(t *testing.T) { - firstRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + t.Run(tt.name+"-lifecycle", func(t *testing.T) { + firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) host := componenttest.NewNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) - secondRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) diff --git a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go index e74642bc94..c560fe1bc8 100644 --- a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go +++ b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go @@ -313,17 +313,25 @@ type MetricsBuilder struct { metricNginxHTTPResponseStatus metricNginxHTTPResponseStatus } -// metricBuilderOption applies changes to default metrics builder. -type metricBuilderOption func(*MetricsBuilder) +// MetricBuilderOption applies changes to default metrics builder. +type MetricBuilderOption interface { + apply(*MetricsBuilder) +} + +type metricBuilderOptionFunc func(mb *MetricsBuilder) + +func (mbof metricBuilderOptionFunc) apply(mb *MetricsBuilder) { + mbof(mb) +} // WithStartTime sets startTime on the metrics builder. -func WithStartTime(startTime pcommon.Timestamp) metricBuilderOption { - return func(mb *MetricsBuilder) { +func WithStartTime(startTime pcommon.Timestamp) MetricBuilderOption { + return metricBuilderOptionFunc(func(mb *MetricsBuilder) { mb.startTime = startTime - } + }) } -func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...metricBuilderOption) *MetricsBuilder { +func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...MetricBuilderOption) *MetricsBuilder { mb := &MetricsBuilder{ config: mbc, startTime: pcommon.NewTimestampFromTime(time.Now()), @@ -336,7 +344,7 @@ func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, opt } for _, op := range options { - op(mb) + op.apply(mb) } return mb } @@ -349,20 +357,28 @@ func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { } // ResourceMetricsOption applies changes to provided resource metrics. -type ResourceMetricsOption func(pmetric.ResourceMetrics) +type ResourceMetricsOption interface { + apply(pmetric.ResourceMetrics) +} + +type resourceMetricsOptionFunc func(pmetric.ResourceMetrics) + +func (rmof resourceMetricsOptionFunc) apply(rm pmetric.ResourceMetrics) { + rmof(rm) +} // WithResource sets the provided resource on the emitted ResourceMetrics. // It's recommended to use ResourceBuilder to create the resource. func WithResource(res pcommon.Resource) ResourceMetricsOption { - return func(rm pmetric.ResourceMetrics) { + return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { res.CopyTo(rm.Resource()) - } + }) } // WithStartTimeOverride overrides start time for all the resource metrics data points. // This option should be only used if different start time has to be set on metrics coming from different resources. func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { - return func(rm pmetric.ResourceMetrics) { + return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { var dps pmetric.NumberDataPointSlice metrics := rm.ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { @@ -376,7 +392,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { dps.At(j).SetStartTimestamp(start) } } - } + }) } // EmitForResource saves all the generated metrics under a new resource and updates the internal state to be ready for @@ -384,7 +400,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { // needs to emit metrics from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceMetricsOption arguments. -func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { +func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { rm := pmetric.NewResourceMetrics() ils := rm.ScopeMetrics().AppendEmpty() ils.Scope().SetName("otelcol/nginxreceiver") @@ -395,8 +411,8 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { mb.metricNginxHTTPRequests.emit(ils.Metrics()) mb.metricNginxHTTPResponseStatus.emit(ils.Metrics()) - for _, op := range rmo { - op(rm) + for _, op := range options { + op.apply(rm) } if ils.Metrics().Len() > 0 { @@ -408,8 +424,8 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { // Emit returns all the metrics accumulated by the metrics builder and updates the internal state to be ready for // recording another set of metrics. This function will be responsible for applying all the transformations required to // produce metric representation defined in metadata and user config, e.g. delta or cumulative. -func (mb *MetricsBuilder) Emit(rmo ...ResourceMetricsOption) pmetric.Metrics { - mb.EmitForResource(rmo...) +func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics { + mb.EmitForResource(options...) metrics := mb.metricsBuffer mb.metricsBuffer = pmetric.NewMetrics() return metrics @@ -437,9 +453,9 @@ func (mb *MetricsBuilder) RecordNginxHTTPResponseStatusDataPoint(ts pcommon.Time // Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, // and metrics builder should update its startTime and reset it's internal state accordingly. -func (mb *MetricsBuilder) Reset(options ...metricBuilderOption) { +func (mb *MetricsBuilder) Reset(options ...MetricBuilderOption) { mb.startTime = pcommon.NewTimestampFromTime(time.Now()) for _, op := range options { - op(mb) + op.apply(mb) } } diff --git a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go index 261655b70a..2581a33ef3 100644 --- a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go +++ b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go @@ -43,14 +43,14 @@ func TestMetricsBuilder(t *testing.T) { expectEmpty: true, }, } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { start := pcommon.Timestamp(1_000_000_000) ts := pcommon.Timestamp(1_000_001_000) observedZapCore, observedLogs := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings() settings.Logger = zap.New(observedZapCore) - mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, test.name), settings, WithStartTime(start)) + mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start)) expectedWarnings := 0 @@ -78,7 +78,7 @@ func TestMetricsBuilder(t *testing.T) { res := pcommon.NewResource() metrics := mb.Emit(WithResource(res)) - if test.expectEmpty { + if tt.expectEmpty { assert.Equal(t, 0, metrics.ResourceMetrics().Len()) return } @@ -88,10 +88,10 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, res, rm.Resource()) assert.Equal(t, 1, rm.ScopeMetrics().Len()) ms := rm.ScopeMetrics().At(0).Metrics() - if test.metricsSet == testDataSetDefault { + if tt.metricsSet == testDataSetDefault { assert.Equal(t, defaultMetricsCount, ms.Len()) } - if test.metricsSet == testDataSetAll { + if tt.metricsSet == testDataSetAll { assert.Equal(t, allMetricsCount, ms.Len()) } validatedMetrics := make(map[string]bool) @@ -104,7 +104,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -136,7 +136,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests received from clients.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -150,7 +150,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The number of responses, grouped by status code range.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) diff --git a/internal/collector/nginxossreceiver/internal/metadata/generated_status.go b/internal/collector/nginxossreceiver/internal/metadata/generated_status.go index f4cd74a5e4..3eb166a1ad 100644 --- a/internal/collector/nginxossreceiver/internal/metadata/generated_status.go +++ b/internal/collector/nginxossreceiver/internal/metadata/generated_status.go @@ -7,7 +7,8 @@ import ( ) var ( - Type = component.MustNewType("nginx") + Type = component.MustNewType("nginx") + ScopeName = "otelcol/nginxreceiver" ) const ( diff --git a/internal/collector/nginxplusreceiver/generated_component_test.go b/internal/collector/nginxplusreceiver/generated_component_test.go index 170385ba71..9fbb9944ca 100644 --- a/internal/collector/nginxplusreceiver/generated_component_test.go +++ b/internal/collector/nginxplusreceiver/generated_component_test.go @@ -46,21 +46,21 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) - for _, test := range tests { - t.Run(test.name+"-shutdown", func(t *testing.T) { - c, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + for _, tt := range tests { + t.Run(tt.name+"-shutdown", func(t *testing.T) { + c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) - t.Run(test.name+"-lifecycle", func(t *testing.T) { - firstRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + t.Run(tt.name+"-lifecycle", func(t *testing.T) { + firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) host := componenttest.NewNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) - secondRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) diff --git a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go index 866fb5a735..15dbba1752 100644 --- a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go +++ b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go @@ -3620,17 +3620,25 @@ type MetricsBuilder struct { metricNginxStreamUpstreamZombieCount metricNginxStreamUpstreamZombieCount } -// metricBuilderOption applies changes to default metrics builder. -type metricBuilderOption func(*MetricsBuilder) +// MetricBuilderOption applies changes to default metrics builder. +type MetricBuilderOption interface { + apply(*MetricsBuilder) +} + +type metricBuilderOptionFunc func(mb *MetricsBuilder) + +func (mbof metricBuilderOptionFunc) apply(mb *MetricsBuilder) { + mbof(mb) +} // WithStartTime sets startTime on the metrics builder. -func WithStartTime(startTime pcommon.Timestamp) metricBuilderOption { - return func(mb *MetricsBuilder) { +func WithStartTime(startTime pcommon.Timestamp) MetricBuilderOption { + return metricBuilderOptionFunc(func(mb *MetricsBuilder) { mb.startTime = startTime - } + }) } -func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...metricBuilderOption) *MetricsBuilder { +func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...MetricBuilderOption) *MetricsBuilder { mb := &MetricsBuilder{ config: mbc, startTime: pcommon.NewTimestampFromTime(time.Now()), @@ -3697,7 +3705,7 @@ func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, opt } for _, op := range options { - op(mb) + op.apply(mb) } return mb } @@ -3710,20 +3718,28 @@ func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { } // ResourceMetricsOption applies changes to provided resource metrics. -type ResourceMetricsOption func(pmetric.ResourceMetrics) +type ResourceMetricsOption interface { + apply(pmetric.ResourceMetrics) +} + +type resourceMetricsOptionFunc func(pmetric.ResourceMetrics) + +func (rmof resourceMetricsOptionFunc) apply(rm pmetric.ResourceMetrics) { + rmof(rm) +} // WithResource sets the provided resource on the emitted ResourceMetrics. // It's recommended to use ResourceBuilder to create the resource. func WithResource(res pcommon.Resource) ResourceMetricsOption { - return func(rm pmetric.ResourceMetrics) { + return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { res.CopyTo(rm.Resource()) - } + }) } // WithStartTimeOverride overrides start time for all the resource metrics data points. // This option should be only used if different start time has to be set on metrics coming from different resources. func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { - return func(rm pmetric.ResourceMetrics) { + return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { var dps pmetric.NumberDataPointSlice metrics := rm.ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { @@ -3737,7 +3753,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { dps.At(j).SetStartTimestamp(start) } } - } + }) } // EmitForResource saves all the generated metrics under a new resource and updates the internal state to be ready for @@ -3745,7 +3761,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { // needs to emit metrics from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceMetricsOption arguments. -func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { +func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { rm := pmetric.NewResourceMetrics() ils := rm.ScopeMetrics().AppendEmpty() ils.Scope().SetName("otelcol/nginxplusreceiver") @@ -3810,8 +3826,8 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { mb.metricNginxStreamUpstreamPeerUnavailable.emit(ils.Metrics()) mb.metricNginxStreamUpstreamZombieCount.emit(ils.Metrics()) - for _, op := range rmo { - op(rm) + for _, op := range options { + op.apply(rm) } if ils.Metrics().Len() > 0 { @@ -3823,8 +3839,8 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { // Emit returns all the metrics accumulated by the metrics builder and updates the internal state to be ready for // recording another set of metrics. This function will be responsible for applying all the transformations required to // produce metric representation defined in metadata and user config, e.g. delta or cumulative. -func (mb *MetricsBuilder) Emit(rmo ...ResourceMetricsOption) pmetric.Metrics { - mb.EmitForResource(rmo...) +func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics { + mb.EmitForResource(options...) metrics := mb.metricsBuffer mb.metricsBuffer = pmetric.NewMetrics() return metrics @@ -4122,9 +4138,9 @@ func (mb *MetricsBuilder) RecordNginxStreamUpstreamZombieCountDataPoint(ts pcomm // Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, // and metrics builder should update its startTime and reset it's internal state accordingly. -func (mb *MetricsBuilder) Reset(options ...metricBuilderOption) { +func (mb *MetricsBuilder) Reset(options ...MetricBuilderOption) { mb.startTime = pcommon.NewTimestampFromTime(time.Now()) for _, op := range options { - op(mb) + op.apply(mb) } } diff --git a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go index 8e8f64cbb9..6d048f6442 100644 --- a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go +++ b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go @@ -43,14 +43,14 @@ func TestMetricsBuilder(t *testing.T) { expectEmpty: true, }, } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { start := pcommon.Timestamp(1_000_000_000) ts := pcommon.Timestamp(1_000_001_000) observedZapCore, observedLogs := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings() settings.Logger = zap.New(observedZapCore) - mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, test.name), settings, WithStartTime(start)) + mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start)) expectedWarnings := 0 @@ -294,7 +294,7 @@ func TestMetricsBuilder(t *testing.T) { res := pcommon.NewResource() metrics := mb.Emit(WithResource(res)) - if test.expectEmpty { + if tt.expectEmpty { assert.Equal(t, 0, metrics.ResourceMetrics().Len()) return } @@ -304,10 +304,10 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, res, rm.Resource()) assert.Equal(t, 1, rm.ScopeMetrics().Len()) ms := rm.ScopeMetrics().At(0).Metrics() - if test.metricsSet == testDataSetDefault { + if tt.metricsSet == testDataSetDefault { assert.Equal(t, defaultMetricsCount, ms.Len()) } - if test.metricsSet == testDataSetAll { + if tt.metricsSet == testDataSetAll { assert.Equal(t, allMetricsCount, ms.Len()) } validatedMetrics := make(map[string]bool) @@ -320,7 +320,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of bytes read from the cache or proxied server.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -370,7 +370,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of responses read from the cache or proxied server.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -390,7 +390,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of NGINX config reloads.", ms.At(i).Description()) assert.Equal(t, "reloads", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -404,7 +404,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -436,7 +436,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections to an endpoint with a limit_conn directive.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -456,7 +456,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of requests to an endpoint with a limit_req directive.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -476,7 +476,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of HTTP byte IO.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -499,7 +499,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of requests completed without sending a response.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -537,7 +537,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests received from clients.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -569,7 +569,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The number of responses, grouped by status code range.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -592,7 +592,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests received from clients.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -630,7 +630,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of byte IO per HTTP upstream peer.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -752,7 +752,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of health check requests made to a HTTP upstream peer.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -781,7 +781,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests forwarded to the HTTP upstream peer.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -831,7 +831,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of responses obtained from the HTTP upstream peer grouped by status range.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -887,7 +887,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Number of times the server became unavailable for client requests (“unavail”).", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -931,7 +931,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of requests rejected due to the queue overflow.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1036,7 +1036,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) - assert.Equal(t, float64(1), dp.DoubleValue()) + assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) attrVal, ok := dp.Attributes().Get("nginx.zone.name") assert.True(t, ok) assert.EqualValues(t, "nginx.zone.name-val", attrVal.Str()) @@ -1047,7 +1047,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The number of attempts to allocate memory of specified size.", ms.At(i).Description()) assert.Equal(t, "allocations", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1106,7 +1106,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of SSL certificate verification failures.", ms.At(i).Description()) assert.Equal(t, "certificates", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1123,7 +1123,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of SSL handshakes.", ms.At(i).Description()) assert.Equal(t, "handshakes", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1143,7 +1143,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of Stream byte IO.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1163,7 +1163,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections accepted from clients.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1180,7 +1180,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Total number of connections completed without creating a session.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1212,7 +1212,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of completed sessions.", ms.At(i).Description()) assert.Equal(t, "sessions", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1232,7 +1232,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of Stream Upstream Peer byte IO.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1309,7 +1309,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client connections forwarded to this stream upstream peer.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1335,7 +1335,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of stream upstream peers grouped by state.", ms.At(i).Description()) assert.Equal(t, "peers", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1358,7 +1358,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of unsuccessful attempts to communicate with the stream upstream peer.", ms.At(i).Description()) assert.Equal(t, "peers", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1381,7 +1381,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of health check requests made to the stream upstream peer.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1434,7 +1434,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Current state of upstream peers in deployment. If any of the upstream peers in the deployment match the given state then the value will be 1. If no upstream peer is a match then the value will be 0.", ms.At(i).Description()) assert.Equal(t, "deployments", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1487,7 +1487,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "How many times the server became unavailable for client connections (state “unavail”) due to the number of unsuccessful attempts reaching the max_fails threshold.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) diff --git a/internal/collector/nginxplusreceiver/internal/metadata/generated_status.go b/internal/collector/nginxplusreceiver/internal/metadata/generated_status.go index feb047ea22..96f453b98a 100644 --- a/internal/collector/nginxplusreceiver/internal/metadata/generated_status.go +++ b/internal/collector/nginxplusreceiver/internal/metadata/generated_status.go @@ -7,7 +7,8 @@ import ( ) var ( - Type = component.MustNewType("nginxplus") + Type = component.MustNewType("nginxplus") + ScopeName = "otelcol/nginxplusreceiver" ) const ( diff --git a/internal/command/command_service.go b/internal/command/command_service.go index 76123bbf5d..88bc84d6b2 100644 --- a/internal/command/command_service.go +++ b/internal/command/command_service.go @@ -239,8 +239,8 @@ func (cs *CommandService) CreateConnection( return nil, err } - slog.DebugContext(ctx, "Connection created", "response", response) - slog.DebugContext(ctx, "Agent connected") + slog.InfoContext(ctx, "Connection created", "response", response) + slog.InfoContext(ctx, "Agent connected") cs.isConnected.Store(true) From b9de2aab953842c17c2d7a7ae21ef2b315effad5 Mon Sep 17 00:00:00 2001 From: Donal Hurley Date: Thu, 26 Sep 2024 10:15:12 +0100 Subject: [PATCH 13/22] Update extensions config for OTel collector (#843) --- internal/collector/otelcol.tmpl | 17 ++++++++++---- internal/config/config.go | 16 +++++++------- internal/config/config_test.go | 18 +++++++++------ internal/config/flags.go | 2 +- internal/config/testdata/nginx-agent.conf | 9 ++++---- internal/config/types.go | 22 ++++++++++++++----- test/config/agent/nginx-agent-otel-load.conf | 10 +++++---- .../test-opentelemetry-collector-agent.yaml | 1 - test/mock/collector/nginx-agent.conf | 9 ++++---- test/types/config.go | 12 ++++++---- 10 files changed, 73 insertions(+), 43 deletions(-) diff --git a/internal/collector/otelcol.tmpl b/internal/collector/otelcol.tmpl index bd34cf733b..cc16d74197 100644 --- a/internal/collector/otelcol.tmpl +++ b/internal/collector/otelcol.tmpl @@ -113,13 +113,22 @@ exporters: {{- end }} {{- end }} +{{- if ne .Extensions nil }} extensions: + {{- if ne .Extensions.Health nil }} health_check: - {{- if .Health }} - endpoint: "{{ .Health.Host -}}:{{- .Health.Port }}" - {{- else }} - endpoint: "localhost:13133" + endpoint: "{{ .Extensions.Health.Server.Host -}}:{{- .Extensions.Health.Server.Port }}" + {{- if ne .Extensions.Health.Path "" }} + path: "{{ .Extensions.Health.Path -}}" {{- end }} + {{- if ne .Extensions.Health.TLS nil }} + tls: + ca_cert: "{{ .Extensions.Health.Server.TLS.Ca -}}" + cert_file: "{{ .Extensions.Health.Server.TLS.Cert -}}" + key_file: "{{ .Extensions.Health.Server.TLS.Key -}}" + {{- end }} + {{- end }} +{{- end }} service: {{- if .Log.Path}} diff --git a/internal/config/config.go b/internal/config/config.go index faddd11d3a..f28f1e7ccd 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -354,12 +354,12 @@ func resolveCollector(allowedDirs []string) (*Collector, error) { } var ( - err error - exporters []Exporter - processors []Processor - receivers Receivers - healthCheck ServerConfig - log Log + err error + exporters []Exporter + processors []Processor + receivers Receivers + extensions Extensions + log Log ) err = errors.Join( @@ -367,7 +367,7 @@ func resolveCollector(allowedDirs []string) (*Collector, error) { resolveMapStructure(CollectorExportersKey, &exporters), resolveMapStructure(CollectorProcessorsKey, &processors), resolveMapStructure(CollectorReceiversKey, &receivers), - resolveMapStructure(CollectorHealthKey, &healthCheck), + resolveMapStructure(CollectorExtensionsKey, &extensions), resolveMapStructure(CollectorLogKey, &log), ) if err != nil { @@ -387,7 +387,7 @@ func resolveCollector(allowedDirs []string) (*Collector, error) { Exporters: exporters, Processors: processors, Receivers: receivers, - Health: &healthCheck, + Extensions: extensions, Log: &log, } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 3daec1c292..e4f292cf9a 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -53,7 +53,7 @@ func TestResolveConfig(t *testing.T) { assert.True(t, viperInstance.IsSet(CollectorExportersKey)) assert.True(t, viperInstance.IsSet(CollectorProcessorsKey)) assert.True(t, viperInstance.IsSet(CollectorReceiversKey)) - assert.True(t, viperInstance.IsSet(CollectorHealthKey)) + assert.True(t, viperInstance.IsSet(CollectorExtensionsKey)) actual, err := ResolveConfig() require.NoError(t, err) @@ -70,7 +70,7 @@ func TestResolveConfig(t *testing.T) { assert.NotEmpty(t, actual.Collector.Receivers) assert.NotEmpty(t, actual.Collector.Processors) assert.NotEmpty(t, actual.Collector.Exporters) - assert.NotEmpty(t, actual.Collector.Health) + assert.NotEmpty(t, actual.Collector.Extensions) assert.Equal(t, 10*time.Second, actual.Client.Timeout) @@ -226,7 +226,7 @@ func TestResolveCollector(t *testing.T) { viperInstance.Set(CollectorReceiversKey, test.expected.Receivers) viperInstance.Set(CollectorProcessorsKey, test.expected.Processors) viperInstance.Set(CollectorExportersKey, test.expected.Exporters) - viperInstance.Set(CollectorHealthKey, test.expected.Health) + viperInstance.Set(CollectorExtensionsKey, test.expected.Extensions) viperInstance.Set(CollectorLogKey, test.expected.Log) actual, err := resolveCollector(testDefault.AllowedDirectories) @@ -396,10 +396,14 @@ func getAgentConfig() *Config { }, }, }, - Health: &ServerConfig{ - Host: "localhost", - Port: 1337, - Type: 0, + Extensions: Extensions{ + Health: Health{ + Server: &ServerConfig{ + Host: "localhost", + Port: 1337, + Type: 0, + }, + }, }, Log: &Log{ Level: "INFO", diff --git a/internal/config/flags.go b/internal/config/flags.go index 1f8c4bcfbf..1474fa6537 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -34,7 +34,7 @@ var ( CollectorConfigPathKey = pre(CollectorRootKey) + "config_path" CollectorExportersKey = pre(CollectorRootKey) + "exporters" CollectorProcessorsKey = pre(CollectorRootKey) + "processors" - CollectorHealthKey = pre(CollectorRootKey) + "health" + CollectorExtensionsKey = pre(CollectorRootKey) + "extensions" CollectorReceiversKey = pre(CollectorRootKey) + "receivers" CollectorLogKey = pre(CollectorRootKey) + "log" CollectorLogLevelKey = pre(CollectorLogKey) + "level" diff --git a/internal/config/testdata/nginx-agent.conf b/internal/config/testdata/nginx-agent.conf index 81ed647b37..f67e1b6608 100644 --- a/internal/config/testdata/nginx-agent.conf +++ b/internal/config/testdata/nginx-agent.conf @@ -56,9 +56,10 @@ collector: cert: /path/to/server-cert.pem key: /path/to/server-key.pem ca: /path/to/server-cert.pem - health: - host: "127.0.0.1" - port: 1234 - type: 0 + extensions: + health: + server: + host: "127.0.0.1" + port: 1234 config_dirs: "/etc/nginx:/usr/local/etc/nginx:/var/run/nginx:/usr/share/nginx/modules:/var/log/nginx:invalid/path" diff --git a/internal/config/types.go b/internal/config/types.go index 7c29e24ca0..acc5dd9842 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -86,12 +86,22 @@ type ( } Collector struct { - ConfigPath string `yaml:"-" mapstructure:"config_path"` - Log *Log `yaml:"-" mapstructure:"log"` - Exporters []Exporter `yaml:"-" mapstructure:"exporters"` - Health *ServerConfig `yaml:"-" mapstructure:"health"` - Processors []Processor `yaml:"-" mapstructure:"processors"` - Receivers Receivers `yaml:"-" mapstructure:"receivers"` + ConfigPath string `yaml:"-" mapstructure:"config_path"` + Log *Log `yaml:"-" mapstructure:"log"` + Exporters []Exporter `yaml:"-" mapstructure:"exporters"` + Extensions Extensions `yaml:"-" mapstructure:"extensions"` + Processors []Processor `yaml:"-" mapstructure:"processors"` + Receivers Receivers `yaml:"-" mapstructure:"receivers"` + } + + Extensions struct { + Health Health `yaml:"-" mapstructure:"health"` + } + + Health struct { + Server *ServerConfig `yaml:"-" mapstructure:"server"` + TLS *TLSConfig `yaml:"-" mapstructure:"tls"` + Path string `yaml:"-" mapstructure:"path"` } // OTel Collector Exporter configuration. diff --git a/test/config/agent/nginx-agent-otel-load.conf b/test/config/agent/nginx-agent-otel-load.conf index 546d250cf8..b328dab3c0 100644 --- a/test/config/agent/nginx-agent-otel-load.conf +++ b/test/config/agent/nginx-agent-otel-load.conf @@ -30,7 +30,9 @@ collector: host: "127.0.0.1" port: 5643 type: 0 - health: - host: "127.0.0.1" - port: 1337 - type: 0 + + extensions: + health: + server: + host: "127.0.0.1" + port: 1337 diff --git a/test/config/collector/test-opentelemetry-collector-agent.yaml b/test/config/collector/test-opentelemetry-collector-agent.yaml index 9deb5be556..ae30185a8c 100644 --- a/test/config/collector/test-opentelemetry-collector-agent.yaml +++ b/test/config/collector/test-opentelemetry-collector-agent.yaml @@ -45,7 +45,6 @@ exporters: verbosity: detailed sampling_initial: 5 sampling_thereafter: 200 - extensions: health_check: endpoint: "localhost:1337" diff --git a/test/mock/collector/nginx-agent.conf b/test/mock/collector/nginx-agent.conf index b2e16388d1..a1074b7ecc 100644 --- a/test/mock/collector/nginx-agent.conf +++ b/test/mock/collector/nginx-agent.conf @@ -58,7 +58,8 @@ collector: host: "otel-collector" port: 4317 type: 0 - health: - host: "127.0.0.1" - port: 1337 - type: 0 + extensions: + health: + server: + host: "127.0.0.1" + port: 1337 diff --git a/test/types/config.go b/test/types/config.go index 68f8830cf4..ad93f325ce 100644 --- a/test/types/config.go +++ b/test/types/config.go @@ -83,10 +83,14 @@ func AgentConfig() *config.Config { }, }, }, - Health: &config.ServerConfig{ - Host: "localhost", - Port: randomPort3, - Type: 0, + Extensions: config.Extensions{ + Health: config.Health{ + Server: &config.ServerConfig{ + Host: "localhost", + Port: randomPort3, + Type: 0, + }, + }, }, Log: &config.Log{ Level: "INFO", From 682e27d4bff2b6130e69b82e2125d7a2c67384f8 Mon Sep 17 00:00:00 2001 From: Donal Hurley Date: Thu, 26 Sep 2024 11:15:51 +0100 Subject: [PATCH 14/22] Update processors and exporters config for Otel collector (#839) --- .../generated_component_test.go | 12 +- .../internal/metadata/generated_metrics.go | 54 +++---- .../metadata/generated_metrics_test.go | 18 +-- .../generated_component_test.go | 12 +- .../internal/metadata/generated_metrics.go | 54 +++---- .../metadata/generated_metrics_test.go | 76 ++++----- internal/collector/otelcol.tmpl | 36 +++-- internal/collector/settings_test.go | 15 +- internal/config/config.go | 87 ++++++---- internal/config/config_test.go | 149 +++++++----------- internal/config/defaults.go | 4 + internal/config/flags.go | 68 ++++---- internal/config/testdata/nginx-agent.conf | 27 ++-- internal/config/types.go | 79 ++++------ test/config/agent/nginx-agent-otel-load.conf | 12 +- .../test-opentelemetry-collector-agent.yaml | 8 +- test/mock/collector/nginx-agent.conf | 11 +- test/types/config.go | 30 ++-- 18 files changed, 356 insertions(+), 396 deletions(-) diff --git a/internal/collector/nginxossreceiver/generated_component_test.go b/internal/collector/nginxossreceiver/generated_component_test.go index 60de562050..3007dc92b4 100644 --- a/internal/collector/nginxossreceiver/generated_component_test.go +++ b/internal/collector/nginxossreceiver/generated_component_test.go @@ -46,21 +46,21 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) - for _, tt := range tests { - t.Run(tt.name+"-shutdown", func(t *testing.T) { - c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + for _, test := range tests { + t.Run(test.name+"-shutdown", func(t *testing.T) { + c, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) - t.Run(tt.name+"-lifecycle", func(t *testing.T) { - firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + t.Run(test.name+"-lifecycle", func(t *testing.T) { + firstRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) host := componenttest.NewNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) - secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + secondRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) diff --git a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go index c560fe1bc8..e74642bc94 100644 --- a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go +++ b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go @@ -313,25 +313,17 @@ type MetricsBuilder struct { metricNginxHTTPResponseStatus metricNginxHTTPResponseStatus } -// MetricBuilderOption applies changes to default metrics builder. -type MetricBuilderOption interface { - apply(*MetricsBuilder) -} - -type metricBuilderOptionFunc func(mb *MetricsBuilder) - -func (mbof metricBuilderOptionFunc) apply(mb *MetricsBuilder) { - mbof(mb) -} +// metricBuilderOption applies changes to default metrics builder. +type metricBuilderOption func(*MetricsBuilder) // WithStartTime sets startTime on the metrics builder. -func WithStartTime(startTime pcommon.Timestamp) MetricBuilderOption { - return metricBuilderOptionFunc(func(mb *MetricsBuilder) { +func WithStartTime(startTime pcommon.Timestamp) metricBuilderOption { + return func(mb *MetricsBuilder) { mb.startTime = startTime - }) + } } -func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...MetricBuilderOption) *MetricsBuilder { +func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...metricBuilderOption) *MetricsBuilder { mb := &MetricsBuilder{ config: mbc, startTime: pcommon.NewTimestampFromTime(time.Now()), @@ -344,7 +336,7 @@ func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, opt } for _, op := range options { - op.apply(mb) + op(mb) } return mb } @@ -357,28 +349,20 @@ func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { } // ResourceMetricsOption applies changes to provided resource metrics. -type ResourceMetricsOption interface { - apply(pmetric.ResourceMetrics) -} - -type resourceMetricsOptionFunc func(pmetric.ResourceMetrics) - -func (rmof resourceMetricsOptionFunc) apply(rm pmetric.ResourceMetrics) { - rmof(rm) -} +type ResourceMetricsOption func(pmetric.ResourceMetrics) // WithResource sets the provided resource on the emitted ResourceMetrics. // It's recommended to use ResourceBuilder to create the resource. func WithResource(res pcommon.Resource) ResourceMetricsOption { - return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { + return func(rm pmetric.ResourceMetrics) { res.CopyTo(rm.Resource()) - }) + } } // WithStartTimeOverride overrides start time for all the resource metrics data points. // This option should be only used if different start time has to be set on metrics coming from different resources. func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { - return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { + return func(rm pmetric.ResourceMetrics) { var dps pmetric.NumberDataPointSlice metrics := rm.ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { @@ -392,7 +376,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { dps.At(j).SetStartTimestamp(start) } } - }) + } } // EmitForResource saves all the generated metrics under a new resource and updates the internal state to be ready for @@ -400,7 +384,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { // needs to emit metrics from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceMetricsOption arguments. -func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { +func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { rm := pmetric.NewResourceMetrics() ils := rm.ScopeMetrics().AppendEmpty() ils.Scope().SetName("otelcol/nginxreceiver") @@ -411,8 +395,8 @@ func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { mb.metricNginxHTTPRequests.emit(ils.Metrics()) mb.metricNginxHTTPResponseStatus.emit(ils.Metrics()) - for _, op := range options { - op.apply(rm) + for _, op := range rmo { + op(rm) } if ils.Metrics().Len() > 0 { @@ -424,8 +408,8 @@ func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { // Emit returns all the metrics accumulated by the metrics builder and updates the internal state to be ready for // recording another set of metrics. This function will be responsible for applying all the transformations required to // produce metric representation defined in metadata and user config, e.g. delta or cumulative. -func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics { - mb.EmitForResource(options...) +func (mb *MetricsBuilder) Emit(rmo ...ResourceMetricsOption) pmetric.Metrics { + mb.EmitForResource(rmo...) metrics := mb.metricsBuffer mb.metricsBuffer = pmetric.NewMetrics() return metrics @@ -453,9 +437,9 @@ func (mb *MetricsBuilder) RecordNginxHTTPResponseStatusDataPoint(ts pcommon.Time // Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, // and metrics builder should update its startTime and reset it's internal state accordingly. -func (mb *MetricsBuilder) Reset(options ...MetricBuilderOption) { +func (mb *MetricsBuilder) Reset(options ...metricBuilderOption) { mb.startTime = pcommon.NewTimestampFromTime(time.Now()) for _, op := range options { - op.apply(mb) + op(mb) } } diff --git a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go index 2581a33ef3..261655b70a 100644 --- a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go +++ b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go @@ -43,14 +43,14 @@ func TestMetricsBuilder(t *testing.T) { expectEmpty: true, }, } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { start := pcommon.Timestamp(1_000_000_000) ts := pcommon.Timestamp(1_000_001_000) observedZapCore, observedLogs := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings() settings.Logger = zap.New(observedZapCore) - mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start)) + mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, test.name), settings, WithStartTime(start)) expectedWarnings := 0 @@ -78,7 +78,7 @@ func TestMetricsBuilder(t *testing.T) { res := pcommon.NewResource() metrics := mb.Emit(WithResource(res)) - if tt.expectEmpty { + if test.expectEmpty { assert.Equal(t, 0, metrics.ResourceMetrics().Len()) return } @@ -88,10 +88,10 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, res, rm.Resource()) assert.Equal(t, 1, rm.ScopeMetrics().Len()) ms := rm.ScopeMetrics().At(0).Metrics() - if tt.metricsSet == testDataSetDefault { + if test.metricsSet == testDataSetDefault { assert.Equal(t, defaultMetricsCount, ms.Len()) } - if tt.metricsSet == testDataSetAll { + if test.metricsSet == testDataSetAll { assert.Equal(t, allMetricsCount, ms.Len()) } validatedMetrics := make(map[string]bool) @@ -104,7 +104,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -136,7 +136,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests received from clients.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -150,7 +150,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The number of responses, grouped by status code range.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) diff --git a/internal/collector/nginxplusreceiver/generated_component_test.go b/internal/collector/nginxplusreceiver/generated_component_test.go index 9fbb9944ca..170385ba71 100644 --- a/internal/collector/nginxplusreceiver/generated_component_test.go +++ b/internal/collector/nginxplusreceiver/generated_component_test.go @@ -46,21 +46,21 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) - for _, tt := range tests { - t.Run(tt.name+"-shutdown", func(t *testing.T) { - c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + for _, test := range tests { + t.Run(test.name+"-shutdown", func(t *testing.T) { + c, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) - t.Run(tt.name+"-lifecycle", func(t *testing.T) { - firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + t.Run(test.name+"-lifecycle", func(t *testing.T) { + firstRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) host := componenttest.NewNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) - secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + secondRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) diff --git a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go index 15dbba1752..866fb5a735 100644 --- a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go +++ b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go @@ -3620,25 +3620,17 @@ type MetricsBuilder struct { metricNginxStreamUpstreamZombieCount metricNginxStreamUpstreamZombieCount } -// MetricBuilderOption applies changes to default metrics builder. -type MetricBuilderOption interface { - apply(*MetricsBuilder) -} - -type metricBuilderOptionFunc func(mb *MetricsBuilder) - -func (mbof metricBuilderOptionFunc) apply(mb *MetricsBuilder) { - mbof(mb) -} +// metricBuilderOption applies changes to default metrics builder. +type metricBuilderOption func(*MetricsBuilder) // WithStartTime sets startTime on the metrics builder. -func WithStartTime(startTime pcommon.Timestamp) MetricBuilderOption { - return metricBuilderOptionFunc(func(mb *MetricsBuilder) { +func WithStartTime(startTime pcommon.Timestamp) metricBuilderOption { + return func(mb *MetricsBuilder) { mb.startTime = startTime - }) + } } -func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...MetricBuilderOption) *MetricsBuilder { +func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...metricBuilderOption) *MetricsBuilder { mb := &MetricsBuilder{ config: mbc, startTime: pcommon.NewTimestampFromTime(time.Now()), @@ -3705,7 +3697,7 @@ func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, opt } for _, op := range options { - op.apply(mb) + op(mb) } return mb } @@ -3718,28 +3710,20 @@ func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { } // ResourceMetricsOption applies changes to provided resource metrics. -type ResourceMetricsOption interface { - apply(pmetric.ResourceMetrics) -} - -type resourceMetricsOptionFunc func(pmetric.ResourceMetrics) - -func (rmof resourceMetricsOptionFunc) apply(rm pmetric.ResourceMetrics) { - rmof(rm) -} +type ResourceMetricsOption func(pmetric.ResourceMetrics) // WithResource sets the provided resource on the emitted ResourceMetrics. // It's recommended to use ResourceBuilder to create the resource. func WithResource(res pcommon.Resource) ResourceMetricsOption { - return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { + return func(rm pmetric.ResourceMetrics) { res.CopyTo(rm.Resource()) - }) + } } // WithStartTimeOverride overrides start time for all the resource metrics data points. // This option should be only used if different start time has to be set on metrics coming from different resources. func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { - return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { + return func(rm pmetric.ResourceMetrics) { var dps pmetric.NumberDataPointSlice metrics := rm.ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { @@ -3753,7 +3737,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { dps.At(j).SetStartTimestamp(start) } } - }) + } } // EmitForResource saves all the generated metrics under a new resource and updates the internal state to be ready for @@ -3761,7 +3745,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { // needs to emit metrics from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceMetricsOption arguments. -func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { +func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { rm := pmetric.NewResourceMetrics() ils := rm.ScopeMetrics().AppendEmpty() ils.Scope().SetName("otelcol/nginxplusreceiver") @@ -3826,8 +3810,8 @@ func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { mb.metricNginxStreamUpstreamPeerUnavailable.emit(ils.Metrics()) mb.metricNginxStreamUpstreamZombieCount.emit(ils.Metrics()) - for _, op := range options { - op.apply(rm) + for _, op := range rmo { + op(rm) } if ils.Metrics().Len() > 0 { @@ -3839,8 +3823,8 @@ func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { // Emit returns all the metrics accumulated by the metrics builder and updates the internal state to be ready for // recording another set of metrics. This function will be responsible for applying all the transformations required to // produce metric representation defined in metadata and user config, e.g. delta or cumulative. -func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics { - mb.EmitForResource(options...) +func (mb *MetricsBuilder) Emit(rmo ...ResourceMetricsOption) pmetric.Metrics { + mb.EmitForResource(rmo...) metrics := mb.metricsBuffer mb.metricsBuffer = pmetric.NewMetrics() return metrics @@ -4138,9 +4122,9 @@ func (mb *MetricsBuilder) RecordNginxStreamUpstreamZombieCountDataPoint(ts pcomm // Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, // and metrics builder should update its startTime and reset it's internal state accordingly. -func (mb *MetricsBuilder) Reset(options ...MetricBuilderOption) { +func (mb *MetricsBuilder) Reset(options ...metricBuilderOption) { mb.startTime = pcommon.NewTimestampFromTime(time.Now()) for _, op := range options { - op.apply(mb) + op(mb) } } diff --git a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go index 6d048f6442..8e8f64cbb9 100644 --- a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go +++ b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go @@ -43,14 +43,14 @@ func TestMetricsBuilder(t *testing.T) { expectEmpty: true, }, } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { start := pcommon.Timestamp(1_000_000_000) ts := pcommon.Timestamp(1_000_001_000) observedZapCore, observedLogs := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings() settings.Logger = zap.New(observedZapCore) - mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start)) + mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, test.name), settings, WithStartTime(start)) expectedWarnings := 0 @@ -294,7 +294,7 @@ func TestMetricsBuilder(t *testing.T) { res := pcommon.NewResource() metrics := mb.Emit(WithResource(res)) - if tt.expectEmpty { + if test.expectEmpty { assert.Equal(t, 0, metrics.ResourceMetrics().Len()) return } @@ -304,10 +304,10 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, res, rm.Resource()) assert.Equal(t, 1, rm.ScopeMetrics().Len()) ms := rm.ScopeMetrics().At(0).Metrics() - if tt.metricsSet == testDataSetDefault { + if test.metricsSet == testDataSetDefault { assert.Equal(t, defaultMetricsCount, ms.Len()) } - if tt.metricsSet == testDataSetAll { + if test.metricsSet == testDataSetAll { assert.Equal(t, allMetricsCount, ms.Len()) } validatedMetrics := make(map[string]bool) @@ -320,7 +320,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of bytes read from the cache or proxied server.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -370,7 +370,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of responses read from the cache or proxied server.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -390,7 +390,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of NGINX config reloads.", ms.At(i).Description()) assert.Equal(t, "reloads", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -404,7 +404,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -436,7 +436,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections to an endpoint with a limit_conn directive.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -456,7 +456,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of requests to an endpoint with a limit_req directive.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -476,7 +476,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of HTTP byte IO.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -499,7 +499,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of requests completed without sending a response.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -537,7 +537,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests received from clients.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -569,7 +569,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The number of responses, grouped by status code range.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -592,7 +592,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests received from clients.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -630,7 +630,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of byte IO per HTTP upstream peer.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -752,7 +752,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of health check requests made to a HTTP upstream peer.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -781,7 +781,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests forwarded to the HTTP upstream peer.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -831,7 +831,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of responses obtained from the HTTP upstream peer grouped by status range.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -887,7 +887,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Number of times the server became unavailable for client requests (“unavail”).", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -931,7 +931,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of requests rejected due to the queue overflow.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1036,7 +1036,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) - assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) + assert.Equal(t, float64(1), dp.DoubleValue()) attrVal, ok := dp.Attributes().Get("nginx.zone.name") assert.True(t, ok) assert.EqualValues(t, "nginx.zone.name-val", attrVal.Str()) @@ -1047,7 +1047,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The number of attempts to allocate memory of specified size.", ms.At(i).Description()) assert.Equal(t, "allocations", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1106,7 +1106,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of SSL certificate verification failures.", ms.At(i).Description()) assert.Equal(t, "certificates", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1123,7 +1123,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of SSL handshakes.", ms.At(i).Description()) assert.Equal(t, "handshakes", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1143,7 +1143,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of Stream byte IO.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1163,7 +1163,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections accepted from clients.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1180,7 +1180,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Total number of connections completed without creating a session.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1212,7 +1212,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of completed sessions.", ms.At(i).Description()) assert.Equal(t, "sessions", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1232,7 +1232,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of Stream Upstream Peer byte IO.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1309,7 +1309,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client connections forwarded to this stream upstream peer.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1335,7 +1335,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of stream upstream peers grouped by state.", ms.At(i).Description()) assert.Equal(t, "peers", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1358,7 +1358,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of unsuccessful attempts to communicate with the stream upstream peer.", ms.At(i).Description()) assert.Equal(t, "peers", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1381,7 +1381,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of health check requests made to the stream upstream peer.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1434,7 +1434,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Current state of upstream peers in deployment. If any of the upstream peers in the deployment match the given state then the value will be 1. If no upstream peer is a match then the value will be 0.", ms.At(i).Description()) assert.Equal(t, "deployments", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1487,7 +1487,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "How many times the server became unavailable for client connections (state “unavail”) due to the number of unsuccessful attempts reaching the max_fails threshold.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) diff --git a/internal/collector/otelcol.tmpl b/internal/collector/otelcol.tmpl index cc16d74197..0cc28a215a 100644 --- a/internal/collector/otelcol.tmpl +++ b/internal/collector/otelcol.tmpl @@ -75,17 +75,17 @@ receivers: collection_interval: 10s {{- end }} -{{ if gt (len .Processors) 0 -}} processors: -{{- range .Processors }} - {{ .Type }}: -{{- end }} +{{- if ne .Processors.Batch nil }} + batch: + send_batch_size: {{ .Processors.Batch.SendBatchSize }} + timeout: {{ .Processors.Batch.Timeout }} + send_batch_max_size: {{ .Processors.Batch.SendBatchMaxSize }} {{- end }} exporters: -{{- range .Exporters }} -{{- if eq .Type "otlp" }} - otlp: +{{- range $index, $otlpExporter := .Exporters.OtlpExporters }} + otlp/{{$index}}: endpoint: "{{ .Server.Host -}}:{{- .Server.Port }}" compression: none timeout: 10s @@ -101,17 +101,17 @@ exporters: {{ if gt (len .TLS.Cert) 0 -}}cert_file: "{{- .TLS.Cert -}}"{{- end }} {{ if gt (len .TLS.Key) 0 -}}key_file: "{{- .TLS.Key -}}"{{- end }} {{- end }} -{{- else if eq .Type "prometheus" }} +{{- end }} +{{- if ne .Exporters.PrometheusExporter nil }} prometheus: - endpoint: "{{ .Server.Host -}}:{{- .Server.Port }}" - namespace: "nginx-agent" -{{- else if eq .Type "debug" }} + endpoint: "{{ .Exporters.PrometheusExporter.Server.Host -}}:{{- .Exporters.PrometheusExporter.Server.Port }}" +{{- end }} +{{- if ne .Exporters.Debug nil }} debug: verbosity: detailed sampling_initial: 5 sampling_thereafter: 200 {{- end }} -{{- end }} {{- if ne .Extensions nil }} extensions: @@ -156,8 +156,16 @@ service: - nginxplus/{{- .InstanceID -}} {{- end }} processors: + {{- if ne .Processors.Batch nil }} - batch + {{- end }} exporters: - {{- range .Exporters }} - - {{ .Type }} + {{- range $index, $otlpExporter := .Exporters.OtlpExporters }} + - otlp/{{$index}} + {{- end }} + {{- if ne .Exporters.PrometheusExporter nil }} + - prometheus {{- end }} + {{- if ne .Exporters.Debug nil }} + - debug + {{- end }} diff --git a/internal/collector/settings_test.go b/internal/collector/settings_test.go index 1cf282af63..fb65198941 100644 --- a/internal/collector/settings_test.go +++ b/internal/collector/settings_test.go @@ -53,21 +53,16 @@ func TestTemplateWrite(t *testing.T) { actualConfPath := filepath.Join("/tmp/", "nginx-agent-otelcol-test.yaml") cfg.Collector.ConfigPath = actualConfPath - cfg.Collector.Exporters = append(cfg.Collector.Exporters, config.Exporter{ - Type: "prometheus", + cfg.Collector.Exporters.PrometheusExporter = &config.PrometheusExporter{ Server: &config.ServerConfig{ Host: "localhost", Port: 9876, Type: 0, }, - Auth: nil, // Auth and TLS not supported yet. - TLS: nil, - }, config.Exporter{ - Type: "debug", - Server: nil, // not relevant to the debug exporter - Auth: nil, - TLS: nil, - }) + TLS: nil, + } + + cfg.Collector.Exporters.Debug = &config.DebugExporter{} cfg.Collector.Receivers.HostMetrics = config.HostMetrics{ CollectionInterval: time.Minute, diff --git a/internal/config/config.go b/internal/config/config.go index f28f1e7ccd..4e581d3d27 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -218,27 +218,6 @@ func registerFlags() { "How often the NGINX Agent will check for file changes.", ) - fs.String( - CollectorConfigPathKey, - DefCollectorConfigPath, - "The path to the Opentelemetry Collector configuration file.", - ) - - fs.String( - CollectorLogLevelKey, - DefCollectorLogLevel, - `The desired verbosity level for logging messages from nginx-agent OTel collector. - Available options, in order of severity from highest to lowest, are: - ERROR, WARN, INFO and DEBUG.`, - ) - - fs.String( - CollectorLogPathKey, - DefCollectorLogPath, - `The path to output OTel collector log messages to. - If the default path doesn't exist, log messages are output to stdout/stderr.`, - ) - fs.Int( ClientMaxMessageSizeKey, DefMaxMessageSize, @@ -246,7 +225,7 @@ func registerFlags() { ) fs.Int( - ClientMaxMessageRecieveSizeKey, + ClientMaxMessageReceiveSizeKey, DefMaxMessageRecieveSize, "Updates the client grpc setting MaxRecvMsgSize with the specific value in MB.", ) @@ -257,6 +236,8 @@ func registerFlags() { "Updates the client grpc setting MaxSendMsgSize with the specific value in MB.", ) + registerCollectorFlags(fs) + fs.SetNormalizeFunc(normalizeFunc) fs.VisitAll(func(flag *flag.Flag) { @@ -270,6 +251,47 @@ func registerFlags() { }) } +func registerCollectorFlags(fs *flag.FlagSet) { + fs.String( + CollectorConfigPathKey, + DefCollectorConfigPath, + "The path to the Opentelemetry Collector configuration file.", + ) + + fs.String( + CollectorLogLevelKey, + DefCollectorLogLevel, + `The desired verbosity level for logging messages from nginx-agent OTel collector. + Available options, in order of severity from highest to lowest, are: + ERROR, WARN, INFO and DEBUG.`, + ) + + fs.String( + CollectorLogPathKey, + DefCollectorLogPath, + `The path to output OTel collector log messages to. + If the default path doesn't exist, log messages are output to stdout/stderr.`, + ) + + fs.Uint32( + CollectorBatchProcessorSendBatchSizeKey, + DefCollectorBatchProcessorSendBatchSize, + `Number of metric data points after which a batch will be sent regardless of the timeout.`, + ) + + fs.Uint32( + CollectorBatchProcessorSendBatchMaxSizeKey, + DefCollectorBatchProcessorSendBatchMaxSize, + `The upper limit of the batch size.`, + ) + + fs.Duration( + CollectorBatchProcessorTimeoutKey, + DefCollectorBatchProcessorTimeout, + `Time duration after which a batch will be sent regardless of size.`, + ) +} + func seekFileInPaths(fileName string, directories ...string) (string, error) { for _, directory := range directories { f := filepath.Join(directory, fileName) @@ -340,7 +362,7 @@ func resolveClient() *Client { Time: viperInstance.GetDuration(ClientTimeKey), PermitWithoutStream: viperInstance.GetBool(ClientPermitWithoutStreamKey), MaxMessageSize: viperInstance.GetInt(ClientMaxMessageSizeKey), - MaxMessageRecieveSize: viperInstance.GetInt(ClientMaxMessageRecieveSizeKey), + MaxMessageRecieveSize: viperInstance.GetInt(ClientMaxMessageReceiveSizeKey), MaxMessageSendSize: viperInstance.GetInt(ClientMaxMessageSendSizeKey), } } @@ -355,8 +377,7 @@ func resolveCollector(allowedDirs []string) (*Collector, error) { var ( err error - exporters []Exporter - processors []Processor + exporters Exporters receivers Receivers extensions Extensions log Log @@ -365,7 +386,6 @@ func resolveCollector(allowedDirs []string) (*Collector, error) { err = errors.Join( err, resolveMapStructure(CollectorExportersKey, &exporters), - resolveMapStructure(CollectorProcessorsKey, &processors), resolveMapStructure(CollectorReceiversKey, &receivers), resolveMapStructure(CollectorExtensionsKey, &extensions), resolveMapStructure(CollectorLogKey, &log), @@ -385,7 +405,7 @@ func resolveCollector(allowedDirs []string) (*Collector, error) { col := &Collector{ ConfigPath: viperInstance.GetString(CollectorConfigPathKey), Exporters: exporters, - Processors: processors, + Processors: resolveProcessors(), Receivers: receivers, Extensions: extensions, Log: &log, @@ -404,6 +424,19 @@ func resolveCollector(allowedDirs []string) (*Collector, error) { return col, nil } +func resolveProcessors() Processors { + processors := Processors{} + + if viperInstance.IsSet(CollectorBatchProcessorKey) { + processors.Batch = &Batch{} + processors.Batch.SendBatchSize = viperInstance.GetUint32(CollectorBatchProcessorSendBatchSizeKey) + processors.Batch.SendBatchMaxSize = viperInstance.GetUint32(CollectorBatchProcessorSendBatchMaxSizeKey) + processors.Batch.Timeout = viperInstance.GetDuration(CollectorBatchProcessorTimeoutKey) + } + + return processors +} + // generate self-signed certificate for OTEL receiver // nolint: revive func handleSelfSignedCertificates(col *Collector) error { diff --git a/internal/config/config_test.go b/internal/config/config_test.go index e4f292cf9a..836ebb7ce0 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -25,8 +25,8 @@ const accessLogFormat = `$remote_addr - $remote_user [$time_local] \"$request\" func TestRegisterConfigFile(t *testing.T) { viperInstance = viper.NewWithOptions(viper.KeyDelimiter(KeyDelimiter)) file, err := os.Create("nginx-agent.conf") - defer helpers.RemoveFileWithErrorCheck(t, file.Name()) require.NoError(t, err) + defer helpers.RemoveFileWithErrorCheck(t, file.Name()) currentDirectory, err := os.Getwd() require.NoError(t, err) @@ -68,7 +68,7 @@ func TestResolveConfig(t *testing.T) { require.NotNil(t, actual.Collector) assert.Equal(t, "/etc/nginx-agent/nginx-agent-otelcol.yaml", actual.Collector.ConfigPath) assert.NotEmpty(t, actual.Collector.Receivers) - assert.NotEmpty(t, actual.Collector.Processors) + assert.Equal(t, Processors{Batch: &Batch{}}, actual.Collector.Processors) assert.NotEmpty(t, actual.Collector.Exporters) assert.NotEmpty(t, actual.Collector.Extensions) @@ -172,73 +172,40 @@ func TestResolveClient(t *testing.T) { func TestResolveCollector(t *testing.T) { testDefault := getAgentConfig() - tests := []struct { - expected *Collector - name string - errMsg string - shouldErr bool - }{ - { - name: "Test 1: Happy path", - expected: testDefault.Collector, - }, - { - name: "Test 2: Non allowed path", - expected: &Collector{ - ConfigPath: "/path/to/secret", - }, - shouldErr: true, - errMsg: "collector path /path/to/secret not allowed", - }, - { - name: "Test 3: Unsupported Exporter", - expected: &Collector{ - ConfigPath: testDefault.Collector.ConfigPath, - Exporters: []Exporter{ - { - Type: "not-allowed", - }, - }, - }, - shouldErr: true, - errMsg: "unsupported exporter type: not-allowed", - }, - { - name: "Test 4: Unsupported Processor", - expected: &Collector{ - ConfigPath: testDefault.Collector.ConfigPath, - Exporters: testDefault.Collector.Exporters, - Processors: []Processor{ - { - Type: "custom-processor", - }, - }, - }, - shouldErr: true, - errMsg: "unsupported processor type: custom-processor", - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - viperInstance = viper.NewWithOptions(viper.KeyDelimiter(KeyDelimiter)) - viperInstance.Set(CollectorConfigPathKey, test.expected.ConfigPath) - viperInstance.Set(CollectorReceiversKey, test.expected.Receivers) - viperInstance.Set(CollectorProcessorsKey, test.expected.Processors) - viperInstance.Set(CollectorExportersKey, test.expected.Exporters) - viperInstance.Set(CollectorExtensionsKey, test.expected.Extensions) - viperInstance.Set(CollectorLogKey, test.expected.Log) - - actual, err := resolveCollector(testDefault.AllowedDirectories) - if test.shouldErr { - require.Error(t, err) - assert.Contains(t, err.Error(), test.errMsg) - } else { - require.NoError(t, err) - assert.Equal(t, test.expected, actual) - } - }) - } + t.Run("Test 1: Happy path", func(t *testing.T) { + expected := testDefault.Collector + + viperInstance = viper.NewWithOptions(viper.KeyDelimiter(KeyDelimiter)) + viperInstance.Set(CollectorConfigPathKey, expected.ConfigPath) + viperInstance.Set(CollectorReceiversKey, expected.Receivers) + viperInstance.Set(CollectorBatchProcessorKey, expected.Processors.Batch) + viperInstance.Set(CollectorBatchProcessorSendBatchSizeKey, expected.Processors.Batch.SendBatchSize) + viperInstance.Set(CollectorBatchProcessorSendBatchMaxSizeKey, expected.Processors.Batch.SendBatchMaxSize) + viperInstance.Set(CollectorBatchProcessorTimeoutKey, expected.Processors.Batch.Timeout) + viperInstance.Set(CollectorExportersKey, expected.Exporters) + viperInstance.Set(CollectorExtensionsKey, expected.Extensions) + viperInstance.Set(CollectorLogKey, expected.Log) + + actual, err := resolveCollector(testDefault.AllowedDirectories) + require.NoError(t, err) + assert.Equal(t, expected, actual) + }) + + t.Run("Test 2: Non allowed path", func(t *testing.T) { + expected := &Collector{ + ConfigPath: "/path/to/secret", + } + errMsg := "collector path /path/to/secret not allowed" + + viperInstance = viper.NewWithOptions(viper.KeyDelimiter(KeyDelimiter)) + viperInstance.Set(CollectorConfigPathKey, expected.ConfigPath) + + _, err := resolveCollector(testDefault.AllowedDirectories) + + require.Error(t, err) + assert.Contains(t, err.Error(), errMsg) + }) } func TestCommand(t *testing.T) { @@ -306,10 +273,10 @@ func TestClient(t *testing.T) { // root keys for sections are set appropriately assert.True(t, viperInstance.IsSet(ClientMaxMessageSizeKey)) - assert.False(t, viperInstance.IsSet(ClientMaxMessageRecieveSizeKey)) + assert.False(t, viperInstance.IsSet(ClientMaxMessageReceiveSizeKey)) assert.False(t, viperInstance.IsSet(ClientMaxMessageSendSizeKey)) - viperInstance.Set(ClientMaxMessageRecieveSizeKey, expected.MaxMessageRecieveSize) + viperInstance.Set(ClientMaxMessageReceiveSizeKey, expected.MaxMessageRecieveSize) viperInstance.Set(ClientMaxMessageSendSizeKey, expected.MaxMessageSendSize) result := resolveClient() @@ -337,29 +304,31 @@ func getAgentConfig() *Config { }, Collector: &Collector{ ConfigPath: "/etc/nginx-agent/nginx-agent-otelcol.yaml", - Exporters: []Exporter{ - { - Type: "otlp", - Server: &ServerConfig{ - Host: "127.0.0.1", - Port: 1234, - Type: 0, - }, - Auth: &AuthConfig{ - Token: "super-secret-token", - }, - TLS: &TLSConfig{ - Cert: "/path/to/server-cert.pem", - Key: "/path/to/server-cert.pem", - Ca: "/path/to/server-cert.pem", - SkipVerify: true, - ServerName: "remote-saas-server", + Exporters: Exporters{ + OtlpExporters: []OtlpExporter{ + { + Server: &ServerConfig{ + Host: "127.0.0.1", + Port: 1234, + }, + Auth: &AuthConfig{ + Token: "super-secret-token", + }, + TLS: &TLSConfig{ + Cert: "/path/to/server-cert.pem", + Key: "/path/to/server-cert.pem", + Ca: "/path/to/server-cert.pem", + SkipVerify: true, + ServerName: "remote-saas-server", + }, }, }, }, - Processors: []Processor{ - { - Type: "batch", + Processors: Processors{ + Batch: &Batch{ + SendBatchMaxSize: DefCollectorBatchProcessorSendBatchMaxSize, + SendBatchSize: DefCollectorBatchProcessorSendBatchSize, + Timeout: DefCollectorBatchProcessorTimeout, }, }, Receivers: Receivers{ diff --git a/internal/config/defaults.go b/internal/config/defaults.go index 5a2b6b7f4b..cede509067 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -50,4 +50,8 @@ const ( DefMaxMessageRecieveSize = 4194304 // math.MaxInt32 DefMaxMessageSendSize = math.MaxInt32 + + DefCollectorBatchProcessorSendBatchSize = 8192 + DefCollectorBatchProcessorSendBatchMaxSize = 0 + DefCollectorBatchProcessorTimeout = 200 * time.Millisecond ) diff --git a/internal/config/flags.go b/internal/config/flags.go index 1474fa6537..92a19839b1 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -25,39 +25,41 @@ const ( var ( // child flags saved as vars to enable easier prefixing. - ClientPermitWithoutStreamKey = pre(ClientRootKey) + "permit_without_stream" - ClientTimeKey = pre(ClientRootKey) + "time" - ClientTimeoutKey = pre(ClientRootKey) + "timeout" - ClientMaxMessageSendSizeKey = pre(ClientRootKey) + "max_message_send_size" - ClientMaxMessageRecieveSizeKey = pre(ClientRootKey) + "max_message_receive_size" - ClientMaxMessageSizeKey = pre(ClientRootKey) + "max_message_size" - CollectorConfigPathKey = pre(CollectorRootKey) + "config_path" - CollectorExportersKey = pre(CollectorRootKey) + "exporters" - CollectorProcessorsKey = pre(CollectorRootKey) + "processors" - CollectorExtensionsKey = pre(CollectorRootKey) + "extensions" - CollectorReceiversKey = pre(CollectorRootKey) + "receivers" - CollectorLogKey = pre(CollectorRootKey) + "log" - CollectorLogLevelKey = pre(CollectorLogKey) + "level" - CollectorLogPathKey = pre(CollectorLogKey) + "path" - CommandAuthKey = pre(CommandRootKey) + "auth" - CommandAuthTokenKey = pre(CommandAuthKey) + "token" - CommandServerHostKey = pre(CommandServerKey) + "host" - CommandServerKey = pre(CommandRootKey) + "server" - CommandServerPortKey = pre(CommandServerKey) + "port" - CommandServerTypeKey = pre(CommandServerKey) + "type" - CommandTLSCaKey = pre(CommandTLSKey) + "ca" - CommandTLSCertKey = pre(CommandTLSKey) + "cert" - CommandTLSKey = pre(CommandRootKey) + "tls" - CommandTLSKeyKey = pre(CommandTLSKey) + "key" - CommandTLSServerNameKey = pre(CommandRootKey) + "server_name" - CommandTLSSkipVerifyKey = pre(CommandTLSKey) + "skip_verify" - LogLevelKey = pre(LogLevelRootKey) + "level" - LogPathKey = pre(LogLevelRootKey) + "path" - NginxReloadMonitoringPeriodKey = pre(DataPlaneConfigRootKey, "nginx") + "reload_monitoring_period" - NginxTreatWarningsAsErrorsKey = pre(DataPlaneConfigRootKey, "nginx") + "treat_warnings_as_errors" - NginxExcludeLogsKey = pre(DataPlaneConfigRootKey, "nginx") + "exclude_logs" - OTLPExportURLKey = pre(CollectorRootKey) + "otlp_export_url" - OTLPReceiverURLKey = pre(CollectorRootKey) + "otlp_receiver_url" + ClientPermitWithoutStreamKey = pre(ClientRootKey) + "permit_without_stream" + ClientTimeKey = pre(ClientRootKey) + "time" + ClientTimeoutKey = pre(ClientRootKey) + "timeout" + ClientMaxMessageSendSizeKey = pre(ClientRootKey) + "max_message_send_size" + ClientMaxMessageReceiveSizeKey = pre(ClientRootKey) + "max_message_receive_size" + ClientMaxMessageSizeKey = pre(ClientRootKey) + "max_message_size" + CollectorConfigPathKey = pre(CollectorRootKey) + "config_path" + CollectorExportersKey = pre(CollectorRootKey) + "exporters" + CollectorProcessorsKey = pre(CollectorRootKey) + "processors" + CollectorBatchProcessorKey = pre(CollectorProcessorsKey) + "batch" + CollectorBatchProcessorSendBatchSizeKey = pre(CollectorBatchProcessorKey) + "send_batch_size" + CollectorBatchProcessorSendBatchMaxSizeKey = pre(CollectorBatchProcessorKey) + "send_batch_max_size" + CollectorBatchProcessorTimeoutKey = pre(CollectorBatchProcessorKey) + "timeout" + CollectorExtensionsKey = pre(CollectorRootKey) + "extensions" + CollectorReceiversKey = pre(CollectorRootKey) + "receivers" + CollectorLogKey = pre(CollectorRootKey) + "log" + CollectorLogLevelKey = pre(CollectorLogKey) + "level" + CollectorLogPathKey = pre(CollectorLogKey) + "path" + CommandAuthKey = pre(CommandRootKey) + "auth" + CommandAuthTokenKey = pre(CommandAuthKey) + "token" + CommandServerHostKey = pre(CommandServerKey) + "host" + CommandServerKey = pre(CommandRootKey) + "server" + CommandServerPortKey = pre(CommandServerKey) + "port" + CommandServerTypeKey = pre(CommandServerKey) + "type" + CommandTLSCaKey = pre(CommandTLSKey) + "ca" + CommandTLSCertKey = pre(CommandTLSKey) + "cert" + CommandTLSKey = pre(CommandRootKey) + "tls" + CommandTLSKeyKey = pre(CommandTLSKey) + "key" + CommandTLSServerNameKey = pre(CommandRootKey) + "server_name" + CommandTLSSkipVerifyKey = pre(CommandTLSKey) + "skip_verify" + LogLevelKey = pre(LogLevelRootKey) + "level" + LogPathKey = pre(LogLevelRootKey) + "path" + NginxReloadMonitoringPeriodKey = pre(DataPlaneConfigRootKey, "nginx") + "reload_monitoring_period" + NginxTreatWarningsAsErrorsKey = pre(DataPlaneConfigRootKey, "nginx") + "treat_warnings_as_errors" + NginxExcludeLogsKey = pre(DataPlaneConfigRootKey, "nginx") + "exclude_logs" ) func pre(prefixes ...string) string { diff --git a/internal/config/testdata/nginx-agent.conf b/internal/config/testdata/nginx-agent.conf index f67e1b6608..398d75d9cf 100644 --- a/internal/config/testdata/nginx-agent.conf +++ b/internal/config/testdata/nginx-agent.conf @@ -41,21 +41,20 @@ collector: - file_path: "/var/log/nginx/access-custom.conf" log_format: "$remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" \"$http_x_forwarded_for\"\"$upstream_cache_status\"" processors: - - type: batch + batch: {} exporters: - - type: otlp - server: - host: "127.0.0.1" - port: 5643 - type: 0 - auth: - Token: "secret-saas-token" - tls: - server_name: "test-saas-server" - skip_verify: false - cert: /path/to/server-cert.pem - key: /path/to/server-key.pem - ca: /path/to/server-cert.pem + otlp_exporters: + - server: + host: "127.0.0.1" + port: 5643 + auth: + Token: "secret-saas-token" + tls: + server_name: "test-saas-server" + skip_verify: false + cert: /path/to/server-cert.pem + key: /path/to/server-key.pem + ca: /path/to/server-cert.pem extensions: health: server: diff --git a/internal/config/types.go b/internal/config/types.go index acc5dd9842..cfa80cf453 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -15,18 +15,6 @@ import ( "github.com/google/uuid" ) -var ( - supportedExporters = map[string]struct{}{ - "debug": {}, - "otlp": {}, - "prometheus": {}, - } - - supportedProcessors = map[string]struct{}{ - "batch": {}, - } -) - type ServerType int const ( @@ -86,12 +74,24 @@ type ( } Collector struct { - ConfigPath string `yaml:"-" mapstructure:"config_path"` - Log *Log `yaml:"-" mapstructure:"log"` - Exporters []Exporter `yaml:"-" mapstructure:"exporters"` - Extensions Extensions `yaml:"-" mapstructure:"extensions"` - Processors []Processor `yaml:"-" mapstructure:"processors"` - Receivers Receivers `yaml:"-" mapstructure:"receivers"` + ConfigPath string `yaml:"-" mapstructure:"config_path"` + Log *Log `yaml:"-" mapstructure:"log"` + Exporters Exporters `yaml:"-" mapstructure:"exporters"` + Extensions Extensions `yaml:"-" mapstructure:"extensions"` + Processors Processors `yaml:"-" mapstructure:"processors"` + Receivers Receivers `yaml:"-" mapstructure:"receivers"` + } + + Exporters struct { + Debug *DebugExporter `yaml:"-" mapstructure:"debug"` + PrometheusExporter *PrometheusExporter `yaml:"-" mapstructure:"prometheus_exporter"` + OtlpExporters []OtlpExporter `yaml:"-" mapstructure:"otlp_exporters"` + } + + OtlpExporter struct { + Server *ServerConfig `yaml:"-" mapstructure:"server"` + Auth *AuthConfig `yaml:"-" mapstructure:"auth"` + TLS *TLSConfig `yaml:"-" mapstructure:"tls"` } Extensions struct { @@ -104,18 +104,24 @@ type ( Path string `yaml:"-" mapstructure:"path"` } - // OTel Collector Exporter configuration. - Exporter struct { + DebugExporter struct{} + + PrometheusExporter struct { Server *ServerConfig `yaml:"-" mapstructure:"server"` - Auth *AuthConfig `yaml:"-" mapstructure:"auth"` TLS *TLSConfig `yaml:"-" mapstructure:"tls"` - Type string `yaml:"-" mapstructure:"type"` } - // OTel Collector Processor configuration. - Processor struct { - Type string `yaml:"-" mapstructure:"type"` + // OTel Collector Processors configuration. + Processors struct { + Batch *Batch `yaml:"-" mapstructure:"batch"` } + + Batch struct { + SendBatchSize uint32 `yaml:"-" mapstructure:"send_batch_size"` + SendBatchMaxSize uint32 `yaml:"-" mapstructure:"send_batch_max_size"` + Timeout time.Duration `yaml:"-" mapstructure:"timeout"` + } + // OTel Collector Receiver configuration. Receivers struct { OtlpReceivers []OtlpReceiver `yaml:"-" mapstructure:"otlp_receivers"` @@ -250,29 +256,6 @@ func (col *Collector) Validate(allowedDirectories []string) error { err = errors.Join(err, nginxReceiver.Validate(allowedDirectories)) } - for _, exp := range col.Exporters { - t := strings.ToLower(exp.Type) - - if _, ok := supportedExporters[t]; !ok { - err = errors.Join(err, fmt.Errorf("unsupported exporter type: %s", exp.Type)) - continue - } - - // normalize field too - exp.Type = t - } - - for _, proc := range col.Processors { - t := strings.ToLower(proc.Type) - - if _, ok := supportedProcessors[t]; !ok { - err = errors.Join(err, fmt.Errorf("unsupported processor type: %s", proc.Type)) - continue - } - - proc.Type = t - } - return err } diff --git a/test/config/agent/nginx-agent-otel-load.conf b/test/config/agent/nginx-agent-otel-load.conf index b328dab3c0..0b8ff73178 100644 --- a/test/config/agent/nginx-agent-otel-load.conf +++ b/test/config/agent/nginx-agent-otel-load.conf @@ -23,14 +23,12 @@ collector: port: 4317 type: 0 processors: - - type: batch + batch: {} exporters: - - type: otlp - server: - host: "127.0.0.1" - port: 5643 - type: 0 - + otlp_exporters: + - server: + host: "127.0.0.1" + port: 5643 extensions: health: server: diff --git a/test/config/collector/test-opentelemetry-collector-agent.yaml b/test/config/collector/test-opentelemetry-collector-agent.yaml index ae30185a8c..4e74a9207f 100644 --- a/test/config/collector/test-opentelemetry-collector-agent.yaml +++ b/test/config/collector/test-opentelemetry-collector-agent.yaml @@ -25,9 +25,12 @@ receivers: processors: batch: + send_batch_size: 8192 + timeout: 200ms + send_batch_max_size: 0 exporters: - otlp: + otlp/0: endpoint: "127.0.0.1:1234" compression: none timeout: 10s @@ -40,7 +43,6 @@ exporters: insecure: true prometheus: endpoint: "localhost:9876" - namespace: "nginx-agent" debug: verbosity: detailed sampling_initial: 5 @@ -66,6 +68,6 @@ service: processors: - batch exporters: - - otlp + - otlp/0 - prometheus - debug diff --git a/test/mock/collector/nginx-agent.conf b/test/mock/collector/nginx-agent.conf index a1074b7ecc..d67410115a 100644 --- a/test/mock/collector/nginx-agent.conf +++ b/test/mock/collector/nginx-agent.conf @@ -51,13 +51,12 @@ collector: key: /tmp/key.pem generate_self_signed_cert: true processors: - - type: batch + batch: exporters: - - type: otlp - server: - host: "otel-collector" - port: 4317 - type: 0 + otlp_exporters: + - server: + host: "otel-collector" + port: 4317 extensions: health: server: diff --git a/test/types/config.go b/test/types/config.go index ad93f325ce..15d82c278d 100644 --- a/test/types/config.go +++ b/test/types/config.go @@ -14,9 +14,7 @@ import ( ) const ( - apiPort = 8980 commandPort = 8981 - metricsPort = 8982 clientPermitWithoutStream = true clientTime = 50 * time.Second @@ -51,22 +49,24 @@ func AgentConfig() *config.Config { AllowedDirectories: []string{"/tmp/"}, Collector: &config.Collector{ ConfigPath: "/etc/nginx-agent/nginx-agent-otelcol.yaml", - Exporters: []config.Exporter{ - { - Type: "otlp", - Server: &config.ServerConfig{ - Host: "127.0.0.1", - Port: randomPort1, - Type: 0, - }, - Auth: &config.AuthConfig{ - Token: "super-secret-token", + Exporters: config.Exporters{ + OtlpExporters: []config.OtlpExporter{ + { + Server: &config.ServerConfig{ + Host: "127.0.0.1", + Port: randomPort1, + }, + Auth: &config.AuthConfig{ + Token: "super-secret-token", + }, }, }, }, - Processors: []config.Processor{ - { - Type: "batch", + Processors: config.Processors{ + Batch: &config.Batch{ + SendBatchSize: config.DefCollectorBatchProcessorSendBatchSize, + SendBatchMaxSize: config.DefCollectorBatchProcessorSendBatchMaxSize, + Timeout: config.DefCollectorBatchProcessorTimeout, }, }, Receivers: config.Receivers{ From ead9df833282ba4a6ffef8c4e9ef0880d708c3a5 Mon Sep 17 00:00:00 2001 From: Donal Hurley Date: Thu, 26 Sep 2024 11:41:28 +0100 Subject: [PATCH 15/22] Fix nginx response status metrics (#854) --- .../internal/record/recorder.go | 68 -- .../internal/record/recorder_test.go | 160 ---- .../basic-nginx.http.response.status.yaml | 26 - .../multicode-nginx.http.response.status.yaml | 73 -- .../scraper/accesslog/nginx_log_scraper.go | 78 +- .../scraper/accesslog/testdata/expected.yaml | 33 +- .../accesslog/testdata/test-access.log | 6 + internal/config/defaults.go | 17 +- scripts/testing/load/Dockerfile | 2 +- .../provisioning/dashboards/host-metrics.json | 4 +- .../dashboards/nginx-dashboard.json | 876 ++++++++---------- 11 files changed, 481 insertions(+), 862 deletions(-) delete mode 100644 internal/collector/nginxossreceiver/internal/record/recorder.go delete mode 100644 internal/collector/nginxossreceiver/internal/record/recorder_test.go delete mode 100644 internal/collector/nginxossreceiver/internal/record/testdata/basic-nginx.http.response.status.yaml delete mode 100644 internal/collector/nginxossreceiver/internal/record/testdata/multicode-nginx.http.response.status.yaml diff --git a/internal/collector/nginxossreceiver/internal/record/recorder.go b/internal/collector/nginxossreceiver/internal/record/recorder.go deleted file mode 100644 index ee8bee3103..0000000000 --- a/internal/collector/nginxossreceiver/internal/record/recorder.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) F5, Inc. -// -// This source code is licensed under the Apache License, Version 2.0 license found in the -// LICENSE file in the root directory of this source tree. - -package record - -import ( - "fmt" - "strconv" - "time" - - "github.com/nginx/agent/v3/internal/collector/nginxossreceiver/internal/metadata" - "github.com/nginx/agent/v3/internal/collector/nginxossreceiver/internal/model" - "go.opentelemetry.io/collector/pdata/pcommon" -) - -const ( - // Needed for "magic number" linter. - status100 = 100 - status200 = 200 - status300 = 300 - status400 = 400 - status500 = 500 - - percent = 100 -) - -// Item extracts data from NGINX Access Items and records them using the given MetricsBuilder. -func Item(ai *model.NginxAccessItem, mb *metadata.MetricsBuilder) error { - now := pcommon.NewTimestampFromTime(time.Now()) - - if ai.Status != "" { - codeRange, err := mapCodeRange(ai.Status) - if err != nil { - return fmt.Errorf("parse status range: %w", err) - } - - mb.RecordNginxHTTPResponseStatusDataPoint(now, 1, codeRange) - } - - return nil -} - -func mapCodeRange(statusCode string) (metadata.AttributeNginxStatusRange, error) { - number, err := strconv.Atoi(statusCode) - if err != nil { - return 0, fmt.Errorf("cast status code to int: %w", err) - } - - // We want to "floor" the response code, so we can map it to the correct range (i.e. to 1xx, 2xx, 4xx or 5xx). - codeRange := (number / percent) * percent - - switch codeRange { - case status100: - return metadata.AttributeNginxStatusRange1xx, nil - case status200: - return metadata.AttributeNginxStatusRange2xx, nil - case status300: - return metadata.AttributeNginxStatusRange3xx, nil - case status400: - return metadata.AttributeNginxStatusRange4xx, nil - case status500: - return metadata.AttributeNginxStatusRange5xx, nil - default: - return 0, fmt.Errorf("unknown code range: %d", codeRange) - } -} diff --git a/internal/collector/nginxossreceiver/internal/record/recorder_test.go b/internal/collector/nginxossreceiver/internal/record/recorder_test.go deleted file mode 100644 index a99c7a725a..0000000000 --- a/internal/collector/nginxossreceiver/internal/record/recorder_test.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) F5, Inc. -// -// This source code is licensed under the Apache License, Version 2.0 license found in the -// LICENSE file in the root directory of this source tree. - -package record - -import ( - "errors" - "path/filepath" - "testing" - - "github.com/nginx/agent/v3/internal/collector/nginxossreceiver/internal/metadata" - "github.com/nginx/agent/v3/internal/collector/nginxossreceiver/internal/model" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden" - "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/pmetrictest" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.opentelemetry.io/collector/receiver/receivertest" -) - -const testDataDir = "testdata" - -func TestRecordAccessItem(t *testing.T) { - tests := []struct { - name string - expectedPath string - expErrMsg string - input []*model.NginxAccessItem - shouldErr bool - }{ - { - name: "Test 1: basic nginx.http.response.status case", - input: []*model.NginxAccessItem{ - { - BodyBytesSent: "615", - Status: "200", - RemoteAddress: "127.0.0.1", - HTTPUserAgent: "PostmanRuntime/7.36.1", - Request: "GET / HTTP/1.1", - BytesSent: "853", - RequestLength: "226", - RequestTime: "0.000", - GzipRatio: "-", - ServerProtocol: "HTTP/1.1", - UpstreamConnectTime: "-", - UpstreamHeaderTime: "-", - UpstreamResponseTime: "-", - UpstreamResponseLength: "-", - UpstreamStatus: "", - UpstreamCacheStatus: "", - }, - { - BodyBytesSent: "28", - Status: "200", - RemoteAddress: "127.0.0.1", - HTTPUserAgent: "PostmanRuntime/7.36.1", - Request: "GET /frontend1 HTTP/1.1", - BytesSent: "190", - RequestLength: "235", - RequestTime: "0.004", - GzipRatio: "-", - ServerProtocol: "HTTP/1.1", - UpstreamConnectTime: "0.003", - UpstreamHeaderTime: "0.003", - UpstreamResponseTime: "0.003", - UpstreamResponseLength: "28", - UpstreamStatus: "", - UpstreamCacheStatus: "", - }, - }, - expectedPath: "basic-nginx.http.response.status.yaml", - }, - { - name: "Test 2: all nginx.http.response.status status codes", - input: []*model.NginxAccessItem{ - { // The recorder only parses the status code for this metric, omitting other fields for brevity. - Status: "100", - }, - { - Status: "103", - }, - { - Status: "200", - }, - { - Status: "202", - }, - { - Status: "300", - }, - { - Status: "302", - }, - { - Status: "400", - }, - { - Status: "404", - }, - { - Status: "500", - }, - { - Status: "502", - }, - }, - expectedPath: "multicode-nginx.http.response.status.yaml", - }, - { - name: "Test 3: random string in status code", - input: []*model.NginxAccessItem{ - { - Status: "not-a-status-code", - }, - }, - shouldErr: true, - expErrMsg: "cast status code to int", - }, - { - name: "Test 4: non-existent status code range", - input: []*model.NginxAccessItem{ - { - Status: "700", - }, - }, - shouldErr: true, - expErrMsg: "unknown code range: 700", - }, - } - - mb := metadata.NewMetricsBuilder(metadata.DefaultMetricsBuilderConfig(), receivertest.NewNopSettings()) - - for _, test := range tests { - t.Run(test.name, func(tt *testing.T) { - var err error - for _, item := range test.input { - recordErr := Item(item, mb) - err = errors.Join(err, recordErr) - } - - if test.shouldErr { - require.Error(tt, err) - assert.Contains(tt, err.Error(), test.expErrMsg) - } else { - require.NoError(tt, err) - expectedFile := filepath.Join(testDataDir, test.expectedPath) - expected, readErr := golden.ReadMetrics(expectedFile) - require.NoError(t, readErr) - - actual := mb.Emit() - require.NoError(tt, pmetrictest.CompareMetrics(expected, actual, - pmetrictest.IgnoreStartTimestamp(), - pmetrictest.IgnoreMetricDataPointsOrder(), - pmetrictest.IgnoreTimestamp(), - pmetrictest.IgnoreMetricsOrder())) - } - }) - } -} diff --git a/internal/collector/nginxossreceiver/internal/record/testdata/basic-nginx.http.response.status.yaml b/internal/collector/nginxossreceiver/internal/record/testdata/basic-nginx.http.response.status.yaml deleted file mode 100644 index 994992e871..0000000000 --- a/internal/collector/nginxossreceiver/internal/record/testdata/basic-nginx.http.response.status.yaml +++ /dev/null @@ -1,26 +0,0 @@ -resourceMetrics: - - resource: {} - scopeMetrics: - - metrics: - - description: The number of responses, grouped by status code range. - name: nginx.http.response.status - sum: - aggregationTemporality: 2 # Cumulative - isMonotonic: true - dataPoints: - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "2xx" - timeUnixNano: "1000000" - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "2xx" - timeUnixNano: "1000000" - unit: responses - scope: - name: otelcol/nginxreceiver - version: latest diff --git a/internal/collector/nginxossreceiver/internal/record/testdata/multicode-nginx.http.response.status.yaml b/internal/collector/nginxossreceiver/internal/record/testdata/multicode-nginx.http.response.status.yaml deleted file mode 100644 index 38ee8518dc..0000000000 --- a/internal/collector/nginxossreceiver/internal/record/testdata/multicode-nginx.http.response.status.yaml +++ /dev/null @@ -1,73 +0,0 @@ -resourceMetrics: - - resource: {} - scopeMetrics: - - metrics: - - description: The number of responses, grouped by status code range. - name: nginx.http.response.status - sum: - aggregationTemporality: 2 # Cumulative - isMonotonic: true - dataPoints: - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "1xx" - timeUnixNano: "1000000" - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "1xx" - timeUnixNano: "1000000" - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "2xx" - timeUnixNano: "1000000" - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "2xx" - timeUnixNano: "1000000" - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "3xx" - timeUnixNano: "1000000" - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "3xx" - timeUnixNano: "1000000" - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "4xx" - timeUnixNano: "1000000" - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "4xx" - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "5xx" - timeUnixNano: "1000000" - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "5xx" - timeUnixNano: "1000000" - unit: responses - scope: - name: otelcol/nginxreceiver - version: latest diff --git a/internal/collector/nginxossreceiver/internal/scraper/accesslog/nginx_log_scraper.go b/internal/collector/nginxossreceiver/internal/scraper/accesslog/nginx_log_scraper.go index 93391655d9..1868fa0e68 100644 --- a/internal/collector/nginxossreceiver/internal/scraper/accesslog/nginx_log_scraper.go +++ b/internal/collector/nginxossreceiver/internal/scraper/accesslog/nginx_log_scraper.go @@ -8,7 +8,11 @@ package accesslog import ( "context" "fmt" + "strconv" "sync" + "time" + + "go.opentelemetry.io/collector/pdata/pcommon" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/entry" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/operator" @@ -27,10 +31,11 @@ import ( "github.com/nginx/agent/v3/internal/collector/nginxossreceiver/internal/config" "github.com/nginx/agent/v3/internal/collector/nginxossreceiver/internal/metadata" "github.com/nginx/agent/v3/internal/collector/nginxossreceiver/internal/model" - "github.com/nginx/agent/v3/internal/collector/nginxossreceiver/internal/record" "github.com/nginx/agent/v3/internal/collector/nginxossreceiver/internal/scraper/accesslog/operator/input/file" ) +const Percentage = 100 + type ( NginxLogScraper struct { outChan <-chan []*entry.Entry @@ -43,6 +48,18 @@ type ( entries []*entry.Entry mut sync.Mutex } + + NginxMetrics struct { + responseStatuses ResponseStatuses + } + + ResponseStatuses struct { + oneHundredStatusRange int64 + twoHundredStatusRange int64 + threeHundredStatusRange int64 + fourHundredStatusRange int64 + fiveHundredStatusRange int64 + } ) var _ scraperhelper.Scraper = (*NginxLogScraper)(nil) @@ -55,7 +72,7 @@ func NewScraper( logger.Info("Creating NGINX access log scraper") mb := metadata.NewMetricsBuilder(cfg.MetricsBuilderConfig, settings) - operators := []operator.Config{} + operators := make([]operator.Config, 0) for _, accessLog := range cfg.AccessLogs { logger.Info("Adding access log file operator", zap.String("file_path", accessLog.FilePath)) @@ -106,21 +123,66 @@ func (nls *NginxLogScraper) Start(parentCtx context.Context, _ component.Host) e func (nls *NginxLogScraper) Scrape(_ context.Context) (pmetric.Metrics, error) { nls.mut.Lock() defer nls.mut.Unlock() + + nginxMetrics := NginxMetrics{} + for _, ent := range nls.entries { - nls.logger.Info("Scraping NGINX access log", zap.Any("entity", ent)) + nls.logger.Debug("Scraping NGINX access log", zap.Any("entity", ent)) item, ok := ent.Body.(*model.NginxAccessItem) if !ok { - nls.logger.Info("Failed to cast log entry to *model.NginxAccessItem", zap.Any("entry", ent.Body)) + nls.logger.Warn("Failed to cast log entry to *model.NginxAccessItem", zap.Any("entry", ent.Body)) continue } - err := record.Item(item, nls.mb) - if err != nil { - nls.logger.Info("Recording metric failed", zap.Any("item", item), zap.Error(err)) - continue + if v, err := strconv.Atoi(item.Status); err == nil { + codeRange := fmt.Sprintf("%dxx", v/Percentage) + + switch codeRange { + case "1xx": + nginxMetrics.responseStatuses.oneHundredStatusRange++ + case "2xx": + nginxMetrics.responseStatuses.twoHundredStatusRange++ + case "3xx": + nginxMetrics.responseStatuses.threeHundredStatusRange++ + case "4xx": + nginxMetrics.responseStatuses.fourHundredStatusRange++ + case "5xx": + nginxMetrics.responseStatuses.fiveHundredStatusRange++ + default: + nls.logger.Error("Unknown status range", zap.String("codeRange", codeRange)) + continue + } } } + nls.entries = make([]*entry.Entry, 0) + timeNow := pcommon.NewTimestampFromTime(time.Now()) + + nls.mb.RecordNginxHTTPResponseStatusDataPoint( + timeNow, + nginxMetrics.responseStatuses.oneHundredStatusRange, + metadata.AttributeNginxStatusRange1xx, + ) + nls.mb.RecordNginxHTTPResponseStatusDataPoint( + timeNow, + nginxMetrics.responseStatuses.twoHundredStatusRange, + metadata.AttributeNginxStatusRange2xx, + ) + nls.mb.RecordNginxHTTPResponseStatusDataPoint( + timeNow, + nginxMetrics.responseStatuses.threeHundredStatusRange, + metadata.AttributeNginxStatusRange3xx, + ) + nls.mb.RecordNginxHTTPResponseStatusDataPoint( + timeNow, + nginxMetrics.responseStatuses.fourHundredStatusRange, + metadata.AttributeNginxStatusRange4xx, + ) + nls.mb.RecordNginxHTTPResponseStatusDataPoint( + timeNow, + nginxMetrics.responseStatuses.fiveHundredStatusRange, + metadata.AttributeNginxStatusRange5xx, + ) return nls.mb.Emit(), nil } diff --git a/internal/collector/nginxossreceiver/internal/scraper/accesslog/testdata/expected.yaml b/internal/collector/nginxossreceiver/internal/scraper/accesslog/testdata/expected.yaml index 94a4d72368..edc97f287a 100644 --- a/internal/collector/nginxossreceiver/internal/scraper/accesslog/testdata/expected.yaml +++ b/internal/collector/nginxossreceiver/internal/scraper/accesslog/testdata/expected.yaml @@ -8,48 +8,27 @@ resourceMetrics: aggregationTemporality: 2 # Cumulative isMonotonic: true dataPoints: - - asInt: 1 + - asInt: 0 attributes: - key: nginx.status_range value: - stringValue: 2xx - timeUnixNano: "1000000" - - asInt: 1 + stringValue: "1xx" + - asInt: 4 attributes: - key: nginx.status_range value: stringValue: "2xx" - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "3xx" - - asInt: 1 + - asInt: 2 attributes: - key: nginx.status_range value: stringValue: "3xx" - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "4xx" - - asInt: 1 + - asInt: 6 attributes: - key: nginx.status_range value: stringValue: "4xx" - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "5xx" - - asInt: 1 - attributes: - - key: nginx.status_range - value: - stringValue: "5xx" - - asInt: 1 + - asInt: 3 attributes: - key: nginx.status_range value: diff --git a/internal/collector/nginxossreceiver/internal/scraper/accesslog/testdata/test-access.log b/internal/collector/nginxossreceiver/internal/scraper/accesslog/testdata/test-access.log index a9d8ed8349..9ebbe29294 100644 --- a/internal/collector/nginxossreceiver/internal/scraper/accesslog/testdata/test-access.log +++ b/internal/collector/nginxossreceiver/internal/scraper/accesslog/testdata/test-access.log @@ -1,8 +1,14 @@ 127.0.0.1 - - [16/Apr/2024:09:00:45 +0100] "GET /example HTTP/1.0" 200 28 "-" "PostmanRuntime/7.36.1" "-" "185" "222" "0.000" "-" "HTTP/1.0" "-""-" "-" "-" +127.0.0.1 - - [16/Apr/2024:09:00:45 +0100] "GET /example HTTP/1.0" 200 28 "-" "PostmanRuntime/7.36.1" "-" "185" "222" "0.000" "-" "HTTP/1.0" "-""-" "-" "-" +127.0.0.1 - - [16/Apr/2024:09:00:45 +0100] "GET /example HTTP/1.0" 200 28 "-" "PostmanRuntime/7.36.1" "-" "185" "222" "0.000" "-" "HTTP/1.0" "-""-" "-" "-" 127.0.0.1 - - [16/Apr/2024:09:00:45 +0100] "GET /example HTTP/1.1" 203 28 "-" "PostmanRuntime/7.36.1" "-" "190" "235" "0.004" "-" "HTTP/1.1" "0.003""0.003" "28" "0.003" 127.0.0.1 - - [16/Apr/2024:09:03:02 +0100] "GET /example HTTP/1.0" 300 28 "-" "PostmanRuntime/7.36.1" "-" "185" "222" "0.000" "-" "HTTP/1.0" "-""-" "-" "-" 127.0.0.1 - - [16/Apr/2024:09:03:02 +0100] "GET /example HTTP/1.1" 303 28 "-" "PostmanRuntime/7.36.1" "-" "190" "235" "0.002" "-" "HTTP/1.1" "0.000""0.003" "28" "0.003" 127.0.0.1 - - [16/Apr/2024:10:57:45 +0100] "GET /example HTTP/1.0" 400 28 "-" "PostmanRuntime/7.36.1" "-" "185" "222" "0.000" "-" "HTTP/1.0" "-""-" "-" "-" +127.0.0.1 - - [16/Apr/2024:10:57:45 +0100] "GET /example HTTP/1.0" 400 28 "-" "PostmanRuntime/7.36.1" "-" "185" "222" "0.000" "-" "HTTP/1.0" "-""-" "-" "-" +127.0.0.1 - - [16/Apr/2024:10:57:45 +0100] "GET /example HTTP/1.0" 400 28 "-" "PostmanRuntime/7.36.1" "-" "185" "222" "0.000" "-" "HTTP/1.0" "-""-" "-" "-" +127.0.0.1 - - [16/Apr/2024:10:57:45 +0100] "GET /example HTTP/1.0" 400 28 "-" "PostmanRuntime/7.36.1" "-" "185" "222" "0.000" "-" "HTTP/1.0" "-""-" "-" "-" +127.0.0.1 - - [16/Apr/2024:10:57:45 +0100] "GET /example HTTP/1.0" 400 28 "-" "PostmanRuntime/7.36.1" "-" "185" "222" "0.000" "-" "HTTP/1.0" "-""-" "-" "-" 127.0.0.1 - - [16/Apr/2024:10:57:45 +0100] "GET /example HTTP/1.1" 401 28 "-" "PostmanRuntime/7.36.1" "-" "190" "235" "0.406" "-" "HTTP/1.1" "0.297""0.407" "28" "0.407" 127.0.0.1 - - [16/Apr/2024:10:57:55 +0100] "GET / HTTP/1.1" 500 615 "-" "PostmanRuntime/7.36.1" "-" "853" "226" "0.000" "-" "HTTP/1.1" "-""-" "-" "-" 127.0.0.1 - - [16/Apr/2024:10:58:25 +0100] "GET / HTTP/1.1" 502 615 "-" "PostmanRuntime/7.36.1" "-" "853" "226" "0.000" "-" "HTTP/1.1" "-""-" "-" "-" diff --git a/internal/config/defaults.go b/internal/config/defaults.go index cede509067..57d7903eb5 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -14,15 +14,14 @@ const ( DefNginxReloadMonitoringPeriod = 10 * time.Second DefTreatErrorsAsWarnings = true - DefCollectorConfigPath = "/var/run/nginx-agent/opentelemetry-collector-agent.yaml" - DefCollectorTLSGenSelfSignedCert = false - DefCollectorLogLevel = "INFO" - DefCollectorLogPath = "/var/log/nginx-agent/opentelemetry-collector-agent.log" - DefConfigDirectories = "/etc/nginx:/usr/local/etc/nginx:/usr/share/nginx/modules" - DefCollectorTLSCertPath = "/var/lib/nginx-agent/cert.pem" - DefCollectorTLSKeyPath = "/var/lib/nginx-agent/key.pem" - DefCollectorTLSCAPath = "/var/lib/nginx-agent/ca.pem" - DefCollectorTLSSANNames = "127.0.0.1,::1,localhost" + DefCollectorConfigPath = "/etc/nginx-agent/opentelemetry-collector-agent.yaml" + DefCollectorLogLevel = "INFO" + DefCollectorLogPath = "/var/log/nginx-agent/opentelemetry-collector-agent.log" + DefConfigDirectories = "/etc/nginx:/usr/local/etc/nginx:/usr/share/nginx/modules" + DefCollectorTLSCertPath = "/var/lib/nginx-agent/cert.pem" + DefCollectorTLSKeyPath = "/var/lib/nginx-agent/key.pem" + DefCollectorTLSCAPath = "/var/lib/nginx-agent/ca.pem" + DefCollectorTLSSANNames = "127.0.0.1,::1,localhost" DefCommandServerHostKey = "" DefCommandServerPortKey = 0 diff --git a/scripts/testing/load/Dockerfile b/scripts/testing/load/Dockerfile index c4fd26a277..af065a08fe 100644 --- a/scripts/testing/load/Dockerfile +++ b/scripts/testing/load/Dockerfile @@ -80,7 +80,7 @@ ENV PATH="/usr/local/go/bin:${PATH}" ENV PATH=$PATH:/usr/local/go/bin RUN mv /agent/test/config/agent/nginx-agent-otel-load.conf /agent/test/load/nginx-agent.conf -RUN mkdir /var/run/nginx-agent/ /var/log/nginx-agent/ +RUN mkdir /var/run/nginx-agent/ /var/log/nginx-agent/ /etc/nginx-agent/ WORKDIR /agent/ CMD make install-tools diff --git a/test/mock/collector/grafana/provisioning/dashboards/host-metrics.json b/test/mock/collector/grafana/provisioning/dashboards/host-metrics.json index 7ba158a2cc..2fd9cee461 100644 --- a/test/mock/collector/grafana/provisioning/dashboards/host-metrics.json +++ b/test/mock/collector/grafana/provisioning/dashboards/host-metrics.json @@ -209,7 +209,7 @@ "fullMetaSearch": false, "includeNullMetadata": true, "instant": false, - "legendFormat": "{{nginx_conn_outcome}}", + "legendFormat": "__auto", "range": true, "refId": "A", "useBackend": false @@ -308,7 +308,7 @@ "fullMetaSearch": false, "includeNullMetadata": true, "instant": false, - "legendFormat": "Requests", + "legendFormat": "__auto", "range": true, "refId": "A", "useBackend": false diff --git a/test/mock/collector/grafana/provisioning/dashboards/nginx-dashboard.json b/test/mock/collector/grafana/provisioning/dashboards/nginx-dashboard.json index a9224370a8..1744513236 100644 --- a/test/mock/collector/grafana/provisioning/dashboards/nginx-dashboard.json +++ b/test/mock/collector/grafana/provisioning/dashboards/nginx-dashboard.json @@ -1,540 +1,440 @@ { "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": { - "type": "grafana", - "uid": "-- Grafana --" - }, - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] }, "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, "links": [], "panels": [ - { - "datasource": { - "type": "prometheus", - "uid": "otel-prometheus-scraper" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 0 - }, - "id": 5, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { + { "datasource": { - "type": "prometheus", - "uid": "otel-prometheus-scraper" + "type": "prometheus", + "uid": "otel-prometheus-scraper" }, - "disableTextWrap": false, - "editorMode": "builder", - "expr": "nginx_http_response_status", - "fullMetaSearch": false, - "includeNullMetadata": true, - "instant": false, - "legendFormat": "__auto", - "range": true, - "refId": "A", - "useBackend": false - } - ], - "title": "HTTP Response Status", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "otel-prometheus-scraper" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ { - "color": "red", - "value": 80 + "datasource": { + "type": "prometheus", + "uid": "otel-prometheus-scraper" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "nginx_http_conn_count", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{nginx_conn_outcome}}", + "range": true, + "refId": "A", + "useBackend": false } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 0 + ], + "title": "HTTP Connections Count", + "type": "timeseries" }, - "id": 4, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "maxHeight": 600, - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { + { "datasource": { - "type": "prometheus", - "uid": "otel-prometheus-scraper" + "type": "prometheus", + "uid": "otel-prometheus-scraper" }, - "disableTextWrap": false, - "editorMode": "builder", - "expr": "nginx_connections_current", - "fullMetaSearch": false, - "includeNullMetadata": true, - "instant": false, - "legendFormat": "__auto", - "range": true, - "refId": "A", - "useBackend": false - } - ], - "title": "NGINX Connections Current", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "otel-prometheus-scraper" - }, - "description": "", - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ { - "color": "red", - "value": 80 + "datasource": { + "type": "prometheus", + "uid": "otel-prometheus-scraper" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "nginx_http_conn", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{nginx_conn_outcome}}", + "range": true, + "refId": "A", + "useBackend": false } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 8 + ], + "title": "HTTP Connections", + "type": "timeseries" }, - "id": 1, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "maxHeight": 600, - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { + { "datasource": { - "type": "prometheus", - "uid": "otel-prometheus-scraper" + "type": "prometheus", + "uid": "otel-prometheus-scraper" }, - "disableTextWrap": false, - "editorMode": "builder", - "expr": "nginx_http_requests", - "fullMetaSearch": false, - "includeNullMetadata": true, - "instant": false, - "legendFormat": "__auto", - "range": true, - "refId": "A", - "useBackend": false - } - ], - "title": "NGINX Requests Total", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "otel-prometheus-scraper" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, + "tooltip": { + "maxHeight": 600, + "mode": "single", + "sort": "none" + } + }, + "targets": [ { - "color": "red", - "value": 80 + "datasource": { + "type": "prometheus", + "uid": "otel-prometheus-scraper" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "nginx_http_requests", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 8 - }, - "id": 3, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "maxHeight": 600, - "mode": "single", - "sort": "none" - } + ], + "title": "Total HTTP Requests", + "type": "timeseries" }, - "targets": [ - { + { "datasource": { - "type": "prometheus", - "uid": "otel-prometheus-scraper" + "type": "prometheus", + "uid": "otel-prometheus-scraper" }, - "disableTextWrap": false, - "editorMode": "builder", - "expr": "nginx_http_conn_count", - "fullMetaSearch": false, - "includeNullMetadata": true, - "instant": false, - "legendFormat": "__auto", - "range": true, - "refId": "A", - "useBackend": false - } - ], - "title": "NGINX Connections Current Count", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "otel-prometheus-scraper" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true }, - { - "color": "red", - "value": 80 + "tooltip": { + "mode": "single", + "sort": "none" } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 16 - }, - "id": 2, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "maxHeight": 600, - "mode": "single", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "otel-prometheus-scraper" }, - "disableTextWrap": false, - "editorMode": "builder", - "expr": "nginx_http_conn", - "fullMetaSearch": false, - "includeNullMetadata": true, - "instant": false, - "legendFormat": "__auto", - "range": true, - "refId": "A", - "useBackend": false - } - ], - "title": "NGINX Connection Totals", - "type": "timeseries" - } + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "otel-prometheus-scraper" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "nginx_http_response_status", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "HTTP Response Status", + "type": "timeseries" + } ], "refresh": "5s", "schemaVersion": 39, "tags": [], "templating": { - "list": [] + "list": [] }, "time": { - "from": "now-5m", - "to": "now" + "from": "now-5m", + "to": "now" }, "timepicker": {}, "timezone": "browser", "title": "NGINX OSS", "uid": "bdogpq9khs9hcb", - "version": 1, + "version": 6, "weekStart": "" - } +} From 20f0c1cb4ad468d6f3de4d1e681e806451f43590 Mon Sep 17 00:00:00 2001 From: aphralG <108004222+aphralG@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:23:39 +0100 Subject: [PATCH 16/22] Added Integration tests to check install, uninstall of agent and version command (#859) * add install uninstall test --- Makefile | 2 +- .../generated_component_test.go | 12 +- .../internal/metadata/generated_metrics.go | 54 ++-- .../metadata/generated_metrics_test.go | 18 +- .../generated_component_test.go | 12 +- .../internal/metadata/generated_metrics.go | 54 ++-- .../metadata/generated_metrics_test.go | 76 +++--- test/docker/agentless-entrypoint.sh | 25 ++ test/helpers/test_containers_utils.go | 80 +++++- test/integration/install_uninstall_test.go | 252 ++++++++++++++++++ 10 files changed, 477 insertions(+), 108 deletions(-) create mode 100644 test/docker/agentless-entrypoint.sh create mode 100644 test/integration/install_uninstall_test.go diff --git a/Makefile b/Makefile index 091981fda5..8307a677af 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ official-image-integration-test: $(SELECTED_PACKAGE) build-mock-management-plane TEST_ENV="Container" CONTAINER_OS_TYPE=$(CONTAINER_OS_TYPE) CONTAINER_NGINX_IMAGE_REGISTRY=${CONTAINER_NGINX_IMAGE_REGISTRY} BUILD_TARGET="install" \ PACKAGES_REPO=$(OSS_PACKAGES_REPO) TAG=${TAG} PACKAGE_NAME=$(PACKAGE_NAME) BASE_IMAGE=$(BASE_IMAGE) DOCKERFILE_PATH=$(OFFICIAL_IMAGE_DOCKERFILE_PATH) \ OS_VERSION=$(OS_VERSION) OS_RELEASE=$(OS_RELEASE) IMAGE_PATH=$(IMAGE_PATH) \ - go test -v ./test/integration + go test -v ./test/integration/grpc_management_plane_api_test.go performance-test: @mkdir -p $(TEST_BUILD_DIR) diff --git a/internal/collector/nginxossreceiver/generated_component_test.go b/internal/collector/nginxossreceiver/generated_component_test.go index 3007dc92b4..60de562050 100644 --- a/internal/collector/nginxossreceiver/generated_component_test.go +++ b/internal/collector/nginxossreceiver/generated_component_test.go @@ -46,21 +46,21 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) - for _, test := range tests { - t.Run(test.name+"-shutdown", func(t *testing.T) { - c, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + for _, tt := range tests { + t.Run(tt.name+"-shutdown", func(t *testing.T) { + c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) - t.Run(test.name+"-lifecycle", func(t *testing.T) { - firstRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + t.Run(tt.name+"-lifecycle", func(t *testing.T) { + firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) host := componenttest.NewNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) - secondRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) diff --git a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go index e74642bc94..c560fe1bc8 100644 --- a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go +++ b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go @@ -313,17 +313,25 @@ type MetricsBuilder struct { metricNginxHTTPResponseStatus metricNginxHTTPResponseStatus } -// metricBuilderOption applies changes to default metrics builder. -type metricBuilderOption func(*MetricsBuilder) +// MetricBuilderOption applies changes to default metrics builder. +type MetricBuilderOption interface { + apply(*MetricsBuilder) +} + +type metricBuilderOptionFunc func(mb *MetricsBuilder) + +func (mbof metricBuilderOptionFunc) apply(mb *MetricsBuilder) { + mbof(mb) +} // WithStartTime sets startTime on the metrics builder. -func WithStartTime(startTime pcommon.Timestamp) metricBuilderOption { - return func(mb *MetricsBuilder) { +func WithStartTime(startTime pcommon.Timestamp) MetricBuilderOption { + return metricBuilderOptionFunc(func(mb *MetricsBuilder) { mb.startTime = startTime - } + }) } -func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...metricBuilderOption) *MetricsBuilder { +func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...MetricBuilderOption) *MetricsBuilder { mb := &MetricsBuilder{ config: mbc, startTime: pcommon.NewTimestampFromTime(time.Now()), @@ -336,7 +344,7 @@ func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, opt } for _, op := range options { - op(mb) + op.apply(mb) } return mb } @@ -349,20 +357,28 @@ func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { } // ResourceMetricsOption applies changes to provided resource metrics. -type ResourceMetricsOption func(pmetric.ResourceMetrics) +type ResourceMetricsOption interface { + apply(pmetric.ResourceMetrics) +} + +type resourceMetricsOptionFunc func(pmetric.ResourceMetrics) + +func (rmof resourceMetricsOptionFunc) apply(rm pmetric.ResourceMetrics) { + rmof(rm) +} // WithResource sets the provided resource on the emitted ResourceMetrics. // It's recommended to use ResourceBuilder to create the resource. func WithResource(res pcommon.Resource) ResourceMetricsOption { - return func(rm pmetric.ResourceMetrics) { + return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { res.CopyTo(rm.Resource()) - } + }) } // WithStartTimeOverride overrides start time for all the resource metrics data points. // This option should be only used if different start time has to be set on metrics coming from different resources. func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { - return func(rm pmetric.ResourceMetrics) { + return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { var dps pmetric.NumberDataPointSlice metrics := rm.ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { @@ -376,7 +392,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { dps.At(j).SetStartTimestamp(start) } } - } + }) } // EmitForResource saves all the generated metrics under a new resource and updates the internal state to be ready for @@ -384,7 +400,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { // needs to emit metrics from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceMetricsOption arguments. -func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { +func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { rm := pmetric.NewResourceMetrics() ils := rm.ScopeMetrics().AppendEmpty() ils.Scope().SetName("otelcol/nginxreceiver") @@ -395,8 +411,8 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { mb.metricNginxHTTPRequests.emit(ils.Metrics()) mb.metricNginxHTTPResponseStatus.emit(ils.Metrics()) - for _, op := range rmo { - op(rm) + for _, op := range options { + op.apply(rm) } if ils.Metrics().Len() > 0 { @@ -408,8 +424,8 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { // Emit returns all the metrics accumulated by the metrics builder and updates the internal state to be ready for // recording another set of metrics. This function will be responsible for applying all the transformations required to // produce metric representation defined in metadata and user config, e.g. delta or cumulative. -func (mb *MetricsBuilder) Emit(rmo ...ResourceMetricsOption) pmetric.Metrics { - mb.EmitForResource(rmo...) +func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics { + mb.EmitForResource(options...) metrics := mb.metricsBuffer mb.metricsBuffer = pmetric.NewMetrics() return metrics @@ -437,9 +453,9 @@ func (mb *MetricsBuilder) RecordNginxHTTPResponseStatusDataPoint(ts pcommon.Time // Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, // and metrics builder should update its startTime and reset it's internal state accordingly. -func (mb *MetricsBuilder) Reset(options ...metricBuilderOption) { +func (mb *MetricsBuilder) Reset(options ...MetricBuilderOption) { mb.startTime = pcommon.NewTimestampFromTime(time.Now()) for _, op := range options { - op(mb) + op.apply(mb) } } diff --git a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go index 261655b70a..2581a33ef3 100644 --- a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go +++ b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go @@ -43,14 +43,14 @@ func TestMetricsBuilder(t *testing.T) { expectEmpty: true, }, } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { start := pcommon.Timestamp(1_000_000_000) ts := pcommon.Timestamp(1_000_001_000) observedZapCore, observedLogs := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings() settings.Logger = zap.New(observedZapCore) - mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, test.name), settings, WithStartTime(start)) + mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start)) expectedWarnings := 0 @@ -78,7 +78,7 @@ func TestMetricsBuilder(t *testing.T) { res := pcommon.NewResource() metrics := mb.Emit(WithResource(res)) - if test.expectEmpty { + if tt.expectEmpty { assert.Equal(t, 0, metrics.ResourceMetrics().Len()) return } @@ -88,10 +88,10 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, res, rm.Resource()) assert.Equal(t, 1, rm.ScopeMetrics().Len()) ms := rm.ScopeMetrics().At(0).Metrics() - if test.metricsSet == testDataSetDefault { + if tt.metricsSet == testDataSetDefault { assert.Equal(t, defaultMetricsCount, ms.Len()) } - if test.metricsSet == testDataSetAll { + if tt.metricsSet == testDataSetAll { assert.Equal(t, allMetricsCount, ms.Len()) } validatedMetrics := make(map[string]bool) @@ -104,7 +104,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -136,7 +136,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests received from clients.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -150,7 +150,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The number of responses, grouped by status code range.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) diff --git a/internal/collector/nginxplusreceiver/generated_component_test.go b/internal/collector/nginxplusreceiver/generated_component_test.go index 170385ba71..9fbb9944ca 100644 --- a/internal/collector/nginxplusreceiver/generated_component_test.go +++ b/internal/collector/nginxplusreceiver/generated_component_test.go @@ -46,21 +46,21 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) - for _, test := range tests { - t.Run(test.name+"-shutdown", func(t *testing.T) { - c, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + for _, tt := range tests { + t.Run(tt.name+"-shutdown", func(t *testing.T) { + c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) - t.Run(test.name+"-lifecycle", func(t *testing.T) { - firstRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + t.Run(tt.name+"-lifecycle", func(t *testing.T) { + firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) host := componenttest.NewNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) - secondRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) diff --git a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go index 866fb5a735..15dbba1752 100644 --- a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go +++ b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go @@ -3620,17 +3620,25 @@ type MetricsBuilder struct { metricNginxStreamUpstreamZombieCount metricNginxStreamUpstreamZombieCount } -// metricBuilderOption applies changes to default metrics builder. -type metricBuilderOption func(*MetricsBuilder) +// MetricBuilderOption applies changes to default metrics builder. +type MetricBuilderOption interface { + apply(*MetricsBuilder) +} + +type metricBuilderOptionFunc func(mb *MetricsBuilder) + +func (mbof metricBuilderOptionFunc) apply(mb *MetricsBuilder) { + mbof(mb) +} // WithStartTime sets startTime on the metrics builder. -func WithStartTime(startTime pcommon.Timestamp) metricBuilderOption { - return func(mb *MetricsBuilder) { +func WithStartTime(startTime pcommon.Timestamp) MetricBuilderOption { + return metricBuilderOptionFunc(func(mb *MetricsBuilder) { mb.startTime = startTime - } + }) } -func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...metricBuilderOption) *MetricsBuilder { +func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...MetricBuilderOption) *MetricsBuilder { mb := &MetricsBuilder{ config: mbc, startTime: pcommon.NewTimestampFromTime(time.Now()), @@ -3697,7 +3705,7 @@ func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, opt } for _, op := range options { - op(mb) + op.apply(mb) } return mb } @@ -3710,20 +3718,28 @@ func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { } // ResourceMetricsOption applies changes to provided resource metrics. -type ResourceMetricsOption func(pmetric.ResourceMetrics) +type ResourceMetricsOption interface { + apply(pmetric.ResourceMetrics) +} + +type resourceMetricsOptionFunc func(pmetric.ResourceMetrics) + +func (rmof resourceMetricsOptionFunc) apply(rm pmetric.ResourceMetrics) { + rmof(rm) +} // WithResource sets the provided resource on the emitted ResourceMetrics. // It's recommended to use ResourceBuilder to create the resource. func WithResource(res pcommon.Resource) ResourceMetricsOption { - return func(rm pmetric.ResourceMetrics) { + return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { res.CopyTo(rm.Resource()) - } + }) } // WithStartTimeOverride overrides start time for all the resource metrics data points. // This option should be only used if different start time has to be set on metrics coming from different resources. func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { - return func(rm pmetric.ResourceMetrics) { + return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { var dps pmetric.NumberDataPointSlice metrics := rm.ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { @@ -3737,7 +3753,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { dps.At(j).SetStartTimestamp(start) } } - } + }) } // EmitForResource saves all the generated metrics under a new resource and updates the internal state to be ready for @@ -3745,7 +3761,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { // needs to emit metrics from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceMetricsOption arguments. -func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { +func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { rm := pmetric.NewResourceMetrics() ils := rm.ScopeMetrics().AppendEmpty() ils.Scope().SetName("otelcol/nginxplusreceiver") @@ -3810,8 +3826,8 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { mb.metricNginxStreamUpstreamPeerUnavailable.emit(ils.Metrics()) mb.metricNginxStreamUpstreamZombieCount.emit(ils.Metrics()) - for _, op := range rmo { - op(rm) + for _, op := range options { + op.apply(rm) } if ils.Metrics().Len() > 0 { @@ -3823,8 +3839,8 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { // Emit returns all the metrics accumulated by the metrics builder and updates the internal state to be ready for // recording another set of metrics. This function will be responsible for applying all the transformations required to // produce metric representation defined in metadata and user config, e.g. delta or cumulative. -func (mb *MetricsBuilder) Emit(rmo ...ResourceMetricsOption) pmetric.Metrics { - mb.EmitForResource(rmo...) +func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics { + mb.EmitForResource(options...) metrics := mb.metricsBuffer mb.metricsBuffer = pmetric.NewMetrics() return metrics @@ -4122,9 +4138,9 @@ func (mb *MetricsBuilder) RecordNginxStreamUpstreamZombieCountDataPoint(ts pcomm // Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, // and metrics builder should update its startTime and reset it's internal state accordingly. -func (mb *MetricsBuilder) Reset(options ...metricBuilderOption) { +func (mb *MetricsBuilder) Reset(options ...MetricBuilderOption) { mb.startTime = pcommon.NewTimestampFromTime(time.Now()) for _, op := range options { - op(mb) + op.apply(mb) } } diff --git a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go index 8e8f64cbb9..6d048f6442 100644 --- a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go +++ b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go @@ -43,14 +43,14 @@ func TestMetricsBuilder(t *testing.T) { expectEmpty: true, }, } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { start := pcommon.Timestamp(1_000_000_000) ts := pcommon.Timestamp(1_000_001_000) observedZapCore, observedLogs := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings() settings.Logger = zap.New(observedZapCore) - mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, test.name), settings, WithStartTime(start)) + mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start)) expectedWarnings := 0 @@ -294,7 +294,7 @@ func TestMetricsBuilder(t *testing.T) { res := pcommon.NewResource() metrics := mb.Emit(WithResource(res)) - if test.expectEmpty { + if tt.expectEmpty { assert.Equal(t, 0, metrics.ResourceMetrics().Len()) return } @@ -304,10 +304,10 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, res, rm.Resource()) assert.Equal(t, 1, rm.ScopeMetrics().Len()) ms := rm.ScopeMetrics().At(0).Metrics() - if test.metricsSet == testDataSetDefault { + if tt.metricsSet == testDataSetDefault { assert.Equal(t, defaultMetricsCount, ms.Len()) } - if test.metricsSet == testDataSetAll { + if tt.metricsSet == testDataSetAll { assert.Equal(t, allMetricsCount, ms.Len()) } validatedMetrics := make(map[string]bool) @@ -320,7 +320,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of bytes read from the cache or proxied server.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -370,7 +370,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of responses read from the cache or proxied server.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -390,7 +390,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of NGINX config reloads.", ms.At(i).Description()) assert.Equal(t, "reloads", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -404,7 +404,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -436,7 +436,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections to an endpoint with a limit_conn directive.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -456,7 +456,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of requests to an endpoint with a limit_req directive.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -476,7 +476,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of HTTP byte IO.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -499,7 +499,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of requests completed without sending a response.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -537,7 +537,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests received from clients.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -569,7 +569,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The number of responses, grouped by status code range.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -592,7 +592,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests received from clients.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -630,7 +630,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of byte IO per HTTP upstream peer.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -752,7 +752,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of health check requests made to a HTTP upstream peer.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -781,7 +781,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests forwarded to the HTTP upstream peer.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -831,7 +831,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of responses obtained from the HTTP upstream peer grouped by status range.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -887,7 +887,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Number of times the server became unavailable for client requests (“unavail”).", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -931,7 +931,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of requests rejected due to the queue overflow.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1036,7 +1036,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) - assert.Equal(t, float64(1), dp.DoubleValue()) + assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) attrVal, ok := dp.Attributes().Get("nginx.zone.name") assert.True(t, ok) assert.EqualValues(t, "nginx.zone.name-val", attrVal.Str()) @@ -1047,7 +1047,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The number of attempts to allocate memory of specified size.", ms.At(i).Description()) assert.Equal(t, "allocations", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1106,7 +1106,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of SSL certificate verification failures.", ms.At(i).Description()) assert.Equal(t, "certificates", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1123,7 +1123,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of SSL handshakes.", ms.At(i).Description()) assert.Equal(t, "handshakes", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1143,7 +1143,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of Stream byte IO.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1163,7 +1163,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections accepted from clients.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1180,7 +1180,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Total number of connections completed without creating a session.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1212,7 +1212,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of completed sessions.", ms.At(i).Description()) assert.Equal(t, "sessions", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1232,7 +1232,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of Stream Upstream Peer byte IO.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1309,7 +1309,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client connections forwarded to this stream upstream peer.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1335,7 +1335,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of stream upstream peers grouped by state.", ms.At(i).Description()) assert.Equal(t, "peers", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1358,7 +1358,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of unsuccessful attempts to communicate with the stream upstream peer.", ms.At(i).Description()) assert.Equal(t, "peers", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1381,7 +1381,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of health check requests made to the stream upstream peer.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1434,7 +1434,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Current state of upstream peers in deployment. If any of the upstream peers in the deployment match the given state then the value will be 1. If no upstream peer is a match then the value will be 0.", ms.At(i).Description()) assert.Equal(t, "deployments", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1487,7 +1487,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "How many times the server became unavailable for client connections (state “unavail”) due to the number of unsuccessful attempts reaching the max_fails threshold.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) + assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) diff --git a/test/docker/agentless-entrypoint.sh b/test/docker/agentless-entrypoint.sh new file mode 100644 index 0000000000..cd1ef49327 --- /dev/null +++ b/test/docker/agentless-entrypoint.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +set -euxo pipefail + +handle_term() +{ + echo "received TERM signal" + echo "stopping nginx ..." + kill -TERM "${nginx_pid}" 2>/dev/null +} + +trap 'handle_term' TERM + +# Launch nginx +echo "starting nginx ..." +/usr/sbin/nginx -g "daemon off;" & + +nginx_pid=$! + +wait_term() +{ + wait ${nginx_pid} +} + +wait_term diff --git a/test/helpers/test_containers_utils.go b/test/helpers/test_containers_utils.go index 485c0d954f..25c633e86d 100644 --- a/test/helpers/test_containers_utils.go +++ b/test/helpers/test_containers_utils.go @@ -99,6 +99,65 @@ func StartContainer( return container } +func StartAgentlessContainer( + ctx context.Context, + tb testing.TB, + parameters *Parameters, +) testcontainers.Container { + tb.Helper() + + packageName := Env(tb, "PACKAGE_NAME") + packageRepo := Env(tb, "PACKAGES_REPO") + baseImage := Env(tb, "BASE_IMAGE") + osRelease := Env(tb, "OS_RELEASE") + osVersion := Env(tb, "OS_VERSION") + dockerfilePath := Env(tb, "DOCKERFILE_PATH") + containerRegistry := Env(tb, "CONTAINER_NGINX_IMAGE_REGISTRY") + tag := Env(tb, "TAG") + imagePath := Env(tb, "IMAGE_PATH") + + req := testcontainers.ContainerRequest{ + FromDockerfile: testcontainers.FromDockerfile{ + Context: "../../", + Dockerfile: dockerfilePath, + KeepImage: false, + PrintBuildLog: true, + BuildArgs: map[string]*string{ + "PACKAGE_NAME": ToPtr(packageName), + "PACKAGES_REPO": ToPtr(packageRepo), + "BASE_IMAGE": ToPtr(baseImage), + "OS_RELEASE": ToPtr(osRelease), + "OS_VERSION": ToPtr(osVersion), + "ENTRY_POINT": ToPtr("./test/docker/agentless-entrypoint.sh"), + "CONTAINER_NGINX_IMAGE_REGISTRY": ToPtr(containerRegistry), + "IMAGE_PATH": ToPtr(imagePath), + "TAG": ToPtr(tag), + }, + BuildOptionsModifier: func(buildOptions *types.ImageBuildOptions) { + buildOptions.Target = "install-nginx" + }, + }, + ExposedPorts: []string{"9091/tcp"}, + WaitingFor: wait.ForLog(parameters.LogMessage), + Files: []testcontainers.ContainerFile{ + { + HostFilePath: parameters.NginxConfigPath, + ContainerFilePath: "/etc/nginx/nginx.conf", + FileMode: configFilePermissions, + }, + }, + } + + container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ + ContainerRequest: req, + Started: true, + }) + + require.NoError(tb, err) + + return container +} + func StartMockManagementPlaneGrpcContainer( ctx context.Context, tb testing.TB, @@ -165,17 +224,18 @@ func LogAndTerminateContainers( err = agentContainer.Terminate(ctx) require.NoError(tb, err) - tb.Log("Logging mock management container logs") + if mockManagementPlaneContainer != nil { + tb.Log("Logging mock management container logs") + logReader, err = mockManagementPlaneContainer.Logs(ctx) + require.NoError(tb, err) - logReader, err = mockManagementPlaneContainer.Logs(ctx) - require.NoError(tb, err) + buf, err = io.ReadAll(logReader) + require.NoError(tb, err) + logs = string(buf) - buf, err = io.ReadAll(logReader) - require.NoError(tb, err) - logs = string(buf) + tb.Log(logs) - tb.Log(logs) - - err = mockManagementPlaneContainer.Terminate(ctx) - require.NoError(tb, err) + err = mockManagementPlaneContainer.Terminate(ctx) + require.NoError(tb, err) + } } diff --git a/test/integration/install_uninstall_test.go b/test/integration/install_uninstall_test.go new file mode 100644 index 0000000000..3dc96d40e4 --- /dev/null +++ b/test/integration/install_uninstall_test.go @@ -0,0 +1,252 @@ +// Copyright (c) F5, Inc. +// +// This source code is licensed under the Apache License, Version 2.0 license found in the +// LICENSE file in the root directory of this source tree. + +package integration + +import ( + "context" + "fmt" + "io" + "os" + "path" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/nginx/agent/v3/test/helpers" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/testcontainers/testcontainers-go" +) + +const ( + maxFileSize = int64(30000000) + maxInstallTime = 30 * time.Second + absContainerAgentPackageDir = "../agent/build" + agentPackageName = "nginx-agent" +) + +var ( + osRelease = os.Getenv("OS_RELEASE") + packageName = os.Getenv("PACKAGE_NAME") + + expectedInstallLogMsgs = map[string]string{ + "InstallFoundNginxAgent": "Found nginx-agent /usr/bin/nginx-agent", + "InstallAgentSuccess": "NGINX Agent package has been successfully installed.", + "InstallAgentStartCmd": "sudo systemctl start nginx-agent", + } + + agentConfigFile = "/etc/nginx-agent/nginx-agent.conf" +) + +func installUninstallSetup(tb testing.TB, expectNoErrorsInLogs bool) (testcontainers.Container, func(tb testing.TB)) { + tb.Helper() + ctx := context.Background() + + params := &helpers.Parameters{ + NginxConfigPath: "../config/nginx/nginx.conf", + LogMessage: "nginx_pid", + } + + // start container without agent installed + testContainer := helpers.StartAgentlessContainer( + ctx, + tb, + params, + ) + + return testContainer, func(tb testing.TB) { + tb.Helper() + helpers.LogAndTerminateContainers( + ctx, + tb, + nil, + testContainer, + expectNoErrorsInLogs, + ) + } +} + +func TestInstallUninstall(t *testing.T) { + testContainer, teardownTest := installUninstallSetup(t, true) + defer teardownTest(t) + ctx := context.Background() + + // verify size of agent package and get path to agent package + containerAgentPackagePath := verifyAgentPackage(t, testContainer) + + // check agent is installed successfully + verifyAgentInstall(ctx, t, testContainer, containerAgentPackagePath) + + // check output of nginx-agent --version command + verifyAgentVersion(ctx, t, testContainer) + + // verify agent is uninstalled successfully + verifyAgentUninstall(ctx, t, testContainer) +} + +func verifyAgentPackage(tb testing.TB, testContainer testcontainers.Container) string { + tb.Helper() + agentPkgPath, filePathErr := filepath.Abs("../../build/") + require.NoError(tb, filePathErr, "Error finding local agent package build dir") + + localAgentPkg, packageErr := os.Stat(getPackagePath(agentPkgPath, osRelease)) + require.NoError(tb, packageErr, "Error accessing package at: "+agentPkgPath) + + // Check the file size is less than or equal 30MB + assert.LessOrEqual(tb, localAgentPkg.Size(), maxFileSize) + + if strings.Contains(osRelease, "ubuntu") || strings.Contains(osRelease, "debian") { + updateDebRepo(tb, testContainer) + } + + return getPackagePath(absContainerAgentPackageDir, osRelease) +} + +func verifyAgentInstall(ctx context.Context, tb testing.TB, testContainer testcontainers.Container, + containerAgentPackagePath string, +) { + tb.Helper() + + installLog, installTime := installAgent(ctx, tb, testContainer, osRelease, containerAgentPackagePath) + + assert.LessOrEqual(tb, installTime, maxInstallTime) + + if nginxIsRunning(ctx, testContainer) { + expectedInstallLogMsgs["InstallAgentToRunAs"] = "nginx-agent will be configured to run as same user" + } + + for _, logMsg := range expectedInstallLogMsgs { + assert.Contains(tb, installLog, logMsg) + } + + _, copyFileErr := testContainer.CopyFileFromContainer(ctx, agentConfigFile) + require.NoError(tb, copyFileErr, "filePath", agentConfigFile) +} + +func verifyAgentUninstall(ctx context.Context, tb testing.TB, testContainer testcontainers.Container) { + tb.Helper() + uninstallLog := uninstallAgent(ctx, tb, testContainer, osRelease) + + expectedUninstallLogMsgs := make(map[string]string) + if strings.Contains(osRelease, "ubuntu") || strings.Contains(osRelease, "debian") { + expectedUninstallLogMsgs["UninstallAgent"] = "Removing nginx-agent" + expectedUninstallLogMsgs["UninstallAgentPurgingFiles"] = "Purging configuration files for nginx-agent" + } else if strings.Contains(osRelease, "alpine") { + expectedUninstallLogMsgs["UninstallAgent"] = "Purging nginx-agent" + } else { + expectedUninstallLogMsgs["UninstallAgent"] = "Removed:\n nginx-agent" + } + + for _, logMsg := range expectedUninstallLogMsgs { + assert.Contains(tb, uninstallLog, logMsg) + } + + _, copyFileErr := testContainer.CopyFileFromContainer(ctx, agentConfigFile) + require.Error(tb, copyFileErr, "filePath", agentConfigFile) +} + +func verifyAgentVersion(ctx context.Context, tb testing.TB, testContainer testcontainers.Container) { + tb.Helper() + + replacer := strings.NewReplacer("nginx-agent-", "v", "SNAPSHOT-", "") + packageVersion := replacer.Replace(os.Getenv("PACKAGE_NAME")) + expectedVersionOutput := fmt.Sprintf("nginx-agent version %s", packageVersion) + + exitCode, cmdOut, err := testContainer.Exec(ctx, []string{"nginx-agent", "--version"}) + require.NoError(tb, err) + assert.Equal(tb, 0, exitCode) + stdoutStderr, _ := io.ReadAll(cmdOut) + + versionOutput := strings.Trim(string(stdoutStderr), "#$%\x00\x01\n") + require.NoError(tb, err) + assert.Equal(tb, expectedVersionOutput, versionOutput) +} + +func installAgent(ctx context.Context, tb testing.TB, container testcontainers.Container, osReleaseContent, + agentPackageFilePath string, +) (string, time.Duration) { + tb.Helper() + installCmd := createInstallCommand(osReleaseContent, agentPackageFilePath) + + start := time.Now() + + exitCode, cmdOut, err := container.Exec(ctx, installCmd) + require.NoError(tb, err) + stdoutStderr, err := io.ReadAll(cmdOut) + require.NoError(tb, err) + assert.Equal(tb, 0, exitCode, fmt.Sprintf("expected error code of 0 from cmd %q. Got:"+ + " %v\n %s", installCmd, exitCode, stdoutStderr)) + + return string(stdoutStderr), time.Since(start) +} + +func uninstallAgent(ctx context.Context, tb testing.TB, container testcontainers.Container, + osReleaseContent string, +) string { + tb.Helper() + uninstallCmd := createUninstallCommand(osReleaseContent) + + exitCode, cmdOut, err := container.Exec(ctx, uninstallCmd) + require.NoError(tb, err) + assert.Equal(tb, 0, exitCode, fmt.Sprintf("expected error code of 0 from cmd %q. Got:"+ + " %v", uninstallCmd, exitCode)) + + stdoutStderr, err := io.ReadAll(cmdOut) + require.NoError(tb, err) + + return string(stdoutStderr) +} + +func updateDebRepo(tb testing.TB, testContainer testcontainers.Container) { + tb.Helper() + updateCmd := []string{"apt-get", "update"} + + exitCode, _, err := testContainer.Exec(context.Background(), updateCmd) + require.NoError(tb, err) + assert.Equal(tb, 0, exitCode, fmt.Sprintf("expected error code of 0 from cmd %q", exitCode)) +} + +func nginxIsRunning(ctx context.Context, container testcontainers.Container) bool { + exitCode, _, err := container.Exec(ctx, []string{"pgrep", "nginx"}) + if err != nil || exitCode != 0 { + return false + } + + return true +} + +func createUninstallCommand(osReleaseContent string) []string { + if strings.Contains(osReleaseContent, "ubuntu") || strings.Contains(osReleaseContent, "debian") { + return []string{"apt", "purge", "-y", agentPackageName} + } else if strings.Contains(osReleaseContent, "alpine") { + return []string{"apk", "del", agentPackageName} + } + + return []string{"yum", "remove", "-y", agentPackageName} +} + +func createInstallCommand(osReleaseContent, agentPackageFilePath string) []string { + if strings.Contains(osReleaseContent, "ubuntu") || strings.Contains(osReleaseContent, "debian") { + return []string{"dpkg", "-i", agentPackageFilePath} + } else if strings.Contains(osReleaseContent, "alpine") { + return []string{"apk", "add", "--allow-untrusted", agentPackageFilePath} + } + + return []string{"yum", "localinstall", "-y", agentPackageFilePath} +} + +func getPackagePath(pkgDir, osReleaseContent string) string { + pkgPath := path.Join(pkgDir, packageName) + + if strings.Contains(osReleaseContent, "ubuntu") || strings.Contains(osReleaseContent, "Debian") { + return pkgPath + ".deb" + } else if strings.Contains(osReleaseContent, "alpine") { + return pkgPath + ".apk" + } + + return pkgPath + ".rpm" +} From ff2a1fbc7ab2d87c5448c06202bf13427c56854f Mon Sep 17 00:00:00 2001 From: Donal Hurley Date: Thu, 26 Sep 2024 14:29:18 +0100 Subject: [PATCH 17/22] Update building agent section in README (#867) --- README.md | 13 +++- .../generated_component_test.go | 12 +-- .../internal/metadata/generated_metrics.go | 54 +++++-------- .../metadata/generated_metrics_test.go | 18 ++--- .../generated_component_test.go | 12 +-- .../internal/metadata/generated_metrics.go | 54 +++++-------- .../metadata/generated_metrics_test.go | 76 +++++++++---------- 7 files changed, 107 insertions(+), 132 deletions(-) diff --git a/README.md b/README.md index 94a2f37de7..3f544d14fb 100644 --- a/README.md +++ b/README.md @@ -26,10 +26,17 @@ make install-tools ``` ### Building NGINX Agent from Source Code -Run the following commands to build and run NGINX Agent: +Build NGINX Agent deb package: ``` -make build -sudo make run +OSARCH= make local-deb-packge +``` +Build NGINX Agent rpm package: +``` +OSARCH= make local-rpm-packge +``` +Build NGINX Agent apk package: +``` +OSARCH= make local-apk-packge ``` ## NGINX Agent Technical Specifications diff --git a/internal/collector/nginxossreceiver/generated_component_test.go b/internal/collector/nginxossreceiver/generated_component_test.go index 60de562050..3007dc92b4 100644 --- a/internal/collector/nginxossreceiver/generated_component_test.go +++ b/internal/collector/nginxossreceiver/generated_component_test.go @@ -46,21 +46,21 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) - for _, tt := range tests { - t.Run(tt.name+"-shutdown", func(t *testing.T) { - c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + for _, test := range tests { + t.Run(test.name+"-shutdown", func(t *testing.T) { + c, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) - t.Run(tt.name+"-lifecycle", func(t *testing.T) { - firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + t.Run(test.name+"-lifecycle", func(t *testing.T) { + firstRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) host := componenttest.NewNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) - secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + secondRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) diff --git a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go index c560fe1bc8..e74642bc94 100644 --- a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go +++ b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics.go @@ -313,25 +313,17 @@ type MetricsBuilder struct { metricNginxHTTPResponseStatus metricNginxHTTPResponseStatus } -// MetricBuilderOption applies changes to default metrics builder. -type MetricBuilderOption interface { - apply(*MetricsBuilder) -} - -type metricBuilderOptionFunc func(mb *MetricsBuilder) - -func (mbof metricBuilderOptionFunc) apply(mb *MetricsBuilder) { - mbof(mb) -} +// metricBuilderOption applies changes to default metrics builder. +type metricBuilderOption func(*MetricsBuilder) // WithStartTime sets startTime on the metrics builder. -func WithStartTime(startTime pcommon.Timestamp) MetricBuilderOption { - return metricBuilderOptionFunc(func(mb *MetricsBuilder) { +func WithStartTime(startTime pcommon.Timestamp) metricBuilderOption { + return func(mb *MetricsBuilder) { mb.startTime = startTime - }) + } } -func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...MetricBuilderOption) *MetricsBuilder { +func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...metricBuilderOption) *MetricsBuilder { mb := &MetricsBuilder{ config: mbc, startTime: pcommon.NewTimestampFromTime(time.Now()), @@ -344,7 +336,7 @@ func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, opt } for _, op := range options { - op.apply(mb) + op(mb) } return mb } @@ -357,28 +349,20 @@ func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { } // ResourceMetricsOption applies changes to provided resource metrics. -type ResourceMetricsOption interface { - apply(pmetric.ResourceMetrics) -} - -type resourceMetricsOptionFunc func(pmetric.ResourceMetrics) - -func (rmof resourceMetricsOptionFunc) apply(rm pmetric.ResourceMetrics) { - rmof(rm) -} +type ResourceMetricsOption func(pmetric.ResourceMetrics) // WithResource sets the provided resource on the emitted ResourceMetrics. // It's recommended to use ResourceBuilder to create the resource. func WithResource(res pcommon.Resource) ResourceMetricsOption { - return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { + return func(rm pmetric.ResourceMetrics) { res.CopyTo(rm.Resource()) - }) + } } // WithStartTimeOverride overrides start time for all the resource metrics data points. // This option should be only used if different start time has to be set on metrics coming from different resources. func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { - return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { + return func(rm pmetric.ResourceMetrics) { var dps pmetric.NumberDataPointSlice metrics := rm.ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { @@ -392,7 +376,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { dps.At(j).SetStartTimestamp(start) } } - }) + } } // EmitForResource saves all the generated metrics under a new resource and updates the internal state to be ready for @@ -400,7 +384,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { // needs to emit metrics from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceMetricsOption arguments. -func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { +func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { rm := pmetric.NewResourceMetrics() ils := rm.ScopeMetrics().AppendEmpty() ils.Scope().SetName("otelcol/nginxreceiver") @@ -411,8 +395,8 @@ func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { mb.metricNginxHTTPRequests.emit(ils.Metrics()) mb.metricNginxHTTPResponseStatus.emit(ils.Metrics()) - for _, op := range options { - op.apply(rm) + for _, op := range rmo { + op(rm) } if ils.Metrics().Len() > 0 { @@ -424,8 +408,8 @@ func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { // Emit returns all the metrics accumulated by the metrics builder and updates the internal state to be ready for // recording another set of metrics. This function will be responsible for applying all the transformations required to // produce metric representation defined in metadata and user config, e.g. delta or cumulative. -func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics { - mb.EmitForResource(options...) +func (mb *MetricsBuilder) Emit(rmo ...ResourceMetricsOption) pmetric.Metrics { + mb.EmitForResource(rmo...) metrics := mb.metricsBuffer mb.metricsBuffer = pmetric.NewMetrics() return metrics @@ -453,9 +437,9 @@ func (mb *MetricsBuilder) RecordNginxHTTPResponseStatusDataPoint(ts pcommon.Time // Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, // and metrics builder should update its startTime and reset it's internal state accordingly. -func (mb *MetricsBuilder) Reset(options ...MetricBuilderOption) { +func (mb *MetricsBuilder) Reset(options ...metricBuilderOption) { mb.startTime = pcommon.NewTimestampFromTime(time.Now()) for _, op := range options { - op.apply(mb) + op(mb) } } diff --git a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go index 2581a33ef3..261655b70a 100644 --- a/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go +++ b/internal/collector/nginxossreceiver/internal/metadata/generated_metrics_test.go @@ -43,14 +43,14 @@ func TestMetricsBuilder(t *testing.T) { expectEmpty: true, }, } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { start := pcommon.Timestamp(1_000_000_000) ts := pcommon.Timestamp(1_000_001_000) observedZapCore, observedLogs := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings() settings.Logger = zap.New(observedZapCore) - mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start)) + mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, test.name), settings, WithStartTime(start)) expectedWarnings := 0 @@ -78,7 +78,7 @@ func TestMetricsBuilder(t *testing.T) { res := pcommon.NewResource() metrics := mb.Emit(WithResource(res)) - if tt.expectEmpty { + if test.expectEmpty { assert.Equal(t, 0, metrics.ResourceMetrics().Len()) return } @@ -88,10 +88,10 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, res, rm.Resource()) assert.Equal(t, 1, rm.ScopeMetrics().Len()) ms := rm.ScopeMetrics().At(0).Metrics() - if tt.metricsSet == testDataSetDefault { + if test.metricsSet == testDataSetDefault { assert.Equal(t, defaultMetricsCount, ms.Len()) } - if tt.metricsSet == testDataSetAll { + if test.metricsSet == testDataSetAll { assert.Equal(t, allMetricsCount, ms.Len()) } validatedMetrics := make(map[string]bool) @@ -104,7 +104,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -136,7 +136,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests received from clients.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -150,7 +150,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The number of responses, grouped by status code range.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) diff --git a/internal/collector/nginxplusreceiver/generated_component_test.go b/internal/collector/nginxplusreceiver/generated_component_test.go index 9fbb9944ca..170385ba71 100644 --- a/internal/collector/nginxplusreceiver/generated_component_test.go +++ b/internal/collector/nginxplusreceiver/generated_component_test.go @@ -46,21 +46,21 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) - for _, tt := range tests { - t.Run(tt.name+"-shutdown", func(t *testing.T) { - c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + for _, test := range tests { + t.Run(test.name+"-shutdown", func(t *testing.T) { + c, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) - t.Run(tt.name+"-lifecycle", func(t *testing.T) { - firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + t.Run(test.name+"-lifecycle", func(t *testing.T) { + firstRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) host := componenttest.NewNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) - secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(), cfg) + secondRcvr, err := test.createFn(context.Background(), receivertest.NewNopSettings(), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) diff --git a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go index 15dbba1752..866fb5a735 100644 --- a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go +++ b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics.go @@ -3620,25 +3620,17 @@ type MetricsBuilder struct { metricNginxStreamUpstreamZombieCount metricNginxStreamUpstreamZombieCount } -// MetricBuilderOption applies changes to default metrics builder. -type MetricBuilderOption interface { - apply(*MetricsBuilder) -} - -type metricBuilderOptionFunc func(mb *MetricsBuilder) - -func (mbof metricBuilderOptionFunc) apply(mb *MetricsBuilder) { - mbof(mb) -} +// metricBuilderOption applies changes to default metrics builder. +type metricBuilderOption func(*MetricsBuilder) // WithStartTime sets startTime on the metrics builder. -func WithStartTime(startTime pcommon.Timestamp) MetricBuilderOption { - return metricBuilderOptionFunc(func(mb *MetricsBuilder) { +func WithStartTime(startTime pcommon.Timestamp) metricBuilderOption { + return func(mb *MetricsBuilder) { mb.startTime = startTime - }) + } } -func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...MetricBuilderOption) *MetricsBuilder { +func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...metricBuilderOption) *MetricsBuilder { mb := &MetricsBuilder{ config: mbc, startTime: pcommon.NewTimestampFromTime(time.Now()), @@ -3705,7 +3697,7 @@ func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, opt } for _, op := range options { - op.apply(mb) + op(mb) } return mb } @@ -3718,28 +3710,20 @@ func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { } // ResourceMetricsOption applies changes to provided resource metrics. -type ResourceMetricsOption interface { - apply(pmetric.ResourceMetrics) -} - -type resourceMetricsOptionFunc func(pmetric.ResourceMetrics) - -func (rmof resourceMetricsOptionFunc) apply(rm pmetric.ResourceMetrics) { - rmof(rm) -} +type ResourceMetricsOption func(pmetric.ResourceMetrics) // WithResource sets the provided resource on the emitted ResourceMetrics. // It's recommended to use ResourceBuilder to create the resource. func WithResource(res pcommon.Resource) ResourceMetricsOption { - return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { + return func(rm pmetric.ResourceMetrics) { res.CopyTo(rm.Resource()) - }) + } } // WithStartTimeOverride overrides start time for all the resource metrics data points. // This option should be only used if different start time has to be set on metrics coming from different resources. func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { - return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { + return func(rm pmetric.ResourceMetrics) { var dps pmetric.NumberDataPointSlice metrics := rm.ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { @@ -3753,7 +3737,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { dps.At(j).SetStartTimestamp(start) } } - }) + } } // EmitForResource saves all the generated metrics under a new resource and updates the internal state to be ready for @@ -3761,7 +3745,7 @@ func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { // needs to emit metrics from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceMetricsOption arguments. -func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { +func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { rm := pmetric.NewResourceMetrics() ils := rm.ScopeMetrics().AppendEmpty() ils.Scope().SetName("otelcol/nginxplusreceiver") @@ -3826,8 +3810,8 @@ func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { mb.metricNginxStreamUpstreamPeerUnavailable.emit(ils.Metrics()) mb.metricNginxStreamUpstreamZombieCount.emit(ils.Metrics()) - for _, op := range options { - op.apply(rm) + for _, op := range rmo { + op(rm) } if ils.Metrics().Len() > 0 { @@ -3839,8 +3823,8 @@ func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { // Emit returns all the metrics accumulated by the metrics builder and updates the internal state to be ready for // recording another set of metrics. This function will be responsible for applying all the transformations required to // produce metric representation defined in metadata and user config, e.g. delta or cumulative. -func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics { - mb.EmitForResource(options...) +func (mb *MetricsBuilder) Emit(rmo ...ResourceMetricsOption) pmetric.Metrics { + mb.EmitForResource(rmo...) metrics := mb.metricsBuffer mb.metricsBuffer = pmetric.NewMetrics() return metrics @@ -4138,9 +4122,9 @@ func (mb *MetricsBuilder) RecordNginxStreamUpstreamZombieCountDataPoint(ts pcomm // Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, // and metrics builder should update its startTime and reset it's internal state accordingly. -func (mb *MetricsBuilder) Reset(options ...MetricBuilderOption) { +func (mb *MetricsBuilder) Reset(options ...metricBuilderOption) { mb.startTime = pcommon.NewTimestampFromTime(time.Now()) for _, op := range options { - op.apply(mb) + op(mb) } } diff --git a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go index 6d048f6442..8e8f64cbb9 100644 --- a/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go +++ b/internal/collector/nginxplusreceiver/internal/metadata/generated_metrics_test.go @@ -43,14 +43,14 @@ func TestMetricsBuilder(t *testing.T) { expectEmpty: true, }, } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { start := pcommon.Timestamp(1_000_000_000) ts := pcommon.Timestamp(1_000_001_000) observedZapCore, observedLogs := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings() settings.Logger = zap.New(observedZapCore) - mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start)) + mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, test.name), settings, WithStartTime(start)) expectedWarnings := 0 @@ -294,7 +294,7 @@ func TestMetricsBuilder(t *testing.T) { res := pcommon.NewResource() metrics := mb.Emit(WithResource(res)) - if tt.expectEmpty { + if test.expectEmpty { assert.Equal(t, 0, metrics.ResourceMetrics().Len()) return } @@ -304,10 +304,10 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, res, rm.Resource()) assert.Equal(t, 1, rm.ScopeMetrics().Len()) ms := rm.ScopeMetrics().At(0).Metrics() - if tt.metricsSet == testDataSetDefault { + if test.metricsSet == testDataSetDefault { assert.Equal(t, defaultMetricsCount, ms.Len()) } - if tt.metricsSet == testDataSetAll { + if test.metricsSet == testDataSetAll { assert.Equal(t, allMetricsCount, ms.Len()) } validatedMetrics := make(map[string]bool) @@ -320,7 +320,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of bytes read from the cache or proxied server.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -370,7 +370,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of responses read from the cache or proxied server.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -390,7 +390,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of NGINX config reloads.", ms.At(i).Description()) assert.Equal(t, "reloads", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -404,7 +404,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -436,7 +436,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections to an endpoint with a limit_conn directive.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -456,7 +456,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of requests to an endpoint with a limit_req directive.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -476,7 +476,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of HTTP byte IO.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -499,7 +499,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of requests completed without sending a response.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -537,7 +537,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests received from clients.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -569,7 +569,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The number of responses, grouped by status code range.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -592,7 +592,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests received from clients.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -630,7 +630,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of byte IO per HTTP upstream peer.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -752,7 +752,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of health check requests made to a HTTP upstream peer.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -781,7 +781,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client requests forwarded to the HTTP upstream peer.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -831,7 +831,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of responses obtained from the HTTP upstream peer grouped by status range.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -887,7 +887,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Number of times the server became unavailable for client requests (“unavail”).", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -931,7 +931,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of requests rejected due to the queue overflow.", ms.At(i).Description()) assert.Equal(t, "responses", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1036,7 +1036,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) - assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) + assert.Equal(t, float64(1), dp.DoubleValue()) attrVal, ok := dp.Attributes().Get("nginx.zone.name") assert.True(t, ok) assert.EqualValues(t, "nginx.zone.name-val", attrVal.Str()) @@ -1047,7 +1047,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The number of attempts to allocate memory of specified size.", ms.At(i).Description()) assert.Equal(t, "allocations", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1106,7 +1106,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of SSL certificate verification failures.", ms.At(i).Description()) assert.Equal(t, "certificates", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1123,7 +1123,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of SSL handshakes.", ms.At(i).Description()) assert.Equal(t, "handshakes", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1143,7 +1143,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of Stream byte IO.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1163,7 +1163,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of connections accepted from clients.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1180,7 +1180,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Total number of connections completed without creating a session.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1212,7 +1212,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of completed sessions.", ms.At(i).Description()) assert.Equal(t, "sessions", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1232,7 +1232,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of Stream Upstream Peer byte IO.", ms.At(i).Description()) assert.Equal(t, "bytes", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1309,7 +1309,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of client connections forwarded to this stream upstream peer.", ms.At(i).Description()) assert.Equal(t, "connections", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1335,7 +1335,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of stream upstream peers grouped by state.", ms.At(i).Description()) assert.Equal(t, "peers", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1358,7 +1358,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of unsuccessful attempts to communicate with the stream upstream peer.", ms.At(i).Description()) assert.Equal(t, "peers", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1381,7 +1381,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "The total number of health check requests made to the stream upstream peer.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1434,7 +1434,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Current state of upstream peers in deployment. If any of the upstream peers in the deployment match the given state then the value will be 1. If no upstream peer is a match then the value will be 0.", ms.At(i).Description()) assert.Equal(t, "deployments", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) @@ -1487,7 +1487,7 @@ func TestMetricsBuilder(t *testing.T) { assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "How many times the server became unavailable for client connections (state “unavail”) due to the number of unsuccessful attempts reaching the max_fails threshold.", ms.At(i).Description()) assert.Equal(t, "requests", ms.At(i).Unit()) - assert.True(t, ms.At(i).Sum().IsMonotonic()) + assert.Equal(t, true, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) From 011a0f9ddc820c71ed4601d4008af78df1d41e27 Mon Sep 17 00:00:00 2001 From: Donal Hurley Date: Thu, 26 Sep 2024 16:43:08 +0100 Subject: [PATCH 18/22] Fix collector extensions config (#870) --- internal/collector/otelcol.tmpl | 5 +++++ internal/config/config_test.go | 2 +- internal/config/types.go | 2 +- test/mock/collector/nginx-agent.conf | 2 +- test/types/config.go | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/internal/collector/otelcol.tmpl b/internal/collector/otelcol.tmpl index 0cc28a215a..44b454ab8e 100644 --- a/internal/collector/otelcol.tmpl +++ b/internal/collector/otelcol.tmpl @@ -138,8 +138,13 @@ service: output_paths: ["{{ .Log.Path -}}"] error_output_paths: ["{{ .Log.Path -}}"] {{- end}} + + {{- if ne .Extensions nil }} extensions: + {{- if ne .Extensions.Health nil }} - health_check + {{- end}} + {{- end}} pipelines: metrics: receivers: diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 836ebb7ce0..b907f15bf6 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -366,7 +366,7 @@ func getAgentConfig() *Config { }, }, Extensions: Extensions{ - Health: Health{ + Health: &Health{ Server: &ServerConfig{ Host: "localhost", Port: 1337, diff --git a/internal/config/types.go b/internal/config/types.go index cfa80cf453..2765883048 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -95,7 +95,7 @@ type ( } Extensions struct { - Health Health `yaml:"-" mapstructure:"health"` + Health *Health `yaml:"-" mapstructure:"health"` } Health struct { diff --git a/test/mock/collector/nginx-agent.conf b/test/mock/collector/nginx-agent.conf index d67410115a..a06c12b934 100644 --- a/test/mock/collector/nginx-agent.conf +++ b/test/mock/collector/nginx-agent.conf @@ -51,7 +51,7 @@ collector: key: /tmp/key.pem generate_self_signed_cert: true processors: - batch: + batch: {} exporters: otlp_exporters: - server: diff --git a/test/types/config.go b/test/types/config.go index 15d82c278d..424f483ab3 100644 --- a/test/types/config.go +++ b/test/types/config.go @@ -84,7 +84,7 @@ func AgentConfig() *config.Config { }, }, Extensions: config.Extensions{ - Health: config.Health{ + Health: &config.Health{ Server: &config.ServerConfig{ Host: "localhost", Port: randomPort3, From 34c34b23b1604768c7db5c71512f385d8f68f40a Mon Sep 17 00:00:00 2001 From: RRashmit <132996156+RRashmit@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:49:54 +0100 Subject: [PATCH 19/22] Publish package for agent (#866) * chore: updated ci to publish packages for v3 * chore: dynamic build number generation * chore: directly using git variable * chore: remove component test * chore: typo * chore: typo * chore: add permissions * chore: update package build number * chore: calculate the build number in a separate job --- .github/workflows/ci.yml | 37 ++++++++++++++++++++++++++-- .github/workflows/release-branch.yml | 26 +++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2f1b449cb5..8ff680bbab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,7 +82,6 @@ jobs: name: nginx-agent-unsigned-snapshots path: build retention-days: 1 - generate-pgo-profile: name: Generate Profile needs: build-unsigned-snapshot @@ -261,7 +260,6 @@ jobs: - name: Push benchmark result if: ${{ success() && github.ref_name == 'v3'}} run: git push 'https://github-actions:${{ secrets.GITHUB_TOKEN }}@github.com/nginx/agent.git' benchmark-results:benchmark-results - load-tests: name: Load Tests if: ${{ !github.event.pull_request.head.repo.fork && !startsWith(github.ref_name, 'dependabot/') }} @@ -334,3 +332,38 @@ jobs: - name: Push load test result if: ${{ success() && github.ref_name == 'v3'}} run: git push 'https://github-actions:${{ secrets.GITHUB_TOKEN }}@github.com/nginx/agent.git' benchmark-results:benchmark-results + publish-packages-vars: + name: Set workflow variables + if: ${{ github.event_name == 'pull_request' && + github.base_ref == 'v3' && + github.event.pull_request.merged == true && + !github.event.pull_request.head.repo.fork }} + runs-on: ubuntu-22.04 + outputs: + package_build_num: ${{ steps.get_build_num.outputs.build_num }} + steps: + - name: Get the build number + id: get_build_num + run: echo "build_num=${{ github.run_number }}-$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT + + publish-packages: + name: Publish NGINX Agent v3 packages + if: ${{ github.event_name == 'pull_request' && + github.base_ref == 'v3' && + github.event.pull_request.merged == true && + !github.event.pull_request.head.repo.fork }} + needs: [ lint, unit-test, performance-tests, + load-tests, official-oss-image-integration-tests, + official-plus-image-integration-tests, + race-condition-test, publish-packages-vars ] + uses: ./.github/workflows/release-branch.yml + secrets: inherit + permissions: + id-token: write + contents: read + with: + packageVersion: "3.0.0" + packageBuildNo: "${{ needs.publish-packages-vars.outputs.package_build_num }}" + uploadAzure: true + publishPackages: true + releaseBranch: "v3" diff --git a/.github/workflows/release-branch.yml b/.github/workflows/release-branch.yml index 812c1520a9..3b2094dc18 100644 --- a/.github/workflows/release-branch.yml +++ b/.github/workflows/release-branch.yml @@ -35,6 +35,32 @@ on: description: 'Release branch to build & publish from' required: true type: string + workflow_call: + inputs: + githubRelease: + type: boolean + default: false + packageVersion: + type: string + default: "3.0.0" + packageBuildNo: + type: string + default: "1" + uploadAzure: + type: boolean + default: true + publishPackages: + type: boolean + default: true + tagRelease: + type: boolean + default: false + createPullRequest: + type: boolean + default: false + releaseBranch: + type: string + required: true env: NFPM_VERSION: 'v2.35.3' From 62bbfb8f438b9345e9038bba404b71986f309e82 Mon Sep 17 00:00:00 2001 From: oliveromahony Date: Fri, 27 Sep 2024 15:11:39 +0100 Subject: [PATCH 20/22] Added default set of features to Agent Configuration (#868) * added initial feature set and documentation --- docs/features/features.md | 211 ++++++++++++++++++ internal/config/config.go | 7 + internal/config/defaults.go | 11 + internal/config/flags.go | 1 + internal/config/types.go | 1 + .../instance/instance_watcher_service.go | 2 +- nginx-agent.conf | 34 +-- pkg/config/features.go | 18 ++ 8 files changed, 268 insertions(+), 17 deletions(-) create mode 100644 docs/features/features.md create mode 100644 pkg/config/features.go diff --git a/docs/features/features.md b/docs/features/features.md new file mode 100644 index 0000000000..f63763adc8 --- /dev/null +++ b/docs/features/features.md @@ -0,0 +1,211 @@ +# NGINX Agent Features + +- [Introduction](#introduction) +- [Feature Flags Overview](#feature-flags-overview) +- [Conflicting Combinations](#conflicting-combinations) +- [Cobra CLI Parameters](#cobra-cli-parameters) +- [Environment Variables](#environment-variables) +- [Configuration File](#configuration-file) +- [Dynamic Updates via gRPC](#dynamic-updates-via-grpc) +- [Internal State Management](#internal-state-management) +- [Code Path Management](#code-path-management) +- [Dynamic Feature Toggling](#dynamic-feature-toggling) +- [Security Considerations](#security-considerations) +- [Conclusion](#conclusion) + +## Introduction + +This document outlines the design of a feature flag management system +for the NGINX Agent. The system enables dynamic toggling of features +based on configurations provided via multiple sources, including CLI +parameters, environment variables, configuration files, and via protobuf +gRPC messages. Feature flags control the execution paths within the +application, allowing for flexible and controlled feature management. + +## Feature Flags Overview + +The design goal of this document is to capture fine grained features in +NGINX Agent v3. + +The ultimate goal of this design is to delegate fine-grained control of +high-level feature sets to the configuration. + +The system manages the following feature flags: + +| Feature Flag | Sub Category 1 | Description | Default | +|---------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------| +| configuration | | Full read/write management of configurations toggled by DataPlaneConfig ConfigMode | On | +| certificates | | Inclusion of public keys and other certificates in the configurations toggled by DataPlaneConfig CertMode | Off | +| connection | | Sends an initial connection message reporting instance information on presence of Command ServerConfig Host and Port | On | +| file-watcher | | Monitoring of file changes in allowed directories; may trigger DataPlane (DP) => ManagementPlane synchronisation of files configured by Watchers | On | +| agent-api | | REST Application Programming Interface (API) for NGINX Agent | Off | +| metrics | | Full metrics reporting | On | +| | metrics-host | All host-level metrics | On (if running in a host, virtualised or not) | +| | metrics-container | Container-level metrics read from cgroup information | On (if running in a container) | +| | metrics-instance | All OSS and Plus Metrics, depending on what instance is present | On (if instance present e.g. NGINX) | + +## Conflicting Combinations + +If there is a feature flag enabled and conflicting features are +enabled, the more specific feature flag takes precedence. If the +feature flag is set e.g. metrics-container in a non-containerised +execution environment, then no useful metrics will be reported. + +**config-certificates** being read-only and reporting ssl under +instances may conflict. + +**metrics** will include every specified metrics category (hence the +inherited specification). If fine-grained metrics are required, this +needs to be absent from the list. + +### Cobra CLI Parameters + +**Usage**: Users can enable or disable features via CLI flags when + launching the application. + +**Example**: + +```bash +./nginx-agent --features=connection,config,metrics,process-watcher,file-watcher,agent-api +``` + +Specifies a comma-separated list of features enabled for the Agent. + +- **Implementation**: Utilises [Cobra](https://github.com/spf13/cobra) + to define and parse CLI flags for each feature. + +### Environment Variables + +- **Usage**: Environment variables provide an alternative + configuration method, suitable for containerised deployments. + +- **Naming Convention**: NGINX_AGENT_FEATURES and is added to the list + +- **Implementation**: Use a library + [Viper](https://github.com/spf13/viper) to bind environment + variables to feature flags. + +### Configuration File + +- **Usage**: A configuration file (e.g., YAML, JSON, TOML) can list + enabled features and their parameters. + +- **Example (YAML)**: + +```yaml +features: +- connection +- configuration +- metrics +- process-watcher +- file-watcher +- agent-api + +``` + +**Implementation**: Parse the configuration file during initialisation using Viper. + +### Dynamic Updates via gRPC + +- Through the MPI + send an updated AgentConfig message with a different list of + features. + +## Internal State Management + +- **Singleton Pattern**: Implement a singleton FeaturePlugin to + maintain the state of all feature flags. On configuration change, + use the message bus to notify throughout the application of any + changes. + +- **Thread-Safety**: Use synchronisation mechanisms to ensure safe + concurrent access of changes + +## Code Path Management + +**Conditional Execution**: Use the FeatureManager to check feature + states before executing specific code paths. + +**Example**: + +```go + if featureManager.IsEnabled("metrics") { + // Execute full metrics reporting code path + } else { + // Execute alternative or no-op code path + } +``` + +- **Abstraction**: Encapsulate feature checks within helper functions + or middleware to streamline conditional logic across the codebase. + +## Dynamic Feature Toggling + +Implement methods within FeaturePlugin to enable, disable, and retrieve +feature states. Watch the nginx-agent.conf file for changes. Listen to +gRPC messages for AgentConfig changes. + +Example useful functionality: + +```go + +func (fm *FeatureManager) IsEnabled(featureName string) bool { + + fm.mutex.RLock() + + defer fm.mutex.RUnlock() + + // Code check to see if the feature is enabled in the AgentConfig + +} + +func (fm *FeatureManager) UpdateFeature(featureName string, enabled bool, parameters map[string]interface{}) error { + + fm.mutex.Lock() + + defer fm.mutex.Unlock() + + switch featureName { + + case "config": + + // update the AgentConfig with the new feature and it\'s configuration + + } + + return nil + +} +``` + +## Security Considerations + +- **Authentication & Authorisation**: Ensure that only authorised + entities can send gRPC messages to update feature flags. + +- **Validation**: Validate feature names and parameters received via + gRPC to prevent invalid configurations (e.g. using + ) + +- **Audit Logging**: Log all feature flag changes for auditing and + rollback purposes. + +- **Secret Management**: Securely handle sensitive configuration + parameters, especially for features like dealing with secrets and + connection settings. + +## Conclusion + +This design provides a flexible and dynamic feature flag management +system that integrates multiple configuration sources and allows +real-time updates via gRPC. + +By centralising feature state management and ensuring thread safety, the +system enables controlled feature toggling with minimal impact on the +running application. + +Proper security measures and validation ensure the integrity and +reliability of the feature management process. + + +[def]: #conflictingcombinations \ No newline at end of file diff --git a/internal/config/config.go b/internal/config/config.go index 4e581d3d27..514cf8ba88 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -102,6 +102,7 @@ func ResolveConfig() (*Config, error) { Command: resolveCommand(), Common: resolveCommon(), Watchers: resolveWatchers(), + Features: viperInstance.GetStringSlice(FeaturesKey), } slog.Debug("Agent config", "config", config) @@ -236,6 +237,12 @@ func registerFlags() { "Updates the client grpc setting MaxSendMsgSize with the specific value in MB.", ) + fs.StringSlice( + FeaturesKey, + GetDefaultFeatures(), + "A comma-separated list of features enabled for the agent.", + ) + registerCollectorFlags(fs) fs.SetNormalizeFunc(normalizeFunc) diff --git a/internal/config/defaults.go b/internal/config/defaults.go index 57d7903eb5..6c8ed93610 100644 --- a/internal/config/defaults.go +++ b/internal/config/defaults.go @@ -7,6 +7,8 @@ package config import ( "math" "time" + + pkg "github.com/nginx/agent/v3/pkg/config" ) const ( @@ -54,3 +56,12 @@ const ( DefCollectorBatchProcessorSendBatchMaxSize = 0 DefCollectorBatchProcessorTimeout = 200 * time.Millisecond ) + +func GetDefaultFeatures() []string { + return []string{ + pkg.FeatureConfiguration, + pkg.FeatureConnection, + pkg.FeatureMetrics, + pkg.FeatureFileWatcher, + } +} diff --git a/internal/config/flags.go b/internal/config/flags.go index 92a19839b1..9bf723bc55 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -18,6 +18,7 @@ const ( CollectorRootKey = "collector" VersionKey = "version" UUIDKey = "uuid" + FeaturesKey = "features" InstanceWatcherMonitoringFrequencyKey = "watchers_instance_watcher_monitoring_frequency" InstanceHealthWatcherMonitoringFrequencyKey = "watchers_instance_health_watcher_monitoring_frequency" FileWatcherMonitoringFrequencyKey = "watchers_file_watcher_monitoring_frequency" diff --git a/internal/config/types.go b/internal/config/types.go index 2765883048..3392e5b7a1 100644 --- a/internal/config/types.go +++ b/internal/config/types.go @@ -45,6 +45,7 @@ type ( ConfigDir string `yaml:"-" mapstructure:"config-dirs"` UUID string `yaml:"-"` AllowedDirectories []string `yaml:"-"` + Features []string `yaml:"-"` } Log struct { diff --git a/internal/watcher/instance/instance_watcher_service.go b/internal/watcher/instance/instance_watcher_service.go index 2840d0693b..958ad96866 100644 --- a/internal/watcher/instance/instance_watcher_service.go +++ b/internal/watcher/instance/instance_watcher_service.go @@ -299,7 +299,7 @@ func (iw *InstanceWatcherService) agentInstance(ctx context.Context) *mpi.Instan Metrics: &mpi.MetricsServer{}, File: &mpi.FileServer{}, Labels: []*structpb.Struct{}, - Features: []string{}, + Features: iw.agentConfig.Features, MessageBufferSize: "", }, }, diff --git a/nginx-agent.conf b/nginx-agent.conf index 141464fd7e..2109917eb6 100644 --- a/nginx-agent.conf +++ b/nginx-agent.conf @@ -5,25 +5,27 @@ # log: - # set log level (panic, fatal, error, info, debug, trace; default "info") + # set log level (error, info, debug; default "info") level: info # set log path. if empty, don't log to file. path: /var/log/nginx-agent/ -watchers: - instance_watcher: - monitoring_frequency: 5s - instance_health_watcher: - monitoring_frequency: 5s - file_watcher: - monitoring_frequency: 5s - -data_plane_config: - nginx: - reload_monitoring_period: 5s - treat_warnings_as_error: true - config_dirs: "/etc/nginx:/usr/local/etc/nginx:/usr/share/nginx/modules:/var/run/nginx:/var/log/nginx" -client: - timeout: 10s +## command server settings +# command: +# server: +# host: "127.0.0.1" # Command server host +# port: 8080 # Command server port +# type: 0 # Server type (e.g., 0 for gRPC) +# auth: +# token: "secret-auth-token" # Authentication token for the command server + +## collector metrics settings +# collector: +# exporters: # exporters +# - type: otlp # exporter type +# server: +# host: "127.0.0.1" # OTLP exporter server host +# port: 5643 # OTLP exporter server port +# tls: {} \ No newline at end of file diff --git a/pkg/config/features.go b/pkg/config/features.go new file mode 100644 index 0000000000..4bc857ca24 --- /dev/null +++ b/pkg/config/features.go @@ -0,0 +1,18 @@ +// Copyright (c) F5, Inc. +// +// This source code is licensed under the Apache License, Version 2.0 license found in the +// LICENSE file in the root directory of this source tree. + +package config + +const ( + FeatureCertificates = "certificates" + FeatureConfiguration = "configuration" + FeatureConnection = "connection" + FeatureMetrics = "metrics" + FeatureMetricsContainer = "metrics-container" + FeatureMetricsHost = "metrics-host" + FeatureMetricsInstance = "metrics-instance" + FeatureFileWatcher = "file-watcher" + FeatureAgentAPI = "agent-api" +) From c42bfa5d05b3b347b677cd9768a0298ddcd6f55e Mon Sep 17 00:00:00 2001 From: RRashmit <132996156+RRashmit@users.noreply.github.com> Date: Fri, 27 Sep 2024 16:38:49 +0100 Subject: [PATCH 21/22] Publish package condition update (#874) * chore: update the condition to run the publishing * chore: update condition to check if the branch is v3 --- .github/workflows/ci.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ff680bbab..31eb34abf0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -334,9 +334,7 @@ jobs: run: git push 'https://github-actions:${{ secrets.GITHUB_TOKEN }}@github.com/nginx/agent.git' benchmark-results:benchmark-results publish-packages-vars: name: Set workflow variables - if: ${{ github.event_name == 'pull_request' && - github.base_ref == 'v3' && - github.event.pull_request.merged == true && + if: ${{ github.ref_name == 'v3' && !github.event.pull_request.head.repo.fork }} runs-on: ubuntu-22.04 outputs: @@ -348,10 +346,8 @@ jobs: publish-packages: name: Publish NGINX Agent v3 packages - if: ${{ github.event_name == 'pull_request' && - github.base_ref == 'v3' && - github.event.pull_request.merged == true && - !github.event.pull_request.head.repo.fork }} + if: ${{ github.ref_name == 'v3' && + !github.event.pull_request.head.repo.fork }} needs: [ lint, unit-test, performance-tests, load-tests, official-oss-image-integration-tests, official-plus-image-integration-tests, From 7ab5bead32e54adb4def20bdead7f51d6d91c883 Mon Sep 17 00:00:00 2001 From: Chris Adams Date: Mon, 30 Sep 2024 09:26:07 +0100 Subject: [PATCH 22/22] Update README.md (#875) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3f544d14fb..a2bdccb7e7 100644 --- a/README.md +++ b/README.md @@ -28,15 +28,15 @@ make install-tools ### Building NGINX Agent from Source Code Build NGINX Agent deb package: ``` -OSARCH= make local-deb-packge +OSARCH= make local-deb-package ``` Build NGINX Agent rpm package: ``` -OSARCH= make local-rpm-packge +OSARCH= make local-rpm-package ``` Build NGINX Agent apk package: ``` -OSARCH= make local-apk-packge +OSARCH= make local-apk-package ``` ## NGINX Agent Technical Specifications