Skip to content

Commit 8201a8d

Browse files
committed
need to defer Porter storage initialization after config loaded
1 parent b586ba2 commit 8201a8d

File tree

3 files changed

+107
-53
lines changed

3 files changed

+107
-53
lines changed

pkg/config/config.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ import (
99
"reflect"
1010
"strings"
1111

12+
"github.com/spf13/viper"
13+
"go.opentelemetry.io/otel/attribute"
14+
1215
"get.porter.sh/porter/pkg/experimental"
1316
"get.porter.sh/porter/pkg/portercontext"
1417
"get.porter.sh/porter/pkg/schema"
1518
"get.porter.sh/porter/pkg/tracing"
16-
"github.com/spf13/viper"
17-
"go.opentelemetry.io/otel/attribute"
1819
)
1920

2021
const (

pkg/plugins/pluggable/connection.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,16 @@ import (
1515
"sync"
1616
"time"
1717

18-
"get.porter.sh/porter/pkg/config"
19-
"get.porter.sh/porter/pkg/plugins"
20-
"get.porter.sh/porter/pkg/tracing"
2118
"github.com/hashicorp/go-hclog"
2219
"github.com/hashicorp/go-multierror"
2320
"github.com/hashicorp/go-plugin"
2421
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
2522
"go.opentelemetry.io/otel/attribute"
2623
"google.golang.org/grpc"
24+
25+
"get.porter.sh/porter/pkg/config"
26+
"get.porter.sh/porter/pkg/plugins"
27+
"get.porter.sh/porter/pkg/tracing"
2728
)
2829

2930
// PluginConnection represents a connection to a plugin.

pkg/porter/porter.go

+100-48
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"net/url"
87
"strings"
98
"sync"
109

@@ -28,6 +27,7 @@ import (
2827
"get.porter.sh/porter/pkg/storage/migrations"
2928
storageplugin "get.porter.sh/porter/pkg/storage/pluginstore"
3029
"get.porter.sh/porter/pkg/storage/sql"
30+
"get.porter.sh/porter/pkg/storage/sql/migrate"
3131
"get.porter.sh/porter/pkg/templates"
3232
"get.porter.sh/porter/pkg/tracing"
3333
)
@@ -54,40 +54,36 @@ type Porter struct {
5454
Secrets secrets.Store
5555
Signer signing.Signer
5656

57+
onClose []func() error
58+
5759
// Deprecated: Use the individual storage providers in the Porter struct instead
5860
// This is only here for backwards compatibility where MongoDB was the only storage provider.
5961
Storage storage.Provider
6062
}
6163

6264
// Options for configuring a new Porter client passed to NewWith.
6365
type Options struct {
64-
Config *config.Config // Optional. Defaults to a config.New.
65-
SecretStorage secrets.Store // Optional. Defaults to a secrets.NewPluginAdapter(secretsplugin.NewStore).
66-
Signer signing.Signer // Optional. Defaults to a signing.NewPluginAdapter(signingplugin.NewSigner).
66+
Config *config.Config // Optional. Defaults to a config.New.
67+
Secrets secrets.Store // Optional. Defaults to a secrets.NewPluginAdapter(secretsplugin.NewStore).
68+
Signer signing.Signer // Optional. Defaults to a signing.NewPluginAdapter(signingplugin.NewSigner).
6769
}
6870

6971
// NewWith creates a new Porter client with useful defaults that can be overridden with the provided options.
72+
//
73+
// Porter.Connect must be called before using the Porter client and Porter.Close must be called when done.
7074
func NewWith(opt Options) (*Porter, error) {
7175
if opt.Config == nil {
7276
opt.Config = config.New()
7377
}
74-
if opt.SecretStorage == nil {
75-
opt.SecretStorage = secrets.NewPluginAdapter(secretsplugin.NewStore(opt.Config))
78+
if opt.Secrets == nil {
79+
opt.Secrets = secrets.NewPluginAdapter(secretsplugin.NewStore(opt.Config))
7680
}
7781
if opt.Signer == nil {
7882
opt.Signer = signing.NewPluginAdapter(signingplugin.NewSigner(opt.Config))
7983
}
8084

81-
if p, ok := sql.IsPostgresStorage(opt.Config); ok {
82-
po, err := newWithSQL(opt.Config, p, opt.SecretStorage, opt.Signer)
83-
if err != nil {
84-
return nil, err
85-
}
86-
return po, nil
87-
}
88-
89-
storage := storage.NewPluginAdapter(storageplugin.NewStore(opt.Config))
90-
return NewFor(opt.Config, storage, opt.SecretStorage, opt.Signer), nil
85+
// storage initialization is deferred until Connect is called where we certainly have the config loaded
86+
return newWith(opt.Config, nil, nil, nil, opt.Secrets, opt.Signer, nil, nil), nil
9187
}
9288

9389
// New porter client, initialized with useful defaults.
@@ -103,6 +99,9 @@ func New() *Porter {
10399
return NewFor(c, storage, secretStorage, signer)
104100
}
105101

102+
// NewFor creates a new Porter client with the provided configuration and storage backend.
103+
//
104+
// Deprecated: Use NewWith instead. NewFor does not support SQL storage backends.
106105
func NewFor(
107106
c *config.Config,
108107
store storage.Store,
@@ -120,36 +119,6 @@ func NewFor(
120119
return newWith(c, installationStorage, credStorage, paramStorage, secretStorage, signer, sanitizerService, storageManager)
121120
}
122121

123-
func newWithSQL(
124-
c *config.Config,
125-
p config.StoragePlugin,
126-
secretStorage secrets.Store,
127-
signer signing.Signer,
128-
) (*Porter, error) {
129-
pc, err := sql.UnmarshalPluginConfig(p.GetConfig())
130-
if err != nil {
131-
return nil, fmt.Errorf("could not unmarshal plugin config: %s", err)
132-
}
133-
if pc.URL == "" {
134-
return nil, errors.New("no URL provided in plugin config")
135-
}
136-
_, err = url.Parse(pc.URL)
137-
if err != nil {
138-
return nil, fmt.Errorf("invalid URL provided in plugin config: %s", err)
139-
}
140-
db, err := gorm.Open(postgres.Open(pc.URL))
141-
if err != nil {
142-
return nil, fmt.Errorf("could not open database: %s", err)
143-
}
144-
145-
installationStorage := storage.NewInstallationStoreSQL(db)
146-
credStorage := storage.NewCredentialStoreSQL(db, secretStorage)
147-
paramStorage := storage.NewParameterStoreSQL(db, secretStorage)
148-
sanitizerService := storage.NewSanitizer(paramStorage, secretStorage)
149-
150-
return newWith(c, installationStorage, credStorage, paramStorage, secretStorage, signer, sanitizerService, nil), nil
151-
}
152-
153122
func newWith(
154123
c *config.Config,
155124
installationStorage storage.InstallationProvider,
@@ -160,6 +129,10 @@ func newWith(
160129
sanitizerService *storage.Sanitizer,
161130
storageManager storage.Provider,
162131
) *Porter {
132+
var cnab cnabprovider.CNABProvider
133+
if installationStorage != nil && credStorage != nil && paramStorage != nil && secretStorage != nil && sanitizerService != nil {
134+
cnab = cnabprovider.NewRuntime(c, installationStorage, credStorage, paramStorage, secretStorage, sanitizerService)
135+
}
163136

164137
return &Porter{
165138
Config: c,
@@ -173,7 +146,7 @@ func newWith(
173146
Templates: templates.NewTemplates(c),
174147
Mixins: mixin.NewPackageManager(c),
175148
Plugins: plugins.NewPackageManager(c),
176-
CNAB: cnabprovider.NewRuntime(c, installationStorage, credStorage, paramStorage, secretStorage, sanitizerService),
149+
CNAB: cnab,
177150
Sanitizer: sanitizerService,
178151
Signer: signer,
179152
}
@@ -196,8 +169,66 @@ func (p *Porter) Connect(ctx context.Context) (context.Context, error) {
196169
}
197170
})
198171

172+
init := func(ctx context.Context) error {
173+
if p.Installations != nil && p.Credentials != nil && p.Parameters != nil && p.Sanitizer != nil {
174+
return nil // already initialized
175+
}
176+
177+
storagePlugin, ok := sql.IsPostgresStorage(p.Config)
178+
if !ok {
179+
store := storage.NewPluginAdapter(storageplugin.NewStore(p.Config))
180+
mgr := migrations.NewManager(p.Config, store)
181+
182+
p.Storage = mgr
183+
p.Installations = storage.NewInstallationStore(p.Storage)
184+
p.Credentials = storage.NewCredentialStore(p.Storage, p.Secrets)
185+
p.Parameters = storage.NewParameterStore(p.Storage, p.Secrets)
186+
p.Sanitizer = storage.NewSanitizer(p.Parameters, p.Secrets)
187+
188+
mgr.Initialize(p.Sanitizer) // we have a bit of a dependency problem here that it would be great to figure out eventually
189+
return nil
190+
}
191+
192+
// Initialize the SQL storage backend
193+
pc, err := sql.UnmarshalPluginConfig(storagePlugin.GetConfig())
194+
if err != nil {
195+
return fmt.Errorf("could not unmarshal plugin config: %s", err)
196+
}
197+
if pc.URL == "" {
198+
return errors.New("no URL provided in plugin config")
199+
}
200+
db, err := gorm.Open(postgres.Open(pc.URL))
201+
if err != nil {
202+
return fmt.Errorf("could not open database: %s", err)
203+
}
204+
closeFn := func() error {
205+
if sqlDB, err := db.DB(); err == nil {
206+
return sqlDB.Close()
207+
}
208+
return nil
209+
}
210+
if err = migrate.MigrateDB(ctx, db); err != nil {
211+
_ = closeFn()
212+
return err
213+
}
214+
215+
p.onClose = append(p.onClose, closeFn)
216+
217+
if p.Installations == nil {
218+
p.Installations = storage.NewInstallationStoreSQL(db)
219+
}
220+
if p.Credentials == nil {
221+
p.Credentials = storage.NewCredentialStoreSQL(db, p.Secrets)
222+
}
223+
if p.Parameters == nil {
224+
p.Parameters = storage.NewParameterStoreSQL(db, p.Secrets)
225+
}
226+
227+
return nil
228+
}
229+
199230
// Load the config file and replace any referenced secrets
200-
return p.Config.Load(ctx, func(innerCtx context.Context, secret string) (string, error) {
231+
ctx, err := p.Config.Load(ctx, func(innerCtx context.Context, secret string) (string, error) {
201232
value, err := p.Secrets.Resolve(innerCtx, "secret", secret)
202233
if err != nil {
203234
if strings.Contains(err.Error(), "invalid value source: secret") {
@@ -207,6 +238,22 @@ func (p *Porter) Connect(ctx context.Context) (context.Context, error) {
207238
}
208239
return value, nil
209240
})
241+
if err != nil {
242+
return ctx, err
243+
}
244+
245+
if err = init(ctx); err != nil {
246+
return ctx, err
247+
}
248+
249+
if p.Sanitizer == nil {
250+
p.Sanitizer = storage.NewSanitizer(p.Parameters, p.Secrets)
251+
}
252+
if p.CNAB == nil {
253+
p.CNAB = cnabprovider.NewRuntime(p.Config, p.Installations, p.Credentials, p.Parameters, p.Secrets, p.Sanitizer)
254+
}
255+
256+
return ctx, nil
210257
}
211258

212259
// Close releases resources used by Porter before terminating the application.
@@ -225,6 +272,11 @@ func (p *Porter) Close() error {
225272
bigErr = multierror.Append(bigErr, err)
226273
}
227274
}
275+
for _, do := range p.onClose {
276+
if err = do(); err != nil {
277+
bigErr = multierror.Append(bigErr, err)
278+
}
279+
}
228280

229281
err = p.Config.Close()
230282
if err != nil {

0 commit comments

Comments
 (0)