Use plugin manager for plugins. Remove component specialization.
This commit is contained in:
parent
b573385dd3
commit
e10cd26407
@ -10,8 +10,6 @@ import (
|
||||
"github.com/hashicorp/go-argmapper"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/hashicorp/vagrant-plugin-sdk/component"
|
||||
"github.com/hashicorp/vagrant-plugin-sdk/core"
|
||||
@ -22,7 +20,6 @@ import (
|
||||
"github.com/hashicorp/vagrant-plugin-sdk/terminal"
|
||||
|
||||
"github.com/hashicorp/vagrant/internal/config"
|
||||
"github.com/hashicorp/vagrant/internal/factory"
|
||||
"github.com/hashicorp/vagrant/internal/plugin"
|
||||
"github.com/hashicorp/vagrant/internal/server/proto/vagrant_server"
|
||||
"github.com/hashicorp/vagrant/internal/serverclient"
|
||||
@ -35,15 +32,14 @@ import (
|
||||
// finished with the basis to properly clean
|
||||
// up any open resources.
|
||||
type Basis struct {
|
||||
basis *vagrant_server.Basis
|
||||
logger hclog.Logger
|
||||
config *config.Config
|
||||
componentCache map[component.Type]map[string]*Component
|
||||
projects map[string]*Project
|
||||
factories map[component.Type]*factory.Factory
|
||||
mappers []*argmapper.Func
|
||||
dir *datadir.Basis
|
||||
ctx context.Context
|
||||
basis *vagrant_server.Basis
|
||||
logger hclog.Logger
|
||||
config *config.Config
|
||||
plugins *plugin.Manager
|
||||
projects map[string]*Project
|
||||
mappers []*argmapper.Func
|
||||
dir *datadir.Basis
|
||||
ctx context.Context
|
||||
|
||||
lock sync.Mutex
|
||||
client *serverclient.VagrantClient
|
||||
@ -56,11 +52,10 @@ type Basis struct {
|
||||
// NewBasis creates a new Basis with the given options.
|
||||
func NewBasis(ctx context.Context, opts ...BasisOption) (b *Basis, err error) {
|
||||
b = &Basis{
|
||||
ctx: ctx,
|
||||
logger: hclog.L(),
|
||||
jobInfo: &component.JobInfo{},
|
||||
factories: plugin.BaseFactories,
|
||||
projects: map[string]*Project{},
|
||||
ctx: ctx,
|
||||
logger: hclog.L(),
|
||||
jobInfo: &component.JobInfo{},
|
||||
projects: map[string]*Project{},
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
@ -109,9 +104,6 @@ func NewBasis(ctx context.Context, opts ...BasisOption) (b *Basis, err error) {
|
||||
return
|
||||
}
|
||||
}
|
||||
commandArgMapper, _ := argmapper.NewFunc(CommandArgToMap,
|
||||
argmapper.Logger(dynamic.Logger))
|
||||
b.mappers = append(b.mappers, commandArgMapper)
|
||||
|
||||
// TODO(spox): After fixing up datadir, use that to do
|
||||
// configuration loading
|
||||
@ -127,12 +119,6 @@ func NewBasis(ctx context.Context, opts ...BasisOption) (b *Basis, err error) {
|
||||
// Ensure any modifications to the basis are persisted
|
||||
b.Closer(func() error { return b.Save() })
|
||||
|
||||
// Setup our caching area for components
|
||||
b.componentCache = map[component.Type]map[string]*Component{}
|
||||
for t, _ := range component.TypeMap {
|
||||
b.componentCache[t] = map[string]*Component{}
|
||||
}
|
||||
|
||||
// Add in our local mappers
|
||||
for _, fn := range Mappers {
|
||||
f, err := argmapper.NewFunc(fn,
|
||||
@ -196,75 +182,66 @@ func (b *Basis) Client() *serverclient.VagrantClient {
|
||||
|
||||
// Returns the detected host for the current platform
|
||||
func (b *Basis) Host() (host core.Host, err error) {
|
||||
var hostName string
|
||||
hosts, err := b.typeComponents(b.ctx, component.HostType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var valid core.Host
|
||||
for n, h := range hosts {
|
||||
b.logger.Trace("running host check",
|
||||
"plugin", hclog.Fmt("%T", h.Value),
|
||||
"name", n,
|
||||
)
|
||||
var result core.Host
|
||||
var result_name string
|
||||
|
||||
for name, h := range hosts {
|
||||
host := h.Value.(core.Host)
|
||||
detected, err := host.Detect()
|
||||
b.logger.Trace("completed host check",
|
||||
"plugin", hclog.Fmt("%T", host),
|
||||
"name", n,
|
||||
"detected", detected)
|
||||
|
||||
if err != nil {
|
||||
b.logger.Error("host check failure",
|
||||
"plugin", hclog.Fmt("%T", host),
|
||||
"name", n,
|
||||
b.logger.Error("host error on detection check",
|
||||
"plugin", name,
|
||||
"type", "Host",
|
||||
"error", err)
|
||||
|
||||
continue
|
||||
}
|
||||
if result == nil {
|
||||
if detected {
|
||||
result = host
|
||||
result_name = name
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
hp, err := host.Parents()
|
||||
if err != nil {
|
||||
b.logger.Error("failed to get parents from host",
|
||||
"plugin", name,
|
||||
"type", "Host",
|
||||
"error", err)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if !detected {
|
||||
rp, err := result.Parents()
|
||||
if err != nil {
|
||||
b.logger.Error("failed to get parents from host",
|
||||
"plugin", result_name,
|
||||
"type", "Host",
|
||||
"error", err)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if valid == nil {
|
||||
b.logger.Trace("setting valid host",
|
||||
"plugin", hclog.Fmt("%T", host),
|
||||
"name", n,
|
||||
)
|
||||
hostName = n
|
||||
valid = host
|
||||
continue
|
||||
}
|
||||
|
||||
vp, err := valid.Parents()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hp, err := host.Parents()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(hp) > len(vp) {
|
||||
b.logger.Trace("updating valid host",
|
||||
"plugin", hclog.Fmt("%T", host),
|
||||
"name", n,
|
||||
)
|
||||
valid = host
|
||||
hostName = n
|
||||
if len(hp) > len(rp) {
|
||||
result = host
|
||||
result_name = name
|
||||
}
|
||||
}
|
||||
|
||||
if valid == nil {
|
||||
if result == nil {
|
||||
return nil, fmt.Errorf("failed to detect host plugin for current platform")
|
||||
}
|
||||
|
||||
b.logger.Info("host detection complete",
|
||||
"plugin", hclog.Fmt("%T", valid),
|
||||
"host", hostName,
|
||||
)
|
||||
return valid, nil
|
||||
"name", result_name)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Initializes the basis for running a command. This will inspect
|
||||
@ -272,24 +249,18 @@ func (b *Basis) Host() (host core.Host, err error) {
|
||||
// information before an actual command is run
|
||||
func (b *Basis) Init() (result *vagrant_server.Job_InitResult, err error) {
|
||||
b.logger.Debug("running init for basis")
|
||||
f := b.factories[component.CommandType]
|
||||
result = &vagrant_server.Job_InitResult{
|
||||
Commands: []*vagrant_server.Job_Command{},
|
||||
}
|
||||
ctx := context.Background()
|
||||
|
||||
for _, name := range f.Registered() {
|
||||
var cmd *Component
|
||||
cmd, err = b.component(ctx, component.CommandType, name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cmds, err := b.typeComponents(ctx, component.CommandType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = b.specializeComponent(cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fn := cmd.Value.(component.Command).CommandInfoFunc()
|
||||
for _, c := range cmds {
|
||||
fn := c.Value.(component.Command).CommandInfoFunc()
|
||||
raw, err := b.callDynamicFunc(ctx, b.logger, fn,
|
||||
(*[]*vagrant_server.Job_Command)(nil))
|
||||
|
||||
@ -328,13 +299,12 @@ func (b *Basis) Project(nameOrId string) *Project {
|
||||
func (b *Basis) LoadProject(popts ...ProjectOption) (p *Project, err error) {
|
||||
// Create our project
|
||||
p = &Project{
|
||||
ctx: b.ctx,
|
||||
basis: b,
|
||||
logger: b.logger,
|
||||
mappers: b.mappers,
|
||||
factories: b.factories,
|
||||
targets: map[string]*Target{},
|
||||
ui: b.ui,
|
||||
ctx: b.ctx,
|
||||
basis: b,
|
||||
logger: b.logger,
|
||||
mappers: b.mappers,
|
||||
targets: map[string]*Target{},
|
||||
ui: b.ui,
|
||||
}
|
||||
|
||||
// Apply any options provided
|
||||
@ -465,28 +435,7 @@ func (b *Basis) SaveFull() (err error) {
|
||||
|
||||
// Returns the list of all known components
|
||||
func (b *Basis) Components(ctx context.Context) ([]*Component, error) {
|
||||
var results []*Component
|
||||
for _, cc := range componentCreatorMap {
|
||||
c, err := cc.Create(ctx, b, "")
|
||||
if status.Code(err) == codes.Unimplemented {
|
||||
c = nil
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
// Make sure we clean ourselves up in an error case.
|
||||
for _, r := range results {
|
||||
r.Close()
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c != nil {
|
||||
results = append(results, c)
|
||||
}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
return b.components(b.ctx)
|
||||
}
|
||||
|
||||
// Runs a specific task via component which matches the task's
|
||||
@ -502,11 +451,6 @@ func (b *Basis) Run(ctx context.Context, task *vagrant_server.Task) (err error)
|
||||
return err
|
||||
}
|
||||
|
||||
// Specialize it if required
|
||||
if _, err = b.specializeComponent(cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fn := cmd.Value.(component.Command).ExecuteFunc(
|
||||
strings.Split(task.CommandName, " "))
|
||||
result, err := b.callDynamicFunc(ctx, b.logger, fn, (*int32)(nil),
|
||||
@ -543,17 +487,29 @@ func (b *Basis) component(
|
||||
if typ == component.CommandType {
|
||||
name = strings.Split(name, " ")[0]
|
||||
}
|
||||
if c, ok := b.componentCache[typ][name]; ok {
|
||||
return c, nil
|
||||
p, err := b.plugins.ByName(name, typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c, err := componentCreatorMap[typ].Create(ctx, b, name)
|
||||
c, err := p.InstanceOf(typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.componentCache[typ][name] = c
|
||||
b.Closer(func() error { return c.Close() })
|
||||
return c, nil
|
||||
// TODO(spox): we need to add hooks
|
||||
|
||||
hooks := map[string][]*config.Hook{}
|
||||
return &Component{
|
||||
Value: c.Component,
|
||||
Info: &vagrant_server.Component{
|
||||
Type: vagrant_server.Component_Type(typ),
|
||||
Name: p.Name,
|
||||
ServerAddr: b.Client().ServerTarget(),
|
||||
},
|
||||
hooks: hooks,
|
||||
mappers: b.mappers,
|
||||
plugin: c,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Load all components of a specific type
|
||||
@ -561,15 +517,18 @@ func (b *Basis) typeComponents(
|
||||
ctx context.Context, // context for the plugins,
|
||||
typ component.Type, // type of the components,
|
||||
) (map[string]*Component, error) {
|
||||
f := b.factories[typ]
|
||||
result := map[string]*Component{}
|
||||
plugins, err := b.plugins.ByType(typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, name := range f.Registered() {
|
||||
c, err := b.component(ctx, typ, name)
|
||||
for _, p := range plugins {
|
||||
c, err := b.component(ctx, typ, p.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[name] = c
|
||||
result[p.Name] = c
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@ -580,9 +539,9 @@ func (b *Basis) components(
|
||||
) ([]*Component, error) {
|
||||
result := []*Component{}
|
||||
|
||||
for typ, f := range b.factories {
|
||||
for _, name := range f.Registered() {
|
||||
c, err := b.component(ctx, typ, name)
|
||||
for _, p := range b.plugins.Plugins {
|
||||
for _, t := range p.Types {
|
||||
c, err := b.component(ctx, t, p.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -592,72 +551,6 @@ func (b *Basis) components(
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Specialize a given component. This is specifically used for
|
||||
// Ruby based legacy Vagrant components.
|
||||
//
|
||||
// TODO: Since legacy Vagrant is no longer directly connecting
|
||||
// to the Vagrant server, this should probably be removed.
|
||||
func (b *Basis) specializeComponent(
|
||||
c *Component, // component to specialize
|
||||
) (cmp plugin.PluginMetadata, err error) {
|
||||
var ok bool
|
||||
if cmp, ok = c.Value.(plugin.PluginMetadata); !ok {
|
||||
return nil, fmt.Errorf("component does not support specialization")
|
||||
}
|
||||
cmp.SetRequestMetadata("basis_resource_id", b.ResourceId())
|
||||
cmp.SetRequestMetadata("vagrant_service_endpoint", b.client.ServerTarget())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// startPlugin starts a plugin with the given type and name. The returned
|
||||
// value must be closed to clean up the plugin properly.
|
||||
func (b *Basis) startPlugin(
|
||||
ctx context.Context, // context used for the plugin
|
||||
typ component.Type, // type of component plugin to start
|
||||
n string, // name of component plugin to start
|
||||
) (*plugin.Instance, error) {
|
||||
log := b.logger.ResetNamed(
|
||||
fmt.Sprintf("vagrant.plugin.%s.%s", strings.ToLower(typ.String()), n))
|
||||
|
||||
f, ok := b.factories[typ]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unknown factory: %T", typ)
|
||||
}
|
||||
|
||||
// Get the factory function for this type
|
||||
fn := f.Func(n)
|
||||
if fn == nil {
|
||||
return nil, fmt.Errorf("unknown type: %q", n)
|
||||
}
|
||||
|
||||
// Call the factory to get our raw value (interface{} type)
|
||||
fnResult := fn.Call(argmapper.Typed(ctx, log),
|
||||
argmapper.Logger(dynamic.Logger))
|
||||
|
||||
if err := fnResult.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Info("initialized component", "type",
|
||||
typ.String(),
|
||||
"name", n)
|
||||
|
||||
raw := fnResult.Out(0)
|
||||
|
||||
// If we have a plugin.Instance then we can extract other information
|
||||
// from this plugin. We accept pure factories too that don't return
|
||||
// this so we type-check here.
|
||||
pinst, ok := raw.(*plugin.Instance)
|
||||
if !ok {
|
||||
pinst = &plugin.Instance{
|
||||
Component: raw,
|
||||
Close: func() {},
|
||||
}
|
||||
}
|
||||
|
||||
return pinst, nil
|
||||
}
|
||||
|
||||
// Calls the function provided and converts the
|
||||
// result to an expected type. If no type conversion
|
||||
// is required, a `false` value for the expectedType
|
||||
@ -723,11 +616,9 @@ func WithLogger(log hclog.Logger) BasisOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithFactory sets a factory for a component type. If this isn't set for
|
||||
// any component type, then the builtin mapper will be used.
|
||||
func WithFactory(t component.Type, f *factory.Factory) BasisOption {
|
||||
func WithPluginManager(m *plugin.Manager) BasisOption {
|
||||
return func(b *Basis) (err error) {
|
||||
b.factories[t] = f
|
||||
b.plugins = m
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -739,14 +630,6 @@ func WithBasisConfig(c *config.Config) BasisOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithComponents sets the factories for components.
|
||||
func WithComponents(fs map[component.Type]*factory.Factory) BasisOption {
|
||||
return func(b *Basis) (err error) {
|
||||
b.factories = fs
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// WithMappers adds the mappers to the list of mappers.
|
||||
func WithMappers(m ...*argmapper.Func) BasisOption {
|
||||
return func(b *Basis) (err error) {
|
||||
|
||||
@ -19,7 +19,6 @@ import (
|
||||
|
||||
"github.com/hashicorp/vagrant/internal/config"
|
||||
"github.com/hashicorp/vagrant/internal/factory"
|
||||
"github.com/hashicorp/vagrant/internal/plugin"
|
||||
"github.com/hashicorp/vagrant/internal/server/proto/vagrant_server"
|
||||
"github.com/hashicorp/vagrant/internal/serverclient"
|
||||
)
|
||||
@ -229,10 +228,6 @@ func (p *Project) Run(ctx context.Context, task *vagrant_server.Task) (err error
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = p.specializeComponent(cmd); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fn := cmd.Value.(component.Command).ExecuteFunc(
|
||||
strings.Split(task.CommandName, " "))
|
||||
result, err := p.callDynamicFunc(ctx, p.logger, fn, (*int32)(nil),
|
||||
@ -378,21 +373,6 @@ func (p *Project) callDynamicFunc(
|
||||
return p.basis.callDynamicFunc(ctx, log, f, expectedType, args...)
|
||||
}
|
||||
|
||||
// Specialize a given component. This is specifically used for
|
||||
// Ruby based legacy Vagrant components.
|
||||
//
|
||||
// TODO: Since legacy Vagrant is no longer directly connecting
|
||||
// to the Vagrant server, this should probably be removed.
|
||||
func (p *Project) specializeComponent(
|
||||
c *Component, // component to specialize
|
||||
) (cmp plugin.PluginMetadata, err error) {
|
||||
if cmp, err = p.basis.specializeComponent(c); err != nil {
|
||||
return
|
||||
}
|
||||
cmp.SetRequestMetadata("project_resource_id", p.ResourceId())
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Project) execHook(
|
||||
ctx context.Context,
|
||||
log hclog.Logger,
|
||||
|
||||
@ -13,7 +13,6 @@ import (
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/vagrant/internal/config"
|
||||
"github.com/hashicorp/vagrant/internal/plugin"
|
||||
"github.com/hashicorp/vagrant/internal/serverclient"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
@ -217,14 +216,6 @@ func (t *Target) Run(ctx context.Context, task *vagrant_server.Task) (err error)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = t.specializeComponent(cmd); err != nil {
|
||||
t.logger.Error("failed to specialize component",
|
||||
"type", component.CommandType,
|
||||
"name", task.Component.Name,
|
||||
"error", err)
|
||||
return
|
||||
}
|
||||
|
||||
fn := cmd.Value.(component.Command).ExecuteFunc(
|
||||
strings.Split(task.CommandName, " "))
|
||||
result, err := t.callDynamicFunc(ctx, t.logger, fn, (*int32)(nil),
|
||||
@ -291,19 +282,6 @@ func (t *Target) callDynamicFunc(
|
||||
return t.project.callDynamicFunc(ctx, log, f, expectedType, args...)
|
||||
}
|
||||
|
||||
// Specialize a given component. This is specifically used for
|
||||
// Ruby based legacy Vagrant components.
|
||||
//
|
||||
// TODO: Since legacy Vagrant is no longer directly connecting
|
||||
// to the Vagrant server, this should probably be removed.
|
||||
func (t *Target) specializeComponent(c *Component) (cmp plugin.PluginMetadata, err error) {
|
||||
if cmp, err = t.project.specializeComponent(c); err != nil {
|
||||
return
|
||||
}
|
||||
cmp.SetRequestMetadata("target_resource_id", t.target.ResourceId)
|
||||
return
|
||||
}
|
||||
|
||||
func (t *Target) execHook(
|
||||
ctx context.Context,
|
||||
log hclog.Logger,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user