Skip to content

Commit

Permalink
Added basic logstash verification
Browse files Browse the repository at this point in the history
Add a test to make sure that Logstash is running, by testing the metrics API endpoint
and checking that the value of status is "green"
  • Loading branch information
robbavey committed Feb 16, 2023
1 parent 4e73a41 commit 5713bb4
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 3 deletions.
2 changes: 1 addition & 1 deletion docs/reference/api-docs.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -1876,7 +1876,7 @@ LogstashSpec defines the desired state of Logstash
| *`image`* __string__ | Image is the Logstash Docker image to deploy. Version and Type have to match the Logstash in the image.
| *`config`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-config[$$Config$$]__ | Config holds the Logstash configuration. At most one of [`Config`, `ConfigRef`] can be specified.
| *`configRef`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-configsource[$$ConfigSource$$]__ | ConfigRef contains a reference to an existing Kubernetes Secret holding the Logstash configuration. Logstash settings must be specified as yaml, under a single "logstash.yml" entry. At most one of [`Config`, `ConfigRef`] can be specified.
| *`http`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-httpconfig[$$HTTPConfig$$]__ | HTTP holds the HTTP layer configuration for the Logstash Metrics API
| *`http`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-httpconfig[$$HTTPConfig$$]__ | HTTP holds the HTTP layer configuration for the Logstash Metrics API TODO: This should likely be changed to a more general `Services LogstashService[]`, where `LogstashService` looks a lot like `HTTPConfig`, but is applicable for more than just an HTTP endpoint, as logstash may need to be opened up for other services: beats, TCP, UDP, etc, inputs
| *`podTemplate`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#podtemplatespec-v1-core[$$PodTemplateSpec$$]__ | PodTemplate provides customisation options for the Logstash pods.
| *`revisionHistoryLimit`* __integer__ | RevisionHistoryLimit is the number of revisions to retain to allow rollback in the underlying StatefulSet.
| *`secureSettings`* __xref:{anchor_prefix}-github-com-elastic-cloud-on-k8s-v2-pkg-apis-common-v1-secretsource[$$SecretSource$$] array__ | SecureSettings is a list of references to Kubernetes Secrets containing sensitive configuration options for the Logstash. Secrets data can be then referenced in the Logstash config using the Secret's keys or as specified in `Entries` field of each SecureSetting.
Expand Down
32 changes: 30 additions & 2 deletions test/e2e/test/logstash/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@ package logstash

import (
"context"
"encoding/json"
"fmt"

logstashv1alpha1 "github.com/elastic/cloud-on-k8s/v2/pkg/apis/logstash/v1alpha1"
"github.com/elastic/cloud-on-k8s/v2/pkg/utils/k8s"
"github.com/elastic/cloud-on-k8s/v2/test/e2e/test"
)

type logstashStatus struct {
Version string `json:"version"`
Status string `json:"status"`
}

// CheckSecrets checks that expected secrets have been created.
func CheckSecrets(b Builder, k *test.K8sClient) test.Step {
return test.CheckSecretsContent(k, b.Logstash.Namespace, func() []test.ExpectedSecret {
Expand Down Expand Up @@ -58,6 +64,28 @@ func CheckStatus(b Builder, k *test.K8sClient) test.Step {

func (b Builder) CheckStackTestSteps(k *test.K8sClient) test.StepList {
println(test.Ctx().TestTimeout)
// TODO: Add stack checks
return test.StepList{}
return test.StepList{
{
Name: "Logstash should respond to requests",
Test: test.Eventually(func() error {
client, err := NewLogstashClient(b.Logstash, k)
if err != nil {
return err
}
bytes, err := DoRequest(client, b.Logstash, "GET", "/")
if err != nil {
return err
}
var status logstashStatus
if err := json.Unmarshal(bytes, &status); err != nil {
return err
}

if status.Status != "green" {
return fmt.Errorf("expected green but got %s", status.Status)
}
return nil
}),
},
}
}
67 changes: 67 additions & 0 deletions test/e2e/test/logstash/http_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License 2.0;
// you may not use this file except in compliance with the Elastic License 2.0.

package logstash

import (
"context"
"crypto/x509"
"fmt"
"io"
"net/http"
"net/url"

"github.com/elastic/cloud-on-k8s/v2/pkg/apis/logstash/v1alpha1"
// "github.com/elastic/cloud-on-k8s/v2/pkg/controller/logstash"
"github.com/elastic/cloud-on-k8s/v2/test/e2e/test"
)

type APIError struct {
StatusCode int
msg string
}

func (e *APIError) Error() string {
return e.msg
}

// TODO refactor identical to Kibana client
func NewLogstashClient(logstash v1alpha1.Logstash, k *test.K8sClient) (*http.Client, error) {
var caCerts []*x509.Certificate
// if ems.Spec.HTTP.TLS.Enabled() {
// crts, err := k.GetHTTPCerts(maps.EMSNamer, ems.Namespace, ems.Name)
// if err != nil {
// return nil, err
// }
// caCerts = crts
//}
return test.NewHTTPClient(caCerts), nil
}

func DoRequest(client *http.Client, logstash v1alpha1.Logstash, method, path string) ([]byte, error) {
scheme := "http"

url, err := url.Parse(fmt.Sprintf("%s://%s.%s.svc:9600%s", scheme, v1alpha1.HTTPServiceName(logstash.Name), logstash.Namespace, path))
if err != nil {
return nil, fmt.Errorf("while parsing URL: %w", err)
}

request, err := http.NewRequestWithContext(context.Background(), method, url.String(), nil)
if err != nil {
return nil, fmt.Errorf("while constructing request: %w", err)
}

resp, err := client.Do(request)
if err != nil {
return nil, fmt.Errorf("while making request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode > 299 {
return nil, &APIError{
StatusCode: resp.StatusCode,
msg: fmt.Sprintf("fail to request %s, status is %d)", path, resp.StatusCode),
}
}
return io.ReadAll(resp.Body)
}

0 comments on commit 5713bb4

Please sign in to comment.