Development Guide
Guide for developing and contributing to Tenant Operator.
First time here?
Start with the Quick Start guide to get familiar with the system before diving into development tooling.
Setup
Prerequisites
| Tool | Version / Notes |
|---|---|
| Go | 1.22+ |
| kubectl | Matches target cluster |
| kind or minikube | Local cluster for testing |
| Docker | Required for image builds |
| make | Used for build/test helpers |
Clone Repository
bash
git clone https://github.com/kubernetes-tenants/tenant-operator.git
cd tenant-operatorInstall Dependencies
bash
go mod downloadLocal Development
Running Locally
bash
# Install CRDs
make install
# Run controller locally (uses ~/.kube/config)
make run
# Run with debug logging
LOG_LEVEL=debug make runLocal TLS
make run disables webhook TLS because the controller runs outside the cluster and uses your local kubeconfig.
Testing Against Local Cluster
bash
# Create kind cluster
kind create cluster --name tenant-operator-dev
# Install CRDs
make install
# Run operator
make runBuilding
Build Binary
bash
# Build for current platform
make build
# Binary output: bin/manager
./bin/manager --helpBuild Container Image
bash
# Build image
make docker-build IMG=myregistry/tenant-operator:dev
# Push image
make docker-push IMG=myregistry/tenant-operator:dev
# Build multi-platform
docker buildx build --platform linux/amd64,linux/arm64 \
-t myregistry/tenant-operator:dev \
--push .Testing
Unit Tests
bash
# Run all unit tests
make test
# Run with coverage
make test-coverage
# View coverage report
go tool cover -html=cover.outIntegration Tests
bash
# Run integration tests (requires cluster)
make test-integrationCluster required
Integration and E2E suites create and mutate Kubernetes resources. Run them against disposable clusters.
E2E Tests
bash
# Create test cluster
kind create cluster --name e2e-test
# Run E2E tests
make test-e2e
# Cleanup
kind delete cluster --name e2e-testCode Quality
Linting
bash
# Run linter
make lint
# Auto-fix issues
golangci-lint run --fixFormatting
bash
# Format code
go fmt ./...
# Or use goimports
goimports -w .Generate Code
bash
# Generate CRD manifests, RBAC, etc.
make generate
# Generate DeepCopy methods
make manifestsProject Structure
tenant-operator/
├── api/v1/ # CRD types
│ ├── tenant_types.go
│ ├── tenantregistry_types.go
│ ├── tenanttemplate_types.go
│ └── common_types.go
├── internal/controller/ # Controllers
│ ├── tenant_controller.go
│ ├── tenantregistry_controller.go
│ └── tenanttemplate_controller.go
├── internal/apply/ # SSA apply engine
├── internal/database/ # Database connectors
├── internal/graph/ # Dependency graph
├── internal/readiness/ # Readiness checks
├── internal/template/ # Template engine
├── internal/metrics/ # Prometheus metrics
├── config/ # Kustomize configs
│ ├── crd/ # CRD manifests
│ ├── rbac/ # RBAC configs
│ ├── manager/ # Deployment configs
│ └── samples/ # Example CRs
├── test/ # Tests
│ ├── e2e/ # E2E tests
│ └── utils/ # Test utilities
├── docs/ # Documentation
└── cmd/ # Entry pointAdding Features
New CRD Field
- Update API types:
go
// api/v1/tenant_types.go
type TenantSpec struct {
NewField string `json:"newField,omitempty"`
}- Generate code:
bash
make generate
make manifestsUpdate controller logic
Add tests
Update documentation
New Controller
- Create controller file:
go
// internal/controller/myresource_controller.go
package controller
type MyResourceReconciler struct {
client.Client
Scheme *runtime.Scheme
}
func (r *MyResourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
// Implementation
}- Register controller:
go
// cmd/main.go
if err = (&controller.MyResourceReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
// Handle error
}- Add tests
Contributing
Contribution checklist
Always include tests, update docs, and run make lint before opening a pull request.
Workflow
- Fork repository
- Create feature branch
- Make changes
- Add tests
- Run linter:
make lint - Run tests:
make test - Commit with conventional commits
- Open Pull Request
Conventional Commits
feat: add new feature
fix: fix bug
docs: update documentation
test: add tests
refactor: refactor code
chore: maintenance tasksPull Request Template
markdown
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] Manual testing performed
## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Documentation updated
- [ ] Tests passingRelease Process
Release automation
Tags trigger the release pipeline. Confirm CI is green before pushing a new tag.
Version Bump
Update version in:
README.mdconfig/manager/kustomization.yaml
Generate changelog
Create git tag:
bash
git tag -a v1.1.0 -m "Release v1.1.0"
git push origin v1.1.0- GitHub Actions builds and publishes release
Useful Commands
bash
# Install CRDs
make install
# Uninstall CRDs
make uninstall
# Deploy operator
make deploy IMG=<image>
# Undeploy operator
make undeploy
# Run locally
make run
# Build binary
make build
# Build container
make docker-build IMG=<image>
# Run tests
make test
# Run linter
make lint
# Generate code
make generate manifests