Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions .github/workflows/e2e-tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: E2E Tests

on:
push:
branches:
- main
- master
pull_request:
branches:
- main
- master
workflow_dispatch: # Allow manual trigger

jobs:
e2e-tests:
name: Run E2E Tests
runs-on: ubuntu-latest
timeout-minutes: 30

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
cache: true

- name: Install dependencies
run: |
# Install kubebuilder for CRD generation
curl -L -o kubebuilder https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH)
chmod +x kubebuilder && sudo mv kubebuilder /usr/local/bin/

- name: Create kind cluster
uses: helm/kind-action@v1
with:
cluster_name: kind
config: scripts/kind-config-ci.yaml
wait: 300s

- name: Verify cluster
run: |
kubectl cluster-info
kubectl get nodes
kubectl get pods -A

- name: Build operator image
run: |
docker build -t example.com/vector-operator:v0.0.1 .

- name: Load image into kind
run: |
kind load docker-image example.com/vector-operator:v0.0.1 --name kind

- name: Run E2E tests
run: make test-e2e
env:
KUBECONFIG: /home/runner/.kube/config

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-results-${{ github.run_number }}
path: test/e2e/results/
retention-days: 7

- name: Publish test results
if: always()
uses: EnricoMi/publish-unit-test-result-action@v2
with:
files: test/e2e/results/run-*/reports/junit-report.xml
check_name: E2E Test Results
comment_mode: off
67 changes: 67 additions & 0 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Lint

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
golangci-lint:
name: golangci-lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v1.64
args: --timeout=5m

go-fmt:
name: go fmt
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true

- name: Check formatting
run: |
if [ -n "$(gofmt -l .)" ]; then
echo "The following files are not formatted:"
gofmt -l .
exit 1
fi

go-vet:
name: go vet
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true

- name: Run go vet
run: go vet ./...
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ testbin/*
__debug_bin

vendor

# E2E test results and artifacts
test/e2e/results/
25 changes: 25 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
run:
timeout: 5m
modules-download-mode: readonly

linters:
enable:
- gosimple
- govet
- ineffassign
- staticcheck
- unused
- errcheck
- gofmt
- goimports

linters-settings:
goimports:
local-prefixes: github.com/kaasops/vector-operator

issues:
exclude-rules:
# Exclude some linters from running on tests files
- path: _test\.go
linters:
- errcheck
86 changes: 81 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,79 @@ vet: ## Run go vet against code.
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out

# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors.
.PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up.
test-e2e:
go test ./test/e2e/ -v -ginkgo.v
# E2E test configuration
E2E_FAIL_FAST ?= false
E2E_RUN_DESCRIPTION ?=
E2E_LABEL_FILTER ?=
NAMESPACE ?= vector

.PHONY: test-e2e # Run e2e tests with comprehensive reporting (JUnit XML + JSON + logs + artifacts)
test-e2e: ginkgo
@TIMESTAMP=$$(date +%Y-%m-%d-%H%M%S); \
RUN_DIR="test/e2e/results/run-$$TIMESTAMP"; \
echo "==> Running e2e tests..."; \
echo "==> Results will be saved to: $$RUN_DIR"; \
mkdir -p "$$RUN_DIR/reports"; \
export E2E_ARTIFACTS_DIR="$$RUN_DIR/artifacts"; \
export E2E_ARTIFACTS_ENABLED=true; \
export E2E_GIT_COMMIT=$$(git rev-parse HEAD 2>/dev/null || echo "unknown"); \
export E2E_GIT_BRANCH=$$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown"); \
export E2E_GIT_DIRTY=$$(git diff --quiet 2>/dev/null || echo "dirty"; git diff --cached --quiet 2>/dev/null || echo "staged"); \
export E2E_RUN_DESCRIPTION="$(E2E_RUN_DESCRIPTION)"; \
echo "==> Git info: commit=$$E2E_GIT_COMMIT branch=$$E2E_GIT_BRANCH dirty=$$E2E_GIT_DIRTY"; \
if [ -n "$$E2E_RUN_DESCRIPTION" ]; then \
echo "==> Run description: $$E2E_RUN_DESCRIPTION"; \
fi; \
GINKGO_FLAGS="-v -timeout=30m"; \
if [ "$(E2E_FAIL_FAST)" = "true" ]; then \
echo "==> Fail-fast mode enabled (stop on first failure)"; \
GINKGO_FLAGS="$$GINKGO_FLAGS --fail-fast"; \
fi; \
if [ -n "$(E2E_LABEL_FILTER)" ]; then \
echo "==> Label filter: $(E2E_LABEL_FILTER)"; \
GINKGO_FLAGS="$$GINKGO_FLAGS --label-filter=\"$(E2E_LABEL_FILTER)\""; \
fi; \
cd test/e2e && $(GINKGO) $$GINKGO_FLAGS \
--junit-report="../../$$RUN_DIR/reports/junit-report.xml" \
--json-report="../../$$RUN_DIR/reports/report.json" \
| tee "../../$$RUN_DIR/reports/test-output.log"; \
EXIT_CODE=$$?; \
echo ""; \
echo "==> Test run complete!"; \
echo "==> All results in one place: $$RUN_DIR"; \
echo " Reports:"; \
echo " - JUnit XML: $$RUN_DIR/reports/junit-report.xml"; \
echo " - JSON: $$RUN_DIR/reports/report.json"; \
echo " - Logs: $$RUN_DIR/reports/test-output.log"; \
if [ -d "$$RUN_DIR/artifacts" ] && [ "$$(find $$RUN_DIR/artifacts -mindepth 1 -maxdepth 1 2>/dev/null | wc -l)" -gt 1 ]; then \
echo " Artifacts: $$RUN_DIR/artifacts/ (collected for failed tests)"; \
else \
echo " Artifacts: None (all tests passed)"; \
fi; \
echo ""; \
echo "Quick commands:"; \
echo " View summary: cat $$RUN_DIR/artifacts/metadata.json 2>/dev/null || echo 'All tests passed'"; \
echo " View failures: grep -A 5 'FAILED' $$RUN_DIR/reports/test-output.log 2>/dev/null || echo 'No failures'"; \
exit $$EXIT_CODE

.PHONY: test-report
test-report: ## Generate interactive HTML report from e2e test results
@echo "==> Generating test report..."
@cd test/e2e/results && python3 ../scripts/generate_report.py
@echo "==> Report generated: test/e2e/results/test_results_report.html"

.PHONY: deploy-helm-e2e
deploy-helm-e2e: manifests ## Deploy operator using Helm for e2e tests (use IMG and NAMESPACE variables)
@echo "==> Installing CRDs..."
$(KUBECTL) apply -f config/crd/bases
@echo "==> Creating namespace $(NAMESPACE)..."
$(KUBECTL) create namespace $(NAMESPACE) || true
@echo "==> Deploying operator via Helm to namespace $(NAMESPACE)..."
helm upgrade --install vector-operator ./helm/charts/vector-operator \
--namespace $(NAMESPACE) \
--set image.repository=$$(echo $(IMG) | cut -d: -f1) \
--set image.tag=$$(echo $(IMG) | cut -d: -f2) \
--wait --timeout 5m

.PHONY: lint
lint: golangci-lint ## Run golangci-lint linter
Expand Down Expand Up @@ -160,12 +229,14 @@ KUSTOMIZE ?= $(LOCALBIN)/kustomize
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint
GINKGO ?= $(LOCALBIN)/ginkgo

## Tool Versions
KUSTOMIZE_VERSION ?= v5.4.3
CONTROLLER_TOOLS_VERSION ?= v0.16.1
ENVTEST_VERSION ?= release-0.19
GOLANGCI_LINT_VERSION ?= v1.59.1
GOLANGCI_LINT_VERSION ?= v1.64.8
GINKGO_VERSION ?= v2.20.2

.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
Expand All @@ -187,6 +258,11 @@ golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
$(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,$(GOLANGCI_LINT_VERSION))

.PHONY: ginkgo
ginkgo: $(GINKGO) ## Download ginkgo locally if necessary.
$(GINKGO): $(LOCALBIN)
$(call go-install-tool,$(GINKGO),github.com/onsi/ginkgo/v2/ginkgo,$(GINKGO_VERSION))

# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist
# $1 - target path with name of binary
# $2 - package url which can be installed
Expand Down
4 changes: 3 additions & 1 deletion api/v1alpha1/clustervectorpipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package v1alpha1

import (
"context"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/kaasops/vector-operator/internal/utils/k8s"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/kaasops/vector-operator/internal/utils/k8s"
)

func (vp *ClusterVectorPipeline) GetSpec() VectorPipelineSpec {
Expand Down
4 changes: 3 additions & 1 deletion api/v1alpha1/vectorpipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package v1alpha1

import (
"context"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/kaasops/vector-operator/internal/utils/k8s"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/kaasops/vector-operator/internal/utils/k8s"
)

type VectorPipelineRole string
Expand Down
2 changes: 1 addition & 1 deletion api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 10 additions & 8 deletions cmd/event_collector/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@ import (
"errors"
"flag"
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/kaasops/vector-operator/internal/buildinfo"
"github.com/kaasops/vector-operator/internal/evcollector"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/spf13/viper"
"k8s.io/client-go/kubernetes"
"log/slog"
"net"
"net/http"
"os"
"os/signal"
ctrl "sigs.k8s.io/controller-runtime"
"strings"
"syscall"

"github.com/fsnotify/fsnotify"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/spf13/viper"
"k8s.io/client-go/kubernetes"
ctrl "sigs.k8s.io/controller-runtime"

"github.com/kaasops/vector-operator/internal/buildinfo"
"github.com/kaasops/vector-operator/internal/evcollector"
)

func main() {
Expand Down Expand Up @@ -112,7 +114,7 @@ func main() {

http.Handle("/metrics", promhttp.Handler())
go func() {
if err = http.ListenAndServe(net.JoinHostPort("", *port), nil); err != nil && !errors.Is(http.ErrServerClosed, err) {
if err = http.ListenAndServe(net.JoinHostPort("", *port), nil); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Error("failed to start http server", "error", err)
os.Exit(1)
}
Expand Down
7 changes: 4 additions & 3 deletions cmd/evgen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import (
"context"
"flag"
"fmt"
"k8s.io/apimachinery/pkg/util/rand"
ctrl "sigs.k8s.io/controller-runtime"
"sync"
"time"

"k8s.io/apimachinery/pkg/util/rand"
ctrl "sigs.k8s.io/controller-runtime"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
Expand All @@ -34,8 +35,8 @@ func main() {
wg := sync.WaitGroup{}

for i := 0; i < *workers; i++ {
wg.Add(1)
go func() {
wg.Add(1)
defer wg.Done()

clientset, err := kubernetes.NewForConfig(config)
Expand Down
Loading