/
store.go
123 lines (103 loc) · 3.28 KB
/
store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package pluginstore
import (
"context"
"errors"
"fmt"
"get.porter.sh/porter/pkg/config"
"get.porter.sh/porter/pkg/plugins/pluggable"
"get.porter.sh/porter/pkg/secrets/plugins"
"get.porter.sh/porter/pkg/tracing"
"go.opentelemetry.io/otel/attribute"
)
var _ plugins.SecretsProtocol = &Store{}
// Store is a plugin-backed source of secrets. It resolves the appropriate
// plugin based on Porter's config and implements the plugins.SecretsProtocol interface
// using the backing plugin.
//
// Connects just-in-time, but you must call Close to release resources.
type Store struct {
*config.Config
plugin plugins.SecretsProtocol
conn *pluggable.PluginConnection
}
func NewStore(c *config.Config) *Store {
return &Store{
Config: c,
}
}
// NewSecretsPluginConfig for secret sources.
func NewSecretsPluginConfig() pluggable.PluginTypeConfig {
return pluggable.PluginTypeConfig{
Interface: plugins.PluginInterface,
Plugin: &Plugin{},
GetDefaultPluggable: func(c *config.Config) string {
return c.Data.DefaultSecrets
},
GetPluggable: func(c *config.Config, name string) (pluggable.Entry, error) {
return c.GetSecretsPlugin(name)
},
GetDefaultPlugin: func(c *config.Config) string {
return c.Data.DefaultSecretsPlugin
},
ProtocolVersion: plugins.PluginProtocolVersion,
}
}
func (s *Store) Resolve(ctx context.Context, keyName string, keyValue string) (string, error) {
ctx, span := tracing.StartSpan(ctx,
attribute.String("keyName", keyName),
attribute.String("keyValue", keyValue))
defer span.EndSpan()
if err := s.Connect(ctx); err != nil {
return "", err
}
value, err := s.plugin.Resolve(ctx, keyName, keyValue)
if err != nil {
return "", span.Error(err)
}
return value, nil
}
func (s *Store) Create(ctx context.Context, keyName string, keyValue string, value string) error {
ctx, span := tracing.StartSpan(ctx,
attribute.String("keyName", keyName),
attribute.String("keyValue", keyValue))
defer span.EndSpan()
if err := s.Connect(ctx); err != nil {
return err
}
err := s.plugin.Create(ctx, keyName, keyValue, value)
if errors.Is(err, plugins.ErrNotImplemented) {
return span.Error(fmt.Errorf(`the current secrets plugin does not support persisting secrets. You need to edit your porter configuration file and configure a different secrets plugin. See https://porter.sh/end-users/configuration/#change-the-default-secrets-plugin for details: %w`, err))
}
return span.Error(err)
}
// Connect initializes the plugin for use.
// The plugin itself is responsible for ensuring it was called.
// Close is called automatically when the plugin is used by Porter.
func (s *Store) Connect(ctx context.Context) error {
if s.plugin != nil {
return nil
}
ctx, span := tracing.StartSpan(ctx)
defer span.EndSpan()
pluginType := NewSecretsPluginConfig()
l := pluggable.NewPluginLoader(s.Config)
conn, err := l.Load(ctx, pluginType)
if err != nil {
return span.Error(err)
}
s.conn = conn
store, ok := conn.GetClient().(plugins.SecretsProtocol)
if !ok {
conn.Close(ctx)
return span.Error(fmt.Errorf("the interface (%T) exposed by the %s plugin was not plugins.SecretsProtocol", conn.GetClient(), conn))
}
s.plugin = store
return nil
}
func (s *Store) Close() error {
if s.conn != nil {
s.conn.Close(context.Background())
s.conn = nil
}
return nil
}