Skip to content

Commit

Permalink
Fix tests after changes in validation webhook (#708)
Browse files Browse the repository at this point in the history
* [OSSM-6799] Fix TestSMCPMultiple after changes in validatingwebhookconfiguration

* [OSSM-6800] Fix TestMustGather test after changes in validatingwebhookconfiguration

* [OSSM-6811] Create test case for OLM validationg/mutating webhooks
  • Loading branch information
mkralik3 committed Jul 11, 2024
1 parent ad7e8e7 commit 370892c
Show file tree
Hide file tree
Showing 5 changed files with 226 additions and 32 deletions.
78 changes: 51 additions & 27 deletions pkg/tests/non-dependant/bug_multiple_smcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package non_dependant

import (
_ "embed"
"fmt"
"testing"

"github.com/maistra/maistra-test-tool/pkg/tests/ossm"
Expand All @@ -10,57 +11,80 @@ import (
"github.com/maistra/maistra-test-tool/pkg/util/oc"
"github.com/maistra/maistra-test-tool/pkg/util/pod"
"github.com/maistra/maistra-test-tool/pkg/util/retry"
"github.com/maistra/maistra-test-tool/pkg/util/shell"
. "github.com/maistra/maistra-test-tool/pkg/util/test"
"github.com/maistra/maistra-test-tool/pkg/util/version"
)

func TestSMCPMultiple(t *testing.T) {
NewTest(t).Id("T36").Groups(Full, ARM).Run(func(t TestHelper) {
t.Log("This test verifies whether the operator only reconciles one SMCP when two exist in a namespace")
t.Log("See https://issues.redhat.com/browse/OSSM-2419")

smcp1 := ossm.DefaultSMCP().WithName("smcp1")
smcp2 := ossm.DefaultSMCP().WithName("smcp2")

t.Cleanup(func() {
t.LogStepf("Delete namespace %s", meshNamespace)
oc.RecreateNamespace(t, meshNamespace)

t.LogStep("Delete operator to recreate the ValidationWebhookConfiguration")
oc.DeletePod(t, pod.MatchingSelector("name=istio-operator", env.GetOperatorNamespace()))

t.LogStep("Wait for operator pod to be ready")
oc.WaitPodReady(t, pod.MatchingSelector("name=istio-operator", env.GetOperatorNamespace()))

t.LogStep("Check whether ValidatingWebhookConfiguration exists")
retry.UntilSuccess(t, func(t TestHelper) {
oc.Get(t, "", "validatingwebhookconfiguration", "openshift-operators.servicemesh-resources.maistra.io")
t.LogSuccess("ValidatingWebhookConfiguration was recreated by the operator")
})
if env.GetOperatorVersion().LessThan(version.OPERATOR_2_6_0) {
t.LogStep("Delete operator to recreate the ValidationWebhookConfiguration")
oc.DeletePod(t, pod.MatchingSelector("name=istio-operator", env.GetOperatorNamespace()))
t.LogStep("Wait for operator pod to be ready")
oc.WaitPodReady(t, pod.MatchingSelector("name=istio-operator", env.GetOperatorNamespace()))
t.LogStep("Check whether ValidatingWebhookConfiguration exists")
retry.UntilSuccess(t, func(t TestHelper) {
oc.Get(t, "", "validatingwebhookconfiguration", "openshift-operators.servicemesh-resources.maistra.io")
t.LogSuccess("ValidatingWebhookConfiguration was recreated by the operator")
})
}
})

t.LogStepf("Delete and recreate namespace %s", meshNamespace)
oc.RecreateNamespace(t, meshNamespace)

t.LogStep("Delete the operator's ValidationWebhookConfiguration")
oc.DeleteResource(t, "", "validatingwebhookconfiguration", "openshift-operators.servicemesh-resources.maistra.io")

t.LogStep("Create the first SMCP")
smcp1 := ossm.DefaultSMCP().WithName("smcp1")
ossm.InstallSMCPCustom(t, meshNamespace, smcp1)

t.LogStep("Check whether the first SMCP gets reconciled and becomes ready")
oc.WaitSMCPReady(t, meshNamespace, smcp1.Name)
t.LogSuccess("First SMCP is ready")

t.LogStep("Create the second SMCP")
ossm.InstallSMCPCustom(t, meshNamespace, smcp2)
if env.GetOperatorVersion().GreaterThanOrEqual(version.OPERATOR_2_6_0) {
t.LogStep("Check that the validationwebhook prevent of creating the second SMCP")
shell.Execute(t,
fmt.Sprintf("echo \"%s\" | oc create -f - -n %s || true", simpleSmcp(), meshNamespace),
assert.OutputContains("admission webhook \"smcp.validation.maistra.io\" denied the request: only one service mesh may be installed per project/namespace",
"Validationwebhook prevents of creating the second SMCP",
"Expect that creation of second smcp fails on validationwebhook"))
} else {
t.LogStep("Delete the operator's ValidationWebhookConfiguration to be able to install the second SMCP")
oc.DeleteResource(t, "", "validatingwebhookconfiguration", "openshift-operators.servicemesh-resources.maistra.io")
t.LogStep("Create the second SMCP")
smcp2 := ossm.DefaultSMCP().WithName("smcp2")
ossm.InstallSMCPCustom(t, meshNamespace, smcp2)
ossm.InstallSMCPCustom(t, meshNamespace, smcp2)

t.LogStep("Check whether the second SMCP shows ErrMultipleSMCPs")
retry.UntilSuccess(t, func(t TestHelper) {
oc.Get(t, meshNamespace,
"smcp", smcp2.Name,
assert.OutputContains("ErrMultipleSMCPs",
"The second SMCP status is ErrMultipleSMCPs",
"The second SMCP status is not ErrMultipleSMCPs"))
})
ossm.InstallSMCPCustom(t, meshNamespace, smcp2)

t.LogStep("Check whether the second SMCP shows ErrMultipleSMCPs")
retry.UntilSuccess(t, func(t TestHelper) {
oc.Get(t, meshNamespace,
"smcp", smcp2.Name,
assert.OutputContains("ErrMultipleSMCPs",
"The second SMCP status is ErrMultipleSMCPs",
"The second SMCP status is not ErrMultipleSMCPs"))
})
}
})
}

func simpleSmcp() string {
return fmt.Sprintf(`
kind: ServiceMeshControlPlane
apiVersion: maistra.io/v2
metadata:
name: basic
spec:
version: %s
`, env.GetSMCPVersion())
}
116 changes: 116 additions & 0 deletions pkg/tests/non-dependant/olm_webhooks_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package non_dependant

import (
_ "embed"
"testing"
"time"

"github.com/maistra/maistra-test-tool/pkg/tests/ossm"
"github.com/maistra/maistra-test-tool/pkg/util/env"
"github.com/maistra/maistra-test-tool/pkg/util/oc"
"github.com/maistra/maistra-test-tool/pkg/util/retry"
. "github.com/maistra/maistra-test-tool/pkg/util/test"
"github.com/maistra/maistra-test-tool/pkg/util/version"
)

func TestOlmWebhookCreation(t *testing.T) {
NewTest(t).Groups(Full, ARM).Run(func(t TestHelper) {
t.Log("This test verifies that OLM creates all validating/mutating webhooks")
t.Log("See https://issues.redhat.com/browse/OSSM-6762")
if env.GetOperatorVersion().LessThan(version.OPERATOR_2_6_0) {
t.Skip("Skipping until 2.6 operator")
}

t.Cleanup(func() {
t.LogStepf("Delete namespace %s", meshNamespace)
oc.RecreateNamespace(t, meshNamespace)
})

t.LogStepf("Delete and recreate namespace %s", meshNamespace)
oc.RecreateNamespace(t, meshNamespace)

t.NewSubTest("Check global webhooks").Run(func(t TestHelper) {
t.Log("Check that global validatingwebhookconfiguration's were created by OLM")
checkGlobalWebhooks(t, "validatingwebhookconfiguration", "olm.webhook-description-generate-name=smcp.validation.maistra.io")
checkGlobalWebhooks(t, "validatingwebhookconfiguration", "olm.webhook-description-generate-name=smmr.validation.maistra.io")
checkGlobalWebhooks(t, "validatingwebhookconfiguration", "olm.webhook-description-generate-name=smm.validation.maistra.io")

t.Log("Check that global validatingwebhookconfiguration's were recreated by OLM after deletion")
deleteGlobalWebhook(t, "validatingwebhookconfiguration", "olm.webhook-description-generate-name=smcp.validation.maistra.io")
deleteGlobalWebhook(t, "validatingwebhookconfiguration", "olm.webhook-description-generate-name=smmr.validation.maistra.io")
deleteGlobalWebhook(t, "validatingwebhookconfiguration", "olm.webhook-description-generate-name=smm.validation.maistra.io")
retry.UntilSuccessWithOptions(t, retry.Options().MaxAttempts(30).DelayBetweenAttempts(5*time.Second), func(t TestHelper) {
checkGlobalWebhooks(t, "validatingwebhookconfiguration", "olm.webhook-description-generate-name=smcp.validation.maistra.io")
checkGlobalWebhooks(t, "validatingwebhookconfiguration", "olm.webhook-description-generate-name=smmr.validation.maistra.io")
checkGlobalWebhooks(t, "validatingwebhookconfiguration", "olm.webhook-description-generate-name=smm.validation.maistra.io")
})

t.Log("Check that global mutatingwebhookconfiguration's were created by OLM")
checkGlobalWebhooks(t, "mutatingwebhookconfiguration", "olm.webhook-description-generate-name=smcp.mutation.maistra.io")
checkGlobalWebhooks(t, "mutatingwebhookconfiguration", "olm.webhook-description-generate-name=smmr.mutation.maistra.io")

t.Log("Check that global mutatingwebhookconfiguration's were recreated by OLM after deletion")
deleteGlobalWebhook(t, "mutatingwebhookconfiguration", "olm.webhook-description-generate-name=smcp.mutation.maistra.io")
deleteGlobalWebhook(t, "mutatingwebhookconfiguration", "olm.webhook-description-generate-name=smmr.mutation.maistra.io")
retry.UntilSuccessWithOptions(t, retry.Options().MaxAttempts(30).DelayBetweenAttempts(5*time.Second), func(t TestHelper) {
checkGlobalWebhooks(t, "mutatingwebhookconfiguration", "olm.webhook-description-generate-name=smcp.mutation.maistra.io")
checkGlobalWebhooks(t, "mutatingwebhookconfiguration", "olm.webhook-description-generate-name=smmr.mutation.maistra.io")
})
})

t.NewSubTest("Check smcp related webhooks").Run(func(t TestHelper) {
t.Log("Check that smcp related webhooks doesn't exist")
checkSmcpWebhooksDoesNotExist(t, "validatingwebhookconfiguration", "maistra.io/owner-name="+env.GetDefaultSMCPName())
checkSmcpWebhooksDoesNotExist(t, "mutatingwebhookconfiguration", "maistra.io/owner-name="+env.GetDefaultSMCPName())

t.LogStep("Create the SMCP")
ossm.DeployControlPlane(t)

t.Log("Check that smcp related webhooks were created by OLM")
checkSmcpWebhooksExist(t, "validatingwebhookconfiguration", "maistra.io/owner-name="+env.GetDefaultSMCPName())
checkSmcpWebhooksExist(t, "mutatingwebhookconfiguration", "maistra.io/owner-name="+env.GetDefaultSMCPName())

t.LogStep("Delete the SMCP")
oc.RecreateNamespace(t, meshNamespace)

t.Log("Check that smcp related webhooks were created by OLM")
checkSmcpWebhooksDoesNotExist(t, "validatingwebhookconfiguration", "maistra.io/owner-name="+env.GetDefaultSMCPName())
checkSmcpWebhooksDoesNotExist(t, "mutatingwebhookconfiguration", "maistra.io/owner-name="+env.GetDefaultSMCPName())
})
})
}

func checkGlobalWebhooks(t TestHelper, kind string, label string) {
if oc.ResourceByLabelExists(t, "", kind, label) {
t.LogSuccessf("Got the expected %s with label %s", kind, label)
} else {
t.Fatalf("Expect to find %s with label %s created automatically by OLM", kind, label)
}
}

func checkSmcpWebhooksExist(t TestHelper, kind string, label string) {
retry.UntilSuccess(t, func(t TestHelper) {
t.Logf("Check that smcp %s was created by OLM", kind)
if oc.ResourceByLabelExists(t, "", kind, label) {
t.LogSuccessf("Got the expected %s with label %s", kind, label)
} else {
t.Fatalf("Expect to find %s with label %s for smcp", kind, label)
}
})
}

func checkSmcpWebhooksDoesNotExist(t TestHelper, kind string, label string) {
retry.UntilSuccess(t, func(t TestHelper) {
t.Logf("Check that smcp %s was deleted by OLM", kind)
if oc.ResourceByLabelExists(t, "", kind, label) {
t.Fatalf("Expect to not find %s with label %s for smcp but it was found", kind, label)
} else {
t.LogSuccessf("Expect to not find %s with label %s for smcp", kind, label)
}
})
}

func deleteGlobalWebhook(t TestHelper, kind string, label string) {
name := oc.GetResouceNameByLabel(t, "", kind, label)
oc.DeleteResource(t, "", kind, name)
}
29 changes: 24 additions & 5 deletions pkg/tests/ossm/smcp_must_gather_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/maistra/maistra-test-tool/pkg/util/ns"
"github.com/maistra/maistra-test-tool/pkg/util/oc"
"github.com/maistra/maistra-test-tool/pkg/util/shell"
"github.com/maistra/maistra-test-tool/pkg/util/version"

. "github.com/maistra/maistra-test-tool/pkg/util/test"
)
Expand Down Expand Up @@ -109,11 +110,29 @@ func TestMustGather(t *testing.T) {
}

t.LogStep("Verify cluster-scoped-resources files exist in cluster-scoped-resources folder")
assertFilesExist(t,
dir,
"**/cluster-scoped-resources/rbac.authorization.k8s.io/clusterrolebindings/istiod-internal-basic-istio-system.yaml",
"**/cluster-scoped-resources/admissionregistration.k8s.io/mutatingwebhookconfigurations/openshift-operators.servicemesh-resources.maistra.io.yaml",
"**/cluster-scoped-resources/rbac.authorization.k8s.io/clusterroles/istiod-clusterrole-basic-istio-system.yaml")
if env.GetOperatorVersion().LessThan(version.OPERATOR_2_6_0) {
assertFilesExist(t,
dir,
"**/cluster-scoped-resources/rbac.authorization.k8s.io/clusterrolebindings/istiod-internal-basic-istio-system.yaml",
"**/cluster-scoped-resources/admissionregistration.k8s.io/mutatingwebhookconfigurations/openshift-operators.servicemesh-resources.maistra.io.yaml",
"**/cluster-scoped-resources/admissionregistration.k8s.io/mutatingwebhookconfigurations/istiod-basic-istio-system.yaml",
"**/cluster-scoped-resources/admissionregistration.k8s.io/validatingwebhookconfigurations/openshift-operators.servicemesh-resources.maistra.io.yaml",
"**/cluster-scoped-resources/admissionregistration.k8s.io/validatingwebhookconfigurations/istio-validator-basic-istio-system.yaml",
"**/cluster-scoped-resources/rbac.authorization.k8s.io/clusterroles/istiod-clusterrole-basic-istio-system.yaml")
} else {
assertFilesExist(t,
dir,
"**/cluster-scoped-resources/rbac.authorization.k8s.io/clusterrolebindings/istiod-internal-basic-istio-system.yaml",
//TODO uncomment when we resolve whether the olm created resources must be in must-gather imaga
// "**/cluster-scoped-resources/admissionregistration.k8s.io/mutatingwebhookconfigurations/smcp.validation.maistra.io-*.yaml",
// "**/cluster-scoped-resources/admissionregistration.k8s.io/mutatingwebhookconfigurations/smmr.validation.maistra.io-*.yaml",
"**/cluster-scoped-resources/admissionregistration.k8s.io/mutatingwebhookconfigurations/istiod-basic-istio-system.yaml",
// "**/cluster-scoped-resources/admissionregistration.k8s.io/validatingwebhookconfigurations/smcp.validation.maistra.io-*.yaml",
// "**/cluster-scoped-resources/admissionregistration.k8s.io/validatingwebhookconfigurations/smmr.validation.maistra.io-*.yaml",
// "**/cluster-scoped-resources/admissionregistration.k8s.io/validatingwebhookconfigurations/smm.validation.maistra.io-*.yaml",
"**/cluster-scoped-resources/admissionregistration.k8s.io/validatingwebhookconfigurations/istio-validator-basic-istio-system.yaml",
"**/cluster-scoped-resources/rbac.authorization.k8s.io/clusterroles/istiod-clusterrole-basic-istio-system.yaml")
}
})

t.NewSubTest("resource for namespaces exist").Run(func(t TestHelper) {
Expand Down
10 changes: 10 additions & 0 deletions pkg/util/oc/oc.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@ func DeleteResource(t test.TestHelper, ns string, kind string, name ...string) {
DefaultOC.DeleteResource(t, ns, kind, name...)
}

func GetResouceNameByLabel(t test.TestHelper, ns string, kind string, label string) string {
t.T().Helper()
return DefaultOC.GetResouceNameByLabel(t, ns, kind, label)
}

func ResourceByLabelExists(t test.TestHelper, ns string, kind string, label string) bool {
t.T().Helper()
return DefaultOC.ResourceByLabelExists(t, ns, kind, label)
}

func DeleteNamespace(t test.TestHelper, namespaces ...string) {
t.T().Helper()
DefaultOC.DeleteNamespace(t, namespaces...)
Expand Down
25 changes: 25 additions & 0 deletions pkg/util/oc/oc_struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,31 @@ func (o OC) ResourceExists(t test.TestHelper, ns, kind, name string) bool {
return exists
}

func (o OC) GetResouceNameByLabel(t test.TestHelper, ns, kind, label string) string {
t.T().Helper()
var value string
o.withKubeconfig(t, func() {
t.T().Helper()
value = shell.Execute(t, fmt.Sprintf("oc %s get %s -l %s -o custom-columns=NAME:.metadata.name --no-headers || true", nsFlag(ns), kind, label))
value = strings.TrimSpace(value)
if value == "" {
t.Fatalf("Could not find resource %s with label %s in namespace %s", kind, label, ns)
}
})
return value
}

func (o OC) ResourceByLabelExists(t test.TestHelper, ns, kind, label string) bool {
t.T().Helper()
var exists bool
o.withKubeconfig(t, func() {
t.T().Helper()
output := shell.Execute(t, fmt.Sprintf("oc %s get %s -l %s || true", nsFlag(ns), kind, label))
exists = !(strings.Contains(output, "Error from server (NotFound)") || strings.Contains(output, "No resources found"))
})
return exists
}

func setEnv(t test.TestHelper, key string, value string) {
if err := os.Setenv(key, value); err != nil {
t.Fatalf("could not set %s: %v", key, err)
Expand Down

0 comments on commit 370892c

Please sign in to comment.