From fcf862c855df3a4b20dcde4b80179eb36a65e22c Mon Sep 17 00:00:00 2001 From: Mansur Uralov Date: Thu, 7 Sep 2023 17:39:35 +0200 Subject: [PATCH 1/7] Implement Send And Get Event APIs --- e2e/sink/cmd/main.go | 20 +++++ e2e/sink/go.mod | 17 ++++ e2e/sink/go.sum | 32 ++++++++ e2e/sink/internal/handler/handler.go | 115 +++++++++++++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 e2e/sink/cmd/main.go create mode 100644 e2e/sink/go.mod create mode 100644 e2e/sink/go.sum create mode 100644 e2e/sink/internal/handler/handler.go diff --git a/e2e/sink/cmd/main.go b/e2e/sink/cmd/main.go new file mode 100644 index 00000000..5fd6d062 --- /dev/null +++ b/e2e/sink/cmd/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "github.com/kyma-project/eventing-manager/sink/internal/handler" + "go.uber.org/zap" +) + +func main() { + logger, err := zap.NewProduction() + if err != nil { + panic(err) + } + defer logger.Sync() + + sHandler := handler.NewSinkHandler(logger) + err = sHandler.Start() + if err != nil { + logger.Error("failed to start SinkHandler", zap.Error(err)) + } +} diff --git a/e2e/sink/go.mod b/e2e/sink/go.mod new file mode 100644 index 00000000..843b7cc6 --- /dev/null +++ b/e2e/sink/go.mod @@ -0,0 +1,17 @@ +module github.com/kyma-project/eventing-manager/sink + +go 1.20 + +require ( + github.com/cloudevents/sdk-go/v2 v2.14.0 + github.com/gorilla/mux v1.8.0 + go.uber.org/zap v1.10.0 +) + +require ( + github.com/json-iterator/go v1.1.10 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect + go.uber.org/atomic v1.4.0 // indirect + go.uber.org/multierr v1.1.0 // indirect +) diff --git a/e2e/sink/go.sum b/e2e/sink/go.sum new file mode 100644 index 00000000..70a2a099 --- /dev/null +++ b/e2e/sink/go.sum @@ -0,0 +1,32 @@ +github.com/cloudevents/sdk-go/v2 v2.14.0 h1:Nrob4FwVgi5L4tV9lhjzZcjYqFVyJzsA56CwPaPfv6s= +github.com/cloudevents/sdk-go/v2 v2.14.0/go.mod h1:xDmKfzNjM8gBvjaF8ijFjM1VYOVUEeUfapHMUX1T5To= +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/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +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/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +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/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/e2e/sink/internal/handler/handler.go b/e2e/sink/internal/handler/handler.go new file mode 100644 index 00000000..b7b97ec2 --- /dev/null +++ b/e2e/sink/internal/handler/handler.go @@ -0,0 +1,115 @@ +package handler + +import ( + "context" + "net/http" + + "github.com/cloudevents/sdk-go/v2/binding" + "github.com/gorilla/mux" + "go.uber.org/zap" + + cev2event "github.com/cloudevents/sdk-go/v2/event" + cev2http "github.com/cloudevents/sdk-go/v2/protocol/http" +) + +type Handler interface { + Start() error +} + +type SinkHandler struct { + logger *zap.Logger + events map[string]*cev2event.Event +} + +func NewSinkHandler(logger *zap.Logger) *SinkHandler { + return &SinkHandler{ + logger: logger, + events: make(map[string]*cev2event.Event), + } +} + +func (h *SinkHandler) Start() error { + router := mux.NewRouter() + router.HandleFunc("/event", h.StoreEvent).Methods(http.MethodPost) + router.HandleFunc("/event/{eventID}", h.GetEvent).Methods(http.MethodGet) + + return http.ListenAndServe(":8080", router) +} + +func (h *SinkHandler) StoreEvent(w http.ResponseWriter, r *http.Request) { + event, err := extractCloudEventFromRequest(r) + if err != nil { + h.namedLogger().With().Error("failed to extract CloudEvent from request", zap.Error(err)) + e := writeResponse(w, http.StatusBadRequest, []byte(err.Error())) + if e != nil { + h.namedLogger().Error("failed to write response", zap.Error(e)) + } + return + } + + h.events[event.ID()] = event + err = writeResponse(w, http.StatusNoContent, []byte("")) + if err != nil { + h.namedLogger().Error("failed to write response", zap.Error(err)) + } +} + +func (h *SinkHandler) GetEvent(w http.ResponseWriter, r *http.Request) { + eventID := mux.Vars(r)["eventID"] + event, ok := h.events[eventID] + if !ok { + h.namedLogger().With().Error("event not found", zap.String("eventID", eventID)) + e := writeResponse(w, http.StatusNotFound, []byte("event not found")) + if e != nil { + h.namedLogger().Error("failed to write response", zap.Error(e)) + } + return + } + + respBody, err := event.MarshalJSON() + if err != nil { + h.namedLogger().With().Error("failed to marshal event", zap.Error(err)) + e := writeResponse(w, http.StatusInternalServerError, []byte(err.Error())) + if e != nil { + h.namedLogger().Error("failed to write response", zap.Error(e)) + } + return + } + + err = writeResponse(w, http.StatusOK, respBody) + if err != nil { + h.namedLogger().Error("failed to write response", zap.Error(err)) + } +} + +func (h *SinkHandler) namedLogger() *zap.Logger { + return h.logger.Named("sink-handler") +} + +// extractCloudEventFromRequest converts an incoming CloudEvent request to an Event. +func extractCloudEventFromRequest(r *http.Request) (*cev2event.Event, error) { + message := cev2http.NewMessageFromHttpRequest(r) + defer func() { _ = message.Finish(nil) }() + + event, err := binding.ToEvent(context.Background(), message) + if err != nil { + return nil, err + } + + err = event.Validate() + if err != nil { + return nil, err + } + return event, nil +} + +// writeResponse writes the HTTP response given the status code and response body. +func writeResponse(writer http.ResponseWriter, statusCode int, respBody []byte) error { + writer.WriteHeader(statusCode) + + if respBody == nil { + return nil + } + _, err := writer.Write(respBody) + return err +} From 8e4d8de50e2cc47fad60f002b57702816db92324 Mon Sep 17 00:00:00 2001 From: Mansur Uralov Date: Fri, 8 Sep 2023 09:40:02 +0200 Subject: [PATCH 2/7] Create GH action and Dockerfile * Create GH action workflow * Improve API Name and Makefile * Don't trigger Lint and Validation for E2E Test Sink change * Create dockerfile * Create makefile file * delete vs code files --- .github/workflows/lint.yml | 5 +- .github/workflows/sink.yml | 76 ++++++++++++++++- .github/workflows/validate.yml | 4 + e2e/sink/.dockerignore | 4 + e2e/sink/.gitignore | 38 +++++++++ e2e/sink/.vscode/launch.json | 15 ---- e2e/sink/Dockerfile | 36 +++++++++ e2e/sink/Makefile | 117 +++++++++++++++++++++++++++ e2e/sink/internal/handler/handler.go | 38 ++++++--- pkg/k8s/client.go | 3 +- 10 files changed, 306 insertions(+), 30 deletions(-) create mode 100644 e2e/sink/.dockerignore create mode 100644 e2e/sink/.gitignore delete mode 100644 e2e/sink/.vscode/launch.json create mode 100644 e2e/sink/Dockerfile create mode 100644 e2e/sink/Makefile diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4fcad9bc..c69d31ac 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,5 +1,8 @@ name: golangci-lint -on: [pull_request] +on: + pull_request: + paths-ignore: + - 'e2e/sink/**' permissions: contents: read # Optional: allow read access to pull request. Use with `only-new-issues` option. diff --git a/.github/workflows/sink.yml b/.github/workflows/sink.yml index 27196342..783badff 100644 --- a/.github/workflows/sink.yml +++ b/.github/workflows/sink.yml @@ -1,11 +1,81 @@ name: E2E Tests Sink -on: [push] +env: + # Use docker.io for Docker Hub if empty + REGISTRY: ghcr.io + # github.repository as / + IMAGE_NAME: ${{ github.repository }}/e2e-tests-sink + E2E_SINK_DIR: e2e/sink + +on: + push: + branches: + - main + tags: [ '*.*.*' ] + paths: + - 'e2e/sink/**' + - .github/workflows/sink.yml + pull_request: + branches: + - main + paths: + - 'e2e/sink/**' + - .github/workflows/sink.yml jobs: build: runs-on: ubuntu-latest + permissions: write-all + + defaults: + run: + working-directory: ${{ env.E2E_SINK_DIR }} steps: - - name: Say Hello - run: echo "Hello, World!" \ No newline at end of file + - uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: 1.19 + cache: true + + - name: Build + run: go build -v ./... + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + # if: github.event_name != 'pull_request' + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v4 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=sha + type=semver,pattern={{version}},event=tag + labels: | + org.opencontainers.image.title=E2E Tests Sink + org.opencontainers.image.description=A webserver imitating an eventing sink that receives events and stores in memory + org.opencontainers.image.url=https://github.com/kyma-project/eventing-manager/${{ env.E2E_SINK_DIR }} + + - name: Build Docker image + id: build-and-push + uses: docker/build-push-action@v4 + with: + context: ${{ env.E2E_SINK_DIR }} + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 5f0e9b53..6113c29b 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -3,8 +3,12 @@ name: validate on: push: branches: [ "main" ] + paths-ignore: + - 'e2e/sink/**' pull_request: branches: [ "main" ] + paths-ignore: + - 'e2e/sink/**' jobs: unit-tests: diff --git a/e2e/sink/.dockerignore b/e2e/sink/.dockerignore new file mode 100644 index 00000000..0f046820 --- /dev/null +++ b/e2e/sink/.dockerignore @@ -0,0 +1,4 @@ +# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file +# Ignore build and test binaries. +bin/ +testbin/ diff --git a/e2e/sink/.gitignore b/e2e/sink/.gitignore new file mode 100644 index 00000000..e500a855 --- /dev/null +++ b/e2e/sink/.gitignore @@ -0,0 +1,38 @@ + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin +testbin/* +Dockerfile.cross + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Kubernetes Generated files - skip generated files, except for vendored files + +!vendor/**/zz_generated.* + +# editor and IDE paraphernalia +.idea +*.swp +*.swo +*~ +.DS_Store +# vscode +*.code-workspace +.vscode/* + +# Binaries +bin/* + +# Vendor +vendor/ + +.env.dev diff --git a/e2e/sink/.vscode/launch.json b/e2e/sink/.vscode/launch.json deleted file mode 100644 index 7f452c9a..00000000 --- a/e2e/sink/.vscode/launch.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Launch Package", - "type": "go", - "request": "launch", - "mode": "auto", - "program": "${workspaceFolder}/cmd/main.go", - } - ] -} \ No newline at end of file diff --git a/e2e/sink/Dockerfile b/e2e/sink/Dockerfile new file mode 100644 index 00000000..676d4fae --- /dev/null +++ b/e2e/sink/Dockerfile @@ -0,0 +1,36 @@ +# Build the sink binary +FROM europe-docker.pkg.dev/kyma-project/prod/external/golang:1.21.0-alpine3.18 as builder +ARG TARGETOS +ARG TARGETARCH + +WORKDIR /workspace + +# Copy the Go Modules manifests +COPY go.mod go.mod +COPY go.sum go.sum + +# cache deps before building and copying source so that we don't need to re-download as much +# and so that source changes don't invalidate our downloaded layer +RUN go mod download + +# Copy the go source +COPY cmd/main.go cmd/main.go +COPY internal internal + +# Build +# the GOARCH has not a default value to allow the binary be built according to the host where the command +# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO +# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, +# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. +RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o sink cmd/main.go + +# Use distroless as minimal base image to package the sink binary +# Refer to https://github.com/GoogleContainerTools/distroless for more details +FROM gcr.io/distroless/static:nonroot +LABEL source = git@github.com:kyma-project/eventing-manager.git + +WORKDIR / +COPY --from=builder /workspace/sink . +USER nonroot:nonroot + +ENTRYPOINT ["/sink"] \ No newline at end of file diff --git a/e2e/sink/Makefile b/e2e/sink/Makefile new file mode 100644 index 00000000..bcbbcab7 --- /dev/null +++ b/e2e/sink/Makefile @@ -0,0 +1,117 @@ + +# Image URL to use all building/pushing image targets +IMG ?= sink:latest + +# VERIFY_IGNORE is a grep pattern to exclude files and directories from verification +VERIFY_IGNORE := /vendor\|/automock + +# FILES_TO_CHECK is a command used to determine which files should be verified +FILES_TO_CHECK = find . -type f -name "*.go" | grep -v "$(VERIFY_IGNORE)" +# DIRS_TO_CHECK is a command used to determine which directories should be verified +DIRS_TO_CHECK = go list ./... | grep -v "$(VERIFY_IGNORE)" +# DIRS_TO_IGNORE is a command used to determine which directories should not be verified +DIRS_TO_IGNORE = go list ./... | grep "$(VERIFY_IGNORE)" + +# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) +ifeq (,$(shell go env GOBIN)) +GOBIN=$(shell go env GOPATH)/bin +else +GOBIN=$(shell go env GOBIN) +endif + +# Setting SHELL to bash allows bash commands to be executed by recipes. +# Options are set to exit when a recipe line exits non-zero or a piped command fails. +SHELL = /usr/bin/env bash -o pipefail +.SHELLFLAGS = -ec + +.PHONY: all +all: build + +##@ General + +# The help target prints out all targets with their descriptions organized +# beneath their categories. The categories are represented by '##@' and the +# target descriptions by '##'. The awk commands is responsible for reading the +# entire set of makefiles included in this invocation, looking for lines of the +# file as xyz: ## something, and then pretty-format the target and help. Then, +# if there's a line with ##@ something, that gets pretty-printed as a category. +# More info on the usage of ANSI control characters for terminal formatting: +# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters +# More info on the awk command: +# http://linuxcommand.org/lc3_adv_awk.php + +.PHONY: help +help: ## Display this help. + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + + +##@ Build + +.PHONY: build +build: fmt vet + go build -o bin/sink cmd/main.go + +.PHONY: run +run: fmt vet ## Run a sink from your host. + go run ./cmd/main.go + +# If you wish built the sink image targeting other platforms you can use the --platform flag. +# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it. +# More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +.PHONY: docker-build +docker-build: ## Build docker image with the sink. + docker build -t ${IMG} . + +.PHONY: docker-push +docker-push: ## Push docker image with the sink. + docker push ${IMG} + +# PLATFORMS defines the target platforms for the sink image be build to provide support to multiple +# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: +# - able to use docker buildx . More info: https://docs.docker.com/build/buildx/ +# - have enable BuildKit, More info: https://docs.docker.com/develop/develop-images/build_enhancements/ +# - be able to push the image for your registry (i.e. if you do not inform a valid value via IMG=> then the export will fail) +# To properly provided solutions that supports more than one platform you should use this option. +PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le +.PHONY: docker-buildx +docker-buildx: ## Build and push docker image for the sink for cross-platform support + # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile + sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross + - docker buildx create --name project-v3-builder + docker buildx use project-v3-builder + - docker buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . + - docker buildx rm project-v3-builder + rm Dockerfile.cross + +##@ Deployment + +ifndef ignore-not-found + ignore-not-found = false +endif + +##@ Build Dependencies + +## Location to install dependencies to +LOCALBIN ?= $(shell pwd)/bin +$(LOCALBIN): + mkdir -p $(LOCALBIN) + +.PHONY: vet +vet: ## Run go vet against code. + go vet ./... + +.PHONY: fmt +fmt: ## Reformat files using `go fmt` + go fmt $$($(DIRS_TO_CHECK)) + +imports: ## Optimize imports + goimports -w -l $$($(FILES_TO_CHECK)) + +lint-thoroughly: + golangci-lint run + +fmt-local: ## Reformat files using `go fmt` + go fmt $$($(DIRS_TO_CHECK)) + +imports-local: ## Optimize imports + goimports -w -l $$($(FILES_TO_CHECK)) diff --git a/e2e/sink/internal/handler/handler.go b/e2e/sink/internal/handler/handler.go index b7b97ec2..9813158d 100644 --- a/e2e/sink/internal/handler/handler.go +++ b/e2e/sink/internal/handler/handler.go @@ -12,30 +12,42 @@ import ( cev2http "github.com/cloudevents/sdk-go/v2/protocol/http" ) +const ( + SampledHeader = "X-B3-Sampled" + TraceparentHeader = "Traceparent" +) + +// Handler interface for the SinkHandler. type Handler interface { Start() error } type SinkHandler struct { logger *zap.Logger - events map[string]*cev2event.Event + events map[string]*sinkEvent } func NewSinkHandler(logger *zap.Logger) *SinkHandler { return &SinkHandler{ logger: logger, - events: make(map[string]*cev2event.Event), + events: make(map[string]*sinkEvent), } } func (h *SinkHandler) Start() error { router := mux.NewRouter() - router.HandleFunc("/event", h.StoreEvent).Methods(http.MethodPost) - router.HandleFunc("/event/{eventID}", h.GetEvent).Methods(http.MethodGet) + router.HandleFunc("/events", h.StoreEvent).Methods(http.MethodPost) + router.HandleFunc("/events/{eventID}", h.GetEvent).Methods(http.MethodGet) return http.ListenAndServe(":8080", router) } +type sinkEvent struct { + // Header stores the non CE events, e.g. X-B3-Sampled and Traceparent + http.Header + cev2event.Event +} + func (h *SinkHandler) StoreEvent(w http.ResponseWriter, r *http.Request) { event, err := extractCloudEventFromRequest(r) if err != nil { @@ -47,7 +59,15 @@ func (h *SinkHandler) StoreEvent(w http.ResponseWriter, r *http.Request) { return } - h.events[event.ID()] = event + // store the event in memory + h.events[event.ID()] = &sinkEvent{ + Header: http.Header{ + SampledHeader: r.Header[SampledHeader], + TraceparentHeader: r.Header[TraceparentHeader], + }, + Event: *event, + } + err = writeResponse(w, http.StatusNoContent, []byte("")) if err != nil { h.namedLogger().Error("failed to write response", zap.Error(err)) @@ -76,6 +96,10 @@ func (h *SinkHandler) GetEvent(w http.ResponseWriter, r *http.Request) { return } + // fill the non CE headers + w.Header().Set(SampledHeader, event.Header.Get(SampledHeader)) + w.Header().Set(TraceparentHeader, event.Header.Get(TraceparentHeader)) + w.Header().Set("Content-Type", "application/json") err = writeResponse(w, http.StatusOK, respBody) if err != nil { h.namedLogger().Error("failed to write response", zap.Error(err)) @@ -96,10 +120,6 @@ func extractCloudEventFromRequest(r *http.Request) (*cev2event.Event, error) { return nil, err } - err = event.Validate() - if err != nil { - return nil, err - } return event, nil } diff --git a/pkg/k8s/client.go b/pkg/k8s/client.go index ee665c7c..2930be30 100644 --- a/pkg/k8s/client.go +++ b/pkg/k8s/client.go @@ -5,9 +5,8 @@ import ( "errors" "strings" - admissionv1 "k8s.io/api/admissionregistration/v1" - natsv1alpha1 "github.com/kyma-project/nats-manager/api/v1alpha1" + admissionv1 "k8s.io/api/admissionregistration/v1" v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" From 3170f1c1abdce87a6b3cdc9aa51dd205e1dad075 Mon Sep 17 00:00:00 2001 From: Mansur Uralov Date: Tue, 12 Sep 2023 09:27:14 +0200 Subject: [PATCH 3/7] Make Webserver Port configurable --- e2e/sink/cmd/main.go | 9 ++++++++- e2e/sink/internal/handler/handler.go | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/e2e/sink/cmd/main.go b/e2e/sink/cmd/main.go index 5fd6d062..91df19b0 100644 --- a/e2e/sink/cmd/main.go +++ b/e2e/sink/cmd/main.go @@ -1,6 +1,8 @@ package main import ( + "os" + "github.com/kyma-project/eventing-manager/sink/internal/handler" "go.uber.org/zap" ) @@ -12,8 +14,13 @@ func main() { } defer logger.Sync() + port := os.Getenv("PORT") + if port == "" { + port = "8080" // default port + } + sHandler := handler.NewSinkHandler(logger) - err = sHandler.Start() + err = sHandler.Start(port) if err != nil { logger.Error("failed to start SinkHandler", zap.Error(err)) } diff --git a/e2e/sink/internal/handler/handler.go b/e2e/sink/internal/handler/handler.go index 9813158d..2ebbeeb7 100644 --- a/e2e/sink/internal/handler/handler.go +++ b/e2e/sink/internal/handler/handler.go @@ -34,12 +34,12 @@ func NewSinkHandler(logger *zap.Logger) *SinkHandler { } } -func (h *SinkHandler) Start() error { +func (h *SinkHandler) Start(port string) error { router := mux.NewRouter() router.HandleFunc("/events", h.StoreEvent).Methods(http.MethodPost) router.HandleFunc("/events/{eventID}", h.GetEvent).Methods(http.MethodGet) - return http.ListenAndServe(":8080", router) + return http.ListenAndServe(":"+port, router) } type sinkEvent struct { From 456bc5bd72a70c914e420808237baa8dad58a3ed Mon Sep 17 00:00:00 2001 From: Mansur Uralov Date: Tue, 12 Sep 2023 09:41:51 +0200 Subject: [PATCH 4/7] Disable PR Image Upload --- .github/workflows/sink.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sink.yml b/.github/workflows/sink.yml index 783badff..ce460c65 100644 --- a/.github/workflows/sink.yml +++ b/.github/workflows/sink.yml @@ -74,8 +74,9 @@ jobs: uses: docker/build-push-action@v4 with: context: ${{ env.E2E_SINK_DIR }} - push: true + push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + load: ${{ github.event_name == 'pull_request' }} cache-from: type=gha cache-to: type=gha,mode=max From a9db8299fa371ac9cbe8bee6a9e2217d7067c88a Mon Sep 17 00:00:00 2001 From: Mansur Uralov Date: Tue, 12 Sep 2023 09:59:52 +0200 Subject: [PATCH 5/7] Add paths to ignore for linting and validation --- .github/workflows/lint.yml | 1 + .github/workflows/sink.yml | 4 ++-- .github/workflows/validate.yml | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c69d31ac..16d231a1 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -3,6 +3,7 @@ on: pull_request: paths-ignore: - 'e2e/sink/**' + - '.github/workflows/sink.yml' permissions: contents: read # Optional: allow read access to pull request. Use with `only-new-issues` option. diff --git a/.github/workflows/sink.yml b/.github/workflows/sink.yml index ce460c65..c89ee3b0 100644 --- a/.github/workflows/sink.yml +++ b/.github/workflows/sink.yml @@ -14,13 +14,13 @@ on: tags: [ '*.*.*' ] paths: - 'e2e/sink/**' - - .github/workflows/sink.yml + - '.github/workflows/sink.yml' pull_request: branches: - main paths: - 'e2e/sink/**' - - .github/workflows/sink.yml + - '.github/workflows/sink.yml' jobs: build: diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 6113c29b..b1aa4141 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -5,10 +5,12 @@ on: branches: [ "main" ] paths-ignore: - 'e2e/sink/**' + - '.github/workflows/sink.yml' pull_request: branches: [ "main" ] paths-ignore: - 'e2e/sink/**' + - '.github/workflows/sink.yml' jobs: unit-tests: From f57472d916e69841c4ac3e1e4e186c3f1a6b20a9 Mon Sep 17 00:00:00 2001 From: Mansur Uralov Date: Tue, 12 Sep 2023 14:05:37 +0200 Subject: [PATCH 6/7] Change for Review Comments * Delete path ignore from lint and validation * Clean-up Makefile * Move sink to hack/e2e --- .github/workflows/lint.yml | 6 +----- .github/workflows/sink.yml | 6 +++--- .github/workflows/validate.yml | 6 ------ {e2e => hack/e2e}/sink/.dockerignore | 0 {e2e => hack/e2e}/sink/.gitignore | 0 {e2e => hack/e2e}/sink/Dockerfile | 0 {e2e => hack/e2e}/sink/Makefile | 14 +------------- {e2e => hack/e2e}/sink/cmd/main.go | 0 {e2e => hack/e2e}/sink/go.mod | 0 {e2e => hack/e2e}/sink/go.sum | 0 {e2e => hack/e2e}/sink/internal/handler/handler.go | 3 +++ 11 files changed, 8 insertions(+), 27 deletions(-) rename {e2e => hack/e2e}/sink/.dockerignore (100%) rename {e2e => hack/e2e}/sink/.gitignore (100%) rename {e2e => hack/e2e}/sink/Dockerfile (100%) rename {e2e => hack/e2e}/sink/Makefile (93%) rename {e2e => hack/e2e}/sink/cmd/main.go (100%) rename {e2e => hack/e2e}/sink/go.mod (100%) rename {e2e => hack/e2e}/sink/go.sum (100%) rename {e2e => hack/e2e}/sink/internal/handler/handler.go (98%) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 16d231a1..4fcad9bc 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,9 +1,5 @@ name: golangci-lint -on: - pull_request: - paths-ignore: - - 'e2e/sink/**' - - '.github/workflows/sink.yml' +on: [pull_request] permissions: contents: read # Optional: allow read access to pull request. Use with `only-new-issues` option. diff --git a/.github/workflows/sink.yml b/.github/workflows/sink.yml index c89ee3b0..0df054f9 100644 --- a/.github/workflows/sink.yml +++ b/.github/workflows/sink.yml @@ -5,7 +5,7 @@ env: REGISTRY: ghcr.io # github.repository as / IMAGE_NAME: ${{ github.repository }}/e2e-tests-sink - E2E_SINK_DIR: e2e/sink + E2E_SINK_DIR: hack/e2e/sink on: push: @@ -13,13 +13,13 @@ on: - main tags: [ '*.*.*' ] paths: - - 'e2e/sink/**' + - 'hack/e2e/sink/**' - '.github/workflows/sink.yml' pull_request: branches: - main paths: - - 'e2e/sink/**' + - 'hack/e2e/sink/**' - '.github/workflows/sink.yml' jobs: diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index b1aa4141..5f0e9b53 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -3,14 +3,8 @@ name: validate on: push: branches: [ "main" ] - paths-ignore: - - 'e2e/sink/**' - - '.github/workflows/sink.yml' pull_request: branches: [ "main" ] - paths-ignore: - - 'e2e/sink/**' - - '.github/workflows/sink.yml' jobs: unit-tests: diff --git a/e2e/sink/.dockerignore b/hack/e2e/sink/.dockerignore similarity index 100% rename from e2e/sink/.dockerignore rename to hack/e2e/sink/.dockerignore diff --git a/e2e/sink/.gitignore b/hack/e2e/sink/.gitignore similarity index 100% rename from e2e/sink/.gitignore rename to hack/e2e/sink/.gitignore diff --git a/e2e/sink/Dockerfile b/hack/e2e/sink/Dockerfile similarity index 100% rename from e2e/sink/Dockerfile rename to hack/e2e/sink/Dockerfile diff --git a/e2e/sink/Makefile b/hack/e2e/sink/Makefile similarity index 93% rename from e2e/sink/Makefile rename to hack/e2e/sink/Makefile index bcbbcab7..6608b16d 100644 --- a/e2e/sink/Makefile +++ b/hack/e2e/sink/Makefile @@ -102,16 +102,4 @@ vet: ## Run go vet against code. .PHONY: fmt fmt: ## Reformat files using `go fmt` - go fmt $$($(DIRS_TO_CHECK)) - -imports: ## Optimize imports - goimports -w -l $$($(FILES_TO_CHECK)) - -lint-thoroughly: - golangci-lint run - -fmt-local: ## Reformat files using `go fmt` - go fmt $$($(DIRS_TO_CHECK)) - -imports-local: ## Optimize imports - goimports -w -l $$($(FILES_TO_CHECK)) + go fmt $$($(DIRS_TO_CHECK)) \ No newline at end of file diff --git a/e2e/sink/cmd/main.go b/hack/e2e/sink/cmd/main.go similarity index 100% rename from e2e/sink/cmd/main.go rename to hack/e2e/sink/cmd/main.go diff --git a/e2e/sink/go.mod b/hack/e2e/sink/go.mod similarity index 100% rename from e2e/sink/go.mod rename to hack/e2e/sink/go.mod diff --git a/e2e/sink/go.sum b/hack/e2e/sink/go.sum similarity index 100% rename from e2e/sink/go.sum rename to hack/e2e/sink/go.sum diff --git a/e2e/sink/internal/handler/handler.go b/hack/e2e/sink/internal/handler/handler.go similarity index 98% rename from e2e/sink/internal/handler/handler.go rename to hack/e2e/sink/internal/handler/handler.go index 2ebbeeb7..6c75f334 100644 --- a/e2e/sink/internal/handler/handler.go +++ b/hack/e2e/sink/internal/handler/handler.go @@ -49,6 +49,9 @@ type sinkEvent struct { } func (h *SinkHandler) StoreEvent(w http.ResponseWriter, r *http.Request) { + + // TODO: event received information with headers and body + event, err := extractCloudEventFromRequest(r) if err != nil { h.namedLogger().With().Error("failed to extract CloudEvent from request", zap.Error(err)) From ea88ae09ae426d88ab1ccdec95ff21d274f3059a Mon Sep 17 00:00:00 2001 From: Mansur Uralov Date: Tue, 12 Sep 2023 14:51:12 +0200 Subject: [PATCH 7/7] Add logs and improve error handling --- hack/e2e/sink/cmd/main.go | 2 +- hack/e2e/sink/internal/handler/handler.go | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/hack/e2e/sink/cmd/main.go b/hack/e2e/sink/cmd/main.go index 91df19b0..e9a9cfa0 100644 --- a/hack/e2e/sink/cmd/main.go +++ b/hack/e2e/sink/cmd/main.go @@ -22,6 +22,6 @@ func main() { sHandler := handler.NewSinkHandler(logger) err = sHandler.Start(port) if err != nil { - logger.Error("failed to start SinkHandler", zap.Error(err)) + logger.Fatal("failed to start SinkHandler", zap.Error(err)) } } diff --git a/hack/e2e/sink/internal/handler/handler.go b/hack/e2e/sink/internal/handler/handler.go index 6c75f334..95c10ada 100644 --- a/hack/e2e/sink/internal/handler/handler.go +++ b/hack/e2e/sink/internal/handler/handler.go @@ -49,9 +49,6 @@ type sinkEvent struct { } func (h *SinkHandler) StoreEvent(w http.ResponseWriter, r *http.Request) { - - // TODO: event received information with headers and body - event, err := extractCloudEventFromRequest(r) if err != nil { h.namedLogger().With().Error("failed to extract CloudEvent from request", zap.Error(err)) @@ -61,6 +58,7 @@ func (h *SinkHandler) StoreEvent(w http.ResponseWriter, r *http.Request) { } return } + h.namedLogger().With().Info("received", zap.String("event", event.String())) // store the event in memory h.events[event.ID()] = &sinkEvent{