From 959d2a8243d8ed284e70da9144b2ab164d4270c4 Mon Sep 17 00:00:00 2001 From: Jing Qi Date: Tue, 4 Jul 2023 10:10:52 +0800 Subject: [PATCH] Add appstudio redhat nstemplatetier Signed-off-by: Jing Qi --- test/e2e/nstemplatetier_test.go | 2 +- testsupport/tiers/checks.go | 458 ++++++++++++++++++++++++++++++++ testsupport/wait/member.go | 26 ++ 3 files changed, 485 insertions(+), 1 deletion(-) diff --git a/test/e2e/nstemplatetier_test.go b/test/e2e/nstemplatetier_test.go index adae4c754..c16d5637e 100644 --- a/test/e2e/nstemplatetier_test.go +++ b/test/e2e/nstemplatetier_test.go @@ -43,7 +43,7 @@ func TestNSTemplateTiers(t *testing.T) { Resources() // all tiers to check - keep the base as the last one, it will verify downgrade back to the default tier at the end of the test - tiersToCheck := []string{"advanced", "baseextendedidling", "baselarge", "test", "appstudio", "appstudio-env", "base1ns", "base1nsnoidling", "base1ns6didler", "base"} + tiersToCheck := []string{"advanced", "baseextendedidling", "baselarge", "test", "appstudio", "appstudio-redhat", "appstudio-env", "base1ns", "base1nsnoidling", "base1ns6didler", "base"} // when the tiers are created during the startup then we can verify them allTiers := &toolchainv1alpha1.NSTemplateTierList{} diff --git a/testsupport/tiers/checks.go b/testsupport/tiers/checks.go index c1619496c..9d7493f58 100644 --- a/testsupport/tiers/checks.go +++ b/testsupport/tiers/checks.go @@ -8,6 +8,7 @@ import ( "testing" toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" + esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1" "github.com/codeready-toolchain/toolchain-e2e/testsupport/wait" "github.com/davecgh/go-spew/spew" @@ -27,6 +28,7 @@ const ( // tier names advanced = "advanced" appstudio = "appstudio" + appstudioRedhat = "appstudio-redhat" appstudioEnv = "appstudio-env" base = "base" base1ns = "base1ns" @@ -78,6 +80,9 @@ func NewChecksForTier(tier *toolchainv1alpha1.NSTemplateTier) (TierChecks, error case appstudio: return &appstudioTierChecks{tierName: appstudio}, nil + case appstudioRedhat: + return &appstudioRedhatTierChecks{tierName: appstudio-redhat}, nil + case appstudioEnv: return &appstudioEnvTierChecks{tierName: appstudioEnv}, nil @@ -382,6 +387,12 @@ func commonNetworkPolicyChecks() []namespaceObjectsCheck { } } +func externalSecretChecks() []namespaceObjectsCheck { + return []namespaceObjectsCheck{ + externalSecretSnykSharedToken(), + } +} + type advancedTierChecks struct { baseTierChecks } @@ -531,6 +542,107 @@ func (a *appstudioTierChecks) GetClusterObjectChecks() []clusterObjectsCheck { pipelineRunnerClusterRole()) } +type appstudioRedhatTierChecks struct { + tierName string +} + +func (a *appstudioRedhatTierChecks) GetNamespaceObjectChecks(_ string) []namespaceObjectsCheck { + checks := []namespaceObjectsCheck{ + resourceQuotaComputeDeploy("20", "32Gi", "1750m", "32Gi"), + resourceQuotaComputeBuild("60", "64Gi", "6", "32Gi"), + resourceQuotaStorage("50Gi", "50Gi", "50Gi", "12"), + limitRange("2", "2Gi", "10m", "256Mi"), + numberOfLimitRanges(1), + toolchainSaReadRole(), + memberOperatorSaReadRoleBinding(), + gitOpsServiceLabel(), + redhatInternalTenantLabel(), + appstudioWorkSpaceNameLabel(), + environment("development"), + resourceQuotaAppstudioCrds("512", "512", "512"), + resourceQuotaAppstudioCrdsBuild("512"), + resourceQuotaAppstudioCrdsGitops("512", "512", "512", "512", "512"), + resourceQuotaAppstudioCrdsIntegration("512", "512", "512"), + resourceQuotaAppstudioCrdsRelease("512", "512", "512", "512", "512"), + resourceQuotaAppstudioCrdsEnterpriseContract("512"), + resourceQuotaAppstudioCrdsSPI("512", "512", "512", "512", "512"), + pipelineServiceAccount(), + pipelineRunnerRoleBinding(), + } + + checks = append(checks, append(commonNetworkPolicyChecks(), externalSecretChecks(), networkPolicyAllowFromCRW(), numberOfNetworkPolicies(6))...) + return checks +} + +func (a *appstudioRedhatTierChecks) GetSpaceRoleChecks(spaceRoles map[string][]string) ([]spaceRoleObjectsCheck, error) { + checks := []spaceRoleObjectsCheck{} + roles := 0 + rolebindings := 0 + for role, usernames := range spaceRoles { + switch role { + case "admin": + checks = append(checks, appstudioRedhatUserActionsRole()) + roles++ + for _, userName := range usernames { + checks = append(checks, + appstudioRedhatUserActionsRoleBinding(userName, "admin"), + appstudioViewRoleBinding(userName), + ) + rolebindings += 2 + } + case "maintainer": + checks = append(checks, appstudioRedhatMaintainerUserActionsRole()) + roles++ + for _, userName := range usernames { + checks = append(checks, + appstudioRedhatUserActionsRoleBinding(userName, "maintainer"), + appstudioViewRoleBinding(userName), + ) + rolebindings += 2 + } + case "contributor": + checks = append(checks, appstudioRedhatContributorUserActionsRole()) + roles++ + for _, userName := range usernames { + checks = append(checks, + appstudioRedhatUserActionsRoleBinding(userName, "contributor"), + appstudioViewRoleBinding(userName), + ) + rolebindings += 2 + } + default: + return nil, fmt.Errorf("unexpected template name: '%s'", role) + } + } + // also count the roles, rolebindings and service accounts + checks = append(checks, + numberOfToolchainRoles(roles+1), // +1 for `toolchain-sa-read` + numberOfToolchainRoleBindings(rolebindings+2), // +2 for `member-operator-sa-read` and `appstudio-pipelines-runner-rolebinding` + ) + return checks, nil +} + +func (a *appstudioRedhatTierChecks) GetExpectedTemplateRefs(t *testing.T, hostAwait *wait.HostAwaitility) TemplateRefs { + templateRefs := GetTemplateRefs(t, hostAwait, a.tierName) + verifyNsTypes(t, a.tierName, templateRefs, "tenant") + return templateRefs +} + +func (a *appstudioRedhatTierChecks) GetClusterObjectChecks() []clusterObjectsCheck { + return clusterObjectsChecks( + clusterResourceQuotaDeployments("150"), + clusterResourceQuotaReplicas(), + clusterResourceQuotaRoutes(), + clusterResourceQuotaJobs(), + clusterResourceQuotaServices(), + clusterResourceQuotaBuildConfig(), + clusterResourceQuotaSecrets(), + clusterResourceQuotaConfigMap(), + numberOfClusterResourceQuotas(8), + idlers(0, ""), + pipelineRunnerClusterRole()) +} + type appstudioEnvTierChecks struct { tierName string } @@ -542,6 +654,7 @@ func (a *appstudioEnvTierChecks) GetNamespaceObjectChecks(_ string) []namespaceO resourceQuotaStorage("50Gi", "50Gi", "50Gi", "12"), limitRange("2", "2Gi", "10m", "256Mi"), numberOfLimitRanges(1), + additionalArgocdReadRole(), namespaceManagerSA(), additionalArgocdReadRole(), namespaceManagerSaAdditionalArgocdReadRoleBinding(), @@ -957,6 +1070,38 @@ func limitRange(cpuLimit, memoryLimit, cpuRequest, memoryRequest string) namespa } } +func externalSecretSnykSharedToken() namespaceObjectsCheck { + return func(t *testing.T, ns *corev1.Namespace, memberAwait *wait.MemberAwaitility, userName string) { + es, err := memberAwait.WaitForExternalSecret(t, ns, "snyk-shared-token") + require.NoError(t, err) + assert.Equal(t, toolchainv1alpha1.ProviderLabelValue, es.ObjectMeta.Labels[toolchainv1alpha1.ProviderLabelKey]) + expected := &esv1beta1.ExternalSecret{ + Annotations: map[string]string{ + "argocd.argoproj.io/sync-options": "SkipDryRunOnMissingResource=true", + "argocd.argoproj.io/sync-wave": "-1", + }, + }, + Spec: esv1beta1.ExternalSecretSpec{ + DataFrom: []esv1beta1.ExternalSecretDataFromRemoteRef{ + { + Extract: &esv1beta1.ExternalSecretDataRemoteRef{ + Key: "snyk-shared-secret", + }, + }, + }, + SecretStoreRef: esv1beta1.SecretStoreRef{ + Name: "appsre-redhat-tenant-vault", + }, + Target: esv1beta1.ExternalSecretTarget{ + Name: "snyk-secret", + }, + }, + } + + assert.Equal(t, expected.Spec, es.Spec) + } +} + func networkPolicySameNamespace() namespaceObjectsCheck { return func(t *testing.T, ns *corev1.Namespace, memberAwait *wait.MemberAwaitility, userName string) { np, err := memberAwait.WaitForNetworkPolicy(t, ns, "allow-same-namespace") @@ -1314,6 +1459,8 @@ func clusterResourceQuotaMatches(userName, tierName string, hard map[corev1.Reso MatchLabels: map[string]string{ toolchainv1alpha1.SpaceLabelKey: userName, }, + AnnotationSelector: map[string]string{ + "openshift.io/requester": userName, }, }, Quota: corev1.ResourceQuotaSpec{ @@ -1456,6 +1603,17 @@ func appstudioWorkSpaceNameLabel() namespaceObjectsCheck { } } +func redhatInternalTenantLabel() namespaceObjectsCheck { + return func(t *testing.T, ns *corev1.Namespace, memberAwait *wait.MemberAwaitility, owner string) { + + labelWaitCriterion := []wait.LabelWaitCriterion{} + labelWaitCriterion = append(labelWaitCriterion, wait.UntilObjectHasLabel("redhat-internal-tenent/label", "true")) + + _, err := memberAwait.WaitForNamespaceWithName(t, ns.Name, labelWaitCriterion...) + require.NoError(t, err) + } +} + func environment(name string) namespaceObjectsCheck { return func(t *testing.T, ns *corev1.Namespace, memberAwait *wait.MemberAwaitility, owner string) { _, err := memberAwait.WaitForEnvironment(t, ns.Name, name, toolchainLabelsWaitCriterion(owner)...) @@ -1548,6 +1706,97 @@ func appstudioUserActionsRole() spaceRoleObjectsCheck { } } +func appstudioRedhatUserActionsRole() spaceRoleObjectsCheck { + return func(t *testing.T, ns *corev1.Namespace, memberAwait *wait.MemberAwaitility, owner string) { + role, err := memberAwait.WaitForRole(t, ns, "appstudio-redhat-user-actions", toolchainLabelsWaitCriterion(owner)...) + require.NoError(t, err) + assert.Len(t, role.Rules, 15) + expected := &rbacv1.Role{ + Rules: []rbacv1.PolicyRule{ + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"applications", "components", "componentdetectionqueries"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"promotionruns", "snapshotenvironmentbindings", "snapshots", "environments"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"deploymenttargets", "deploymenttargetclaims"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{"managed-gitops.redhat.com"}, + Resources: []string{"gitopsdeployments", "gitopsdeploymentmanagedenvironments", "gitopsdeploymentrepositorycredentials", "gitopsdeploymentsyncruns"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"tekton.dev"}, + Resources: []string{"pipelineruns"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{"results.tekton.dev"}, + Resources: []string{"results", "records", "logs"}, + Verbs: []string{"get", "list"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"enterprisecontractpolicies", "integrationtestscenarios", "releases", "releasestrategies", "releaseplans", "releaseplanadmissions"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{"jvmbuildservice.io"}, + Resources: []string{"jbsconfigs", "artifactbuilds"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"spiaccesstokenbindings", "spiaccesschecks", "spiaccesstokens", "spifilecontentrequests", "spiaccesstokendataupdates"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"remotesecrets"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"secrets"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"configmaps"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"buildpipelineselectors"}, + Verbs: []string{"get", "list", "watch", "create", "update", "patch", "delete"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"serviceaccounts"}, + ResourceNames: []string{"appstudio-pipeline"}, + Verbs: []string{"get", "list", "watch", "update", "patch"}, + }, + { + APIGroups: []string{"external-secrets.io"}, + Resources: []string{"externalsecrets"}, + ResourceNames: []string{"snyk-shared-token"}, + Verbs: []string{"get", "list"}, + }, + }, + } + + assert.Equal(t, expected.Rules, role.Rules) + } +} + func appstudioMaintainerUserActionsRole() spaceRoleObjectsCheck { return func(t *testing.T, ns *corev1.Namespace, memberAwait *wait.MemberAwaitility, owner string) { role, err := memberAwait.WaitForRole(t, ns, "appstudio-maintainer-user-actions", toolchainLabelsWaitCriterion(owner)...) @@ -1633,6 +1882,100 @@ func appstudioMaintainerUserActionsRole() spaceRoleObjectsCheck { }, } + assert.Equal(t, expected.Rules, role.Rules) + } + +func appstudioRedhatMaintainerUserActionsRole() spaceRoleObjectsCheck { + return func(t *testing.T, ns *corev1.Namespace, memberAwait *wait.MemberAwaitility, owner string) { + role, err := memberAwait.WaitForRole(t, ns, "appstudio-redhat-maintainer-user-actions", toolchainLabelsWaitCriterion(owner)...) + require.NoError(t, err) + assert.Len(t, role.Rules, 16) + expected := &rbacv1.Role{ + Rules: []rbacv1.PolicyRule{ + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"applications", "components", "componentdetectionqueries"}, + Verbs: []string{"get", "list", "watch", "create", "update", "patch"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"promotionruns", "snapshotenvironmentbindings", "snapshots", "environments"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"deploymenttargets", "deploymenttargetclaims"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"managed-gitops.redhat.com"}, + Resources: []string{"gitopsdeployments", "gitopsdeploymentmanagedenvironments", "gitopsdeploymentrepositorycredentials", "gitopsdeploymentsyncruns"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"tekton.dev"}, + Resources: []string{"pipelineruns"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"results.tekton.dev"}, + Resources: []string{"results", "records", "logs"}, + Verbs: []string{"get", "list"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"integrationtestscenarios"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"enterprisecontractpolicies"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"releases", "releasestrategies", "releaseplans"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"releaseplanadmissions"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{"jvmbuildservice.io"}, + Resources: []string{"jbsconfigs", "artifactbuilds"}, + Verbs: []string{"get", "list", "watch", "create", "update", "patch"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"spiaccesstokenbindings", "spiaccesschecks", "spiaccesstokens", "spifilecontentrequests", "spiaccesstokendataupdates"}, + Verbs: []string{"get", "list", "watch", "create", "update", "patch"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"remotesecrets"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"configmaps"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"buildpipelineselectors"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"external-secrets.io"}, + Resources: []string{"externalsecrets"}, + ResourceNames: []string{"snyk-shared-token"}, + Verbs: []string{"get", "list"}, + }, + }, + } + assert.Equal(t, expected.Rules, role.Rules) } } @@ -1722,6 +2065,100 @@ func appstudioContributorUserActionsRole() spaceRoleObjectsCheck { }, } + assert.Equal(t, expected.Rules, role.Rules) + } + +func appstudioRedhatContributorUserActionsRole() spaceRoleObjectsCheck { + return func(t *testing.T, ns *corev1.Namespace, memberAwait *wait.MemberAwaitility, owner string) { + role, err := memberAwait.WaitForRole(t, ns, "appstudio-redhat-contributor-user-actions", toolchainLabelsWaitCriterion(owner)...) + require.NoError(t, err) + assert.Len(t, role.Rules, 15) + expected := &rbacv1.Role{ + Rules: []rbacv1.PolicyRule{ + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"applications", "components", "componentdetectionqueries"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"promotionruns", "snapshotenvironmentbindings", "snapshots", "environments"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"deploymenttargets", "deploymenttargetclaims"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"managed-gitops.redhat.com"}, + Resources: []string{"gitopsdeployments", "gitopsdeploymentmanagedenvironments", "gitopsdeploymentrepositorycredentials", "gitopsdeploymentsyncruns"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"tekton.dev"}, + Resources: []string{"pipelineruns"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"results.tekton.dev"}, + Resources: []string{"results", "records", "logs"}, + Verbs: []string{"get", "list"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"integrationtestscenarios"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"enterprisecontractpolicies"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"releases", "releasestrategies", "releaseplans"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"releaseplanadmissions"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"jvmbuildservice.io"}, + Resources: []string{"jbsconfigs", "artifactbuilds"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"spiaccesstokenbindings", "spiaccesschecks", "spiaccesstokens", "spifilecontentrequests"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"remotesecrets"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"configmaps"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"appstudio.redhat.com"}, + Resources: []string{"buildpipelineselectors"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"external-secrets.io"}, + Resources: []string{"externalsecrets"}, + ResourceNames: []string{"snyk-shared-token"}, + Verbs: []string{"get", "list"}, + }, + }, + } + assert.Equal(t, expected.Rules, role.Rules) } } @@ -1746,6 +2183,27 @@ func appstudioUserActionsRoleBinding(userName string, role string) spaceRoleObje assert.Equal(t, "Role", rb.RoleRef.Kind) assert.Equal(t, "rbac.authorization.k8s.io", rb.RoleRef.APIGroup) } + +func appstudioRedhatUserActionsRoleBinding(userName string, role string) spaceRoleObjectsCheck { + return func(t *testing.T, ns *corev1.Namespace, memberAwait *wait.MemberAwaitility, owner string) { + rbName := "" + roleName := "" + if role == "admin" { + roleName = "appstudio-redhat-user-actions" + rbName = fmt.Sprintf("appstudio-redhat-%s-actions-user", userName) + } else { + roleName = fmt.Sprintf("appstudio-redhat-%s-user-actions", role) + rbName = fmt.Sprintf("appstudio-redhat-%s-%s-actions-user", role, userName) + } + rb, err := memberAwait.WaitForRoleBinding(t, ns, rbName, toolchainLabelsWaitCriterion(owner)...) + require.NoError(t, err) + assert.Len(t, rb.Subjects, 1) + assert.Equal(t, "User", rb.Subjects[0].Kind) + assert.Equal(t, userName, rb.Subjects[0].Name) + assert.Equal(t, roleName, rb.RoleRef.Name) + assert.Equal(t, "Role", rb.RoleRef.Kind) + assert.Equal(t, "rbac.authorization.k8s.io", rb.RoleRef.APIGroup) + } } func appstudioViewRoleBinding(userName string) spaceRoleObjectsCheck { diff --git a/testsupport/wait/member.go b/testsupport/wait/member.go index 5999f46e2..3aed03779 100644 --- a/testsupport/wait/member.go +++ b/testsupport/wait/member.go @@ -12,6 +12,7 @@ import ( "github.com/codeready-toolchain/toolchain-common/pkg/cluster" "github.com/codeready-toolchain/toolchain-common/pkg/test" appstudiov1 "github.com/codeready-toolchain/toolchain-e2e/testsupport/appstudio/api/v1alpha1" + esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1" "github.com/davecgh/go-spew/spew" "github.com/ghodss/yaml" quotav1 "github.com/openshift/api/quota/v1" @@ -936,6 +937,31 @@ func (a *MemberAwaitility) WaitForNetworkPolicy(t *testing.T, namespace *corev1. return np, err } +// WaitForExternalSecret waits until a ExternalSecret with the given name exists in the given namespace +func (a *MemberAwaitility) WaitForExternalSecret(t *testing.T, namespace *corev1.Namespace, name string) (*esv1beta1.ExternalSecret, error) { + t.Logf("waiting for ExternalSecret '%s' in namespace '%s'", name, namespace.Name) + es := &esv1beta1.ExternalSecret{} + err := wait.Poll(a.RetryInterval, a.Timeout, func() (done bool, err error) { + obj := &esv1beta1.ExternalSecret{} + if err := a.Client.Get(context.TODO(), types.NamespacedName{Namespace: namespace.Name, Name: name}, obj); err != nil { + if errors.IsNotFound(err) { + allESs := &esv1beta1.ExternalSecretList{} + if err := a.Client.List(context.TODO(), allESs, client.InNamespace(namespace)); err != nil { + return false, err + } + return false, nil + } + return false, err + } + es = obj + return true, nil + }) + if err != nil { + t.Logf("failed to wait for ExternalSecret '%s' in namespace '%s'", name, namespace.Name) + } + return es, err +} + // WaitForRole waits until a Role with the given name exists in the given namespace func (a *MemberAwaitility) WaitForRole(t *testing.T, namespace *corev1.Namespace, name string, criteria ...LabelWaitCriterion) (*rbacv1.Role, error) { t.Logf("waiting for Role '%s' in namespace '%s'", name, namespace.Name)