Skip to content
Merged
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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ Apply database-optimized kernel parameters to cluster pods automatically with `s

```bash
kubectl apply -f https://raw.githubusercontent.com/keldonio/keldon-operator/main/config/crd/bases/keldon.io_databaseclusters.yaml
kubectl apply -f https://raw.githubusercontent.com/keldonio/keldon-operator/main/config/crd/bases/keldon.io_databaseversions.yaml
kubectl apply -f https://raw.githubusercontent.com/keldonio/keldon-operator/main/config/crd/bases/keldon.io_databaseimages.yaml
kubectl apply -f https://raw.githubusercontent.com/keldonio/keldon-operator/main/config/crd/bases/keldon.io_databasebackups.yaml
kubectl apply -f https://raw.githubusercontent.com/keldonio/keldon-operator/main/config/crd/bases/keldon.io_databaserestores.yaml
kubectl apply -f https://raw.githubusercontent.com/keldonio/keldon-operator/main/config/crd/bases/keldon.io_databaseprofiles.yaml
Expand All @@ -152,7 +152,7 @@ kubectl apply -f https://raw.githubusercontent.com/keldonio/keldon-operator/main
```yaml
# database-version.yaml
apiVersion: keldon.io/v1alpha1
kind: DatabaseVersion
kind: DatabaseImage
metadata:
name: cloudberry-2.1.0
spec:
Expand Down Expand Up @@ -205,7 +205,7 @@ The Keldon Operator manages five custom resources under the `keldon.io` API grou
| Kind | Short Name | Purpose |
|-------------------|------------|------------------------------------------------------|
| DatabaseCluster | `dbc` | The MPP cluster itself (coordinator, segments, etc.) |
| DatabaseVersion | `dbv` | A reference to a container image for a DB version |
| DatabaseImage | `dbi` | A reference to a container image for a DB version |
| DatabaseProfile | `dbp` | Reusable configuration defaults for clusters |
| DatabaseBackup | `dbb` | An on-demand backup to S3 storage |
| DatabaseRestore | `dbr` | A restore operation from a backup into a cluster |
Expand Down
10 changes: 8 additions & 2 deletions api/v1alpha1/databasecluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,14 @@ type DatabaseClusterSpec struct {
// +optional
Profile string `json:"profile,omitempty"`

// +optional
Version string `json:"version,omitempty"`
// databaseImage is the name of the DatabaseImage this cluster uses.
// The named DatabaseImage must exist (DatabaseImage is cluster-scoped).
// Not a container image URL — the metadata.name of a DatabaseImage
// resource.
// Example: cloudberry-2.1.0
// +required
DatabaseImage string `json:"databaseImage"`

// +optional
Coordinator CoordinatorSpec `json:"coordinator,omitempty"`
// +optional
Expand Down
207 changes: 207 additions & 0 deletions api/v1alpha1/databaseimage_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
/*
Copyright 2026.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// Paths captures the filesystem layout inside the container image
// for a given fork. Different forks place binaries and data
// directories differently; this struct tells the operator where
// to find them.
type Paths struct {
// binaryHome is the root directory containing fork binaries.
// Used informationally and for path construction by users.
// Example: /usr/local/cloudberry-db
// +required
BinaryHome string `json:"binaryHome"`

// envScript is the FULL PATH to the shell script that sets PATH
// and environment variables for the database binaries. Sourced
// by the operator before every gp* command invocation.
// Example: /usr/local/cloudberry-db/greenplum_path.sh
// +required
EnvScript string `json:"envScript"`

// coordinatorDataDir is the path to the coordinator's data
// directory on the coordinator pod.
// Example: /data0/database/coordinator/gpseg-1
// +required
CoordinatorDataDir string `json:"coordinatorDataDir"`

// segmentDataDir is the parent path for primary segment data
// directories. Each segment instance lives at
// <segmentDataDir>/gpseg<N>.
// Example: /data0/database/primary
// +required
SegmentDataDir string `json:"segmentDataDir"`

// mirrorDataDir is the parent path for mirror segment data
// directories.
// Example: /data0/database/mirror
// +required
MirrorDataDir string `json:"mirrorDataDir"`
}

// Commands captures the templated command strings the operator
// invokes for each fork. The operator renders each command with
// the following variables before execution:
//
// {{.BinaryHome}} from spec.paths.binaryHome
// {{.EnvScript}} from spec.paths.envScript
// {{.CoordinatorDataDir}} from spec.paths.coordinatorDataDir
// {{.SegmentDataDir}} from spec.paths.segmentDataDir
// {{.MirrorDataDir}} from spec.paths.mirrorDataDir
// {{.AdminUser}} from spec.adminUser
// {{.ConfigPath}} runtime, populated by operator
// {{.HostsPath}} runtime, populated by operator
type Commands struct {
// init bootstraps a new cluster. The operator writes a
// gpinitsystem config and segment hosts file to /tmp before
// invoking this command.
// Example: "gpinitsystem -a -c {{.ConfigPath}} -h {{.HostsPath}}"
// +required
Init string `json:"init"`

// start starts the cluster.
// Example: "gpstart -a"
// +required
Start string `json:"start"`

// stop stops the cluster gracefully.
// Example: "gpstop -a"
// +required
Stop string `json:"stop"`

// activateStandby promotes a standby coordinator to primary.
// Example: "gpactivatestandby -d {{.CoordinatorDataDir}} -f"
// +required
ActivateStandby string `json:"activateStandby"`

// recover repairs a down segment by syncing from its mirror.
// Example: "gprecoverseg -a"
// +required
Recover string `json:"recover"`

// rebalance restores segments to their preferred role.
// Example: "gprecoverseg -ra"
// +required
Rebalance string `json:"rebalance"`

// expand initializes gpexpand against a generated input file.
// Example: "gpexpand -i {{.ConfigPath}}"
// +required
Expand string `json:"expand"`

// expandRedistribute redistributes data after expand init.
// Example: "gpexpand -d 01:00:00 -a"
// +required
ExpandRedistribute string `json:"expandRedistribute"`
}

// DatabaseImageSpec defines the desired state of DatabaseImage.
//
// A DatabaseImage encapsulates everything the operator needs to know
// about a specific fork+version container image: which image to pull,
// what OS user runs the database inside it, where binaries and data
// live, and how to invoke fork-specific commands.
//
// The operator stays fork-agnostic — all per-fork differences are
// expressed here, not in operator code.
type DatabaseImageSpec struct {
// version is the semver of the database itself. Informational —
// the operator does not act on this value, but it surfaces in
// `kubectl get dbi` and is useful for humans and future tooling
// that wants to reason about database versions.
// Example: "2.1.0"
// +required
Version string `json:"version"`

// image is the fully qualified container image for this version.
// Example: ghcr.io/keldonio/database-cloudberry:2.1.0
// +required
Image string `json:"image"`

// adminUser is the OS user that runs the database and owns
// data directories. Replaces the historically hardcoded
// "gpadmin" throughout the operator.
// Example: "gpadmin"
// +required
AdminUser string `json:"adminUser"`

// paths describes the filesystem layout inside the image.
// +required
Paths Paths `json:"paths"`

// commands describes the templated fork-specific commands.
// +required
Commands Commands `json:"commands"`
}

// DatabaseImageStatus defines the observed state of DatabaseImage.
type DatabaseImageStatus struct {
// conditions represent the current state of the DatabaseImage.
// Typical conditions:
// - Ready: the image definition is well-formed and usable
// +listType=map
// +listMapKey=type
// +optional
Conditions []metav1.Condition `json:"conditions,omitempty"`
}

// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:scope=Cluster
// +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".spec.version"
// +kubebuilder:printcolumn:name="Image",type="string",JSONPath=".spec.image"
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
// +kubebuilder:resource:shortName=dbi

// DatabaseImage is the Schema for the databaseimages API.
//
// DatabaseImage is cluster-scoped: one named image (e.g. cloudberry-2.1.0)
// is shared across all namespaces. DatabaseClusters reference it by name
// via cluster.spec.version.
type DatabaseImage struct {
metav1.TypeMeta `json:",inline"`

// metadata is standard object metadata.
// +optional
metav1.ObjectMeta `json:"metadata,omitempty"`

// spec defines the desired state of DatabaseImage.
// +required
Spec DatabaseImageSpec `json:"spec"`

// status defines the observed state of DatabaseImage.
// +optional
Status DatabaseImageStatus `json:"status,omitempty"`
}

// +kubebuilder:object:root=true

// DatabaseImageList contains a list of DatabaseImage.
type DatabaseImageList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []DatabaseImage `json:"items"`
}

func init() {
SchemeBuilder.Register(&DatabaseImage{}, &DatabaseImageList{})
}
9 changes: 0 additions & 9 deletions api/v1alpha1/databaseprofile_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,6 @@ type BackupRetentionProfileSpec struct {
// by DatabaseClusters. Every field is optional — a cluster using this profile
// can override any individual field via its own spec.
type DatabaseProfileSpec struct {
// Image references a DatabaseVersion to use as the default for clusters
// using this profile. Clusters can still override via their own spec.version.
// +optional
Image string `json:"image,omitempty"`

// SegmentCount is the default number of segments.
// +optional
Expand All @@ -141,11 +137,6 @@ type DatabaseProfileSpec struct {
// +optional
KernelParameters map[string]string `json:"kernelParameters,omitempty"`

// PostgresConfig is the default set of postgres configuration parameters (GUCs).
// Each key is a GUC name (e.g. "shared_buffers"); each value is its desired setting.
// +optional
PostgresConfig map[string]string `json:"postgresConfig,omitempty"`

// Coordinator is the default configuration for the coordinator role.
// +optional
Coordinator *CoordinatorProfileSpec `json:"coordinator,omitempty"`
Expand Down
84 changes: 0 additions & 84 deletions api/v1alpha1/databaseversion_types.go

This file was deleted.

Loading
Loading