diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88d1753..29e73d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,8 +23,28 @@ jobs: -c 'git config --global --add safe.directory /repo && gitleaks detect --source /repo --no-banner --redact' - # Added together with the Go scaffolding: - # build-test: go build ./... && go test ./... - # lint: golangci-lint + build-test: + name: Build and test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - run: go build ./... + - run: go test -race ./... + + lint: + name: Lint (golangci-lint) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - uses: golangci/golangci-lint-action@v8 + with: + version: v2.11.4 + # Added together with the protobuf schema: # proto: buf lint && buf breaking --against main diff --git a/.gitignore b/.gitignore index fb51497..5a4865d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ # Test binary, built with `go test -c` *.test +# Build output +bin/ + # Code coverage profiles and other test artifacts *.out coverage.* diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..bb8ff89 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,17 @@ +version: "2" + +linters: + default: standard + enable: + - errorlint + - gocritic + - gosec + - misspell + - revive + - unconvert + - unparam + +formatters: + enable: + - gofmt + - goimports diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..163d98e --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev) +LDFLAGS := -X main.version=$(VERSION) + +.PHONY: build test lint tidy clean + +build: ## Build the agent binary into bin/ + go build -ldflags '$(LDFLAGS)' -o bin/agent ./cmd/agent + +test: ## Run all tests with the race detector + go test -race ./... + +lint: ## Run golangci-lint + golangci-lint run + +tidy: ## Sync go.mod/go.sum + go mod tidy + +clean: + rm -rf bin diff --git a/cmd/agent/main.go b/cmd/agent/main.go new file mode 100644 index 0000000..01e6d3c --- /dev/null +++ b/cmd/agent/main.go @@ -0,0 +1,37 @@ +// Command agent is the RebuildStack runtime agent. It collects resource-usage +// rollups and workload metadata inside a Kubernetes cluster and ships them +// one-way to a backend. See docs/ for the architecture. +package main + +import ( + "context" + "log/slog" + "os" + "os/signal" + "syscall" +) + +// version is set at build time via -ldflags. +var version = "dev" + +func main() { + ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) + logger := slog.New(slog.NewJSONHandler(os.Stderr, nil)) + err := run(ctx, logger) + stop() + if err != nil { + logger.Error("agent exited with error", "error", err) + os.Exit(1) + } +} + +// run is the agent's lifecycle: it starts, works until ctx is canceled, and +// returns. Collectors and sinks will be wired in here. +// +//nolint:unparam // the error return is the contract; collectors wired in later can fail +func run(ctx context.Context, logger *slog.Logger) error { + logger.Info("agent starting", "version", version) + <-ctx.Done() + logger.Info("agent stopping") + return nil +} diff --git a/cmd/agent/main_test.go b/cmd/agent/main_test.go new file mode 100644 index 0000000..915786c --- /dev/null +++ b/cmd/agent/main_test.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "io" + "log/slog" + "testing" + "time" +) + +func TestRunStopsOnContextCancel(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + logger := slog.New(slog.NewTextHandler(io.Discard, nil)) + + done := make(chan error, 1) + go func() { done <- run(ctx, logger) }() + + cancel() + select { + case err := <-done: + if err != nil { + t.Fatalf("run returned error on graceful stop: %v", err) + } + case <-time.After(5 * time.Second): + t.Fatal("run did not stop after context cancellation") + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d41ca94 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/RebuildStackCo/runtime-agent + +go 1.26.1