@@ -94,6 +94,9 @@ func NewNode() (*Node, error) {
94
94
Credentials : node .ReplCredentials ,
95
95
}
96
96
97
+ _ , present := os .LookupEnv ("WITNESS" )
98
+ node .RepMgr .Witness = present
99
+
97
100
node .PGConfig = PGConfig {
98
101
DataDir : node .DataDir ,
99
102
Port : node .Port ,
@@ -122,7 +125,6 @@ func (n *Node) Init(ctx context.Context) error {
122
125
123
126
// Check to see if we were just restored
124
127
if os .Getenv ("FLY_RESTORED_FROM" ) != "" {
125
- // Check to see if there's an active restore.
126
128
active , err := isRestoreActive ()
127
129
if err != nil {
128
130
return fmt .Errorf ("failed to verify active restore: %s" , err )
@@ -163,31 +165,41 @@ func (n *Node) Init(ctx context.Context) error {
163
165
return fmt .Errorf ("failed to verify cluster state %s" , err )
164
166
}
165
167
166
- if ! clusterInitialized {
168
+ if clusterInitialized {
169
+ if n .RepMgr .Witness {
170
+ log .Println ("Provisioning witness" )
171
+ if err := n .PGConfig .writePasswordFile (n .OperatorCredentials .Password ); err != nil {
172
+ return fmt .Errorf ("failed to write pg password file: %s" , err )
173
+ }
174
+
175
+ if err := n .PGConfig .initdb (); err != nil {
176
+ return fmt .Errorf ("failed to initialize postgres %s" , err )
177
+ }
178
+ } else {
179
+ log .Println ("Provisioning standby" )
180
+ cloneTarget , err := n .RepMgr .ResolveMemberOverDNS (ctx )
181
+ if err != nil {
182
+ return fmt .Errorf ("failed to resolve member over dns: %s" , err )
183
+ }
184
+
185
+ if err := n .RepMgr .clonePrimary (cloneTarget .Hostname ); err != nil {
186
+ // Clean-up the directory so it can be retried.
187
+ if rErr := os .Remove (n .DataDir ); rErr != nil {
188
+ log .Printf ("[ERROR] failed to cleanup postgresql dir after clone error: %s\n " , rErr )
189
+ }
190
+
191
+ return fmt .Errorf ("failed to clone primary: %s" , err )
192
+ }
193
+ }
194
+ } else {
167
195
log .Println ("Provisioning primary" )
168
- // TODO - This should probably run on boot in case the password changes.
169
196
if err := n .PGConfig .writePasswordFile (n .OperatorCredentials .Password ); err != nil {
170
197
return fmt .Errorf ("failed to write pg password file: %s" , err )
171
198
}
172
199
173
200
if err := n .PGConfig .initdb (); err != nil {
174
201
return fmt .Errorf ("failed to initialize postgres %s" , err )
175
202
}
176
- } else {
177
- log .Println ("Provisioning standby" )
178
- cloneTarget , err := n .RepMgr .ResolveMemberOverDNS (ctx )
179
- if err != nil {
180
- return fmt .Errorf ("failed to resolve member over dns: %s" , err )
181
- }
182
-
183
- if err := n .RepMgr .clonePrimary (cloneTarget .Hostname ); err != nil {
184
- // Clean-up the directory so it can be retried.
185
- if rErr := os .Remove (n .DataDir ); rErr != nil {
186
- log .Printf ("[ERROR] failed to cleanup postgresql dir after clone error: %s\n " , rErr )
187
- }
188
-
189
- return fmt .Errorf ("failed to clone primary: %s" , err )
190
- }
191
203
}
192
204
}
193
205
@@ -236,13 +248,13 @@ func (n *Node) PostInit(ctx context.Context) error {
236
248
}
237
249
238
250
if registered {
239
- // Existing member
240
251
repConn , err := n .RepMgr .NewLocalConnection (ctx )
241
252
if err != nil {
242
253
return fmt .Errorf ("failed to establish connection to local repmgr: %s" , err )
243
254
}
244
255
defer func () { _ = repConn .Close (ctx ) }()
245
256
257
+ // Existing member
246
258
member , err := n .RepMgr .Member (ctx , repConn )
247
259
if err != nil {
248
260
return fmt .Errorf ("failed to resolve member role: %s" , err )
@@ -289,6 +301,16 @@ func (n *Node) PostInit(ctx context.Context) error {
289
301
if err := n .RepMgr .registerStandby (); err != nil {
290
302
return fmt .Errorf ("failed to register existing standby: %s" , err )
291
303
}
304
+ case WitnessRoleName :
305
+ primary , err := n .RepMgr .PrimaryMember (ctx , repConn )
306
+ if err != nil {
307
+ return fmt .Errorf ("failed to resolve primary member when updating witness: %s" , err )
308
+ }
309
+
310
+ // Register existing witness to take-on any configuration changes.
311
+ if err := n .RepMgr .registerWitness (primary .Hostname ); err != nil {
312
+ return fmt .Errorf ("failed to register existing witness: %s" , err )
313
+ }
292
314
default :
293
315
return fmt .Errorf ("member has unknown role: %q" , member .Role )
294
316
}
@@ -350,10 +372,32 @@ func (n *Node) PostInit(ctx context.Context) error {
350
372
return fmt .Errorf ("failed to issue registration certificate: %s" , err )
351
373
}
352
374
} else {
353
- // Configure as standby
354
- log .Println ("Registering standby" )
355
- if err := n .RepMgr .registerStandby (); err != nil {
356
- return fmt .Errorf ("failed to register new standby: %s" , err )
375
+ if n .RepMgr .Witness {
376
+ log .Println ("Registering witness" )
377
+
378
+ // Create required users
379
+ if err := n .setupCredentials (ctx , conn ); err != nil {
380
+ return fmt .Errorf ("failed to create required users: %s" , err )
381
+ }
382
+
383
+ // Setup repmgr database and extension
384
+ if err := n .RepMgr .enable (ctx , conn ); err != nil {
385
+ return fmt .Errorf ("failed to enable repmgr: %s" , err )
386
+ }
387
+
388
+ primary , err := n .RepMgr .ResolveMemberOverDNS (ctx )
389
+ if err != nil {
390
+ return fmt .Errorf ("failed to resolve primary member: %s" , err )
391
+ }
392
+
393
+ if err := n .RepMgr .registerWitness (primary .Hostname ); err != nil {
394
+ return fmt .Errorf ("failed to register witness: %s" , err )
395
+ }
396
+ } else {
397
+ log .Println ("Registering standby" )
398
+ if err := n .RepMgr .registerStandby (); err != nil {
399
+ return fmt .Errorf ("failed to register new standby: %s" , err )
400
+ }
357
401
}
358
402
359
403
// Let the boot process know that we've already been configured.
0 commit comments