Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write deployment context in init container #2905

Merged
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
1 change: 1 addition & 0 deletions charts/nginx-gateway-fabric/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ data:
ssl_certificate_key /etc/nginx/certs-bootstrap/tls.key;
{{- end }}
enforce_initial_report off;
deployment_context /etc/nginx/main-includes/deployment_ctx.json;
}
{{- end }}
14 changes: 12 additions & 2 deletions charts/nginx-gateway-fabric/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,26 @@ spec:
{{- toYaml .Values.topologySpreadConstraints | nindent 8 }}
{{- end }}
initContainers:
- name: copy-nginx-config
- name: init
image: {{ .Values.nginxGateway.image.repository }}:{{ default .Chart.AppVersion .Values.nginxGateway.image.tag }}
imagePullPolicy: {{ .Values.nginxGateway.image.pullPolicy }}
command:
- /usr/bin/gateway
- copy
- initialize
- --source
- /includes/main.conf
{{- if .Values.nginx.plus }}
- --source
- /includes/mgmt.conf
- --nginx-plus
{{- end }}
- --destination
- /etc/nginx/main-includes
env:
- name: POD_UID
valueFrom:
fieldRef:
fieldPath: metadata.uid
securityContext:
seccompProfile:
type: RuntimeDefault
Expand Down Expand Up @@ -132,6 +138,10 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_UID
valueFrom:
fieldRef:
fieldPath: metadata.uid
image: {{ .Values.nginxGateway.image.repository }}:{{ default .Chart.AppVersion .Values.nginxGateway.image.tag }}
imagePullPolicy: {{ .Values.nginxGateway.image.pullPolicy }}
name: nginx-gateway
Expand Down
160 changes: 105 additions & 55 deletions cmd/gateway/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"runtime/debug"
"strconv"
"time"
Expand All @@ -16,14 +14,20 @@
"k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/klog/v2"
ctlr "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
ctlrZap "sigs.k8s.io/controller-runtime/pkg/log/zap"

"github.com/nginxinc/nginx-gateway-fabric/internal/mode/provisioner"
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static"
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/config"
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/licensing"
ngxConfig "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/config"
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/file"
)

// These flags are shared by multiple commands.
const (
domain = "gateway.nginx.org"
gatewayClassFlag = "gatewayclass"
Expand All @@ -32,6 +36,7 @@
gatewayCtlrNameFlag = "gateway-ctlr-name"
gatewayCtlrNameUsageFmt = `The name of the Gateway controller. ` +
`The controller name must be of the form: DOMAIN/PATH. The controller's domain is '%s'`
plusFlag = "nginx-plus"
)

func createRootCommand() *cobra.Command {
Expand All @@ -47,7 +52,6 @@
return rootCmd
}

//nolint:gocyclo
func createStaticModeCommand() *cobra.Command {
// flag names
const (
Expand All @@ -63,7 +67,6 @@
leaderElectionDisableFlag = "leader-election-disable"
leaderElectionLockNameFlag = "leader-election-lock-name"
productTelemetryDisableFlag = "product-telemetry-disable"
plusFlag = "nginx-plus"
gwAPIExperimentalFlag = "gateway-api-experimental-features"
usageReportSecretFlag = "usage-report-secret"
usageReportEndpointFlag = "usage-report-endpoint"
Expand Down Expand Up @@ -159,21 +162,6 @@
return fmt.Errorf("error validating ports: %w", err)
}

podIP := os.Getenv("POD_IP")
if err := validateIP(podIP); err != nil {
return fmt.Errorf("error validating POD_IP environment variable: %w", err)
}

namespace := os.Getenv("POD_NAMESPACE")
if namespace == "" {
return errors.New("POD_NAMESPACE environment variable must be set")
}

podName := os.Getenv("POD_NAME")
if podName == "" {
return errors.New("POD_NAME environment variable must be set")
}

imageSource := os.Getenv("BUILD_AGENT")
if imageSource != "gha" && imageSource != "local" {
imageSource = "unknown"
Expand Down Expand Up @@ -218,6 +206,11 @@

flagKeys, flagValues := parseFlags(cmd.Flags())

podConfig, err := createGatewayPodConfig(serviceName.value)
if err != nil {
return fmt.Errorf("error creating gateway pod config: %w", err)
}

Check warning on line 212 in cmd/gateway/commands.go

View check run for this annotation

Codecov / codecov/patch

cmd/gateway/commands.go#L209-L212

Added lines #L209 - L212 were not covered by tests

conf := config.Config{
GatewayCtlrName: gatewayCtlrName.value,
ConfigName: configName.String(),
Expand All @@ -226,12 +219,7 @@
GatewayClassName: gatewayClassName.value,
GatewayNsName: gwNsName,
UpdateGatewayClassStatus: updateGCStatus,
GatewayPodConfig: config.GatewayPodConfig{
PodIP: podIP,
ServiceName: serviceName.value,
Namespace: namespace,
Name: podName,
},
GatewayPodConfig: podConfig,

Check warning on line 222 in cmd/gateway/commands.go

View check run for this annotation

Codecov / codecov/patch

cmd/gateway/commands.go#L222

Added line #L222 was not covered by tests
HealthConfig: config.HealthConfig{
Enabled: !disableHealth,
Port: healthListenPort.value,
Expand All @@ -244,7 +232,7 @@
LeaderElection: config.LeaderElectionConfig{
Enabled: !disableLeaderElection,
LockName: leaderElectionLockName.String(),
Identity: podName,
Identity: podConfig.Name,

Check warning on line 235 in cmd/gateway/commands.go

View check run for this annotation

Codecov / codecov/patch

cmd/gateway/commands.go#L235

Added line #L235 was not covered by tests
},
UsageReportConfig: usageReportConfig,
ProductTelemetryConfig: config.ProductTelemetryConfig{
Expand Down Expand Up @@ -524,29 +512,63 @@
return cmd
}

func createCopyCommand() *cobra.Command {
func createInitializeCommand() *cobra.Command {
// flag names
const srcFlag = "source"
const destFlag = "destination"

// flag values
var srcFiles []string
var dest string
var plus bool

cmd := &cobra.Command{
Use: "copy",
Short: "Copy files to another directory",
Use: "initialize",
Short: "Write initial configuration files",
RunE: func(_ *cobra.Command, _ []string) error {
if err := validateSleepArgs(srcFiles, dest); err != nil {
if err := validateCopyArgs(srcFiles, dest); err != nil {

Check warning on line 529 in cmd/gateway/commands.go

View check run for this annotation

Codecov / codecov/patch

cmd/gateway/commands.go#L529

Added line #L529 was not covered by tests
return err
}

for _, src := range srcFiles {
if err := copyFile(src, dest); err != nil {
return err
}
podUID, err := getValueFromEnv("POD_UID")
if err != nil {
return fmt.Errorf("could not get pod UID: %w", err)

Check warning on line 535 in cmd/gateway/commands.go

View check run for this annotation

Codecov / codecov/patch

cmd/gateway/commands.go#L533-L535

Added lines #L533 - L535 were not covered by tests
}

return nil
clusterCfg := ctlr.GetConfigOrDie()
k8sReader, err := client.New(clusterCfg, client.Options{})
if err != nil {
return fmt.Errorf("unable to initialize k8s client: %w", err)
}

Check warning on line 542 in cmd/gateway/commands.go

View check run for this annotation

Codecov / codecov/patch

cmd/gateway/commands.go#L538-L542

Added lines #L538 - L542 were not covered by tests

logger := ctlrZap.New()
klog.SetLogger(logger)
logger.Info(
"Starting init container",
"source filenames to copy", srcFiles,
"destination directory", dest,
"nginx-plus",
plus,
)
log.SetLogger(logger)

dcc := licensing.NewDeploymentContextCollector(licensing.DeploymentContextCollectorConfig{
K8sClientReader: k8sReader,
PodUID: podUID,
Logger: logger.WithName("deployCtxCollector"),
})

return initialize(initializeConfig{
fileManager: file.NewStdLibOSFileManager(),
fileGenerator: ngxConfig.NewGeneratorImpl(plus, nil, logger.WithName("generator")),
logger: logger,
plus: plus,
collector: dcc,
copy: copyFiles{
srcFileNames: srcFiles,
destDirName: dest,
},
})

Check warning on line 571 in cmd/gateway/commands.go

View check run for this annotation

Codecov / codecov/patch

cmd/gateway/commands.go#L544-L571

Added lines #L544 - L571 were not covered by tests
},
}

Expand All @@ -564,31 +586,18 @@
"The destination directory for the source files to be copied to",
)

cmd.Flags().BoolVar(
&plus,
plusFlag,
false,
"Use NGINX Plus",
)

cmd.MarkFlagsRequiredTogether(srcFlag, destFlag)

return cmd
}

func copyFile(src, dest string) error {
srcFile, err := os.Open(src)
if err != nil {
return fmt.Errorf("error opening source file: %w", err)
}
defer srcFile.Close()

destFile, err := os.Create(filepath.Join(dest, filepath.Base(src)))
if err != nil {
return fmt.Errorf("error creating destination file: %w", err)
}
defer destFile.Close()

if _, err := io.Copy(destFile, srcFile); err != nil {
return fmt.Errorf("error copying file contents: %w", err)
}

return nil
}

func parseFlags(flags *pflag.FlagSet) ([]string, []string) {
var flagKeys, flagValues []string

Expand Down Expand Up @@ -634,3 +643,44 @@

return
}

func createGatewayPodConfig(svcName string) (config.GatewayPodConfig, error) {
podIP, err := getValueFromEnv("POD_IP")
if err != nil {
return config.GatewayPodConfig{}, err
}

podUID, err := getValueFromEnv("POD_UID")
if err != nil {
return config.GatewayPodConfig{}, err
}

ns, err := getValueFromEnv("POD_NAMESPACE")
if err != nil {
return config.GatewayPodConfig{}, err
}

name, err := getValueFromEnv("POD_NAME")
if err != nil {
return config.GatewayPodConfig{}, err
}

c := config.GatewayPodConfig{
PodIP: podIP,
ServiceName: svcName,
Namespace: ns,
Name: name,
UID: podUID,
}

return c, nil
}

func getValueFromEnv(key string) (string, error) {
val := os.Getenv(key)
if val == "" {
return "", fmt.Errorf("environment variable %s not set", key)
}

return val, nil
}
Loading
Loading