From c099abe066831258e92ca6ba6b75c7a331446784 Mon Sep 17 00:00:00 2001 From: Paul Abel <128620221+pdabelf5@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:40:59 +0100 Subject: [PATCH 1/5] WAFv5 update to 5.3/alpine update (#6507) --- .github/workflows/regression.yml | 2 +- .github/workflows/setup-smoke.yml | 2 +- build/Dockerfile | 12 ++++++------ charts/nginx-ingress/values.schema.json | 12 ++++++------ charts/nginx-ingress/values.yaml | 4 ++-- .../installing-nic/installation-with-helm.md | 4 ++-- tests/settings.py | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/regression.yml b/.github/workflows/regression.yml index 986315586d..3aae12c64a 100644 --- a/.github/workflows/regression.yml +++ b/.github/workflows/regression.yml @@ -262,7 +262,7 @@ jobs: - name: Generate WAF v5 tgz from JSON run: | - docker run --rm --user root -v /var/run/docker.sock:/var/run/docker.sock -v ${{ github.workspace }}/tests/data/ap-waf-v5:/data gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/nap/waf-compiler:5.2.0 -p /data/wafv5.json -o /data/wafv5.tgz + docker run --rm --user root -v /var/run/docker.sock:/var/run/docker.sock -v ${{ github.workspace }}/tests/data/ap-waf-v5:/data gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/nap/waf-compiler:5.3.0 -p /data/wafv5.json -o /data/wafv5.tgz if: ${{ contains(matrix.images.image, 'nap-v5')}} - name: Run Regression Tests diff --git a/.github/workflows/setup-smoke.yml b/.github/workflows/setup-smoke.yml index 0489533f46..9e4e0c2a1c 100644 --- a/.github/workflows/setup-smoke.yml +++ b/.github/workflows/setup-smoke.yml @@ -149,7 +149,7 @@ jobs: - name: Generate WAF v5 tgz from JSON run: | - docker run --rm --user root -v /var/run/docker.sock:/var/run/docker.sock -v ${{ github.workspace }}/tests/data/ap-waf-v5:/data gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/nap/waf-compiler:5.2.0 -p /data/wafv5.json -o /data/wafv5.tgz + docker run --rm --user root -v /var/run/docker.sock:/var/run/docker.sock -v ${{ github.workspace }}/tests/data/ap-waf-v5:/data gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/nap/waf-compiler:5.3.0 -p /data/wafv5.json -o /data/wafv5.tgz if: ${{ contains(inputs.image, 'nap-v5')}} - name: Run Smoke Tests diff --git a/build/Dockerfile b/build/Dockerfile index 1333390838..4a866b60c9 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -101,8 +101,8 @@ RUN --mount=type=bind,from=nginx-files,src=patch-os.sh,target=/usr/local/bin/pat USER 101 -############################################# Base image for Alpine with NGINX Plus ############################################# -FROM alpine:3.20@sha256:e72ad0747b9dc266fca31fb004580d316b6ae5b0fdbbb65f17bbe371a5b24cff AS alpine-plus +############################################# Base image for Alpine with NGINX Plus ############################################## +FROM alpine:3.20@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d AS alpine-plus ARG NGINX_PLUS_VERSION ARG PACKAGE_REPO @@ -198,7 +198,7 @@ RUN --mount=type=bind,from=alpine-fips-3.17,target=/tmp/fips/ \ && cp -av /tmp/fips/etc/ssl/openssl.cnf /etc/ssl/openssl.cnf \ && cp -av /tmp/ot/usr/local/lib/libjaegertracing*so* /tmp/ot/usr/local/lib/libzipkin*so* /tmp/ot/usr/local/lib/libdd*so* /tmp/ot/usr/local/lib/libyaml*so* /usr/local/lib/ \ && ldconfig /usr/local/lib/ \ - && apk add --no-cache app-protect-module-plus~=32.5.48 \ + && apk add --no-cache app-protect-module-plus~=32.5.144 \ && sed -i -e '/nginx.com/d' /etc/apk/repositories \ && nap-waf.sh \ && if [ "${NGINX_AGENT}" = "true" ]; then \ @@ -300,7 +300,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode && apt-get update \ && if [ "${NGINX_AGENT}" = "true" ]; then apt-get install --no-install-recommends --no-install-suggests -y nginx-agent; fi \ && if [ -z "${NAP_MODULES##*waf*}" ]; then \ - apt-get install --no-install-recommends --no-install-suggests -y app-protect-module-plus=32+5.48*; \ + apt-get install --no-install-recommends --no-install-suggests -y app-protect-module-plus=32+5.144*; \ rm -f /etc/apt/sources.list.d/app-protect.sources; \ nap-waf.sh; \ fi \ @@ -430,7 +430,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode && if [ "${NGINX_AGENT}" = "true" ]; then microdnf --nodocs install -y nginx-agent; fi \ && if [ -z "${NAP_MODULES##*waf*}" ]; then \ cp /tmp/app-protect-9.repo /etc/yum.repos.d/app-protect-9.repo \ - && microdnf --nodocs install -y app-protect-module-plus-32+5.48* \ + && microdnf --nodocs install -y app-protect-module-plus-32+5.144* \ && nap-waf.sh \ && rm -f /etc/yum.repos.d/app-protect-9.repo; \ fi \ @@ -517,7 +517,7 @@ RUN --mount=type=secret,id=nginx-repo.crt,dst=/etc/ssl/nginx/nginx-repo.crt,mode && dnf config-manager --set-enabled codeready-builder-for-rhel-8-x86_64-rpms \ && dnf --nodocs install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm \ && if [ -z "${NAP_MODULES##*waf*}" ]; then \ - dnf --nodocs install -y app-protect-module-plus-32+5.48*; \ + dnf --nodocs install -y app-protect-module-plus-32+5.144*; \ fi \ && subscription-manager unregister \ && if [ -z "${NAP_MODULES##*waf*}" ]; then \ diff --git a/charts/nginx-ingress/values.schema.json b/charts/nginx-ingress/values.schema.json index 423dd014c5..37297c6bbc 100644 --- a/charts/nginx-ingress/values.schema.json +++ b/charts/nginx-ingress/values.schema.json @@ -208,10 +208,10 @@ }, "tag": { "type": "string", - "default": "5.2.0", + "default": "5.3.0", "title": "The tag of the App Protect WAF v5 Enforcer image", "examples": [ - "5.2.0" + "5.3.0" ] }, "digest": { @@ -248,7 +248,7 @@ "examples": [ { "repository": "private-registry.nginx.com/nap/waf-enforcer", - "tag": "5.2.0", + "tag": "5.3.0", "pullPolicy": "IfNotPresent" } ] @@ -282,10 +282,10 @@ }, "tag": { "type": "string", - "default": "5.2.0", + "default": "5.3.0", "title": "The tag of the App Protect WAF v5 Config Manager image", "examples": [ - "5.2.0" + "5.3.0" ] }, "digest": { @@ -322,7 +322,7 @@ "examples": [ { "repository": "private-registry.nginx.com/nap/waf-config-mgr", - "tag": "5.2.0", + "tag": "5.3.0", "pullPolicy": "IfNotPresent" } ] diff --git a/charts/nginx-ingress/values.yaml b/charts/nginx-ingress/values.yaml index ebece1f3a6..c8892f0223 100644 --- a/charts/nginx-ingress/values.yaml +++ b/charts/nginx-ingress/values.yaml @@ -49,7 +49,7 @@ controller: repository: private-registry.nginx.com/nap/waf-enforcer ## The tag of the App Protect WAF v5 Enforcer image. - tag: "5.2.0" + tag: "5.3.0" ## The digest of the App Protect WAF v5 Enforcer image. ## If digest is specified it has precedence over tag and will be used instead # digest: "sha256:CHANGEME" @@ -65,7 +65,7 @@ controller: repository: private-registry.nginx.com/nap/waf-config-mgr ## The tag of the App Protect WAF v5 Configuration Manager image. - tag: "5.2.0" + tag: "5.3.0" ## The digest of the App Protect WAF v5 Configuration Manager image. ## If digest is specified it has precedence over tag and will be used instead # digest: "sha256:CHANGEME" diff --git a/docs/content/installation/installing-nic/installation-with-helm.md b/docs/content/installation/installing-nic/installation-with-helm.md index a6a6fedee0..5c4511083b 100644 --- a/docs/content/installation/installing-nic/installation-with-helm.md +++ b/docs/content/installation/installing-nic/installation-with-helm.md @@ -405,12 +405,12 @@ The following tables lists the configurable parameters of the NGINX Ingress Cont | **controller.appprotect.enforcer.host** | Host that the App Protect WAF v5 Enforcer runs on. | "127.0.0.1" | | **controller.appprotect.enforcer.port** | Port that the App Protect WAF v5 Enforcer runs on. | 50000 | | **controller.appprotect.enforcer.image** | The image repository of the App Protect WAF v5 Enforcer. | private-registry.nginx.com/nap/waf-enforcer | -| **controller.appprotect.enforcer.tag** | The tag of the App Protect WAF v5 Enforcer. | "5.2.0" | +| **controller.appprotect.enforcer.tag** | The tag of the App Protect WAF v5 Enforcer. | "5.3.0" | | **controller.appprotect.enforcer.digest** | The digest of the App Protect WAF v5 Enforcer. Takes precedence over tag if set. | "" | | **controller.appprotect.enforcer.pullPolicy** | The pull policy for the App Protect WAF v5 Enforcer image. | IfNotPresent | | **controller.appprotect.enforcer.securityContext** | The security context for App Protect WAF v5 Enforcer container. | {} | | **controller.appprotect.configManager.image** | The image repository of the App Protect WAF v5 Configuration Manager. | private-registry.nginx.com/nap/waf-config-mgr | -| **controller.appprotect.configManager.tag** | The tag of the App Protect WAF v5 Configuration Manager. | "5.2.0" | +| **controller.appprotect.configManager.tag** | The tag of the App Protect WAF v5 Configuration Manager. | "5.3.0" | | **controller.appprotect.configManager.digest** | The digest of the App Protect WAF v5 Configuration Manager. Takes precedence over tag if set. | "" | | **controller.appprotect.configManager.pullPolicy** | The pull policy for the App Protect WAF v5 Configuration Manager image. | IfNotPresent | | **controller.appprotect.configManager.securityContext** | The security context for App Protect WAF v5 Configuration Manager container. | {"allowPrivilegeEscalation":false,"runAsUser":101,"runAsNonRoot":true,"capabilities":{"drop":["all"]}} | diff --git a/tests/settings.py b/tests/settings.py index 8c23605fc7..ce03b76491 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -33,4 +33,4 @@ # Nginx registry address to pull waf components from NGX_REG = "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr" # WAF component version to pull from above registry -WAF_V5_VERSION = "5.2.0" +WAF_V5_VERSION = "5.3.0" From 4a0d5b5cfdf9499b8de534485b84f9db7ac98045 Mon Sep 17 00:00:00 2001 From: nginx-bot <68849795+nginx-bot@users.noreply.github.com> Date: Thu, 26 Sep 2024 00:56:18 -0700 Subject: [PATCH 2/5] Docker image update e000531c (#6512) Update docker images e000531c --- build/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/Dockerfile b/build/Dockerfile index 4a866b60c9..7ec70a62f2 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -135,7 +135,7 @@ RUN --mount=type=bind,from=alpine-fips-3.20,target=/tmp/fips/ \ ############################################# Base image for Alpine with NGINX Plus, App Protect WAF and FIPS ############################################# -FROM alpine:3.17@sha256:7f4ce018279b83f63d886529a33ff763da1f6b68a2a0e75114080e730f826c1e AS alpine-plus-nap-fips +FROM alpine:3.17@sha256:3451da08fc6ef554a100da3e2df5ac6d598c82f2a774d5f6ed465c3d80cd163a AS alpine-plus-nap-fips ARG NGINX_PLUS_VERSION ARG NGINX_AGENT ARG NGINX_PLUS_VERSION @@ -172,7 +172,7 @@ RUN --mount=type=bind,from=alpine-fips-3.17,target=/tmp/fips/ \ ############################################# Base image for Alpine with NGINX Plus, App Protect WAFv5 and FIPS ############################################# -FROM alpine:3.17@sha256:7f4ce018279b83f63d886529a33ff763da1f6b68a2a0e75114080e730f826c1e AS alpine-plus-nap-v5-fips +FROM alpine:3.17@sha256:3451da08fc6ef554a100da3e2df5ac6d598c82f2a774d5f6ed465c3d80cd163a AS alpine-plus-nap-v5-fips ARG NGINX_PLUS_VERSION ARG NGINX_AGENT ARG NGINX_PLUS_VERSION From 4ee3676f16cd17f4cf7c570af000548c122fcfed Mon Sep 17 00:00:00 2001 From: AlexFenlon Date: Thu, 26 Sep 2024 09:26:43 +0100 Subject: [PATCH 3/5] refactor to prepare for struct logs (#6501) --- cmd/nginx-ingress/flags.go | 114 +++++++++++++++++++------------------ cmd/nginx-ingress/main.go | 2 +- 2 files changed, 59 insertions(+), 57 deletions(-) diff --git a/cmd/nginx-ingress/flags.go b/cmd/nginx-ingress/flags.go index 587eca2cd6..a3b6acf53b 100644 --- a/cmd/nginx-ingress/flags.go +++ b/cmd/nginx-ingress/flags.go @@ -217,50 +217,12 @@ var ( func parseFlags() { flag.Parse() - if *versionFlag { + if *versionFlag { // printed in main os.Exit(0) } +} - mustValidateInitialChecks() - mustValidateWatchedNamespaces() - mustValidateFlags() - - if *enableTLSPassthrough && !*enableCustomResources { - glog.Fatal("enable-tls-passthrough flag requires -enable-custom-resources") - } - - if *appProtect && !*nginxPlus { - glog.Fatal("NGINX App Protect support is for NGINX Plus only") - } - - if *appProtectLogLevel != appProtectLogLevelDefault && !*appProtect && !*nginxPlus { - glog.Fatal("app-protect-log-level support is for NGINX Plus only and App Protect is enable") - } - - if *appProtectDos && !*nginxPlus { - glog.Fatal("NGINX App Protect Dos support is for NGINX Plus only") - } - - if *appProtectDosDebug && !*appProtectDos && !*nginxPlus { - glog.Fatal("NGINX App Protect Dos debug support is for NGINX Plus only and App Protect Dos is enable") - } - - if *appProtectDosMaxDaemons != 0 && !*appProtectDos && !*nginxPlus { - glog.Fatal("NGINX App Protect Dos max daemons support is for NGINX Plus only and App Protect Dos is enable") - } - - if *appProtectDosMaxWorkers != 0 && !*appProtectDos && !*nginxPlus { - glog.Fatal("NGINX App Protect Dos max workers support is for NGINX Plus and App Protect Dos is enable") - } - - if *appProtectDosMemory != 0 && !*appProtectDos && !*nginxPlus { - glog.Fatal("NGINX App Protect Dos memory support is for NGINX Plus and App Protect Dos is enable") - } - - if *enableInternalRoutes && *spireAgentAddress == "" { - glog.Fatal("enable-internal-routes flag requires spire-agent-address") - } - +func initValidate() { if *enableLatencyMetrics && !*enablePrometheusMetrics { glog.Warning("enable-latency-metrics flag requires enable-prometheus-metrics, latency metrics will not be collected") *enableLatencyMetrics = false @@ -271,26 +233,14 @@ func parseFlags() { *enableServiceInsight = false } - if *enableCertManager && !*enableCustomResources { - glog.Fatal("enable-cert-manager flag requires -enable-custom-resources") - } - - if *enableExternalDNS && !*enableCustomResources { - glog.Fatal("enable-external-dns flag requires -enable-custom-resources") - } - - if *ingressLink != "" && *externalService != "" { - glog.Fatal("ingresslink and external-service cannot both be set") - } - if *enableDynamicWeightChangesReload && !*nginxPlus { glog.Warning("weight-changes-dynamic-reload flag support is for NGINX Plus, Dynamic Weight Changes will not be enabled") *enableDynamicWeightChangesReload = false } - if *agent && !*appProtect { - glog.Fatal("NGINX Agent is used to enable the Security Monitoring dashboard and requires NGINX App Protect to be enabled") - } + mustValidateInitialChecks() + mustValidateWatchedNamespaces() + mustValidateFlags() } func mustValidateInitialChecks() { @@ -402,6 +352,58 @@ func mustValidateFlags() { glog.Fatalf("Invalid value for app-protect-log-level: %v", *appProtectLogLevel) } } + + if *enableTLSPassthrough && !*enableCustomResources { + glog.Fatal("enable-tls-passthrough flag requires -enable-custom-resources") + } + + if *appProtect && !*nginxPlus { + glog.Fatal("NGINX App Protect support is for NGINX Plus only") + } + + if *appProtectLogLevel != appProtectLogLevelDefault && !*appProtect && !*nginxPlus { + glog.Fatal("app-protect-log-level support is for NGINX Plus only and App Protect is enable") + } + + if *appProtectDos && !*nginxPlus { + glog.Fatal("NGINX App Protect Dos support is for NGINX Plus only") + } + + if *appProtectDosDebug && !*appProtectDos && !*nginxPlus { + glog.Fatal("NGINX App Protect Dos debug support is for NGINX Plus only and App Protect Dos is enable") + } + + if *appProtectDosMaxDaemons != 0 && !*appProtectDos && !*nginxPlus { + glog.Fatal("NGINX App Protect Dos max daemons support is for NGINX Plus only and App Protect Dos is enable") + } + + if *appProtectDosMaxWorkers != 0 && !*appProtectDos && !*nginxPlus { + glog.Fatal("NGINX App Protect Dos max workers support is for NGINX Plus and App Protect Dos is enable") + } + + if *appProtectDosMemory != 0 && !*appProtectDos && !*nginxPlus { + glog.Fatal("NGINX App Protect Dos memory support is for NGINX Plus and App Protect Dos is enable") + } + + if *enableInternalRoutes && *spireAgentAddress == "" { + glog.Fatal("enable-internal-routes flag requires spire-agent-address") + } + + if *enableCertManager && !*enableCustomResources { + glog.Fatal("enable-cert-manager flag requires -enable-custom-resources") + } + + if *enableExternalDNS && !*enableCustomResources { + glog.Fatal("enable-external-dns flag requires -enable-custom-resources") + } + + if *ingressLink != "" && *externalService != "" { + glog.Fatal("ingresslink and external-service cannot both be set") + } + + if *agent && !*appProtect { + glog.Fatal("NGINX Agent is used to enable the Security Monitoring dashboard and requires NGINX App Protect to be enabled") + } } // validateNamespaceNames validates the namespaces are in the correct format diff --git a/cmd/nginx-ingress/main.go b/cmd/nginx-ingress/main.go index ccb6dd77f9..fe70d76eb1 100644 --- a/cmd/nginx-ingress/main.go +++ b/cmd/nginx-ingress/main.go @@ -62,8 +62,8 @@ const ( func main() { commitHash, commitTime, dirtyBuild := getBuildInfo() fmt.Printf("NGINX Ingress Controller Version=%v Commit=%v Date=%v DirtyState=%v Arch=%v/%v Go=%v\n", version, commitHash, commitTime, dirtyBuild, runtime.GOOS, runtime.GOARCH, runtime.Version()) - parseFlags() + initValidate() parsedFlags := os.Args[1:] buildOS := os.Getenv("BUILD_OS") From 3f47e40af9cfd0cc545c722d88ca3504b504f4a6 Mon Sep 17 00:00:00 2001 From: Madhu Rajagopal Date: Thu, 26 Sep 2024 20:43:21 +1200 Subject: [PATCH 4/5] Docs: Added Support page (#6467) --- .../troubleshooting/troubleshoot-common.md | 2 +- .../troubleshoot-configmap-policy.md | 2 +- .../troubleshooting/troubleshoot-support.md | 40 +++++++++++++++++++ .../troubleshoot-transportserver.md | 2 +- .../troubleshoot-virtualserver.md | 2 +- 5 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 docs/content/troubleshooting/troubleshoot-support.md diff --git a/docs/content/troubleshooting/troubleshoot-common.md b/docs/content/troubleshooting/troubleshoot-common.md index bfb20b7155..7a99f26761 100644 --- a/docs/content/troubleshooting/troubleshoot-common.md +++ b/docs/content/troubleshooting/troubleshoot-common.md @@ -7,7 +7,7 @@ tags: - docs title: Troubleshooting common issues toc: true -weight: 100 +weight: 200 --- This page describes how to troubleshoot common issues with NGINX Ingress Controller. Instruction for specific resources is available in the [Troubleshooting]({{< relref "troubleshooting/" >}}) section. diff --git a/docs/content/troubleshooting/troubleshoot-configmap-policy.md b/docs/content/troubleshooting/troubleshoot-configmap-policy.md index 8c5227b26f..34ae10337c 100644 --- a/docs/content/troubleshooting/troubleshoot-configmap-policy.md +++ b/docs/content/troubleshooting/troubleshoot-configmap-policy.md @@ -4,7 +4,7 @@ doctypes: - '' title: Troubleshooting Policy resources toc: true -weight: 200 +weight: 300 --- This page describes how to troubleshoot NGINX Ingress Controller Policy Resources. diff --git a/docs/content/troubleshooting/troubleshoot-support.md b/docs/content/troubleshooting/troubleshoot-support.md new file mode 100644 index 0000000000..b9b99d2139 --- /dev/null +++ b/docs/content/troubleshooting/troubleshoot-support.md @@ -0,0 +1,40 @@ +--- +title: Commercial support +weight: 100 +docs: DOCS-000 +--- + +F5 NGINX Ingress Controller adheres to the support policy detailed in the following knowledge base article: [K000140156](https://my.f5.com/manage/s/article/K000140156). + +After opening a support ticket, F5 staff will request additional information to better understand the problem. + +The [nginx-supportpkg-for-k8s](https://github.com/nginxinc/nginx-supportpkg-for-k8s) plugin collects the information needed by F5 Technical Support to assist with troubleshooting your issue. + +When used, the plugin will generate a tarball of the collected information which can be shared with the support channels. + + +The plugin uses [krew](https://krew.sigs.k8s.io), the plugin manager for the Kubernetes [kubectl](https://kubernetes.io/docs/reference/kubectl/) command-line tool. + +The plugin may collect some or all of the following global and namespace-specific information: + +* K8s version, nodes information, and Custom Resources (kubectl describe output) +* Pods' logs +* List of Pods, events, ConfigMaps, Services, Deployments, Daemonsets, StatefulSets, ReplicaSets, and Leases +* K8s metrics +* Helm deployments +* `nginx -T` output from NGINX-related pods + +This plugin **does not** collect secrets or coredumps. + +Visit the [project’s GitHub repository](https://github.com/nginxinc/nginx-supportpkg-for-k8s) for further details. + + +## Support channels + +- If you experience issues with NGINX Ingress Controller, please [open an issue](https://github.com/nginxinc/kubernetes-ingress/issues/new?assignees=&labels=bug%2Cneeds+triage&projects=&template=BUG-REPORT.yml&title=%5BBug%5D%3A+) in GitHub. + +- If you have any enhancement requests, please [open a feature request](https://github.com/nginxinc/kubernetes-ingress/issues/new?assignees=&labels=proposal&projects=&template=feature_request.md&title=) in GitHub. + +- If you have any ideas or suggestions to discuss, please [open an idea discussion](https://github.com/nginxinc/kubernetes-ingress/discussions/categories/ideas) in GitHub. + +- You can contact us directly, by sending an email to [kubernetes@nginx.com](mailto:kubernetes@nginx.com). diff --git a/docs/content/troubleshooting/troubleshoot-transportserver.md b/docs/content/troubleshooting/troubleshoot-transportserver.md index 50dd972621..4d5fa7112d 100644 --- a/docs/content/troubleshooting/troubleshoot-transportserver.md +++ b/docs/content/troubleshooting/troubleshoot-transportserver.md @@ -3,7 +3,7 @@ doctypes: - '' draft: true title: Troubleshooting TransportServer Resources -weight: 400 +weight: 500 --- # Troubleshooting TransportServer Resources diff --git a/docs/content/troubleshooting/troubleshoot-virtualserver.md b/docs/content/troubleshooting/troubleshoot-virtualserver.md index 8d6b74e834..72af8d32c0 100644 --- a/docs/content/troubleshooting/troubleshoot-virtualserver.md +++ b/docs/content/troubleshooting/troubleshoot-virtualserver.md @@ -4,7 +4,7 @@ doctypes: - '' title: Troubleshooting VirtualServer resources toc: true -weight: 500 +weight: 600 --- This page describes how to troubleshoot VirtualServer and VirtualServer resource events. From 4e2e789cb744a7ab894034289b09e0b80dd5a75f Mon Sep 17 00:00:00 2001 From: Paul Abel <128620221+pdabelf5@users.noreply.github.com> Date: Thu, 26 Sep 2024 10:16:31 +0100 Subject: [PATCH 5/5] Slog handler (#6474) --- internal/logger/glog/handler.go | 129 +++++++++++++++++++++++++++ internal/logger/glog/handler_test.go | 93 +++++++++++++++++++ internal/logger/logger.go | 24 +++++ 3 files changed, 246 insertions(+) create mode 100644 internal/logger/glog/handler.go create mode 100644 internal/logger/glog/handler_test.go create mode 100644 internal/logger/logger.go diff --git a/internal/logger/glog/handler.go b/internal/logger/glog/handler.go new file mode 100644 index 0000000000..335310e403 --- /dev/null +++ b/internal/logger/glog/handler.go @@ -0,0 +1,129 @@ +package glog + +// Custom log levels https://go.dev/src/log/slog/example_custom_levels_test.go - for fatal & trace + +import ( + "context" + "io" + "log/slog" + "os" + "runtime" + "strconv" + "strings" + "sync" +) + +const ( + // LevelTrace - Trace Level Logging same as glog.V(3) + LevelTrace = slog.Level(-8) + // LevelDebug - Debug Level Logging same as glog.V(2) + LevelDebug = slog.LevelDebug + // LevelInfo - Info Level Logging same as glog.Info() + LevelInfo = slog.LevelInfo + // LevelWarning - Warn Level Logging same as glog.Warning() + LevelWarning = slog.LevelWarn + // LevelError - Error Level Logging same as glog.Error() + LevelError = slog.LevelError + // LevelFatal - Fatal Level Logging same as glog.Fatal() + LevelFatal = slog.Level(12) +) + +// Handler holds all the parameters for the handler +type Handler struct { + opts Options + mu *sync.Mutex + out io.Writer +} + +// Options contains the log Level +type Options struct { + // Level reports the minimum level to log. + // Levels with lower levels are discarded. + // If nil, the Handler uses [slog.LevelInfo]. + Level slog.Leveler +} + +// New - create a new Handler +func New(out io.Writer, opts *Options) *Handler { + h := &Handler{out: out, mu: &sync.Mutex{}} + if opts != nil { + h.opts = *opts + } + if h.opts.Level == nil { + h.opts.Level = slog.LevelInfo + } + return h +} + +// Enabled - is this log level enabled? +func (h *Handler) Enabled(_ context.Context, level slog.Level) bool { + return level >= h.opts.Level.Level() +} + +// WithGroup - not needed +func (h *Handler) WithGroup(_ string) slog.Handler { + // not needed. + return h +} + +// WithAttrs - not needed +func (h *Handler) WithAttrs(_ []slog.Attr) slog.Handler { + // not needed. + return h +} + +// Handle log event +// Format F20240920 16:53:18.817844 70741 main.go:285] message +// +// YYYYMMDD HH:MM:SS.NNNNNN : +func (h *Handler) Handle(_ context.Context, r slog.Record) error { + buf := make([]byte, 0, 1024) + // LogLevel + switch r.Level { + case LevelTrace: + buf = append(buf, "I"...) + case LevelDebug: + buf = append(buf, "I"...) + case LevelInfo: + buf = append(buf, "I"...) + case LevelWarning: + buf = append(buf, "W"...) + case LevelError: + buf = append(buf, "E"...) + case LevelFatal: + buf = append(buf, "F"...) + } + + // date/time + if !r.Time.IsZero() { + buf = append(buf, r.Time.Format("20060102 15:04:05.000000")...) + } + + buf = append(buf, " "...) + + // PID + buf = append(buf, strconv.Itoa(os.Getpid())...) + + buf = append(buf, " "...) + // Log line + if r.PC != 0 { + fs := runtime.CallersFrames([]uintptr{r.PC}) + f, _ := fs.Next() + buf = append(buf, getShortFileName(f.File)...) + buf = append(buf, ":"...) + buf = append(buf, strconv.Itoa(f.Line)...) + } + buf = append(buf, "]"...) + buf = append(buf, " "...) + buf = append(buf, r.Message...) + buf = append(buf, "\n"...) + h.mu.Lock() + defer h.mu.Unlock() + _, err := h.out.Write(buf) + return err +} + +func getShortFileName(f string) string { + fp := strings.Split(f, "/") + return fp[len(fp)-1] +} diff --git a/internal/logger/glog/handler_test.go b/internal/logger/glog/handler_test.go new file mode 100644 index 0000000000..ef99f00092 --- /dev/null +++ b/internal/logger/glog/handler_test.go @@ -0,0 +1,93 @@ +package glog + +import ( + "bytes" + "context" + "log/slog" + "regexp" + "testing" +) + +func TestGlogFormat(t *testing.T) { + var buf bytes.Buffer + l := slog.New(New(&buf, nil)) + l.Info("hello") + got := buf.String() + wantre := `^\w\d{8}\s\d+:\d+:\d+.\d{6}\s+\d+\s\w+\.go:\d+\]\s.*\s$` + re := regexp.MustCompile(wantre) + if !re.MatchString(got) { + t.Errorf("\ngot:\n%q\nwant:\n%q", got, wantre) + } +} + +func TestGlogLogLevels(t *testing.T) { + testCases := []struct { + name string + level slog.Level + wantre string + }{ + { + name: "Trace level log message", + level: LevelTrace, + wantre: `^I\d{8}\s\d+:\d+:\d+.\d{6}\s+\d+\s\w+\.go:\d+\]\s.*\s$`, + }, + { + name: "Debug level log message", + level: LevelDebug, + wantre: `^I\d{8}\s\d+:\d+:\d+.\d{6}\s+\d+\s\w+\.go:\d+\]\s.*\s$`, + }, + { + name: "Info level log message", + level: LevelInfo, + wantre: `^I\d{8}\s\d+:\d+:\d+.\d{6}\s+\d+\s\w+\.go:\d+\]\s.*\s$`, + }, + { + name: "Warning level log message", + level: LevelWarning, + wantre: `^W\d{8}\s\d+:\d+:\d+.\d{6}\s+\d+\s\w+\.go:\d+\]\s.*\s$`, + }, + { + name: "Error level log message", + level: LevelError, + wantre: `^E\d{8}\s\d+:\d+:\d+.\d{6}\s+\d+\s\w+\.go:\d+\]\s.*\s$`, + }, + { + name: "Fatal level log message", + level: LevelFatal, + wantre: `^F\d{8}\s\d+:\d+:\d+.\d{6}\s+\d+\s\w+\.go:\d+\]\s.*\s$`, + }, + } + t.Parallel() + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var buf bytes.Buffer + l := slog.New(New(&buf, &Options{Level: tc.level})) + l.Log(context.Background(), tc.level, "test") + got := buf.String() + re := regexp.MustCompile(tc.wantre) + if !re.MatchString(got) { + t.Errorf("\ngot:\n%q\nwant:\n%q", got, tc.wantre) + } + }) + } +} + +func TestGlogDefaultLevel(t *testing.T) { + var buf bytes.Buffer + l := slog.New(New(&buf, nil)) + + l.Debug("test") + if got := buf.Len(); got != 0 { + t.Errorf("got buf.Len() = %d, want 0", got) + } +} + +func TestGlogHigherLevel(t *testing.T) { + var buf bytes.Buffer + l := slog.New(New(&buf, &Options{Level: LevelError})) + + l.Info("test") + if got := buf.Len(); got != 0 { + t.Errorf("got buf.Len() = %d, want 0", got) + } +} diff --git a/internal/logger/logger.go b/internal/logger/logger.go new file mode 100644 index 0000000000..a20f59b2c9 --- /dev/null +++ b/internal/logger/logger.go @@ -0,0 +1,24 @@ +package log + +import ( + "context" + "log/slog" + "os" + + "github.com/nginxinc/kubernetes-ingress/internal/logger/glog" +) + +type ctxLogger struct{} + +// ContextWithLogger adds logger to context +func ContextWithLogger(ctx context.Context, l *slog.Logger) context.Context { + return context.WithValue(ctx, ctxLogger{}, l) +} + +// LoggerFromContext returns logger from context +func LoggerFromContext(ctx context.Context) *slog.Logger { + if l, ok := ctx.Value(ctxLogger{}).(*slog.Logger); ok { + return l + } + return slog.New(glog.New(os.Stdout, nil)) +}