diff --git a/.github/workflows/e2e-pr-tester.yaml b/.github/workflows/e2e-pr-tester.yaml index 30525063..e2df6186 100644 --- a/.github/workflows/e2e-pr-tester.yaml +++ b/.github/workflows/e2e-pr-tester.yaml @@ -174,7 +174,7 @@ jobs: python-version: "3.11" - name: Clone k8s-apps-deployer - run: git clone https://github.com/stillalearner/k8s-apps-deployer.git + run: git clone --branch conditional-ocp-resources --single-branch https://github.com/stillalearner/k8s-apps-deployer.git - name: Create venv and install package run: | diff --git a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/export/resources/simple-nginx-nopv/Route_route.openshift.io_v1_simple-nginx-nopv_my-simple-nginx-nopv.yaml b/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/export/resources/simple-nginx-nopv/Route_route.openshift.io_v1_simple-nginx-nopv_my-simple-nginx-nopv.yaml new file mode 100644 index 00000000..26363c24 --- /dev/null +++ b/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/export/resources/simple-nginx-nopv/Route_route.openshift.io_v1_simple-nginx-nopv_my-simple-nginx-nopv.yaml @@ -0,0 +1,32 @@ +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + annotations: + openshift.io/host.generated: "true" + creationTimestamp: "2026-07-08T11:53:19Z" + generation: 1 + labels: + app: simple-nginx-nopv + name: my-simple-nginx-nopv + namespace: simple-nginx-nopv + resourceVersion: "140464" + uid: 845eb523-3590-4071-9161-16e13b294be1 +spec: + host: my-simple-nginx-nopv-simple-nginx-nopv.apps.migqe-57431.qe.devcluster.openshift.com + port: + targetPort: 8080 + to: + kind: Service + name: my-simple-nginx-nopv + weight: 100 + wildcardPolicy: None +status: + ingress: + - conditions: + - lastTransitionTime: "2026-07-08T11:53:19Z" + status: "True" + type: Admitted + host: my-simple-nginx-nopv-simple-nginx-nopv.apps.migqe-57431.qe.devcluster.openshift.com + routerCanonicalHostname: router-default.apps.migqe-57431.qe.devcluster.openshift.com + routerName: default + wildcardPolicy: None diff --git a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/output.yaml b/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/output.yaml index 19b7a482..e39be354 100644 --- a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/output.yaml +++ b/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/output.yaml @@ -1,91 +1,4 @@ apiVersion: v1 -imagePullSecrets: -- name: builder-dockercfg-n5zzt -kind: ServiceAccount -metadata: - annotations: - openshift.io/internal-registry-pull-secret-ref: builder-dockercfg-n5zzt - name: builder - namespace: simple-nginx-nopv -secrets: -- name: builder-dockercfg-n5zzt ---- -apiVersion: v1 -imagePullSecrets: -- name: deployer-dockercfg-rgp2c -kind: ServiceAccount -metadata: - annotations: - openshift.io/internal-registry-pull-secret-ref: deployer-dockercfg-rgp2c - name: deployer - namespace: simple-nginx-nopv -secrets: -- name: deployer-dockercfg-rgp2c ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - annotations: - openshift.io/description: Allows deploymentconfigs in this namespace to rollout - pods in this namespace. It is auto-managed by a controller; remove subjects - to disable. - name: system:deployers - namespace: simple-nginx-nopv -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:deployer -subjects: -- kind: ServiceAccount - name: deployer - namespace: simple-nginx-nopv ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - annotations: - openshift.io/description: Allows builds in this namespace to push images to this - namespace. It is auto-managed by a controller; remove subjects to disable. - name: system:image-builders - namespace: simple-nginx-nopv -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:image-builder -subjects: -- kind: ServiceAccount - name: builder - namespace: simple-nginx-nopv ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - annotations: - openshift.io/description: Allows all pods in this namespace to pull images from - this namespace. It is auto-managed by a controller; remove subjects to disable. - name: system:image-pullers - namespace: simple-nginx-nopv -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:image-puller -subjects: -- apiGroup: rbac.authorization.k8s.io - kind: Group - name: system:serviceaccounts:simple-nginx-nopv ---- -apiVersion: v1 -data: - service-ca.crt: | - REDACTED -kind: ConfigMap -metadata: - annotations: - service.beta.openshift.io/inject-cabundle: "true" - name: openshift-service-ca.crt - namespace: simple-nginx-nopv ---- -apiVersion: v1 kind: Service metadata: labels: @@ -148,3 +61,36 @@ spec: schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 +--- +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + annotations: + openshift.io/host.generated: "true" + creationTimestamp: "2026-07-08T11:53:19Z" + generation: 1 + labels: + app: simple-nginx-nopv + name: my-simple-nginx-nopv + namespace: simple-nginx-nopv + resourceVersion: "140464" + uid: 845eb523-3590-4071-9161-16e13b294be1 +spec: + host: my-simple-nginx-nopv-simple-nginx-nopv.apps.migqe-57431.qe.devcluster.openshift.com + port: + targetPort: 8080 + to: + kind: Service + name: my-simple-nginx-nopv + weight: 100 + wildcardPolicy: None +status: + ingress: + - conditions: + - lastTransitionTime: "2026-07-08T11:53:19Z" + status: "True" + type: Admitted + host: my-simple-nginx-nopv-simple-nginx-nopv.apps.migqe-57431.qe.devcluster.openshift.com + routerCanonicalHostname: router-default.apps.migqe-57431.qe.devcluster.openshift.com + routerName: default + wildcardPolicy: None diff --git a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/ConfigMap__v1_simple-nginx-nopv_openshift-service-ca.crt.yaml b/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/ConfigMap__v1_simple-nginx-nopv_openshift-service-ca.crt.yaml deleted file mode 100644 index 620f03dd..00000000 --- a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/ConfigMap__v1_simple-nginx-nopv_openshift-service-ca.crt.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -data: - service-ca.crt: REDACTED -kind: ConfigMap -metadata: - annotations: - service.beta.openshift.io/inject-cabundle: "true" - name: openshift-service-ca.crt - namespace: simple-nginx-nopv diff --git a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/RoleBinding_rbac.authorization.k8s.io_v1_simple-nginx-nopv_system:deployers.yaml b/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/RoleBinding_rbac.authorization.k8s.io_v1_simple-nginx-nopv_system:deployers.yaml deleted file mode 100644 index f603a26b..00000000 --- a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/RoleBinding_rbac.authorization.k8s.io_v1_simple-nginx-nopv_system:deployers.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - annotations: - openshift.io/description: Allows deploymentconfigs in this namespace to rollout pods in this namespace. It is auto-managed by a controller; remove subjects to disable. - name: system:deployers - namespace: simple-nginx-nopv -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:deployer -subjects: - - kind: ServiceAccount - name: deployer - namespace: simple-nginx-nopv diff --git a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/RoleBinding_rbac.authorization.k8s.io_v1_simple-nginx-nopv_system:image-builders.yaml b/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/RoleBinding_rbac.authorization.k8s.io_v1_simple-nginx-nopv_system:image-builders.yaml deleted file mode 100644 index c7016efc..00000000 --- a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/RoleBinding_rbac.authorization.k8s.io_v1_simple-nginx-nopv_system:image-builders.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - annotations: - openshift.io/description: Allows builds in this namespace to push images to this namespace. It is auto-managed by a controller; remove subjects to disable. - name: system:image-builders - namespace: simple-nginx-nopv -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:image-builder -subjects: - - kind: ServiceAccount - name: builder - namespace: simple-nginx-nopv diff --git a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/RoleBinding_rbac.authorization.k8s.io_v1_simple-nginx-nopv_system:image-pullers.yaml b/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/RoleBinding_rbac.authorization.k8s.io_v1_simple-nginx-nopv_system:image-pullers.yaml deleted file mode 100644 index 94c9140f..00000000 --- a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/RoleBinding_rbac.authorization.k8s.io_v1_simple-nginx-nopv_system:image-pullers.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - annotations: - openshift.io/description: Allows all pods in this namespace to pull images from this namespace. It is auto-managed by a controller; remove subjects to disable. - name: system:image-pullers - namespace: simple-nginx-nopv -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:image-puller -subjects: - - apiGroup: rbac.authorization.k8s.io - kind: Group - name: system:serviceaccounts:simple-nginx-nopv diff --git a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/Route_route.openshift.io_v1_simple-nginx-nopv_my-simple-nginx-nopv.yaml b/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/Route_route.openshift.io_v1_simple-nginx-nopv_my-simple-nginx-nopv.yaml new file mode 100644 index 00000000..26363c24 --- /dev/null +++ b/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/Route_route.openshift.io_v1_simple-nginx-nopv_my-simple-nginx-nopv.yaml @@ -0,0 +1,32 @@ +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + annotations: + openshift.io/host.generated: "true" + creationTimestamp: "2026-07-08T11:53:19Z" + generation: 1 + labels: + app: simple-nginx-nopv + name: my-simple-nginx-nopv + namespace: simple-nginx-nopv + resourceVersion: "140464" + uid: 845eb523-3590-4071-9161-16e13b294be1 +spec: + host: my-simple-nginx-nopv-simple-nginx-nopv.apps.migqe-57431.qe.devcluster.openshift.com + port: + targetPort: 8080 + to: + kind: Service + name: my-simple-nginx-nopv + weight: 100 + wildcardPolicy: None +status: + ingress: + - conditions: + - lastTransitionTime: "2026-07-08T11:53:19Z" + status: "True" + type: Admitted + host: my-simple-nginx-nopv-simple-nginx-nopv.apps.migqe-57431.qe.devcluster.openshift.com + routerCanonicalHostname: router-default.apps.migqe-57431.qe.devcluster.openshift.com + routerName: default + wildcardPolicy: None diff --git a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/ServiceAccount__v1_simple-nginx-nopv_builder.yaml b/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/ServiceAccount__v1_simple-nginx-nopv_builder.yaml deleted file mode 100644 index 7afcea92..00000000 --- a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/ServiceAccount__v1_simple-nginx-nopv_builder.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -imagePullSecrets: - - name: builder-dockercfg-n5zzt -kind: ServiceAccount -metadata: - annotations: - openshift.io/internal-registry-pull-secret-ref: builder-dockercfg-n5zzt - name: builder - namespace: simple-nginx-nopv -secrets: - - name: builder-dockercfg-n5zzt diff --git a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/ServiceAccount__v1_simple-nginx-nopv_deployer.yaml b/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/ServiceAccount__v1_simple-nginx-nopv_deployer.yaml deleted file mode 100644 index c9e1d603..00000000 --- a/e2e-tests/golden-manifests-ocp/simple-nginx-nopv/output/resources/simple-nginx-nopv/ServiceAccount__v1_simple-nginx-nopv_deployer.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -imagePullSecrets: - - name: deployer-dockercfg-rgp2c -kind: ServiceAccount -metadata: - annotations: - openshift.io/internal-registry-pull-secret-ref: deployer-dockercfg-rgp2c - name: deployer - namespace: simple-nginx-nopv -secrets: - - name: deployer-dockercfg-rgp2c diff --git a/e2e-tests/tests/tier0/mta_839_networkpolicy_migration_test.go b/e2e-tests/tests/tier0/mta_839_networkpolicy_migration_test.go index a44906b5..a7c39a19 100644 --- a/e2e-tests/tests/tier0/mta_839_networkpolicy_migration_test.go +++ b/e2e-tests/tests/tier0/mta_839_networkpolicy_migration_test.go @@ -55,6 +55,16 @@ var _ = Describe("NetworkPolicy migration", func() { Expect(PrepareSourceApp(srcApp, kubectlSrcNonAdmin)).NotTo(HaveOccurred()) log.Printf("Source app %s prepared successfully\n", srcApp.Name) + ingressFrom := ` - podSelector: {}` + if kubectlTgtNonAdmin.IsOpenShift() { + // OpenShift router pods run in openshift-ingress namespace and must be + // allowed to reach backend pods through this NetworkPolicy. + ingressFrom += ` + - namespaceSelector: + matchLabels: + network.openshift.io/policy-group: ingress` + } + networkPolicyManifest := fmt.Sprintf(`apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: @@ -69,7 +79,7 @@ spec: - Egress ingress: - from: - - podSelector: {} +%s ports: - protocol: TCP port: 8080 @@ -81,7 +91,7 @@ spec: port: 53 - protocol: TCP port: 53 -`, networkPolicyName, namespace, appName) +`, networkPolicyName, namespace, appName, ingressFrom) By("Create NetworkPolicy on source cluster") Expect(kubectlSrcNonAdmin.ApplyYAMLSpec(networkPolicyManifest, namespace)).NotTo(HaveOccurred()) diff --git a/e2e-tests/utils/utils.go b/e2e-tests/utils/utils.go index 2ca866bc..831cb5fd 100644 --- a/e2e-tests/utils/utils.go +++ b/e2e-tests/utils/utils.go @@ -707,6 +707,15 @@ func normalizeUnstableFields(doc any) any { return normalized } + if kind == "Route" { + // OpenShift Route host includes ephemeral cluster domain and can vary + // across test environments/runs. + if spec, ok := root["spec"].(map[string]any); ok { + delete(spec, "host") + } + return normalized + } + if kind == "ReplicaSet" { delete(metadata, "name") stripPodTemplateHash(metadata) @@ -1191,35 +1200,35 @@ func AssertFilesExist(dir string, expectedFiles []string) error { } return nil } - - // RemapNamespaceInYAML parses each document in a multi-doc YAML stream, - // replaces srcNamespace with tgtNamespace in metadata.namespace, - // and returns the re-serialized YAML string. - func RemapNamespaceInYAML(content []byte, srcNamespace, tgtNamespace string) (string, error) { - docs, err := parseYAMLDocuments(content) - if err != nil { - return "", fmt.Errorf("parsing YAML documents: %w", err) - } - - var parts []string - for i, doc := range docs { - obj, ok := doc.(map[string]any) - if !ok { - return "", fmt.Errorf("document %d: expected map[string]any, got %T", i, doc) - } - if meta, ok := obj["metadata"].(map[string]any); ok { - if meta["namespace"] == srcNamespace { - meta["namespace"] = tgtNamespace - } - } - out, err := yaml.Marshal(obj) - if err != nil { - return "", fmt.Errorf("marshaling YAML document: %w", err) - } - parts = append(parts, string(out)) - } - return strings.Join(parts, "---\n"), nil - } + +// RemapNamespaceInYAML parses each document in a multi-doc YAML stream, +// replaces srcNamespace with tgtNamespace in metadata.namespace, +// and returns the re-serialized YAML string. +func RemapNamespaceInYAML(content []byte, srcNamespace, tgtNamespace string) (string, error) { + docs, err := parseYAMLDocuments(content) + if err != nil { + return "", fmt.Errorf("parsing YAML documents: %w", err) + } + + var parts []string + for i, doc := range docs { + obj, ok := doc.(map[string]any) + if !ok { + return "", fmt.Errorf("document %d: expected map[string]any, got %T", i, doc) + } + if meta, ok := obj["metadata"].(map[string]any); ok { + if meta["namespace"] == srcNamespace { + meta["namespace"] = tgtNamespace + } + } + out, err := yaml.Marshal(obj) + if err != nil { + return "", fmt.Errorf("marshaling YAML document: %w", err) + } + parts = append(parts, string(out)) + } + return strings.Join(parts, "---\n"), nil +} // ParseValidationReport reads and parses a crane validate report file. // The report parameter should be a pointer to the structure that will hold the parsed data. diff --git a/e2e-tests/utils/utils_test.go b/e2e-tests/utils/utils_test.go index 8628c3a0..d6a5a620 100644 --- a/e2e-tests/utils/utils_test.go +++ b/e2e-tests/utils/utils_test.go @@ -1109,6 +1109,39 @@ func TestNormalizeUnstableFields(t *testing.T) { } }, }, + { + name: "drops_route_host_but_keeps_stable_route_fields", + in: map[string]any{ + "apiVersion": "route.openshift.io/v1", + "kind": "Route", + "metadata": map[string]any{ + "name": "my-route", + "namespace": "ns", + }, + "spec": map[string]any{ + "host": "my-route-ns.apps.cluster-a.example.com", + "to": map[string]any{ + "kind": "Service", + "name": "my-svc", + }, + "port": map[string]any{ + "targetPort": 8080, + }, + }, + }, + validate: func(t *testing.T, got any) { + t.Helper() + m := got.(map[string]any) + spec := m["spec"].(map[string]any) + if _, exists := spec["host"]; exists { + t.Fatal("expected route spec.host to be removed") + } + to := spec["to"].(map[string]any) + if to["name"] != "my-svc" { + t.Fatalf("expected route spec.to fields to remain, got: %#v", to) + } + }, + }, { name: "drops_nested_template_metadata_creation_timestamp", in: map[string]any{