Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ result-*

# generic
dist/

# Go
go.work
Empty file added config/.gitkeep
Empty file.
9 changes: 7 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,14 @@ The operator creates and manages all necessary Kubernetes resources for these co

```
multigres-operator/
├── api/v1alpha1/ # CRD definitions
├── go.mod # Root module
├── cmd/multigres-operator/ # Main entry point
└── internal/ # Controller and resource builders
└── pkg/ # Multi-module structure
├── cluster-handler/ # Cluster orchestration (separate module)
├── data-handler/ # Data plane management (separate module)
└── resource-handler/ # Component resources (separate module)

Note: go.work can be created locally for development. It is in .gitignore
```

### Documentation and Configuration
Expand Down
96 changes: 64 additions & 32 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,36 +40,68 @@

```
multigres-operator/
├── api/v1alpha1/ # CRD definitions and types
├── go.mod # Root module (primarily for cmd)
├── cmd/multigres-operator/ # Main entry point
├── internal/
│ ├── controller/ # Main reconciler and component reconcilers
│ │ ├── etcd/
│ │ ├── multigateway/
│ │ ├── multiorch/
│ │ └── multipooler/
│ ├── resources/ # Pure resource builder functions
│ ├── webhook/ # Admission webhooks (defaulting, validation)
│ └── testutil/ # Test helpers and utilities
├── pkg/
│ ├── cluster-handler/ # Cluster-level orchestration (separate Go module)
│ │ ├── go.mod
│ │ └── controller/
│ │ └── multigrescluster/ # MultigresCluster reconciler
│ ├── data-handler/ # Data plane management (separate Go module)
│ │ ├── go.mod
│ │ └── controller/
│ │ └── cell/ # Cell reconciler
│ └── resource-handler/ # Component resources (separate Go module)
│ ├── go.mod
│ └── controller/
│ ├── multigateway/
│ ├── multiorch/
│ ├── multipooler/
│ └── etcd/
├── config/ # Kubernetes manifests for operator deployment
├── docs/ # Architecture, conventions, and development guides
└── plans/ # Planning documents
```

### API Layer (`api/v1alpha1`)
- **Purpose**: Defines Multigres custom resource schema
- **Components**: MultigresSpec, MultigresStatus, component specs (MultiGatewaySpec, MultiOrchSpec, MultiPoolerSpec, EtcdSpec)
- **Validation**: Kubebuilder markers for OpenAPI validation and defaults

### Controller Layer (`internal/controller`)
- **MultigresReconciler**: Main controller - manages lifecycle, finalizers, status aggregation
- **Component Reconcilers**: etcd, multigateway, multiorch, multipooler reconcilers run in parallel
- **Responsibilities**: Create/update resources, check component health, update status
Note: go.work file can be created locally for development convenience. It is in .gitignore.
```

### Resource Layer (`internal/resources`)
- **Pure Functions**: Build Kubernetes manifests (Deployments, StatefulSets, Services, HPAs)
- **Label Management**: Consistent label generation for resource selection
- **No Side Effects**: Same input always produces same output
### Multi-Module Architecture

The operator is organized into three independent Go modules with clear separation of concerns. Developers can use **Go workspaces** locally (`go.work`) for easier cross-module development, though this file is not committed to the repository:

#### Cluster Handler Module (`pkg/cluster-handler`)
- **Purpose**: High-level cluster orchestration
- **Responsibilities**:
- Manages MultigresCluster custom resource
- Coordinates creation of child resources (MultiGateway, MultiOrch, MultiPooler, Etcd, Cell)
- Aggregates status from child resources
- Handles cluster-wide lifecycle (finalizers, upgrades)
- **Independence**: Can be tested and versioned separately from resource handlers

#### Data Handler Module (`pkg/data-handler`)
- **Purpose**: Data plane management and topology
- **Responsibilities**:
- Manages Cell custom resource (data topology abstraction)
- Handles data plane configuration and routing
- Coordinates with Vitess/Multigres data components
- **Independence**: Data plane logic isolated from control plane and resource management

#### Resource Handler Module (`pkg/resource-handler`)
- **Purpose**: Individual component resource management
- **Responsibilities**:
- Manages component CRDs: MultiGateway, MultiOrch, MultiPooler, Etcd
- Creates and reconciles Kubernetes resources (Deployments, StatefulSets, Services, HPAs)
- Implements pure resource builder functions
- Component-specific health checking and status reporting
- **Independence**: Component reconcilers can evolve independently of cluster orchestration

### Benefits of Multi-Module Structure

- **Clear Boundaries**: Each module has distinct responsibilities and can be understood independently
- **Independent Testing**: Unit and integration tests scoped to each module
- **Parallel Development**: Teams can work on different modules without conflicts
- **Selective Imports**: Main binary only imports what it needs from each module
- **Version Flexibility**: Modules can evolve at different paces (though currently developed in lockstep)

## Core Components

Expand All @@ -85,14 +117,14 @@ The operator follows a standard Kubernetes reconciliation pattern:

### Component Reconcilers

Each Multigres component has its own reconciler:
The **resource-handler** module contains individual reconcilers for each Multigres component:

- **etcd Reconciler**: Manages StatefulSet for etcd cluster, headless and client Services
- **multigateway Reconciler**: Manages Deployment, Service, and optional HPA for MultiGateway
- **multiorch Reconciler**: Manages Deployment and optional HPA for MultiOrch
- **multipooler Reconciler**: Manages StatefulSet with multi-container pods (pooler, pgctld, postgres), and optional HPA
- **etcd Reconciler** (`pkg/resource-handler/controller/etcd`): Manages StatefulSet for etcd cluster, headless and client Services
- **multigateway Reconciler** (`pkg/resource-handler/controller/multigateway`): Manages Deployment, Service, and optional HPA for MultiGateway
- **multiorch Reconciler** (`pkg/resource-handler/controller/multiorch`): Manages Deployment and optional HPA for MultiOrch
- **multipooler Reconciler** (`pkg/resource-handler/controller/multipooler`): Manages StatefulSet with multi-container pods (pooler, pgctld, postgres), and optional HPA

All component reconcilers run in parallel.
All component reconcilers run in parallel and are independent of each other.

### Resource Builders

Expand Down Expand Up @@ -146,8 +178,8 @@ Current preference is init container pattern (same as Istio, NGINX Ingress), but
## Technology Stack

### Language and Runtime
- **Language**: Go 1.24+
- **Key Features**: Concurrency, interfaces, strong typing
- **Language**: Go 1.25+
- **Key Features**: Concurrency, interfaces, strong typing, workspaces for multi-module projects

### Key Dependencies
- **Framework**: Kubebuilder v3 - scaffolding and patterns for Kubernetes operators
Expand Down
39 changes: 23 additions & 16 deletions docs/implementation-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
## Development Environment

### Language Configuration
- **Language**: Go 1.24+
- **Build System**: Make for task orchestration, Go modules for dependencies
- **Project Structure**: Standard Kubebuilder layout - `api/`, `cmd/`, `internal/`, `config/`
- **Language**: Go 1.25+
- **Build System**: Make for task orchestration, Go workspaces for multi-module management
- **Project Structure**: Multi-module workspace - `go.work`, `pkg/{module}/`, `cmd/`, `config/`
- **Linting**: golangci-lint (configured in `.golangci.yml`)

### Required Tools
- **go**: 1.24 or higher
- **go**: 1.25 or higher (workspace support required)
- **kubectl**: Kubernetes CLI for cluster interaction
- **kind**: Local Kubernetes cluster for testing (or other local cluster)
- **kubebuilder**: Optional - for regenerating CRDs and scaffolding
Expand All @@ -22,10 +22,14 @@
- **kustomize**: Included with kubectl 1.14+, used for manifest management

### Dependency Management
- **Go Modules**: `go.mod` and `go.sum` for dependency tracking
- **Version Pinning**: Pin controller-runtime and client-go to compatible versions
- **Vendor Directory**: Not used - rely on module cache
- **Updating Dependencies**: Use `go get -u` carefully, test thoroughly after updates
- **Per-Module Dependencies**: Each module (`cluster-handler`, `data-handler`, `resource-handler`) has its own `go.mod` and `go.sum`
- **Version Pinning**: Pin controller-runtime and client-go to compatible versions in each module
- **Go Workspaces (Local Only)**:
- Create `go.work` locally for easier multi-module development: `go work init ./pkg/cluster-handler ./pkg/data-handler ./pkg/resource-handler`
- `go.work` is in `.gitignore`
- **IMPORTANT**: `go.work` MUST NOT be committed - committing it would break the build and cause artifacts to ignore pinned versions
- Workspaces simplify local development by allowing cross-module references without publishing
- **Updating Dependencies**: Update in each module separately with `go get -u`, test thoroughly after updates

## Coding Standards

Expand Down Expand Up @@ -64,15 +68,17 @@ Common markers:

### Testing Strategy

**Unit Tests** (internal/resources, internal/webhook):
**Unit Tests** (per module):
- Test pure resource builder functions with table-driven tests
- Mock nothing - builders are pure functions
- Focus on correct Kubernetes manifest generation
- Run tests in each module: `cd pkg/resource-handler && go test ./...`

**Integration Tests** (internal/controller):
**Integration Tests** (per module):
- Use `envtest` - provides real Kubernetes API without full cluster
- Test reconciliation loops end-to-end
- Verify resource creation, updates, and status updates
- Each module has its own integration tests scoped to its controllers

**Test Commands**:
```bash
Expand Down Expand Up @@ -145,12 +151,13 @@ make manifests
make install
```

**Controller Changes** (`internal/controller/`):
- Run `make test` frequently during development
**Controller Changes** (`pkg/{module}/controller/`):
- Run tests in the specific module: `cd pkg/resource-handler && go test ./...`
- Integration tests catch reconciliation bugs early
- Use `make run` for quick iteration (no docker build needed)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realise that this line is unchanged - just pointing out that we should remember to create a Makefile with a run target :D

- Changes in one module don't require rebuilding others during local development

**Resource Builder Changes** (`internal/resources/`):
- Write/update table-driven tests first
- Run `make test` - very fast feedback loop
- Integration tests verify end-to-end behavior
**Module-Specific Development**:
- **Resource Handler** (`pkg/resource-handler`): Component reconcilers and resource builders
- **Cluster Handler** (`pkg/cluster-handler`): MultigresCluster orchestration logic
- **Data Handler** (`pkg/data-handler`): Cell management and data plane configuration
Empty file added internal/.gitkeep
Empty file.
5 changes: 5 additions & 0 deletions pkg/cluster-handler/controller/multigrescluster/dummy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package multigrescluster

func Dummy() string {
return "dummy string from cluster-handler's multigrescluster controller"
}
3 changes: 3 additions & 0 deletions pkg/cluster-handler/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/numtide/multigres-operator/pkg/cluster-handler

go 1.25.0
5 changes: 5 additions & 0 deletions pkg/data-handler/controller/cell/dummy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package cell

func Dummy() string {
return "dummy string from data-handler's cell controller"
}
3 changes: 3 additions & 0 deletions pkg/data-handler/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/numtide/multigres-operator/pkg/data-handler

go 1.25.0
5 changes: 5 additions & 0 deletions pkg/resource-handler/controller/multigateway/dummy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package multigateway

func Dummy() string {
return "dummy string from resource-handler's multigateway controller"
}
3 changes: 3 additions & 0 deletions pkg/resource-handler/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/numtide/multigres-operator/pkg/resource-handler

go 1.25.0
Empty file added plans/.gitkeep
Empty file.
Loading