diff --git a/builtin/myplugin/host/alwaystrue.go b/builtin/myplugin/host/alwaystrue.go index c9c500b7c..10fad11c8 100644 --- a/builtin/myplugin/host/alwaystrue.go +++ b/builtin/myplugin/host/alwaystrue.go @@ -1,8 +1,10 @@ package host import ( + "errors" + "github.com/hashicorp/vagrant-plugin-sdk/component" - sdkcore "github.com/hashicorp/vagrant-plugin-sdk/core" + "github.com/hashicorp/vagrant-plugin-sdk/terminal" "github.com/hashicorp/vagrant/builtin/myplugin/host/cap" ) @@ -12,8 +14,6 @@ type HostConfig struct { // AlwaysTrueHost is a Host implementation for myplugin. type AlwaysTrueHost struct { config HostConfig - - sdkcore.CapabilityHost } // DetectFunc implements component.Host @@ -22,16 +22,35 @@ func (h *AlwaysTrueHost) DetectFunc() interface{} { } func (h *AlwaysTrueHost) Detect() bool { - h.InitializeCapabilities() return true } -func (h *AlwaysTrueHost) InitializeCapabilities() (err error) { - err = h.RegisterCapability("write_hello", cap.WriteHello) - return +func (h *AlwaysTrueHost) HasCapabilityFunc() interface{} { + return h.CheckCapability +} + +func (h *AlwaysTrueHost) CheckCapability(n *component.NamedCapability) bool { + if n.Capability == "write_hello" { + return true + } + return false +} + +func (h *AlwaysTrueHost) CapabilityFunc(name string) interface{} { + if name == "write_hello" { + return h.WriteHelloCap + } + return errors.New("Invalid capability requested") +} + +func (h *AlwaysTrueHost) WriteHelloCap(ui terminal.UI) error { + return cap.WriteHello(ui) +} + +func (h *AlwaysTrueHost) WriteHelloCapNoUI() error { + return cap.WriteHelloNoUI() } var ( _ component.Host = (*AlwaysTrueHost)(nil) - _ sdkcore.Host = (*AlwaysTrueHost)(nil) ) diff --git a/builtin/myplugin/host/cap/write_hello.go b/builtin/myplugin/host/cap/write_hello.go index b60dd4b91..d8f298750 100644 --- a/builtin/myplugin/host/cap/write_hello.go +++ b/builtin/myplugin/host/cap/write_hello.go @@ -13,3 +13,10 @@ func WriteHello(ui terminal.UI) error { ioutil.WriteFile("/tmp/hello", data, 0644) return nil } + +func WriteHelloNoUI() error { + msg := "Hello from the write hello capability, compliments of the AlwaysTrue Host" + data := []byte(msg) + ioutil.WriteFile("/tmp/hello", data, 0644) + return nil +} diff --git a/builtin/otherplugin/command.go b/builtin/otherplugin/command.go index 467039138..6cff1b72e 100644 --- a/builtin/otherplugin/command.go +++ b/builtin/otherplugin/command.go @@ -4,7 +4,6 @@ import ( "strings" "github.com/DavidGamba/go-getoptions/option" - "github.com/hashicorp/go-argmapper" "github.com/hashicorp/vagrant-plugin-sdk/component" plugincore "github.com/hashicorp/vagrant-plugin-sdk/core" @@ -157,18 +156,28 @@ func (c *Command) ExecuteOfni(trm terminal.UI) int64 { return 0 } -func (c *Command) ExecuteUseHostPlugin(trm terminal.UI, host plugincore.Host) int64 { - trm.Output("I'm going to use a the host plugin to do something!") - ok := host.HasCapability("write_hello") +func (c *Command) ExecuteUseHostPlugin(trm terminal.UI, basis plugincore.Basis) int64 { + trm.Output("I'm going to use a the host plugin to do something!\n\n") + host, err := basis.Host() + if err != nil { + trm.Output("Error: Failed to receive host plugin - " + err.Error() + "\n\n") + return 1 + } + ok, err := host.HasCapability("write_hello") + if err != nil { + trm.Output("ERROR: " + err.Error() + "\n\n") + // return 1 + } if ok { - trm.Output("Writing to file using `write_hello` capability") - _, err := host.Capability("write_hello", argmapper.Typed(trm)) + trm.Output("Writing to file using `write_hello` capability\n\n") + _, err = host.Capability("write_hello", trm) if err != nil { - trm.Output("Error!") + trm.Output("Error executing capability - " + err.Error() + "\n\n") return 1 } } else { trm.Output("no `write_hello` capability found") } + return 0 } diff --git a/internal/cli/base.go b/internal/cli/base.go index 6c7de6894..5e7b9b650 100644 --- a/internal/cli/base.go +++ b/internal/cli/base.go @@ -179,7 +179,7 @@ func BaseCommand(ctx context.Context, log hclog.Logger, logOutput io.Writer, opt // Start building our client options basisOpts := []clientpkg.Option{ - clientpkg.WithLogger(bc.Log), + clientpkg.WithLogger(bc.Log.ResetNamed("vagrant.client")), clientpkg.WithClientConnect(connectOpts...), clientpkg.WithBasis( &vagrant_server.Basis{ @@ -431,7 +431,7 @@ func (c *baseCommand) Do(ctx context.Context, f func(context.Context, Tasker) er // Start with checking if we are running in a machine based scope if len(c.targets) > 0 { for _, m := range c.targets { - c.Log.Warn("running command on target", "target", m) + c.Log.Debug("running command on target", "target", m) // If the context has been canceled, then bail if err := ctx.Err(); err != nil { return err diff --git a/internal/cli/main.go b/internal/cli/main.go index b497c221d..38730e1ac 100644 --- a/internal/cli/main.go +++ b/internal/cli/main.go @@ -228,7 +228,7 @@ func Commands( func logger(args []string) ([]string, hclog.Logger, io.Writer, error) { app := args[0] - // Determine our log level if we have any. First override we check if env var + // Determine our log level if we have any. First override we check is env var level := hclog.NoLevel if v := os.Getenv(EnvLogLevel); v != "" { level = hclog.LevelFromString(v) diff --git a/internal/client/basis.go b/internal/client/basis.go index 194e9a5b7..e73fc3ea6 100644 --- a/internal/client/basis.go +++ b/internal/client/basis.go @@ -38,7 +38,7 @@ type Basis struct { func New(ctx context.Context, opts ...Option) (basis *Basis, err error) { basis = &Basis{ - logger: hclog.L().Named("basis"), + logger: hclog.L(), runner: &vagrant_server.Ref_Runner{ Target: &vagrant_server.Ref_Runner_Any{ Any: &vagrant_server.Ref_RunnerAny{}, @@ -55,6 +55,8 @@ func New(ctx context.Context, opts ...Option) (basis *Basis, err error) { } } + basis.logger = basis.logger.Named("basis") + // If no internal basis was provided, set it up now if basis.basis == nil { vh, err := paths.VagrantHome() diff --git a/internal/client/runner.go b/internal/client/runner.go index 280ee9205..340248177 100644 --- a/internal/client/runner.go +++ b/internal/client/runner.go @@ -11,7 +11,7 @@ func (b *Basis) startRunner() (*runner.Runner, error) { r, err := runner.New( runner.WithClient(b.client), runner.WithVagrantRubyRuntime(b.vagrantRubyRuntime), - runner.WithLogger(b.logger.Named("runner")), + runner.WithLogger(b.logger), runner.ByIdOnly(), // We'll direct target this runner.WithLocal(b.UI()), // Local mode ) diff --git a/internal/client/server.go b/internal/client/server.go index 2107bdc99..70c8bd57c 100644 --- a/internal/client/server.go +++ b/internal/client/server.go @@ -35,7 +35,7 @@ import ( // found, this will spin up an in-memory server. // func (b *Basis) initServerClient(ctx context.Context, cfg *config) (*grpc.ClientConn, error) { - log := b.logger.Named("server") + log := b.logger.ResetNamed("vagrant.server") // If we're local, then connection is optional. opts := cfg.connectOpts @@ -73,7 +73,7 @@ func (b *Basis) initServerClient(ctx context.Context, cfg *config) (*grpc.Client // If this returns an error, all resources associated with this operation // will be closed, but the project can retry. func (b *Basis) initLocalServer(ctx context.Context) (_ *grpc.ClientConn, err error) { - log := b.logger.Named("server") + log := b.logger.ResetNamed("vagrant.server") b.localServer = true // We use this pointer to accumulate things we need to clean up diff --git a/internal/core/basis.go b/internal/core/basis.go index d7636794d..fbd21fd92 100644 --- a/internal/core/basis.go +++ b/internal/core/basis.go @@ -73,6 +73,12 @@ func NewBasis(ctx context.Context, opts ...BasisOption) (b *Basis, err error) { return } + if b.logger.IsTrace() { + b.logger = b.logger.Named("basis") + } else { + b.logger = b.logger.ResetNamed("vagrant.core.basis") + } + if b.basis == nil { return nil, errors.New("basis data was not properly loaded") } @@ -96,8 +102,9 @@ func NewBasis(ctx context.Context, opts ...BasisOption) (b *Basis, err error) { // If the mappers aren't already set, load known mappers if len(b.mappers) == 0 { b.mappers, err = argmapper.NewFuncList(protomappers.All, - argmapper.Logger(b.logger), + argmapper.Logger(dynamicLogger), ) + if err != nil { return } @@ -161,6 +168,15 @@ func (b *Basis) Client() *serverclient.VagrantClient { return b.client } +func (b *Basis) Host() (host core.Host, err error) { + h, err := b.findHostPlugin(b.ctx) + if err != nil { + return + } + host = h.Value.(core.Host) + return +} + func (b *Basis) Init() (result *vagrant_server.Job_InitResult, err error) { b.logger.Debug("running init for basis") f := b.factories[component.CommandType] @@ -203,7 +219,6 @@ func (b *Basis) Init() (result *vagrant_server.Job_InitResult, err error) { b.convertCommandInfo(r, []string{})...) } - b.logger.Warn("resulting init commands", "commands", result.Commands) return } @@ -224,7 +239,7 @@ func (b *Basis) LoadProject(popts ...ProjectOption) (p *Project, err error) { p = &Project{ ctx: b.ctx, basis: b, - logger: b.logger.Named("project"), + logger: b.logger, mappers: b.mappers, factories: b.factories, targets: map[string]*Target{}, @@ -237,6 +252,7 @@ func (b *Basis) LoadProject(popts ...ProjectOption) (p *Project, err error) { err = multierror.Append(err, oerr) } } + if err != nil { return } @@ -249,6 +265,12 @@ func (b *Basis) LoadProject(popts ...ProjectOption) (p *Project, err error) { // Set our loaded project into the basis b.projects[p.project.ResourceId] = p + if p.logger.IsTrace() { + p.logger = p.logger.Named("project") + } else { + p.logger = p.logger.ResetNamed("vagrant.core.project") + } + // Ensure project directory is set if p.dir == nil { if p.dir, err = b.dir.Project(p.project.Name); err != nil { @@ -399,6 +421,9 @@ func (b *Basis) findHostPlugin(ctx context.Context) (*Component, error) { h, h.Value.(component.Host).DetectFunc(), ) + if err != nil { + return nil, err + } if detected != nil && detected.(bool) { return h, nil } @@ -451,7 +476,7 @@ func (b *Basis) startPlugin( typ component.Type, n string, ) (*plugin.Instance, error) { - log := b.logger.Named(strings.ToLower(typ.String())) + log := b.logger.ResetNamed(fmt.Sprintf("vagrant.plugin.%s.%s", strings.ToLower(typ.String()), n)) f, ok := b.factories[typ] if !ok { @@ -465,11 +490,11 @@ func (b *Basis) startPlugin( } // Call the factory to get our raw value (interface{} type) - fnResult := fn.Call(argmapper.Typed(ctx, log)) + fnResult := fn.Call(argmapper.Typed(ctx, log), argmapper.Logger(dynamicLogger)) if err := fnResult.Err(); err != nil { return nil, err } - log.Info("initialized component", "type", typ.String()) + 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 @@ -494,13 +519,14 @@ func (b *Basis) callDynamicFunc( f interface{}, // function args ...argmapper.Arg, ) (interface{}, error) { - // We allow f to be a *mapper.Func because our plugin system creates - // a func directly due to special argument types. - // TODO: test - rawFunc, ok := f.(*argmapper.Func) - if !ok { + var rawFunc *argmapper.Func + if fn, ok := f.(*argmapper.Func); ok { + rawFunc = fn + } else if fn, ok := f.(*component.SpicyFunc); ok { + rawFunc = fn.Func + } else { var err error - rawFunc, err = argmapper.NewFunc(f, argmapper.Logger(log)) + rawFunc, err = argmapper.NewFunc(f) if err != nil { return nil, err } @@ -512,11 +538,12 @@ func (b *Basis) callDynamicFunc( args = append(args, argmapper.ConverterFunc(b.mappers...), - argmapper.Typed(b, b.ui, ctx, log), + argmapper.Typed(b, b.ui, ctx, log.Named("plugin-call")), argmapper.Named("basis", b), + argmapper.Logger(dynamicLogger), ) - b.logger.Info("running dynamic call from basis", "basis", b) + b.logger.Info("running dynamic call from basis", "basis", b, "func", rawFunc.Name()) // Build the chain and call it callResult := rawFunc.Call(args...) @@ -690,3 +717,8 @@ func WithBasisResourceId(rid string) BasisOption { } var _ core.Basis = (*Basis)(nil) + +var dynamicLogger hclog.Logger = hclog.New(&hclog.LoggerOptions{ + Name: "vagrant.core.dynamic-function", + Level: hclog.Error, +}) diff --git a/internal/core/project.go b/internal/core/project.go index 0d2724989..6083d53d8 100644 --- a/internal/core/project.go +++ b/internal/core/project.go @@ -97,11 +97,7 @@ func (p *Project) DefaultPrivateKey() (path string, err error) { } func (p *Project) Host() (host core.Host, err error) { - hostComponent, err := p.basis.findHostPlugin(p.ctx) - if err != nil { - return nil, err - } - return hostComponent.Value.(core.Host), nil + return p.basis.Host() } func (p *Project) MachineNames() (names []string, err error) { @@ -156,7 +152,7 @@ func (p *Project) LoadTarget(topts ...TargetOption) (t *Target, err error) { t = &Target{ ctx: p.ctx, project: p, - logger: p.logger.Named("target"), + logger: p.logger, ui: p.ui, } @@ -178,6 +174,12 @@ func (p *Project) LoadTarget(topts ...TargetOption) (t *Target, err error) { p.targets[t.target.ResourceId] = t + if t.logger.IsTrace() { + t.logger = t.logger.Named("target") + } else { + t.logger = t.logger.ResetNamed("vagrant.core.target") + } + if t.dir == nil { if t.dir, err = p.dir.Target(t.target.Name); err != nil { return diff --git a/internal/core/target.go b/internal/core/target.go index e48a60377..8530c9753 100644 --- a/internal/core/target.go +++ b/internal/core/target.go @@ -166,22 +166,15 @@ func (t *Target) Run(ctx context.Context, task *vagrant_server.Task) (err error) return } - host, _ := t.project.Host() - - // _, err = t.callDynamicFunc( - // ctx, - // t.logger, - // (interface{})(nil), - // nil, - // host.(component.Host).CapabilityFunc("write_hello"), - // argmapper.Typed(t.ui), - // ) - // host.Capability("write_hello", argmapper.Typed(t.ui)) + host, err := t.project.Host() + if err != nil { + return err + } result, err := t.callDynamicFunc( ctx, t.logger, - (interface{})(nil), + nil, cmd, cmd.Value.(component.Command).ExecuteFunc(strings.Split(task.CommandName, " ")), argmapper.Typed(task.CliArgs, t.jobInfo, t.dir, host), diff --git a/internal/plugin/builtin.go b/internal/plugin/builtin.go index 6589dc6bc..92630d554 100644 --- a/internal/plugin/builtin.go +++ b/internal/plugin/builtin.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "strings" + "sync" "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-plugin" @@ -20,6 +21,7 @@ type Builtin struct { log hclog.Logger cancel context.CancelFunc ctx context.Context + mu sync.Mutex } func NewBuiltins(ctx context.Context, log hclog.Logger) *Builtin { @@ -33,6 +35,8 @@ func NewBuiltins(ctx context.Context, log hclog.Logger) *Builtin { } func (b *Builtin) ConnectInfo(name string) (*plugin.ReattachConfig, error) { + b.mu.Lock() + defer b.mu.Unlock() r, ok := b.servers[name] if !ok { b.log.Error("failed to locate plugin", "name", name, "servers", b.servers) @@ -54,7 +58,12 @@ func (b *Builtin) Add(name string, opts ...sdk.Option) (err error) { opts = append(opts, sdk.InProcess(cfg), sdk.WithLogger(b.log)) // Spin off a new go routine to get the reattach config - go func() { b.servers[name] = <-reCh }() + go func() { + rc := <-reCh + b.mu.Lock() + defer b.mu.Unlock() + b.servers[name] = rc + }() // Add the plugin server to our group b.group.Add(func() error { diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go index ed3cb546f..af7015722 100644 --- a/internal/plugin/plugin.go +++ b/internal/plugin/plugin.go @@ -9,7 +9,7 @@ import ( ) // disable in process plugins by default for now -const IN_PROCESS_PLUGINS = true +const IN_PROCESS_PLUGINS = false var ( // Builtins is the map of all available builtin plugins and their diff --git a/internal/runner/runner.go b/internal/runner/runner.go index 396c610d1..6c3c001ef 100644 --- a/internal/runner/runner.go +++ b/internal/runner/runner.go @@ -106,6 +106,7 @@ func New(opts ...Option) (*Runner, error) { } } + runner.logger = runner.logger.ResetNamed("vagrant.runner") // Setup our runner components list for t, f := range runner.factories { for _, n := range f.Registered() { diff --git a/internal/server/server.go b/internal/server/server.go index 914a67c9f..01ac8c9e7 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -30,6 +30,7 @@ func Run(opts ...Option) error { if cfg.Logger == nil { cfg.Logger = hclog.L() } + cfg.Logger = cfg.Logger.ResetNamed("vagrant.server") // Setup our run group since we're going to be starting multiple // goroutines for all the servers that we want to live/die as a group. diff --git a/internal/serverclient/ruby_client.go b/internal/serverclient/ruby_client.go index c22215545..bd02c20ba 100644 --- a/internal/serverclient/ruby_client.go +++ b/internal/serverclient/ruby_client.go @@ -32,7 +32,7 @@ type RubyVagrantClient struct { } func RubyVagrantPluginConfig(log hclog.Logger) *plugin.ClientConfig { - log = log.Named("vagrant-ruby-runtime") + log = log.ResetNamed("vagrant.client.ruby-runtime") config := pluginclient.ClientConfig(log) config.Logger = log config.VersionedPlugins[1]["vagrantrubyruntime"] = &RubyVagrantPlugin{}