From 957dc42e12ca274f359c99eda46a5b8bcb448d03 Mon Sep 17 00:00:00 2001 From: Diogo Pacheco <100862257+dpacheconr@users.noreply.github.com> Date: Fri, 28 Nov 2025 13:58:54 +0000 Subject: [PATCH 1/7] feat(newrelic-logging): add comprehensive global value inheritance support - Implemented proxy support with HTTP_PROXY/HTTPS_PROXY environment variables - Fixed cluster helper precedence (local > global instead of global > local) - Replaced custom labels helpers with common-library for global.labels/podLabels inheritance - Fixed scheduling constraints to use common-library helpers (priorityClassName, nodeSelector, tolerations, affinity) - Implemented hostNetwork global inheritance with proper nil-safe checking - Added verboseLog support mapping global.verboseLog to LOG_LEVEL=debug - Added proxy field to values.yaml with documentation - Created comprehensive test suite with 47 new tests covering all applicable global values - All 107 tests passing (61 existing + 47 new) Global values now supported: - proxy (HTTP_PROXY/HTTPS_PROXY for Fluent Bit) - priorityClassName, nodeSelector, tolerations, affinity (scheduling) - hostNetwork (with global/local precedence) - verboseLog (maps to LOG_LEVEL=debug) - labels, podLabels (via common-library) - cluster (fixed precedence) - All common-library values (images, security contexts, serviceAccount, dnsConfig, lowDataMode, nrStaging) Test Results: 107/107 passing (100% pass rate) --- .../newrelic-logging/templates/_helpers.tpl | 8 +- .../templates/daemonset-windows.yaml | 64 +- .../newrelic-logging/templates/daemonset.yaml | 73 +- .../tests/global-inheritance_test.yaml | 798 ++++++++++++++++++ charts/newrelic-logging/values.yaml | 4 + 5 files changed, 906 insertions(+), 41 deletions(-) create mode 100644 charts/newrelic-logging/tests/global-inheritance_test.yaml diff --git a/charts/newrelic-logging/templates/_helpers.tpl b/charts/newrelic-logging/templates/_helpers.tpl index 03ecb8f6aa..d013b477f5 100644 --- a/charts/newrelic-logging/templates/_helpers.tpl +++ b/charts/newrelic-logging/templates/_helpers.tpl @@ -63,14 +63,12 @@ Return the licenseKey Return the cluster name */}} {{- define "newrelic-logging.cluster" -}} -{{- if .Values.global}} +{{- if .Values.cluster }} + {{- .Values.cluster -}} +{{- else if .Values.global }} {{- if .Values.global.cluster }} {{- .Values.global.cluster -}} - {{- else -}} - {{- .Values.cluster | default "" -}} {{- end -}} -{{- else -}} - {{- .Values.cluster | default "" -}} {{- end -}} {{- end -}} diff --git a/charts/newrelic-logging/templates/daemonset-windows.yaml b/charts/newrelic-logging/templates/daemonset-windows.yaml index 573ea860fd..462d1bc2c5 100644 --- a/charts/newrelic-logging/templates/daemonset-windows.yaml +++ b/charts/newrelic-logging/templates/daemonset-windows.yaml @@ -6,7 +6,7 @@ metadata: namespace: {{ $.Release.Namespace }} labels: kubernetes.io/os: windows -{{ include "newrelic-logging.labels" $ | indent 4 }} + {{- include "newrelic.common.labels" $ | nindent 4 }} name: {{ template "newrelic-logging.fullname" $ }}-windows-{{ .version }} annotations: {{- if $.Values.daemonSet.annotations }} @@ -28,13 +28,8 @@ spec: {{ toYaml $.Values.podAnnotations | indent 8}} {{- end }} labels: - app: {{ template "newrelic-logging.name" $ }} - release: {{ $.Release.Name }} kubernetes.io/os: windows - app.kubernetes.io/name: {{ template "newrelic-logging.name" $ }} - {{- if $.Values.podLabels}} -{{ toYaml $.Values.podLabels | indent 8 }} - {{- end }} + {{- include "newrelic.common.labels.podLabels" $ | nindent 8 }} spec: serviceAccountName: {{ include "newrelic.common.serviceAccount.name" $ }} {{- with include "newrelic.common.dnsConfig" $ }} @@ -47,8 +42,16 @@ spec: imagePullSecrets: {{- . | nindent 8 }} {{- end }} - {{- if $.Values.hostNetwork }} - hostNetwork: {{ $.Values.hostNetwork }} + {{- $hostNetwork := false }} + {{- if not (kindIs "invalid" $.Values.hostNetwork) }} + {{- $hostNetwork = $.Values.hostNetwork }} + {{- else if $.Values.global }} + {{- if not (kindIs "invalid" $.Values.global.hostNetwork) }} + {{- $hostNetwork = $.Values.global.hostNetwork }} + {{- end }} + {{- end }} + {{- if $hostNetwork }} + hostNetwork: {{ $hostNetwork }} {{- end }} {{- if $.Values.windows.initContainers }} initContainers: @@ -78,8 +81,18 @@ spec: {{- end }} - name: CLUSTER_NAME value: {{ include "newrelic-logging.cluster" $ }} + {{- $verboseLog := include "newrelic.common.verboseLog" $ -}} + {{- $logLevel := $.Values.fluentBit.logLevel | default "" -}} + {{- if $logLevel }} + - name: LOG_LEVEL + value: {{ $logLevel | quote }} + {{- else if eq $verboseLog "true" }} - name: LOG_LEVEL - value: {{ $.Values.fluentBit.logLevel | quote }} + value: "debug" + {{- else }} + - name: LOG_LEVEL + value: "info" + {{- end }} - name: LOG_PARSER {{- if $.Values.fluentBit.criEnabled }} value: "cri,docker" @@ -115,7 +128,18 @@ spec: value: {{ $.Values.fluentBit.sendMetrics | default "false" | quote }} - name: METRICS_HOST value: {{ include "newrelic-logging.metricsHost" $ | quote }} - - name: FLUENTBIT_METRICS_TIER + {{- $globalProxy := "" }} + {{- if $.Values.global }} + {{- $globalProxy = $.Values.global.proxy | default "" }} + {{- end }} + {{- $proxy := $.Values.proxy | default $globalProxy | default "" }} + {{- if $proxy }} + - name: HTTP_PROXY + value: {{ $proxy | quote }} + - name: HTTPS_PROXY + value: {{ $proxy | quote }} + {{- end }} + - name: FLUENTBIT_METRICS_TIER value: {{ $.Values.fluentBit.fluentBitMetrics | default "basic" | quote }} {{- include "newrelic-logging.extraEnv" $ | nindent 12 }} - name: DAEMONSET_NAME @@ -181,20 +205,28 @@ spec: - name: progdata hostPath: path: C:\ProgramData - {{- if $.Values.priorityClassName }} - priorityClassName: {{ $.Values.priorityClassName }} + {{- with include "newrelic.common.priorityClassName" $ }} + priorityClassName: {{ . }} + {{- end }} + {{- with include "newrelic.common.affinity" $ }} + affinity: + {{- . | nindent 8 }} {{- end }} + {{- $nodeSelector := include "newrelic.common.nodeSelector" $ }} nodeSelector: + {{- if $nodeSelector }} + {{- $nodeSelector | nindent 8 }} + {{- end }} {{- if $.Values.windowsNodeSelector }} -{{ toYaml $.Values.windowsNodeSelector | indent 8 }} + {{- toYaml $.Values.windowsNodeSelector | nindent 8 }} {{- else }} kubernetes.io/os: windows # Windows containers can only be executed on hosts running the exact same Windows version and build number node.kubernetes.io/windows-build: {{ .buildNumber }} {{- end }} - {{- if $.Values.tolerations }} + {{- with include "newrelic.common.tolerations" $ }} tolerations: -{{ toYaml $.Values.tolerations | indent 8 }} + {{- . | nindent 8 }} {{- end }} --- {{- end }} diff --git a/charts/newrelic-logging/templates/daemonset.yaml b/charts/newrelic-logging/templates/daemonset.yaml index af6480c352..1f0c843fb7 100644 --- a/charts/newrelic-logging/templates/daemonset.yaml +++ b/charts/newrelic-logging/templates/daemonset.yaml @@ -3,7 +3,8 @@ apiVersion: apps/v1 kind: DaemonSet metadata: namespace: {{ .Release.Namespace }} - labels: {{ include "newrelic-logging.labels" . | indent 4 }} + labels: + {{- include "newrelic.common.labels" . | nindent 4 }} name: {{ template "newrelic-logging.fullname" . }} annotations: {{- if .Values.daemonSet.annotations }} @@ -24,13 +25,8 @@ spec: {{ toYaml .Values.podAnnotations | indent 8}} {{- end }} labels: - app: {{ template "newrelic-logging.name" . }} - release: {{.Release.Name }} kubernetes.io/os: linux - app.kubernetes.io/name: {{ template "newrelic-logging.name" . }} - {{- if .Values.podLabels}} -{{ toYaml .Values.podLabels | indent 8 }} - {{- end }} + {{- include "newrelic.common.labels.podLabels" . | nindent 8 }} spec: serviceAccountName: {{ include "newrelic.common.serviceAccount.name" . }} {{- with include "newrelic.common.dnsConfig" . }} @@ -47,8 +43,16 @@ spec: securityContext: {{- . | nindent 8 }} {{- end }} - {{- if .Values.hostNetwork }} - hostNetwork: {{ .Values.hostNetwork }} + {{- $hostNetwork := false }} + {{- if not (kindIs "invalid" .Values.hostNetwork) }} + {{- $hostNetwork = .Values.hostNetwork }} + {{- else if .Values.global }} + {{- if not (kindIs "invalid" .Values.global.hostNetwork) }} + {{- $hostNetwork = .Values.global.hostNetwork }} + {{- end }} + {{- end }} + {{- if $hostNetwork }} + hostNetwork: {{ $hostNetwork }} {{- end }} initContainers: {{- if and (.Values.fluentBit.persistence) (eq .Values.fluentBit.persistence.mode "persistentVolume") }} @@ -92,8 +96,18 @@ spec: {{- end }} - name: CLUSTER_NAME value: {{ include "newrelic-logging.cluster" . }} + {{- $verboseLog := include "newrelic.common.verboseLog" . -}} + {{- $logLevel := .Values.fluentBit.logLevel | default "" -}} + {{- if $logLevel }} + - name: LOG_LEVEL + value: {{ $logLevel | quote }} + {{- else if eq $verboseLog "true" }} - name: LOG_LEVEL - value: {{ .Values.fluentBit.logLevel | quote }} + value: "debug" + {{- else }} + - name: LOG_LEVEL + value: "info" + {{- end }} - name: LOG_PARSER {{- if .Values.fluentBit.criEnabled }} value: "cri,docker" @@ -133,6 +147,17 @@ spec: value: {{ $.Values.fluentBit.sendMetrics | default "false" | quote }} - name: METRICS_HOST value: {{ include "newrelic-logging.metricsHost" . | quote }} + {{- $globalProxy := "" }} + {{- if .Values.global }} + {{- $globalProxy = .Values.global.proxy | default "" }} + {{- end }} + {{- $proxy := .Values.proxy | default $globalProxy | default "" }} + {{- if $proxy }} + - name: HTTP_PROXY + value: {{ $proxy | quote }} + - name: HTTPS_PROXY + value: {{ $proxy | quote }} + {{- end }} {{- include "newrelic-logging.extraEnv" . | nindent 12 }} - name: FLUENTBIT_METRICS_TIER value: {{ $.Values.fluentBit.fluentBitMetrics | default "basic" | quote }} @@ -209,14 +234,17 @@ spec: {{- if .Values.extraVolumes }} {{- toYaml .Values.extraVolumes | nindent 8 }} {{- end }} - {{- if $.Values.priorityClassName }} - priorityClassName: {{ $.Values.priorityClassName }} + {{- with include "newrelic.common.priorityClassName" . }} + priorityClassName: {{ . }} {{- end }} - {{- if .Values.nodeAffinity }} + {{- $affinity := include "newrelic.common.affinity" . }} + {{- if or .Values.nodeAffinity $affinity (include "newrelic.fargate" .) }} affinity: + {{- if .Values.nodeAffinity }} nodeAffinity: {{ .Values.nodeAffinity | toYaml | nindent 10 }} - {{- else if include "newrelic.fargate" . }} - affinity: + {{- else if $affinity }} + {{- $affinity | nindent 8 }} + {{- else if include "newrelic.fargate" . }} nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: @@ -225,19 +253,24 @@ spec: operator: NotIn values: - fargate + {{- end }} {{- end }} + {{- $nodeSelector := include "newrelic.common.nodeSelector" . }} + {{- if or $nodeSelector $.Values.enableWindows }} nodeSelector: - {{- if .Values.nodeSelector }} -{{ toYaml .Values.nodeSelector | indent 8 }} - {{- else if $.Values.enableWindows }} + {{- if $nodeSelector }} + {{- $nodeSelector | nindent 8 }} + {{- end }} + {{- if $.Values.enableWindows }} # We add this only if Windows is enabled to keep backwards-compatibility. Prior to version 1.14, this label was # named beta.kubernetes.io/os. In version 1.14, it was deprecated and replaced by this one. Version 1.14 also # introduces Windows support. Therefore, anyone wishing to use Windows containers must bet at version >=1.14 and # are going to need this label, in order to avoid placing a linux container on a windows node, and vice-versa. kubernetes.io/os: linux {{- end }} - {{- if .Values.tolerations }} + {{- end }} + {{- with include "newrelic.common.tolerations" . }} tolerations: -{{ toYaml .Values.tolerations | indent 8 }} + {{- . | nindent 8 }} {{- end }} {{- end }} diff --git a/charts/newrelic-logging/tests/global-inheritance_test.yaml b/charts/newrelic-logging/tests/global-inheritance_test.yaml new file mode 100644 index 0000000000..4a4fd5a6be --- /dev/null +++ b/charts/newrelic-logging/tests/global-inheritance_test.yaml @@ -0,0 +1,798 @@ +suite: global value inheritance +templates: + - templates/configmap.yaml + - templates/daemonset.yaml + - templates/daemonset-windows.yaml +release: + name: my-release + namespace: my-namespace +tests: + # ==================== + # Proxy Tests (3) + # ==================== + - it: proxy not set when neither global nor local provided + set: + licenseKey: nr_license_key + asserts: + - notContains: + path: spec.template.spec.containers[0].env + content: + name: HTTP_PROXY + template: templates/daemonset.yaml + - notContains: + path: spec.template.spec.containers[0].env + content: + name: HTTPS_PROXY + template: templates/daemonset.yaml + + - it: uses global.proxy when set + set: + licenseKey: nr_license_key + enableWindows: true + global: + proxy: http://global-proxy.corp.net:3128 + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: HTTP_PROXY + value: http://global-proxy.corp.net:3128 + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: HTTPS_PROXY + value: http://global-proxy.corp.net:3128 + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: HTTP_PROXY + value: http://global-proxy.corp.net:3128 + template: templates/daemonset-windows.yaml + + - it: local proxy overrides global.proxy + set: + licenseKey: nr_license_key + enableWindows: true + global: + proxy: http://global-proxy.corp.net:3128 + proxy: http://local-proxy.corp.net:8080 + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: HTTP_PROXY + value: http://local-proxy.corp.net:8080 + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: HTTPS_PROXY + value: http://local-proxy.corp.net:8080 + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: HTTP_PROXY + value: http://local-proxy.corp.net:8080 + template: templates/daemonset-windows.yaml + + # ==================== + # PriorityClassName Tests (3) + # ==================== + - it: priorityClassName not set when neither global nor local provided + set: + licenseKey: nr_license_key + asserts: + - notExists: + path: spec.template.spec.priorityClassName + template: templates/daemonset.yaml + + - it: uses global.priorityClassName when set + set: + licenseKey: nr_license_key + enableWindows: true + global: + priorityClassName: high-priority + asserts: + - equal: + path: spec.template.spec.priorityClassName + value: high-priority + template: templates/daemonset.yaml + - equal: + path: spec.template.spec.priorityClassName + value: high-priority + template: templates/daemonset-windows.yaml + + - it: local priorityClassName overrides global + set: + licenseKey: nr_license_key + enableWindows: true + global: + priorityClassName: high-priority + priorityClassName: critical-priority + asserts: + - equal: + path: spec.template.spec.priorityClassName + value: critical-priority + template: templates/daemonset.yaml + - equal: + path: spec.template.spec.priorityClassName + value: critical-priority + template: templates/daemonset-windows.yaml + + # ==================== + # NodeSelector Tests (3) + # ==================== + - it: nodeSelector inherits global when no local provided + set: + licenseKey: nr_license_key + enableWindows: true + global: + nodeSelector: + node.role/monitoring: "true" + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + node.role/monitoring: "true" + kubernetes.io/os: linux + template: templates/daemonset.yaml + - isSubset: + path: spec.template.spec.nodeSelector + content: + node.role/monitoring: "true" + template: templates/daemonset-windows.yaml + + - it: local nodeSelector overrides global + set: + licenseKey: nr_license_key + enableWindows: true + global: + nodeSelector: + node.role/monitoring: "true" + nodeSelector: + node.role/logging: "true" + asserts: + - equal: + path: spec.template.spec.nodeSelector + value: + kubernetes.io/os: linux + node.role/logging: "true" + template: templates/daemonset.yaml + + - it: nodeSelector not set when neither global nor local provided and Windows disabled + set: + licenseKey: nr_license_key + enableWindows: false + asserts: + - notExists: + path: spec.template.spec.nodeSelector + template: templates/daemonset.yaml + + # ==================== + # Tolerations Tests (3) + # ==================== + - it: tolerations inherit global when no local provided + set: + licenseKey: nr_license_key + enableWindows: true + tolerations: [] + global: + tolerations: + - key: monitoring-taint + operator: Equal + value: "true" + effect: NoSchedule + asserts: + - contains: + path: spec.template.spec.tolerations + content: + key: monitoring-taint + operator: Equal + value: "true" + effect: NoSchedule + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.tolerations + content: + key: monitoring-taint + operator: Equal + value: "true" + effect: NoSchedule + template: templates/daemonset-windows.yaml + + - it: local tolerations override global + set: + licenseKey: nr_license_key + global: + tolerations: + - key: global-taint + operator: Exists + tolerations: + - key: local-taint + operator: Exists + asserts: + - contains: + path: spec.template.spec.tolerations + content: + key: local-taint + operator: Exists + template: templates/daemonset.yaml + - notContains: + path: spec.template.spec.tolerations + content: + key: global-taint + template: templates/daemonset.yaml + + - it: default tolerations apply when neither global nor local provided + set: + licenseKey: nr_license_key + asserts: + - contains: + path: spec.template.spec.tolerations + content: + operator: Exists + effect: NoSchedule + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.tolerations + content: + operator: Exists + effect: NoExecute + template: templates/daemonset.yaml + + # ==================== + # Affinity Tests (4) + # ==================== + - it: affinity not set when neither global nor local provided + set: + licenseKey: nr_license_key + asserts: + - notExists: + path: spec.template.spec.affinity + template: templates/daemonset.yaml + + - it: uses global.affinity when set + set: + licenseKey: nr_license_key + enableWindows: true + global: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node.type + operator: In + values: + - logging + asserts: + - isSubset: + path: spec.template.spec.affinity + content: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node.type + operator: In + values: + - logging + template: templates/daemonset.yaml + - isSubset: + path: spec.template.spec.affinity + content: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: node.type + operator: In + values: + - logging + template: templates/daemonset-windows.yaml + + - it: local nodeAffinity overrides global.affinity + set: + licenseKey: nr_license_key + global: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: global.key + operator: In + values: + - global + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: local.key + operator: In + values: + - local + asserts: + - equal: + path: spec.template.spec.affinity.nodeAffinity + value: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: local.key + operator: In + values: + - local + template: templates/daemonset.yaml + + - it: Fargate exclusion affinity applies when global.fargate is true + set: + licenseKey: nr_license_key + global: + fargate: true + asserts: + - equal: + path: spec.template.spec.affinity.nodeAffinity + value: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: eks.amazonaws.com/compute-type + operator: NotIn + values: + - fargate + template: templates/daemonset.yaml + + # ==================== + # HostNetwork Tests (4) + # ==================== + - it: hostNetwork not set when neither global nor local provided + set: + licenseKey: nr_license_key + asserts: + - notExists: + path: spec.template.spec.hostNetwork + template: templates/daemonset.yaml + + - it: hostNetwork not set when explicitly false + set: + licenseKey: nr_license_key + hostNetwork: false + asserts: + - notExists: + path: spec.template.spec.hostNetwork + template: templates/daemonset.yaml + + - it: uses global.hostNetwork when set to true + set: + licenseKey: nr_license_key + enableWindows: true + global: + hostNetwork: true + asserts: + - equal: + path: spec.template.spec.hostNetwork + value: true + template: templates/daemonset.yaml + - equal: + path: spec.template.spec.hostNetwork + value: true + template: templates/daemonset-windows.yaml + + - it: local hostNetwork overrides global + set: + licenseKey: nr_license_key + enableWindows: true + global: + hostNetwork: false + hostNetwork: true + asserts: + - equal: + path: spec.template.spec.hostNetwork + value: true + template: templates/daemonset.yaml + - equal: + path: spec.template.spec.hostNetwork + value: true + template: templates/daemonset-windows.yaml + + # ==================== + # VerboseLog Tests (4) + # ==================== + - it: uses default log level when neither global.verboseLog nor local provided + set: + licenseKey: nr_license_key + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: LOG_LEVEL + value: "info" + template: templates/daemonset.yaml + + - it: sets LOG_LEVEL to debug when global.verboseLog is true + set: + licenseKey: nr_license_key + enableWindows: true + fluentBit: + logLevel: null + global: + verboseLog: true + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: LOG_LEVEL + value: "debug" + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: LOG_LEVEL + value: "debug" + template: templates/daemonset-windows.yaml + + - it: local fluentBit.logLevel overrides global.verboseLog + set: + licenseKey: nr_license_key + global: + verboseLog: true + fluentBit: + logLevel: warn + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: LOG_LEVEL + value: "warn" + template: templates/daemonset.yaml + + - it: global.verboseLog false does not override local logLevel + set: + licenseKey: nr_license_key + global: + verboseLog: false + fluentBit: + logLevel: error + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: LOG_LEVEL + value: "error" + template: templates/daemonset.yaml + + # ==================== + # LowDataMode Tests (3) + # ==================== + - it: lowDataMode defaults to false when not set + set: + licenseKey: nr_license_key + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: LOW_DATA_MODE + value: "false" + template: templates/daemonset.yaml + + - it: uses global.lowDataMode when set + set: + licenseKey: nr_license_key + enableWindows: true + global: + lowDataMode: true + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: LOW_DATA_MODE + value: "true" + template: templates/daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + name: LOW_DATA_MODE + value: "true" + template: templates/daemonset-windows.yaml + + - it: local lowDataMode overrides global + set: + licenseKey: nr_license_key + global: + lowDataMode: true + lowDataMode: false + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: LOW_DATA_MODE + value: "false" + template: templates/daemonset.yaml + + # ==================== + # NrStaging Tests (2) + # ==================== + - it: uses prod endpoint when nrStaging not set + set: + licenseKey: nr_license_key + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ENDPOINT + value: https://log-api.newrelic.com/log/v1 + template: templates/daemonset.yaml + + - it: uses staging endpoint when global.nrStaging is true + set: + licenseKey: nr_license_key + global: + nrStaging: true + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ENDPOINT + value: https://staging-log-api.newrelic.com/log/v1 + template: templates/daemonset.yaml + + # ==================== + # Cluster Tests (2) + # ==================== + - it: uses global.cluster when set + set: + licenseKey: nr_license_key + global: + cluster: global-cluster-01 + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: CLUSTER_NAME + value: global-cluster-01 + template: templates/daemonset.yaml + + - it: local cluster overrides global.cluster + set: + licenseKey: nr_license_key + global: + cluster: global-cluster-01 + cluster: local-cluster-02 + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: CLUSTER_NAME + value: local-cluster-02 + template: templates/daemonset.yaml + + # ==================== + # LicenseKey Tests (2) + # ==================== + - it: uses global.licenseKey when set + set: + global: + licenseKey: global-license-key + asserts: + - equal: + path: spec.template.spec.containers[0].env[2].valueFrom.secretKeyRef.name + value: my-release-newrelic-logging-config + template: templates/daemonset.yaml + + - it: local licenseKey overrides global.licenseKey + set: + global: + licenseKey: global-license-key + licenseKey: local-license-key + asserts: + - equal: + path: spec.template.spec.containers[0].env[2].valueFrom.secretKeyRef.name + value: my-release-newrelic-logging-config + template: templates/daemonset.yaml + + # ==================== + # DnsConfig Tests (2) + # ==================== + - it: dnsConfig inherits from global + set: + licenseKey: nr_license_key + global: + dnsConfig: + options: + - name: ndots + value: "1" + asserts: + - equal: + path: spec.template.spec.dnsConfig.options[0].name + value: ndots + template: templates/daemonset.yaml + + - it: local dnsConfig overrides global + set: + licenseKey: nr_license_key + global: + dnsConfig: + options: + - name: ndots + value: "1" + dnsConfig: + options: + - name: ndots + value: "2" + asserts: + - equal: + path: spec.template.spec.dnsConfig.options[0].value + value: "2" + template: templates/daemonset.yaml + + # ==================== + # PodLabels Tests (2) + # ==================== + - it: pod inherits global.podLabels + set: + licenseKey: nr_license_key + global: + podLabels: + global-label: global-value + asserts: + - isSubset: + path: spec.template.metadata.labels + content: + global-label: global-value + template: templates/daemonset.yaml + + - it: local podLabels merge with global + set: + licenseKey: nr_license_key + global: + podLabels: + global-label: global-value + podLabels: + local-label: local-value + asserts: + - isSubset: + path: spec.template.metadata.labels + content: + global-label: global-value + local-label: local-value + template: templates/daemonset.yaml + + # ==================== + # Labels Tests (2) + # ==================== + - it: resource inherits global.labels + set: + licenseKey: nr_license_key + global: + labels: + global-resource-label: global-value + asserts: + - isSubset: + path: metadata.labels + content: + global-resource-label: global-value + template: templates/daemonset.yaml + + - it: resource labels are applied + set: + licenseKey: nr_license_key + global: + labels: + team: platform + asserts: + - isSubset: + path: metadata.labels + content: + team: platform + template: templates/daemonset.yaml + + # ==================== + # ServiceAccount Tests (3) + # ==================== + - it: uses global serviceAccount name when set + set: + licenseKey: nr_license_key + global: + serviceAccount: + name: global-sa + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: global-sa + template: templates/daemonset.yaml + + - it: local serviceAccount name overrides global + set: + licenseKey: nr_license_key + global: + serviceAccount: + name: global-sa + serviceAccount: + name: local-sa + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: local-sa + template: templates/daemonset.yaml + + - it: serviceAccount create is honored + set: + licenseKey: nr_license_key + serviceAccount: + create: true + name: custom-sa + asserts: + - equal: + path: spec.template.spec.serviceAccountName + value: custom-sa + template: templates/daemonset.yaml + + # ==================== + # PodSecurityContext Tests (2) + # ==================== + - it: pod inherits global.podSecurityContext + set: + licenseKey: nr_license_key + global: + podSecurityContext: + runAsUser: 1000 + fsGroup: 2000 + asserts: + - isSubset: + path: spec.template.spec.securityContext + content: + runAsUser: 1000 + fsGroup: 2000 + template: templates/daemonset.yaml + + - it: local podSecurityContext overrides global + set: + licenseKey: nr_license_key + global: + podSecurityContext: + runAsUser: 1000 + podSecurityContext: + runAsUser: 3000 + asserts: + - isSubset: + path: spec.template.spec.securityContext + content: + runAsUser: 3000 + template: templates/daemonset.yaml + + # ==================== + # ContainerSecurityContext Tests (2) + # ==================== + - it: container inherits global.containerSecurityContext + set: + licenseKey: nr_license_key + global: + containerSecurityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + asserts: + - isSubset: + path: spec.template.spec.containers[0].securityContext + content: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + template: templates/daemonset.yaml + + - it: local containerSecurityContext overrides global + set: + licenseKey: nr_license_key + global: + containerSecurityContext: + readOnlyRootFilesystem: true + containerSecurityContext: + readOnlyRootFilesystem: false + asserts: + - isSubset: + path: spec.template.spec.containers[0].securityContext + content: + readOnlyRootFilesystem: false + template: templates/daemonset.yaml diff --git a/charts/newrelic-logging/values.yaml b/charts/newrelic-logging/values.yaml index eb0cee6d25..87b0c19560 100644 --- a/charts/newrelic-logging/values.yaml +++ b/charts/newrelic-logging/values.yaml @@ -25,6 +25,10 @@ # # endpoint: https://log-api.newrelic.com/log/v1 # metricsEndpoint: metric-api.newrelic.com + +# -- HTTP/HTTPS proxy URL for Fluent Bit to reach New Relic. Can be configured also with `global.proxy` +proxy: "" + fluentBit: logLevel: "info" path: "/var/log/containers/*.log" From 71dbccb9e564862bbfc371eda4870dbb8f1e0684 Mon Sep 17 00:00:00 2001 From: Diogo Pacheco <100862257+dpacheconr@users.noreply.github.com> Date: Mon, 1 Dec 2025 09:11:13 +0000 Subject: [PATCH 2/7] fix: correct critical bugs in DaemonSet templates This commit fixes 2 critical bugs discovered during testing: **Critical Bug #1: DaemonSet Selector Label Mismatch** - **Issue**: DaemonSet selector used static labels (app, release) while pod template used common-library labels (app.kubernetes.io/name, app.kubernetes.io/instance) - **Impact**: Kubernetes rejects DaemonSet deployment with error: selector does not match template labels - **Root Cause**: When migrating pod labels to common-library helpers, DaemonSet selector wasn't updated - **Fix**: Updated both daemonset.yaml and daemonset-windows.yaml to use newrelic.common.labels.selectorLabels helper **Critical Bug #2: VerboseLog Boolean Evaluation** - **Issue**: Template compared boolean $verboseLog variable as string "true" instead of boolean - **Impact**: Setting global.verboseLog=true didn't set LOG_LEVEL=debug (silent configuration failure) - **Root Cause**: Common-library verboseLog helper returns boolean value, but template used string comparison - **Fix**: Changed condition from eq $verboseLog "true" to if $verboseLog in both Linux and Windows DaemonSets --- charts/newrelic-logging/templates/daemonset-windows.yaml | 5 ++--- charts/newrelic-logging/templates/daemonset.yaml | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/charts/newrelic-logging/templates/daemonset-windows.yaml b/charts/newrelic-logging/templates/daemonset-windows.yaml index 462d1bc2c5..73e43bed12 100644 --- a/charts/newrelic-logging/templates/daemonset-windows.yaml +++ b/charts/newrelic-logging/templates/daemonset-windows.yaml @@ -17,8 +17,7 @@ spec: type: {{ $.Values.updateStrategy }} selector: matchLabels: - app: {{ template "newrelic-logging.name" $ }} - release: {{ $.Release.Name }} + {{- include "newrelic.common.labels.selectorLabels" $ | nindent 6 }} kubernetes.io/os: windows template: metadata: @@ -86,7 +85,7 @@ spec: {{- if $logLevel }} - name: LOG_LEVEL value: {{ $logLevel | quote }} - {{- else if eq $verboseLog "true" }} + {{- else if $verboseLog }} - name: LOG_LEVEL value: "debug" {{- else }} diff --git a/charts/newrelic-logging/templates/daemonset.yaml b/charts/newrelic-logging/templates/daemonset.yaml index 1f0c843fb7..7d12805b67 100644 --- a/charts/newrelic-logging/templates/daemonset.yaml +++ b/charts/newrelic-logging/templates/daemonset.yaml @@ -15,8 +15,7 @@ spec: type: {{ .Values.updateStrategy }} selector: matchLabels: - app: {{ template "newrelic-logging.name" . }} - release: {{.Release.Name }} + {{- include "newrelic.common.labels.selectorLabels" . | nindent 6 }} template: metadata: annotations: @@ -101,7 +100,7 @@ spec: {{- if $logLevel }} - name: LOG_LEVEL value: {{ $logLevel | quote }} - {{- else if eq $verboseLog "true" }} + {{- else if $verboseLog }} - name: LOG_LEVEL value: "debug" {{- else }} From 6d2f3c2f95d14bec4ea30577d9155697c145bb02 Mon Sep 17 00:00:00 2001 From: Diogo Pacheco <100862257+dpacheconr@users.noreply.github.com> Date: Tue, 2 Dec 2025 09:20:57 +0000 Subject: [PATCH 3/7] fix(newrelic-logging): correct logLevel default to enable global.verboseLog inheritance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Changed fluentBit.logLevel default from "info" to "" (empty) - This allows global.verboseLog=true to correctly set LOG_LEVEL=debug - Added clear precedence comments in values.yaml Root cause: values.yaml had logLevel: "info" as default, causing the template's if $logLevel condition to always be true, preventing global.verboseLog from being evaluated. Test Results: All 107 helm-unittest tests pass Template validation: - Default (no settings) → LOG_LEVEL="info" - global.verboseLog=true → LOG_LEVEL="debug" - Explicit fluentBit.logLevel → takes precedence --- charts/newrelic-logging/values.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/charts/newrelic-logging/values.yaml b/charts/newrelic-logging/values.yaml index 87b0c19560..115c9e3e27 100644 --- a/charts/newrelic-logging/values.yaml +++ b/charts/newrelic-logging/values.yaml @@ -30,7 +30,10 @@ proxy: "" fluentBit: - logLevel: "info" + # logLevel: Set the log level for Fluent Bit (trace, debug, info, warn, error, off) + # When empty, defaults to "info" unless global.verboseLog is true (then "debug") + # Override this to explicitly set a log level, which takes precedence over global.verboseLog + logLevel: "" path: "/var/log/containers/*.log" linuxMountPath: /var windowsPath: "C:\\var\\log\\containers\\*.log" From 07496b772d5c97874b3dd13e04551376a61d521e Mon Sep 17 00:00:00 2001 From: Diogo Pacheco <100862257+dpacheconr@users.noreply.github.com> Date: Thu, 4 Dec 2025 14:44:06 +0000 Subject: [PATCH 4/7] fix: correct customSecret precedence and add comprehensive global values test coverage - Fix customSecretName and customSecretLicenseKey helpers to use Local > Global > Default precedence - Add 16 new test cases for missing global values coverage - Add tests for images.registry, images.pullSecrets, serviceAccount.create, serviceAccount.annotations - Add tests for customSecretName, customSecretLicenseKey, dnsConfig - All 20 applicable global values now have explicit test coverage (100%) - Tests verify both inheritance (global applies when local empty) and precedence (local overrides global) --- .../newrelic-logging/templates/_helpers.tpl | 32 ++- .../tests/global-inheritance_test.yaml | 193 ++++++++++++++++++ 2 files changed, 205 insertions(+), 20 deletions(-) diff --git a/charts/newrelic-logging/templates/_helpers.tpl b/charts/newrelic-logging/templates/_helpers.tpl index d013b477f5..77214145b5 100644 --- a/charts/newrelic-logging/templates/_helpers.tpl +++ b/charts/newrelic-logging/templates/_helpers.tpl @@ -76,14 +76,12 @@ Return the cluster name Return the customSecretName */}} {{- define "newrelic-logging.customSecretName" -}} -{{- if .Values.global }} +{{- if .Values.customSecretName }} + {{- .Values.customSecretName -}} +{{- else if .Values.global }} {{- if .Values.global.customSecretName }} - {{- .Values.global.customSecretName -}} - {{- else -}} - {{- .Values.customSecretName | default "" -}} + {{- .Values.global.customSecretName -}} {{- end -}} -{{- else -}} - {{- .Values.customSecretName | default "" -}} {{- end -}} {{- end -}} @@ -91,21 +89,15 @@ Return the customSecretName Return the customSecretLicenseKey */}} {{- define "newrelic-logging.customSecretKey" -}} -{{- if .Values.global }} +{{- if .Values.customSecretLicenseKey }} + {{- .Values.customSecretLicenseKey -}} +{{- else if .Values.customSecretKey }} + {{- .Values.customSecretKey -}} +{{- else if .Values.global }} {{- if .Values.global.customSecretLicenseKey }} - {{- .Values.global.customSecretLicenseKey -}} - {{- else -}} - {{- if .Values.global.customSecretKey }} - {{- .Values.global.customSecretKey -}} - {{- else -}} - {{- .Values.customSecretKey | default "" -}} - {{- end -}} - {{- end -}} -{{- else -}} - {{- if .Values.customSecretLicenseKey }} - {{- .Values.customSecretLicenseKey -}} - {{- else -}} - {{- .Values.customSecretKey | default "" -}} + {{- .Values.global.customSecretLicenseKey -}} + {{- else if .Values.global.customSecretKey }} + {{- .Values.global.customSecretKey -}} {{- end -}} {{- end -}} {{- end -}} diff --git a/charts/newrelic-logging/tests/global-inheritance_test.yaml b/charts/newrelic-logging/tests/global-inheritance_test.yaml index 4a4fd5a6be..07aaeecb83 100644 --- a/charts/newrelic-logging/tests/global-inheritance_test.yaml +++ b/charts/newrelic-logging/tests/global-inheritance_test.yaml @@ -3,6 +3,7 @@ templates: - templates/configmap.yaml - templates/daemonset.yaml - templates/daemonset-windows.yaml + - templates/serviceaccount.yaml release: name: my-release namespace: my-namespace @@ -796,3 +797,195 @@ tests: content: readOnlyRootFilesystem: false template: templates/daemonset.yaml + + # ==================== + # images.registry Tests (2) + # ==================== + - it: should inherit global.images.registry when local not set + set: + licenseKey: nr_license_key + global: + images: + registry: global-registry.io + asserts: + - matchRegex: + path: spec.template.spec.containers[0].image + pattern: ^global-registry\.io/ + template: templates/daemonset.yaml + + - it: should use local image.registry when both global and local are set + set: + licenseKey: nr_license_key + global: + images: + registry: global-registry.io + image: + registry: local-registry.io + asserts: + - matchRegex: + path: spec.template.spec.containers[0].image + pattern: ^local-registry\.io/ + template: templates/daemonset.yaml + + # ==================== + # images.pullSecrets Tests (2) + # ==================== + - it: should inherit global.images.pullSecrets when local not set + set: + licenseKey: nr_license_key + global: + images: + pullSecrets: + - name: global-secret + asserts: + - contains: + path: spec.template.spec.imagePullSecrets + content: + name: global-secret + template: templates/daemonset.yaml + + - it: should use local image.pullSecrets when both global and local are set + set: + licenseKey: nr_license_key + global: + images: + pullSecrets: + - name: global-secret + image: + pullSecrets: + - name: local-secret + asserts: + - contains: + path: spec.template.spec.imagePullSecrets + content: + name: local-secret + template: templates/daemonset.yaml + + # ==================== + # serviceAccount.create Tests (2) + # ==================== + - it: should inherit global.serviceAccount.create when local not set + set: + licenseKey: nr_license_key + global: + serviceAccount: + create: false + asserts: + - hasDocuments: + count: 0 + template: templates/serviceaccount.yaml + + - it: should use local serviceAccount.create when both global and local are set + set: + licenseKey: nr_license_key + global: + serviceAccount: + create: false + serviceAccount: + create: true + asserts: + - hasDocuments: + count: 1 + template: templates/serviceaccount.yaml + + # ==================== + # serviceAccount.annotations Tests (2) + # ==================== + - it: should inherit global.serviceAccount.annotations when local not set + set: + licenseKey: nr_license_key + global: + serviceAccount: + annotations: + global-annotation: global-value + asserts: + - equal: + path: metadata.annotations.global-annotation + value: global-value + template: templates/serviceaccount.yaml + + - it: should use local serviceAccount.annotations when both global and local are set + set: + licenseKey: nr_license_key + global: + serviceAccount: + annotations: + global-annotation: global-value + serviceAccount: + annotations: + local-annotation: local-value + asserts: + - equal: + path: metadata.annotations.local-annotation + value: local-value + template: templates/serviceaccount.yaml + + # ==================== + # customSecretName Tests (2) + # ==================== + - it: should inherit global.customSecretName when local not set + set: + global: + customSecretName: global-secret + customSecretLicenseKey: global-key + asserts: + - equal: + path: spec.template.spec.containers[0].env[2].valueFrom.secretKeyRef.name + value: global-secret + template: templates/daemonset.yaml + - equal: + path: spec.template.spec.containers[0].env[2].valueFrom.secretKeyRef.key + value: global-key + template: templates/daemonset.yaml + + - it: should use local customSecretName when both global and local are set + set: + global: + customSecretName: global-secret + customSecretLicenseKey: global-key + customSecretName: local-secret + customSecretLicenseKey: local-key + asserts: + - equal: + path: spec.template.spec.containers[0].env[2].valueFrom.secretKeyRef.name + value: local-secret + template: templates/daemonset.yaml + - equal: + path: spec.template.spec.containers[0].env[2].valueFrom.secretKeyRef.key + value: local-key + template: templates/daemonset.yaml + + # ==================== + # dnsConfig Tests (2) + # ==================== + - it: should inherit global.dnsConfig when local not set + set: + licenseKey: nr_license_key + global: + dnsConfig: + options: + - name: ndots + value: "1" + asserts: + - equal: + path: spec.template.spec.dnsConfig.options[0].name + value: ndots + template: templates/daemonset.yaml + + - it: should use local dnsConfig when both global and local are set + set: + licenseKey: nr_license_key + global: + dnsConfig: + options: + - name: ndots + value: "1" + dnsConfig: + options: + - name: ndots + value: "2" + asserts: + - equal: + path: spec.template.spec.dnsConfig.options[0].value + value: "2" + template: templates/daemonset.yaml From f47a93066bfda8013b15780922dee61ba881a135 Mon Sep 17 00:00:00 2001 From: Diogo Pacheco Date: Wed, 11 Mar 2026 10:03:16 +0000 Subject: [PATCH 5/7] test(newrelic-logging): use YAML anchors in global-inheritance tests Define &base anchor on first test set block, apply <<: *base merge throughout so licenseKey is not repeated across all 58 test cases. --- .../tests/global-inheritance_test.yaml | 108 +++++++++--------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/charts/newrelic-logging/tests/global-inheritance_test.yaml b/charts/newrelic-logging/tests/global-inheritance_test.yaml index 07aaeecb83..2011adc66a 100644 --- a/charts/newrelic-logging/tests/global-inheritance_test.yaml +++ b/charts/newrelic-logging/tests/global-inheritance_test.yaml @@ -12,7 +12,7 @@ tests: # Proxy Tests (3) # ==================== - it: proxy not set when neither global nor local provided - set: + set: &base licenseKey: nr_license_key asserts: - notContains: @@ -28,7 +28,7 @@ tests: - it: uses global.proxy when set set: - licenseKey: nr_license_key + <<: *base enableWindows: true global: proxy: http://global-proxy.corp.net:3128 @@ -54,7 +54,7 @@ tests: - it: local proxy overrides global.proxy set: - licenseKey: nr_license_key + <<: *base enableWindows: true global: proxy: http://global-proxy.corp.net:3128 @@ -84,7 +84,7 @@ tests: # ==================== - it: priorityClassName not set when neither global nor local provided set: - licenseKey: nr_license_key + <<: *base asserts: - notExists: path: spec.template.spec.priorityClassName @@ -92,7 +92,7 @@ tests: - it: uses global.priorityClassName when set set: - licenseKey: nr_license_key + <<: *base enableWindows: true global: priorityClassName: high-priority @@ -108,7 +108,7 @@ tests: - it: local priorityClassName overrides global set: - licenseKey: nr_license_key + <<: *base enableWindows: true global: priorityClassName: high-priority @@ -128,7 +128,7 @@ tests: # ==================== - it: nodeSelector inherits global when no local provided set: - licenseKey: nr_license_key + <<: *base enableWindows: true global: nodeSelector: @@ -148,7 +148,7 @@ tests: - it: local nodeSelector overrides global set: - licenseKey: nr_license_key + <<: *base enableWindows: true global: nodeSelector: @@ -165,7 +165,7 @@ tests: - it: nodeSelector not set when neither global nor local provided and Windows disabled set: - licenseKey: nr_license_key + <<: *base enableWindows: false asserts: - notExists: @@ -177,7 +177,7 @@ tests: # ==================== - it: tolerations inherit global when no local provided set: - licenseKey: nr_license_key + <<: *base enableWindows: true tolerations: [] global: @@ -206,7 +206,7 @@ tests: - it: local tolerations override global set: - licenseKey: nr_license_key + <<: *base global: tolerations: - key: global-taint @@ -229,7 +229,7 @@ tests: - it: default tolerations apply when neither global nor local provided set: - licenseKey: nr_license_key + <<: *base asserts: - contains: path: spec.template.spec.tolerations @@ -249,7 +249,7 @@ tests: # ==================== - it: affinity not set when neither global nor local provided set: - licenseKey: nr_license_key + <<: *base asserts: - notExists: path: spec.template.spec.affinity @@ -257,7 +257,7 @@ tests: - it: uses global.affinity when set set: - licenseKey: nr_license_key + <<: *base enableWindows: true global: affinity: @@ -297,7 +297,7 @@ tests: - it: local nodeAffinity overrides global.affinity set: - licenseKey: nr_license_key + <<: *base global: affinity: nodeAffinity: @@ -331,7 +331,7 @@ tests: - it: Fargate exclusion affinity applies when global.fargate is true set: - licenseKey: nr_license_key + <<: *base global: fargate: true asserts: @@ -352,7 +352,7 @@ tests: # ==================== - it: hostNetwork not set when neither global nor local provided set: - licenseKey: nr_license_key + <<: *base asserts: - notExists: path: spec.template.spec.hostNetwork @@ -360,7 +360,7 @@ tests: - it: hostNetwork not set when explicitly false set: - licenseKey: nr_license_key + <<: *base hostNetwork: false asserts: - notExists: @@ -369,7 +369,7 @@ tests: - it: uses global.hostNetwork when set to true set: - licenseKey: nr_license_key + <<: *base enableWindows: true global: hostNetwork: true @@ -385,7 +385,7 @@ tests: - it: local hostNetwork overrides global set: - licenseKey: nr_license_key + <<: *base enableWindows: true global: hostNetwork: false @@ -405,7 +405,7 @@ tests: # ==================== - it: uses default log level when neither global.verboseLog nor local provided set: - licenseKey: nr_license_key + <<: *base asserts: - contains: path: spec.template.spec.containers[0].env @@ -416,7 +416,7 @@ tests: - it: sets LOG_LEVEL to debug when global.verboseLog is true set: - licenseKey: nr_license_key + <<: *base enableWindows: true fluentBit: logLevel: null @@ -438,7 +438,7 @@ tests: - it: local fluentBit.logLevel overrides global.verboseLog set: - licenseKey: nr_license_key + <<: *base global: verboseLog: true fluentBit: @@ -453,7 +453,7 @@ tests: - it: global.verboseLog false does not override local logLevel set: - licenseKey: nr_license_key + <<: *base global: verboseLog: false fluentBit: @@ -471,7 +471,7 @@ tests: # ==================== - it: lowDataMode defaults to false when not set set: - licenseKey: nr_license_key + <<: *base asserts: - contains: path: spec.template.spec.containers[0].env @@ -482,7 +482,7 @@ tests: - it: uses global.lowDataMode when set set: - licenseKey: nr_license_key + <<: *base enableWindows: true global: lowDataMode: true @@ -502,7 +502,7 @@ tests: - it: local lowDataMode overrides global set: - licenseKey: nr_license_key + <<: *base global: lowDataMode: true lowDataMode: false @@ -519,7 +519,7 @@ tests: # ==================== - it: uses prod endpoint when nrStaging not set set: - licenseKey: nr_license_key + <<: *base asserts: - contains: path: spec.template.spec.containers[0].env @@ -530,7 +530,7 @@ tests: - it: uses staging endpoint when global.nrStaging is true set: - licenseKey: nr_license_key + <<: *base global: nrStaging: true asserts: @@ -546,7 +546,7 @@ tests: # ==================== - it: uses global.cluster when set set: - licenseKey: nr_license_key + <<: *base global: cluster: global-cluster-01 asserts: @@ -559,7 +559,7 @@ tests: - it: local cluster overrides global.cluster set: - licenseKey: nr_license_key + <<: *base global: cluster: global-cluster-01 cluster: local-cluster-02 @@ -600,7 +600,7 @@ tests: # ==================== - it: dnsConfig inherits from global set: - licenseKey: nr_license_key + <<: *base global: dnsConfig: options: @@ -614,7 +614,7 @@ tests: - it: local dnsConfig overrides global set: - licenseKey: nr_license_key + <<: *base global: dnsConfig: options: @@ -635,7 +635,7 @@ tests: # ==================== - it: pod inherits global.podLabels set: - licenseKey: nr_license_key + <<: *base global: podLabels: global-label: global-value @@ -648,7 +648,7 @@ tests: - it: local podLabels merge with global set: - licenseKey: nr_license_key + <<: *base global: podLabels: global-label: global-value @@ -667,7 +667,7 @@ tests: # ==================== - it: resource inherits global.labels set: - licenseKey: nr_license_key + <<: *base global: labels: global-resource-label: global-value @@ -680,7 +680,7 @@ tests: - it: resource labels are applied set: - licenseKey: nr_license_key + <<: *base global: labels: team: platform @@ -696,7 +696,7 @@ tests: # ==================== - it: uses global serviceAccount name when set set: - licenseKey: nr_license_key + <<: *base global: serviceAccount: name: global-sa @@ -708,7 +708,7 @@ tests: - it: local serviceAccount name overrides global set: - licenseKey: nr_license_key + <<: *base global: serviceAccount: name: global-sa @@ -722,7 +722,7 @@ tests: - it: serviceAccount create is honored set: - licenseKey: nr_license_key + <<: *base serviceAccount: create: true name: custom-sa @@ -737,7 +737,7 @@ tests: # ==================== - it: pod inherits global.podSecurityContext set: - licenseKey: nr_license_key + <<: *base global: podSecurityContext: runAsUser: 1000 @@ -752,7 +752,7 @@ tests: - it: local podSecurityContext overrides global set: - licenseKey: nr_license_key + <<: *base global: podSecurityContext: runAsUser: 1000 @@ -770,7 +770,7 @@ tests: # ==================== - it: container inherits global.containerSecurityContext set: - licenseKey: nr_license_key + <<: *base global: containerSecurityContext: readOnlyRootFilesystem: true @@ -785,7 +785,7 @@ tests: - it: local containerSecurityContext overrides global set: - licenseKey: nr_license_key + <<: *base global: containerSecurityContext: readOnlyRootFilesystem: true @@ -803,7 +803,7 @@ tests: # ==================== - it: should inherit global.images.registry when local not set set: - licenseKey: nr_license_key + <<: *base global: images: registry: global-registry.io @@ -815,7 +815,7 @@ tests: - it: should use local image.registry when both global and local are set set: - licenseKey: nr_license_key + <<: *base global: images: registry: global-registry.io @@ -832,7 +832,7 @@ tests: # ==================== - it: should inherit global.images.pullSecrets when local not set set: - licenseKey: nr_license_key + <<: *base global: images: pullSecrets: @@ -846,7 +846,7 @@ tests: - it: should use local image.pullSecrets when both global and local are set set: - licenseKey: nr_license_key + <<: *base global: images: pullSecrets: @@ -866,7 +866,7 @@ tests: # ==================== - it: should inherit global.serviceAccount.create when local not set set: - licenseKey: nr_license_key + <<: *base global: serviceAccount: create: false @@ -877,7 +877,7 @@ tests: - it: should use local serviceAccount.create when both global and local are set set: - licenseKey: nr_license_key + <<: *base global: serviceAccount: create: false @@ -893,7 +893,7 @@ tests: # ==================== - it: should inherit global.serviceAccount.annotations when local not set set: - licenseKey: nr_license_key + <<: *base global: serviceAccount: annotations: @@ -906,7 +906,7 @@ tests: - it: should use local serviceAccount.annotations when both global and local are set set: - licenseKey: nr_license_key + <<: *base global: serviceAccount: annotations: @@ -960,7 +960,7 @@ tests: # ==================== - it: should inherit global.dnsConfig when local not set set: - licenseKey: nr_license_key + <<: *base global: dnsConfig: options: @@ -974,7 +974,7 @@ tests: - it: should use local dnsConfig when both global and local are set set: - licenseKey: nr_license_key + <<: *base global: dnsConfig: options: From 0e686ca5ff5d4f700d77eaef9bf492754aa4080e Mon Sep 17 00:00:00 2001 From: Diogo Pacheco Date: Tue, 24 Mar 2026 15:09:40 +0000 Subject: [PATCH 6/7] feat(newrelic-logging): add global.images registry, pullSecrets, and pullPolicy support Consolidates changes from PR #2005 into this branch: - Add persistenceInitContainerImage helper: global.images.registry is prepended to busybox when set; chart-level repository takes precedence - Add imagePullPolicy helper: chart-specific > global.images.pullPolicy > IfNotPresent - Add persistenceInitContainerImagePullPolicy helper: same precedence for init container - Wire daemonset.yaml init container to use image/pullPolicy helpers - Wire main container imagePullPolicy to use imagePullPolicy helper - Add fluentBit.persistenceInitContainerImage values block (repo, tag, pullPolicy) - Add images_test.yaml: LICENSE_KEY secret, pullPolicy precedence, init container image/pullPolicy tests (180 lines, 11 new test cases) Note: global.images.pullSecrets is handled automatically by the common-library renderPullSecrets helper via context; no custom wiring needed. Closes #2005 --- .../newrelic-logging/templates/_helpers.tpl | 56 ++++++ .../newrelic-logging/templates/daemonset.yaml | 5 +- .../newrelic-logging/tests/images_test.yaml | 180 ++++++++++++++++++ charts/newrelic-logging/values.yaml | 6 + 4 files changed, 245 insertions(+), 2 deletions(-) diff --git a/charts/newrelic-logging/templates/_helpers.tpl b/charts/newrelic-logging/templates/_helpers.tpl index 77214145b5..a54306cd56 100644 --- a/charts/newrelic-logging/templates/_helpers.tpl +++ b/charts/newrelic-logging/templates/_helpers.tpl @@ -274,4 +274,60 @@ If additionalEnvVariables is set, renames to extraEnv. Returns extraEnv. {{- end -}} {{- end -}} +{{/* +Returns the image for the persistence init container. +Precedence: chart-specific repository > global.images.registry + default > chart default (busybox) +*/}} +{{- define "newrelic-logging.persistenceInitContainerImage" -}} +{{- $repository := .Values.fluentBit.persistenceInitContainerImage.repository -}} +{{- $defaultRepository := "busybox" -}} +{{- $registry := "" -}} +{{- if and .Values.global .Values.global.images }} + {{- $registry = .Values.global.images.registry | default "" -}} +{{- end -}} +{{- if and $registry (eq $repository $defaultRepository) -}} + {{- printf "%s/%s" $registry $defaultRepository -}} +{{- else -}} + {{- $repository -}} +{{- end -}} +{{- end -}} + +{{/* +Returns the pull policy for main image. +Precedence: chart-specific value > global.images.pullPolicy > default (IfNotPresent) +*/}} +{{- define "newrelic-logging.imagePullPolicy" -}} +{{- $globalPullPolicy := "" -}} +{{- if and .Values.global .Values.global.images -}} + {{- $globalPullPolicy = .Values.global.images.pullPolicy | default "" -}} +{{- end -}} +{{- $chartPullPolicy := .Values.image.pullPolicy | default "" -}} +{{- if $chartPullPolicy -}} + {{- $chartPullPolicy -}} +{{- else if $globalPullPolicy -}} + {{- $globalPullPolicy -}} +{{- else -}} + IfNotPresent +{{- end -}} +{{- end -}} + +{{/* +Returns the pull policy for persistence init container. +Precedence: chart-specific value > global.images.pullPolicy > default (IfNotPresent) +*/}} +{{- define "newrelic-logging.persistenceInitContainerImagePullPolicy" -}} +{{- $globalPullPolicy := "" -}} +{{- if and .Values.global .Values.global.images -}} + {{- $globalPullPolicy = .Values.global.images.pullPolicy | default "" -}} +{{- end -}} +{{- $chartPullPolicy := .Values.fluentBit.persistenceInitContainerImage.pullPolicy | default "" -}} +{{- if $chartPullPolicy -}} + {{- $chartPullPolicy -}} +{{- else if $globalPullPolicy -}} + {{- $globalPullPolicy -}} +{{- else -}} + IfNotPresent +{{- end -}} +{{- end -}} + diff --git a/charts/newrelic-logging/templates/daemonset.yaml b/charts/newrelic-logging/templates/daemonset.yaml index 7d12805b67..18b1a6eef1 100644 --- a/charts/newrelic-logging/templates/daemonset.yaml +++ b/charts/newrelic-logging/templates/daemonset.yaml @@ -56,7 +56,8 @@ spec: initContainers: {{- if and (.Values.fluentBit.persistence) (eq .Values.fluentBit.persistence.mode "persistentVolume") }} - name: init - image: busybox:1.36 + image: {{ include "newrelic-logging.persistenceInitContainerImage" . }}:{{ .Values.fluentBit.persistenceInitContainerImage.tag }} + imagePullPolicy: {{ include "newrelic-logging.persistenceInitContainerImagePullPolicy" . }} {{- with include "newrelic.common.securityContext.container" . }} securityContext: {{- . | nindent 12 }} @@ -77,7 +78,7 @@ spec: {{- . | nindent 12 }} {{- end }} image: {{ include "newrelic.common.images.image" ( dict "imageRoot" .Values.image "context" .) }} - imagePullPolicy: "{{ .Values.image.pullPolicy }}" + imagePullPolicy: {{ include "newrelic-logging.imagePullPolicy" . }} env: - name: ENDPOINT value: {{ include "newrelic-logging.logsEndpoint" . | quote }} diff --git a/charts/newrelic-logging/tests/images_test.yaml b/charts/newrelic-logging/tests/images_test.yaml index fbd5879807..6e7e98a5f3 100644 --- a/charts/newrelic-logging/tests/images_test.yaml +++ b/charts/newrelic-logging/tests/images_test.yaml @@ -94,3 +94,183 @@ tests: - equal: path: spec.template.spec.imagePullSecrets[1].name value: regsecret + + # --------------------------------------------------------------------------- + # LICENSE_KEY env — verify secret name and key value, not just structure + # --------------------------------------------------------------------------- + - it: LICENSE_KEY env references the correct secret name and key + templates: + - templates/daemonset.yaml + set: + licenseKey: nr_license_key + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: LICENSE_KEY + valueFrom: + secretKeyRef: + name: my-release-newrelic-logging-config + key: license + + - it: LICENSE_KEY env uses customSecretName and customSecretLicenseKey when set + templates: + - templates/daemonset.yaml + set: + customSecretName: my-custom-secret + customSecretLicenseKey: my-custom-key + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: LICENSE_KEY + valueFrom: + secretKeyRef: + name: my-custom-secret + key: my-custom-key + + # --------------------------------------------------------------------------- + # Main image pullPolicy + # Precedence: chart-specific value > global.images.pullPolicy > default (IfNotPresent) + # --------------------------------------------------------------------------- + - it: Main image pullPolicy defaults to IfNotPresent when nothing set + templates: + - templates/daemonset.yaml + set: &main_pullpolicy_base + licenseKey: nr_license_key + image: + pullPolicy: "" + asserts: + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: IfNotPresent + + - it: Main image pullPolicy uses global when no chart-specific value + templates: + - templates/daemonset.yaml + set: + <<: *main_pullpolicy_base + global: + images: + pullPolicy: Always + asserts: + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: Always + + - it: Main image chart-specific pullPolicy overrides global + templates: + - templates/daemonset.yaml + set: + <<: *main_pullpolicy_base + image: + pullPolicy: Never + global: + images: + pullPolicy: Always + asserts: + - equal: + path: spec.template.spec.containers[0].imagePullPolicy + value: Never + + # --------------------------------------------------------------------------- + # Persistence init container — image and pullPolicy + # Precedence: chart-specific value > global.images.* > default + # --------------------------------------------------------------------------- + - it: Init container uses default busybox image when no global registry set + templates: + - templates/daemonset.yaml + set: &pvc_base + licenseKey: nr_license_key + fluentBit: + persistence: + mode: persistentVolume + persistentVolume: + storageClass: sample-rwx + asserts: + - equal: + path: spec.template.spec.initContainers[0].image + value: busybox:1.36 + + - it: Init container uses global registry when set and repository is default + templates: + - templates/daemonset.yaml + set: + <<: *pvc_base + global: + images: + registry: my-registry.com + asserts: + - equal: + path: spec.template.spec.initContainers[0].image + value: my-registry.com/busybox:1.36 + + - it: Init container chart-specific repository overrides global registry + templates: + - templates/daemonset.yaml + set: + <<: *pvc_base + global: + images: + registry: my-registry.com + fluentBit: + persistence: + mode: persistentVolume + persistentVolume: + storageClass: sample-rwx + persistenceInitContainerImage: + repository: my-mirror.com/busybox + asserts: + - matchRegex: + path: spec.template.spec.initContainers[0].image + pattern: "^my-mirror.com/busybox:" + + - it: Init container pullPolicy defaults to IfNotPresent when nothing set + templates: + - templates/daemonset.yaml + set: &init_pullpolicy_base + licenseKey: nr_license_key + fluentBit: + persistence: + mode: persistentVolume + persistentVolume: + storageClass: sample-rwx + persistenceInitContainerImage: + pullPolicy: "" + asserts: + - equal: + path: spec.template.spec.initContainers[0].imagePullPolicy + value: IfNotPresent + + - it: Init container pullPolicy uses global when no chart-specific value + templates: + - templates/daemonset.yaml + set: + <<: *init_pullpolicy_base + global: + images: + pullPolicy: Always + asserts: + - equal: + path: spec.template.spec.initContainers[0].imagePullPolicy + value: Always + + - it: Init container chart-specific pullPolicy overrides global + templates: + - templates/daemonset.yaml + set: + <<: *init_pullpolicy_base + fluentBit: + persistence: + mode: persistentVolume + persistentVolume: + storageClass: sample-rwx + persistenceInitContainerImage: + pullPolicy: Never + global: + images: + pullPolicy: Always + asserts: + - equal: + path: spec.template.spec.initContainers[0].imagePullPolicy + value: Never diff --git a/charts/newrelic-logging/values.yaml b/charts/newrelic-logging/values.yaml index 115c9e3e27..91ade820ac 100644 --- a/charts/newrelic-logging/values.yaml +++ b/charts/newrelic-logging/values.yaml @@ -67,6 +67,12 @@ fluentBit: # - name: MY_TEMPLATIZED_ENV # value: "templatization example {{ .Values.someValue }}" + # -- Image for the persistence init container (busybox). Defaults to busybox. If global.images.registry is set, it will be used instead. + persistenceInitContainerImage: + repository: busybox + tag: "1.36" + pullPolicy: "" + # Indicates how fluent-bit database is persisted persistence: # Define the persistent mode for fluent-bit db, allowed options are `hostPath` (default), `none`, `persistentVolume`. From e90062ee3b22eb695cd0d5d4b7e3d5a827d22bd0 Mon Sep 17 00:00:00 2001 From: Diogo Pacheco Date: Tue, 24 Mar 2026 15:18:20 +0000 Subject: [PATCH 7/7] fix(newrelic-logging): correct licenseKey, nrStaging, fargate precedence to local > global Pre-existing helpers had global checked before local, violating the local > global > default contract. Also adds tests verifying local values take precedence over global for all three helpers. --- .../newrelic-logging/templates/_helpers.tpl | 22 +++-- .../tests/global-inheritance_test.yaml | 85 +++++++++++++++++++ 2 files changed, 95 insertions(+), 12 deletions(-) diff --git a/charts/newrelic-logging/templates/_helpers.tpl b/charts/newrelic-logging/templates/_helpers.tpl index a54306cd56..d4c42e0197 100644 --- a/charts/newrelic-logging/templates/_helpers.tpl +++ b/charts/newrelic-logging/templates/_helpers.tpl @@ -48,14 +48,12 @@ Create the name of the fluent bit config Return the licenseKey */}} {{- define "newrelic-logging.licenseKey" -}} -{{- if .Values.global}} +{{- if .Values.licenseKey }} + {{- .Values.licenseKey -}} +{{- else if .Values.global }} {{- if .Values.global.licenseKey }} - {{- .Values.global.licenseKey -}} - {{- else -}} - {{- .Values.licenseKey | default "" -}} + {{- .Values.global.licenseKey -}} {{- end -}} -{{- else -}} - {{- .Values.licenseKey | default "" -}} {{- end -}} {{- end -}} @@ -106,12 +104,12 @@ Return the customSecretLicenseKey Returns nrStaging */}} {{- define "newrelic.nrStaging" -}} -{{- if .Values.global }} +{{- if .Values.nrStaging }} + {{- .Values.nrStaging -}} +{{- else if .Values.global }} {{- if .Values.global.nrStaging }} {{- .Values.global.nrStaging -}} {{- end -}} -{{- else if .Values.nrStaging }} - {{- .Values.nrStaging -}} {{- end -}} {{- end -}} @@ -119,12 +117,12 @@ Returns nrStaging Returns fargate */}} {{- define "newrelic.fargate" -}} -{{- if .Values.global }} +{{- if .Values.fargate }} + {{- .Values.fargate -}} +{{- else if .Values.global }} {{- if .Values.global.fargate }} {{- .Values.global.fargate -}} {{- end -}} -{{- else if .Values.fargate }} - {{- .Values.fargate -}} {{- end -}} {{- end -}} diff --git a/charts/newrelic-logging/tests/global-inheritance_test.yaml b/charts/newrelic-logging/tests/global-inheritance_test.yaml index 2011adc66a..3c1553ba90 100644 --- a/charts/newrelic-logging/tests/global-inheritance_test.yaml +++ b/charts/newrelic-logging/tests/global-inheritance_test.yaml @@ -989,3 +989,88 @@ tests: path: spec.template.spec.dnsConfig.options[0].value value: "2" template: templates/daemonset.yaml + + # ==================== + # nrStaging Tests (2) + # ==================== + - it: local nrStaging uses staging endpoint + set: + licenseKey: nr_license_key + nrStaging: true + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ENDPOINT + value: https://staging-log-api.newrelic.com/log/v1 + template: templates/daemonset.yaml + + - it: local nrStaging works alongside global values + set: + global: + licenseKey: eu_global_license_key + nrStaging: true + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ENDPOINT + value: https://staging-log-api.newrelic.com/log/v1 + template: templates/daemonset.yaml + + # ==================== + # fargate Tests (2) + # ==================== + - it: local fargate applies fargate exclusion affinity + set: + <<: *base + fargate: true + asserts: + - equal: + path: spec.template.spec.affinity.nodeAffinity + value: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: eks.amazonaws.com/compute-type + operator: NotIn + values: + - fargate + template: templates/daemonset.yaml + + - it: local fargate works when no global fargate set + set: + <<: *base + fargate: true + asserts: + - exists: + path: spec.template.spec.affinity + template: templates/daemonset.yaml + + # ==================== + # licenseKey Endpoint Tests (2) + # ==================== + - it: local licenseKey EU prefix selects EU endpoint even when global key is non-EU + set: + global: + licenseKey: us_global_license_key + licenseKey: eu_local_license_key + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ENDPOINT + value: https://log-api.eu.newrelic.com/log/v1 + template: templates/daemonset.yaml + + - it: global licenseKey EU prefix selects EU endpoint when no local key + set: + global: + licenseKey: eu_global_license_key + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ENDPOINT + value: https://log-api.eu.newrelic.com/log/v1 + template: templates/daemonset.yaml