Update plugin manager loading. Add ruby client.

This commit is contained in:
Chris Roberts 2022-06-14 09:57:13 -07:00
parent a8fd255f5b
commit 1134a4e5ed
3 changed files with 91 additions and 12 deletions

View File

@ -27,6 +27,16 @@ func NewInternal(
}
}
func Internal(l hclog.Logger, m []*argmapper.Func) *internal {
return &internal{
broker: nil,
cache: cacher.New(),
cleanup: cleanup.New(),
logger: l,
mappers: m,
}
}
type internal struct {
broker *plugin.GRPCBroker
cache cacher.Cache

View File

@ -41,6 +41,7 @@ var (
type PluginRegistration func(hclog.Logger) (*Plugin, error)
type PluginConfigurator func(*Instance, hclog.Logger) error
type PluginInitializer func(*Plugin, hclog.Logger) error
type componentCache map[string]componentEntry
type componentEntry map[component.Type]*Instance
@ -56,16 +57,22 @@ type Manager struct {
discoveredPaths []path.Path // List of paths this manager has loaded
dispenseFuncs []PluginConfigurator // Configuration functions applied to instances
instances componentCache // Cache for prevlous generated components
initFuncs []PluginInitializer // Initializer functions applied to plugins at creation
legacyLoaded bool // Flag that legacy plugins have been loaded
legacyBroker *plugin.GRPCBroker // Broker for legacy runtime
logger hclog.Logger // Logger for the manager
m sync.Mutex
parent *Manager // Parent manager if this is a sub manager
srv []byte // Marshalled proto message for plugin manager
rubyC *serverclient.RubyVagrantClient // Client to the Ruby runtime
parent *Manager // Parent manager if this is a sub manager
srv []byte // Marshalled proto message for plugin manager
}
// Create a new plugin manager
func NewManager(ctx context.Context, l hclog.Logger) *Manager {
func NewManager(
ctx context.Context, // context for the manager
r *serverclient.RubyVagrantClient, // client to the ruby runtime
l hclog.Logger, // logger
) *Manager {
return &Manager{
Plugins: []*Plugin{},
builtins: NewBuiltins(ctx, l),
@ -75,9 +82,18 @@ func NewManager(ctx context.Context, l hclog.Logger) *Manager {
dispenseFuncs: []PluginConfigurator{},
instances: make(componentCache),
logger: l,
rubyC: r,
}
}
// Returns the client to the Ruby runtime
func (m *Manager) RubyClient() *serverclient.RubyVagrantClient {
if m.parent != nil {
return m.parent.RubyClient()
}
return m.rubyC
}
// Create a sub manager based off current manager
func (m *Manager) Sub(name string) *Manager {
if name == "" {
@ -326,7 +342,13 @@ func (m *Manager) Configure(fn PluginConfigurator) error {
return nil
}
// Find a specific plugin by name and component type
// Add initializer to be applied to plugin when created
func (m *Manager) Initializer(fn PluginInitializer) error {
m.initFuncs = append(m.initFuncs, fn)
return nil
}
// Find a component instance by plugin name and component type
func (m *Manager) Find(
n string, // Name of the plugin
t component.Type, // component type of plugin
@ -337,6 +359,24 @@ func (m *Manager) Find(
return m.find(n, t)
}
// Get a plugin by name
func (m *Manager) Get(
n string, // Name of the plugin
t component.Type, // component type supported by plugin
) (*Plugin, error) {
for _, p := range m.Plugins {
if p.Name == n && p.HasType(t) {
return p, nil
}
}
if m.parent != nil {
return m.parent.Get(n, t)
}
return nil, fmt.Errorf("failed to locate plugin %s implementing component %s", n, t.String())
}
// Find all plugins which support a specific component type
func (m *Manager) Typed(
t component.Type, // Type of plugins
@ -348,6 +388,10 @@ func (m *Manager) Typed(
for _, p := range m.Plugins {
if p.HasType(t) {
result = append(result, p.Name)
m.logger.Trace("found typed plugin match",
"type", t.String(),
"name", p.Name,
)
}
}
@ -524,6 +568,13 @@ func (m *Manager) register(
}
plg.manager = m
// Run initializers on new plugin
for _, fn := range m.initFuncs {
if err = fn(plg, m.logger); err != nil {
return
}
}
m.Plugins = append(m.Plugins, plg)
return
}
@ -597,10 +648,6 @@ func (m *Manager) fetch(
t component.Type, // type of component
c []PluginConfigurator,
) (i *Instance, err error) {
m.logger.Info("configurators for use by fetch function",
"passed-count", len(c),
"local-count", len(m.dispenseFuncs),
)
var cfns []PluginConfigurator
if len(c) > 0 {
l := len(c) + len(m.dispenseFuncs)
@ -615,7 +662,7 @@ func (m *Manager) fetch(
// and generate the component instance
for _, p := range m.Plugins {
if p.Name == n && p.HasType(t) {
return p.InstanceOf(t, cfns)
return p.instanceOf(t, cfns)
}
}
@ -650,7 +697,7 @@ func (m *Manager) isCacheable(t component.Type) bool {
func (m *Manager) loadParent(i *Instance) error {
c, ok := i.Component.(HasParent)
if !ok {
m.logger.Debug("component component does not support parents",
m.logger.Trace("component does not support parents",
"type", i.Type.String(),
"name", i.Name,
)

View File

@ -15,6 +15,7 @@ import (
"github.com/hashicorp/vagrant-plugin-sdk/core"
"github.com/hashicorp/vagrant-plugin-sdk/internal-shared/cacher"
"github.com/hashicorp/vagrant-plugin-sdk/internal-shared/cleanup"
"github.com/hashicorp/vagrant/builtin/configvagrant"
"github.com/hashicorp/vagrant/builtin/httpdownloader"
"github.com/hashicorp/vagrant/builtin/myplugin"
"github.com/hashicorp/vagrant/builtin/otherplugin"
@ -32,6 +33,7 @@ var (
// Builtins is the map of all available builtin plugins and their
// options for launching them.
Builtins = map[string][]sdk.Option{
"configvagrant": configvagrant.CommandOptions,
"myplugin": myplugin.CommandOptions,
"otherplugin": otherplugin.CommandOptions,
"httpdownloader": httpdownloader.PluginOptions,
@ -77,6 +79,23 @@ type HasParent interface {
SetParentComponent(interface{})
}
// Returns the plugin manager instance this plugin is attached
func (p *Plugin) Manager() *Manager {
return p.manager
}
// Get a component from the plugin. This will load the component via
// the configured plugin manager so all expected caching and configuration
// will occur.
func (p *Plugin) Component(t component.Type) (interface{}, error) {
i, err := p.manager.Find(p.Name, t)
if err != nil {
return nil, err
}
return i.Component, nil
}
// Check if plugin implements specific component type
func (p *Plugin) HasType(
t component.Type,
@ -102,8 +121,11 @@ func (p *Plugin) Close() (err error) {
return p.cleaner.Close()
}
// Get specific component type from plugin
func (p *Plugin) InstanceOf(
// Get specific component type from plugin. This is not exported
// as it should not be called directly. The plugin manager should
// be used for loading component instances so all callbacks are
// applied appropriately and caching will be respected
func (p *Plugin) instanceOf(
c component.Type,
cfns []PluginConfigurator,
) (i *Instance, err error) {