@@ -64,7 +64,6 @@ type RegistrySQL struct {
6464 cv * client.Validator
6565 ctxer contextx.Contextualizer
6666 hh * healthx.Handler
67- migrationStatus * popx.MigrationStatuses
6867 kc * aead.AESGCM
6968 flowc * aead.XChaCha20Poly1305
7069 cos consent.Strategy
@@ -76,7 +75,7 @@ type RegistrySQL struct {
7675 trc * otelx.Tracer
7776 tracerWrapper func (* otelx.Tracer ) * otelx.Tracer
7877 arhs []oauth2.AccessRequestHook
79- persister persistence. Persister
78+ basePersister * sql. BasePersister
8079 oc fosite.Configurator
8180 oidcs jwk.JWTSigner
8281 ats jwk.JWTSigner
@@ -87,10 +86,11 @@ type RegistrySQL struct {
8786 publicCORS * cors.Cors
8887 kratos kratos.Client
8988 fositeFactories []fositex.Factory
89+ migrator * sql.MigrationManager
9090
91- defaultKeyManager jwk.Manager
92- initialPing func ( r * RegistrySQL ) error
93- middlewares []negroni.Handler
91+ keyManager jwk.Manager
92+ initialPing func ( ctx context. Context , l * logrusx. Logger , p * sql. BasePersister ) error
93+ middlewares []negroni.Handler
9494}
9595
9696var (
@@ -101,12 +101,10 @@ var (
101101// defaultInitialPing is the default function that will be called within RegistrySQL.Init to make sure
102102// the database is reachable. It can be injected for test purposes by changing the value
103103// of RegistrySQL.initialPing.
104- func defaultInitialPing (m * RegistrySQL ) error {
105- if err := resilience .Retry (m .l , 5 * time .Second , 5 * time .Minute , m .Ping ); err != nil {
106- m .Logger ().Print ("Could not ping database: " , err )
107- return errors .WithStack (err )
108- }
109- return nil
104+ func defaultInitialPing (ctx context.Context , l * logrusx.Logger , p * sql.BasePersister ) error {
105+ return errors .WithStack (resilience .Retry (l , 5 * time .Second , 5 * time .Minute , func () error {
106+ return p .Ping (ctx )
107+ }))
110108}
111109
112110func (m * RegistrySQL ) Init (
@@ -116,7 +114,7 @@ func (m *RegistrySQL) Init(
116114 extraMigrations []fs.FS ,
117115 goMigrations []popx.Migration ,
118116) error {
119- if m .persister == nil {
117+ if m .basePersister == nil {
120118 if m .Config ().CGroupsV1AutoMaxProcsEnabled () {
121119 _ , err := maxprocs .Set (maxprocs .Logger (m .Logger ().Infof ))
122120 if err != nil {
@@ -146,59 +144,40 @@ func (m *RegistrySQL) Init(
146144 return errors .WithStack (err )
147145 }
148146
149- p , err := sql .NewPersister (c , m , m .Config (), extraMigrations , goMigrations )
150- if err != nil {
151- return err
152- }
153- m .persister = p
154- if err := m .initialPing (m ); err != nil {
147+ m .basePersister = sql .NewBasePersister (c , m )
148+ if err := m .initialPing (ctx , m .Logger (), m .basePersister ); err != nil {
149+ m .Logger ().Print ("Could not ping database: " , err )
155150 return err
156151 }
157152
158- if m .Config ().HSMEnabled () {
159- hardwareKeyManager := hsm .NewKeyManager (m .HSMContext (), m .Config ())
160- m .defaultKeyManager = jwk .NewManagerStrategy (hardwareKeyManager , m .persister )
161- } else {
162- m .defaultKeyManager = m .persister
163- }
153+ m .migrator = sql .NewMigrationManager (c , m , extraMigrations , goMigrations )
164154
165155 // if dsn is memory we have to run the migrations on every start
166156 // use case - such as
167157 // - just in memory
168158 // - shared connection
169159 // - shared but unique in the same process
170160 // see: https://sqlite.org/inmemorydb.html
171- if dbal .IsMemorySQLite (m .Config ().DSN ()) {
172- m .Logger ().Print ("Hydra is running migrations on every startup as DSN is memory.\n " )
173- m .Logger ().Print ("This means your data is lost when Hydra terminates.\n " )
174- if err := p .MigrateUp (context .Background ()); err != nil {
175- return err
176- }
177- } else if migrate {
178- if err := p .MigrateUp (context .Background ()); err != nil {
161+ switch {
162+ case dbal .IsMemorySQLite (m .Config ().DSN ()):
163+ m .Logger ().Println ("Hydra is running migrations on every startup as DSN is memory." )
164+ m .Logger ().Println ("This means your data is lost when Hydra terminates." )
165+ fallthrough
166+ case migrate :
167+ if err := m .migrator .MigrateUp (ctx ); err != nil {
179168 return err
180169 }
181170 }
182171
183- if skipNetworkInit {
184- m .persister = p
185- } else {
186- net , err := p .DetermineNetwork (ctx )
172+ if ! skipNetworkInit {
173+ net , err := m .basePersister .DetermineNetwork (ctx )
187174 if err != nil {
188175 m .Logger ().WithError (err ).Warnf ("Unable to determine network, retrying." )
189176 return err
190177 }
191178
192- m .persister = p .WithFallbackNetworkID (net .ID )
193- }
194-
195- if m .Config ().HSMEnabled () {
196- hardwareKeyManager := hsm .NewKeyManager (m .HSMContext (), m .Config ())
197- m .defaultKeyManager = jwk .NewManagerStrategy (hardwareKeyManager , m .persister )
198- } else {
199- m .defaultKeyManager = m .persister
179+ m .basePersister = m .basePersister .WithFallbackNetworkID (net .ID )
200180 }
201-
202181 }
203182
204183 return nil
@@ -211,11 +190,7 @@ func (m *RegistrySQL) alwaysCanHandle(dsn string) bool {
211190}
212191
213192func (m * RegistrySQL ) PingContext (ctx context.Context ) error {
214- return m .Persister ().Ping (ctx )
215- }
216-
217- func (m * RegistrySQL ) Ping () error {
218- return m .PingContext (context .Background ())
193+ return m .basePersister .Ping (ctx )
219194}
220195
221196func (m * RegistrySQL ) ClientManager () client.Manager {
@@ -231,11 +206,16 @@ func (m *RegistrySQL) OAuth2Storage() x.FositeStorer {
231206}
232207
233208func (m * RegistrySQL ) KeyManager () jwk.Manager {
234- return m .defaultKeyManager
235- }
236-
237- func (m * RegistrySQL ) SoftwareKeyManager () jwk.Manager {
238- return m .Persister ()
209+ if m .keyManager == nil {
210+ softwareKeyManager := & sql.JWKPersister {BasePersister : m .basePersister }
211+ if m .Config ().HSMEnabled () {
212+ hardwareKeyManager := hsm .NewKeyManager (m .HSMContext (), m .Config ())
213+ m .keyManager = jwk .NewManagerStrategy (hardwareKeyManager , softwareKeyManager )
214+ } else {
215+ m .keyManager = softwareKeyManager
216+ }
217+ }
218+ return m .keyManager
239219}
240220
241221func (m * RegistrySQL ) GrantManager () trust.GrantManager {
@@ -330,11 +310,7 @@ func (m *RegistrySQL) HealthHandler() *healthx.Handler {
330310 return m .PingContext (r .Context ())
331311 },
332312 "migrations" : func (r * http.Request ) error {
333- if m .migrationStatus != nil && ! m .migrationStatus .HasPending () {
334- return nil
335- }
336-
337- status , err := m .Persister ().MigrationStatus (r .Context ())
313+ status , err := m .migrator .MigrationStatus (r .Context ())
338314 if err != nil {
339315 return err
340316 }
@@ -344,8 +320,6 @@ func (m *RegistrySQL) HealthHandler() *healthx.Handler {
344320 m .Logger ().WithField ("status" , fmt .Sprintf ("%+v" , status )).WithError (err ).Warn ("Instance is not yet ready because migrations have not yet been fully applied." )
345321 return err
346322 }
347-
348- m .migrationStatus = & status
349323 return nil
350324 },
351325 })
@@ -529,7 +503,7 @@ func (m *RegistrySQL) OpenIDConnectRequestValidator() *openid.OpenIDConnectReque
529503}
530504
531505func (m * RegistrySQL ) Networker () x.Networker {
532- return m .persister
506+ return m .basePersister
533507}
534508
535509func (m * RegistrySQL ) SubjectIdentifierAlgorithm (ctx context.Context ) map [string ]consent.SubjectIdentifierAlgorithm {
@@ -569,7 +543,7 @@ func (m *RegistrySQL) Tracer(_ context.Context) *otelx.Tracer {
569543}
570544
571545func (m * RegistrySQL ) Persister () persistence.Persister {
572- return m . persister
546+ return sql . NewPersister ( m . basePersister , m )
573547}
574548
575549// Config returns the configuration for the given context. It may or may not be the same as the global configuration.
@@ -609,3 +583,7 @@ func (m *RegistrySQL) Kratos() kratos.Client {
609583func (m * RegistrySQL ) HTTPMiddlewares () []negroni.Handler {
610584 return m .middlewares
611585}
586+
587+ func (m * RegistrySQL ) Migrator () * sql.MigrationManager {
588+ return m .migrator
589+ }
0 commit comments