@@ -2,7 +2,6 @@ package database
22
33import (
44 "context"
5- "crypto/tls"
65 "errors"
76 "fmt"
87 "slices"
@@ -16,7 +15,6 @@ import (
1615 "github.com/pgEdge/control-plane/server/internal/patroni"
1716 "github.com/pgEdge/control-plane/server/internal/postgres"
1817 "github.com/pgEdge/control-plane/server/internal/resource"
19- "github.com/pgEdge/control-plane/server/internal/utils"
2018)
2119
2220var _ resource.Resource = (* InstanceResource )(nil )
@@ -122,6 +120,10 @@ func (r *InstanceResource) Delete(ctx context.Context, rc *resource.Context) err
122120}
123121
124122func (r * InstanceResource ) Connection (ctx context.Context , rc * resource.Context , dbName string ) (* pgx.Conn , error ) {
123+ if rc .HostID != r .Spec .HostID {
124+ return nil , fmt .Errorf ("cannot connect to an instance running on a different host. executing host = '%s', instance host = '%s'" , rc .HostID , r .Spec .HostID )
125+ }
126+
125127 certs , err := do.Invoke [* certificates.Service ](rc .Injector )
126128 if err != nil {
127129 return nil , err
@@ -143,17 +145,17 @@ func (r *InstanceResource) Connection(ctx context.Context, rc *resource.Context,
143145}
144146
145147func (r * InstanceResource ) initializeInstance (ctx context.Context , rc * resource.Context ) error {
146- certs , err := do.Invoke [* certificates.Service ](rc .Injector )
147- if err != nil {
148- return err
149- }
148+ // certs, err := do.Invoke[*certificates.Service](rc.Injector)
149+ // if err != nil {
150+ // return err
151+ // }
150152
151153 if err := r .updateConnectionInfo (ctx , rc ); err != nil {
152154 return err
153155 }
154156
155157 patroniClient := r .patroniClient ()
156- err = WaitForPatroniRunning (ctx , patroniClient , 0 )
158+ err : = WaitForPatroniRunning (ctx , patroniClient , 0 )
157159 if err != nil {
158160 return fmt .Errorf ("failed to wait for patroni to enter running state: %w" , err )
159161 }
@@ -173,98 +175,41 @@ func (r *InstanceResource) initializeInstance(ctx context.Context, rc *resource.
173175 return nil
174176 }
175177
176- tlsCfg , err := certs .PostgresUserTLS (ctx , r .Spec .InstanceID , r .InstanceHostname , "pgedge" )
177- if err != nil {
178- return fmt .Errorf ("failed to get TLS config: %w" , err )
179- }
180-
181- var spockSets []postgres.ReplicationSet
182- var spockTables []postgres.ReplicationSetTable
183- if r .Spec .RestoreConfig != nil && r .isFirstTimeSetup (rc ) {
184- err = r .renameDB (ctx , tlsCfg )
185- if err != nil {
186- return fmt .Errorf ("failed to rename database %q: %w" , r .Spec .DatabaseName , err )
187- }
188-
189- spockSets , spockTables , err = r .backupReplicationSets (ctx , tlsCfg )
190- if err != nil {
191- return err
192- }
193-
194- err = r .dropSpock (ctx , tlsCfg )
195- if err != nil {
196- return fmt .Errorf ("failed to drop spock: %w" , err )
197- }
198- }
199-
200- err = r .createDB (ctx , tlsCfg )
178+ conn , err := r .Connection (ctx , rc , "postgres" )
201179 if err != nil {
202- return fmt .Errorf ("failed to create database %q: %w" , r .Spec .DatabaseName , err )
203- }
204-
205- conn , err := ConnectToInstance (ctx , & ConnectionOptions {
206- DSN : r .ConnectionInfo .AdminDSN (r .Spec .DatabaseName ),
207- TLS : tlsCfg ,
208- })
209- if err != nil {
210- return fmt .Errorf ("failed to connect to database %q: %w" , r .Spec .DatabaseName , err )
180+ return err
211181 }
212182 defer conn .Close (ctx )
213183
214- tx , err := conn .Begin (ctx )
184+ // Spock shouldn't exist in the 'postgres' database, but we want to err on
185+ // the side of caution.
186+ tx , err := postgres .StartRepairModeTxn (ctx , conn )
215187 if err != nil {
216- return fmt .Errorf ("failed to begin transaction: %w" , err )
188+ return fmt .Errorf ("failed to start repair mode transaction: %w" , err )
217189 }
218190 defer tx .Rollback (ctx )
219191
220- enabled , err := postgres .IsSpockEnabled ().Scalar (ctx , tx )
221- if err != nil {
222- return fmt .Errorf ("failed to check if spock is enabled: %w" , err )
223- }
224-
225- if enabled {
226- err = postgres .EnableRepairMode ().Exec (ctx , tx )
227- if err != nil {
228- return fmt .Errorf ("failed to enable repair mode: %w" , err )
229- }
230- }
231-
232- err = postgres .InitializePgEdgeExtensions (
233- r .Spec .NodeName ,
234- r .ConnectionInfo .PeerDSN (r .Spec .DatabaseName ),
235- ).Exec (ctx , conn )
236- if err != nil {
237- return fmt .Errorf ("failed to initialize pgedge extensions: %w" , err )
238- }
239- if len (spockSets ) > 0 || len (spockTables ) > 0 {
240- if err := postgres .RestoreReplicationSets (spockSets , spockTables ).Exec (ctx , conn ); err != nil {
241- return fmt .Errorf ("failed to restore spock metadata: %w" , err )
242- }
243- }
244192 roleStatements , err := postgres .CreateBuiltInRoles (postgres.BuiltinRoleOptions {
245193 PGVersion : r .Spec .PgEdgeVersion .PostgresVersion .String (),
246- DBName : r .Spec .DatabaseName ,
247194 })
248195 if err != nil {
249196 return fmt .Errorf ("failed to generate built-in role statements: %w" , err )
250197 }
251- if err := roleStatements .Exec (ctx , conn ); err != nil {
198+ if err := roleStatements .Exec (ctx , tx ); err != nil {
252199 return fmt .Errorf ("failed to create built-in roles: %w" , err )
253200 }
254201
255202 for _ , user := range r .Spec .DatabaseUsers {
256203 statement , err := postgres .CreateUserRole (postgres.UserRoleOptions {
257204 Name : user .Username ,
258205 Password : user .Password ,
259- DBName : r .Spec .DatabaseName ,
260- DBOwner : user .DBOwner ,
261206 Attributes : user .Attributes ,
262207 Roles : user .Roles ,
263208 })
264209 if err != nil {
265210 return fmt .Errorf ("failed to produce create user role statement %q: %w" , user .Username , err )
266211 }
267- if err := statement .Exec (ctx , conn ); err != nil {
212+ if err := statement .Exec (ctx , tx ); err != nil {
268213 return fmt .Errorf ("failed to create user role %q: %w" , user .Username , err )
269214 }
270215 }
@@ -332,103 +277,3 @@ func (r *InstanceResource) updateConnectionInfo(ctx context.Context, rc *resourc
332277func (r * InstanceResource ) patroniClient () * patroni.Client {
333278 return patroni .NewClient (r .ConnectionInfo .PatroniURL (), nil )
334279}
335-
336- func (r * InstanceResource ) createDB (ctx context.Context , tlsCfg * tls.Config ) error {
337- createDBConn , err := ConnectToInstance (ctx , & ConnectionOptions {
338- DSN : r .ConnectionInfo .AdminDSN ("postgres" ),
339- TLS : tlsCfg ,
340- })
341- if err != nil {
342- return fmt .Errorf ("failed to connect to 'postgres' database on instance: %w" , err )
343- }
344- defer createDBConn .Close (ctx )
345-
346- err = postgres .CreateDatabase (r .Spec .DatabaseName ).Exec (ctx , createDBConn )
347- if err != nil {
348- return fmt .Errorf ("failed to create database %q: %w" , r .Spec .DatabaseName , err )
349- }
350-
351- return nil
352- }
353-
354- func (r * InstanceResource ) renameDB (ctx context.Context , tlsCfg * tls.Config ) error {
355- // Short circuit if the restore config doesn't include a dbname or if the
356- // database name is the same.
357- if r .Spec .RestoreConfig .SourceDatabaseName == "" || r .Spec .RestoreConfig .SourceDatabaseName == r .Spec .DatabaseName {
358- return nil
359- }
360-
361- // This operation can be flaky because of other processes connected to the
362- // database. We retry it a few times to avoid failing the entire create
363- // operation.
364- err := utils .Retry (3 , 500 * time .Millisecond , func () error {
365- createDBConn , err := ConnectToInstance (ctx , & ConnectionOptions {
366- DSN : r .ConnectionInfo .AdminDSN ("postgres" ),
367- TLS : tlsCfg ,
368- })
369- if err != nil {
370- return fmt .Errorf ("failed to connect to 'postgres' database on instance: %w" , err )
371- }
372- defer createDBConn .Close (ctx )
373-
374- return postgres .
375- RenameDB (r .Spec .RestoreConfig .SourceDatabaseName , r .Spec .DatabaseName ).
376- Exec (ctx , createDBConn )
377- })
378- if err != nil {
379- return fmt .Errorf ("failed to rename database %q: %w" , r .Spec .DatabaseName , err )
380- }
381-
382- return nil
383- }
384-
385- func (r * InstanceResource ) dropSpock (ctx context.Context , tlsCfg * tls.Config ) error {
386- conn , err := ConnectToInstance (ctx , & ConnectionOptions {
387- DSN : r .ConnectionInfo .AdminDSN (r .Spec .DatabaseName ),
388- TLS : tlsCfg ,
389- })
390- if err != nil {
391- return fmt .Errorf ("failed to connect to database %q: %w" , r .Spec .DatabaseName , err )
392- }
393- defer conn .Close (ctx )
394-
395- err = postgres .DropSpockAndCleanupSlots (r .Spec .DatabaseName ).Exec (ctx , conn )
396- if err != nil {
397- return fmt .Errorf ("failed to drop spock: %w" , err )
398- }
399-
400- return nil
401- }
402-
403- func (r * InstanceResource ) isFirstTimeSetup (rc * resource.Context ) bool {
404- // This instance will already exist in the state if it's been successfully
405- // created before.
406- _ , ok := rc .State .Get (r .Identifier ())
407- return ! ok
408- }
409-
410- func (r * InstanceResource ) backupReplicationSets (
411- ctx context.Context ,
412- tlsCfg * tls.Config ,
413- ) ([]postgres.ReplicationSet , []postgres.ReplicationSetTable , error ) {
414- conn , err := ConnectToInstance (ctx , & ConnectionOptions {
415- DSN : r .ConnectionInfo .AdminDSN (r .Spec .DatabaseName ),
416- TLS : tlsCfg ,
417- })
418- if err != nil {
419- return nil , nil , fmt .Errorf ("failed to connect to database %q: %w" , r .Spec .DatabaseName , err )
420- }
421- defer conn .Close (ctx )
422-
423- sets , err := postgres .GetReplicationSets ().Structs (ctx , conn )
424- if err != nil {
425- return nil , nil , fmt .Errorf ("spock backup failed to get replication sets: %w" , err )
426- }
427-
428- tabs , err := postgres .GetReplicationSetTables ().Structs (ctx , conn )
429- if err != nil {
430- return nil , nil , fmt .Errorf ("spock backup failed to get replication set tables: %w" , err )
431- }
432-
433- return sets , tabs , nil
434- }
0 commit comments