Skip to content

Commit cd9da85

Browse files
committed
Use regexp to scan pgBackRest restore options once
Input options were being scanned multiple times in different ways.
1 parent 871dbc0 commit cd9da85

File tree

2 files changed

+34
-45
lines changed

2 files changed

+34
-45
lines changed

internal/controller/postgrescluster/pgbackrest.go

Lines changed: 31 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"path/filepath"
1212
"reflect"
1313
"regexp"
14+
"slices"
1415
"sort"
1516
"strings"
1617
"time"
@@ -1190,63 +1191,49 @@ func (r *Reconciler) reconcileRestoreJob(ctx context.Context,
11901191
pgdataVolume, pgwalVolume *corev1.PersistentVolumeClaim,
11911192
pgtablespaceVolumes []*corev1.PersistentVolumeClaim,
11921193
dataSource *v1beta1.PostgresClusterDataSource,
1193-
instanceName, instanceSetName, configHash, stanzaName string) error {
1194-
1194+
instanceName, instanceSetName, configHash, stanzaName string,
1195+
) error {
1196+
hasFlag := make(map[string]bool)
1197+
matchFlag := regexp.MustCompile(`--[^ =]+`)
11951198
repoName := dataSource.RepoName
1196-
options := dataSource.Options
1199+
1200+
for _, input := range dataSource.Options {
1201+
for _, match := range matchFlag.FindAllString(input, -1) {
1202+
hasFlag[match] = true
1203+
}
1204+
}
11971205

11981206
// ensure options are properly set
11991207
// TODO (andrewlecuyer): move validation logic to a webhook
1200-
for _, opt := range options {
1208+
{
12011209
var msg string
12021210
switch {
1203-
// Since '--repo' can be set with or without an equals ('=') sign, we check for both
1204-
// usage patterns.
1205-
case strings.Contains(opt, "--repo=") || strings.Contains(opt, "--repo "):
1211+
case hasFlag["--repo"]:
12061212
msg = "Option '--repo' is not allowed: please use the 'repoName' field instead."
1207-
case strings.Contains(opt, "--stanza"):
1208-
msg = "Option '--stanza' is not allowed: the operator will automatically set this " +
1209-
"option"
1210-
case strings.Contains(opt, "--pg1-path"):
1211-
msg = "Option '--pg1-path' is not allowed: the operator will automatically set this " +
1212-
"option"
1213-
case strings.Contains(opt, "--target-action"):
1214-
msg = "Option '--target-action' is not allowed: the operator will automatically set this " +
1215-
"option "
1216-
case strings.Contains(opt, "--link-map"):
1217-
msg = "Option '--link-map' is not allowed: the operator will automatically set this " +
1218-
"option "
1213+
case hasFlag["--stanza"]:
1214+
msg = "Option '--stanza' is not allowed: the operator will automatically set this option"
1215+
case hasFlag["--pg1-path"]:
1216+
msg = "Option '--pg1-path' is not allowed: the operator will automatically set this option"
1217+
case hasFlag["--target-action"]:
1218+
msg = "Option '--target-action' is not allowed: the operator will automatically set this option"
1219+
case hasFlag["--link-map"]:
1220+
msg = "Option '--link-map' is not allowed: the operator will automatically set this option"
12191221
}
12201222
if msg != "" {
1221-
r.Recorder.Eventf(cluster, corev1.EventTypeWarning, "InvalidDataSource", msg, repoName)
1223+
r.Recorder.Event(cluster, corev1.EventTypeWarning, "InvalidDataSource", msg)
12221224
return nil
12231225
}
12241226
}
12251227

12261228
pgdata := postgres.DataDirectory(cluster)
12271229
// combine options provided by user in the spec with those populated by the operator for a
12281230
// successful restore
1229-
opts := append(options, []string{
1230-
"--stanza=" + stanzaName,
1231-
"--pg1-path=" + pgdata,
1232-
"--repo=" + regexRepoIndex.FindString(repoName)}...)
1233-
1234-
// Look specifically for the "--target" flag, NOT flags that contain
1235-
// "--target" (e.g. "--target-timeline")
1236-
targetRegex, err := regexp.Compile("--target[ =]")
1237-
if err != nil {
1238-
return err
1239-
}
1240-
var deltaOptFound, foundTarget bool
1241-
for _, opt := range opts {
1242-
switch {
1243-
case targetRegex.MatchString(opt):
1244-
foundTarget = true
1245-
case strings.Contains(opt, "--delta"):
1246-
deltaOptFound = true
1247-
}
1248-
}
1249-
if !deltaOptFound {
1231+
opts := append(slices.Clone(dataSource.Options), shell.QuoteWords(
1232+
"--stanza="+stanzaName,
1233+
"--pg1-path="+pgdata,
1234+
"--repo="+regexRepoIndex.FindString(repoName),
1235+
)...)
1236+
if !hasFlag["--delta"] {
12501237
opts = append(opts, "--delta")
12511238
}
12521239

@@ -1262,14 +1249,14 @@ func (r *Reconciler) reconcileRestoreJob(ctx context.Context,
12621249
// - https://github.com/pgbackrest/pgbackrest/blob/bb03b3f41942d0b781931092a76877ad309001ef/src/command/restore/restore.c#L1623
12631250
// - https://github.com/pgbackrest/pgbackrest/issues/1314
12641251
// - https://github.com/pgbackrest/pgbackrest/issues/987
1265-
if foundTarget {
1252+
if hasFlag["--target"] {
12661253
opts = append(opts, "--target-action=promote")
12671254
}
12681255

12691256
for i, instanceSpec := range cluster.Spec.InstanceSets {
12701257
if instanceSpec.Name == instanceSetName {
1271-
opts = append(opts, "--link-map=pg_wal="+postgres.WALDirectory(cluster,
1272-
&cluster.Spec.InstanceSets[i]))
1258+
opts = append(opts, "--link-map=pg_wal="+
1259+
postgres.WALDirectory(cluster, &cluster.Spec.InstanceSets[i]))
12731260
}
12741261
}
12751262

internal/controller/postgrescluster/pgbackrest_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
3535
"sigs.k8s.io/controller-runtime/pkg/manager"
3636
"sigs.k8s.io/controller-runtime/pkg/reconcile"
37+
"sigs.k8s.io/yaml"
3738

3839
"github.com/crunchydata/postgres-operator/internal/controller/runtime"
3940
"github.com/crunchydata/postgres-operator/internal/initialize"
@@ -2355,7 +2356,8 @@ func TestReconcileCloudBasedDataSource(t *testing.T) {
23552356
LabelSelector: naming.PGBackRestRestoreJobSelector(clusterName),
23562357
Namespace: cluster.Namespace,
23572358
}))
2358-
assert.Assert(t, tc.result.jobCount == len(restoreJobs.Items))
2359+
assert.Equal(t, tc.result.jobCount, len(restoreJobs.Items),
2360+
"got:\n%s", require.Value(yaml.Marshal(restoreJobs.Items)))
23592361
if len(restoreJobs.Items) == 1 {
23602362
assert.Assert(t, restoreJobs.Items[0].Labels[naming.LabelStartupInstance] != "")
23612363
assert.Assert(t, restoreJobs.Items[0].Annotations[naming.PGBackRestConfigHash] != "")

0 commit comments

Comments
 (0)