diff --git a/Makefile b/Makefile index fc288423184..188e9f261cb 100644 --- a/Makefile +++ b/Makefile @@ -384,6 +384,7 @@ e2e-local: --auto-port-forwarding \ --local \ --log-verbosity=$(LOG_VERBOSITY) \ + --ignore-webhook-failures \ --test-timeout=$(TEST_TIMEOUT) @E2E_JSON=$(E2E_JSON) test/e2e/run.sh -run "$(TESTS_MATCH)" -args -testContextPath $(LOCAL_E2E_CTX) diff --git a/config/e2e/global_operator.yaml b/config/e2e/global_operator.yaml index 5e681ed7584..e5b3144b383 100644 --- a/config/e2e/global_operator.yaml +++ b/config/e2e/global_operator.yaml @@ -185,6 +185,13 @@ spec: requests: cpu: 100m memory: 20Mi + readinessProbe: + httpGet: + path: /validate-elasticsearch-k8s-elastic-co-v1-elasticsearch + port: webhook-server + scheme: HTTPS + failureThreshold: 3 + periodSeconds: 5 ports: - containerPort: 9443 name: webhook-server @@ -213,7 +220,7 @@ webhooks: namespace: {{ .GlobalOperator.Namespace }} # this is the path controller-runtime automatically generates path: /validate-elasticsearch-k8s-elastic-co-v1beta1-elasticsearch - failurePolicy: Ignore + failurePolicy: {{ if .IgnoreWebhookFailures }}Ignore{{ else }}Fail{{ end }} name: elastic-es-validation.k8s.elastic.co rules: - apiGroups: @@ -232,7 +239,7 @@ webhooks: namespace: {{ .GlobalOperator.Namespace }} # this is the path controller-runtime automatically generates path: /validate-elasticsearch-k8s-elastic-co-v1-elasticsearch - failurePolicy: Ignore + failurePolicy: {{ if .IgnoreWebhookFailures }}Ignore{{ else }}Fail{{ end }} name: elastic-es-validation.k8s.elastic.co rules: - apiGroups: @@ -255,4 +262,4 @@ spec: - port: 443 targetPort: 9443 selector: - control-plane: elastic-operator + control-plane: {{ .GlobalOperator.Name }} diff --git a/test/e2e/cmd/run/command.go b/test/e2e/cmd/run/command.go index 6db2dc57469..8b615ef1553 100644 --- a/test/e2e/cmd/run/command.go +++ b/test/e2e/cmd/run/command.go @@ -20,23 +20,24 @@ import ( ) type runFlags struct { - managedNamespaces []string - e2eImage string - elasticStackVersion string - kubeConfig string - operatorImage string - testContextOutPath string - testLicense string - scratchDirRoot string - testRegex string - testRunName string - commandTimeout time.Duration - autoPortForwarding bool - skipCleanup bool - local bool - logToFile bool - logVerbosity int - testTimeout time.Duration + managedNamespaces []string + e2eImage string + elasticStackVersion string + kubeConfig string + operatorImage string + testContextOutPath string + testLicense string + scratchDirRoot string + testRegex string + testRunName string + commandTimeout time.Duration + autoPortForwarding bool + skipCleanup bool + local bool + logToFile bool + ignoreWebhookFailures bool + logVerbosity int + testTimeout time.Duration } var log logr.Logger @@ -78,6 +79,7 @@ func Command() *cobra.Command { cmd.Flags().StringVar(&flags.testRunName, "test-run-name", randomTestRunName(), "Name of this test run") cmd.Flags().DurationVar(&flags.testTimeout, "test-timeout", 5*time.Minute, "Timeout before failing a test") cmd.Flags().BoolVar(&flags.logToFile, "log-to-file", false, "Specifies if should log test output to file. Disabled by default.") + cmd.Flags().BoolVar(&flags.ignoreWebhookFailures, "ignore-webhook-failures", false, "Specifies if webhook errors should be ignored. Useful when running test locally. False by default") logutil.BindFlags(cmd.PersistentFlags()) // enable setting flags via environment variables diff --git a/test/e2e/cmd/run/run.go b/test/e2e/cmd/run/run.go index 5bf835f9ca6..c42b45f5c6c 100644 --- a/test/e2e/cmd/run/run.go +++ b/test/e2e/cmd/run/run.go @@ -141,11 +141,12 @@ func (h *helper) initTestContext() error { }, ManagedNamespaces: make([]string, len(h.managedNamespaces)), }, - OperatorImage: h.operatorImage, - TestLicense: h.testLicense, - TestRegex: h.testRegex, - TestRun: h.testRunName, - TestTimeout: h.testTimeout, + OperatorImage: h.operatorImage, + TestLicense: h.testLicense, + TestRegex: h.testRegex, + TestRun: h.testRunName, + TestTimeout: h.testTimeout, + IgnoreWebhookFailures: h.ignoreWebhookFailures, } for i, ns := range h.managedNamespaces { diff --git a/test/e2e/es/naming_test.go b/test/e2e/es/naming_test.go index 7f71f6a8d75..e35243cc591 100644 --- a/test/e2e/es/naming_test.go +++ b/test/e2e/es/naming_test.go @@ -104,7 +104,7 @@ func testRejectionOfLongName(t *testing.T) { err := k.Client.Create(obj) if err != nil { // validating webhook is active and rejected the request - require.Contains(t, err.Error(), `admission webhook "validation.elasticsearch.elastic.co" denied the request`) + require.Contains(t, err.Error(), `admission webhook "elastic-es-validation.k8s.elastic.co" denied the request`) return } diff --git a/test/e2e/test/context.go b/test/e2e/test/context.go index 8714d487992..601ec9e068e 100644 --- a/test/e2e/test/context.go +++ b/test/e2e/test/context.go @@ -61,8 +61,9 @@ func initializeContext() { func defaultContext() Context { return Context{ - AutoPortForwarding: false, - ElasticStackVersion: defaultElasticStackVersion, + AutoPortForwarding: false, + ElasticStackVersion: defaultElasticStackVersion, + IgnoreWebhookFailures: false, GlobalOperator: ClusterResource{ Name: "elastic-global-operator", Namespace: "elastic-system", @@ -80,20 +81,21 @@ func defaultContext() Context { // Context encapsulates data about a specific test run type Context struct { - GlobalOperator ClusterResource `json:"global_operator"` - NamespaceOperator NamespaceOperator `json:"namespace_operator"` - E2EImage string `json:"e2e_image"` - E2ENamespace string `json:"e2e_namespace"` - E2EServiceAccount string `json:"e2e_service_account"` - ElasticStackVersion string `json:"elastic_stack_version"` - LogVerbosity int `json:"log_verbosity"` - OperatorImage string `json:"operator_image"` - TestLicense string `json:"test_license"` - TestRegex string `json:"test_regex"` - TestRun string `json:"test_run"` - TestTimeout time.Duration `json:"test_timeout"` - AutoPortForwarding bool `json:"auto_port_forwarding"` - Local bool `json:"local"` + GlobalOperator ClusterResource `json:"global_operator"` + NamespaceOperator NamespaceOperator `json:"namespace_operator"` + E2EImage string `json:"e2e_image"` + E2ENamespace string `json:"e2e_namespace"` + E2EServiceAccount string `json:"e2e_service_account"` + ElasticStackVersion string `json:"elastic_stack_version"` + LogVerbosity int `json:"log_verbosity"` + OperatorImage string `json:"operator_image"` + TestLicense string `json:"test_license"` + TestRegex string `json:"test_regex"` + TestRun string `json:"test_run"` + TestTimeout time.Duration `json:"test_timeout"` + AutoPortForwarding bool `json:"auto_port_forwarding"` + Local bool `json:"local"` + IgnoreWebhookFailures bool `json:"ignore_webhook_failures"` } // ManagedNamespace returns the nth managed namespace. diff --git a/test/e2e/test/elasticsearch/steps_init.go b/test/e2e/test/elasticsearch/steps_init.go index 77426fbffe6..a9098a75961 100644 --- a/test/e2e/test/elasticsearch/steps_init.go +++ b/test/e2e/test/elasticsearch/steps_init.go @@ -9,12 +9,14 @@ import ( "testing" esv1 "github.com/elastic/cloud-on-k8s/pkg/apis/elasticsearch/v1" + "github.com/elastic/cloud-on-k8s/pkg/controller/webhook" "github.com/elastic/cloud-on-k8s/pkg/utils/k8s" "github.com/elastic/cloud-on-k8s/test/e2e/test" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" ) // InitTestSteps includes pre-requisite tests (eg. is k8s accessible), @@ -29,7 +31,6 @@ func (b Builder) InitTestSteps(k *test.K8sClient) test.StepList { require.NoError(t, err) }, }, - { Name: "Elasticsearch CRDs should exist", Test: func(t *testing.T) { @@ -42,7 +43,29 @@ func (b Builder) InitTestSteps(k *test.K8sClient) test.StepList { } }, }, - + { + Name: "Webhook endpoint should not be empty", + Test: test.Eventually(func() error { + if test.Ctx().IgnoreWebhookFailures { + return nil + } + webhookEndpoints := &corev1.Endpoints{} + if err := k.Client.Get(types.NamespacedName{ + Namespace: test.Ctx().GlobalOperator.Namespace, + Name: webhook.WebhookServiceName, + }, webhookEndpoints); err != nil { + return err + } + if len(webhookEndpoints.Subsets) == 0 { + return fmt.Errorf( + "endpoint %s/%s is empty", + webhookEndpoints.Namespace, + webhookEndpoints.Name, + ) + } + return nil + }), + }, { Name: "Remove Elasticsearch if it already exists", Test: func(t *testing.T) {