Skip to content

Commit 8d684a8

Browse files
committed
fix: always use absolute paths for WAL upload (#45)
While pgbackrest can work with relative ones, such setup requires additional config flags and a matching Postgresql working directory configuration, which seems to be invalid in the context of the plugin's container. Signed-off-by: Szymon Soloch <ssoloch@opera.com>
1 parent c5df2b9 commit 8d684a8

File tree

2 files changed

+46
-37
lines changed

2 files changed

+46
-37
lines changed

internal/pgbackrest/archiver/command.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ import (
3737
// `requestedWALFile` is the name of the file whose archiving was requested by
3838
// PostgreSQL, and that file is always the first of the list and is always included.
3939
// `parallel` is the maximum number of WALs that we can archive in parallel
40+
// It's important to ensure this method returns absolute paths. While pgbackrest can
41+
// work with relative ones, such setup requires additional config flags and a matching
42+
// Postgresql working directory configuration, which seems to be invalid in the context
43+
// of the plugin's container.
4044
func (archiver *WALArchiver) GatherWALFilesToArchive(
4145
ctx context.Context,
4246
requestedWALFile string,
@@ -57,7 +61,10 @@ func (archiver *WALArchiver) GatherWALFilesToArchive(
5761
// slightly more optimized, but equivalent to:
5862
// walList = []string{requestedWALFile}
5963
walList = make([]string, 1, walListLength)
60-
walList[0] = requestedWALFile
64+
// Ensure it's an absolute path. While Postgres should be configured to use absolute
65+
// paths in the archive command, its documentation mentions that even in this mode
66+
// a relative path might be used in some cases.
67+
walList[0] = filepath.Join(pgWalDirectory, filepath.Base(requestedWALFile))
6168

6269
err := filepath.WalkDir(archiveStatusPath, func(path string, d os.DirEntry, err error) error {
6370
// If err is set, it means the current path is a directory and the readdir raised an error
@@ -96,7 +103,7 @@ func (archiver *WALArchiver) GatherWALFilesToArchive(
96103
return nil
97104
}
98105

99-
walList = append(walList, filepath.Join("pg_wal", walFileName))
106+
walList = append(walList, filepath.Join(pgWalDirectory, walFileName))
100107
return nil
101108
})
102109

internal/pgbackrest/archiver/command_test.go

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -111,51 +111,61 @@ var _ = Describe("GatherWALFilesToArchive", func() {
111111
os.Unsetenv("PGDATA")
112112
})
113113

114-
// Helper function to create .ready files
115-
createReadyFile := func(walName string) {
114+
// Helper function to create .ready files and return the absolute path to the file.
115+
// Pgbackrest preffers absolute paths for uploaded files. For relative ones
116+
// additional flags must be passed and Postgres config must match those flags.
117+
// For some reason it doesn't so we ensure only absolute paths are returned.
118+
createReadyFile := func(walName string) string {
116119
path := filepath.Join(archiveStatusDir, walName+".ready")
117120
err := os.WriteFile(path, []byte{}, 0644)
118121
Expect(err).ToNot(HaveOccurred())
122+
return filepath.Join(tempPgData, "pg_wal", walName)
119123
}
120124

121125
Context("when parallel=1", func() {
122126
It("should gather only the requested file", func(ctx SpecContext) {
123127
// Create .ready files for multiple WAL files
124-
createReadyFile("000000010000000000000001")
128+
wal1 := createReadyFile("000000010000000000000001")
125129
createReadyFile("000000010000000000000002")
126130
createReadyFile("000000010000000000000003")
127131

128132
walList := archiver.GatherWALFilesToArchive(ctx, "pg_wal/000000010000000000000001", 1)
129133

130-
Expect(walList).To(ConsistOf("pg_wal/000000010000000000000001"))
134+
Expect(walList).To(ConsistOf(wal1))
135+
})
136+
137+
It("should handle an absolute path as input", func(ctx SpecContext) {
138+
// Create .ready files for multiple WAL files
139+
wal1 := createReadyFile("000000010000000000000001")
140+
createReadyFile("000000010000000000000002")
141+
createReadyFile("000000010000000000000003")
142+
143+
walList := archiver.GatherWALFilesToArchive(ctx, filepath.Join(tempPgData, "pg_wal", "000000010000000000000001"), 1)
144+
145+
Expect(walList).To(ConsistOf(wal1))
131146
})
132147

133148
It("should handle when no other .ready files exist", func(ctx SpecContext) {
134149
// Only create the requested file
135-
createReadyFile("000000010000000000000001")
150+
wal1 := createReadyFile("000000010000000000000001")
136151

137152
walList := archiver.GatherWALFilesToArchive(ctx, "pg_wal/000000010000000000000001", 1)
138153

139-
Expect(walList).To(ConsistOf("pg_wal/000000010000000000000001"))
154+
Expect(walList).To(ConsistOf(wal1))
140155
})
141156
})
142157

143158
Context("when parallel>1", func() {
144159
It("should gather multiple files when parallel=4", func(ctx SpecContext) {
145160
// Create .ready files for multiple WAL files
146-
createReadyFile("000000010000000000000001")
147-
createReadyFile("000000010000000000000002")
148-
createReadyFile("000000010000000000000003")
149-
createReadyFile("000000010000000000000004")
161+
wal1 := createReadyFile("000000010000000000000001")
162+
wal2 := createReadyFile("000000010000000000000002")
163+
wal3 := createReadyFile("000000010000000000000003")
164+
wal4 := createReadyFile("000000010000000000000004")
150165

151166
walList := archiver.GatherWALFilesToArchive(ctx, "pg_wal/000000010000000000000001", 4)
152167

153-
Expect(walList).To(ConsistOf(
154-
"pg_wal/000000010000000000000001",
155-
"pg_wal/000000010000000000000002",
156-
"pg_wal/000000010000000000000003",
157-
"pg_wal/000000010000000000000004",
158-
))
168+
Expect(walList).To(ConsistOf(wal1, wal2, wal3, wal4))
159169
})
160170

161171
It("should not exceed parallel limit even when more files are ready", func(ctx SpecContext) {
@@ -171,36 +181,34 @@ var _ = Describe("GatherWALFilesToArchive", func() {
171181

172182
It("should handle when fewer files exist than parallel limit", func(ctx SpecContext) {
173183
// Create only 2 .ready files but request parallel=5
174-
createReadyFile("000000010000000000000001")
175-
createReadyFile("000000010000000000000002")
184+
wal1 := createReadyFile("000000010000000000000001")
185+
wal2 := createReadyFile("000000010000000000000002")
176186

177187
walList := archiver.GatherWALFilesToArchive(ctx, "pg_wal/000000010000000000000001", 5)
178188

179189
// Should only get the files that exist
180-
Expect(walList).To(ConsistOf(
181-
"pg_wal/000000010000000000000001",
182-
"pg_wal/000000010000000000000002",
183-
))
190+
Expect(walList).To(ConsistOf(wal1, wal2))
184191
})
185192
})
186193

187194
Context("edge cases", func() {
188195
It("should handle empty archive_status directory", func(ctx SpecContext) {
189196
// Don't create any .ready files
197+
expectedWal := filepath.Join(tempPgData, "pg_wal", "000000010000000000000001")
190198

191199
walList := archiver.GatherWALFilesToArchive(ctx, "pg_wal/000000010000000000000001", 3)
192200

193201
// Should still return the requested file
194-
Expect(walList).To(ConsistOf("pg_wal/000000010000000000000001"))
202+
Expect(walList).To(ConsistOf(expectedWal))
195203
})
196204

197205
})
198206

199207
Context("other files in directory", func() {
200208
It("should ignore non-.ready files in archive_status", func(ctx SpecContext) {
201209
// Create .ready files
202-
createReadyFile("000000010000000000000001")
203-
createReadyFile("000000010000000000000002")
210+
wal1 := createReadyFile("000000010000000000000001")
211+
wal2 := createReadyFile("000000010000000000000002")
204212

205213
// Create .done files (should be ignored)
206214
donePath := filepath.Join(archiveStatusDir, "000000010000000000000003.done")
@@ -215,22 +223,16 @@ var _ = Describe("GatherWALFilesToArchive", func() {
215223
walList := archiver.GatherWALFilesToArchive(ctx, "pg_wal/000000010000000000000001", 5)
216224

217225
// Should only get .ready files, not .done or other files
218-
Expect(walList).To(ConsistOf(
219-
"pg_wal/000000010000000000000001",
220-
"pg_wal/000000010000000000000002",
221-
))
226+
Expect(walList).To(ConsistOf(wal1, wal2))
222227
})
223228
It("should handle timeline history files", func(ctx SpecContext) {
224229
// Create timeline history file
225-
createReadyFile("00000002.history")
226-
createReadyFile("000000010000000000000001")
230+
history := createReadyFile("00000002.history")
231+
wal1 := createReadyFile("000000010000000000000001")
227232

228233
walList := archiver.GatherWALFilesToArchive(ctx, "pg_wal/00000002.history", 2)
229234

230-
Expect(walList).To(ConsistOf(
231-
"pg_wal/00000002.history",
232-
"pg_wal/000000010000000000000001",
233-
))
235+
Expect(walList).To(ConsistOf(history, wal1))
234236
})
235237
})
236238
})

0 commit comments

Comments
 (0)