Skip to content

Commit 3a701c4

Browse files
authored
Merge pull request #1688 from splunk/feature/database-controllers-cluster-controller
Postgres Cluster controller with base functionality.
2 parents dc4758e + a2770c5 commit 3a701c4

29 files changed

+1233
-256
lines changed

PROJECT

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ resources:
119119
controller: true
120120
domain: splunk.com
121121
group: enterprise
122-
kind: Database
122+
kind: PostgresCluster
123123
path: github.com/splunk/splunk-operator/api/v4
124124
version: v4
125125
- api:
@@ -128,7 +128,7 @@ resources:
128128
controller: true
129129
domain: splunk.com
130130
group: enterprise
131-
kind: DatabaseClass
131+
kind: PostgresClusterClass
132132
path: github.com/splunk/splunk-operator/api/v4
133133
version: v4
134134
- api:
@@ -137,7 +137,7 @@ resources:
137137
controller: true
138138
domain: splunk.com
139139
group: enterprise
140-
kind: PostgresCluster
140+
kind: PostgresDatabase
141141
path: github.com/splunk/splunk-operator/api/v4
142142
version: v4
143143
version: "3"

api/v3/zz_generated.deepcopy.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v4/groupversion_info.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2021.
2+
Copyright 2026.
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.

api/v4/postgrescluster_types.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
Copyright 2026.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v4
18+
19+
import (
20+
corev1 "k8s.io/api/core/v1"
21+
"k8s.io/apimachinery/pkg/api/resource"
22+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23+
)
24+
25+
// PostgresClusterSpec defines the desired state of PostgresCluster.
26+
// Validation rules ensure immutability of Class, and that Storage and PostgresVersion can only be set once and cannot be removed or downgraded.
27+
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.postgresVersion) || semver(self.postgresVersion, true).compareTo(semver(oldSelf.postgresVersion, true)) >= 0",message="Postgres version cannot be downgraded"
28+
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.storage) || (has(self.storage) && quantity(self.storage).compareTo(quantity(oldSelf.storage)) >= 0)",message="Storage size cannot be removed and can only be increased"
29+
type PostgresClusterSpec struct {
30+
// This field is IMMUTABLE after creation.
31+
// +kubebuilder:validation:Required
32+
// +kubebuilder:validation:MinLength=1
33+
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="class is immutable"
34+
Class string `json:"class"`
35+
36+
// Storage overrides the storage size from ClusterClass.
37+
// Example: "5Gi"
38+
// +optional
39+
Storage *resource.Quantity `json:"storage,omitempty"`
40+
41+
// Instances overrides the number of PostgreSQL instances from ClusterClass.
42+
// +optional
43+
// +kubebuilder:validation:Minimum=1
44+
// +kubebuilder:validation:Maximum=10
45+
Instances *int32 `json:"instances,omitempty"`
46+
47+
// PostgresVersion is the PostgreSQL version (major or major.minor).
48+
// Examples: "18" (latest 18.x), "18.1" (specific minor), "17", "16"
49+
// +kubebuilder:validation:Pattern=`^[0-9]+(\.[0-9]+)?$`
50+
// +kubebuilder:default="18"
51+
// +optional
52+
PostgresVersion *string `json:"postgresVersion,omitempty"`
53+
54+
// Resources overrides CPU/memory resources from ClusterClass.
55+
// +optional
56+
Resources *corev1.ResourceRequirements `json:"resources,omitempty"`
57+
58+
// PostgreSQL overrides PostgreSQL engine parameters from ClusterClass.
59+
// Maps to postgresql.conf settings.
60+
// Default empty map prevents panic.
61+
// Example: {"shared_buffers": "128MB", "log_min_duration_statement": "500ms"}
62+
// +optional
63+
// +kubebuilder:default={}
64+
PostgreSQLConfig map[string]string `json:"postgresqlConfig,omitempty"`
65+
66+
// PgHBA contains pg_hba.conf host-based authentication rules.
67+
// Defines client authentication and connection security (cluster-wide).
68+
// Maps to pg_hba.conf settings.
69+
// Default empty array prevents panic.
70+
// Example: ["hostssl all all 0.0.0.0/0 scram-sha-256"]
71+
// +optional
72+
// +kubebuilder:default={}
73+
PgHBA []string `json:"pgHBA,omitempty"`
74+
}
75+
76+
// PostgresClusterStatus defines the observed state of PostgresCluster.
77+
type PostgresClusterStatus struct {
78+
// Phase represents the current phase of the PostgresCluster.
79+
// Values: "Pending", "Provisioning", "Failed", "Ready", "Deleting"
80+
// +optional
81+
Phase string `json:"phase,omitempty"`
82+
83+
// Conditions represent the latest available observations of the PostgresCluster's state.
84+
// +optional
85+
Conditions []metav1.Condition `json:"conditions,omitempty"`
86+
87+
// ProvisionerRef contains reference to the provisioner resource managing this PostgresCluster.
88+
// Right now, only CNPG is supported.
89+
// +optional
90+
ProvisionerRef *corev1.ObjectReference `json:"provisionerRef,omitempty"`
91+
}
92+
93+
// +kubebuilder:object:root=true
94+
// +kubebuilder:subresource:status
95+
// +kubebuilder:resource:scope=Namespaced
96+
// +kubebuilder:printcolumn:name="Class",type=string,JSONPath=`.spec.class`
97+
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`
98+
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
99+
100+
// PostgresCluster is the Schema for the postgresclusters API.
101+
type PostgresCluster struct {
102+
metav1.TypeMeta `json:",inline"`
103+
metav1.ObjectMeta `json:"metadata,omitempty"`
104+
105+
Spec PostgresClusterSpec `json:"spec,omitempty"`
106+
Status PostgresClusterStatus `json:"status,omitempty"`
107+
}
108+
109+
// +kubebuilder:object:root=true
110+
111+
// PostgresClusterList contains a list of PostgresCluster.
112+
type PostgresClusterList struct {
113+
metav1.TypeMeta `json:",inline"`
114+
metav1.ListMeta `json:"metadata,omitempty"`
115+
Items []PostgresCluster `json:"items"`
116+
}
117+
118+
func init() {
119+
SchemeBuilder.Register(&PostgresCluster{}, &PostgresClusterList{})
120+
}
Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,32 +22,32 @@ import (
2222
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2323
)
2424

25-
// ClusterClassSpec defines the desired state of ClusterClass.
26-
// ClusterClass is immutable after creation - it serves as a template for Cluster CRs.
27-
type ClusterClassSpec struct {
25+
// PostgresClusterClassSpec defines the desired state of PostgresClusterClass.
26+
// PostgresClusterClass is immutable after creation - it serves as a template for Cluster CRs.
27+
type PostgresClusterClassSpec struct {
2828
// Provisioner identifies which database provisioner to use.
2929
// Currently supported: "postgresql.cnpg.io" (CloudNativePG)
3030
// +kubebuilder:validation:Required
3131
// +kubebuilder:validation:Enum=postgresql.cnpg.io
3232
Provisioner string `json:"provisioner"`
3333

34-
// ClusterConfig contains cluster-level configuration.
35-
// These settings apply to database cluster infrastructure.
36-
// Can be overridden in Cluster CR.
34+
// PostgresClusterConfig contains cluster-level configuration.
35+
// These settings apply to PostgresCluster infrastructure.
36+
// Can be overridden in PostgresCluster CR.
3737
// +kubebuilder:default={}
3838
// +optional
39-
ClusterConfig ClusterConfig `json:"clusterConfig,omitempty"`
39+
Config PosgresClusterClassConfig `json:"config,omitempty"`
4040

4141
// CNPG contains CloudNativePG-specific configuration and policies.
4242
// Only used when Provisioner is "postgresql.cnpg.io"
43-
// These settings CANNOT be overridden in Cluster CR (platform policy).
43+
// These settings CANNOT be overridden in PostgresCluster CR (platform policy).
4444
// +optional
4545
CNPG *CNPGConfig `json:"cnpg,omitempty"`
4646
}
4747

48-
// ClusterConfig contains provider-agnostic cluster configuration.
49-
// These fields define database cluster infrastructure and can be overridden in Cluster CR.
50-
type ClusterConfig struct {
48+
// PosgresClusterClassConfig contains provider-agnostic cluster configuration.
49+
// These fields define PostgresCluster infrastructure and can be overridden in PostgresCluster CR.
50+
type PosgresClusterClassConfig struct {
5151
// Instances is the number of database instances (1 primary + N replicas).
5252
// Single instance (1) is suitable for development.
5353
// High availability requires at least 3 instances (1 primary + 2 replicas).
@@ -106,13 +106,13 @@ type CNPGConfig struct {
106106
PrimaryUpdateMethod string `json:"primaryUpdateMethod,omitempty"`
107107
}
108108

109-
// ClusterClassStatus defines the observed state of ClusterClass.
110-
type ClusterClassStatus struct {
111-
// Conditions represent the latest available observations of the ClusterClass state.
109+
// PostgresClusterClassStatus defines the observed state of PostgresClusterClass.
110+
type PostgresClusterClassStatus struct {
111+
// Conditions represent the latest available observations of the PostgresClusterClass state.
112112
// +optional
113113
Conditions []metav1.Condition `json:"conditions,omitempty"`
114114

115-
// Phase represents the current phase of the ClusterClass.
115+
// Phase represents the current phase of the PostgresClusterClass.
116116
// Valid phases: "Ready", "Invalid"
117117
// +optional
118118
Phase string `json:"phase,omitempty"`
@@ -122,31 +122,31 @@ type ClusterClassStatus struct {
122122
// +kubebuilder:subresource:status
123123
// +kubebuilder:resource:scope=Cluster
124124
// +kubebuilder:printcolumn:name="Provisioner",type=string,JSONPath=`.spec.provisioner`
125-
// +kubebuilder:printcolumn:name="Instances",type=integer,JSONPath=`.spec.clusterConfig.instances`
126-
// +kubebuilder:printcolumn:name="Storage",type=string,JSONPath=`.spec.clusterConfig.storage`
127-
// +kubebuilder:printcolumn:name="Version",type=string,JSONPath=`.spec.clusterConfig.postgresVersion`
125+
// +kubebuilder:printcolumn:name="Instances",type=integer,JSONPath=`.spec.postgresClusterConfig.instances`
126+
// +kubebuilder:printcolumn:name="Storage",type=string,JSONPath=`.spec.postgresClusterConfig.storage`
127+
// +kubebuilder:printcolumn:name="Version",type=string,JSONPath=`.spec.postgresClusterConfig.postgresVersion`
128128
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`
129129
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
130130

131-
// ClusterClass is the Schema for the clusterclasses API.
132-
// ClusterClass defines a reusable template and policy for database cluster provisioning.
133-
type ClusterClass struct {
131+
// PostgresClusterClass is the Schema for the postgresclusterclasses API.
132+
// PostgresClusterClass defines a reusable template and policy for postgres cluster provisioning.
133+
type PostgresClusterClass struct {
134134
metav1.TypeMeta `json:",inline"`
135135
metav1.ObjectMeta `json:"metadata,omitempty"`
136136

137-
Spec ClusterClassSpec `json:"spec,omitempty"`
138-
Status ClusterClassStatus `json:"status,omitempty"`
137+
Spec PostgresClusterClassSpec `json:"spec,omitempty"`
138+
Status PostgresClusterClassStatus `json:"status,omitempty"`
139139
}
140140

141141
// +kubebuilder:object:root=true
142142

143-
// ClusterClassList contains a list of ClusterClass.
144-
type ClusterClassList struct {
143+
// PostgresClusterClassList contains a list of PostgresClusterClass.
144+
type PostgresClusterClassList struct {
145145
metav1.TypeMeta `json:",inline"`
146146
metav1.ListMeta `json:"metadata,omitempty"`
147-
Items []ClusterClass `json:"items"`
147+
Items []PostgresClusterClass `json:"items"`
148148
}
149149

150150
func init() {
151-
SchemeBuilder.Register(&ClusterClass{}, &ClusterClassList{})
151+
SchemeBuilder.Register(&PostgresClusterClass{}, &PostgresClusterClassList{})
152152
}

0 commit comments

Comments
 (0)