diff --git a/.ci_env b/.ci_env
new file mode 100644
index 0000000..9ffe598
--- /dev/null
+++ b/.ci_env
@@ -0,0 +1,2 @@
+DOCKER_ORGANIZATION="keptnsandbox"
+IMAGE="keptn-service-template-go"
\ No newline at end of file
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..e69de29
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..5f4c27a
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,12 @@
+version: 2
+updates:
+ - package-ecosystem: github-actions
+ directory: "/"
+ schedule:
+ interval: daily
+ open-pull-requests-limit: 10
+ - package-ecosystem: gomod
+ directory: "/"
+ schedule:
+ interval: daily
+ open-pull-requests-limit: 10
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
new file mode 100644
index 0000000..0608f0c
--- /dev/null
+++ b/.github/workflows/CI.yml
@@ -0,0 +1,181 @@
+name: CI
+on:
+ # always execute docker build when something is pushed to master or release-* branches
+ push:
+ branches:
+ - 'master'
+ - 'main'
+ - 'release-*'
+ # in addition, execute for pull requests to those branches
+ pull_request:
+ branches:
+ - 'master'
+ - 'main'
+ - 'release-*'
+defaults:
+ run:
+ shell: bash
+jobs:
+ prepare_ci_run:
+ name: Prepare CI Run
+ # Prepare CI Run looks at what has been changed in this commit/PR/... and determines which artifacts should be
+ # built afterwards (in other jobs that depend on this one).
+ runs-on: ubuntu-20.04
+ outputs: # declare what this job outputs (so it can be re-used for other jobs)
+ # build config
+ # metadata
+ GIT_SHA: ${{ steps.extract_branch.outputs.GIT_SHA }}
+ BRANCH: ${{ steps.extract_branch.outputs.BRANCH }}
+ BRANCH_SLUG: ${{ steps.extract_branch.outputs.BRANCH_SLUG }}
+ VERSION: ${{ steps.get_version.outputs.VERSION }}
+ DATE: ${{ steps.get_datetime.outputs.DATE }}
+ TIME: ${{ steps.get_datetime.outputs.TIME }}
+ DATETIME: ${{ steps.get_datetime.outputs.DATETIME }}
+
+ steps:
+ - name: Check out code
+ uses: actions/checkout@v2.3.4
+ with:
+ fetch-depth: 0 # need to checkout "all commits" for certain features to work (e.g., get all changed files)
+
+ - name: Load CI Environment from .ci_env
+ id: load_ci_env
+ uses: c-py/action-dotenv-to-setenv@v3
+ with:
+ env-file: .ci_env
+
+ - name: Extract branch name
+ id: extract_branch
+ # see https://github.com/keptn/gh-action-extract-branch-name for details
+ uses: keptn/gh-action-extract-branch-name@main
+
+ - name: 'Get Previous tag'
+ id: get_previous_tag
+ uses: "WyriHaximus/github-action-get-previous-tag@v1.1"
+ with:
+ fallback: "0.0.1"
+ - name: 'Get next patch version'
+ id: get_next_semver_tag
+ uses: "WyriHaximus/github-action-next-semvers@v1.1"
+ with:
+ version: ${{ steps.get_previous_tag.outputs.tag }}
+ - name: Get the version
+ id: get_version
+ env:
+ BRANCH: ${{ steps.extract_branch.outputs.BRANCH }}
+ BRANCH_SLUG: ${{ steps.extract_branch.outputs.BRANCH_SLUG }}
+ shell: bash
+ run: |
+ # determine version
+ GIT_LAST_TAG=${{ steps.get_previous_tag.outputs.tag }}
+ GIT_NEXT_TAG=${{ steps.get_next_semver_tag.outputs.patch }}
+ echo "GIT_LAST_TAG=${GIT_LAST_TAG}, GIT_NEXT_TAG=${GIT_NEXT_TAG}"
+
+ if [[ "$BRANCH" == "release-"* ]]; then
+ # Release Branch: extract version from branch name
+ VERSION=${BRANCH#"release-"}
+ else
+ if [[ "$BRANCH" == "master" ]]; then
+ # master branch = latest
+ VERSION="${GIT_NEXT_TAG}-dev"
+ else
+ # Feature/Development Branch - use last tag with branch slug
+ VERSION="${GIT_NEXT_TAG}-dev-${BRANCH_SLUG}"
+ fi
+ fi
+
+ echo "VERSION=${VERSION}"
+
+ echo "##[set-output name=VERSION;]$(echo ${VERSION})"
+ - name: Get current date and time
+ id: get_datetime
+ run: |
+ echo "::set-output name=DATE::$(date +'%Y%m%d')"
+ echo "::set-output name=TIME::$(date +'%H%M')"
+ echo "::set-output name=DATETIME::$(date +'%Y%m%d')$(date +'%H%M')"
+
+ ############################################################################
+ # Unit tests #
+ ############################################################################
+ unit-tests:
+ name: Unit Tests
+ needs: prepare_ci_run
+ runs-on: ubuntu-20.04
+ steps:
+ - name: Set up Go 1.x
+ uses: actions/setup-go@v2
+ with:
+ go-version: ^1.16
+ - name: Checkout Code
+ uses: actions/checkout@v2.3.4
+
+ - name: Load CI Environment from .ci_env
+ id: load_ci_env
+ uses: c-py/action-dotenv-to-setenv@v3
+ with:
+ env-file: .ci_env
+
+ - name: Test
+ run: go test -coverprofile=coverage.txt -covermode=atomic -v ./...
+ working-directory: .
+
+
+ ############################################################################
+ # Build Docker Image #
+ ############################################################################
+ docker_build:
+ needs: [prepare_ci_run, unit-tests]
+ name: Docker Build
+ runs-on: ubuntu-20.04
+ env:
+ BRANCH: ${{ needs.prepare_ci_run.outputs.BRANCH }}
+ VERSION: ${{ needs.prepare_ci_run.outputs.VERSION }}
+ DATETIME: ${{ needs.prepare_ci_run.outputs.DATE }}${{ needs.prepare_ci_run.outputs.TIME }}
+ GIT_SHA: ${{ needs.prepare_ci_run.outputs.GIT_SHA }}
+ steps:
+ - name: Checkout Code
+ uses: actions/checkout@v2.3.4
+
+ - name: Load CI Environment from .ci_env
+ id: load_ci_env
+ uses: c-py/action-dotenv-to-setenv@v3
+ with:
+ env-file: .ci_env
+
+ - id: docker_login
+ name: Docker Login
+ # only run docker login on pushes; also for PRs, but only if this is not a fork
+ if: (github.event_name == 'push') || (github.event.pull_request.head.repo.full_name == github.repository)
+ # note: GH does not allow to access secrets for PRs from a forked repositories due to security reasons
+ # that's fine, but it means we can't push images to dockerhub
+ uses: docker/login-action@v1.9.0
+ with:
+ username: ${{ secrets.REGISTRY_USER }}
+ password: ${{ secrets.REGISTRY_PASSWORD }}
+
+ - id: docker_build
+ name: Docker Build
+ uses: keptn/gh-action-build-docker-image@master
+ with:
+ VERSION: ${{ env.VERSION }}
+ IMAGE_NAME: "${{ env.DOCKER_ORGANIZATION }}/${{ env.IMAGE }}"
+ DATETIME: ${{ env.DATETIME }}
+
+ - id: create_docker_build_report
+ name: Create Docker Build Report
+ run: |
+ echo "The following Docker Images have been built: " > docker_build_report_final.txt
+ cat docker_build_report.txt >> docker_build_report_final.txt || echo "* No images have been built or uploaded" >> docker_build_report_final.txt
+ echo "---"
+ cat docker_build_report_final.txt
+
+ - id: report_docker_build_to_pr
+ # Comment the docker build report to the PR
+ # This only works for PRs coming from inside of the repo, not from forks
+ name: Report Docker Build to PR
+ if: (github.event_name == 'pull_request') && (github.event.pull_request.head.repo.full_name == github.repository)
+ uses: marocchino/sticky-pull-request-comment@v2.1.0
+ with:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ path: docker_build_report_final.txt
+ recreate: true
\ No newline at end of file
diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml
new file mode 100644
index 0000000..be7a8f9
--- /dev/null
+++ b/.github/workflows/reviewdog.yml
@@ -0,0 +1,24 @@
+name: reviewdog
+on: [pull_request]
+jobs:
+ reviewdog:
+ name: reviewdog
+ runs-on: ubuntu-latest
+ steps:
+ - name: Set up Go
+ uses: actions/setup-go@v2
+ with:
+ go-version: 1.16
+ id: go
+ - name: Check out code.
+ uses: actions/checkout@v2.3.4
+ - name: Install linters
+ run: '( mkdir linters && cd linters && go get golang.org/x/lint/golint )'
+ - uses: reviewdog/action-setup@v1.0.3
+ with:
+ reviewdog_version: latest
+ - name: Run reviewdog
+ env:
+ REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ reviewdog -reporter=github-pr-review
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..57d2be8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,27 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+vendor/*
+.DS_Store
+
+# binaries (created by go build on Linux/OSX)
+main
+keptn-service-template-go
+
+# IDE specific folders
+.vscode
+
+# only ignore contents of local .idea
+.idea/*
+# but allow .idea shared run configurations
+!.idea/runConfigurations/
diff --git a/.idea/runConfigurations/Build_Dockerfile.xml b/.idea/runConfigurations/Build_Dockerfile.xml
new file mode 100644
index 0000000..83a1b39
--- /dev/null
+++ b/.idea/runConfigurations/Build_Dockerfile.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/Develop_on_Kubernetes.xml b/.idea/runConfigurations/Develop_on_Kubernetes.xml
new file mode 100644
index 0000000..1d51e33
--- /dev/null
+++ b/.idea/runConfigurations/Develop_on_Kubernetes.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/Run_on_Kubernetes.xml b/.idea/runConfigurations/Run_on_Kubernetes.xml
new file mode 100644
index 0000000..8b112e5
--- /dev/null
+++ b/.idea/runConfigurations/Run_on_Kubernetes.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/go_build_example_com_keptn_service_template_go.xml b/.idea/runConfigurations/go_build_example_com_keptn_service_template_go.xml
new file mode 100644
index 0000000..4948018
--- /dev/null
+++ b/.idea/runConfigurations/go_build_example_com_keptn_service_template_go.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.reviewdog.yml b/.reviewdog.yml
new file mode 100644
index 0000000..111e075
--- /dev/null
+++ b/.reviewdog.yml
@@ -0,0 +1,12 @@
+runner:
+ golint:
+ cmd: golint ./...
+ errorformat:
+ - "%f:%l:%c: %m"
+ level: warning
+ gofmt:
+ cmd: gofmt -l -s .|xargs -I{} echo {}:1 file {} is not gofmted
+ errorformat:
+ - "%f:%l %m"
+ govet:
+ cmd: go vet -all .
diff --git a/CODEOWNERS b/CODEOWNERS
new file mode 100644
index 0000000..c291844
--- /dev/null
+++ b/CODEOWNERS
@@ -0,0 +1,10 @@
+##############################################################
+#
+# Lists the owners of this project
+#
+##############################################################
+#
+# Learn about CODEOWNERS file format:
+# https://help.github.com/en/articles/about-code-owners
+#
+
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..f2dfd25
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,67 @@
+# Use the offical Golang image to create a build artifact.
+# This is based on Debian and sets the GOPATH to /go.
+# https://hub.docker.com/_/golang
+FROM golang:1.16.2-alpine as builder
+
+RUN apk add --no-cache gcc libc-dev git
+
+WORKDIR /src/keptn-service-template-go
+
+ARG version=develop
+ENV VERSION="${version}"
+
+# Force the go compiler to use modules
+ENV GO111MODULE=on
+ENV BUILDFLAGS=""
+ENV GOPROXY=https://proxy.golang.org
+
+# Copy `go.mod` for definitions and `go.sum` to invalidate the next layer
+# in case of a change in the dependencies
+COPY go.mod go.sum ./
+
+# Download dependencies
+RUN go mod download
+
+ARG debugBuild
+
+# set buildflags for debug build
+RUN if [ ! -z "$debugBuild" ]; then export BUILDFLAGS='-gcflags "all=-N -l"'; fi
+
+# Copy local code to the container image.
+COPY . .
+
+# Build the command inside the container.
+# (You may fetch or manage dependencies here, either manually or with a tool like "godep".)
+RUN GOOS=linux go build -ldflags '-linkmode=external' $BUILDFLAGS -v -o keptn-service-template-go
+
+# Use a Docker multi-stage build to create a lean production image.
+# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
+FROM alpine:3.13
+ENV ENV=production
+
+# Install extra packages
+# See https://github.com/gliderlabs/docker-alpine/issues/136#issuecomment-272703023
+
+RUN apk update && apk upgrade \
+ && apk add ca-certificates libc6-compat \
+ && update-ca-certificates \
+ && rm -rf /var/cache/apk/*
+
+ARG version=develop
+ENV VERSION="${version}"
+
+# Copy the binary to the production image from the builder stage.
+COPY --from=builder /src/keptn-service-template-go/keptn-service-template-go /keptn-service-template-go
+
+EXPOSE 8080
+
+# required for external tools to detect this as a go binary
+ENV GOTRACEBACK=all
+
+# KEEP THE FOLLOWING LINES COMMENTED OUT!!! (they will be included within the travis-ci build)
+#build-uncomment ADD MANIFEST /
+#build-uncomment COPY entrypoint.sh /
+#build-uncomment ENTRYPOINT ["/entrypoint.sh"]
+
+# Run the web service on container startup.
+CMD ["/keptn-service-template-go"]
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7cadfe2
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2020 Dynatrace LLC
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9851796
--- /dev/null
+++ b/README.md
@@ -0,0 +1,163 @@
+# README
+
+This is a Keptn Service Template written in GoLang. Follow the instructions below for writing your own Keptn integration.
+
+Quick start:
+
+1. In case you want to contribute your service to keptn-sandbox or keptn-contrib, make sure you have read and understood the [Contributing Guidelines](https://github.com/keptn-sandbox/contributing).
+1. Click [Use this template](https://github.com/keptn-sandbox/keptn-service-template-go/generate) on top of the repository, or download the repo as a zip-file, extract it into a new folder named after the service you want to create (e.g., simple-service)
+1. Replace every occurrence of (docker) image names and tags from `keptnsandbox/keptn-service-template-go` to your docker organization and image name (e.g., `yourorganization/simple-service`)
+1. Replace every occurrence of `keptn-service-template-go` with the name of your service (e.g., `simple-service`)
+1. Optional (but recommended): Create a git repo (e.g., on `github.com/your-username/simple-service`)
+1. Àdapt the [go.mod](go.mod) file and change `example.com/` to the actual package name (e.g., `github.com/your-username/simple-service`)
+1. Add yourself to the [CODEOWNERS](CODEOWNERS) file
+1. Initialize a git repository:
+ * `git init .`
+ * `git add .`
+ * `git commit -m "Initial Commit"`
+1. Optional: Push your code an upstream git repo (e.g., GitHub) and adapt all links that contain `github.com` (e.g., to `github.com/your-username/simple-service`)
+1. Figure out whether your Kubernetes Deployment requires [any RBAC rules or a different service-account](https://github.com/keptn-sandbox/contributing#rbac-guidelines), and adapt [deploy/service.yaml](deploy/service.yaml) accordingly (initial setup is `serviceAccountName: keptn-default`).
+1. Last but not least: Remove this intro within the README file and make sure the README file properly states what this repository is about
+
+---
+
+# keptn-service-template-go
+![GitHub release (latest by date)](https://img.shields.io/github/v/release/keptn-sandbox/keptn-service-template-go)
+[![Go Report Card](https://goreportcard.com/badge/github.com/keptn-sandbox/keptn-service-template-go)](https://goreportcard.com/report/github.com/keptn-sandbox/keptn-service-template-go)
+
+This implements a keptn-service-template-go for Keptn. If you want to learn more about Keptn visit us on [keptn.sh](https://keptn.sh)
+
+## Compatibility Matrix
+
+*Please fill in your versions accordingly*
+
+| Keptn Version | [Keptn-Service-Template-Go Docker Image](https://hub.docker.com/r/keptnsandbox/keptn-service-template-go/tags) |
+|:----------------:|:----------------------------------------:|
+| 0.6.1 | keptnsandbox/keptn-service-template-go:0.1.0 |
+| 0.7.1 | keptnsandbox/keptn-service-template-go:0.1.1 |
+| 0.7.2 | keptnsandbox/keptn-service-template-go:0.1.2 |
+
+## Installation
+
+The *keptn-service-template-go* can be installed as a part of [Keptn's uniform](https://keptn.sh).
+
+### Deploy in your Kubernetes cluster
+
+To deploy the current version of the *keptn-service-template-go* in your Keptn Kubernetes cluster, apply the [`deploy/service.yaml`](deploy/service.yaml) file:
+
+```console
+kubectl apply -f deploy/service.yaml
+```
+
+This should install the `keptn-service-template-go` together with a Keptn `distributor` into the `keptn` namespace, which you can verify using
+
+```console
+kubectl -n keptn get deployment keptn-service-template-go -o wide
+kubectl -n keptn get pods -l run=keptn-service-template-go
+```
+
+### Up- or Downgrading
+
+Adapt and use the following command in case you want to up- or downgrade your installed version (specified by the `$VERSION` placeholder):
+
+```console
+kubectl -n keptn set image deployment/keptn-service-template-go keptn-service-template-go=keptnsandbox/keptn-service-template-go:$VERSION --record
+```
+
+### Uninstall
+
+To delete a deployed *keptn-service-template-go*, use the file `deploy/*.yaml` files from this repository and delete the Kubernetes resources:
+
+```console
+kubectl delete -f deploy/service.yaml
+```
+
+## Development
+
+Development can be conducted using any GoLang compatible IDE/editor (e.g., Jetbrains GoLand, VSCode with Go plugins).
+
+It is recommended to make use of branches as follows:
+
+* `master` contains the latest potentially unstable version
+* `release-*` contains a stable version of the service (e.g., `release-0.1.0` contains version 0.1.0)
+* create a new branch for any changes that you are working on, e.g., `feature/my-cool-stuff` or `bug/overflow`
+* once ready, create a pull request from that branch back to the `master` branch
+
+When writing code, it is recommended to follow the coding style suggested by the [Golang community](https://github.com/golang/go/wiki/CodeReviewComments).
+
+### 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.
+
+To better understand all variants of Keptn CloudEvents, please look at the [Keptn Spec](https://github.com/keptn/spec).
+
+If you want to get more insights into processing those CloudEvents or even defining your own CloudEvents in code, please
+ look into [main.go](main.go) (specifically `processKeptnCloudEvent`), [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
+
+* Build the binary: `go build -ldflags '-linkmode=external' -v -o keptn-service-template-go`
+* Run tests: `go test -race -v ./...`
+* Build the docker image: `docker build . -t keptnsandbox/keptn-service-template-go:dev` (Note: Ensure that you use the correct DockerHub account/organization)
+* Run the docker image locally: `docker run --rm -it -p 8080:8080 keptnsandbox/keptn-service-template-go:dev`
+* Push the docker image to DockerHub: `docker push keptnsandbox/keptn-service-template-go:dev` (Note: Ensure that you use the correct DockerHub account/organization)
+* 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 keptn-service-template-go -o wide`
+* Get logs using `kubectl`: `kubectl -n keptn logs deployment/keptn-service-template-go -f`
+* Watch the deployed pods using `kubectl`: `kubectl -n keptn get pods -l run=keptn-service-template-go`
+* Deploy the service using [Skaffold](https://skaffold.dev/): `skaffold run --default-repo=your-docker-registry --tail` (Note: Replace `your-docker-registry` with your DockerHub username; also make sure to adapt the image name in [skaffold.yaml](skaffold.yaml))
+
+
+### Testing Cloud Events
+
+We have dummy cloud-events in the form of [RFC 2616](https://ietf.org/rfc/rfc2616.txt) requests in the [test-events/](test-events/) directory. These can be easily executed using third party plugins such as the [Huachao Mao REST Client in VS Code](https://marketplace.visualstudio.com/items?itemName=humao.rest-client).
+
+## Automation
+
+### GitHub Actions: Automated Pull Request Review
+
+This repo uses [reviewdog](https://github.com/reviewdog/reviewdog) for automated reviews of Pull Requests.
+
+You can find the details in [.github/workflows/reviewdog.yml](.github/workflows/reviewdog.yml).
+
+### GitHub Actions: Unit Tests
+
+This repo has automated unit tests for pull requests.
+
+You can find the details in [.github/workflows/tests.yml](.github/workflows/tests.yml).
+
+### GH Actions/Workflow: Build Docker Images
+
+This repo uses GH Actions and Workflows to test the code and automatically build docker images.
+
+Docker Images are automatically pushed based on the configuration done in [.ci_env](.ci_env) and the two [GitHub Secrets](https://github.com/keptn-sandbox/keptn-service-template-go/settings/secrets/actions)
+* `REGISTRY_USER` - your DockerHub username
+* `REGISTRY_PASSWORD` - a DockerHub [access token](https://hub.docker.com/settings/security) (alternatively, your DockerHub password)
+
+## How to release a new version of this service
+
+It is assumed that the current development takes place in the master branch (either via Pull Requests or directly).
+
+To make use of the built-in automation using GH Actions for releasing a new version of this service, you should
+
+* branch away from master to a branch called `release-x.y.z` (where `x.y.z` is your version),
+* write release notes in the [releasenotes/](releasenotes/) folder,
+* check the output of GH Actions builds for the release branch,
+* verify that your image was built and pushed to DockerHub with the right tags,
+* update the image tags in [deploy/service.yaml], and
+* test your service against a working Keptn installation.
+
+If any problems occur, fix them in the release branch and test them again.
+
+Once you have confirmed that everything works and your version is ready to go, you should
+
+* create a new release on the release branch using the [GitHub releases page](https://github.com/keptn-sandbox/keptn-service-template-go/releases), and
+* merge any changes from the release branch back to the master branch.
+
+## License
+
+Please find more information in the [LICENSE](LICENSE) file.
diff --git a/deploy/service.yaml b/deploy/service.yaml
new file mode 100644
index 0000000..8a39c30
--- /dev/null
+++ b/deploy/service.yaml
@@ -0,0 +1,67 @@
+---
+# Deployment of our keptn-service-template-go
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: keptn-service-template-go
+ namespace: keptn
+spec:
+ selector:
+ matchLabels:
+ run: keptn-service-template-go
+ replicas: 1
+ template:
+ metadata:
+ labels:
+ run: keptn-service-template-go
+ spec:
+ containers:
+ - name: keptn-service-template-go
+ image: keptnsandbox/keptn-service-template-go:latest # Todo: Replace this with your image name
+ ports:
+ - containerPort: 8080
+ env:
+ - name: CONFIGURATION_SERVICE
+ value: 'http://configuration-service:8080'
+ - name: distributor
+ image: keptn/distributor:0.8.3
+ livenessProbe:
+ httpGet:
+ path: /health
+ port: 10999
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ imagePullPolicy: Always
+ ports:
+ - containerPort: 8080
+ resources:
+ requests:
+ memory: "16Mi"
+ cpu: "25m"
+ limits:
+ memory: "128Mi"
+ cpu: "250m"
+ env:
+ - name: PUBSUB_URL
+ value: 'nats://keptn-nats-cluster'
+ - name: PUBSUB_TOPIC
+ value: 'sh.keptn.>'
+ - name: PUBSUB_RECIPIENT
+ value: '127.0.0.1'
+ serviceAccountName: keptn-default
+---
+# Expose keptn-service-template-go via Port 8080 within the cluster
+apiVersion: v1
+kind: Service
+metadata:
+ name: keptn-service-template-go
+ namespace: keptn
+ labels:
+ run: keptn-service-template-go
+spec:
+ ports:
+ - port: 8080
+ protocol: TCP
+ selector:
+ run: keptn-service-template-go
+
diff --git a/eventhandler_test.go b/eventhandler_test.go
new file mode 100644
index 0000000..e741e17
--- /dev/null
+++ b/eventhandler_test.go
@@ -0,0 +1,179 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "github.com/keptn/go-utils/pkg/lib/v0_2_0/fake"
+ "io/ioutil"
+ "testing"
+
+ keptn "github.com/keptn/go-utils/pkg/lib/keptn"
+ keptnv2 "github.com/keptn/go-utils/pkg/lib/v0_2_0"
+
+ cloudevents "github.com/cloudevents/sdk-go/v2" // make sure to use v2 cloudevents here
+)
+
+/**
+ * loads a cloud event from the passed test json file and initializes a keptn object with it
+ */
+func initializeTestObjects(eventFileName string) (*keptnv2.Keptn, *cloudevents.Event, error) {
+ // load sample event
+ eventFile, err := ioutil.ReadFile(eventFileName)
+ if err != nil {
+ return nil, nil, fmt.Errorf("Cant load %s: %s", eventFileName, err.Error())
+ }
+
+ incomingEvent := &cloudevents.Event{}
+ err = json.Unmarshal(eventFile, incomingEvent)
+ if err != nil {
+ return nil, nil, fmt.Errorf("Error parsing: %s", err.Error())
+ }
+
+ // Add a Fake EventSender to KeptnOptions
+ var keptnOptions = keptn.KeptnOpts{
+ EventSender: &fake.EventSender{},
+ }
+ keptnOptions.UseLocalFileSystem = true
+ myKeptn, err := keptnv2.NewKeptn(incomingEvent, keptnOptions)
+
+ return myKeptn, incomingEvent, err
+}
+
+// Tests HandleActionTriggeredEvent
+// TODO: Add your test-code
+func TestHandleActionTriggeredEvent(t *testing.T) {
+ myKeptn, incomingEvent, err := initializeTestObjects("test-events/action.triggered.json")
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ specificEvent := &keptnv2.ActionTriggeredEventData{}
+ err = incomingEvent.DataAs(specificEvent)
+ if err != nil {
+ t.Errorf("Error getting keptn event data")
+ }
+
+ err = HandleActionTriggeredEvent(myKeptn, *incomingEvent, specificEvent)
+ if err != nil {
+ t.Errorf("Error: " + err.Error())
+ }
+
+ gotEvents := len(myKeptn.EventSender.(*fake.EventSender).SentEvents)
+
+ // Verify that HandleGetSliTriggeredEvent has sent 2 cloudevents
+ if gotEvents != 2 {
+ t.Errorf("Expected two events to be sent, but got %v", gotEvents)
+ }
+
+ // Verify that the first CE sent is a .started event
+ if keptnv2.GetStartedEventType(keptnv2.ActionTaskName) != myKeptn.EventSender.(*fake.EventSender).SentEvents[0].Type() {
+ t.Errorf("Expected a action.started event type")
+ }
+
+ // Verify that the second CE sent is a .finished event
+ if keptnv2.GetFinishedEventType(keptnv2.ActionTaskName) != myKeptn.EventSender.(*fake.EventSender).SentEvents[1].Type() {
+ t.Errorf("Expected a action.finished event type")
+ }
+}
+
+// Tests HandleDeploymentTriggeredEvent
+// TODO: Add your test-code
+func TestHandleDeploymentTriggeredEvent(t *testing.T) {
+ myKeptn, incomingEvent, err := initializeTestObjects("test-events/evaluation.triggered.json")
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ specificEvent := &keptnv2.DeploymentTriggeredEventData{}
+ err = incomingEvent.DataAs(specificEvent)
+ if err != nil {
+ t.Errorf("Error getting keptn event data")
+ }
+
+ err = HandleDeploymentTriggeredEvent(myKeptn, *incomingEvent, specificEvent)
+ if err != nil {
+ t.Errorf("Error: " + err.Error())
+ }
+}
+
+// Tests HandleEvaluationTriggeredEvent
+// TODO: Add your test-code
+func TestHandleEvaluationTriggeredEvent(t *testing.T) {
+ myKeptn, incomingEvent, err := initializeTestObjects("test-events/evaluation.triggered.json")
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ specificEvent := &keptnv2.EvaluationTriggeredEventData{}
+ err = incomingEvent.DataAs(specificEvent)
+ if err != nil {
+ t.Errorf("Error getting keptn event data")
+ }
+
+ err = HandleEvaluationTriggeredEvent(myKeptn, *incomingEvent, specificEvent)
+ if err != nil {
+ t.Errorf("Error: " + err.Error())
+ }
+}
+
+// Tests the HandleGetSliTriggeredEvent Handler
+// TODO: Add your test-code
+func TestHandleGetSliTriggered(t *testing.T) {
+ myKeptn, incomingEvent, err := initializeTestObjects("test-events/get-sli.triggered.json")
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ specificEvent := &keptnv2.GetSLITriggeredEventData{}
+ err = incomingEvent.DataAs(specificEvent)
+ if err != nil {
+ t.Errorf("Error getting keptn event data")
+ }
+
+ err = HandleGetSliTriggeredEvent(myKeptn, *incomingEvent, specificEvent)
+ if err != nil {
+ t.Errorf("Error: " + err.Error())
+ }
+
+ gotEvents := len(myKeptn.EventSender.(*fake.EventSender).SentEvents)
+
+ // Verify that HandleGetSliTriggeredEvent has sent 2 cloudevents
+ if gotEvents != 2 {
+ t.Errorf("Expected two events to be sent, but got %v", gotEvents)
+ }
+
+ // Verify that the first CE sent is a .started event
+ if keptnv2.GetStartedEventType(keptnv2.GetSLITaskName) != myKeptn.EventSender.(*fake.EventSender).SentEvents[0].Type() {
+ t.Errorf("Expected a get-sli.started event type")
+ }
+
+ // Verify that the second CE sent is a .finished event
+ if keptnv2.GetFinishedEventType(keptnv2.GetSLITaskName) != myKeptn.EventSender.(*fake.EventSender).SentEvents[1].Type() {
+ t.Errorf("Expected a get-sli.finished event type")
+ }
+}
+
+// Tests the HandleReleaseTriggeredEvent Handler
+// TODO: Add your test-code
+func TestHandleReleaseTriggeredEvent(t *testing.T) {
+ myKeptn, incomingEvent, err := initializeTestObjects("test-events/release.triggered.json")
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ specificEvent := &keptnv2.ReleaseTriggeredEventData{}
+ err = incomingEvent.DataAs(specificEvent)
+ if err != nil {
+ t.Errorf("Error getting keptn event data")
+ }
+
+ err = HandleReleaseTriggeredEvent(myKeptn, *incomingEvent, specificEvent)
+ if err != nil {
+ t.Errorf("Error: " + err.Error())
+ }
+}
diff --git a/eventhandlers.go b/eventhandlers.go
new file mode 100644
index 0000000..8cb5419
--- /dev/null
+++ b/eventhandlers.go
@@ -0,0 +1,224 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "time"
+
+ cloudevents "github.com/cloudevents/sdk-go/v2" // make sure to use v2 cloudevents here
+ keptn "github.com/keptn/go-utils/pkg/lib"
+ keptnv2 "github.com/keptn/go-utils/pkg/lib/v0_2_0"
+)
+
+/**
+* Here are all the handler functions for the individual event
+* See https://github.com/keptn/spec/blob/0.8.0-alpha/cloudevents.md for details on the payload
+**/
+
+// GenericLogKeptnCloudEventHandler is a generic handler for Keptn Cloud Events that logs the CloudEvent
+func GenericLogKeptnCloudEventHandler(myKeptn *keptnv2.Keptn, incomingEvent cloudevents.Event, data interface{}) error {
+ log.Printf("Handling %s Event: %s", incomingEvent.Type(), incomingEvent.Context.GetID())
+ log.Printf("CloudEvent %T: %v", data, data)
+
+ return nil
+}
+
+// OldHandleConfigureMonitoringEvent handles old configure-monitoring events
+// TODO: add in your handler code
+func OldHandleConfigureMonitoringEvent(myKeptn *keptnv2.Keptn, incomingEvent cloudevents.Event, data *keptn.ConfigureMonitoringEventData) error {
+ log.Printf("Handling old configure-monitoring Event: %s", incomingEvent.Context.GetID())
+
+ return nil
+}
+
+// HandleConfigureMonitoringTriggeredEvent handles configure-monitoring.triggered events
+// TODO: add in your handler code
+func HandleConfigureMonitoringTriggeredEvent(myKeptn *keptnv2.Keptn, incomingEvent cloudevents.Event, data *keptnv2.ConfigureMonitoringTriggeredEventData) error {
+ log.Printf("Handling configure-monitoring.triggered Event: %s", incomingEvent.Context.GetID())
+
+ return nil
+}
+
+// HandleDeploymentTriggeredEvent handles deployment.triggered events
+// TODO: add in your handler code
+func HandleDeploymentTriggeredEvent(myKeptn *keptnv2.Keptn, incomingEvent cloudevents.Event, data *keptnv2.DeploymentTriggeredEventData) error {
+ log.Printf("Handling deployment.triggered Event: %s", incomingEvent.Context.GetID())
+
+ return nil
+}
+
+// HandleTestTriggeredEvent handles test.triggered events
+// TODO: add in your handler code
+func HandleTestTriggeredEvent(myKeptn *keptnv2.Keptn, incomingEvent cloudevents.Event, data *keptnv2.TestTriggeredEventData) error {
+ log.Printf("Handling test.triggered Event: %s", incomingEvent.Context.GetID())
+
+ return nil
+}
+
+// HandleApprovalTriggeredEvent handles approval.triggered events
+// TODO: add in your handler code
+func HandleApprovalTriggeredEvent(myKeptn *keptnv2.Keptn, incomingEvent cloudevents.Event, data *keptnv2.ApprovalTriggeredEventData) error {
+ log.Printf("Handling approval.triggered Event: %s", incomingEvent.Context.GetID())
+
+ return nil
+}
+
+// HandleEvaluationTriggeredEvent handles evaluation.triggered events
+// TODO: add in your handler code
+func HandleEvaluationTriggeredEvent(myKeptn *keptnv2.Keptn, incomingEvent cloudevents.Event, data *keptnv2.EvaluationTriggeredEventData) error {
+ log.Printf("Handling evaluation.triggered Event: %s", incomingEvent.Context.GetID())
+
+ return nil
+}
+
+// HandleReleaseTriggeredEvent handles release.triggered events
+// TODO: add in your handler code
+func HandleReleaseTriggeredEvent(myKeptn *keptnv2.Keptn, incomingEvent cloudevents.Event, data *keptnv2.ReleaseTriggeredEventData) error {
+ log.Printf("Handling release.triggered Event: %s", incomingEvent.Context.GetID())
+
+ return nil
+}
+
+// HandleGetSliTriggeredEvent handles get-sli.triggered events if SLIProvider == keptn-service-template-go
+// This function acts as an example showing how to handle get-sli events by sending .started and .finished events
+// TODO: adapt handler code to your needs
+func HandleGetSliTriggeredEvent(myKeptn *keptnv2.Keptn, incomingEvent cloudevents.Event, data *keptnv2.GetSLITriggeredEventData) error {
+ log.Printf("Handling get-sli.triggered Event: %s", incomingEvent.Context.GetID())
+
+ // Step 1 - Do we need to do something?
+ // Lets make sure we are only processing an event that really belongs to our SLI Provider
+ if data.GetSLI.SLIProvider != "keptn-service-template-go" {
+ log.Printf("Not handling get-sli event as it is meant for %s", data.GetSLI.SLIProvider)
+ return nil
+ }
+
+ // Step 2 - Send out a get-sli.started CloudEvent
+ // The get-sli.started cloud-event is new since Keptn 0.8.0 and is required to be send when the task is started
+ _, err := myKeptn.SendTaskStartedEvent(data, ServiceName)
+
+ if err != nil {
+ errMsg := fmt.Sprintf("Failed to send task started CloudEvent (%s), aborting...", err.Error())
+ log.Println(errMsg)
+ return err
+ }
+
+ // Step 4 - prep-work
+ // Get any additional input / configuration data
+ // - Labels: get the incoming labels for potential config data and use it to pass more labels on result, e.g: links
+ // - SLI.yaml: if your service uses SLI.yaml to store query definitions for SLIs get that file from Keptn
+ labels := data.Labels
+ if labels == nil {
+ labels = make(map[string]string)
+ }
+ testRunID := labels["testRunId"]
+
+ // Step 5 - get SLI Config File
+ // Get SLI File from keptn-service-template-go subdirectory of the config repo - to add the file use:
+ // keptn add-resource --project=PROJECT --stage=STAGE --service=SERVICE --resource=my-sli-config.yaml --resourceUri=keptn-service-template-go/sli.yaml
+ sliFile := "keptn-service-template-go/sli.yaml"
+ sliConfigFileContent, err := myKeptn.GetKeptnResource(sliFile)
+
+ // FYI you do not need to "fail" if sli.yaml is missing, you can also assume smart defaults like we do
+ // in keptn-contrib/dynatrace-service and keptn-contrib/prometheus-service
+ if err != nil {
+ // failed to fetch sli config file
+ errMsg := fmt.Sprintf("Failed to fetch SLI file %s from config repo: %s", sliFile, err.Error())
+ log.Println(errMsg)
+ // send a get-sli.finished event with status=error and result=failed back to Keptn
+
+ _, err = myKeptn.SendTaskFinishedEvent(&keptnv2.EventData{
+ Status: keptnv2.StatusErrored,
+ Result: keptnv2.ResultFailed,
+ }, ServiceName)
+
+ return err
+ }
+
+ fmt.Println(sliConfigFileContent)
+
+ // Step 6 - do your work - iterate through the list of requested indicators and return their values
+ // Indicators: this is the list of indicators as requested in the SLO.yaml
+ // SLIResult: this is the array that will receive the results
+ indicators := data.GetSLI.Indicators
+ sliResults := []*keptnv2.SLIResult{}
+
+ for _, indicatorName := range indicators {
+ sliResult := &keptnv2.SLIResult{
+ Metric: indicatorName,
+ Value: 123.4, // ToDo: Fetch the values from your monitoring tool here
+ }
+ sliResults = append(sliResults, sliResult)
+ }
+
+ // Step 7 - add additional context via labels (e.g., a backlink to the monitoring or CI tool)
+ labels["Link to Data Source"] = "https://mydatasource/myquery?testRun=" + testRunID
+
+ // Step 8 - Build get-sli.finished event data
+ getSliFinishedEventData := &keptnv2.GetSLIFinishedEventData{
+ EventData: keptnv2.EventData{
+ Status: keptnv2.StatusSucceeded,
+ Result: keptnv2.ResultPass,
+ },
+ GetSLI: keptnv2.GetSLIFinished{
+ IndicatorValues: sliResults,
+ Start: data.GetSLI.Start,
+ End: data.GetSLI.End,
+ },
+ }
+
+ _, err = myKeptn.SendTaskFinishedEvent(getSliFinishedEventData, ServiceName)
+
+ if err != nil {
+ errMsg := fmt.Sprintf("Failed to send task finished CloudEvent (%s), aborting...", err.Error())
+ log.Println(errMsg)
+ return err
+ }
+
+ return nil
+}
+
+// HandleProblemEvent handles two problem events:
+// - ProblemOpenEventType = "sh.keptn.event.problem.open"
+// - ProblemEventType = "sh.keptn.events.problem"
+// TODO: add in your handler code
+func HandleProblemEvent(myKeptn *keptnv2.Keptn, incomingEvent cloudevents.Event, data *keptn.ProblemEventData) error {
+ log.Printf("Handling Problem Event: %s", incomingEvent.Context.GetID())
+
+ // Deprecated since Keptn 0.7.0 - use the HandleActionTriggeredEvent instead
+
+ return nil
+}
+
+// HandleActionTriggeredEvent handles action.triggered events
+// TODO: add in your handler code
+func HandleActionTriggeredEvent(myKeptn *keptnv2.Keptn, incomingEvent cloudevents.Event, data *keptnv2.ActionTriggeredEventData) error {
+ log.Printf("Handling Action Triggered Event: %s", incomingEvent.Context.GetID())
+ log.Printf("Action=%s\n", data.Action.Action)
+
+ // check if action is supported
+ if data.Action.Action == "action-xyz" {
+ // -----------------------------------------------------
+ // 1. Send Action.Started Cloud-Event
+ // -----------------------------------------------------
+ myKeptn.SendTaskStartedEvent(data, ServiceName)
+
+ // -----------------------------------------------------
+ // 2. Implement your remediation action here
+ // -----------------------------------------------------
+ time.Sleep(5 * time.Second) // Example: Wait 5 seconds. Maybe the problem fixes itself.
+
+ // -----------------------------------------------------
+ // 3. Send Action.Finished Cloud-Event
+ // -----------------------------------------------------
+ myKeptn.SendTaskFinishedEvent(&keptnv2.EventData{
+ Status: keptnv2.StatusSucceeded, // alternative: keptnv2.StatusErrored
+ Result: keptnv2.ResultPass, // alternative: keptnv2.ResultFailed
+ Message: "Successfully sleeped!",
+ }, ServiceName)
+
+ } else {
+ log.Printf("Retrieved unknown action %s, skipping...", data.Action.Action)
+ return nil
+ }
+ return nil
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..6d01b29
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,12 @@
+module example.com/keptn-service-template-go
+
+go 1.16
+
+require (
+ github.com/cloudevents/sdk-go/v2 v2.3.1
+ github.com/kelseyhightower/envconfig v1.4.0
+ github.com/keptn/go-utils v0.8.4
+ github.com/mitchellh/mapstructure v1.2.2 // indirect
+ github.com/onsi/ginkgo v1.12.0 // indirect
+ github.com/onsi/gomega v1.9.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..48cded7
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,226 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
+github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudevents/sdk-go/v2 v2.3.1 h1:QRTu0yRA4FbznjRSds0/4Hy6cVYpWV2wInlNJSHWAtw=
+github.com/cloudevents/sdk-go/v2 v2.3.1/go.mod h1:4fO2UjPMYYR1/7KPJQCwTPb0lFA8zYuitkUpAZFSY1Q=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
+github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
+github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
+github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
+github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
+github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
+github.com/go-openapi/analysis v0.19.4 h1:1TjOzrWkj+9BrjnM1yPAICbaoC0FyfD49oVkTBrSSa0=
+github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
+github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
+github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
+github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY=
+github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
+github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
+github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
+github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
+github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
+github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
+github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
+github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
+github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
+github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
+github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
+github.com/go-openapi/loads v0.19.2 h1:rf5ArTHmIJxyV5Oiks+Su0mUens1+AjpkPoWr5xFRcI=
+github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
+github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
+github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
+github.com/go-openapi/runtime v0.19.4 h1:csnOgcgAiuGoM/Po7PEpKDoNulCcF3FGbSnbHfxgjMI=
+github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
+github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
+github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
+github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
+github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc=
+github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
+github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
+github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
+github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
+github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
+github.com/go-openapi/strfmt v0.19.3 h1:eRfyY5SkaNJCAwmmMcADjY31ow9+N7MCLW7oRkbsINA=
+github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
+github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
+github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
+github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
+github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
+github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
+github.com/go-openapi/validate v0.19.4 h1:LGjO87VyXY3bIKjlYpXSFuLRG2mTeuYlZyeNwFFWpyM=
+github.com/go-openapi/validate v0.19.4/go.mod h1:BkJ0ZmXui7yB0bJXWSXgLPNTmbLVeX/3D1xn/N9mMUM=
+github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
+github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=
+github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
+github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
+github.com/keptn/go-utils v0.8.4 h1:v+Wlpw5iD8hauW1nnAt7yKF5+QYEKibljQSozgKouQY=
+github.com/keptn/go-utils v0.8.4/go.mod h1:8cm/j/fPLl+qpSIDyyw5WVqT7W6W/ZlsAtMv8dLKtPU=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac h1:+2b6iGRJe3hvV/yVXrd41yVEjxuFHxasJqDhkIjS4gk=
+github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac/go.mod h1:Frd2bnT3w5FB5q49ENTfVlztJES+1k/7lyWX2+9gq/M=
+github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
+github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
+github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
+github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
+github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
+github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
+github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
+go.mongodb.org/mongo-driver v1.1.1 h1:Sq1fR+0c58RME5EoqKdjkiQAmPjmfHlZOoRI6fTUOcs=
+go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
+go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/helm/.helmignore b/helm/.helmignore
new file mode 100644
index 0000000..0e8a0eb
--- /dev/null
+++ b/helm/.helmignore
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/helm/Chart.yaml b/helm/Chart.yaml
new file mode 100644
index 0000000..23f555d
--- /dev/null
+++ b/helm/Chart.yaml
@@ -0,0 +1,6 @@
+apiVersion: v2
+appVersion: 0.8.0
+description: Helm Chart for the keptn keptn-service-template-go
+name: keptn-service-template-go
+type: application
+version: 0.8.0
diff --git a/helm/README.md b/helm/README.md
new file mode 100644
index 0000000..a841961
--- /dev/null
+++ b/helm/README.md
@@ -0,0 +1,44 @@
+
+keptn-service-template-go
+===========
+
+Helm Chart for the keptn keptn-service-template-go
+
+
+## Configuration
+
+The following table lists the configurable parameters of the keptn-service-template-go chart and their default values.
+
+| Parameter | Description | Default |
+| ------------------------ | ----------------------- | -------------- |
+| `keptnservice.image.repository` | Container image name | `"docker.io/keptnsandbox/keptn-service-template-go"` |
+| `keptnservice.image.pullPolicy` | Kubernetes image pull policy | `"IfNotPresent"` |
+| `keptnservice.image.tag` | Container tag | `""` |
+| `keptnservice.service.enabled` | Creates a kubernetes service for the keptn-service-template-go | `true` |
+| `distributor.stageFilter` | Sets the stage this helm service belongs to | `""` |
+| `distributor.serviceFilter` | Sets the service this helm service belongs to | `""` |
+| `distributor.projectFilter` | Sets the project this helm service belongs to | `""` |
+| `distributor.image.repository` | Container image name | `"docker.io/keptn/distributor"` |
+| `distributor.image.pullPolicy` | Kubernetes image pull policy | `"IfNotPresent"` |
+| `distributor.image.tag` | Container tag | `""` |
+| `remoteControlPlane.enabled` | Enables remote execution plane mode | `false` |
+| `remoteControlPlane.api.protocol` | Used protocol (http, https | `"https"` |
+| `remoteControlPlane.api.hostname` | Hostname of the control plane cluster (and port) | `""` |
+| `remoteControlPlane.api.apiValidateTls` | Defines if the control plane certificate should be validated | `true` |
+| `remoteControlPlane.api.token` | Keptn api token | `""` |
+| `imagePullSecrets` | Secrets to use for container registry credentials | `[]` |
+| `serviceAccount.create` | Enables the service account creation | `true` |
+| `serviceAccount.annotations` | Annotations to add to the service account | `{}` |
+| `serviceAccount.name` | The name of the service account to use. | `""` |
+| `podAnnotations` | Annotations to add to the created pods | `{}` |
+| `podSecurityContext` | Set the pod security context (e.g. fsgroups) | `{}` |
+| `securityContext` | Set the security context (e.g. runasuser) | `{}` |
+| `resources` | Resource limits and requests | `{}` |
+| `nodeSelector` | Node selector configuration | `{}` |
+| `tolerations` | Tolerations for the pods | `[]` |
+| `affinity` | Affinity rules | `{}` |
+
+
+
+
+
diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl
new file mode 100644
index 0000000..2967d68
--- /dev/null
+++ b/helm/templates/_helpers.tpl
@@ -0,0 +1,63 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "keptn-service.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "keptn-service.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "keptn-service.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "keptn-service.labels" -}}
+helm.sh/chart: {{ include "keptn-service.chart" . }}
+{{ include "keptn-service.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+
+{{/*
+Selector labels
+*/}}
+{{- define "keptn-service.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "keptn-service.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "keptn-service.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "keptn-service.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml
new file mode 100644
index 0000000..a8a7e40
--- /dev/null
+++ b/helm/templates/deployment.yaml
@@ -0,0 +1,101 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ include "keptn-service.fullname" . }}
+ labels:
+ {{- include "keptn-service.labels" . | nindent 4 }}
+
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ {{- include "keptn-service.selectorLabels" . | nindent 6 }}
+ template:
+ metadata:
+ {{- with .Values.podAnnotations }}
+ annotations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ labels:
+ {{- include "keptn-service.selectorLabels" . | nindent 8 }}
+ spec:
+ {{- with .Values.imagePullSecrets }}
+ imagePullSecrets:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ serviceAccountName: {{ include "keptn-service.serviceAccountName" . }}
+ securityContext:
+ {{- toYaml .Values.podSecurityContext | nindent 8 }}
+ containers:
+ - name: keptn-service
+ securityContext:
+ {{- toYaml .Values.securityContext | nindent 12 }}
+ {{- if .Values.image }}
+ image: {{ .Values.image }} # use image from .Values.image (e.g., when starting via skaffold)
+ {{- else }}
+ image: "{{ .Values.keptnservice.image.repository }}:{{ .Values.keptnservice.image.tag | default .Chart.AppVersion }}"
+ {{- end }}
+ imagePullPolicy: {{ .Values.keptnservice.image.pullPolicy }}
+ ports:
+ - containerPort: 80
+ env:
+ - name: CONFIGURATION_SERVICE
+ value: "http://localhost:8081/configuration-service"
+ - name: env
+ value: 'production'
+ livenessProbe:
+ httpGet:
+ path: /health
+ port: 10999
+ resources:
+ {{- toYaml .Values.resources | nindent 12 }}
+ - name: distributor
+ image: "{{ .Values.distributor.image.repository }}:{{ .Values.distributor.image.tag | default .Chart.AppVersion }}"
+ livenessProbe:
+ httpGet:
+ path: /health
+ port: 10999
+ initialDelaySeconds: 5
+ periodSeconds: 5
+ imagePullPolicy: Always
+ ports:
+ - containerPort: 8080
+ resources:
+ requests:
+ memory: "32Mi"
+ cpu: "50m"
+ limits:
+ memory: "128Mi"
+ cpu: "500m"
+ env:
+ - name: PUBSUB_TOPIC
+ value: 'sh.keptn.event.test.triggered'
+ - name: PUBSUB_RECIPIENT
+ value: '127.0.0.1'
+ - name: STAGE_FILTER
+ value: "{{ .Values.distributor.stageFilter }}"
+ - name: PROJECT_FILTER
+ value: "{{ .Values.distributor.projectFilter }}"
+ - name: SERVICE_FILTER
+ value: "{{ .Values.distributor.serviceFilter }}"
+ {{- if .Values.remoteControlPlane.enabled }}
+ - name: KEPTN_API_ENDPOINT
+ value: "{{ .Values.remoteControlPlane.api.protocol }}://{{ .Values.remoteControlPlane.api.hostname }}/api"
+ - name: KEPTN_API_TOKEN
+ value: "{{ .Values.remoteControlPlane.api.token }}"
+ - name: HTTP_SSL_VERIFY
+ value: "{{ .Values.remoteControlPlane.api.apiValidateTls | default "true" }}"
+ {{- end }}
+
+ {{- with .Values.nodeSelector }}
+ nodeSelector:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.affinity }}
+ affinity:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.tolerations }}
+ tolerations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
diff --git a/helm/templates/service.yaml b/helm/templates/service.yaml
new file mode 100644
index 0000000..8bb05ca
--- /dev/null
+++ b/helm/templates/service.yaml
@@ -0,0 +1,15 @@
+{{- if .Values.keptnservice.service.enabled -}}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ include "keptn-service.fullname" . }}
+ labels:
+ {{- include "keptn-service.labels" . | nindent 4 }}
+spec:
+ type: ClusterIP
+ ports:
+ - port: 8080
+ protocol: TCP
+ selector:
+ {{- include "keptn-service.selectorLabels" . | nindent 4 }}
+ {{- end }}
\ No newline at end of file
diff --git a/helm/templates/serviceaccount.yaml b/helm/templates/serviceaccount.yaml
new file mode 100644
index 0000000..cff7450
--- /dev/null
+++ b/helm/templates/serviceaccount.yaml
@@ -0,0 +1,30 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ include "keptn-service.serviceAccountName" . }}
+ labels:
+ {{- include "keptn-service.labels" . | nindent 4 }}
+ {{- with .Values.serviceAccount.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: keptn-{{ .Release.Namespace }}-keptn-service-cluster-admin
+ labels:
+ {{- include "keptn-service.labels" . | nindent 4 }}
+ {{- with .Values.serviceAccount.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+subjects:
+ - kind: ServiceAccount
+ name: {{ include "keptn-service.serviceAccountName" . }}
+ namespace: {{ .Release.Namespace }}
+roleRef:
+ kind: ClusterRole
+ name: cluster-admin
+ apiGroup: rbac.authorization.k8s.io
diff --git a/helm/templates/tests/test-api-connection.yaml b/helm/templates/tests/test-api-connection.yaml
new file mode 100644
index 0000000..08294b8
--- /dev/null
+++ b/helm/templates/tests/test-api-connection.yaml
@@ -0,0 +1,19 @@
+{{- if .Values.remoteControlPlane.enabled -}}
+apiVersion: v1
+kind: Pod
+metadata:
+ name: "{{ include "keptn-service.fullname" . }}-test-api-connection"
+ labels:
+ {{- include "keptn-service.labels" . | nindent 4 }}
+ annotations:
+ "helm.sh/hook": test
+spec:
+ containers:
+ - name: wget
+ image: busybox
+ args:
+ - wget
+ - '--header=x-token: {{ .Values.remoteControlPlane.api.token }}'
+ - {{ .Values.remoteControlPlane.api.protocol }}://{{ .Values.remoteControlPlane.api.hostname }}/api/v1/metadata
+ restartPolicy: Never
+ {{- end -}}
\ No newline at end of file
diff --git a/helm/values.schema.json b/helm/values.schema.json
new file mode 100644
index 0000000..e533dbb
--- /dev/null
+++ b/helm/values.schema.json
@@ -0,0 +1,110 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "properties": {
+ "remoteControlPlane": {
+ "type": "object",
+ "required": [
+ "enabled"
+ ],
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ }
+ },
+ "if": {
+ "properties": {
+ "enabled": {
+ "const": true
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "api": {
+ "type": "object",
+ "required": [
+ "protocol",
+ "hostname",
+ "token"
+ ],
+ "properties": {
+ "hostname": {
+ "pattern": "^[a-z0-9][a-z0-9-.]{2,63}$"
+ },
+ "protocol": {
+ "enum": [
+ "http",
+ "https"
+ ]
+ },
+ "apiValidateTls": {
+ "type": "boolean"
+ },
+ "token": {
+ "pattern": "^[A-Za-z0-9-.]{2,63}$"
+ }
+ }
+ }
+ }
+ }
+ },
+ "keptnservice": {
+ "type": "object",
+ "required": [
+ "image"
+ ],
+ "properties": {
+ "image": {
+ "properties": {
+ "repository": {
+ "pattern": "^[a-z][a-z0-9-./]{2,63}$"
+ },
+ "pullPolicy": {
+ "enum": [
+ "IfNotPresent",
+ "Always"
+ ]
+ }
+ }
+ },
+ "service": {
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+ },
+ "distributor": {
+ "type": "object",
+ "required": [
+ "image"
+ ],
+ "properties": {
+ "image": {
+ "properties": {
+ "repository": {
+ "pattern": "[a-z][a-z0-9-./]{2,63}$"
+ },
+ "pullPolicy": {
+ "enum": [
+ "IfNotPresent",
+ "Always"
+ ]
+ }
+ }
+ },
+ "stageFilter": {
+ "pattern": "^$|[A-Za-z0-9-.]{2,63}$"
+ },
+ "serviceFilter": {
+ "pattern": "^$|[A-Za-z0-9-.]{2,63}$"
+ },
+ "projectFilter": {
+ "pattern": "^$|[A-Za-z0-9-.]{2,63}$"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/helm/values.yaml b/helm/values.yaml
new file mode 100644
index 0000000..0bd1f67
--- /dev/null
+++ b/helm/values.yaml
@@ -0,0 +1,59 @@
+keptnservice:
+ image:
+ repository: docker.io/keptnsandbox/keptn-service-template-go # Container Image Name
+ pullPolicy: Always # Kubernetes Image Pull Policy
+ tag: "dev" # Container Tag
+ service:
+ enabled: true # Creates a Kubernetes Service for the keptn-service-template-go
+
+distributor:
+ stageFilter: "" # Sets the stage this helm service belongs to
+ serviceFilter: "" # Sets the service this helm service belongs to
+ projectFilter: "" # Sets the project this helm service belongs to
+ image:
+ repository: docker.io/keptn/distributor # Container Image Name
+ pullPolicy: IfNotPresent # Kubernetes Image Pull Policy
+ tag: "" # Container Tag
+
+remoteControlPlane:
+ enabled: true # Enables remote execution plane mode
+ api:
+ protocol: "http" # Used Protocol (http, https)
+ hostname: "" # Hostname of the control plane cluster (and Port)
+ apiValidateTls: true # Defines if the control plane certificate should be validated
+ token: "" # Keptn API Token
+
+imagePullSecrets: [] # Secrets to use for container registry credentials
+
+serviceAccount:
+ create: true # Enables the service account creation
+ annotations: {} # Annotations to add to the service account
+ name: "" # The name of the service account to use.
+
+podAnnotations: {} # Annotations to add to the created pods
+
+podSecurityContext: {} # Set the pod security context (e.g. fsGroups)
+ # fsGroup: 2000
+
+securityContext: {} # Set the security context (e.g. runAsUser)
+# readOnlyRootFilesystem: true
+# runAsNonRoot: true
+# runAsUser: 1000
+
+resources: # Resource limits and requests
+ # We usually recommend not to specify default resources and to leave this as a conscious
+ # choice for the user. This also increases chances charts run on environments with little
+ # resources, such as Minikube. If you do want to specify resources, uncomment the following
+ # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+ # limits:
+ # cpu: 100m
+ # memory: 128Mi
+ requests:
+ cpu: 100m
+ memory: 128Mi
+
+nodeSelector: {} # Node selector configuration
+
+tolerations: [] # Tolerations for the pods
+
+affinity: {} # Affinity rules
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..85f8421
--- /dev/null
+++ b/main.go
@@ -0,0 +1,539 @@
+package main
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "log"
+ "os"
+
+ cloudevents "github.com/cloudevents/sdk-go/v2" // make sure to use v2 cloudevents here
+ "github.com/kelseyhightower/envconfig"
+ keptnlib "github.com/keptn/go-utils/pkg/lib"
+ keptn "github.com/keptn/go-utils/pkg/lib/keptn"
+ keptnv2 "github.com/keptn/go-utils/pkg/lib/v0_2_0"
+)
+
+var keptnOptions = keptn.KeptnOpts{}
+
+type envConfig struct {
+ // Port on which to listen for cloudevents
+ Port int `envconfig:"RCV_PORT" default:"8080"`
+ // Path to which cloudevents are sent
+ Path string `envconfig:"RCV_PATH" default:"/"`
+ // Whether we are running locally (e.g., for testing) or on production
+ Env string `envconfig:"ENV" default:"local"`
+ // URL of the Keptn configuration service (this is where we can fetch files from the config repo)
+ ConfigurationServiceUrl string `envconfig:"CONFIGURATION_SERVICE" default:""`
+}
+
+// ServiceName specifies the current services name (e.g., used as source when sending CloudEvents)
+const ServiceName = "keptn-service-template-go"
+
+/**
+ * Parses a Keptn Cloud Event payload (data attribute)
+ */
+func parseKeptnCloudEventPayload(event cloudevents.Event, data interface{}) error {
+ err := event.DataAs(data)
+ if err != nil {
+ log.Fatalf("Got Data Error: %s", err.Error())
+ return err
+ }
+ return nil
+}
+
+/**
+ * This method gets called when a new event is received from the Keptn Event Distributor
+ * Depending on the Event Type will call the specific event handler functions, e.g: handleDeploymentFinishedEvent
+ * See https://github.com/keptn/spec/blob/0.2.0-alpha/cloudevents.md for details on the payload
+ */
+func processKeptnCloudEvent(ctx context.Context, event cloudevents.Event) error {
+ // create keptn handler
+ log.Printf("Initializing Keptn Handler")
+ myKeptn, err := keptnv2.NewKeptn(&event, keptnOptions)
+ if err != nil {
+ return errors.New("Could not create Keptn Handler: " + err.Error())
+ }
+
+ log.Printf("gotEvent(%s): %s - %s", event.Type(), myKeptn.KeptnContext, event.Context.GetID())
+
+ if err != nil {
+ log.Printf("failed to parse incoming cloudevent: %v", err)
+ return err
+ }
+
+ /**
+ * CloudEvents types in Keptn 0.8.0 follow the following pattern:
+ * - sh.keptn.event.${EVENTNAME}.triggered
+ * - sh.keptn.event.${EVENTNAME}.started
+ * - sh.keptn.event.${EVENTNAME}.status.changed
+ * - sh.keptn.event.${EVENTNAME}.finished
+ *
+ * For convenience, types can be generated using the following methods:
+ * - triggered: keptnv2.GetTriggeredEventType(${EVENTNAME}) (e.g,. keptnv2.GetTriggeredEventType(keptnv2.DeploymentTaskName))
+ * - started: keptnv2.GetStartedEventType(${EVENTNAME}) (e.g,. keptnv2.GetStartedEventType(keptnv2.DeploymentTaskName))
+ * - status.changed: keptnv2.GetStatusChangedEventType(${EVENTNAME}) (e.g,. keptnv2.GetStatusChangedEventType(keptnv2.DeploymentTaskName))
+ * - finished: keptnv2.GetFinishedEventType(${EVENTNAME}) (e.g,. keptnv2.GetFinishedEventType(keptnv2.DeploymentTaskName))
+ *
+ * Keptn reserves some Cloud Event types, please read up on that here: https://keptn.sh/docs/0.8.x/manage/shipyard/
+ *
+ * For those Cloud Events the keptn/go-utils library conveniently provides several data structures
+ * and strings in github.com/keptn/go-utils/pkg/lib/v0_2_0, e.g.:
+ * - deployment: DeploymentTaskName, DeploymentTriggeredEventData, DeploymentStartedEventData, DeploymentFinishedEventData
+ * - test: TestTaskName, TestTriggeredEventData, TestStartedEventData, TestFinishedEventData
+ * - ... (they all follow the same pattern)
+ *
+ *
+ * In most cases you will be interested in processing .triggered events (e.g., sh.keptn.event.deployment.triggered),
+ * which you an achieve as follows:
+ * if event.type() == keptnv2.GetTriggeredEventType(keptnv2.DeploymentTaskName) { ... }
+ *
+ * Processing the event payload can be achieved as follows:
+ *
+ * eventData := &keptnv2.DeploymentTriggeredEventData{}
+ * parseKeptnCloudEventPayload(event, eventData)
+ *
+ * See https://github.com/keptn/spec/blob/0.2.0-alpha/cloudevents.md for more details of Keptn Cloud Events and their payload
+ * Also, see https://github.com/keptn-sandbox/echo-service/blob/a90207bc119c0aca18368985c7bb80dea47309e9/pkg/events.go as an example how to create your own CloudEvents
+ **/
+
+ /**
+ * The following code presents a very generic implementation of processing almost all possible
+ * Cloud Events that are retrieved by this service.
+ * Please follow the documentation provided above for more guidance on the different types.
+ * Feel free to delete parts that you don't need.
+ **/
+ switch event.Type() {
+
+ // -------------------------------------------------------
+ // sh.keptn.event.project.create - Note: This is due to change
+ case keptnv2.GetStartedEventType(keptnv2.ProjectCreateTaskName): // sh.keptn.event.project.create.started
+ log.Printf("Processing Project.Create.Started Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.ProjectCreateStartedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+ case keptnv2.GetFinishedEventType(keptnv2.ProjectCreateTaskName): // sh.keptn.event.project.create.finished
+ log.Printf("Processing Project.Create.Finished Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.ProjectCreateFinishedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+ // -------------------------------------------------------
+ // sh.keptn.event.service.create - Note: This is due to change
+ case keptnv2.GetStartedEventType(keptnv2.ServiceCreateTaskName): // sh.keptn.event.service.create.started
+ log.Printf("Processing Service.Create.Started Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.ServiceCreateStartedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+ case keptnv2.GetFinishedEventType(keptnv2.ServiceCreateTaskName): // sh.keptn.event.service.create.finished
+ log.Printf("Processing Service.Create.Finished Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.ServiceCreateFinishedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+
+ // -------------------------------------------------------
+ // sh.keptn.event.approval
+ case keptnv2.GetTriggeredEventType(keptnv2.ApprovalTaskName): // sh.keptn.event.approval.triggered
+ log.Printf("Processing Approval.Triggered Event")
+
+ eventData := &keptnv2.ApprovalTriggeredEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ return HandleApprovalTriggeredEvent(myKeptn, event, eventData)
+ case keptnv2.GetStartedEventType(keptnv2.ApprovalTaskName): // sh.keptn.event.approval.started
+ log.Printf("Processing Approval.Started Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.ApprovalStartedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+ case keptnv2.GetFinishedEventType(keptnv2.ApprovalTaskName): // sh.keptn.event.approval.finished
+ log.Printf("Processing Approval.Finished Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.ApprovalFinishedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+
+ // -------------------------------------------------------
+ // sh.keptn.event.deployment
+ case keptnv2.GetTriggeredEventType(keptnv2.DeploymentTaskName): // sh.keptn.event.deployment.triggered
+ log.Printf("Processing Deployment.Triggered Event")
+
+ eventData := &keptnv2.DeploymentTriggeredEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ return HandleDeploymentTriggeredEvent(myKeptn, event, eventData)
+ case keptnv2.GetStartedEventType(keptnv2.DeploymentTaskName): // sh.keptn.event.deployment.started
+ log.Printf("Processing Deployment.Started Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.DeploymentStartedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+ case keptnv2.GetFinishedEventType(keptnv2.DeploymentTaskName): // sh.keptn.event.deployment.finished
+ log.Printf("Processing Deployment.Finished Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.DeploymentFinishedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+
+ // -------------------------------------------------------
+ // sh.keptn.event.test
+ case keptnv2.GetTriggeredEventType(keptnv2.TestTaskName): // sh.keptn.event.test.triggered
+ log.Printf("Processing Test.Triggered Event")
+
+ eventData := &keptnv2.TestTriggeredEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ return HandleTestTriggeredEvent(myKeptn, event, eventData)
+ case keptnv2.GetStartedEventType(keptnv2.TestTaskName): // sh.keptn.event.test.started
+ log.Printf("Processing Test.Started Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.TestStartedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+ case keptnv2.GetFinishedEventType(keptnv2.TestTaskName): // sh.keptn.event.test.finished
+ log.Printf("Processing Test.Finished Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.TestFinishedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+
+ // -------------------------------------------------------
+ // sh.keptn.event.evaluation
+ case keptnv2.GetTriggeredEventType(keptnv2.EvaluationTaskName): // sh.keptn.event.evaluation.triggered
+ log.Printf("Processing Evaluation.Triggered Event")
+
+ eventData := &keptnv2.EvaluationTriggeredEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ return HandleEvaluationTriggeredEvent(myKeptn, event, eventData)
+ case keptnv2.GetStartedEventType(keptnv2.EvaluationTaskName): // sh.keptn.event.evaluation.started
+ log.Printf("Processing Evaluation.Started Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.EvaluationStartedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+ case keptnv2.GetFinishedEventType(keptnv2.EvaluationTaskName): // sh.keptn.event.evaluation.finished
+ log.Printf("Processing Evaluation.Finished Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.EvaluationFinishedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+
+ // -------------------------------------------------------
+ // sh.keptn.event.release
+ case keptnv2.GetTriggeredEventType(keptnv2.ReleaseTaskName): // sh.keptn.event.release.triggered
+ log.Printf("Processing Release.Triggered Event")
+
+ eventData := &keptnv2.ReleaseTriggeredEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ return HandleReleaseTriggeredEvent(myKeptn, event, eventData)
+ case keptnv2.GetStartedEventType(keptnv2.ReleaseTaskName): // sh.keptn.event.release.started
+ log.Printf("Processing Release.Started Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.ReleaseStartedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+ case keptnv2.GetStatusChangedEventType(keptnv2.ReleaseTaskName): // sh.keptn.event.release.status.changed
+ log.Printf("Processing Release.Status.Changed Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.ReleaseStatusChangedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+ case keptnv2.GetFinishedEventType(keptnv2.ReleaseTaskName): // sh.keptn.event.release.finished
+ log.Printf("Processing Release.Finished Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.ReleaseFinishedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+
+ // -------------------------------------------------------
+ // sh.keptn.event.get-action (sent by shipyard-controller to extract a remediation action from remediations.yaml)
+ case keptnv2.GetTriggeredEventType(keptnv2.GetActionTaskName): // sh.keptn.event.action.triggered
+ log.Printf("Processing Get-Action.Triggered Event")
+
+ eventData := &keptnv2.GetActionTriggeredEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+ case keptnv2.GetStartedEventType(keptnv2.GetActionTaskName): // sh.keptn.event.action.started
+ log.Printf("Processing Get-Action.Started Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.GetActionStartedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+ case keptnv2.GetFinishedEventType(keptnv2.GetActionTaskName): // sh.keptn.event.action.finished
+ log.Printf("Processing Get-Action.Finished Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.GetActionFinishedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+
+ // -------------------------------------------------------
+ // sh.keptn.event.action (sent by shipyard-controller to execute a remediation action)
+ case keptnv2.GetTriggeredEventType(keptnv2.ActionTaskName): // sh.keptn.event.action.triggered
+ log.Printf("Processing Action.Triggered Event")
+
+ eventData := &keptnv2.ActionTriggeredEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ return HandleActionTriggeredEvent(myKeptn, event, eventData)
+ case keptnv2.GetStartedEventType(keptnv2.ActionTaskName): // sh.keptn.event.action.started
+ log.Printf("Processing Action.Started Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.ActionStartedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+ case keptnv2.GetFinishedEventType(keptnv2.ActionTaskName): // sh.keptn.event.action.finished
+ log.Printf("Processing Action.Finished Event")
+ // Please note: Processing .started, .status.changed and .finished events is only recommended when you want to
+ // notify an external service (e.g., for logging purposes).
+
+ eventData := &keptnv2.ActionFinishedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+
+ // -------------------------------------------------------
+ // sh.keptn.event.problem / problem.open
+ // Please Note: This is deprecated; Use Action.Triggered instead
+ case keptnlib.ProblemEventType: // sh.keptn.event.problem - e.g., sent by Dynatrace to Keptn Api
+ log.Printf("Processing problem Event")
+ log.Printf("Subscribing to a problem.open or problem event is not recommended since Keptn 0.7. Please subscribe to event of type: sh.keptn.event.action.triggered")
+
+ eventData := &keptnlib.ProblemEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ return HandleProblemEvent(myKeptn, event, eventData)
+
+ // -------------------------------------------------------
+ // sh.keptn.event.get-sli (sent by lighthouse-service to fetch SLIs from the sli provider)
+ case keptnv2.GetTriggeredEventType(keptnv2.GetSLITaskName): // sh.keptn.event.get-sli.triggered
+ log.Printf("Processing Get-SLI.Triggered Event")
+
+ eventData := &keptnv2.GetSLITriggeredEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ return HandleGetSliTriggeredEvent(myKeptn, event, eventData)
+ case keptnv2.GetStartedEventType(keptnv2.GetSLITaskName): // sh.keptn.event.get-sli.started
+ log.Printf("Processing Get-SLI.Started Event")
+
+ eventData := &keptnv2.GetSLIStartedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+ case keptnv2.GetFinishedEventType(keptnv2.GetSLITaskName): // sh.keptn.event.get-sli.finished
+ log.Printf("Processing Get-SLI.Finished Event")
+
+ eventData := &keptnv2.GetSLIFinishedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+
+ // -------------------------------------------------------
+ // sh.keptn.event.configure-monitoring
+ case keptnlib.ConfigureMonitoringEventType: // old configure-monitoring CE; compatibility with 0.8.0-alpha
+ log.Printf("Processing old configure-monitoring Event")
+ log.Printf("Note: This will be deprecated with Keptn 0.8.0")
+
+ eventData := &keptnlib.ConfigureMonitoringEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Handle old configure-monitoring event
+ return OldHandleConfigureMonitoringEvent(myKeptn, event, eventData)
+
+ case keptnv2.GetTriggeredEventType(keptnv2.ConfigureMonitoringTaskName): // sh.keptn.event.configure-monitoring.triggered
+ log.Printf("Processing configure-monitoring.Triggered Event")
+
+ eventData := &keptnv2.ConfigureMonitoringTriggeredEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ return HandleConfigureMonitoringTriggeredEvent(myKeptn, event, eventData)
+ case keptnv2.GetStartedEventType(keptnv2.ConfigureMonitoringTaskName): // sh.keptn.event.configure-monitoring.started
+ log.Printf("Processing configure-monitoring.Started Event")
+
+ eventData := &keptnv2.ConfigureMonitoringStartedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+ case keptnv2.GetFinishedEventType(keptnv2.ConfigureMonitoringTaskName): // sh.keptn.event.configure-monitoring.finished
+ log.Printf("Processing configure-monitoring.Finished Event")
+
+ eventData := &keptnv2.ConfigureMonitoringFinishedEventData{}
+ parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+
+ // -------------------------------------------------------
+ // your custom cloud event, e.g., sh.keptn.your-event
+ // see https://github.com/keptn-sandbox/echo-service/blob/a90207bc119c0aca18368985c7bb80dea47309e9/pkg/events.go
+ // for an example on how to generate your own CloudEvents and structs
+ case keptnv2.GetTriggeredEventType("your-event"): // sh.keptn.event.your-event.triggered
+ log.Printf("Processing your-event.triggered Event")
+
+ // eventData := &keptnv2.YourEventTriggeredEventData{}
+ // parseKeptnCloudEventPayload(event, eventData)
+
+ break
+ case keptnv2.GetStartedEventType(keptnv2.ConfigureMonitoringTaskName): // sh.keptn.event.your-event.started
+ log.Printf("Processing your-event.started Event")
+
+ // eventData := &keptnv2.YourEventStartedEventData{}
+ // parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ // return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+
+ break
+ case keptnv2.GetFinishedEventType(keptnv2.ConfigureMonitoringTaskName): // sh.keptn.event.your-event.finished
+ log.Printf("Processing your-event.finished Event")
+
+ // eventData := &keptnv2.YourEventFinishedEventData{}
+ // parseKeptnCloudEventPayload(event, eventData)
+
+ // Just log this event
+ // return GenericLogKeptnCloudEventHandler(myKeptn, event, eventData)
+
+ break
+ }
+
+ // Unknown Event -> Throw Error!
+ var errorMsg string
+ errorMsg = fmt.Sprintf("Unhandled Keptn Cloud Event: %s", event.Type())
+
+ log.Print(errorMsg)
+ return errors.New(errorMsg)
+}
+
+/**
+ * Usage: ./main
+ * no args: starts listening for cloudnative events on localhost:port/path
+ *
+ * Environment Variables
+ * env=runlocal -> will fetch resources from local drive instead of configuration service
+ */
+func main() {
+ var env envConfig
+ if err := envconfig.Process("", &env); err != nil {
+ log.Fatalf("Failed to process env var: %s", err)
+ }
+
+ os.Exit(_main(os.Args[1:], env))
+}
+
+/**
+ * Opens up a listener on localhost:port/path and passes incoming requets to gotEvent
+ */
+func _main(args []string, env envConfig) int {
+ // configure keptn options
+ if env.Env == "local" {
+ log.Println("env=local: Running with local filesystem to fetch resources")
+ keptnOptions.UseLocalFileSystem = true
+ }
+
+ keptnOptions.ConfigurationServiceURL = env.ConfigurationServiceUrl
+
+ log.Println("Starting keptn-service-template-go...")
+ log.Printf(" on Port = %d; Path=%s", env.Port, env.Path)
+
+ ctx := context.Background()
+ ctx = cloudevents.WithEncodingStructured(ctx)
+
+ log.Printf("Creating new http handler")
+
+ // configure http server to receive cloudevents
+ p, err := cloudevents.NewHTTP(cloudevents.WithPath(env.Path), cloudevents.WithPort(env.Port))
+
+ if err != nil {
+ log.Fatalf("failed to create client, %v", err)
+ }
+ c, err := cloudevents.NewClient(p)
+ if err != nil {
+ log.Fatalf("failed to create client, %v", err)
+ }
+
+ log.Printf("Starting receiver")
+ log.Fatal(c.StartReceiver(ctx, processKeptnCloudEvent))
+
+ return 0
+}
diff --git a/releasenotes/releasenotes_develop.md b/releasenotes/releasenotes_develop.md
new file mode 100644
index 0000000..c9faad2
--- /dev/null
+++ b/releasenotes/releasenotes_develop.md
@@ -0,0 +1,8 @@
+# Release Notes develop
+
+## New Features
+
+## Fixed Issues
+
+## Known Limitations
+
diff --git a/skaffold.yaml b/skaffold.yaml
new file mode 100644
index 0000000..59e36ad
--- /dev/null
+++ b/skaffold.yaml
@@ -0,0 +1,13 @@
+apiVersion: skaffold/v1beta13
+kind: Config
+build:
+ artifacts:
+ - image: keptnsandbox/keptn-service-template-go # Todo: Replace this with your image name
+ docker:
+ dockerfile: Dockerfile
+ buildArgs:
+ debugBuild: true
+deploy:
+ kubectl:
+ manifests:
+ - deploy/service.yaml
diff --git a/test-events/action.triggered.json b/test-events/action.triggered.json
new file mode 100644
index 0000000..08897aa
--- /dev/null
+++ b/test-events/action.triggered.json
@@ -0,0 +1,30 @@
+{
+ "type": "sh.keptn.event.action.triggered",
+ "specversion": "1.0",
+ "source": "test-events",
+ "id": "f2b878d3-03c0-4e8f-bc3f-454bc1b3d79b",
+ "time": "2019-06-07T07:02:15.64489Z",
+ "contenttype": "application/json",
+ "shkeptncontext": "08735340-6f9e-4b32-97ff-3b6c292bc50i",
+ "data": {
+ "project": "sockshop",
+ "stage": "dev",
+ "service": "carts",
+ "labels": {
+ "testId": "4711",
+ "buildId": "build-17",
+ "owner": "JohnDoe"
+ },
+ "status": "succeeded",
+ "result": "pass",
+
+ "action": {
+ "name": "my action name",
+ "action": "action-xyz",
+ "description": "so something as defined in remediation.yaml",
+ "value" : "1"
+ },
+ "problem": {
+ }
+ }
+ }
\ No newline at end of file
diff --git a/test-events/deployment.triggered.json b/test-events/deployment.triggered.json
new file mode 100644
index 0000000..3a4205b
--- /dev/null
+++ b/test-events/deployment.triggered.json
@@ -0,0 +1,30 @@
+{
+ "type": "sh.keptn.event.deployment.triggered",
+ "specversion": "1.0",
+ "source": "test-events",
+ "id": "f2b878d3-03c0-4e8f-bc3f-454bc1b3d79a",
+ "time": "2019-06-07T07:02:15.64489Z",
+ "contenttype": "application/json",
+ "shkeptncontext": "08735340-6f9e-4b32-97ff-3b6c292bc50g",
+ "data": {
+ "project": "sockshop",
+ "stage": "dev",
+ "service": "carts",
+ "labels": {
+ "testId": "4711",
+ "buildId": "build-17",
+ "owner": "JohnDoe"
+ },
+ "status": "succeeded",
+ "result": "pass",
+
+ "configurationChange": {
+ "values": {
+ "image": "docker.io/keptnexamples/carts:0.11.2"
+ }
+ },
+ "deployment": {
+ "deploymentstrategy": "blue_green_service"
+ }
+ }
+ }
\ No newline at end of file
diff --git a/test-events/evaluation.triggered.json b/test-events/evaluation.triggered.json
new file mode 100644
index 0000000..e009eb6
--- /dev/null
+++ b/test-events/evaluation.triggered.json
@@ -0,0 +1,28 @@
+{
+ "data": {
+ "deployment": {
+ "deploymentNames": null
+ },
+ "evaluation": {
+ "end": "2021-01-15T15:09:45.000Z",
+ "start": "2021-01-15T15:04:45.000Z"
+ },
+ "labels": null,
+ "message": "",
+ "project": "sockshop",
+ "result": "",
+ "service": "carts",
+ "stage": "staging",
+ "status": "",
+ "test": {
+ "end": "",
+ "start": ""
+ }
+ },
+ "id": "5afa758e-697c-4496-8deb-4d7cc1c93967",
+ "source": "test-events",
+ "specversion": "1.0",
+ "time": "2021-01-15T15:09:46.006Z",
+ "type": "sh.keptn.event.evaluation.triggered",
+ "shkeptncontext": "da7aec34-78c4-4182-a2c8-51eb88f5871d"
+ }
\ No newline at end of file
diff --git a/test-events/get-sli.triggered.json b/test-events/get-sli.triggered.json
new file mode 100644
index 0000000..f32b2e7
--- /dev/null
+++ b/test-events/get-sli.triggered.json
@@ -0,0 +1,27 @@
+{
+ "data": {
+ "get-sli": {
+ "customFilters": [],
+ "end": "2021-01-15T15:09:45.000Z",
+ "indicators": [
+ "response_time_p95",
+ "some_other_metric"
+ ],
+ "sliProvider": "keptn-service-template-go",
+ "start": "2021-01-15T15:04:45.000Z"
+ },
+ "labels": null,
+ "message": "",
+ "project": "sockshop",
+ "result": "",
+ "service": "carts",
+ "stage": "staging",
+ "status": ""
+ },
+ "id": "409539ae-c0b9-436e-abc6-c257292e28ff",
+ "source": "test-events",
+ "specversion": "1.0",
+ "time": "2021-01-15T15:09:46.144Z",
+ "type": "sh.keptn.event.get-sli.triggered",
+ "shkeptncontext": "da7aec34-78c4-4182-a2c8-51eb88f5871d"
+ }
\ No newline at end of file
diff --git a/test-events/release.triggered.json b/test-events/release.triggered.json
new file mode 100644
index 0000000..28234f4
--- /dev/null
+++ b/test-events/release.triggered.json
@@ -0,0 +1,25 @@
+{
+ "type": "sh.keptn.event.release.triggered",
+ "specversion": "1.0",
+ "source": "test-events",
+ "id": "f2b878d3-03c0-4e8f-bc3f-454bc1b3d79b",
+ "time": "2019-06-07T07:02:15.64489Z",
+ "contenttype": "application/json",
+ "shkeptncontext": "08735340-6f9e-4b32-97ff-3b6c292bc50h",
+ "data": {
+ "project": "sockshop",
+ "stage": "dev",
+ "service": "carts",
+ "labels": {
+ "testId": "4711",
+ "buildId": "build-17",
+ "owner": "JohnDoe"
+ },
+ "status": "succeeded",
+ "result": "pass",
+
+ "deployment": {
+ "deploymentstrategy": "blue_green_service"
+ }
+ }
+ }
\ No newline at end of file
diff --git a/test-events/send-test-events.http b/test-events/send-test-events.http
new file mode 100644
index 0000000..1d1a24b
--- /dev/null
+++ b/test-events/send-test-events.http
@@ -0,0 +1,56 @@
+# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection) or
+# paste cURL into the file and request will be converted to HTTP Request format.
+#
+# Following HTTP Request Live Templates are available:
+# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
+# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
+# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
+
+# send service.create.finished test-event
+POST http://localhost:8080/
+Accept: application/json
+Cache-Control: no-cache
+Content-Type: application/cloudevents+json
+
+< ./service.create.finished.json
+###
+
+# send action.triggered test-event
+POST http://localhost:8080/
+Accept: application/json
+Cache-Control: no-cache
+Content-Type: application/cloudevents+json
+
+< ./action.triggered.json
+
+###
+
+# send deployment.triggered test-event
+POST http://localhost:8080/
+Accept: application/json
+Cache-Control: no-cache
+Content-Type: application/cloudevents+json
+
+< ./deployment.triggered.json
+
+###
+
+# send evaluation.triggered test-event
+POST http://localhost:8080/
+Accept: application/json
+Cache-Control: no-cache
+Content-Type: application/cloudevents+json
+
+< ./evaluation.triggered.json
+
+###
+
+# send get-sli.triggered test-event
+POST http://localhost:8080/
+Accept: application/json
+Cache-Control: no-cache
+Content-Type: application/cloudevents+json
+
+< ./get-sli.triggered.json
+
+###
\ No newline at end of file
diff --git a/test-events/service.create.finished.json b/test-events/service.create.finished.json
new file mode 100644
index 0000000..dc59670
--- /dev/null
+++ b/test-events/service.create.finished.json
@@ -0,0 +1,24 @@
+{
+ "type": "sh.keptn.event.service.create.finished",
+ "specversion": "1.0",
+ "source": "test-events",
+ "id": "f2b878d3-03c0-4e8f-bc3f-454bc1b3d79d",
+ "time": "2019-06-07T07:02:15.64489Z",
+ "contenttype": "application/json",
+ "shkeptncontext": "08735340-6f9e-4b32-97ff-3b6c292bc50f",
+ "data": {
+ "project": "sockshop",
+ "service": "carts",
+ "labels": {
+ "testId": "4711",
+ "buildId": "build-17",
+ "owner": "JohnDoe"
+ },
+ "status": "succeeded",
+ "result": "pass",
+
+ "helm": {
+ "chart": "H4sIFAAAAAAA/ykAK2FIUjBjSE02THk5NWIzVjBkUzVpWlM5Nk9WVjZNV2xqYW5keVRRbz1IZWxtAOxYS2/jNhDOWb9i4Mu2B8uUH7sLAXsIHHc33dgxHCdAURQGI41jNpTIkpSxRur/XlAvy5adFGgeCOq5OJoXOdTMx08JqDK61V9QZdwVjfjJCwghhHzsdtNfQsjuL/HaH0+8zieP9Hrtttc5IV67QzonQF5iM7uSaEPVCfnPa+0W906ESnaDSjMR+7D0nBB1oJg06fMpfEMeQWCbA+ZCgUa1ZAFC2jROTCP087+XRQ7iei5x3rqqo/xbyeZ/SXmC+qUA4Kn5b3vt3fnvdXrH+X8NYRG9Qx9CEdyjcplo3aM0Mf6gkeSoW2l7+MT1PNdzFErOAtoXSWx88Bwn9fUdAKnEnxgYH7QI7vVCSAdAmywzLu1DhhwFXACEKLlYRWgzhUxhYN76JP6fks2/wUhyalC3Nu/l+dDgifnv2mHfnv9et0OO8/8a0mw2wamSACqlbi09557FoQ9nZTs4ERoaUkPtvFevfi0xsLocHbQPDw/g3mQ3ShUyYL1OYUFRg3crGwKgBOcsvruWITWYqQAi+uM6pkvKOL3l6ANJ9WYl0YdJNSAFFo6BESqLjagJFhf0FrkuklEpN6hT9HnuXVQEuS/fityJLVXufXKLKkaD2gJmdhaVmlNUdAuulBZ9KJbF2tDY4mLjkQTNmm0zpbBeNx5ZIBCRFHGKslSyRxwlVaYp5vs2koP7EytFNKZ3GDZvVz58t3GP+JZs8eEBftKSMwMNv1Eum95JP7szD/6GEOc04QYaKTyZRnGeRddZCURsKItRla+uudWhxUbyu65aYaraqizVjBPOx4KzYOXD+XwkzFihtkNQeElh78XysVhvYYwslem1aEQguA/T/riiLzc8Fsr48Jl8JqUV42U979l01r++ml4OZ+PJZTVTStx8aOQn+sWWln3M5QMN6zUoXLLSOkGOVKM7yZWZQ6qza235jGhkDwfSPpjlffDlkQbJPfPWrXtuerrwtCRhj5/JXkvutWn3uuuBUShObnx5NhudDge7Z/aLEpFfUQLMGfJwgvNtba4fU7PwoVEghmuT1xc7G4wvLn8bDkbTl1gzQ6ffP2wq/vBHfQ/9y9H09Hw0mMzOh6dfa3t4qv2LNN8H4+nIdtuvg/70QJKs0fImOZTiarpnF89w+lrSYM8ryBcdTG7O+/uKTxGhHnY9uhicXn1LAweT2fXkYk+snW6/1UpiOx0LN/9thrhsUck2STlbYoxaj5W4xWpBNsFXNNs1yrS41gIpN4ttSx0dAFjMDKP8DDldXWEg4lD78LHqIVExEZY2r2ozLEKRmI2xVxoV0pC9x21rkagAdXV7nEXM6N1eCmRi8xIS7RgijIRa+dAm3c9DVjEq/CtBfSBT73Aij7S7Q/Ye/g2yy/9zhH7WfwU8+f3/aZf/dz+R4/f/q0iN/5fU/yrrBGeLJdeIv1VmzLzPE21QnVt6ktEja6sxowIdsocaQTJU3aHZ4kUlxc9oeoWUv/XhHeUoRznKO5Z/AgAA///9mYwrABwAAA=="
+ }
+ }
+ }
\ No newline at end of file