/
legacy_plugin_adapter.go
130 lines (110 loc) · 3.8 KB
/
legacy_plugin_adapter.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
124
125
126
127
128
129
130
package migrations
import (
"context"
"fmt"
"path/filepath"
"get.porter.sh/porter/pkg/config"
"get.porter.sh/porter/pkg/plugins/pluggable"
"get.porter.sh/porter/pkg/storage/migrations/crudstore"
"get.porter.sh/porter/pkg/storage/plugins"
"get.porter.sh/porter/pkg/tracing"
"go.opentelemetry.io/otel/attribute"
)
// LegacyPluginAdapter can connect to a legacy Porter v0.38 storage plugin to
// retrieve data to migrate to the current version of Porter.
type LegacyPluginAdapter struct {
config *config.Config
// The name of the source storage account from which we will read old Porter data.
storageName string
// The path to an older PORTER_HOME directory containing the previous version
// of Porter and compatible plugins.
oldPorterHome string
// The legacy porter v0.38 storage interface that we will use with the old plugins
// to retrieve data.
store crudstore.Store
// Connection to the legacy plugin
pluginConn *pluggable.PluginConnection
}
func NewLegacyPluginAdapter(c *config.Config, oldPorterHome string, storageName string) *LegacyPluginAdapter {
return &LegacyPluginAdapter{
config: c,
oldPorterHome: oldPorterHome,
storageName: storageName,
}
}
// Connect loads the legacy plugin specified by the source storage account.
func (m *LegacyPluginAdapter) Connect(ctx context.Context) error {
ctx, log := tracing.StartSpan(ctx,
attribute.String("storage-name", m.storageName))
defer log.EndSpan()
// Create a config file that uses the old PORTER_HOME
oldConfig := config.New()
oldConfig.SetHomeDir(m.oldPorterHome)
oldConfig.SetPorterPath(filepath.Join(m.oldPorterHome, "porter"))
oldConfig.Load(ctx, func(ctx context.Context, secretKey string) (string, error) {
return "", nil
})
oldConfig.Setenv(config.EnvHOME, m.oldPorterHome)
// Start the plugin
l := pluggable.NewPluginLoader(oldConfig)
conn, err := l.Load(ctx, m.makePluginConfig())
if err != nil {
return log.Error(fmt.Errorf("could not load legacy storage plugin: %w", err))
}
m.pluginConn = conn
// Ensure we close the plugin connection if anything fails
// Afterwards its on the caller to close it
connected := false
defer func() {
if !connected {
conn.Close(ctx)
}
}()
// Cast the plugin connection to a subset of the old protocol from v0.38 that can only read data
store, ok := conn.GetClient().(crudstore.Store)
if !ok {
return log.Error(fmt.Errorf("the interface exposed by the %s plugin was not crudstore.Store", conn))
}
m.store = store
connected = true
return nil
}
// makePluginConfig creates a plugin configuration compatible with the legacy plugins
// from porter v0.38
func (m *LegacyPluginAdapter) makePluginConfig() pluggable.PluginTypeConfig {
return pluggable.PluginTypeConfig{
Interface: plugins.PluginInterface,
Plugin: &crudstore.Plugin{},
GetDefaultPluggable: func(c *config.Config) string {
// Load the config for the specific storage account named as the source for the migration
return m.storageName
},
GetPluggable: func(c *config.Config, name string) (pluggable.Entry, error) {
return c.GetStorage(name)
},
GetDefaultPlugin: func(c *config.Config) string {
// filesystem is the default storage plugin for v0.38
return "filesystem"
},
ProtocolVersion: 1, // protocol version used by porter v0.38
}
}
func (m *LegacyPluginAdapter) Close() error {
if m.pluginConn != nil {
m.pluginConn.Close(context.Background())
m.pluginConn = nil
}
return nil
}
func (m *LegacyPluginAdapter) List(ctx context.Context, itemType string, group string) ([]string, error) {
if err := m.Connect(ctx); err != nil {
return nil, err
}
return m.store.List(itemType, group)
}
func (m *LegacyPluginAdapter) Read(ctx context.Context, itemType string, name string) ([]byte, error) {
if err := m.Connect(ctx); err != nil {
return nil, err
}
return m.store.Read(itemType, name)
}