vaguerent/internal/core/machine.go
2022-04-25 12:23:57 -05:00

148 lines
3.6 KiB
Go

package core
import (
"context"
"github.com/golang/protobuf/proto"
"github.com/hashicorp/go-argmapper"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/vagrant/internal/config"
"github.com/hashicorp/vagrant/internal/plugin"
"github.com/hashicorp/vagrant/internal/serverclient"
"github.com/hashicorp/vagrant-plugin-sdk/component"
"github.com/hashicorp/vagrant-plugin-sdk/datadir"
"github.com/hashicorp/vagrant-plugin-sdk/terminal"
"github.com/hashicorp/vagrant/internal/server/proto/vagrant_server"
)
type Machine struct {
name string
resourceid string
project *Project
logger hclog.Logger
config *config.Machine
dir *datadir.Machine
labels map[string]string
overrideLabels map[string]string
jobInfo *component.JobInfo
UI terminal.UI
}
func (m *Machine) Ui() terminal.UI {
return m.UI
}
func (m *Machine) Ref() interface{} {
return &vagrant_server.Ref_Machine{
ResourceId: m.resourceid,
Name: m.name,
Project: m.project.Ref().(*vagrant_server.Ref_Project),
}
}
func (m *Machine) JobInfo() *component.JobInfo {
return m.jobInfo
}
func (m *Machine) Client() *serverclient.VagrantClient {
return m.project.basis.client
}
func (m *Machine) Close() (err error) {
return
}
func (m *Machine) specializeComponent(c *Component) (cmp plugin.PluginMetadata, err error) {
if cmp, err = m.project.specializeComponent(c); err != nil {
return
}
cmp.SetRequestMetadata("machine_resource_id", m.resourceid)
return
}
func (m *Machine) Run(ctx context.Context, task *vagrant_server.Task) (err error) {
m.logger.Debug("running new task", "machine", m, "task", task)
cmd, err := m.project.basis.component(
ctx, component.CommandType, task.Component.Name)
if err != nil {
m.logger.Error("failed to build requested component", "type", component.CommandType,
"name", task.Component.Name, "error", err)
return err
}
if _, err = m.specializeComponent(cmd); err != nil {
m.logger.Error("failed to specialize component", "type", component.CommandType,
"name", task.Component.Name, "error", err)
return err
}
result, err := m.callDynamicFunc(
ctx,
m.logger,
(interface{})(nil),
cmd,
cmd.Value.(component.Command).ExecuteFunc(),
argmapper.Typed(task.CliArgs),
)
if err != nil || result == nil || result.(int64) != 0 {
m.logger.Error("failed to execute command", "type", component.CommandType,
"name", task.Component.Name, "error", err)
return err
}
return
}
func (m *Machine) callDynamicFunc(
ctx context.Context,
log hclog.Logger,
result interface{}, // expected result type
c *Component, // component
f interface{}, // function
args ...argmapper.Arg,
) (interface{}, error) {
// Be sure that the status is closed after every operation so we don't leak
// weird output outside the normal execution.
defer m.UI.Status().Close()
args = append(args,
argmapper.Typed(
m.jobInfo,
m.dir,
m.UI,
),
)
return m.project.callDynamicFunc(ctx, log, result, c, f, args...)
}
func (m *Machine) mergeLabels(ls ...map[string]string) map[string]string {
result := map[string]string{}
// Merge order
mergeOrder := []map[string]string{result, m.labels}
mergeOrder = append(mergeOrder, ls...)
mergeOrder = append(mergeOrder, m.overrideLabels)
// Merge them
return labelsMerge(mergeOrder...)
}
func (m *Machine) execHook(ctx context.Context, log hclog.Logger, h *config.Hook) error {
return execHook(ctx, m, log, h)
}
func (m *Machine) doOperation(ctx context.Context, log hclog.Logger, op operation) (interface{}, proto.Message, error) {
return doOperation(ctx, log, m, op)
}
var _ *Machine = (*Machine)(nil)