From adcd81a26116f083d522d708b63c3a78737812b1 Mon Sep 17 00:00:00 2001 From: jetzlstorfer Date: Mon, 5 Oct 2020 11:04:39 +0200 Subject: [PATCH 1/7] small fixes --- eventhandlers.go | 1 - test-events/deployment-finished.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/eventhandlers.go b/eventhandlers.go index c90ad7c..467d675 100644 --- a/eventhandlers.go +++ b/eventhandlers.go @@ -90,7 +90,6 @@ func HandleDeploymentFinishedEvent(myKeptn *keptn.Keptn, incomingEvent cloudeven break } chaosStatus = strings.Trim(chaosStatus, `'"`) - log.Println("status: " + chaosStatus) // interval before we check the chaosengine status again time.Sleep(2 * time.Second) } diff --git a/test-events/deployment-finished.json b/test-events/deployment-finished.json index 3fa260c..c96a365 100644 --- a/test-events/deployment-finished.json +++ b/test-events/deployment-finished.json @@ -15,7 +15,7 @@ "image": "docker.io/keptnexamples/carts", "labels": { "testid": "12345", - "buildnr": "build17", + "buildId": "build17", "runby": "JohnDoe" }, "deploymentURILocal": "http://carts.litmus-chaos.svc.cluster.local", From 9036e1171eb9370cb3ee72518ac329c7b6994a04 Mon Sep 17 00:00:00 2001 From: jetzlstorfer Date: Fri, 9 Oct 2020 12:33:00 +0200 Subject: [PATCH 2/7] fix reviewdog --- .github/workflows/reviewdog.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index 396cc0b..747e03f 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -5,15 +5,24 @@ jobs: name: reviewdog runs-on: ubuntu-latest steps: + - name: Set up Go + uses: actions/setup-go@v1 + with: + go-version: 1.13 + id: go + - name: Add $GOPATH/bin + run: | + echo ::add-path::$(go env GOPATH)/bin - name: Check out code. uses: actions/checkout@v1 + - name: Install linters + run: '( mkdir linters && cd linters && go get golang.org/x/lint/golint )' - name: Setup reviewdog run: | mkdir -p $HOME/bin && curl -sfL https://raw.githubusercontent.com/reviewdog/reviewdog/master/install.sh| sh -s -- -b $HOME/bin echo ::add-path::$HOME/bin - echo ::add-path::$(go env GOPATH)/bin # for Go projects - name: Run reviewdog env: REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - reviewdog -reporter=github-pr-review + reviewdog -reporter=github-pr-review \ No newline at end of file From 649411e705719d22883db0fa7d65ccdc2796020b Mon Sep 17 00:00:00 2001 From: jetzlstorfer Date: Fri, 9 Oct 2020 12:33:18 +0200 Subject: [PATCH 3/7] control event workflow with env variable --- deploy/service.yaml | 2 ++ eventhandlers.go | 14 +++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/deploy/service.yaml b/deploy/service.yaml index e4892f3..1e0cde6 100644 --- a/deploy/service.yaml +++ b/deploy/service.yaml @@ -65,6 +65,8 @@ spec: value: 'http://event-broker.keptn.svc.cluster.local/keptn' - name: CONFIGURATION_SERVICE value: 'http://configuration-service.keptn.svc.cluster.local:8080' + - name: SEND_TEST_FINISHED_EVENT + value: false - name: distributor image: keptn/distributor:0.7.1 livenessProbe: diff --git a/eventhandlers.go b/eventhandlers.go index 467d675..b6974ac 100644 --- a/eventhandlers.go +++ b/eventhandlers.go @@ -15,6 +15,9 @@ import ( keptn "github.com/keptn/go-utils/pkg/lib" ) +// SendTestsFinishedEvent defines whether to send a test finished event after executing chaos tests +var SendTestsFinishedEvent = os.Getenv("SEND_TEST_FINISHED_EVENT") + /** * Here are all the handler functions for the individual event See https://github.com/keptn/spec/blob/0.1.3/cloudevents.md for details on the payload @@ -50,8 +53,6 @@ func HandleDeploymentFinishedEvent(myKeptn *keptn.Keptn, incomingEvent cloudeven startTime := time.Now() // run tests - // ToDo: Implement your tests here - log.Printf("looking for Litmus chaos experiment in Keptn git repo...") resourceHandler := keptnapi.NewResourceHandler("configuration-service:8080") @@ -111,17 +112,20 @@ func HandleDeploymentFinishedEvent(myKeptn *keptn.Keptn, incomingEvent cloudeven log.Println("Final Result: " + verdict) // Send Test Finished Event - return myKeptn.SendTestsFinishedEvent(&incomingEvent, "", "", startTime, verdict, nil, "litmus-service") - //return nil + if SendTestsFinishedEvent == "true" { + return myKeptn.SendTestsFinishedEvent(&incomingEvent, "", "", startTime, verdict, nil, "litmus-service") + } + return nil } // // Handles TestsFinishedEventType = "sh.keptn.events.tests-finished" -// TODO: add in your handler code // func HandleTestsFinishedEvent(myKeptn *keptn.Keptn, incomingEvent cloudevents.Event, data *keptn.TestsFinishedEventData) error { log.Printf("Handling Tests Finished Event: %s", incomingEvent.Context.GetID()) + // potential improvement: check if the Test-finished event is coming from Litmus service and ignore if so + // delete chaos experiment log.Printf("Deleting chaos experiment resources") _, err := ExecuteCommand("kubectl", []string{"delete", "-f", LitmusExperimentFileName}) From eda5ec16f0adc026cec81b972fa6e2cb02e15ab7 Mon Sep 17 00:00:00 2001 From: jetzlstorfer Date: Wed, 14 Oct 2020 08:44:58 +0200 Subject: [PATCH 4/7] prepare for releae --- deploy/service.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/service.yaml b/deploy/service.yaml index 1e0cde6..bf23c14 100644 --- a/deploy/service.yaml +++ b/deploy/service.yaml @@ -56,7 +56,7 @@ spec: serviceAccountName: keptn-litmus-service containers: - name: litmus-service - image: jetzlstorfer/litmus-service:dev + image: keptnsandbox/litmus-service:0.1.0 imagePullPolicy: Always ports: - containerPort: 8080 From bd310c929f5b51421fbe2811234d3d46edb9fc25 Mon Sep 17 00:00:00 2001 From: jetzlstorfer Date: Wed, 14 Oct 2020 08:48:09 +0200 Subject: [PATCH 5/7] fix module name --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 6039283..a7fbe84 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module example.com/litmus-service +module github.com/keptn-sandbox/litmus-service go 1.13 From efe75a22c3b52b73ea86c84e7613bd22b03eaf2c Mon Sep 17 00:00:00 2001 From: jetzlstorfer Date: Thu, 15 Oct 2020 14:22:30 +0200 Subject: [PATCH 6/7] update readme --- README.md | 61 ++++++++++++++++------------------------ assets/litmus-keptn.png | Bin 0 -> 32090 bytes 2 files changed, 25 insertions(+), 36 deletions(-) create mode 100644 assets/litmus-keptn.png diff --git a/README.md b/README.md index 226ca90..e524e54 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ -# litmus-service +# Litmus Service + ![GitHub release (latest by date)](https://img.shields.io/github/v/release/keptn-sandbox/litmus-service) [![Go Report Card](https://goreportcard.com/badge/github.com/keptn-sandbox/litmus-service)](https://goreportcard.com/report/github.com/keptn-sandbox/litmus-service) -This service provides a way to perform chaos tests on your applications within the [Keptn](https://keptn.sh) pipeline using +![](./assets/litmus-keptn.png) + +This service provides a way to perform chaos tests on your applications triggered by [Keptn](https://keptn.sh) using the [LitmusChaos](https://litmuschaos.io) framework. ## Compatibility Matrix @@ -10,8 +13,10 @@ the [LitmusChaos](https://litmuschaos.io) framework. | Keptn Version | [litmus-service Docker Image](https://hub.docker.com/r/keptnsandbox/litmus-service/tags) | |:----------------:|:----------------------------------------:| | 0.7.1 | keptnsandbox/litmus-service:0.1.0 | +| 0.7.2 | TBD | + -### PreRequisites +## PreRequisites The Keptn *litmus-service* requires the following prerequisites to be setup on the Kubernetes cluster for it to run the chaos tests: @@ -20,7 +25,7 @@ The Keptn *litmus-service* requires the following prerequisites to be setup on t - The `ChaosExperiment` custom resources (CRs) - The RBAC (`serviceaccount`, `role`, `rolebinding`) associated with the chaos test -Execute the following commands to setup these dependencies: +Execute the following commands to setup these dependencies for a demo setup: ```console kubectl apply -f ./test-data/litmus/litmus-operator-v1.8.1.yaml @@ -35,43 +40,36 @@ You can choose to specify other [experiments](https://hub.litmuschaos.io/) depen Ensure that the correct `ChaosEngine` spec is provided in the [experiment manifest](./test-data/litmus/experiment.yaml) along with the corresponding `ChaosExperiment` CR & RBAC manifests. -- This repo uses the sample [*carts*](https://github.com/keptn-sandbox/litmus-service/tree/master/test-data/carts) app as the Application-Under-Test (AUT) - to illustrate the impact of chaos. Hence, the [experiment](./test-data/litmus/experiment.yaml) is populated with the respective attributes for app - filtering purposes. Ensure you have the right data placed in the `spec.appinfo` when adopting this for your environments. +- This repo uses the sample [*carts*](https://github.com/keptn-sandbox/litmus-service/tree/master/test-data/carts) app as the Application-Under-Test (AUT) to illustrate the impact of chaos. Hence, the [experiment](./test-data/litmus/experiment.yaml) is populated with the respective attributes for app filtering purposes. Ensure you have the right data placed in the `spec.appinfo` when adopting this for your environments. -### Deploy in your Kubernetes cluster +## Installation - Deploy in your Kubernetes cluster -To deploy the current version of the *litmus-service* in your Keptn Kubernetes cluster, apply the [`deploy/service.yaml`](deploy/service.yaml) file: +To deploy the current version of the *litmus-service* in your Keptn Kubernetes cluster, clone the repo and apply the [`deploy/service.yaml`](deploy/service.yaml) file: ```console kubectl apply -f deploy/service.yaml ``` -This should install the `litmus-service` together with a Keptn `distributor` into the `keptn` namespace, which you can verify using +This will install the `litmus-service` into the `keptn` namespace, which you can verify using: ```console kubectl -n keptn get deployment litmus-service -o wide kubectl -n keptn get pods -l run=litmus-service ``` -### How does the service work +## How does the service work? -The service implements [handlers](https://github.com/keptn-sandbox/litmus-service/blob/master/eventhandlers.go) for triggering the chaos tests -immediately after the review app is deployed successfully on the namespace created for the pipeline stage. The test is executed by a set of -*chaos pods* (notably, the *chaos-runner* & *experiment* pod) and the test results stored in a `ChaosResult` custom resource. The duration of the -test & other tunables can be configured in the `ChaosEngine` resource. Refer to the [Litmus docs](https://docs.litmuschaos.io/docs/chaosengine/) on -supported tunables. Litmus ensures that the review app/deployment is restored to it's initial state upon completion of the test. +The service implements [handlers](https://github.com/keptn-sandbox/litmus-service/blob/master/eventhandlers.go) for triggering the chaos tests in the "testing phase" of Keptn, that means that Keptn will trigger the chaos tests right after deployment. The test is executed by a set of *chaos pods* (notably, the *chaos-runner* & *experiment* pod) and the test results stored in a `ChaosResult` custom resource. The duration of the test & other tunables can be configured in the `ChaosEngine` resource. Refer to the [Litmus docs](https://docs.litmuschaos.io/docs/chaosengine/) on supported tunables. Litmus ensures that the review app/deployment is restored to it's initial state upon completion of the test. -The Keptn litmus-service also [conditionally](https://github.com/keptn-sandbox/litmus-service/blob/master/deploy/service.yaml#L68) generates & handles -the `test.finished` event by cleaning up residual chaos resources (*running* or *completed*) in the cluster. +The Keptn litmus-service also [conditionally](https://github.com/keptn-sandbox/litmus-service/blob/master/deploy/service.yaml#L68) generates & handles the `test.finished` event by cleaning up residual chaos resources (*running* or *completed*) in the cluster. It is a standard practice to execute the chaos tests in parallel with other performance/load tests running on the AUT. The subsequent quality gate evaluations in such cases are more reflective of real world outcomes. -**Note**: This repo, in its sample pipeline, uses a [jmeter](https://github.com/keptn-sandbox/litmus-service/tree/master/test-data/jmeter) load test +**Note**: The sample project provided in this repo (in the `test-data` folder), uses a [jmeter](https://github.com/keptn-sandbox/litmus-service/tree/master/test-data/jmeter) load test against the AUT, *carts*, running in parallel with the pod-delete chaos test. -### Delete in your Kubernetes cluster +## Uninstall - Delete from your Kubernetes cluster To delete the litmus-service, delete using the [`deploy/service.yaml`](deploy/service.yaml) file: @@ -79,7 +77,7 @@ To delete the litmus-service, delete using the [`deploy/service.yaml`](deploy/se kubectl delete -f deploy/service.yaml ``` -### Upgrade or Downgrading +## Upgrade or Downgrading Adapt and use the following command in case you want to upgrade or downgrade your installed version (specified by the `$VERSION` placeholder): @@ -89,17 +87,11 @@ kubectl -n keptn set image deployment/litmus-service litmus-service=keptnsandbox ### Configuring the Service -- The service implements simple handlers for the `deployment.finished` & `test.finished` events - i.e., triggers chaos by creating the `ChaosEngine` - resource, fetching info from `ChaosResult` resource & eventually deleting them, respectively. In case you would need additional functions/capabilities, - update the [eventhandlers.go](https://github.com/keptn-sandbox/litmus-service/blob/master/eventhandlers.go). For more info around how to go about this, - view the **Development** section. +- The service implements simple handlers for the `deployment.finished` & `test.finished` events - i.e., triggers chaos by creating the `ChaosEngine` resource, fetching info from `ChaosResult` resource & eventually deleting them, respectively. In case you would need additional functions/capabilities, update the [eventhandlers.go](https://github.com/keptn-sandbox/litmus-service/blob/master/eventhandlers.go). For more info around how to go about this, view the **Development** section. -- Considering the litmus-service runs in the keptn namespace & acts on resources/applications on other namespaces (as per the project/stage names), - it uses a cluster-wide RBAC. Tune the [permissions](https://github.com/keptn-sandbox/litmus-service/blob/master/deploy/service.yaml#L17) associated with this - service based on functionality needed apart from CRUD on `ChaosEngine` & `ChaosResults`. +- Considering the litmus-service runs in the keptn namespace & acts on resources/applications on other namespaces (as per the project/stage names), it uses a cluster-wide RBAC. Tune the [permissions](https://github.com/keptn-sandbox/litmus-service/blob/master/deploy/service.yaml#L17) associated with this service based on functionality needed apart from CRUD on `ChaosEngine` & `ChaosResults`. -- In case you would like to cleanup chaos resources immediately after completion of the chaos test (either because you aren't running other tests of - primary significance such as perf tests), set the environment variable `SEND_TEST_FINISHED_EVENT` to `true` in the litmus-service deployment +- In case you would like to cleanup chaos resources immediately after completion of the chaos test (either because you aren't running other tests of primary significance such as perf tests), set the environment variable `SEND_TEST_FINISHED_EVENT` to `true` in the litmus-service deployment. ## Development @@ -117,14 +109,11 @@ When writing code, it is recommended to follow the coding style suggested by the ### Where to start -If you don't care about the details, your first entrypoint is [eventhandlers.go](eventhandlers.go). Within this file - you can add implementation for pre-defined Keptn Cloud events. +If you don't care about the details, your first entrypoint is [eventhandlers.go](eventhandlers.go). Within this file you can add implementation for pre-defined Keptn Cloud events. To better understand Keptn CloudEvents, please look at the [Keptn Spec](https://github.com/keptn/spec). -If you want to get more insights, please look into [main.go](main.go), [deploy/service.yaml](deploy/service.yaml), - consult the [Keptn docs](https://keptn.sh/docs/) as well as existing [Keptn Core](https://github.com/keptn/keptn) and - [Keptn Contrib](https://github.com/keptn-contrib/) services. +If you want to get more insights, please look into [main.go](main.go), [deploy/service.yaml](deploy/service.yaml), consult the [Keptn docs](https://keptn.sh/docs/) as well as existing [Keptn Core](https://github.com/keptn/keptn) and [Keptn Contrib](https://github.com/keptn-contrib/) services. ### Common tasks @@ -132,7 +121,7 @@ If you want to get more insights, please look into [main.go](main.go), [deploy/s * Run tests: `go test -race -v ./...` * Build the docker image: `docker build . -t keptnsandbox/litmus-service:dev` (Note: Ensure that you use the correct DockerHub account/organization) * Run the docker image locally: `docker run --rm -it -p 8080:8080 keptnsandbox/litmus-service:dev` -* Push the docker image to DockerHub: `docker push keptnsandbox/litmus-service:dev` (Note: Ensure that you use the correct DockerHub account/organization) +* Push the docker image to DockerHub: `docker push keptnsandbox/litmus-service:dev` (Note: Ensure that you use the correct DockerHub account/organization, e.g., your personal account like `docker push myaccount/litmus-service:dev`) * Deploy the service using `kubectl`: `kubectl apply -f deploy/` * Delete/undeploy the service using `kubectl`: `kubectl delete -f deploy/` * Watch the deployment using `kubectl`: `kubectl -n keptn get deployment litmus-service -o wide` diff --git a/assets/litmus-keptn.png b/assets/litmus-keptn.png new file mode 100644 index 0000000000000000000000000000000000000000..5ea157a4c21ce3df318f466002ed99a918cecd47 GIT binary patch literal 32090 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 Date: Fri, 16 Oct 2020 15:12:03 +0200 Subject: [PATCH 7/7] add usage notes --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e524e54..f14d585 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ the [LitmusChaos](https://litmuschaos.io) framework. | 0.7.2 | TBD | -## PreRequisites +## Prerequisites The Keptn *litmus-service* requires the following prerequisites to be setup on the Kubernetes cluster for it to run the chaos tests: @@ -57,6 +57,19 @@ kubectl -n keptn get deployment litmus-service -o wide kubectl -n keptn get pods -l run=litmus-service ``` +### Usage + +To make use of the Litmus service, a dedicated `experiment.yaml` file with the actual chaos experiment has to be added to Keptn (for the service under test). + +You can do this via the Keptn CLI, please replace the values for `project`, `stage`, `service` and `resource` with your actual values. But note that the `resourceUri` has to be set to `litmus/experiment.yaml`. + +``` +keptn add-resource --project=litmus --stage=chaos --service=carts --resource=litmus/experiment.yaml --resourceUri=litmus/experiment.yaml +``` + +Please note that it is recommended to run the chaos experiment along with some load testing. +Now when a `send-test` event is sent to Keptn, the chaos test will be triggered along with the load tests. Once the load tests are finished, Keptn will do the evaluation and provide you with a result. With this you can then verify if your application is resilient in the way that your SLOs are still met. + ## How does the service work? The service implements [handlers](https://github.com/keptn-sandbox/litmus-service/blob/master/eventhandlers.go) for triggering the chaos tests in the "testing phase" of Keptn, that means that Keptn will trigger the chaos tests right after deployment. The test is executed by a set of *chaos pods* (notably, the *chaos-runner* & *experiment* pod) and the test results stored in a `ChaosResult` custom resource. The duration of the test & other tunables can be configured in the `ChaosEngine` resource. Refer to the [Litmus docs](https://docs.litmuschaos.io/docs/chaosengine/) on supported tunables. Litmus ensures that the review app/deployment is restored to it's initial state upon completion of the test.