From 282041685f1a8430498c6cef8f1585d86bdaa0d6 Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Fri, 4 Jul 2025 14:18:32 +0100
Subject: [PATCH 01/20] Ensure packages are installed on images
---
tests/data/modules/data.json | 260 ++++++++++++++++++++++++++++
tests/suite/test_docker_packages.py | 18 ++
2 files changed, 278 insertions(+)
create mode 100644 tests/data/modules/data.json
create mode 100644 tests/suite/test_docker_packages.py
diff --git a/tests/data/modules/data.json b/tests/data/modules/data.json
new file mode 100644
index 0000000000..9faa657223
--- /dev/null
+++ b/tests/data/modules/data.json
@@ -0,0 +1,260 @@
+{
+ "images": [
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:edge",
+ "packages": [
+ "nginx",
+ "nginx-module-njs",
+ "nginx-module-otel",
+ "nginx-agent"
+ ],
+ "cmd": "dpkg -l",
+ "regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
+ "platform": "linux/arm64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:edge",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-agent"
+ ],
+ "cmd": "dpkg -l",
+ "regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
+ "platform": "linux/arm64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:edge",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-plus-module-appprotect",
+ "nginx-agent"
+ ],
+ "cmd": "dpkg -l",
+ "regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
+ "platform": "linux/amd64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:edge",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-plus-module-appprotect",
+ "nginx-agent"
+ ],
+ "cmd": "dpkg -l",
+ "regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
+ "platform": "linux/amd64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:edge",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-plus-module-appprotectdos"
+ ],
+ "cmd": "dpkg -l",
+ "regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
+ "platform": "linux/amd64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:edge",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-plus-module-appprotect",
+ "nginx-plus-module-appprotectdos",
+ "nginx-agent"
+ ],
+ "cmd": "dpkg -l",
+ "regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
+ "platform": "linux/amd64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:edge-alpine",
+ "packages": [
+ "nginx",
+ "nginx-module-njs",
+ "nginx-module-otel",
+ "nginx-agent"
+ ],
+ "cmd": "apk list",
+ "regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
+ "platform": "linux/arm64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:edge-alpine",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-agent"
+ ],
+ "cmd": "apk list",
+ "regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
+ "platform": "linux/arm64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:edge-alpine-fips",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-agent"
+ ],
+ "cmd": "apk list",
+ "regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
+ "platform": "linux/arm64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:edge-alpine-fips",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-agent",
+ "nginx-plus-module-appprotect"
+ ],
+ "cmd": "apk list",
+ "regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
+ "platform": "linux/amd64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:edge-alpine-fips",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-agent",
+ "nginx-plus-module-appprotect"
+ ],
+ "cmd": "apk list",
+ "regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
+ "platform": "linux/amd64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:edge-ubi",
+ "packages": [
+ "nginx",
+ "nginx-module-njs",
+ "nginx-module-otel",
+ "nginx-agent"
+ ],
+ "cmd": "rpm -q",
+ "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "platform": "linux/arm64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:edge-ubi",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-agent"
+ ],
+ "cmd": "rpm -q",
+ "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "platform": "linux/arm64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:edge-ubi",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-agent",
+ "nginx-plus-module-appprotect"
+ ],
+ "cmd": "rpm -q",
+ "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "platform": "linux/amd64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:edge-ubi",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-agent",
+ "nginx-plus-module-appprotect"
+ ],
+ "cmd": "rpm -q",
+ "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "platform": "linux/amd64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:edge-ubi8",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-agent",
+ "nginx-plus-module-appprotect"
+ ],
+ "cmd": "rpm -q",
+ "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "platform": "linux/amd64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:edge-ubi8",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-agent",
+ "nginx-plus-module-appprotect"
+ ],
+ "cmd": "rpm -q",
+ "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "platform": "linux/amd64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:edge-ubi",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-plus-module-appprotectdos"
+ ],
+ "cmd": "rpm -q",
+ "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "platform": "linux/amd64"
+ },
+ {
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:edge-ubi",
+ "packages": [
+ "nginx-plus",
+ "nginx-plus-module-njs",
+ "nginx-plus-module-otel",
+ "nginx-plus-module-fips-check",
+ "nginx-plus-module-appprotect",
+ "nginx-plus-module-appprotectdos",
+ "nginx-agent"
+ ],
+ "cmd": "rpm -q",
+ "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "platform": "linux/amd64"
+ }
+ ]
+}
diff --git a/tests/suite/test_docker_packages.py b/tests/suite/test_docker_packages.py
new file mode 100644
index 0000000000..943714349c
--- /dev/null
+++ b/tests/suite/test_docker_packages.py
@@ -0,0 +1,18 @@
+import json
+import re
+
+import docker
+
+client = docker.from_env()
+images = json.loads(open("tests/data/modules/data.json").read())
+
+for image in images["images"]:
+ regexInstalled = image["regex"]
+ for package in image["packages"]:
+ command = f"{image['cmd']} {package}"
+ output = client.containers.run(
+ image["image"], command, entrypoint="", platform=image["platform"], auto_remove=True, detach=False
+ )
+ result = re.search(regexInstalled, output.decode("utf-8").strip())
+ assert result, f"{package} not found in {image['image']}, output: {output.decode('utf-8').strip()}"
+ print(image["image"], result.group(1, 2, 3))
From 20294fcba84ba0a448723ff8bc2bd1b84ec18e63 Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Fri, 4 Jul 2025 15:36:29 +0100
Subject: [PATCH 02/20] Expand to include package versions
---
tests/data/modules/data.json | 774 ++++++++++++++++++++++++----
tests/suite/test_docker_packages.py | 7 +-
2 files changed, 675 insertions(+), 106 deletions(-)
diff --git a/tests/data/modules/data.json b/tests/data/modules/data.json
index 9faa657223..3185a13ad8 100644
--- a/tests/data/modules/data.json
+++ b/tests/data/modules/data.json
@@ -3,10 +3,26 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:edge",
"packages": [
- "nginx",
- "nginx-module-njs",
- "nginx-module-otel",
- "nginx-agent"
+ {
+ "name": "nginx",
+ "version": "1.27.5",
+ "arch": "arm64"
+ },
+ {
+ "name": "nginx-module-njs",
+ "version": "1.27.5",
+ "arch": "arm64"
+ },
+ {
+ "name": "nginx-module-otel",
+ "version": "1.27.5",
+ "arch": "arm64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "3.0",
+ "arch": "arm64"
+ }
],
"cmd": "dpkg -l",
"regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
@@ -15,11 +31,31 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:edge",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-agent"
+ {
+ "name": "nginx-plus",
+ "version": "34-2",
+ "arch": "arm64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "arm64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "arm64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "arm64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "3.0",
+ "arch": "arm64"
+ }
],
"cmd": "dpkg -l",
"regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
@@ -28,12 +64,51 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:edge",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-plus-module-appprotect",
- "nginx-agent"
+ {
+ "name": "nginx-plus",
+ "version": "34-2",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-appprotect",
+ "version": "34+5.442",
+ "arch": "amd64"
+ },
+ {
+ "name": "app-protect",
+ "version": "34+5.442",
+ "arch": "amd64"
+ },
+ {
+ "name": "app-protect-attack-signatures",
+ "version": "2025",
+ "arch": "amd64"
+ },
+ {
+ "name": "app-protect-threat-campaigns",
+ "version": "2025",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "2",
+ "arch": "amd64"
+ }
],
"cmd": "dpkg -l",
"regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
@@ -42,12 +117,46 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:edge",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-plus-module-appprotect",
- "nginx-agent"
+ {
+ "name": "nginx-plus",
+ "version": "34-2",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-appprotect",
+ "version": "34+5.442",
+ "arch": "amd64"
+ },
+ {
+ "name": "app-protect-module-plus",
+ "version": "34+5.442",
+ "arch": "amd64"
+ },
+ {
+ "name": "app-protect-plugin",
+ "version": "6.16.0",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "2",
+ "arch": "amd64"
+ }
],
"cmd": "dpkg -l",
"regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
@@ -56,11 +165,36 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:edge",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-plus-module-appprotectdos"
+ {
+ "name": "nginx-plus",
+ "version": "34-2",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-appprotectdos",
+ "version": "34+4",
+ "arch": "amd64"
+ },
+ {
+ "name": "app-protect-dos",
+ "version": "34+4",
+ "arch": "amd64"
+ }
],
"cmd": "dpkg -l",
"regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
@@ -69,13 +203,61 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:edge",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-plus-module-appprotect",
- "nginx-plus-module-appprotectdos",
- "nginx-agent"
+ {
+ "name": "nginx-plus",
+ "version": "34-2",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-appprotect",
+ "version": "34+5.442",
+ "arch": "amd64"
+ },
+ {
+ "name": "app-protect",
+ "version": "34+5.442",
+ "arch": "amd64"
+ },
+ {
+ "name": "app-protect-attack-signatures",
+ "version": "2025",
+ "arch": "amd64"
+ },
+ {
+ "name": "app-protect-threat-campaigns",
+ "version": "2025",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-plus-module-appprotectdos",
+ "version": "34+4",
+ "arch": "amd64"
+ },
+ {
+ "name": "app-protect-dos",
+ "version": "34+4",
+ "arch": "amd64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "2",
+ "arch": "amd64"
+ }
],
"cmd": "dpkg -l",
"regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
@@ -84,10 +266,26 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:edge-alpine",
"packages": [
- "nginx",
- "nginx-module-njs",
- "nginx-module-otel",
- "nginx-agent"
+ {
+ "name": "nginx",
+ "version": "1.27.5",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-module-njs",
+ "version": "1.27.5",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-module-otel",
+ "version": "1.27.5",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "3.0",
+ "arch": "aarch64"
+ }
],
"cmd": "apk list",
"regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
@@ -96,11 +294,31 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:edge-alpine",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-agent"
+ {
+ "name": "nginx-plus",
+ "version": "34-r2",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "3.0",
+ "arch": "aarch64"
+ }
],
"cmd": "apk list",
"regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
@@ -109,11 +327,31 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:edge-alpine-fips",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-agent"
+ {
+ "name": "nginx-plus",
+ "version": "34-r2",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "3.0",
+ "arch": "aarch64"
+ }
],
"cmd": "apk list",
"regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
@@ -122,12 +360,51 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:edge-alpine-fips",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-agent",
- "nginx-plus-module-appprotect"
+ {
+ "name": "nginx-plus",
+ "version": "34-r2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-appprotect",
+ "version": "34.5.442",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect",
+ "version": "34.5.442",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-attack-signatures",
+ "version": "2025",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-threat-campaigns",
+ "version": "2025",
+ "arch": "x86_64"
+ }
],
"cmd": "apk list",
"regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
@@ -136,12 +413,46 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:edge-alpine-fips",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-agent",
- "nginx-plus-module-appprotect"
+ {
+ "name": "nginx-plus",
+ "version": "34-r2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-appprotect",
+ "version": "34.5.442",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-module-plus",
+ "version": "34.5.442",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-plugin",
+ "version": "6.16.0",
+ "arch": "x86_64"
+ }
],
"cmd": "apk list",
"regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
@@ -150,10 +461,26 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:edge-ubi",
"packages": [
- "nginx",
- "nginx-module-njs",
- "nginx-module-otel",
- "nginx-agent"
+ {
+ "name": "nginx",
+ "version": "1.27.5",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-module-njs",
+ "version": "1.27.5",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-module-otel",
+ "version": "1.27.5",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "3.0",
+ "arch": "aarch64"
+ }
],
"cmd": "rpm -q",
"regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
@@ -162,11 +489,31 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:edge-ubi",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-agent"
+ {
+ "name": "nginx-plus",
+ "version": "34-2",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "aarch64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "3.0",
+ "arch": "aarch64"
+ }
],
"cmd": "rpm -q",
"regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
@@ -175,12 +522,51 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:edge-ubi",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-agent",
- "nginx-plus-module-appprotect"
+ {
+ "name": "nginx-plus",
+ "version": "34-2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-appprotect",
+ "version": "34+5.442",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect",
+ "version": "34+5.442",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-attack-signatures",
+ "version": "2025",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-threat-campaigns",
+ "version": "2025",
+ "arch": "x86_64"
+ }
],
"cmd": "rpm -q",
"regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
@@ -189,12 +575,46 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:edge-ubi",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-agent",
- "nginx-plus-module-appprotect"
+ {
+ "name": "nginx-plus",
+ "version": "34-2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-appprotect",
+ "version": "34+5.442",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-module-plus",
+ "version": "34+5.442",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-plugin",
+ "version": "6.16.0",
+ "arch": "x86_64"
+ }
],
"cmd": "rpm -q",
"regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
@@ -203,12 +623,51 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:edge-ubi8",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-agent",
- "nginx-plus-module-appprotect"
+ {
+ "name": "nginx-plus",
+ "version": "34-2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-appprotect",
+ "version": "34+5.442",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect",
+ "version": "34+5.442",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-attack-signatures",
+ "version": "2025",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-threat-campaigns",
+ "version": "2025",
+ "arch": "x86_64"
+ }
],
"cmd": "rpm -q",
"regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
@@ -217,12 +676,46 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:edge-ubi8",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-agent",
- "nginx-plus-module-appprotect"
+ {
+ "name": "nginx-plus",
+ "version": "34-2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-appprotect",
+ "version": "34+5.442",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-module-plus",
+ "version": "34+5.442",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-plugin",
+ "version": "6.16.0",
+ "arch": "x86_64"
+ }
],
"cmd": "rpm -q",
"regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
@@ -231,11 +724,36 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:edge-ubi",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-plus-module-appprotectdos"
+ {
+ "name": "nginx-plus",
+ "version": "34-2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-appprotectdos",
+ "version": "34+4",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-dos",
+ "version": "34+4",
+ "arch": "x86_64"
+ }
],
"cmd": "rpm -q",
"regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
@@ -244,13 +762,61 @@
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:edge-ubi",
"packages": [
- "nginx-plus",
- "nginx-plus-module-njs",
- "nginx-plus-module-otel",
- "nginx-plus-module-fips-check",
- "nginx-plus-module-appprotect",
- "nginx-plus-module-appprotectdos",
- "nginx-agent"
+ {
+ "name": "nginx-plus",
+ "version": "34-2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-njs",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-otel",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-fips-check",
+ "version": "34",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-appprotect",
+ "version": "34+5.442",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-plus-module-appprotectdos",
+ "version": "34+4",
+ "arch": "x86_64"
+ },
+ {
+ "name": "nginx-agent",
+ "version": "2",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect",
+ "version": "34+5.442",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-attack-signatures",
+ "version": "2025",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-threat-campaigns",
+ "version": "2025",
+ "arch": "x86_64"
+ },
+ {
+ "name": "app-protect-dos",
+ "version": "34+4",
+ "arch": "x86_64"
+ }
],
"cmd": "rpm -q",
"regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
diff --git a/tests/suite/test_docker_packages.py b/tests/suite/test_docker_packages.py
index 943714349c..db1105f159 100644
--- a/tests/suite/test_docker_packages.py
+++ b/tests/suite/test_docker_packages.py
@@ -9,10 +9,13 @@
for image in images["images"]:
regexInstalled = image["regex"]
for package in image["packages"]:
- command = f"{image['cmd']} {package}"
+ command = f"{image['cmd']} {package['name']}"
output = client.containers.run(
image["image"], command, entrypoint="", platform=image["platform"], auto_remove=True, detach=False
)
result = re.search(regexInstalled, output.decode("utf-8").strip())
- assert result, f"{package} not found in {image['image']}, output: {output.decode('utf-8').strip()}"
+ assert result, f"{package['name']} not found in {image['image']}, output: {output.decode('utf-8').strip()}"
+ assert result.group(2).startswith(
+ package["version"]
+ ), f"{package['name']} version {package['version']} does not match {result.group(2)}"
print(image["image"], result.group(1, 2, 3))
From f8c26eeebd8afc334598f06651331bb8fd7dc05c Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Fri, 4 Jul 2025 16:59:07 +0100
Subject: [PATCH 03/20] add test to ci
---
.github/workflows/ci.yml | 48 +++++++++++++++++++++++++++++
tests/requirements.txt | 6 ++++
tests/suite/test_docker_packages.py | 2 ++
3 files changed, 56 insertions(+)
mode change 100644 => 100755 tests/suite/test_docker_packages.py
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c438c0b1f8..43354a8b98 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -377,6 +377,54 @@ jobs:
secrets: inherit
if: ${{ inputs.force || (needs.checks.outputs.forked_workflow == 'true' && needs.checks.outputs.docs_only == 'false') || (needs.checks.outputs.forked_workflow == 'false' && needs.checks.outputs.stable_image_exists != 'true' && needs.checks.outputs.docs_only == 'false') }}
+ package-tests:
+ if: ${{ needs.checks.outputs.docs_only != 'true' }}
+ name: Package Tests
+ runs-on: ubuntu-22.04
+ needs: [checks, binaries, build-docker, build-docker-plus, build-docker-nap]
+ permissions:
+ contents: read
+ id-token: write
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+ - name: Authenticate to Google Cloud
+ id: auth
+ uses: google-github-actions/auth@ba79af03959ebeac9769e648f473a284504d9193 # v2.1.10
+ with:
+ token_format: access_token
+ workload_identity_provider: ${{ secrets.GCR_WORKLOAD_IDENTITY }}
+ service_account: ${{ secrets.GCR_SERVICE_ACCOUNT }}
+ if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Login to GCR
+ uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
+ with:
+ registry: gcr.io
+ username: oauth2accesstoken
+ password: ${{ steps.auth.outputs.access_token }}
+ if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Install Python dependencies
+ run: |
+ make -f tests/Makefile setup-venv
+ if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Run tests
+ id: packages
+ run: |
+ source tests/venv/bin/activate
+ python tests/suite/test_docker_packages.py | tee package_output.txt 2&>1
+ if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Add comment
+ run: |
+ gh pr comment ${{ github.event.pull_request.number }} -F package_output.txt
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ if: ${{ ( needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' ) && github.event.pull_request }}
+
helm-tests:
if: ${{ needs.checks.outputs.docs_only != 'true' && (inputs.run_tests && inputs.run_tests || true) }}
name: Helm Tests ${{ matrix.base-os }}
diff --git a/tests/requirements.txt b/tests/requirements.txt
index 9f6bf55043..2137354f42 100644
--- a/tests/requirements.txt
+++ b/tests/requirements.txt
@@ -229,6 +229,10 @@ cryptography==45.0.5 \
# via
# -r requirements.in
# pyopenssl
+docker==7.1.0 \
+ --hash=sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c \
+ --hash=sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0
+ # via -r requirements.in
durationpy==0.10 \
--hash=sha256:1fa6893409a6e739c9c72334fc65cca1f355dbdd93405d30f726deb5bde42fba \
--hash=sha256:3b41e1b601234296b4fb368338fdcd3e13e0b4fb5b67345948f4f2bf9868b286
@@ -689,6 +693,7 @@ requests==2.32.4 \
--hash=sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422
# via
# -r requirements.in
+ # docker
# forcediphttpsadapter
# kubernetes
# requests-oauthlib
@@ -722,6 +727,7 @@ urllib3==2.5.0 \
--hash=sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc
# via
# -r requirements.in
+ # docker
# kubernetes
# requests
websocket-client==1.8.0 \
diff --git a/tests/suite/test_docker_packages.py b/tests/suite/test_docker_packages.py
old mode 100644
new mode 100755
index db1105f159..7370abc554
--- a/tests/suite/test_docker_packages.py
+++ b/tests/suite/test_docker_packages.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python
+
import json
import re
From 0ded1d16b9fd4b99373be7d20813f9130d5170fb Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Tue, 15 Jul 2025 15:06:26 +0100
Subject: [PATCH 04/20] move package test script
---
.github/workflows/ci.yml | 2 +-
.../test_container_packages.py} | 0
2 files changed, 1 insertion(+), 1 deletion(-)
rename tests/{suite/test_docker_packages.py => scripts/test_container_packages.py} (100%)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 43354a8b98..a50aa11f39 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -415,7 +415,7 @@ jobs:
id: packages
run: |
source tests/venv/bin/activate
- python tests/suite/test_docker_packages.py | tee package_output.txt 2&>1
+ python tests/scripts/test_container_packages.py | tee package_output.txt 2&>1
if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
- name: Add comment
diff --git a/tests/suite/test_docker_packages.py b/tests/scripts/test_container_packages.py
similarity index 100%
rename from tests/suite/test_docker_packages.py
rename to tests/scripts/test_container_packages.py
From 5fa0f2ed290a2ed701b32fbd640724f05ccbda43 Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Tue, 15 Jul 2025 15:10:48 +0100
Subject: [PATCH 05/20] fix file open issue
---
tests/scripts/test_container_packages.py | 31 +++++++++++++-----------
1 file changed, 17 insertions(+), 14 deletions(-)
diff --git a/tests/scripts/test_container_packages.py b/tests/scripts/test_container_packages.py
index 7370abc554..c56d55fd62 100755
--- a/tests/scripts/test_container_packages.py
+++ b/tests/scripts/test_container_packages.py
@@ -1,23 +1,26 @@
#!/usr/bin/env python
import json
+import os
import re
import docker
client = docker.from_env()
-images = json.loads(open("tests/data/modules/data.json").read())
+script_dir = os.path.dirname(os.path.abspath(__file__))
+with open(f"{script_dir}../data/modules/data.json") as file:
+ images = json.load(file)
-for image in images["images"]:
- regexInstalled = image["regex"]
- for package in image["packages"]:
- command = f"{image['cmd']} {package['name']}"
- output = client.containers.run(
- image["image"], command, entrypoint="", platform=image["platform"], auto_remove=True, detach=False
- )
- result = re.search(regexInstalled, output.decode("utf-8").strip())
- assert result, f"{package['name']} not found in {image['image']}, output: {output.decode('utf-8').strip()}"
- assert result.group(2).startswith(
- package["version"]
- ), f"{package['name']} version {package['version']} does not match {result.group(2)}"
- print(image["image"], result.group(1, 2, 3))
+ for image in images["images"]:
+ regexInstalled = image["regex"]
+ for package in image["packages"]:
+ command = f"{image['cmd']} {package['name']}"
+ output = client.containers.run(
+ image["image"], command, entrypoint="", platform=image["platform"], auto_remove=True, detach=False
+ )
+ result = re.search(regexInstalled, output.decode("utf-8").strip())
+ assert result, f"{package['name']} not found in {image['image']}, output: {output.decode('utf-8').strip()}"
+ assert result.group(2).startswith(
+ package["version"]
+ ), f"{package['name']} version {package['version']} does not match {result.group(2)}"
+ print(image["image"], result.group(1, 2, 3))
From c77470f0979b2963a8d6cd4b4a593caa59a22626 Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Tue, 15 Jul 2025 15:14:59 +0100
Subject: [PATCH 06/20] allow setup-venv to be run outside the tests directory
---
tests/Makefile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/Makefile b/tests/Makefile
index 8fe5f96035..80a9ac807d 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -56,7 +56,7 @@ $(MINIKUBE_KUBE_CONFIG_FOLDER): $(KUBE_CONFIG_FOLDER)
setup-venv:
$(PYTHON) -m venv $(ROOT_DIR)/tests/venv;
source $(ROOT_DIR)/tests/venv/bin/activate \
- && pip install --require-hashes -r requirements.txt --no-deps \
+ && pip install --require-hashes -r $(ROOT_DIR)/tests/requirements.txt --no-deps \
&& playwright install --with-deps chromium
From 8bbb48e344ab5f339cf6bdaf3ef43901ee71d7fc Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Tue, 15 Jul 2025 15:18:52 +0100
Subject: [PATCH 07/20] rename script
---
.github/workflows/ci.yml | 2 +-
.pre-commit-config.yaml | 2 +-
.../{test_container_packages.py => check_container_packages.py} | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
rename tests/scripts/{test_container_packages.py => check_container_packages.py} (93%)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a50aa11f39..44fe654d23 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -415,7 +415,7 @@ jobs:
id: packages
run: |
source tests/venv/bin/activate
- python tests/scripts/test_container_packages.py | tee package_output.txt 2&>1
+ python tests/scripts/check_container_packages.py | tee package_output.txt 2&>1
if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
- name: Add comment
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 82d1981cfa..4bf48df7ba 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -27,7 +27,7 @@ repos:
args: [--fix=lf]
- id: name-tests-test
args: [--pytest-test-first]
- exclude: ^(tests/suite/utils|tests/suite/fixtures|tests/suite/grpc|tests/settings.py)
+ exclude: ^(tests/suite/utils|tests/suite/fixtures|tests/suite/grpc|tests/settings.py|tests/scripts)
- id: no-commit-to-branch
- id: requirements-txt-fixer
- id: fix-byte-order-marker
diff --git a/tests/scripts/test_container_packages.py b/tests/scripts/check_container_packages.py
similarity index 93%
rename from tests/scripts/test_container_packages.py
rename to tests/scripts/check_container_packages.py
index c56d55fd62..c199e871d0 100755
--- a/tests/scripts/test_container_packages.py
+++ b/tests/scripts/check_container_packages.py
@@ -8,7 +8,7 @@
client = docker.from_env()
script_dir = os.path.dirname(os.path.abspath(__file__))
-with open(f"{script_dir}../data/modules/data.json") as file:
+with open(f"{script_dir}/../data/modules/data.json") as file:
images = json.load(file)
for image in images["images"]:
From 026c8938c8eae28b7a4fd1b54683ee585373bbd0 Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Tue, 15 Jul 2025 16:19:49 +0100
Subject: [PATCH 08/20] allow tag to be passed as cli arg
---
.github/workflows/ci.yml | 2 +-
tests/data/modules/data.json | 57 +++++++++++++++--------
tests/scripts/check_container_packages.py | 40 ++++++++++++++--
3 files changed, 76 insertions(+), 23 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 44fe654d23..c111cfb2f7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -415,7 +415,7 @@ jobs:
id: packages
run: |
source tests/venv/bin/activate
- python tests/scripts/check_container_packages.py | tee package_output.txt 2&>1
+ python tests/scripts/check_container_packages.py --tag ${{ needs.checks.outputs.build_tag }} | tee package_output.txt 2&>1
if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
- name: Add comment
diff --git a/tests/data/modules/data.json b/tests/data/modules/data.json
index 3185a13ad8..43939b922d 100644
--- a/tests/data/modules/data.json
+++ b/tests/data/modules/data.json
@@ -1,7 +1,8 @@
{
"images": [
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:edge",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress",
+ "tag_suffix": "",
"packages": [
{
"name": "nginx",
@@ -29,7 +30,8 @@
"platform": "linux/arm64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:edge",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress",
+ "tag_suffix": "",
"packages": [
{
"name": "nginx-plus",
@@ -62,7 +64,8 @@
"platform": "linux/arm64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:edge",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress",
+ "tag_suffix": "",
"packages": [
{
"name": "nginx-plus",
@@ -115,7 +118,8 @@
"platform": "linux/amd64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:edge",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress",
+ "tag_suffix": "",
"packages": [
{
"name": "nginx-plus",
@@ -163,7 +167,8 @@
"platform": "linux/amd64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:edge",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress",
+ "tag_suffix": "",
"packages": [
{
"name": "nginx-plus",
@@ -201,7 +206,8 @@
"platform": "linux/amd64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:edge",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress",
+ "tag_suffix": "",
"packages": [
{
"name": "nginx-plus",
@@ -264,7 +270,8 @@
"platform": "linux/amd64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:edge-alpine",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress",
+ "tag_suffix": "-alpine",
"packages": [
{
"name": "nginx",
@@ -292,7 +299,8 @@
"platform": "linux/arm64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:edge-alpine",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress",
+ "tag_suffix": "-alpine",
"packages": [
{
"name": "nginx-plus",
@@ -325,7 +333,8 @@
"platform": "linux/arm64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:edge-alpine-fips",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress",
+ "tag_suffix": "-alpine-fips",
"packages": [
{
"name": "nginx-plus",
@@ -358,7 +367,8 @@
"platform": "linux/arm64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:edge-alpine-fips",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress",
+ "tag_suffix": "-alpine-fips",
"packages": [
{
"name": "nginx-plus",
@@ -411,7 +421,8 @@
"platform": "linux/amd64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:edge-alpine-fips",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress",
+ "tag_suffix": "-alpine-fips",
"packages": [
{
"name": "nginx-plus",
@@ -459,7 +470,8 @@
"platform": "linux/amd64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress:edge-ubi",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress",
+ "tag_suffix": "-ubi",
"packages": [
{
"name": "nginx",
@@ -487,7 +499,8 @@
"platform": "linux/arm64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress:edge-ubi",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress",
+ "tag_suffix": "-ubi",
"packages": [
{
"name": "nginx-plus",
@@ -520,7 +533,8 @@
"platform": "linux/arm64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:edge-ubi",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress",
+ "tag_suffix": "-ubi",
"packages": [
{
"name": "nginx-plus",
@@ -573,7 +587,8 @@
"platform": "linux/amd64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:edge-ubi",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress",
+ "tag_suffix": "-ubi",
"packages": [
{
"name": "nginx-plus",
@@ -621,7 +636,8 @@
"platform": "linux/amd64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress:edge-ubi8",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress",
+ "tag_suffix": "-ubi8",
"packages": [
{
"name": "nginx-plus",
@@ -674,7 +690,8 @@
"platform": "linux/amd64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress:edge-ubi8",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress",
+ "tag_suffix": "-ubi8",
"packages": [
{
"name": "nginx-plus",
@@ -722,7 +739,8 @@
"platform": "linux/amd64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress:edge-ubi",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress",
+ "tag_suffix": "-ubi",
"packages": [
{
"name": "nginx-plus",
@@ -760,7 +778,8 @@
"platform": "linux/amd64"
},
{
- "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress:edge-ubi",
+ "image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress",
+ "tag_suffix": "-ubi",
"packages": [
{
"name": "nginx-plus",
diff --git a/tests/scripts/check_container_packages.py b/tests/scripts/check_container_packages.py
index c199e871d0..9488b84f18 100755
--- a/tests/scripts/check_container_packages.py
+++ b/tests/scripts/check_container_packages.py
@@ -1,10 +1,17 @@
#!/usr/bin/env python
+import argparse
import json
import os
import re
import docker
+import docker.errors
+
+# parse args
+parser = argparse.ArgumentParser()
+parser.add_argument("-t", "--tag", type=str, help="NGINX Ingress Controller image tag", default="edge")
+args = parser.parse_args()
client = docker.from_env()
script_dir = os.path.dirname(os.path.abspath(__file__))
@@ -13,11 +20,38 @@
for image in images["images"]:
regexInstalled = image["regex"]
+ tag = f"{args.tag}{image['tag_suffix']}"
+ try:
+ client.images.get(f"{image['image']}:{tag}")
+ print(f"Image {image['image']}:{tag} already exists, skipping pull")
+ except docker.errors.ImageNotFound:
+ print(f"Image {image['image']}:{tag} not found, pulling...")
+ ## pull the image
+ print(f"Pulling image {image['image']}:{tag} for platform {image['platform']}")
+ i = client.images.pull(repository=image["image"], tag=tag, platform=image["platform"])
+ print(f"Image {i.id} pulled successfully")
for package in image["packages"]:
command = f"{image['cmd']} {package['name']}"
- output = client.containers.run(
- image["image"], command, entrypoint="", platform=image["platform"], auto_remove=True, detach=False
- )
+ output = ""
+ try:
+ output = client.containers.run(
+ f"{image['image']}:{tag}",
+ command,
+ entrypoint="",
+ platform=image["platform"],
+ auto_remove=True,
+ detach=False,
+ )
+ except (docker.errors.ContainerError, docker.errors.NotFound) as e:
+ print(f"Container error: {e}, retrying")
+ output = client.containers.run(
+ f"{image['image']}:{tag}",
+ command,
+ entrypoint="",
+ platform=image["platform"],
+ auto_remove=True,
+ detach=False,
+ )
result = re.search(regexInstalled, output.decode("utf-8").strip())
assert result, f"{package['name']} not found in {image['image']}, output: {output.decode('utf-8').strip()}"
assert result.group(2).startswith(
From 68c6ef10b2fc665acbb62fcc322f2dbb5fb7fa18 Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Tue, 15 Jul 2025 16:33:34 +0100
Subject: [PATCH 09/20] debug
---
.github/workflows/ci.yml | 352 +--------------------------------------
1 file changed, 1 insertion(+), 351 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c111cfb2f7..970756924d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -415,7 +415,7 @@ jobs:
id: packages
run: |
source tests/venv/bin/activate
- python tests/scripts/check_container_packages.py --tag ${{ needs.checks.outputs.build_tag }} | tee package_output.txt 2&>1
+ python tests/scripts/check_container_packages.py --tag ${{ needs.checks.outputs.build_tag }}
if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
- name: Add comment
@@ -424,353 +424,3 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: ${{ ( needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' ) && github.event.pull_request }}
-
- helm-tests:
- if: ${{ needs.checks.outputs.docs_only != 'true' && (inputs.run_tests && inputs.run_tests || true) }}
- name: Helm Tests ${{ matrix.base-os }}
- runs-on: ubuntu-22.04
- needs: [checks, binaries, build-docker, build-docker-plus]
- strategy:
- fail-fast: false
- matrix:
- include:
- - base-os: debian
- image: gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress
- tag: ${{ needs.checks.outputs.build_tag }}
- type: oss
- - base-os: debian-plus
- image: gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress
- tag: ${{ needs.checks.outputs.build_tag }}
- type: plus
- permissions:
- contents: read
- id-token: write
- steps:
- - name: Checkout Repository
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
- - name: Authenticate to Google Cloud
- id: auth
- uses: google-github-actions/auth@ba79af03959ebeac9769e648f473a284504d9193 # v2.1.10
- with:
- token_format: access_token
- workload_identity_provider: ${{ secrets.GCR_WORKLOAD_IDENTITY }}
- service_account: ${{ secrets.GCR_SERVICE_ACCOUNT }}
- if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
-
- - name: Login to GCR
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
- with:
- registry: gcr.io
- username: oauth2accesstoken
- password: ${{ steps.auth.outputs.access_token }}
- if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
-
- - name: Check if stable image exists
- id: stable_exists
- run: |
- if docker pull ${{ matrix.image }}:${{ needs.checks.outputs.stable_tag }}; then
- echo "exists=true" >> $GITHUB_OUTPUT
- fi
- if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
-
- - name: Pull build image
- run: |
- docker pull ${{ matrix.image }}:${{ needs.checks.outputs.build_tag }}
- if: ${{ ( needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' ) && steps.stable_exists.outputs.exists != 'true' }}
-
- - name: Fetch Cached Artifacts
- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
- with:
- path: ${{ github.workspace }}/dist
- key: nginx-ingress-${{ needs.checks.outputs.go_code_md5 }}
- if: ${{ needs.checks.outputs.forked_workflow == 'true' && needs.checks.outputs.docs_only == 'false' }}
-
- - name: Docker Buildx
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
- if: ${{ needs.checks.outputs.forked_workflow == 'true' && needs.checks.outputs.docs_only == 'false' }}
-
- - name: Build Docker Image ${{ matrix.base-os }}
- uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
- with:
- file: build/Dockerfile
- context: "."
- cache-from: type=gha,scope=${{ matrix.base-os }}
- target: goreleaser
- tags: "${{ matrix.image }}:${{ matrix.tag }}"
- pull: true
- load: true
- build-args: |
- BUILD_OS=${{ matrix.base-os }}
- IC_VERSION=CI
- secrets: |
- ${{ matrix.type == 'plus' && format('"nginx-repo.crt={0}"', secrets.NGINX_CRT) || '' }}
- ${{ matrix.type == 'plus' && format('"nginx-repo.key={0}"', secrets.NGINX_KEY) || '' }}
- if: ${{ needs.checks.outputs.forked_workflow == 'true' && needs.checks.outputs.docs_only == 'false' }}
-
- - name: Deploy Kubernetes
- id: k8s
- run: |
- kind create cluster --name ${{ github.run_id }} --image=kindest/node:v${{ needs.checks.outputs.k8s_latest }} --wait 75s
- docker version
- kind load docker-image "${{ matrix.image }}:${{ matrix.tag }}" --name ${{ github.run_id }}
- echo "DEBUG: Kind setup complete!"
- if: ${{ steps.stable_exists.outputs.exists != 'true' && needs.checks.outputs.docs_only == 'false' }}
-
- - name: Create Plus Secret
- run: kubectl create secret generic license-token --from-literal=license.jwt="${{ secrets.PLUS_JWT }}" --type="nginx.com/license"
- if: ${{ matrix.type == 'plus' && steps.stable_exists.outputs.exists != 'true' && needs.checks.outputs.docs_only == 'false' }}
-
- - name: Install Chart
- run: >
- helm install
- ${{ matrix.type }}
- .
- --set controller.image.repository=${{ matrix.image }}
- --set controller.image.tag=${{ matrix.tag }}
- --set controller.service.type=NodePort
- --set controller.nginxplus=${{ contains(matrix.type, 'plus') && 'true' || 'false' }}
- --set controller.telemetryReporting.enable=false
- --wait
- working-directory: ${{ github.workspace }}/charts/nginx-ingress
- if: ${{ steps.stable_exists.outputs.exists != 'true' && needs.checks.outputs.docs_only == 'false' }}
-
- - name: Expose Test Ingresses
- run: |
- kubectl port-forward service/${{ matrix.type }}-nginx-ingress-controller 8080:80 8443:443 &
- if: ${{ steps.stable_exists.outputs.exists != 'true' && needs.checks.outputs.docs_only == 'false' }}
-
- - name: Test HTTP
- run: |
- counter=0
- max_attempts=5
- until [ $(curl --write-out %{http_code} -s --output /dev/null http://localhost:8080) -eq 404 ]; do
- if [ ${counter} -eq ${max_attempts} ]; then
- exit 1
- fi
- printf '.'; counter=$(($counter+1)); sleep 5;
- done
- if: ${{ steps.stable_exists.outputs.exists != 'true' && needs.checks.outputs.docs_only == 'false' }}
-
- - name: Test HTTPS
- run: |
- counter=0
- max_attempts=5
- until [ $(curl --write-out %{http_code} -ks --output /dev/null https://localhost:8443) -eq 000 ]; do
- if [ ${counter} -eq ${max_attempts} ]; then
- exit 1
- fi
- printf '.'; counter=$(($counter+1)); sleep 5;
- done
- if: ${{ steps.stable_exists.outputs.exists != 'true' && needs.checks.outputs.docs_only == 'false' }}
-
- setup-matrix:
- if: ${{ inputs.force || (inputs.run_tests && inputs.run_tests || true) || needs.checks.outputs.docs_only != 'true' }}
- name: Setup Matrix for Smoke Tests
- runs-on: ubuntu-22.04
- needs: [binaries, checks]
- permissions:
- contents: read
- id-token: write
- outputs:
- matrix_oss: ${{ steps.set-matrix.outputs.matrix_oss }}
- matrix_plus: ${{ steps.set-matrix.outputs.matrix_plus }}
- matrix_nap: ${{ steps.set-matrix.outputs.matrix_nap }}
- steps:
- - name: Checkout Repository
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
- - id: set-matrix
- run: |
- echo "matrix_oss=$(cat .github/data/matrix-smoke-oss.json | jq -c --arg latest "${{ needs.checks.outputs.k8s_latest }}" '.k8s += [$latest]')" >> $GITHUB_OUTPUT
- echo "matrix_plus=$(cat .github/data/matrix-smoke-plus.json | jq -c --arg latest "${{ needs.checks.outputs.k8s_latest }}" '.k8s += [$latest]')" >> $GITHUB_OUTPUT
- echo "matrix_nap=$(cat .github/data/matrix-smoke-nap.json | jq -c --arg latest "${{ needs.checks.outputs.k8s_latest }}" '.k8s += [$latest]')" >> $GITHUB_OUTPUT
-
- - name: Docker Buildx
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
-
- - name: Authenticate to Google Cloud
- id: auth
- uses: google-github-actions/auth@ba79af03959ebeac9769e648f473a284504d9193 # v2.1.10
- with:
- token_format: access_token
- workload_identity_provider: ${{ secrets.GCR_WORKLOAD_IDENTITY }}
- service_account: ${{ secrets.GCR_SERVICE_ACCOUNT }}
- if: ${{ needs.checks.outputs.forked_workflow == 'false' && needs.checks.outputs.docs_only == 'false' }}
-
- - name: Login to GCR
- uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
- with:
- registry: gcr.io
- username: oauth2accesstoken
- password: ${{ steps.auth.outputs.access_token }}
- if: ${{ needs.checks.outputs.forked_workflow == 'false' && needs.checks.outputs.docs_only == 'false' }}
-
- - name: Check if test image exists
- id: check-image
- run: |
- docker pull gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/test-runner:${{ hashFiles('./tests/requirements.txt', './tests/Dockerfile') || 'latest' }}
- shell: bash
- continue-on-error: true
- if: ${{ needs.checks.outputs.forked_workflow == 'false' && needs.checks.outputs.docs_only == 'false' }}
-
- - name: Build Test-Runner Container
- uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
- with:
- file: tests/Dockerfile
- context: "."
- cache-from: type=gha,scope=test-runner
- tags: "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/test-runner:${{ hashFiles('./tests/requirements.txt', './tests/Dockerfile') || 'latest' }}"
- pull: true
- push: ${{ needs.checks.outputs.forked_workflow == 'false' }}
- load: false
- if: ${{ steps.check-image.outcome == 'failure' && needs.checks.outputs.docs_only == 'false' }}
-
- smoke-tests-oss:
- if: ${{ inputs.force || (inputs.run_tests && inputs.run_tests || true) || needs.checks.outputs.docs_only != 'true' }}
- name: ${{ matrix.images.label }} ${{ matrix.images.image }} ${{ matrix.k8s }} smoke tests
- needs:
- - checks
- - setup-matrix
- - build-docker
- strategy:
- fail-fast: false
- matrix: ${{ fromJSON(needs.setup-matrix.outputs.matrix_oss) }}
- permissions:
- contents: read
- id-token: write
- uses: ./.github/workflows/setup-smoke.yml
- secrets: inherit
- with:
- image: ${{ matrix.images.image }}
- target: ${{ matrix.images.target }}
- nap-modules: ${{ matrix.images.nap_modules }}
- marker: ${{ matrix.images.marker }}
- label: ${{ matrix.images.label }}
- go-md5: ${{ needs.checks.outputs.go_code_md5 }}
- build-tag: ${{ needs.checks.outputs.build_tag }}
- stable-tag: ${{ needs.checks.outputs.stable_tag }}
- authenticated: ${{ needs.checks.outputs.forked_workflow != 'true' }}
- k8s-version: ${{ matrix.k8s }}
-
- smoke-tests-plus:
- if: ${{ inputs.force || (inputs.run_tests && inputs.run_tests || true) || needs.checks.outputs.docs_only != 'true' }}
- name: ${{ matrix.images.label }} ${{ matrix.images.image }} ${{ matrix.k8s }} smoke tests
- needs:
- - checks
- - setup-matrix
- - build-docker-plus
- strategy:
- fail-fast: false
- matrix: ${{ fromJSON(needs.setup-matrix.outputs.matrix_plus) }}
- permissions:
- contents: read
- id-token: write
- uses: ./.github/workflows/setup-smoke.yml
- secrets: inherit
- with:
- image: ${{ matrix.images.image }}
- target: ${{ matrix.images.target }}
- nap-modules: ${{ matrix.images.nap_modules }}
- marker: ${{ matrix.images.marker }}
- label: ${{ matrix.images.label }}
- go-md5: ${{ needs.checks.outputs.go_code_md5 }}
- build-tag: ${{ needs.checks.outputs.build_tag }}
- stable-tag: ${{ needs.checks.outputs.stable_tag }}
- authenticated: ${{ needs.checks.outputs.forked_workflow != 'true' }}
- k8s-version: ${{ matrix.k8s }}
-
- smoke-tests-nap:
- if: ${{ inputs.force || (inputs.run_tests && inputs.run_tests || true) || needs.checks.outputs.docs_only != 'true' }}
- name: ${{ matrix.images.label }} ${{ matrix.images.image }} ${{ matrix.k8s }} smoke tests
- needs:
- - checks
- - setup-matrix
- - build-docker-nap
- strategy:
- fail-fast: false
- matrix: ${{ fromJSON(needs.setup-matrix.outputs.matrix_nap) }}
- permissions:
- contents: read
- id-token: write
- uses: ./.github/workflows/setup-smoke.yml
- secrets: inherit
- with:
- image: ${{ matrix.images.image }}
- target: ${{ matrix.images.target }}
- nap-modules: ${{ matrix.images.nap_modules }}
- marker: ${{ matrix.images.marker }}
- label: ${{ matrix.images.label }}
- go-md5: ${{ needs.checks.outputs.go_code_md5 }}
- build-tag: ${{ needs.checks.outputs.build_tag }}
- stable-tag: ${{ needs.checks.outputs.stable_tag }}
- authenticated: ${{ needs.checks.outputs.forked_workflow != 'true' }}
- k8s-version: ${{ matrix.k8s }}
-
- tag-stable:
- name: Tag tested image as stable
- needs: [checks, build-docker, build-docker-plus, build-docker-nap, smoke-tests-oss, smoke-tests-plus, smoke-tests-nap]
- permissions:
- contents: read # To checkout repository
- id-token: write # To sign into Google Container Registry
- uses: ./.github/workflows/retag-images.yml
- with:
- source_tag: ${{ needs.checks.outputs.build_tag }}
- target_tag: ${{ needs.checks.outputs.stable_tag }}
- dry_run: false
- secrets: inherit
- if: ${{ inputs.force || (needs.checks.outputs.forked_workflow == 'true' && needs.checks.outputs.docs_only == 'false') || (needs.checks.outputs.forked_workflow == 'false' && needs.checks.outputs.stable_image_exists != 'true' && needs.checks.outputs.docs_only == 'false') }}
-
- final-results:
- if: ${{ !cancelled() }}
- runs-on: ubuntu-22.04
- name: Final CI Results
- needs: [tag-stable, build-docker, build-docker-plus, build-docker-nap, smoke-tests-oss, smoke-tests-plus, smoke-tests-nap]
- steps:
- - run: |
- tagResult="${{ needs.tag-stable.result }}"
- smokeOSSResult="${{ needs.smoke-tests-oss.result }}"
- smokePlusResult="${{ needs.smoke-tests-plus.result }}"
- smokeNAPResult="${{ needs.smoke-tests-nap.result }}"
- buildOSSResult="${{ needs.build-docker.result }}"
- buildPlusResult="${{ needs.build-docker-plus.result }}"
- buildNAPResult="${{ needs.build-docker-nap.result }}"
- if [[ $tagResult != "success" && $tagResult != "skipped" ]]; then
- exit 1
- fi
- if [[ $smokeOSSResult != "success" && $smokeOSSResult != "skipped" ]]; then
- exit 1
- fi
- if [[ $smokePlusResult != "success" && $smokePlusResult != "skipped" ]]; then
- exit 1
- fi
- if [[ $smokeNAPResult != "success" && $smokeNAPResult != "skipped" ]]; then
- exit 1
- fi
- if [[ $buildOSSResult != "success" && $buildOSSResult != "skipped" ]]; then
- exit 1
- fi
- if [[ $buildPlusResult != "success" && $buildPlusResult != "skipped" ]]; then
- exit 1
- fi
- if [[ $buildNAPResult != "success" && $buildNAPResult != "skipped" ]]; then
- exit 1
- fi
-
- trigger-image-promotion:
- name: Promote images on Force Run
- needs:
- - build-docker
- - build-docker-plus
- - build-docker-nap
- - final-results
- permissions:
- contents: write # for pushing to Helm Charts repository
- id-token: write # To sign into Google Container Registry
- actions: read
- packages: write # for helm to push to GHCR
- security-events: write
- pull-requests: write # for scout report
- uses: ./.github/workflows/image-promotion.yml
- secrets: inherit
- if: ${{ inputs.force && inputs.force || false }}
From e6596a73e8252fefaa59a893ab4f8831c3c2f0c7 Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Tue, 15 Jul 2025 16:39:35 +0100
Subject: [PATCH 10/20] add qemu
---
.github/workflows/ci.yml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 970756924d..a3131b47c0 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -389,6 +389,12 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - name: Setup QEMU
+ uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
+ with:
+ platforms: arm64
+ if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
+
- name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@ba79af03959ebeac9769e648f473a284504d9193 # v2.1.10
From dd6f7987317caf8357df7ad3cd33b31805055d95 Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Tue, 15 Jul 2025 16:42:16 +0100
Subject: [PATCH 11/20] switch to amd64
---
.github/workflows/ci.yml | 6 ------
tests/data/modules/data.json | 10 +++++-----
2 files changed, 5 insertions(+), 11 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a3131b47c0..970756924d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -389,12 +389,6 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- - name: Setup QEMU
- uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
- with:
- platforms: arm64
- if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
-
- name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@ba79af03959ebeac9769e648f473a284504d9193 # v2.1.10
diff --git a/tests/data/modules/data.json b/tests/data/modules/data.json
index 43939b922d..2c1675cbb1 100644
--- a/tests/data/modules/data.json
+++ b/tests/data/modules/data.json
@@ -7,27 +7,27 @@
{
"name": "nginx",
"version": "1.27.5",
- "arch": "arm64"
+ "arch": "amd64"
},
{
"name": "nginx-module-njs",
"version": "1.27.5",
- "arch": "arm64"
+ "arch": "amd64"
},
{
"name": "nginx-module-otel",
"version": "1.27.5",
- "arch": "arm64"
+ "arch": "amd64"
},
{
"name": "nginx-agent",
"version": "3.0",
- "arch": "arm64"
+ "arch": "amd64"
}
],
"cmd": "dpkg -l",
"regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
- "platform": "linux/arm64"
+ "platform": "linux/amd64"
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress",
From b371040a84cb541a0beb8c90aee718aeb4fc1bad Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Tue, 15 Jul 2025 16:48:01 +0100
Subject: [PATCH 12/20] switch to amd64
---
tests/data/modules/data.json | 68 ++++++++++++++++++------------------
1 file changed, 34 insertions(+), 34 deletions(-)
diff --git a/tests/data/modules/data.json b/tests/data/modules/data.json
index 2c1675cbb1..9f80df8b16 100644
--- a/tests/data/modules/data.json
+++ b/tests/data/modules/data.json
@@ -36,32 +36,32 @@
{
"name": "nginx-plus",
"version": "34-2",
- "arch": "arm64"
+ "arch": "amd64"
},
{
"name": "nginx-plus-module-njs",
"version": "34",
- "arch": "arm64"
+ "arch": "amd64"
},
{
"name": "nginx-plus-module-otel",
"version": "34",
- "arch": "arm64"
+ "arch": "amd64"
},
{
"name": "nginx-plus-module-fips-check",
"version": "34",
- "arch": "arm64"
+ "arch": "amd64"
},
{
"name": "nginx-agent",
"version": "3.0",
- "arch": "arm64"
+ "arch": "amd64"
}
],
"cmd": "dpkg -l",
"regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
- "platform": "linux/arm64"
+ "platform": "linux/amd64"
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress",
@@ -276,27 +276,27 @@
{
"name": "nginx",
"version": "1.27.5",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-module-njs",
"version": "1.27.5",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-module-otel",
"version": "1.27.5",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-agent",
"version": "3.0",
- "arch": "aarch64"
+ "arch": "x64_64"
}
],
"cmd": "apk list",
"regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
- "platform": "linux/arm64"
+ "platform": "linux/amd64"
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress",
@@ -305,32 +305,32 @@
{
"name": "nginx-plus",
"version": "34-r2",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-plus-module-njs",
"version": "34",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-plus-module-otel",
"version": "34",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-plus-module-fips-check",
"version": "34",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-agent",
"version": "3.0",
- "arch": "aarch64"
+ "arch": "x64_64"
}
],
"cmd": "apk list",
"regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
- "platform": "linux/arm64"
+ "platform": "linux/amd64"
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress",
@@ -339,32 +339,32 @@
{
"name": "nginx-plus",
"version": "34-r2",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-plus-module-njs",
"version": "34",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-plus-module-otel",
"version": "34",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-plus-module-fips-check",
"version": "34",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-agent",
"version": "3.0",
- "arch": "aarch64"
+ "arch": "x64_64"
}
],
"cmd": "apk list",
"regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
- "platform": "linux/arm64"
+ "platform": "linux/amd64"
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress",
@@ -476,27 +476,27 @@
{
"name": "nginx",
"version": "1.27.5",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-module-njs",
"version": "1.27.5",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-module-otel",
"version": "1.27.5",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-agent",
"version": "3.0",
- "arch": "aarch64"
+ "arch": "x64_64"
}
],
"cmd": "rpm -q",
"regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
- "platform": "linux/arm64"
+ "platform": "linux/amd64"
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress",
@@ -505,32 +505,32 @@
{
"name": "nginx-plus",
"version": "34-2",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-plus-module-njs",
"version": "34",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-plus-module-otel",
"version": "34",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-plus-module-fips-check",
"version": "34",
- "arch": "aarch64"
+ "arch": "x64_64"
},
{
"name": "nginx-agent",
"version": "3.0",
- "arch": "aarch64"
+ "arch": "x64_64"
}
],
"cmd": "rpm -q",
"regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
- "platform": "linux/arm64"
+ "platform": "linux/amd64"
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress",
From c2c5dc303ba6bed3df9aae52ec9d1b399f6da043 Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Tue, 15 Jul 2025 16:53:21 +0100
Subject: [PATCH 13/20] add tests back
---
.github/workflows/ci.yml | 352 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 351 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 970756924d..c111cfb2f7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -415,7 +415,7 @@ jobs:
id: packages
run: |
source tests/venv/bin/activate
- python tests/scripts/check_container_packages.py --tag ${{ needs.checks.outputs.build_tag }}
+ python tests/scripts/check_container_packages.py --tag ${{ needs.checks.outputs.build_tag }} | tee package_output.txt 2&>1
if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
- name: Add comment
@@ -424,3 +424,353 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: ${{ ( needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' ) && github.event.pull_request }}
+
+ helm-tests:
+ if: ${{ needs.checks.outputs.docs_only != 'true' && (inputs.run_tests && inputs.run_tests || true) }}
+ name: Helm Tests ${{ matrix.base-os }}
+ runs-on: ubuntu-22.04
+ needs: [checks, binaries, build-docker, build-docker-plus]
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - base-os: debian
+ image: gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress
+ tag: ${{ needs.checks.outputs.build_tag }}
+ type: oss
+ - base-os: debian-plus
+ image: gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress
+ tag: ${{ needs.checks.outputs.build_tag }}
+ type: plus
+ permissions:
+ contents: read
+ id-token: write
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+ - name: Authenticate to Google Cloud
+ id: auth
+ uses: google-github-actions/auth@ba79af03959ebeac9769e648f473a284504d9193 # v2.1.10
+ with:
+ token_format: access_token
+ workload_identity_provider: ${{ secrets.GCR_WORKLOAD_IDENTITY }}
+ service_account: ${{ secrets.GCR_SERVICE_ACCOUNT }}
+ if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Login to GCR
+ uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
+ with:
+ registry: gcr.io
+ username: oauth2accesstoken
+ password: ${{ steps.auth.outputs.access_token }}
+ if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Check if stable image exists
+ id: stable_exists
+ run: |
+ if docker pull ${{ matrix.image }}:${{ needs.checks.outputs.stable_tag }}; then
+ echo "exists=true" >> $GITHUB_OUTPUT
+ fi
+ if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Pull build image
+ run: |
+ docker pull ${{ matrix.image }}:${{ needs.checks.outputs.build_tag }}
+ if: ${{ ( needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' ) && steps.stable_exists.outputs.exists != 'true' }}
+
+ - name: Fetch Cached Artifacts
+ uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
+ with:
+ path: ${{ github.workspace }}/dist
+ key: nginx-ingress-${{ needs.checks.outputs.go_code_md5 }}
+ if: ${{ needs.checks.outputs.forked_workflow == 'true' && needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Docker Buildx
+ uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+ if: ${{ needs.checks.outputs.forked_workflow == 'true' && needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Build Docker Image ${{ matrix.base-os }}
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+ with:
+ file: build/Dockerfile
+ context: "."
+ cache-from: type=gha,scope=${{ matrix.base-os }}
+ target: goreleaser
+ tags: "${{ matrix.image }}:${{ matrix.tag }}"
+ pull: true
+ load: true
+ build-args: |
+ BUILD_OS=${{ matrix.base-os }}
+ IC_VERSION=CI
+ secrets: |
+ ${{ matrix.type == 'plus' && format('"nginx-repo.crt={0}"', secrets.NGINX_CRT) || '' }}
+ ${{ matrix.type == 'plus' && format('"nginx-repo.key={0}"', secrets.NGINX_KEY) || '' }}
+ if: ${{ needs.checks.outputs.forked_workflow == 'true' && needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Deploy Kubernetes
+ id: k8s
+ run: |
+ kind create cluster --name ${{ github.run_id }} --image=kindest/node:v${{ needs.checks.outputs.k8s_latest }} --wait 75s
+ docker version
+ kind load docker-image "${{ matrix.image }}:${{ matrix.tag }}" --name ${{ github.run_id }}
+ echo "DEBUG: Kind setup complete!"
+ if: ${{ steps.stable_exists.outputs.exists != 'true' && needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Create Plus Secret
+ run: kubectl create secret generic license-token --from-literal=license.jwt="${{ secrets.PLUS_JWT }}" --type="nginx.com/license"
+ if: ${{ matrix.type == 'plus' && steps.stable_exists.outputs.exists != 'true' && needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Install Chart
+ run: >
+ helm install
+ ${{ matrix.type }}
+ .
+ --set controller.image.repository=${{ matrix.image }}
+ --set controller.image.tag=${{ matrix.tag }}
+ --set controller.service.type=NodePort
+ --set controller.nginxplus=${{ contains(matrix.type, 'plus') && 'true' || 'false' }}
+ --set controller.telemetryReporting.enable=false
+ --wait
+ working-directory: ${{ github.workspace }}/charts/nginx-ingress
+ if: ${{ steps.stable_exists.outputs.exists != 'true' && needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Expose Test Ingresses
+ run: |
+ kubectl port-forward service/${{ matrix.type }}-nginx-ingress-controller 8080:80 8443:443 &
+ if: ${{ steps.stable_exists.outputs.exists != 'true' && needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Test HTTP
+ run: |
+ counter=0
+ max_attempts=5
+ until [ $(curl --write-out %{http_code} -s --output /dev/null http://localhost:8080) -eq 404 ]; do
+ if [ ${counter} -eq ${max_attempts} ]; then
+ exit 1
+ fi
+ printf '.'; counter=$(($counter+1)); sleep 5;
+ done
+ if: ${{ steps.stable_exists.outputs.exists != 'true' && needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Test HTTPS
+ run: |
+ counter=0
+ max_attempts=5
+ until [ $(curl --write-out %{http_code} -ks --output /dev/null https://localhost:8443) -eq 000 ]; do
+ if [ ${counter} -eq ${max_attempts} ]; then
+ exit 1
+ fi
+ printf '.'; counter=$(($counter+1)); sleep 5;
+ done
+ if: ${{ steps.stable_exists.outputs.exists != 'true' && needs.checks.outputs.docs_only == 'false' }}
+
+ setup-matrix:
+ if: ${{ inputs.force || (inputs.run_tests && inputs.run_tests || true) || needs.checks.outputs.docs_only != 'true' }}
+ name: Setup Matrix for Smoke Tests
+ runs-on: ubuntu-22.04
+ needs: [binaries, checks]
+ permissions:
+ contents: read
+ id-token: write
+ outputs:
+ matrix_oss: ${{ steps.set-matrix.outputs.matrix_oss }}
+ matrix_plus: ${{ steps.set-matrix.outputs.matrix_plus }}
+ matrix_nap: ${{ steps.set-matrix.outputs.matrix_nap }}
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+ - id: set-matrix
+ run: |
+ echo "matrix_oss=$(cat .github/data/matrix-smoke-oss.json | jq -c --arg latest "${{ needs.checks.outputs.k8s_latest }}" '.k8s += [$latest]')" >> $GITHUB_OUTPUT
+ echo "matrix_plus=$(cat .github/data/matrix-smoke-plus.json | jq -c --arg latest "${{ needs.checks.outputs.k8s_latest }}" '.k8s += [$latest]')" >> $GITHUB_OUTPUT
+ echo "matrix_nap=$(cat .github/data/matrix-smoke-nap.json | jq -c --arg latest "${{ needs.checks.outputs.k8s_latest }}" '.k8s += [$latest]')" >> $GITHUB_OUTPUT
+
+ - name: Docker Buildx
+ uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
+
+ - name: Authenticate to Google Cloud
+ id: auth
+ uses: google-github-actions/auth@ba79af03959ebeac9769e648f473a284504d9193 # v2.1.10
+ with:
+ token_format: access_token
+ workload_identity_provider: ${{ secrets.GCR_WORKLOAD_IDENTITY }}
+ service_account: ${{ secrets.GCR_SERVICE_ACCOUNT }}
+ if: ${{ needs.checks.outputs.forked_workflow == 'false' && needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Login to GCR
+ uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
+ with:
+ registry: gcr.io
+ username: oauth2accesstoken
+ password: ${{ steps.auth.outputs.access_token }}
+ if: ${{ needs.checks.outputs.forked_workflow == 'false' && needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Check if test image exists
+ id: check-image
+ run: |
+ docker pull gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/test-runner:${{ hashFiles('./tests/requirements.txt', './tests/Dockerfile') || 'latest' }}
+ shell: bash
+ continue-on-error: true
+ if: ${{ needs.checks.outputs.forked_workflow == 'false' && needs.checks.outputs.docs_only == 'false' }}
+
+ - name: Build Test-Runner Container
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
+ with:
+ file: tests/Dockerfile
+ context: "."
+ cache-from: type=gha,scope=test-runner
+ tags: "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/test-runner:${{ hashFiles('./tests/requirements.txt', './tests/Dockerfile') || 'latest' }}"
+ pull: true
+ push: ${{ needs.checks.outputs.forked_workflow == 'false' }}
+ load: false
+ if: ${{ steps.check-image.outcome == 'failure' && needs.checks.outputs.docs_only == 'false' }}
+
+ smoke-tests-oss:
+ if: ${{ inputs.force || (inputs.run_tests && inputs.run_tests || true) || needs.checks.outputs.docs_only != 'true' }}
+ name: ${{ matrix.images.label }} ${{ matrix.images.image }} ${{ matrix.k8s }} smoke tests
+ needs:
+ - checks
+ - setup-matrix
+ - build-docker
+ strategy:
+ fail-fast: false
+ matrix: ${{ fromJSON(needs.setup-matrix.outputs.matrix_oss) }}
+ permissions:
+ contents: read
+ id-token: write
+ uses: ./.github/workflows/setup-smoke.yml
+ secrets: inherit
+ with:
+ image: ${{ matrix.images.image }}
+ target: ${{ matrix.images.target }}
+ nap-modules: ${{ matrix.images.nap_modules }}
+ marker: ${{ matrix.images.marker }}
+ label: ${{ matrix.images.label }}
+ go-md5: ${{ needs.checks.outputs.go_code_md5 }}
+ build-tag: ${{ needs.checks.outputs.build_tag }}
+ stable-tag: ${{ needs.checks.outputs.stable_tag }}
+ authenticated: ${{ needs.checks.outputs.forked_workflow != 'true' }}
+ k8s-version: ${{ matrix.k8s }}
+
+ smoke-tests-plus:
+ if: ${{ inputs.force || (inputs.run_tests && inputs.run_tests || true) || needs.checks.outputs.docs_only != 'true' }}
+ name: ${{ matrix.images.label }} ${{ matrix.images.image }} ${{ matrix.k8s }} smoke tests
+ needs:
+ - checks
+ - setup-matrix
+ - build-docker-plus
+ strategy:
+ fail-fast: false
+ matrix: ${{ fromJSON(needs.setup-matrix.outputs.matrix_plus) }}
+ permissions:
+ contents: read
+ id-token: write
+ uses: ./.github/workflows/setup-smoke.yml
+ secrets: inherit
+ with:
+ image: ${{ matrix.images.image }}
+ target: ${{ matrix.images.target }}
+ nap-modules: ${{ matrix.images.nap_modules }}
+ marker: ${{ matrix.images.marker }}
+ label: ${{ matrix.images.label }}
+ go-md5: ${{ needs.checks.outputs.go_code_md5 }}
+ build-tag: ${{ needs.checks.outputs.build_tag }}
+ stable-tag: ${{ needs.checks.outputs.stable_tag }}
+ authenticated: ${{ needs.checks.outputs.forked_workflow != 'true' }}
+ k8s-version: ${{ matrix.k8s }}
+
+ smoke-tests-nap:
+ if: ${{ inputs.force || (inputs.run_tests && inputs.run_tests || true) || needs.checks.outputs.docs_only != 'true' }}
+ name: ${{ matrix.images.label }} ${{ matrix.images.image }} ${{ matrix.k8s }} smoke tests
+ needs:
+ - checks
+ - setup-matrix
+ - build-docker-nap
+ strategy:
+ fail-fast: false
+ matrix: ${{ fromJSON(needs.setup-matrix.outputs.matrix_nap) }}
+ permissions:
+ contents: read
+ id-token: write
+ uses: ./.github/workflows/setup-smoke.yml
+ secrets: inherit
+ with:
+ image: ${{ matrix.images.image }}
+ target: ${{ matrix.images.target }}
+ nap-modules: ${{ matrix.images.nap_modules }}
+ marker: ${{ matrix.images.marker }}
+ label: ${{ matrix.images.label }}
+ go-md5: ${{ needs.checks.outputs.go_code_md5 }}
+ build-tag: ${{ needs.checks.outputs.build_tag }}
+ stable-tag: ${{ needs.checks.outputs.stable_tag }}
+ authenticated: ${{ needs.checks.outputs.forked_workflow != 'true' }}
+ k8s-version: ${{ matrix.k8s }}
+
+ tag-stable:
+ name: Tag tested image as stable
+ needs: [checks, build-docker, build-docker-plus, build-docker-nap, smoke-tests-oss, smoke-tests-plus, smoke-tests-nap]
+ permissions:
+ contents: read # To checkout repository
+ id-token: write # To sign into Google Container Registry
+ uses: ./.github/workflows/retag-images.yml
+ with:
+ source_tag: ${{ needs.checks.outputs.build_tag }}
+ target_tag: ${{ needs.checks.outputs.stable_tag }}
+ dry_run: false
+ secrets: inherit
+ if: ${{ inputs.force || (needs.checks.outputs.forked_workflow == 'true' && needs.checks.outputs.docs_only == 'false') || (needs.checks.outputs.forked_workflow == 'false' && needs.checks.outputs.stable_image_exists != 'true' && needs.checks.outputs.docs_only == 'false') }}
+
+ final-results:
+ if: ${{ !cancelled() }}
+ runs-on: ubuntu-22.04
+ name: Final CI Results
+ needs: [tag-stable, build-docker, build-docker-plus, build-docker-nap, smoke-tests-oss, smoke-tests-plus, smoke-tests-nap]
+ steps:
+ - run: |
+ tagResult="${{ needs.tag-stable.result }}"
+ smokeOSSResult="${{ needs.smoke-tests-oss.result }}"
+ smokePlusResult="${{ needs.smoke-tests-plus.result }}"
+ smokeNAPResult="${{ needs.smoke-tests-nap.result }}"
+ buildOSSResult="${{ needs.build-docker.result }}"
+ buildPlusResult="${{ needs.build-docker-plus.result }}"
+ buildNAPResult="${{ needs.build-docker-nap.result }}"
+ if [[ $tagResult != "success" && $tagResult != "skipped" ]]; then
+ exit 1
+ fi
+ if [[ $smokeOSSResult != "success" && $smokeOSSResult != "skipped" ]]; then
+ exit 1
+ fi
+ if [[ $smokePlusResult != "success" && $smokePlusResult != "skipped" ]]; then
+ exit 1
+ fi
+ if [[ $smokeNAPResult != "success" && $smokeNAPResult != "skipped" ]]; then
+ exit 1
+ fi
+ if [[ $buildOSSResult != "success" && $buildOSSResult != "skipped" ]]; then
+ exit 1
+ fi
+ if [[ $buildPlusResult != "success" && $buildPlusResult != "skipped" ]]; then
+ exit 1
+ fi
+ if [[ $buildNAPResult != "success" && $buildNAPResult != "skipped" ]]; then
+ exit 1
+ fi
+
+ trigger-image-promotion:
+ name: Promote images on Force Run
+ needs:
+ - build-docker
+ - build-docker-plus
+ - build-docker-nap
+ - final-results
+ permissions:
+ contents: write # for pushing to Helm Charts repository
+ id-token: write # To sign into Google Container Registry
+ actions: read
+ packages: write # for helm to push to GHCR
+ security-events: write
+ pull-requests: write # for scout report
+ uses: ./.github/workflows/image-promotion.yml
+ secrets: inherit
+ if: ${{ inputs.force && inputs.force || false }}
From 53de46e8cac238c283ab99ca5d1b7bfbec11e3b9 Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Tue, 15 Jul 2025 17:03:14 +0100
Subject: [PATCH 14/20] add pull_request: write permission to add comment
---
.github/workflows/ci.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c111cfb2f7..d6bd09885b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -384,6 +384,7 @@ jobs:
needs: [checks, binaries, build-docker, build-docker-plus, build-docker-nap]
permissions:
contents: read
+ pull-requests: write # for package report
id-token: write
steps:
- name: Checkout Repository
@@ -415,7 +416,7 @@ jobs:
id: packages
run: |
source tests/venv/bin/activate
- python tests/scripts/check_container_packages.py --tag ${{ needs.checks.outputs.build_tag }} | tee package_output.txt 2&>1
+ python tests/scripts/check_container_packages.py --tag ${{ needs.checks.outputs.build_tag }} | tee package_output.txt
if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
- name: Add comment
From 25ca39698b5d19eb8f5d08d4a062df0b4fe5ff64 Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Tue, 15 Jul 2025 17:37:34 +0100
Subject: [PATCH 15/20] add logger
---
.github/workflows/ci.yml | 2 +-
tests/data/modules/data.json | 46 ++++++++++-----------
tests/scripts/check_container_packages.py | 49 ++++++++++++++++++-----
3 files changed, 62 insertions(+), 35 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d6bd09885b..73fe990913 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -416,7 +416,7 @@ jobs:
id: packages
run: |
source tests/venv/bin/activate
- python tests/scripts/check_container_packages.py --tag ${{ needs.checks.outputs.build_tag }} | tee package_output.txt
+ python tests/scripts/check_container_packages.py --tag ${{ needs.checks.outputs.build_tag }} --log package_output.txt
if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
- name: Add comment
diff --git a/tests/data/modules/data.json b/tests/data/modules/data.json
index 9f80df8b16..de64923c2f 100644
--- a/tests/data/modules/data.json
+++ b/tests/data/modules/data.json
@@ -276,22 +276,22 @@
{
"name": "nginx",
"version": "1.27.5",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-module-njs",
"version": "1.27.5",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-module-otel",
"version": "1.27.5",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-agent",
"version": "3.0",
- "arch": "x64_64"
+ "arch": "x86_64"
}
],
"cmd": "apk list",
@@ -305,27 +305,27 @@
{
"name": "nginx-plus",
"version": "34-r2",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-plus-module-njs",
"version": "34",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-plus-module-otel",
"version": "34",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-plus-module-fips-check",
"version": "34",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-agent",
"version": "3.0",
- "arch": "x64_64"
+ "arch": "x86_64"
}
],
"cmd": "apk list",
@@ -339,27 +339,27 @@
{
"name": "nginx-plus",
"version": "34-r2",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-plus-module-njs",
"version": "34",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-plus-module-otel",
"version": "34",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-plus-module-fips-check",
"version": "34",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-agent",
"version": "3.0",
- "arch": "x64_64"
+ "arch": "x86_64"
}
],
"cmd": "apk list",
@@ -476,22 +476,22 @@
{
"name": "nginx",
"version": "1.27.5",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-module-njs",
"version": "1.27.5",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-module-otel",
"version": "1.27.5",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-agent",
"version": "3.0",
- "arch": "x64_64"
+ "arch": "x86_64"
}
],
"cmd": "rpm -q",
@@ -505,27 +505,27 @@
{
"name": "nginx-plus",
"version": "34-2",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-plus-module-njs",
"version": "34",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-plus-module-otel",
"version": "34",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-plus-module-fips-check",
"version": "34",
- "arch": "x64_64"
+ "arch": "x86_64"
},
{
"name": "nginx-agent",
"version": "3.0",
- "arch": "x64_64"
+ "arch": "x86_64"
}
],
"cmd": "rpm -q",
diff --git a/tests/scripts/check_container_packages.py b/tests/scripts/check_container_packages.py
index 9488b84f18..2498bf8e3d 100755
--- a/tests/scripts/check_container_packages.py
+++ b/tests/scripts/check_container_packages.py
@@ -2,6 +2,7 @@
import argparse
import json
+import logging
import os
import re
@@ -11,8 +12,26 @@
# parse args
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--tag", type=str, help="NGINX Ingress Controller image tag", default="edge")
+parser.add_argument("-l", "--log", type=str, help="log file", required=False)
args = parser.parse_args()
+# Create a logger
+logger = logging.getLogger("package_checker")
+logger.setLevel(logging.DEBUG)
+
+# Create a stream handler (for stdout)
+stream_handler = logging.StreamHandler()
+stream_handler.setLevel(logging.DEBUG)
+stream_handler.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s"))
+logger.addHandler(stream_handler)
+
+if args.log:
+ # Create a file handler
+ file_handler = logging.FileHandler(args.log)
+ file_handler.setLevel(logging.INFO)
+ file_handler.setFormatter(logging.Formatter("%(message)s"))
+ logger.addHandler(file_handler)
+
client = docker.from_env()
script_dir = os.path.dirname(os.path.abspath(__file__))
with open(f"{script_dir}/../data/modules/data.json") as file:
@@ -22,14 +41,17 @@
regexInstalled = image["regex"]
tag = f"{args.tag}{image['tag_suffix']}"
try:
- client.images.get(f"{image['image']}:{tag}")
- print(f"Image {image['image']}:{tag} already exists, skipping pull")
+ i = client.images.get(f"{image['image']}:{tag}")
+ ## check if the image is for the correct platform
+ if image["platform"] != i.attrs["Os"]:
+ raise docker.errors.ImageNotFound(
+ f"Image {image['image']}:{tag} is not for platform {image['platform']}, found {i.attrs['Os']}"
+ )
except docker.errors.ImageNotFound:
- print(f"Image {image['image']}:{tag} not found, pulling...")
## pull the image
- print(f"Pulling image {image['image']}:{tag} for platform {image['platform']}")
+ logger.debug(f"Pulling image {image['image']}:{tag} for platform {image['platform']}")
i = client.images.pull(repository=image["image"], tag=tag, platform=image["platform"])
- print(f"Image {i.id} pulled successfully")
+ logger.debug(f"Image {i.id} pulled successfully")
for package in image["packages"]:
command = f"{image['cmd']} {package['name']}"
output = ""
@@ -43,7 +65,7 @@
detach=False,
)
except (docker.errors.ContainerError, docker.errors.NotFound) as e:
- print(f"Container error: {e}, retrying")
+ logger.error(f"{e}, retrying")
output = client.containers.run(
f"{image['image']}:{tag}",
command,
@@ -53,8 +75,13 @@
detach=False,
)
result = re.search(regexInstalled, output.decode("utf-8").strip())
- assert result, f"{package['name']} not found in {image['image']}, output: {output.decode('utf-8').strip()}"
- assert result.group(2).startswith(
- package["version"]
- ), f"{package['name']} version {package['version']} does not match {result.group(2)}"
- print(image["image"], result.group(1, 2, 3))
+ assert result, logger.error(
+ f"{package['name']} not found in {image['image']}, output: {output.decode('utf-8').strip()}"
+ )
+ assert result.group(2).startswith(package["version"]), logger.error(
+ f"{package['name']} version {package['version']} does not match {result.group(2)}"
+ )
+ assert result.group(3) == package["arch"], logger.error(
+ f"{package['name']} arch {package['arch']} does not match {result.group(3)}"
+ )
+ logger.info(f"{image["image"]}, {result.group(1)}, {result.group(2)}, {result.group(3)}")
From 4219a46a287b8d24fa43d72a877e8af506336b4a Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Wed, 16 Jul 2025 10:20:12 +0100
Subject: [PATCH 16/20] move regex and cmd to python code
---
tests/data/modules/data.json | 459 ++++++++--------------
tests/scripts/check_container_packages.py | 25 +-
2 files changed, 172 insertions(+), 312 deletions(-)
diff --git a/tests/data/modules/data.json b/tests/data/modules/data.json
index de64923c2f..4873fb948d 100644
--- a/tests/data/modules/data.json
+++ b/tests/data/modules/data.json
@@ -6,27 +6,22 @@
"packages": [
{
"name": "nginx",
- "version": "1.27.5",
- "arch": "amd64"
+ "version": "1.27.5"
},
{
"name": "nginx-module-njs",
- "version": "1.27.5",
- "arch": "amd64"
+ "version": "1.27.5"
},
{
"name": "nginx-module-otel",
- "version": "1.27.5",
- "arch": "amd64"
+ "version": "1.27.5"
},
{
"name": "nginx-agent",
- "version": "3.0",
- "arch": "amd64"
+ "version": "3.0"
}
],
- "cmd": "dpkg -l",
- "regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
+ "system": "debian",
"platform": "linux/amd64"
},
{
@@ -35,32 +30,26 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-2",
- "arch": "amd64"
+ "version": "34-2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-agent",
- "version": "3.0",
- "arch": "amd64"
+ "version": "3.0"
}
],
- "cmd": "dpkg -l",
- "regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
+ "system": "debian",
"platform": "linux/amd64"
},
{
@@ -69,52 +58,42 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-2",
- "arch": "amd64"
+ "version": "34-2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-plus-module-appprotect",
- "version": "34+5.442",
- "arch": "amd64"
+ "version": "34+5.442"
},
{
"name": "app-protect",
- "version": "34+5.442",
- "arch": "amd64"
+ "version": "34+5.442"
},
{
"name": "app-protect-attack-signatures",
- "version": "2025",
- "arch": "amd64"
+ "version": "2025"
},
{
"name": "app-protect-threat-campaigns",
- "version": "2025",
- "arch": "amd64"
+ "version": "2025"
},
{
"name": "nginx-agent",
- "version": "2",
- "arch": "amd64"
+ "version": "2"
}
],
- "cmd": "dpkg -l",
- "regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
+ "system": "debian",
"platform": "linux/amd64"
},
{
@@ -123,47 +102,38 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-2",
- "arch": "amd64"
+ "version": "34-2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-plus-module-appprotect",
- "version": "34+5.442",
- "arch": "amd64"
+ "version": "34+5.442"
},
{
"name": "app-protect-module-plus",
- "version": "34+5.442",
- "arch": "amd64"
+ "version": "34+5.442"
},
{
"name": "app-protect-plugin",
- "version": "6.16.0",
- "arch": "amd64"
+ "version": "6.16.0"
},
{
"name": "nginx-agent",
- "version": "2",
- "arch": "amd64"
+ "version": "2"
}
],
- "cmd": "dpkg -l",
- "regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
+ "system": "debian",
"platform": "linux/amd64"
},
{
@@ -172,37 +142,30 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-2",
- "arch": "amd64"
+ "version": "34-2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-plus-module-appprotectdos",
- "version": "34+4",
- "arch": "amd64"
+ "version": "34+4"
},
{
"name": "app-protect-dos",
- "version": "34+4",
- "arch": "amd64"
+ "version": "34+4"
}
],
- "cmd": "dpkg -l",
- "regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
+ "system": "debian",
"platform": "linux/amd64"
},
{
@@ -211,62 +174,50 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-2",
- "arch": "amd64"
+ "version": "34-2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "amd64"
+ "version": "34"
},
{
"name": "nginx-plus-module-appprotect",
- "version": "34+5.442",
- "arch": "amd64"
+ "version": "34+5.442"
},
{
"name": "app-protect",
- "version": "34+5.442",
- "arch": "amd64"
+ "version": "34+5.442"
},
{
"name": "app-protect-attack-signatures",
- "version": "2025",
- "arch": "amd64"
+ "version": "2025"
},
{
"name": "app-protect-threat-campaigns",
- "version": "2025",
- "arch": "amd64"
+ "version": "2025"
},
{
"name": "nginx-plus-module-appprotectdos",
- "version": "34+4",
- "arch": "amd64"
+ "version": "34+4"
},
{
"name": "app-protect-dos",
- "version": "34+4",
- "arch": "amd64"
+ "version": "34+4"
},
{
"name": "nginx-agent",
- "version": "2",
- "arch": "amd64"
+ "version": "2"
}
],
- "cmd": "dpkg -l",
- "regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
+ "system": "debian",
"platform": "linux/amd64"
},
{
@@ -275,27 +226,22 @@
"packages": [
{
"name": "nginx",
- "version": "1.27.5",
- "arch": "x86_64"
+ "version": "1.27.5"
},
{
"name": "nginx-module-njs",
- "version": "1.27.5",
- "arch": "x86_64"
+ "version": "1.27.5"
},
{
"name": "nginx-module-otel",
- "version": "1.27.5",
- "arch": "x86_64"
+ "version": "1.27.5"
},
{
"name": "nginx-agent",
- "version": "3.0",
- "arch": "x86_64"
+ "version": "3.0"
}
],
- "cmd": "apk list",
- "regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
+ "system": "alpine",
"platform": "linux/amd64"
},
{
@@ -304,32 +250,26 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-r2",
- "arch": "x86_64"
+ "version": "34-r2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-agent",
- "version": "3.0",
- "arch": "x86_64"
+ "version": "3.0"
}
],
- "cmd": "apk list",
- "regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
+ "system": "alpine",
"platform": "linux/amd64"
},
{
@@ -338,32 +278,26 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-r2",
- "arch": "x86_64"
+ "version": "34-r2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-agent",
- "version": "3.0",
- "arch": "x86_64"
+ "version": "3.0"
}
],
- "cmd": "apk list",
- "regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
+ "system": "alpine",
"platform": "linux/amd64"
},
{
@@ -372,52 +306,42 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-r2",
- "arch": "x86_64"
+ "version": "34-r2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-agent",
- "version": "2",
- "arch": "x86_64"
+ "version": "2"
},
{
"name": "nginx-plus-module-appprotect",
- "version": "34.5.442",
- "arch": "x86_64"
+ "version": "34.5.442"
},
{
"name": "app-protect",
- "version": "34.5.442",
- "arch": "x86_64"
+ "version": "34.5.442"
},
{
"name": "app-protect-attack-signatures",
- "version": "2025",
- "arch": "x86_64"
+ "version": "2025"
},
{
"name": "app-protect-threat-campaigns",
- "version": "2025",
- "arch": "x86_64"
+ "version": "2025"
}
],
- "cmd": "apk list",
- "regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
+ "system": "alpine",
"platform": "linux/amd64"
},
{
@@ -426,47 +350,38 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-r2",
- "arch": "x86_64"
+ "version": "34-r2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-agent",
- "version": "2",
- "arch": "x86_64"
+ "version": "2"
},
{
"name": "nginx-plus-module-appprotect",
- "version": "34.5.442",
- "arch": "x86_64"
+ "version": "34.5.442"
},
{
"name": "app-protect-module-plus",
- "version": "34.5.442",
- "arch": "x86_64"
+ "version": "34.5.442"
},
{
"name": "app-protect-plugin",
- "version": "6.16.0",
- "arch": "x86_64"
+ "version": "6.16.0"
}
],
- "cmd": "apk list",
- "regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
+ "system": "alpine",
"platform": "linux/amd64"
},
{
@@ -475,27 +390,22 @@
"packages": [
{
"name": "nginx",
- "version": "1.27.5",
- "arch": "x86_64"
+ "version": "1.27.5"
},
{
"name": "nginx-module-njs",
- "version": "1.27.5",
- "arch": "x86_64"
+ "version": "1.27.5"
},
{
"name": "nginx-module-otel",
- "version": "1.27.5",
- "arch": "x86_64"
+ "version": "1.27.5"
},
{
"name": "nginx-agent",
- "version": "3.0",
- "arch": "x86_64"
+ "version": "3.0"
}
],
- "cmd": "rpm -q",
- "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "system": "ubi",
"platform": "linux/amd64"
},
{
@@ -504,32 +414,26 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-2",
- "arch": "x86_64"
+ "version": "34-2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-agent",
- "version": "3.0",
- "arch": "x86_64"
+ "version": "3.0"
}
],
- "cmd": "rpm -q",
- "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "system": "ubi",
"platform": "linux/amd64"
},
{
@@ -538,52 +442,42 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-2",
- "arch": "x86_64"
+ "version": "34-2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-agent",
- "version": "2",
- "arch": "x86_64"
+ "version": "2"
},
{
"name": "nginx-plus-module-appprotect",
- "version": "34+5.442",
- "arch": "x86_64"
+ "version": "34+5.442"
},
{
"name": "app-protect",
- "version": "34+5.442",
- "arch": "x86_64"
+ "version": "34+5.442"
},
{
"name": "app-protect-attack-signatures",
- "version": "2025",
- "arch": "x86_64"
+ "version": "2025"
},
{
"name": "app-protect-threat-campaigns",
- "version": "2025",
- "arch": "x86_64"
+ "version": "2025"
}
],
- "cmd": "rpm -q",
- "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "system": "ubi",
"platform": "linux/amd64"
},
{
@@ -592,47 +486,38 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-2",
- "arch": "x86_64"
+ "version": "34-2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-agent",
- "version": "2",
- "arch": "x86_64"
+ "version": "2"
},
{
"name": "nginx-plus-module-appprotect",
- "version": "34+5.442",
- "arch": "x86_64"
+ "version": "34+5.442"
},
{
"name": "app-protect-module-plus",
- "version": "34+5.442",
- "arch": "x86_64"
+ "version": "34+5.442"
},
{
"name": "app-protect-plugin",
- "version": "6.16.0",
- "arch": "x86_64"
+ "version": "6.16.0"
}
],
- "cmd": "rpm -q",
- "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "system": "ubi",
"platform": "linux/amd64"
},
{
@@ -641,52 +526,42 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-2",
- "arch": "x86_64"
+ "version": "34-2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-agent",
- "version": "2",
- "arch": "x86_64"
+ "version": "2"
},
{
"name": "nginx-plus-module-appprotect",
- "version": "34+5.442",
- "arch": "x86_64"
+ "version": "34+5.442"
},
{
"name": "app-protect",
- "version": "34+5.442",
- "arch": "x86_64"
+ "version": "34+5.442"
},
{
"name": "app-protect-attack-signatures",
- "version": "2025",
- "arch": "x86_64"
+ "version": "2025"
},
{
"name": "app-protect-threat-campaigns",
- "version": "2025",
- "arch": "x86_64"
+ "version": "2025"
}
],
- "cmd": "rpm -q",
- "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "system": "ubi",
"platform": "linux/amd64"
},
{
@@ -695,47 +570,38 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-2",
- "arch": "x86_64"
+ "version": "34-2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-agent",
- "version": "2",
- "arch": "x86_64"
+ "version": "2"
},
{
"name": "nginx-plus-module-appprotect",
- "version": "34+5.442",
- "arch": "x86_64"
+ "version": "34+5.442"
},
{
"name": "app-protect-module-plus",
- "version": "34+5.442",
- "arch": "x86_64"
+ "version": "34+5.442"
},
{
"name": "app-protect-plugin",
- "version": "6.16.0",
- "arch": "x86_64"
+ "version": "6.16.0"
}
],
- "cmd": "rpm -q",
- "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "system": "ubi",
"platform": "linux/amd64"
},
{
@@ -744,37 +610,30 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-2",
- "arch": "x86_64"
+ "version": "34-2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-appprotectdos",
- "version": "34+4",
- "arch": "x86_64"
+ "version": "34+4"
},
{
"name": "app-protect-dos",
- "version": "34+4",
- "arch": "x86_64"
+ "version": "34+4"
}
],
- "cmd": "rpm -q",
- "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "system": "ubi",
"platform": "linux/amd64"
},
{
@@ -783,62 +642,50 @@
"packages": [
{
"name": "nginx-plus",
- "version": "34-2",
- "arch": "x86_64"
+ "version": "34-2"
},
{
"name": "nginx-plus-module-njs",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-otel",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-fips-check",
- "version": "34",
- "arch": "x86_64"
+ "version": "34"
},
{
"name": "nginx-plus-module-appprotect",
- "version": "34+5.442",
- "arch": "x86_64"
+ "version": "34+5.442"
},
{
"name": "nginx-plus-module-appprotectdos",
- "version": "34+4",
- "arch": "x86_64"
+ "version": "34+4"
},
{
"name": "nginx-agent",
- "version": "2",
- "arch": "x86_64"
+ "version": "2"
},
{
"name": "app-protect",
- "version": "34+5.442",
- "arch": "x86_64"
+ "version": "34+5.442"
},
{
"name": "app-protect-attack-signatures",
- "version": "2025",
- "arch": "x86_64"
+ "version": "2025"
},
{
"name": "app-protect-threat-campaigns",
- "version": "2025",
- "arch": "x86_64"
+ "version": "2025"
},
{
"name": "app-protect-dos",
- "version": "34+4",
- "arch": "x86_64"
+ "version": "34+4"
}
],
- "cmd": "rpm -q",
- "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ "system": "ubi",
"platform": "linux/amd64"
}
]
diff --git a/tests/scripts/check_container_packages.py b/tests/scripts/check_container_packages.py
index 2498bf8e3d..909d5d2107 100755
--- a/tests/scripts/check_container_packages.py
+++ b/tests/scripts/check_container_packages.py
@@ -32,13 +32,29 @@
file_handler.setFormatter(logging.Formatter("%(message)s"))
logger.addHandler(file_handler)
+systems = {
+ "alpine": {
+ "cmd": "apk list",
+ "regex": "^(.+?)-(\\d+.+?)\\s+(\\w+).*\\[installed\\]",
+ },
+ "debian": {
+ "cmd": "dpkg -l",
+ "regex": "ii\\s+(.+?)\\s+(.+?)\\s+(\\w+?)\\s",
+ },
+ "ubi": {
+ "cmd": "rpm -q",
+ "regex": "(.+?)-(\\d+.+)(?:\\.ngx)?\\.(\\w+)",
+ },
+}
+
client = docker.from_env()
script_dir = os.path.dirname(os.path.abspath(__file__))
with open(f"{script_dir}/../data/modules/data.json") as file:
images = json.load(file)
for image in images["images"]:
- regexInstalled = image["regex"]
+ regexInstalled = systems[image["system"]]["regex"]
+ cmd = systems[image["system"]]["cmd"]
tag = f"{args.tag}{image['tag_suffix']}"
try:
i = client.images.get(f"{image['image']}:{tag}")
@@ -53,7 +69,7 @@
i = client.images.pull(repository=image["image"], tag=tag, platform=image["platform"])
logger.debug(f"Image {i.id} pulled successfully")
for package in image["packages"]:
- command = f"{image['cmd']} {package['name']}"
+ command = f"{cmd} {package['name']}"
output = ""
try:
output = client.containers.run(
@@ -81,7 +97,4 @@
assert result.group(2).startswith(package["version"]), logger.error(
f"{package['name']} version {package['version']} does not match {result.group(2)}"
)
- assert result.group(3) == package["arch"], logger.error(
- f"{package['name']} arch {package['arch']} does not match {result.group(3)}"
- )
- logger.info(f"{image["image"]}, {result.group(1)}, {result.group(2)}, {result.group(3)}")
+ logger.info(f"{image["image"]}, {result.group(1)}, {result.group(2)}")
From 86f6610f038445fc01d30592375c682523cbd42b Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Wed, 16 Jul 2025 11:21:18 +0100
Subject: [PATCH 17/20] check each image architecture
---
.github/workflows/ci.yml | 6 ++
tests/data/modules/data.json | 83 +++++++++++++++++-----
tests/scripts/check_container_packages.py | 85 ++++++++++++-----------
3 files changed, 113 insertions(+), 61 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 73fe990913..cbf325b1da 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -390,6 +390,12 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+ - name: Setup QEMU
+ uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
+ with:
+ platforms: arm64
+ if: ${{ needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' }}
+
- name: Authenticate to Google Cloud
id: auth
uses: google-github-actions/auth@ba79af03959ebeac9769e648f473a284504d9193 # v2.1.10
diff --git a/tests/data/modules/data.json b/tests/data/modules/data.json
index 4873fb948d..b30eb79c72 100644
--- a/tests/data/modules/data.json
+++ b/tests/data/modules/data.json
@@ -22,7 +22,10 @@
}
],
"system": "debian",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64",
+ "linux/arm64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress",
@@ -50,7 +53,10 @@
}
],
"system": "debian",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64",
+ "linux/arm64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress",
@@ -94,7 +100,9 @@
}
],
"system": "debian",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress",
@@ -134,7 +142,9 @@
}
],
"system": "debian",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress",
@@ -166,7 +176,9 @@
}
],
"system": "debian",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress",
@@ -218,7 +230,9 @@
}
],
"system": "debian",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress",
@@ -242,7 +256,10 @@
}
],
"system": "alpine",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64",
+ "linux/arm64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress",
@@ -270,7 +287,10 @@
}
],
"system": "alpine",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64",
+ "linux/arm64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress",
@@ -298,7 +318,10 @@
}
],
"system": "alpine",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64",
+ "linux/arm64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress",
@@ -342,7 +365,9 @@
}
],
"system": "alpine",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress",
@@ -382,7 +407,9 @@
}
],
"system": "alpine",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-ingress",
@@ -406,7 +433,10 @@
}
],
"system": "ubi",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64",
+ "linux/arm64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic/nginx-plus-ingress",
@@ -434,7 +464,10 @@
}
],
"system": "ubi",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64",
+ "linux/arm64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress",
@@ -478,7 +511,9 @@
}
],
"system": "ubi",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress",
@@ -518,7 +553,9 @@
}
],
"system": "ubi",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap/nginx-plus-ingress",
@@ -562,7 +599,9 @@
}
],
"system": "ubi",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-nap-v5/nginx-plus-ingress",
@@ -602,7 +641,9 @@
}
],
"system": "ubi",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos/nginx-plus-ingress",
@@ -634,7 +675,9 @@
}
],
"system": "ubi",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64"
+ ]
},
{
"image": "gcr.io/f5-gcs-7899-ptg-ingrss-ctlr/dev/nginx-ic-dos-nap/nginx-plus-ingress",
@@ -686,7 +729,9 @@
}
],
"system": "ubi",
- "platform": "linux/amd64"
+ "platforms": [
+ "linux/amd64"
+ ]
}
]
}
diff --git a/tests/scripts/check_container_packages.py b/tests/scripts/check_container_packages.py
index 909d5d2107..4e69326ae0 100755
--- a/tests/scripts/check_container_packages.py
+++ b/tests/scripts/check_container_packages.py
@@ -53,48 +53,49 @@
images = json.load(file)
for image in images["images"]:
- regexInstalled = systems[image["system"]]["regex"]
- cmd = systems[image["system"]]["cmd"]
- tag = f"{args.tag}{image['tag_suffix']}"
- try:
- i = client.images.get(f"{image['image']}:{tag}")
- ## check if the image is for the correct platform
- if image["platform"] != i.attrs["Os"]:
- raise docker.errors.ImageNotFound(
- f"Image {image['image']}:{tag} is not for platform {image['platform']}, found {i.attrs['Os']}"
- )
- except docker.errors.ImageNotFound:
- ## pull the image
- logger.debug(f"Pulling image {image['image']}:{tag} for platform {image['platform']}")
- i = client.images.pull(repository=image["image"], tag=tag, platform=image["platform"])
- logger.debug(f"Image {i.id} pulled successfully")
- for package in image["packages"]:
- command = f"{cmd} {package['name']}"
- output = ""
+ for platform in image["platforms"]:
+ regexInstalled = systems[image["system"]]["regex"]
+ cmd = systems[image["system"]]["cmd"]
+ tag = f"{args.tag}{image['tag_suffix']}"
try:
- output = client.containers.run(
- f"{image['image']}:{tag}",
- command,
- entrypoint="",
- platform=image["platform"],
- auto_remove=True,
- detach=False,
+ i = client.images.get(f"{image['image']}:{tag}")
+ ## check if the image is for the correct platform
+ if platform != i.attrs["Os"]:
+ raise docker.errors.ImageNotFound(
+ f"Image {image['image']}:{tag} is not for platform {platform}, found {i.attrs['Os']}"
+ )
+ except docker.errors.ImageNotFound:
+ ## pull the image
+ logger.debug(f"Pulling image {image['image']}:{tag} for platform {platform}")
+ i = client.images.pull(repository=image["image"], tag=tag, platform=platform)
+ logger.debug(f"Image {i.id} pulled successfully")
+ for package in image["packages"]:
+ command = f"{cmd} {package['name']}"
+ output = ""
+ try:
+ output = client.containers.run(
+ f"{image['image']}:{tag}",
+ command,
+ entrypoint="",
+ platform=platform,
+ auto_remove=True,
+ detach=False,
+ )
+ except (docker.errors.ContainerError, docker.errors.NotFound) as e:
+ logger.error(f"{e}, retrying")
+ output = client.containers.run(
+ f"{image['image']}:{tag}",
+ command,
+ entrypoint="",
+ platform=platform,
+ auto_remove=True,
+ detach=False,
+ )
+ result = re.search(regexInstalled, output.decode("utf-8").strip())
+ assert result, logger.error(
+ f"{package['name']} not found in {image['image']}, output: {output.decode('utf-8').strip()}"
)
- except (docker.errors.ContainerError, docker.errors.NotFound) as e:
- logger.error(f"{e}, retrying")
- output = client.containers.run(
- f"{image['image']}:{tag}",
- command,
- entrypoint="",
- platform=image["platform"],
- auto_remove=True,
- detach=False,
+ assert result.group(2).startswith(package["version"]), logger.error(
+ f"{package['name']} version {package['version']} does not match {result.group(2)}"
)
- result = re.search(regexInstalled, output.decode("utf-8").strip())
- assert result, logger.error(
- f"{package['name']} not found in {image['image']}, output: {output.decode('utf-8').strip()}"
- )
- assert result.group(2).startswith(package["version"]), logger.error(
- f"{package['name']} version {package['version']} does not match {result.group(2)}"
- )
- logger.info(f"{image["image"]}, {result.group(1)}, {result.group(2)}")
+ logger.info(f"{image["image"]}, {result.group(1)}, {result.group(2)}, {result.group(3)}")
From c269e0217b0e40b60148306fa59d4c570fbcca93 Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Wed, 16 Jul 2025 11:35:48 +0100
Subject: [PATCH 18/20] use named variables for image name
---
tests/scripts/check_container_packages.py | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/tests/scripts/check_container_packages.py b/tests/scripts/check_container_packages.py
index 4e69326ae0..abcb0f50f8 100755
--- a/tests/scripts/check_container_packages.py
+++ b/tests/scripts/check_container_packages.py
@@ -54,7 +54,8 @@
for image in images["images"]:
for platform in image["platforms"]:
- regexInstalled = systems[image["system"]]["regex"]
+ image_name = image["image"]
+ regex = systems[image["system"]]["regex"]
cmd = systems[image["system"]]["cmd"]
tag = f"{args.tag}{image['tag_suffix']}"
try:
@@ -67,7 +68,7 @@
except docker.errors.ImageNotFound:
## pull the image
logger.debug(f"Pulling image {image['image']}:{tag} for platform {platform}")
- i = client.images.pull(repository=image["image"], tag=tag, platform=platform)
+ i = client.images.pull(repository=image_name, tag=tag, platform=platform)
logger.debug(f"Image {i.id} pulled successfully")
for package in image["packages"]:
command = f"{cmd} {package['name']}"
@@ -91,11 +92,11 @@
auto_remove=True,
detach=False,
)
- result = re.search(regexInstalled, output.decode("utf-8").strip())
+ result = re.search(regex, output.decode("utf-8").strip())
assert result, logger.error(
f"{package['name']} not found in {image['image']}, output: {output.decode('utf-8').strip()}"
)
assert result.group(2).startswith(package["version"]), logger.error(
f"{package['name']} version {package['version']} does not match {result.group(2)}"
)
- logger.info(f"{image["image"]}, {result.group(1)}, {result.group(2)}, {result.group(3)}")
+ logger.info(f"{image_name}, {result.group(1)}, {result.group(2)}, {result.group(3)}")
From 4fa7908d8ad71b1baae06f0ed5b91eb3954d2fa8 Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Wed, 16 Jul 2025 11:52:13 +0100
Subject: [PATCH 19/20] format comment
---
.github/workflows/ci.yml | 7 ++++++-
tests/scripts/check_container_packages.py | 2 +-
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index cbf325b1da..2f37557e20 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -427,7 +427,12 @@ jobs:
- name: Add comment
run: |
- gh pr comment ${{ github.event.pull_request.number }} -F package_output.txt
+ # make sure the comment is formatted correctly, as a code block
+ echo '### Package Report' > output.txt
+ echo '```' >> output.txt
+ cat package_output.txt >> output.txt
+ echo '```' >> output.txt
+ gh pr comment ${{ github.event.pull_request.number }} -F output.txt
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: ${{ ( needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' ) && github.event.pull_request }}
diff --git a/tests/scripts/check_container_packages.py b/tests/scripts/check_container_packages.py
index abcb0f50f8..f4010da4fc 100755
--- a/tests/scripts/check_container_packages.py
+++ b/tests/scripts/check_container_packages.py
@@ -99,4 +99,4 @@
assert result.group(2).startswith(package["version"]), logger.error(
f"{package['name']} version {package['version']} does not match {result.group(2)}"
)
- logger.info(f"{image_name}, {result.group(1)}, {result.group(2)}, {result.group(3)}")
+ logger.info(f"{image_name}:{tag}, {result.group(1)}, {result.group(2)}, {result.group(3)}")
From 0713c16d9ae40458bb61b6667f28d7e5c8a16d92 Mon Sep 17 00:00:00 2001
From: Paul Abel
Date: Wed, 16 Jul 2025 11:58:21 +0100
Subject: [PATCH 20/20] update comment if it already exists
---
.github/workflows/ci.yml | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2f37557e20..6265b3155a 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -378,7 +378,7 @@ jobs:
if: ${{ inputs.force || (needs.checks.outputs.forked_workflow == 'true' && needs.checks.outputs.docs_only == 'false') || (needs.checks.outputs.forked_workflow == 'false' && needs.checks.outputs.stable_image_exists != 'true' && needs.checks.outputs.docs_only == 'false') }}
package-tests:
- if: ${{ needs.checks.outputs.docs_only != 'true' }}
+ if: ${{ needs.checks.outputs.docs_only != 'true' && (inputs.run_tests && inputs.run_tests || true) }}
name: Package Tests
runs-on: ubuntu-22.04
needs: [checks, binaries, build-docker, build-docker-plus, build-docker-nap]
@@ -432,7 +432,7 @@ jobs:
echo '```' >> output.txt
cat package_output.txt >> output.txt
echo '```' >> output.txt
- gh pr comment ${{ github.event.pull_request.number }} -F output.txt
+ gh pr comment --edit-last --create-if-none ${{ github.event.pull_request.number }} -F output.txt
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: ${{ ( needs.checks.outputs.forked_workflow == 'false' || needs.checks.outputs.docs_only == 'false' ) && github.event.pull_request }}
@@ -737,10 +737,12 @@ jobs:
if: ${{ !cancelled() }}
runs-on: ubuntu-22.04
name: Final CI Results
- needs: [tag-stable, build-docker, build-docker-plus, build-docker-nap, smoke-tests-oss, smoke-tests-plus, smoke-tests-nap]
+ needs: [tag-stable, build-docker, build-docker-plus, build-docker-nap, smoke-tests-oss, smoke-tests-plus, smoke-tests-nap, package-tests, helm-tests]
steps:
- run: |
tagResult="${{ needs.tag-stable.result }}"
+ packageResult="${{ needs.package-tests.result }}"
+ helmResult="${{ needs.helm-tests.result }}"
smokeOSSResult="${{ needs.smoke-tests-oss.result }}"
smokePlusResult="${{ needs.smoke-tests-plus.result }}"
smokeNAPResult="${{ needs.smoke-tests-nap.result }}"
@@ -768,6 +770,12 @@ jobs:
if [[ $buildNAPResult != "success" && $buildNAPResult != "skipped" ]]; then
exit 1
fi
+ if [[ $helmResult != "success" && $helmResult != "skipped" ]]; then
+ exit 1
+ fi
+ if [[ $packageResult != "success" && $packageResult != "skipped" ]]; then
+ exit 1
+ fi
trigger-image-promotion:
name: Promote images on Force Run