Host component related work

This commit is contained in:
Chris Roberts 2021-06-17 08:36:12 -07:00 committed by Paul Hinze
parent 908b1e3449
commit 05d5634c83
No known key found for this signature in database
GPG Key ID: B69DEDF2D55501C0
16 changed files with 132 additions and 57 deletions

View File

@ -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)
)

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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)

View File

@ -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()

View File

@ -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
)

View File

@ -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

View File

@ -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,
})

View File

@ -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

View File

@ -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),

View File

@ -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 {

View File

@ -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

View File

@ -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() {

View File

@ -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.

View File

@ -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{}