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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions cmd/nginx-ingress/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func main() {
appProtectVersion = getAppProtectVersionInfo()
}

updateSelfWithVersionInfo(kubeClient, version, nginxVersion, appProtectVersion)
updateSelfWithVersionInfo(kubeClient, version, nginxVersion.String(), appProtectVersion)

templateExecutor, templateExecutorV2 := createTemplateExecutors()

Expand Down Expand Up @@ -118,6 +118,7 @@ func main() {
EnableCertManager: *enableCertManager,
DynamicSSLReload: *enableDynamicSSLReload,
StaticSSLPath: nginxManager.GetSecretsDir(),
NginxVersion: nginxVersion,
}

processNginxConfig(staticCfgParams, cfgParams, templateExecutor, nginxManager)
Expand Down Expand Up @@ -146,6 +147,7 @@ func main() {
IsPrometheusEnabled: *enablePrometheusMetrics,
IsLatencyMetricsEnabled: *enableLatencyMetrics,
IsDynamicSSLReloadEnabled: *enableDynamicSSLReload,
NginxVersion: nginxVersion,
})

controllerNamespace := os.Getenv("POD_NAMESPACE")
Expand Down Expand Up @@ -400,17 +402,16 @@ func createNginxManager(managerCollector collectors.ManagerCollector) (nginx.Man
return nginxManager, useFakeNginxManager
}

func getNginxVersionInfo(nginxManager nginx.Manager) string {
nginxVersion := nginxManager.Version()
isPlus := strings.Contains(nginxVersion, "plus")
glog.Infof("Using %s", nginxVersion)
func getNginxVersionInfo(nginxManager nginx.Manager) nginx.Version {
nginxInfo := nginxManager.Version()
glog.Infof("Using %s", nginxInfo.String())

if *nginxPlus && !isPlus {
if *nginxPlus && !nginxInfo.IsPlus {
glog.Fatal("NGINX Plus flag enabled (-nginx-plus) without NGINX Plus binary")
} else if !*nginxPlus && isPlus {
} else if !*nginxPlus && nginxInfo.IsPlus {
glog.Fatal("NGINX Plus binary found without NGINX Plus flag (-nginx-plus)")
}
return nginxVersion
return nginxInfo
}

func getAppProtectVersionInfo() string {
Expand Down
6 changes: 5 additions & 1 deletion internal/configs/config_params.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package configs

import conf_v1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1"
import (
"github.com/nginxinc/kubernetes-ingress/internal/nginx"
conf_v1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1"
)

// ConfigParams holds NGINX configuration parameters that affect the main NGINX config
// as well as configs for Ingress resources.
Expand Down Expand Up @@ -136,6 +139,7 @@ type StaticConfigParams struct {
EnableCertManager bool
DynamicSSLReload bool
StaticSSLPath string
NginxVersion nginx.Version
}

// GlobalConfigParams holds global configuration parameters. For now, it only holds listeners.
Expand Down
1 change: 1 addition & 0 deletions internal/configs/configmaps.go
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ func GenerateNginxMainConfig(staticCfgParams *StaticConfigParams, config *Config
OIDC: staticCfgParams.EnableOIDC,
DynamicSSLReloadEnabled: staticCfgParams.DynamicSSLReload,
StaticSSLPath: staticCfgParams.StaticSSLPath,
NginxVersion: staticCfgParams.NginxVersion,
}
return nginxCfg
}
1 change: 1 addition & 0 deletions internal/configs/configurator.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ type ConfiguratorParams struct {
IsWildcardEnabled bool
IsLatencyMetricsEnabled bool
IsDynamicSSLReloadEnabled bool
NginxVersion nginx.Version
}

// NewConfigurator creates a new Configurator.
Expand Down
2 changes: 2 additions & 0 deletions internal/configs/configurator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func createTestStaticConfigParams() *StaticConfigParams {
NginxStatusAllowCIDRs: []string{"127.0.0.1"},
NginxStatusPort: 8080,
StubStatusOverUnixSocketForOSS: false,
NginxVersion: nginx.NewVersion("nginx version: nginx/1.25.3 (nginx-plus-r31)"),
}
}

Expand Down Expand Up @@ -53,6 +54,7 @@ func createTestConfigurator(t *testing.T) *Configurator {
IsWildcardEnabled: false,
IsPrometheusEnabled: false,
IsLatencyMetricsEnabled: false,
NginxVersion: nginx.NewVersion("nginx version: nginx/1.25.3 (nginx-plus-r31)"),
})
cnf.isReloadsEnabled = true
return cnf
Expand Down
3 changes: 3 additions & 0 deletions internal/configs/version1/config.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package version1

import "github.com/nginxinc/kubernetes-ingress/internal/nginx"

// UpstreamLabels describes the Prometheus labels for an NGINX upstream.
type UpstreamLabels struct {
Service string
Expand Down Expand Up @@ -234,6 +236,7 @@ type MainConfig struct {
OIDC bool
DynamicSSLReloadEnabled bool
StaticSSLPath string
NginxVersion nginx.Version
}

// NewUpstreamWithDefaultServer creates an upstream with the default server.
Expand Down
6 changes: 6 additions & 0 deletions internal/configs/version1/nginx-plus.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -346,3 +346,9 @@ stream {

include /etc/nginx/stream-conf.d/*.conf;
}

{{- if (.NginxVersion.PlusGreaterThanOrEqualTo "nginx-plus-r31") }}
mgmt {
usage_report interval=0s;
}
{{- end}}
49 changes: 49 additions & 0 deletions internal/configs/version1/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"strings"
"testing"
"text/template"

"github.com/nginxinc/kubernetes-ingress/internal/nginx"
)

func TestExecuteMainTemplateForNGINXPlus(t *testing.T) {
Expand All @@ -20,6 +22,19 @@ func TestExecuteMainTemplateForNGINXPlus(t *testing.T) {
t.Log(buf.String())
}

func TestExecuteMainTemplateForNGINXPlusR31(t *testing.T) {
t.Parallel()

tmpl := newNGINXPlusMainTmpl(t)
buf := &bytes.Buffer{}

err := tmpl.Execute(buf, mainCfgR31)
if err != nil {
t.Error(err)
}
t.Log(buf.String())
}

func TestExecuteMainTemplateForNGINX(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -1291,6 +1306,33 @@ var (
KeepaliveRequests: 100,
VariablesHashBucketSize: 256,
VariablesHashMaxSize: 1024,
NginxVersion: nginx.NewVersion("nginx version: nginx/1.25.3 (nginx-plus-r31)"),
}

mainCfgR31 = MainConfig{
DefaultHTTPListenerPort: 80,
DefaultHTTPSListenerPort: 443,
ServerNamesHashMaxSize: "512",
ServerTokens: "off",
WorkerProcesses: "auto",
WorkerCPUAffinity: "auto",
WorkerShutdownTimeout: "1m",
WorkerConnections: "1024",
WorkerRlimitNofile: "65536",
LogFormat: []string{"$remote_addr", "$remote_user"},
LogFormatEscaping: "default",
StreamSnippets: []string{"# comment"},
StreamLogFormat: []string{"$remote_addr", "$remote_user"},
StreamLogFormatEscaping: "none",
ResolverAddresses: []string{"example.com", "127.0.0.1"},
ResolverIPV6: false,
ResolverValid: "10s",
ResolverTimeout: "15s",
KeepaliveTimeout: "65s",
KeepaliveRequests: 100,
VariablesHashBucketSize: 256,
VariablesHashMaxSize: 1024,
NginxVersion: nginx.NewVersion("nginx version: nginx/1.25.3 (nginx-plus-r31)"),
}

mainCfgHTTP2On = MainConfig{
Expand All @@ -1317,6 +1359,7 @@ var (
KeepaliveRequests: 100,
VariablesHashBucketSize: 256,
VariablesHashMaxSize: 1024,
NginxVersion: nginx.NewVersion("nginx version: nginx/1.25.3 (nginx-plus-r31)"),
}

mainCfgCustomTLSPassthroughPort = MainConfig{
Expand All @@ -1342,6 +1385,7 @@ var (
VariablesHashMaxSize: 1024,
TLSPassthrough: true,
TLSPassthroughPort: 8443,
NginxVersion: nginx.NewVersion("nginx version: nginx/1.25.3 (nginx-plus-r31)"),
}

mainCfgWithoutTLSPassthrough = MainConfig{
Expand All @@ -1367,6 +1411,7 @@ var (
VariablesHashMaxSize: 1024,
TLSPassthrough: false,
TLSPassthroughPort: 8443,
NginxVersion: nginx.NewVersion("nginx version: nginx/1.25.3 (nginx-plus-r31)"),
}

mainCfgDefaultTLSPassthroughPort = MainConfig{
Expand All @@ -1392,6 +1437,7 @@ var (
VariablesHashMaxSize: 1024,
TLSPassthrough: true,
TLSPassthroughPort: 443,
NginxVersion: nginx.NewVersion("nginx version: nginx/1.25.3 (nginx-plus-r31)"),
}

mainCfgCustomDefaultHTTPAndHTTPSListenerPorts = MainConfig{
Expand All @@ -1417,6 +1463,7 @@ var (
KeepaliveRequests: 100,
VariablesHashBucketSize: 256,
VariablesHashMaxSize: 1024,
NginxVersion: nginx.NewVersion("nginx version: nginx/1.25.3 (nginx-plus-r31)"),
}

mainCfgCustomDefaultHTTPListenerPort = MainConfig{
Expand All @@ -1442,6 +1489,7 @@ var (
KeepaliveRequests: 100,
VariablesHashBucketSize: 256,
VariablesHashMaxSize: 1024,
NginxVersion: nginx.NewVersion("nginx version: nginx/1.25.3 (nginx-plus-r31)"),
}

mainCfgCustomDefaultHTTPSListenerPort = MainConfig{
Expand All @@ -1467,6 +1515,7 @@ var (
KeepaliveRequests: 100,
VariablesHashBucketSize: 256,
VariablesHashMaxSize: 1024,
NginxVersion: nginx.NewVersion("nginx version: nginx/1.25.3 (nginx-plus-r31)"),
}

// Vars for Mergable Ingress Master - Minion tests
Expand Down
4 changes: 2 additions & 2 deletions internal/nginx/fake_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ func (fm *FakeManager) CreateDHParam(_ string) (string, error) {
}

// Version provides a fake implementation of Version.
func (*FakeManager) Version() string {
func (*FakeManager) Version() Version {
glog.V(3).Info("Printing nginx version")
return "fake version plus"
return Version{}
}

// Start provides a fake implementation of Start.
Expand Down
97 changes: 94 additions & 3 deletions internal/nginx/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os/exec"
"path"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -46,6 +47,19 @@ const (
appProtectDosAgentStartDebugCmd = "/usr/bin/admd -d --standalone --log debug"
)

var (
re = regexp.MustCompile(`(?P<name>\S+)/(?P<version>\S+)`)
plusre = regexp.MustCompile(`(?P<name>\S+)/(?P<version>\S+).\((?P<plus>\S+plus\S+)\)`)
)

// Version holds the parsed output from `nginx -v`
type Version struct {
raw string
OSS string
IsPlus bool
Plus string
}

// ServerConfig holds the config data for an upstream server in NGINX Plus.
type ServerConfig struct {
MaxFails int
Expand All @@ -72,7 +86,7 @@ type Manager interface {
CreateDHParam(content string) (string, error)
CreateOpenTracingTracerConfig(content string) error
Start(done chan error)
Version() string
Version() Version
Reload(isEndpointsUpdate bool) error
Quit()
UpdateConfigVersionFile(openTracing bool)
Expand Down Expand Up @@ -334,13 +348,13 @@ func (lm *LocalManager) Quit() {
}

// Version returns NGINX version
func (lm *LocalManager) Version() string {
func (lm *LocalManager) Version() Version {
binaryFilename := getBinaryFileName(lm.debug)
out, err := exec.Command(binaryFilename, "-v").CombinedOutput()
if err != nil {
glog.Fatalf("Failed to get nginx version: %v", err)
}
return string(out)
return NewVersion(string(out))
}

// UpdateConfigVersionFile writes the config version file.
Expand Down Expand Up @@ -432,6 +446,83 @@ func (lm *LocalManager) CreateOpenTracingTracerConfig(content string) error {
return nil
}

// Return the raw Nginx version string from `nginx -v`
func (v *Version) String() string {
return v.raw
}

// PlusGreaterThanOrEqualTo compares the supplied nginx-plus version string with the Version{} struct
func (v Version) PlusGreaterThanOrEqualTo(target string) (bool, error) {
r, p, err := extractPlusVersionValues(v.String())
if err != nil {
return false, err
}
tr, tp, err := extractPlusVersionValues(target)
if err != nil {
return false, err
}

return (r > tr || (r == tr && p >= tp)), nil
}

// NewVersion will take the output from `nginx -v` and explodes it into the `nginx.Version` struct
func NewVersion(line string) Version {
matches := re.FindStringSubmatch(line)
plusmatches := plusre.FindStringSubmatch(line)
nv := Version{
raw: line,
}

if len(plusmatches) > 0 {
subNames := plusre.SubexpNames()
nv.IsPlus = true
for i, v := range plusmatches {
switch subNames[i] {
case "plus":
nv.Plus = v
case "version":
nv.OSS = v
}
}
}

if len(matches) > 0 {
for i, key := range re.SubexpNames() {
val := matches[i]
if key == "version" {
nv.OSS = val
}
}
}

return nv
}

// extractPlusVersionValues
func extractPlusVersionValues(input string) (int, int, error) {
var rValue, pValue int
re := regexp.MustCompile(`-r(\d+)(?:-p(\d+))?`)
matches := re.FindStringSubmatch(input)

if len(matches) < 2 {
return 0, 0, fmt.Errorf("no matches found in the input string")
}

rValue, err := strconv.Atoi(matches[1])
if err != nil {
return 0, 0, fmt.Errorf("failed to convert rValue to integer: %w", err)
}

if len(matches) > 2 && len(matches[2]) > 0 {
pValue, err = strconv.Atoi(matches[2])
if err != nil {
return 0, 0, fmt.Errorf("failed to convert pValue to integer: %w", err)
}
}

return rValue, pValue, nil
}

// verifyConfigVersion is used to check if the worker process that the API client is connected
// to is using the latest version of nginx config. This way we avoid making changes on
// a worker processes that is being shut down.
Expand Down
Loading