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  }