vaguerent/internal/core/machine.go
sophia 9ea254735a
Set target uuid opposed to resource id
The uuid is the public identifier vs the resource id which should
be for internal operations.
The target uuid should correspond to the machine id (given by
the provider)
2022-04-25 12:26:13 -05:00

260 lines
6.2 KiB
Go

package core
import (
"fmt"
"reflect"
"github.com/golang/protobuf/ptypes"
"github.com/mitchellh/mapstructure"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/vagrant-plugin-sdk/component"
"github.com/hashicorp/vagrant-plugin-sdk/core"
"github.com/hashicorp/vagrant-plugin-sdk/proto/vagrant_plugin_sdk"
"github.com/hashicorp/vagrant/internal/server/proto/vagrant_server"
)
type Machine struct {
*Target
box *Box
machine *vagrant_server.Target_Machine
logger hclog.Logger
guest core.Guest
}
// Close implements core.Machine
func (m *Machine) Close() (err error) {
return
}
// ID implements core.Machine
func (m *Machine) ID() (id string, err error) {
return m.machine.Id, nil
}
// SetID implements core.Machine
func (m *Machine) SetID(value string) (err error) {
if value == "" {
err = m.Destroy()
if err != nil {
return err
}
m.machine.Id = value
} else {
m.machine.Id = value
return m.SaveMachine()
}
return
}
func (m *Machine) Box() (b core.Box, err error) {
if m.box == nil {
// TODO: get provider info here too/generate full machine config?
// We know that these are machines so, save the Machine record
boxes, _ := m.project.Boxes()
boxName := m.Config().ConfigVm.Box
// Get the first provider available - that's the one that
// will be used to launch the machine
provider := m.Config().ConfigVm.Providers[0].Type
b, err := boxes.Find(boxName, "", provider)
if err != nil {
return nil, err
}
if b == nil {
// Add the box
b, err = addBox(boxName, provider, m.project.basis)
if err != nil {
return nil, err
}
}
m.machine.Box = b.(*Box).ToProto()
m.Save()
m.box = b.(*Box)
}
return m.box, nil
}
// Guest implements core.Machine
func (m *Machine) Guest() (g core.Guest, err error) {
// Try to see if a guest has already been found
if m.guest != nil {
return m.guest, nil
}
// Check if a guest is provided by the Vagrantfile. If it is, then try
// to use that guest
// TODO: This check maybe needs to get reworked when the Vagrantfile bits
// actually start getting used
if m.target.Configuration.ConfigVm.Guest != "" {
// Ignore error about guest not being found - will also try detecting the guest
guest, _ := m.project.basis.component(
m.ctx, component.GuestType, m.target.Configuration.ConfigVm.Guest)
if guest != nil {
m.guest = guest.Value.(core.Guest)
m.seedPlugin(m.guest)
return m.guest, nil
}
}
// Try to detect a guest
guests, err := m.project.basis.typeComponents(m.ctx, component.GuestType)
if err != nil {
return
}
var result core.Guest
var result_name string
var numParents int
for name, g := range guests {
guest := g.Value.(core.Guest)
detected, err := guest.Detect(m.toTarget())
if err != nil {
m.logger.Error("guest error on detection check",
"plugin", name,
"type", "Guest",
"error", err)
continue
}
if result == nil {
if detected {
result = guest
result_name = name
if numParents, err = m.project.basis.countParents(guest); err != nil {
return nil, err
}
}
continue
}
if detected {
gp, err := m.project.basis.countParents(guest)
if err != nil {
m.logger.Error("failed to get parents from guest",
"plugin", name,
"type", "Guest",
"error", err,
)
continue
}
if gp > numParents {
result = guest
result_name = name
numParents = gp
}
}
}
if result == nil {
return nil, fmt.Errorf("failed to detect guest plugin for current platform")
}
m.logger.Info("guest detection complete",
"name", result_name)
// NOTE: For guest seeding we need to prevent guest plugin instance
// from being cached and reused. Currently, in a multi-machine setup
// which are the same guest, the target values will get appended
// TODO(spox): Fix this in the plugin manager
m.seedPlugin(result)
m.guest = result
return result, nil
}
func (m *Machine) seedPlugin(plg interface{}) (err error) {
if s, ok := plg.(core.Seeder); ok {
seeds, err := s.Seeds()
if err != nil {
return err
}
seeds.Typed = append(seeds.Typed, m.Target)
if err = s.Seed(seeds); err != nil {
return err
}
}
return
}
func (m *Machine) Inspect() (printable string, err error) {
name, err := m.Name()
provider, err := m.Provider()
printable = "#<" + reflect.TypeOf(m).String() + ": " + name + " (" + reflect.TypeOf(provider).String() + ")>"
return
}
// Reload implements core.Machine
func (m *Machine) Reload() (err error) {
// TODO
return
}
// ConnectionInfo implements core.Machine
func (m *Machine) ConnectionInfo() (info *core.ConnectionInfo, err error) {
// TODO: need Vagrantfile
return
}
// MachineState implements core.Machine
func (m *Machine) MachineState() (state *core.MachineState, err error) {
var result core.MachineState
return &result, mapstructure.Decode(m.machine.State, &result)
}
// SetMachineState implements core.Machine
func (m *Machine) SetMachineState(state *core.MachineState) (err error) {
var st *vagrant_plugin_sdk.Args_Target_Machine_State
mapstructure.Decode(state, &st)
m.machine.State = st
return m.SaveMachine()
}
func (m *Machine) UID() (userId string, err error) {
return m.machine.Uid, nil
}
// SyncedFolders implements core.Machine
func (m *Machine) SyncedFolders() (folders []*core.MachineSyncedFolder, err error) {
config := m.target.Configuration
machineConfig := config.ConfigVm
syncedFolders := machineConfig.SyncedFolders
folders = []*core.MachineSyncedFolder{}
for _, folder := range syncedFolders {
// TODO: get default synced folder type
folder.Type = "virtualbox"
plg, err := m.project.basis.component(m.ctx, component.SyncedFolderType, folder.Type)
if err != nil {
return nil, err
}
m.seedPlugin(plg.Value)
var f *core.Folder
mapstructure.Decode(folder, &f)
folders = append(folders, &core.MachineSyncedFolder{
Plugin: plg.Value.(core.SyncedFolder),
Folder: f,
})
}
return
}
func (m *Machine) SaveMachine() (err error) {
m.logger.Debug("saving machine to db", "machine", m.machine.Id)
m.target.Record, err = ptypes.MarshalAny(m.machine)
m.target.Uuid = m.machine.Id
if err != nil {
return nil
}
return m.Save()
}
func (m *Machine) toTarget() core.Target {
return m
}
var _ core.Machine = (*Machine)(nil)
var _ core.Target = (*Machine)(nil)