// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package dbplugin import ( "context" "fmt" "github.com/hashicorp/errwrap" log "github.com/hashicorp/go-hclog" "github.com/hashicorp/vault/sdk/helper/consts" "github.com/hashicorp/vault/sdk/helper/pluginutil" ) // PluginFactory is used to build plugin database types. It wraps the database // object in a logging and metrics middleware. func PluginFactory(ctx context.Context, pluginName string, sys pluginutil.LookRunnerUtil, logger log.Logger) (Database, error) { return PluginFactoryVersion(ctx, pluginName, "", sys, logger) } // PluginFactoryVersion is used to build plugin database types with a version specified. // It wraps the database object in a logging and metrics middleware. func PluginFactoryVersion(ctx context.Context, pluginName string, pluginVersion string, sys pluginutil.LookRunnerUtil, logger log.Logger) (Database, error) { // Look for plugin in the plugin catalog pluginRunner, err := sys.LookupPluginVersion(ctx, pluginName, consts.PluginTypeDatabase, pluginVersion) if err != nil { return nil, err } namedLogger := logger.Named(pluginName) var transport string var db Database if pluginRunner.Builtin { // Plugin is builtin so we can retrieve an instance of the interface // from the pluginRunner. Then cast it to a Database. dbRaw, err := pluginRunner.BuiltinFactory() if err != nil { return nil, errwrap.Wrapf("error initializing plugin: {{err}}", err) } var ok bool db, ok = dbRaw.(Database) if !ok { return nil, fmt.Errorf("unsupported database type: %q", pluginName) } transport = "builtin" } else { config := pluginutil.PluginClientConfig{ Name: pluginName, PluginType: consts.PluginTypeDatabase, Version: pluginVersion, PluginSets: PluginSets, HandshakeConfig: HandshakeConfig, Logger: namedLogger, IsMetadataMode: false, AutoMTLS: true, Wrapper: sys, } // create a DatabasePluginClient instance db, err = NewPluginClient(ctx, sys, config) if err != nil { return nil, err } // Switch on the underlying database client type to get the transport // method. switch db.(*DatabasePluginClient).Database.(type) { case *gRPCClient: transport = "gRPC" } } typeStr, err := db.Type() if err != nil { return nil, errwrap.Wrapf("error getting plugin type: {{err}}", err) } logger.Debug("got database plugin instance", "type", typeStr) // Wrap with metrics middleware db = &databaseMetricsMiddleware{ next: db, typeStr: typeStr, } // Wrap with tracing middleware if namedLogger.IsTrace() { db = &databaseTracingMiddleware{ next: db, logger: namedLogger.With("transport", transport), } } return db, nil }