Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1e43226

Browse files
Add Disk Auto Grow for pgBackrest repo host volumes (#4247)
* Add Disk Auto Grow for pgBackrest repo host volumes This update adds the ability to automatically grow repo host PVCs. The AutoGrowVolumes feature gate must be enabled and the relevant volumes must include a Limit value. Once enabled, this feature tracks the current disk utilization and, when utilization reaches 75%, the disk request is updated to 150% of the observed value. At this point and beyond, the requested value will be tracked by CPK. The volume request can grow up to the configured limit value. Note: This change now treats limit values as authoritative regardless of the feature gate setting. However, the implementation also now allows limits to be updated after being set. Issue: PGO-1427
1 parent d60114c commit 1e43226

File tree

15 files changed

+942
-152
lines changed

15 files changed

+942
-152
lines changed

‎config/crd/bases/postgres-operator.crunchydata.com_postgresclusters.yaml‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18759,6 +18759,9 @@ spec:
1875918759
description: Whether or not the pgBackRest repository PersistentVolumeClaim
1876018760
is bound to a volume
1876118761
type: boolean
18762+
desiredRepoVolume:
18763+
description: Desired Size of the repo volume
18764+
type: string
1876218765
name:
1876318766
description: The name of the pgBackRest repository
1876418767
type: string
@@ -37681,6 +37684,9 @@ spec:
3768137684
description: Whether or not the pgBackRest repository PersistentVolumeClaim
3768237685
is bound to a volume
3768337686
type: boolean
37687+
desiredRepoVolume:
37688+
description: Desired Size of the repo volume
37689+
type: string
3768437690
name:
3768537691
description: The name of the pgBackRest repository
3768637692
type: string

‎internal/controller/postgrescluster/autogrow.go‎

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ package postgrescluster
66

77
import (
88
"context"
9+
"strings"
910

11+
"github.com/pkg/errors"
1012
corev1 "k8s.io/api/core/v1"
1113
"k8s.io/apimachinery/pkg/api/resource"
1214

@@ -19,7 +21,7 @@ import (
1921
// status. If the value has grown, create an Event.
2022
func (r *Reconciler) storeDesiredRequest(
2123
ctx context.Context, cluster *v1beta1.PostgresCluster,
22-
volumeType, instanceSetName, desiredRequest, desiredRequestBackup string,
24+
volumeType, host, desiredRequest, desiredRequestBackup string,
2325
) string {
2426
var current resource.Quantity
2527
var previous resource.Quantity
@@ -31,7 +33,7 @@ func (r *Reconciler) storeDesiredRequest(
3133
current, err = resource.ParseQuantity(desiredRequest)
3234
if err != nil {
3335
log.Error(err, "Unable to parse "+volumeType+" volume request from status ("+
34-
desiredRequest+") for "+cluster.Name+"/"+instanceSetName)
36+
desiredRequest+") for "+cluster.Name+"/"+host)
3537
// If there was an error parsing the value, treat as unset (equivalent to zero).
3638
desiredRequest = ""
3739
current, _ = resource.ParseQuantity("")
@@ -44,7 +46,7 @@ func (r *Reconciler) storeDesiredRequest(
4446
previous, err = resource.ParseQuantity(desiredRequestBackup)
4547
if err != nil {
4648
log.Error(err, "Unable to parse "+volumeType+" volume request from status backup ("+
47-
desiredRequestBackup+") for "+cluster.Name+"/"+instanceSetName)
49+
desiredRequestBackup+") for "+cluster.Name+"/"+host)
4850
// If there was an error parsing the value, treat as unset (equivalent to zero).
4951
desiredRequestBackup = ""
5052
previous, _ = resource.ParseQuantity("")
@@ -53,12 +55,12 @@ func (r *Reconciler) storeDesiredRequest(
5355
}
5456

5557
// determine if the appropriate volume limit is set
56-
limitSet := limitIsSet(cluster, volumeType, instanceSetName)
58+
limitSet := limitIsSet(cluster, volumeType, host)
5759

5860
if limitSet && current.Value() > previous.Value() {
5961
r.Recorder.Eventf(cluster, corev1.EventTypeNormal, "VolumeAutoGrow",
6062
"%s volume expansion to %v requested for %s/%s.",
61-
volumeType, current.String(), cluster.Name, instanceSetName)
63+
volumeType, current.String(), cluster.Name, host)
6264
}
6365

6466
// If the desired size was not observed, update with previously stored value.
@@ -77,34 +79,44 @@ func limitIsSet(cluster *v1beta1.PostgresCluster, volumeType, instanceSetName st
7779

7880
var limitSet bool
7981

80-
switch volumeType{
82+
switch {
8183

8284
// Cycle through the instance sets to ensure the correct limit is identified.
83-
case "pgData":
85+
case volumeType=="pgData":
8486
for _, specInstance := range cluster.Spec.InstanceSets {
8587
if specInstance.Name == instanceSetName {
8688
limitSet = !specInstance.DataVolumeClaimSpec.Resources.Limits.Storage().IsZero()
8789
}
8890
}
91+
92+
// VolumeType for the repository host volumes should be in the form 'repoN'
93+
// where N is 1-4. As above, cycle through any defined repositories and ensure
94+
// the correct limit is identified.
95+
case strings.HasPrefix(volumeType, "repo"):
96+
for _, specRepo := range cluster.Spec.Backups.PGBackRest.Repos {
97+
if specRepo.Name == volumeType && specRepo.Volume != nil {
98+
limitSet = !specRepo.Volume.VolumeClaimSpec.Resources.Limits.Storage().IsZero()
99+
}
100+
}
89101
}
90-
// TODO: Add cases for pgWAL and repo volumes
102+
// TODO: Add case for pgWAL
91103

92104
return limitSet
93105

94106
}
95107

96-
// setVolumeSize compares the potential sizes from the instance spec, status
97-
// and limit and sets the appropriate current value.
108+
// setVolumeSize compares the potential sizes from the cluster status, volume request
109+
// and volume limit and sets the appropriate current value.
98110
func (r *Reconciler) setVolumeSize(ctx context.Context, cluster *v1beta1.PostgresCluster,
99-
pvc *corev1.PersistentVolumeClaim, volumeType, instanceSpecName string) {
111+
spec *corev1.PersistentVolumeClaimSpec, volumeType, host string) {
100112

101113
log := logging.FromContext(ctx)
102114

103115
// Store the limit for this instance set. This value will not change below.
104-
volumeLimitFromSpec := pvc.Spec.Resources.Limits.Storage()
116+
volumeLimitFromSpec := spec.Resources.Limits.Storage()
105117

106118
// This value will capture our desired update.
107-
volumeRequestSize := pvc.Spec.Resources.Requests.Storage()
119+
volumeRequestSize := spec.Resources.Requests.Storage()
108120

109121
// A limit of 0 is ignorned, so the volume request is used.
110122
if volumeLimitFromSpec.IsZero() {
@@ -116,19 +128,19 @@ func (r *Reconciler) setVolumeSize(ctx context.Context, cluster *v1beta1.Postgre
116128
if volumeRequestSize.Value() > volumeLimitFromSpec.Value() {
117129
r.Recorder.Eventf(cluster, corev1.EventTypeWarning, "VolumeRequestOverLimit",
118130
"%s volume request (%v) for %s/%s is greater than set limit (%v). Limit value will be used.",
119-
volumeType, volumeRequestSize, cluster.Name, instanceSpecName, volumeLimitFromSpec)
131+
volumeType, volumeRequestSize, cluster.Name, host, volumeLimitFromSpec)
120132

121-
pvc.Spec.Resources.Requests = corev1.ResourceList{
133+
spec.Resources.Requests = corev1.ResourceList{
122134
corev1.ResourceStorage: *resource.NewQuantity(volumeLimitFromSpec.Value(), resource.BinarySI),
123135
}
124136
// Otherwise, if the feature gate is not enabled, do not autogrow.
125137
} else if feature.Enabled(ctx, feature.AutoGrowVolumes) {
126138

127139
// determine the appropriate volume request based on what's set in the status
128140
if dpv, err := getDesiredVolumeSize(
129-
cluster, volumeType, instanceSpecName, volumeRequestSize,
141+
cluster, volumeType, host, volumeRequestSize,
130142
); err != nil {
131-
log.Error(err, "For "+cluster.Name+"/"+instanceSpecName+
143+
log.Error(err, "For "+cluster.Name+"/"+host+
132144
": Unable to parse "+volumeType+" volume request: "+dpv)
133145
}
134146

@@ -140,19 +152,19 @@ func (r *Reconciler) setVolumeSize(ctx context.Context, cluster *v1beta1.Postgre
140152

141153
r.Recorder.Eventf(cluster, corev1.EventTypeNormal, "VolumeLimitReached",
142154
"%s volume(s) for %s/%s are at size limit (%v).", volumeType,
143-
cluster.Name, instanceSpecName, volumeLimitFromSpec)
155+
cluster.Name, host, volumeLimitFromSpec)
144156

145157
// If the volume size request is greater than the limit, issue an
146158
// additional event warning.
147159
if volumeRequestSize.Value() > volumeLimitFromSpec.Value() {
148160
r.Recorder.Eventf(cluster, corev1.EventTypeWarning, "DesiredVolumeAboveLimit",
149161
"The desired size (%v) for the %s/%s %s volume(s) is greater than the size limit (%v).",
150-
volumeRequestSize, cluster.Name, instanceSpecName, volumeType, volumeLimitFromSpec)
162+
volumeRequestSize, cluster.Name, host, volumeType, volumeLimitFromSpec)
151163
}
152164

153165
volumeRequestSize = volumeLimitFromSpec
154166
}
155-
pvc.Spec.Resources.Requests = corev1.ResourceList{
167+
spec.Resources.Requests = corev1.ResourceList{
156168
corev1.ResourceStorage: *resource.NewQuantity(volumeRequestSize.Value(), resource.BinarySI),
157169
}
158170
}
@@ -164,8 +176,8 @@ func getDesiredVolumeSize(cluster *v1beta1.PostgresCluster,
164176
volumeType, instanceSpecName string,
165177
volumeRequestSize *resource.Quantity) (string, error) {
166178

167-
switch volumeType{
168-
case "pgData":
179+
switch {
180+
case volumeType=="pgData":
169181
for i := range cluster.Status.InstanceSets {
170182
if instanceSpecName == cluster.Status.InstanceSets[i].Name {
171183
for _, dpv := range cluster.Status.InstanceSets[i].DesiredPGDataVolume {
@@ -182,7 +194,30 @@ func getDesiredVolumeSize(cluster *v1beta1.PostgresCluster,
182194
}
183195
}
184196
}
185-
// TODO: Add cases for pgWAL and repo volumes (requires relevant status sections)
197+
198+
// VolumeType for the repository host volumes should be in the form 'repoN'
199+
// where N is 1-4. As above, cycle through any defined repositories and ensure
200+
// the correct limit is identified.
201+
case strings.HasPrefix(volumeType, "repo"):
202+
if cluster.Status.PGBackRest == nil {
203+
return "", errors.New("PostgresCluster.Status.PGBackRest is nil")
204+
}
205+
for i := range cluster.Status.PGBackRest.Repos {
206+
if volumeType == cluster.Status.PGBackRest.Repos[i].Name {
207+
dpv := cluster.Status.PGBackRest.Repos[i].DesiredRepoVolume
208+
if dpv != "" {
209+
desiredRequest, err := resource.ParseQuantity(dpv)
210+
if err == nil {
211+
if desiredRequest.Value() > volumeRequestSize.Value() {
212+
*volumeRequestSize = desiredRequest
213+
}
214+
} else {
215+
return dpv, err
216+
}
217+
}
218+
}
219+
}
186220
}
221+
// TODO: Add case for pgWAL
187222
return "", nil
188223
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /