get.porter.sh/porter@v1.3.0/pkg/storage/pluginstore/store.go (about) 1 package pluginstore 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 8 "get.porter.sh/porter/pkg/config" 9 "get.porter.sh/porter/pkg/plugins/pluggable" 10 "get.porter.sh/porter/pkg/storage/plugins" 11 "get.porter.sh/porter/pkg/tracing" 12 "go.mongodb.org/mongo-driver/bson" 13 "go.opentelemetry.io/otel/attribute" 14 ) 15 16 var _ io.Closer = &Store{} 17 var _ plugins.StorageProtocol = &Store{} 18 19 // Store is a plugin-backed source of storage. It resolves the appropriate 20 // plugin based on Porter's config and implements the plugins.StorageProtocol interface 21 // using the backing plugin. 22 // 23 // Connects just-in-time, but you must call Close to release resources. 24 type Store struct { 25 *config.Config 26 plugin plugins.StorageProtocol 27 conn *pluggable.PluginConnection 28 } 29 30 func NewStore(c *config.Config) *Store { 31 return &Store{ 32 Config: c, 33 } 34 } 35 36 // NewStoragePluginConfig for porter home storage. 37 func NewStoragePluginConfig() pluggable.PluginTypeConfig { 38 return pluggable.PluginTypeConfig{ 39 Interface: plugins.PluginInterface, 40 Plugin: &Plugin{}, 41 GetDefaultPluggable: func(c *config.Config) string { 42 return c.Data.DefaultStorage 43 }, 44 GetPluggable: func(c *config.Config, name string) (pluggable.Entry, error) { 45 return c.GetStorage(name) 46 }, 47 GetDefaultPlugin: func(c *config.Config) string { 48 return c.Data.DefaultStoragePlugin 49 }, 50 ProtocolVersion: plugins.PluginProtocolVersion, 51 } 52 } 53 54 // Connect initializes the plugin for use. 55 // The plugin itself is responsible for ensuring it was called. 56 // Close is called automatically when the plugin is used by Porter. 57 func (s *Store) Connect(ctx context.Context) error { 58 if s.plugin != nil { 59 return nil 60 } 61 62 ctx, span := tracing.StartSpan(ctx) 63 defer span.EndSpan() 64 65 pluginType := NewStoragePluginConfig() 66 67 l := pluggable.NewPluginLoader(s.Config) 68 conn, err := l.Load(ctx, pluginType) 69 if err != nil { 70 return span.Error(fmt.Errorf("could not load %s plugin: %w", pluginType.Interface, err)) 71 } 72 s.conn = conn 73 74 store, ok := conn.GetClient().(plugins.StorageProtocol) 75 if !ok { 76 conn.Close(ctx) 77 return span.Error(fmt.Errorf("the interface (%T) exposed by the %s plugin was not plugins.StorageProtocol", conn.GetClient(), conn)) 78 } 79 80 s.plugin = store 81 82 return nil 83 } 84 85 func (s *Store) Close() error { 86 if s.conn != nil { 87 s.conn.Close(context.Background()) 88 s.conn = nil 89 } 90 return nil 91 } 92 93 func (s *Store) EnsureIndex(ctx context.Context, opts plugins.EnsureIndexOptions) error { 94 ctx, span := tracing.StartSpan(ctx, 95 tracing.ObjectAttribute("options", opts)) 96 defer span.EndSpan() 97 98 if err := s.Connect(ctx); err != nil { 99 return err 100 } 101 102 err := s.plugin.EnsureIndex(ctx, opts) 103 return span.Error(err) 104 } 105 106 func (s *Store) Aggregate(ctx context.Context, opts plugins.AggregateOptions) ([]bson.Raw, error) { 107 ctx, span := tracing.StartSpan(ctx, 108 tracing.ObjectAttribute("options", opts)) 109 defer span.EndSpan() 110 111 if err := s.Connect(ctx); err != nil { 112 return nil, err 113 } 114 115 results, err := s.plugin.Aggregate(ctx, opts) 116 if err != nil { 117 return nil, span.Error(err) 118 } 119 120 return results, nil 121 } 122 123 func (s *Store) Count(ctx context.Context, opts plugins.CountOptions) (int64, error) { 124 ctx, span := tracing.StartSpan(ctx, 125 tracing.ObjectAttribute("options", opts)) 126 defer span.EndSpan() 127 128 if err := s.Connect(ctx); err != nil { 129 return 0, err 130 } 131 132 count, err := s.plugin.Count(ctx, opts) 133 if err != nil { 134 return 0, span.Error(err) 135 } 136 span.SetAttributes(attribute.Int64("result", count)) 137 return count, nil 138 } 139 140 func (s *Store) Find(ctx context.Context, opts plugins.FindOptions) ([]bson.Raw, error) { 141 ctx, span := tracing.StartSpan(ctx, 142 tracing.ObjectAttribute("options", opts)) 143 defer span.EndSpan() 144 145 if err := s.Connect(ctx); err != nil { 146 return nil, err 147 } 148 149 results, err := s.plugin.Find(ctx, opts) 150 span.SetAttributes(attribute.Int("results", len(results))) 151 return results, span.Error(err) 152 } 153 154 func (s *Store) Insert(ctx context.Context, opts plugins.InsertOptions) error { 155 ctx, span := tracing.StartSpan(ctx, 156 tracing.ObjectAttribute("options", opts)) 157 defer span.EndSpan() 158 159 if err := s.Connect(ctx); err != nil { 160 return err 161 } 162 163 err := s.plugin.Insert(ctx, opts) 164 return span.Error(err) 165 } 166 167 func (s *Store) Patch(ctx context.Context, opts plugins.PatchOptions) error { 168 ctx, span := tracing.StartSpan(ctx, 169 tracing.ObjectAttribute("options", opts)) 170 defer span.EndSpan() 171 172 if err := s.Connect(ctx); err != nil { 173 return err 174 } 175 176 err := s.plugin.Patch(ctx, opts) 177 return span.Error(err) 178 } 179 180 func (s *Store) Remove(ctx context.Context, opts plugins.RemoveOptions) error { 181 ctx, span := tracing.StartSpan(ctx, 182 tracing.ObjectAttribute("options", opts)) 183 defer span.EndSpan() 184 185 if err := s.Connect(ctx); err != nil { 186 return err 187 } 188 189 err := s.plugin.Remove(ctx, opts) 190 return span.Error(err) 191 } 192 193 func (s *Store) Update(ctx context.Context, opts plugins.UpdateOptions) error { 194 ctx, span := tracing.StartSpan(ctx, 195 tracing.ObjectAttribute("options", opts)) 196 defer span.EndSpan() 197 198 if err := s.Connect(ctx); err != nil { 199 return err 200 } 201 202 err := s.plugin.Update(ctx, opts) 203 return span.Error(err) 204 }