Merge pull request #295 from hashicorp/target-load-stored-configuration
Testing fixes and target loading
This commit is contained in:
commit
f9dd348847
72
internal/core/helpers_test.go
Normal file
72
internal/core/helpers_test.go
Normal file
@ -0,0 +1,72 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/vagrant-plugin-sdk/component"
|
||||
"github.com/hashicorp/vagrant/internal/plugin"
|
||||
)
|
||||
|
||||
// Synced folder entry
|
||||
type testSyncedFolder struct {
|
||||
source string
|
||||
destination string
|
||||
kind string
|
||||
}
|
||||
|
||||
// Add vm box name to configuration
|
||||
func testBoxConfig(name string) *component.ConfigData {
|
||||
return &component.ConfigData{
|
||||
Data: map[string]interface{}{
|
||||
"vm": &component.ConfigData{
|
||||
Data: map[string]interface{}{
|
||||
"box": name,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Add synced folders to vm configuration
|
||||
func testSyncedFolderConfig(folders []*testSyncedFolder) *component.ConfigData {
|
||||
f := map[interface{}]interface{}{}
|
||||
for _, tf := range folders {
|
||||
f[tf.destination] = map[interface{}]interface{}{
|
||||
"hostpath": tf.source,
|
||||
"guestpath": tf.destination,
|
||||
"type": tf.kind,
|
||||
}
|
||||
}
|
||||
|
||||
return &component.ConfigData{
|
||||
Data: map[string]interface{}{
|
||||
"vm": &component.ConfigData{
|
||||
Data: map[string]interface{}{
|
||||
"__synced_folders": f,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Set guest name in vm configuration
|
||||
func testGuestConfig(name string) *component.ConfigData {
|
||||
return &component.ConfigData{
|
||||
Data: map[string]interface{}{
|
||||
"vm": &component.ConfigData{
|
||||
Data: map[string]interface{}{
|
||||
"guest": name,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a synced folder plugin
|
||||
func syncedFolderPlugin(t *testing.T, name string) *plugin.Plugin {
|
||||
return plugin.TestPlugin(t,
|
||||
BuildTestSyncedFolderPlugin(""),
|
||||
plugin.WithPluginName(name),
|
||||
plugin.WithPluginTypes(component.SyncedFolderType),
|
||||
)
|
||||
}
|
||||
@ -107,6 +107,10 @@ func (m *Machine) Guest() (g core.Guest, err error) {
|
||||
}
|
||||
}()
|
||||
|
||||
// Note that if we get the guest value from the
|
||||
// local cache, we return it directly to prevent
|
||||
// the seeding and cache registration from happening
|
||||
// again.
|
||||
i := m.cache.Get("guest")
|
||||
if i != nil {
|
||||
return i.(core.Guest), nil
|
||||
@ -122,13 +126,13 @@ func (m *Machine) Guest() (g core.Guest, err error) {
|
||||
} else {
|
||||
guestName, ok := vg.(string)
|
||||
if ok {
|
||||
guest, err := m.project.basis.component(m.ctx, component.GuestType, guestName)
|
||||
var guest *Component
|
||||
guest, err = m.project.basis.component(m.ctx, component.GuestType, guestName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if guest != nil {
|
||||
return guest.Value.(core.Guest), nil
|
||||
}
|
||||
g = guest.Value.(core.Guest)
|
||||
return
|
||||
} else {
|
||||
m.logger.Debug("guest name was not a valid string value",
|
||||
"guest", vg,
|
||||
@ -388,7 +392,15 @@ func (m *Machine) SyncedFolders() (folders []*core.MachineSyncedFolder, err erro
|
||||
}
|
||||
}
|
||||
if ftype == "" {
|
||||
ftype = "virtualbox" // TODO(spox): use default type function after rebase
|
||||
ftype, err = m.project.DefaultProvider(
|
||||
&core.DefaultProviderOptions{
|
||||
CheckUsable: false,
|
||||
MachineName: m.target.Name,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
lookup := "syncedfolder_" + ftype
|
||||
|
||||
@ -10,15 +10,10 @@ import (
|
||||
"github.com/hashicorp/vagrant/internal/server/proto/vagrant_server"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
)
|
||||
|
||||
func TestMachineSetValidId(t *testing.T) {
|
||||
tm, err := TestMinimalMachine(t)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tm := TestMinimalMachine(t)
|
||||
|
||||
// Set valid id
|
||||
tm.SetID("something")
|
||||
@ -41,7 +36,7 @@ func TestMachineSetValidId(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMachineSetEmptyId(t *testing.T) {
|
||||
tm, _ := TestMinimalMachine(t)
|
||||
tm := TestMinimalMachine(t)
|
||||
oldId := tm.target.ResourceId
|
||||
|
||||
// Set empty id
|
||||
@ -85,7 +80,7 @@ func TestMachineSetEmptyId(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMachineSetIdBlankThenSomethingPreservesDataDir(t *testing.T) {
|
||||
tm, _ := TestMinimalMachine(t)
|
||||
tm := TestMinimalMachine(t)
|
||||
|
||||
// Set empty id, followed by a temp id. This is the same thing that happens
|
||||
// in the Docker provider's InitState action
|
||||
@ -102,8 +97,8 @@ func TestMachineSetIdBlankThenSomethingPreservesDataDir(t *testing.T) {
|
||||
|
||||
func TestMachineGetNonExistentBox(t *testing.T) {
|
||||
tp := TestMinimalProject(t)
|
||||
tm, _ := TestMachine(t, tp,
|
||||
WithTestTargetConfig(testBoxConfig("somename")),
|
||||
tm := TestMachine(t, tp,
|
||||
WithTestTargetConfig(testBoxConfig("somebox")),
|
||||
WithTestTargetProvider("testprovider"),
|
||||
)
|
||||
|
||||
@ -120,133 +115,11 @@ func TestMachineGetNonExistentBox(t *testing.T) {
|
||||
require.Empty(t, metaurl)
|
||||
}
|
||||
|
||||
func testBoxConfig(name string) *vagrant_plugin_sdk.Args_ConfigData {
|
||||
b_key, _ := anypb.New(&wrapperspb.StringValue{Value: "box"})
|
||||
b_name, _ := anypb.New(&wrapperspb.StringValue{Value: name})
|
||||
vm_key, _ := anypb.New(&wrapperspb.StringValue{Value: "vm"})
|
||||
vm, _ := anypb.New(&vagrant_plugin_sdk.Args_ConfigData{
|
||||
Data: &vagrant_plugin_sdk.Args_Hash{
|
||||
Entries: []*vagrant_plugin_sdk.Args_HashEntry{
|
||||
{
|
||||
Key: b_key,
|
||||
Value: b_name,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return &vagrant_plugin_sdk.Args_ConfigData{
|
||||
Data: &vagrant_plugin_sdk.Args_Hash{
|
||||
Entries: []*vagrant_plugin_sdk.Args_HashEntry{
|
||||
{
|
||||
Key: vm_key,
|
||||
Value: vm,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type testSyncedFolder struct {
|
||||
source string
|
||||
destination string
|
||||
kind string
|
||||
}
|
||||
|
||||
func testSyncedFolderConfig(folders []*testSyncedFolder) *vagrant_plugin_sdk.Args_ConfigData {
|
||||
f := &vagrant_plugin_sdk.Args_Hash{
|
||||
Entries: []*vagrant_plugin_sdk.Args_HashEntry{},
|
||||
}
|
||||
src_key, _ := anypb.New(&wrapperspb.StringValue{Value: "hostpath"})
|
||||
dst_key, _ := anypb.New(&wrapperspb.StringValue{Value: "guestpath"})
|
||||
type_key, _ := anypb.New(&wrapperspb.StringValue{Value: "type"})
|
||||
for i := 0; i < len(folders); i++ {
|
||||
fld := folders[i]
|
||||
f_src, _ := anypb.New(&wrapperspb.StringValue{Value: fld.source})
|
||||
f_dst, _ := anypb.New(&wrapperspb.StringValue{Value: fld.destination})
|
||||
f_type, _ := anypb.New(&wrapperspb.StringValue{Value: fld.kind})
|
||||
|
||||
hsh := &vagrant_plugin_sdk.Args_Hash{
|
||||
Entries: []*vagrant_plugin_sdk.Args_HashEntry{
|
||||
{
|
||||
Key: src_key,
|
||||
Value: f_src,
|
||||
},
|
||||
{
|
||||
Key: dst_key,
|
||||
Value: f_dst,
|
||||
},
|
||||
{
|
||||
Key: type_key,
|
||||
Value: f_type,
|
||||
},
|
||||
},
|
||||
}
|
||||
entry, _ := anypb.New(hsh)
|
||||
f.Entries = append(f.Entries,
|
||||
&vagrant_plugin_sdk.Args_HashEntry{
|
||||
Key: f_dst,
|
||||
Value: entry,
|
||||
},
|
||||
)
|
||||
}
|
||||
f_key, _ := anypb.New(&wrapperspb.StringValue{Value: "__synced_folders"})
|
||||
f_value, _ := anypb.New(f)
|
||||
vm_key, _ := anypb.New(&wrapperspb.StringValue{Value: "vm"})
|
||||
vm, _ := anypb.New(&vagrant_plugin_sdk.Args_ConfigData{
|
||||
Data: &vagrant_plugin_sdk.Args_Hash{
|
||||
Entries: []*vagrant_plugin_sdk.Args_HashEntry{
|
||||
{
|
||||
Key: f_key,
|
||||
Value: f_value,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return &vagrant_plugin_sdk.Args_ConfigData{
|
||||
Data: &vagrant_plugin_sdk.Args_Hash{
|
||||
Entries: []*vagrant_plugin_sdk.Args_HashEntry{
|
||||
{
|
||||
Key: vm_key,
|
||||
Value: vm,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func testGuestConfig(name string) *vagrant_plugin_sdk.Args_ConfigData {
|
||||
g_key, _ := anypb.New(&wrapperspb.StringValue{Value: "guest"})
|
||||
g_name, _ := anypb.New(&wrapperspb.StringValue{Value: name})
|
||||
vm_key, _ := anypb.New(&wrapperspb.StringValue{Value: "vm"})
|
||||
vm, _ := anypb.New(&vagrant_plugin_sdk.Args_ConfigData{
|
||||
Data: &vagrant_plugin_sdk.Args_Hash{
|
||||
Entries: []*vagrant_plugin_sdk.Args_HashEntry{
|
||||
{
|
||||
Key: g_key,
|
||||
Value: g_name,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return &vagrant_plugin_sdk.Args_ConfigData{
|
||||
Data: &vagrant_plugin_sdk.Args_Hash{
|
||||
Entries: []*vagrant_plugin_sdk.Args_HashEntry{
|
||||
{
|
||||
Key: vm_key,
|
||||
Value: vm,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestMachineGetExistentBox(t *testing.T) {
|
||||
tp := TestMinimalProject(t)
|
||||
tm, _ := TestMachine(t, tp,
|
||||
tm := TestMachine(t, tp,
|
||||
WithTestTargetConfig(testBoxConfig("test/box")),
|
||||
WithTestTargetProvider("virtualbox"),
|
||||
)
|
||||
testBox := newFullBox(t, testboxBoxData(), tp.basis)
|
||||
testBox.Save()
|
||||
@ -266,7 +139,7 @@ func TestMachineGetExistentBox(t *testing.T) {
|
||||
|
||||
func TestMachineConfigedGuest(t *testing.T) {
|
||||
type test struct {
|
||||
config *vagrant_plugin_sdk.Args_ConfigData
|
||||
config *component.ConfigData
|
||||
errors bool
|
||||
}
|
||||
|
||||
@ -275,7 +148,7 @@ func TestMachineConfigedGuest(t *testing.T) {
|
||||
{config: testGuestConfig("idontexist"), errors: true},
|
||||
}
|
||||
guestMock := BuildTestGuestPlugin("myguest", "")
|
||||
guestMock.On("Detect", mock.AnythingOfType("*core.Machine")).Return(false, nil)
|
||||
guestMock.On("Detect", mock.AnythingOfType("*core.Machine")).Return(true, nil)
|
||||
guestMock.On("Parent").Return("", nil)
|
||||
|
||||
pluginManager := plugin.TestManager(t,
|
||||
@ -288,7 +161,7 @@ func TestMachineConfigedGuest(t *testing.T) {
|
||||
|
||||
for _, tc := range tests {
|
||||
tp := TestProject(t, WithPluginManager(pluginManager))
|
||||
tm, _ := TestMachine(t, tp,
|
||||
tm := TestMachine(t, tp,
|
||||
WithTestTargetConfig(tc.config),
|
||||
)
|
||||
guest, err := tm.Guest()
|
||||
@ -350,7 +223,7 @@ func TestMachineNoConfigGuest(t *testing.T) {
|
||||
pluginManager := plugin.TestManager(t, tc.plugins...)
|
||||
tp := TestProject(t, WithPluginManager(pluginManager))
|
||||
|
||||
tm, _ := TestMachine(t, tp, WithTestTargetMinimalConfig())
|
||||
tm := TestMachine(t, tp)
|
||||
guest, err := tm.Guest()
|
||||
if tc.errors {
|
||||
require.Error(t, err)
|
||||
@ -369,7 +242,7 @@ func TestMachineNoConfigGuest(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMachineSetState(t *testing.T) {
|
||||
tm, _ := TestMinimalMachine(t)
|
||||
tm := TestMinimalMachine(t)
|
||||
|
||||
type test struct {
|
||||
id string
|
||||
@ -402,21 +275,13 @@ func TestMachineSetState(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func syncedFolderPlugin(t *testing.T, name string) *plugin.Plugin {
|
||||
return plugin.TestPlugin(t,
|
||||
BuildTestSyncedFolderPlugin(""),
|
||||
plugin.WithPluginName(name),
|
||||
plugin.WithPluginTypes(component.SyncedFolderType),
|
||||
)
|
||||
}
|
||||
|
||||
func TestMachineSyncedFolders(t *testing.T) {
|
||||
mySyncedFolder := syncedFolderPlugin(t, "mysyncedfolder")
|
||||
myOtherSyncedFolder := syncedFolderPlugin(t, "myothersyncedfolder")
|
||||
|
||||
type test struct {
|
||||
plugins []*plugin.Plugin
|
||||
config *vagrant_plugin_sdk.Args_ConfigData
|
||||
config *component.ConfigData
|
||||
errors bool
|
||||
expectedFolders int
|
||||
}
|
||||
@ -427,7 +292,7 @@ func TestMachineSyncedFolders(t *testing.T) {
|
||||
errors: false,
|
||||
config: testSyncedFolderConfig(
|
||||
[]*testSyncedFolder{
|
||||
&testSyncedFolder{
|
||||
{
|
||||
source: ".",
|
||||
destination: "/vagrant",
|
||||
kind: "mysyncedfolder",
|
||||
@ -442,20 +307,20 @@ func TestMachineSyncedFolders(t *testing.T) {
|
||||
errors: false,
|
||||
config: testSyncedFolderConfig(
|
||||
[]*testSyncedFolder{
|
||||
&testSyncedFolder{
|
||||
{
|
||||
source: ".",
|
||||
destination: "/vagrant",
|
||||
kind: "mysyncedfolder",
|
||||
},
|
||||
&testSyncedFolder{
|
||||
{
|
||||
source: "./two",
|
||||
destination: "/vagrant-two",
|
||||
kind: "mysyncedfolder",
|
||||
},
|
||||
&testSyncedFolder{
|
||||
{
|
||||
source: "./three",
|
||||
destination: "/vagrant-three",
|
||||
kind: "mysyncedfolder",
|
||||
kind: "myothersyncedfolder",
|
||||
},
|
||||
},
|
||||
),
|
||||
@ -467,20 +332,20 @@ func TestMachineSyncedFolders(t *testing.T) {
|
||||
errors: true,
|
||||
config: testSyncedFolderConfig(
|
||||
[]*testSyncedFolder{
|
||||
&testSyncedFolder{
|
||||
{
|
||||
source: ".",
|
||||
destination: "/vagrant",
|
||||
kind: "mysyncedfolder",
|
||||
kind: "idontexist",
|
||||
},
|
||||
&testSyncedFolder{
|
||||
{
|
||||
source: "./two",
|
||||
destination: "/vagrant-two",
|
||||
kind: "mysyncedfolder",
|
||||
},
|
||||
&testSyncedFolder{
|
||||
{
|
||||
source: "./three",
|
||||
destination: "/vagrant-three",
|
||||
kind: "mysyncedfolder",
|
||||
kind: "myothersyncedfolder",
|
||||
},
|
||||
},
|
||||
),
|
||||
@ -490,7 +355,7 @@ func TestMachineSyncedFolders(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
pluginManager := plugin.TestManager(t, tc.plugins...)
|
||||
tp := TestProject(t, WithPluginManager(pluginManager))
|
||||
tm, _ := TestMachine(t, tp,
|
||||
tm := TestMachine(t, tp,
|
||||
WithTestTargetConfig(tc.config),
|
||||
)
|
||||
folders, err := tm.SyncedFolders()
|
||||
|
||||
@ -13,7 +13,9 @@ import (
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
goplugin "github.com/hashicorp/go-plugin"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/hashicorp/vagrant-plugin-sdk/component"
|
||||
@ -436,12 +438,12 @@ func (p *Project) JobInfo() *component.JobInfo {
|
||||
|
||||
// LoadTarget loads a target within the current project. If the target is not
|
||||
// found, it will be created.
|
||||
func (p *Project) LoadTarget(topts ...TargetOption) (t *Target, err error) {
|
||||
func (p *Project) LoadTarget(topts ...TargetOption) (*Target, error) {
|
||||
p.m.Lock()
|
||||
defer p.m.Unlock()
|
||||
|
||||
// Create our target
|
||||
t = &Target{
|
||||
t := &Target{
|
||||
cache: cacher.New(),
|
||||
ctx: p.ctx,
|
||||
project: p,
|
||||
@ -451,6 +453,7 @@ func (p *Project) LoadTarget(topts ...TargetOption) (t *Target, err error) {
|
||||
},
|
||||
ui: p.ui,
|
||||
}
|
||||
var err error
|
||||
|
||||
// Apply any options provided
|
||||
for _, opt := range topts {
|
||||
@ -481,12 +484,15 @@ func (p *Project) LoadTarget(topts ...TargetOption) (t *Target, err error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.vagrantfile = tv.(*Vagrantfile)
|
||||
// Set the vagrantfile if one was returned
|
||||
if tv != nil {
|
||||
t.vagrantfile = tv.(*Vagrantfile)
|
||||
}
|
||||
}
|
||||
|
||||
// If this is the first time through, re-init the target
|
||||
if err = t.init(); err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the data directory is set, set it
|
||||
@ -521,7 +527,7 @@ func (p *Project) LoadTarget(topts ...TargetOption) (t *Target, err error) {
|
||||
p.targets[t.target.ResourceId] = t
|
||||
p.targets[t.target.Name] = t
|
||||
|
||||
return
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// Client returns the API client for the backend server.
|
||||
@ -724,14 +730,7 @@ func (p *Project) InitTargets() (err error) {
|
||||
|
||||
updated := false
|
||||
for _, t := range targets {
|
||||
_, err = p.Client().UpsertTarget(p.ctx,
|
||||
&vagrant_server.UpsertTargetRequest{
|
||||
Target: &vagrant_server.Target{
|
||||
Name: t,
|
||||
Project: p.Ref().(*vagrant_plugin_sdk.Ref_Project),
|
||||
},
|
||||
},
|
||||
)
|
||||
_, err = p.createTarget(t)
|
||||
if err != nil {
|
||||
p.logger.Error("failed to initialize target with project",
|
||||
"project", p.Name(),
|
||||
@ -775,6 +774,44 @@ func (p *Project) refreshProject() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Create a target within this project if it does not already exist
|
||||
func (p *Project) createTarget(
|
||||
name string, // name of the target
|
||||
) (*vagrant_server.Target, error) {
|
||||
result, err := p.Client().FindTarget(p.ctx,
|
||||
&vagrant_server.FindTargetRequest{
|
||||
Target: &vagrant_server.Target{
|
||||
Name: name,
|
||||
Project: p.Ref().(*vagrant_plugin_sdk.Ref_Project),
|
||||
},
|
||||
},
|
||||
)
|
||||
// If we encountered any error except a not found, return it
|
||||
if err != nil && status.Code(err) != codes.NotFound {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If we have no error here, we have an existing result
|
||||
if err == nil {
|
||||
return result.Target, nil
|
||||
}
|
||||
|
||||
// And if we are still here, create it
|
||||
resp, err := p.Client().UpsertTarget(p.ctx,
|
||||
&vagrant_server.UpsertTargetRequest{
|
||||
Target: &vagrant_server.Target{
|
||||
Name: name,
|
||||
Project: p.Ref().(*vagrant_plugin_sdk.Ref_Project),
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resp.Target, 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
|
||||
@ -890,9 +927,10 @@ func WithProjectRef(r *vagrant_plugin_sdk.Ref_Project) ProjectOption {
|
||||
result, err := p.Client().FindProject(p.ctx,
|
||||
&vagrant_server.FindProjectRequest{
|
||||
Project: &vagrant_server.Project{
|
||||
Basis: r.Basis,
|
||||
Name: r.Name,
|
||||
Path: r.Path,
|
||||
Basis: r.Basis,
|
||||
Name: r.Name,
|
||||
Path: r.Path,
|
||||
ResourceId: r.ResourceId,
|
||||
},
|
||||
},
|
||||
)
|
||||
@ -916,7 +954,7 @@ func WithProjectRef(r *vagrant_plugin_sdk.Ref_Project) ProjectOption {
|
||||
}
|
||||
|
||||
// Before we init, validate basis is consistent
|
||||
if project.Basis.ResourceId != r.Basis.ResourceId {
|
||||
if r.Basis != nil && project.Basis.ResourceId != r.Basis.ResourceId {
|
||||
p.logger.Error("invalid basis for project", "request-basis", r.Basis,
|
||||
"project-basis", project.Basis)
|
||||
return errors.New("project basis configuration is invalid")
|
||||
|
||||
@ -11,14 +11,11 @@ import (
|
||||
func projectTargets(t *testing.T, project *Project, numTargets int) (targets []*Target) {
|
||||
targets = make([]*Target, numTargets)
|
||||
for i := 0; i < numTargets; i++ {
|
||||
tt, err := TestTarget(t, project, &vagrant_server.Target{
|
||||
tt := TestTarget(t, project, &vagrant_server.Target{
|
||||
ResourceId: fmt.Sprintf("id-%d", i),
|
||||
Name: fmt.Sprintf("target-%d", i),
|
||||
Uuid: fmt.Sprintf("uuid-%d", i),
|
||||
})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
targets = append(targets, tt)
|
||||
}
|
||||
return
|
||||
@ -35,14 +32,8 @@ func TestNewProject(t *testing.T) {
|
||||
func TestProjectGetTarget(t *testing.T) {
|
||||
tp := TestMinimalProject(t)
|
||||
// Add targets to project
|
||||
targetOne, err := TestTarget(t, tp, &vagrant_server.Target{ResourceId: "id-one", Name: "target-one"})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
targetTwo, err := TestTarget(t, tp, &vagrant_server.Target{ResourceId: "id-two", Name: "target-two"})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
targetOne := TestTarget(t, tp, &vagrant_server.Target{ResourceId: "id-one", Name: "target-one"})
|
||||
targetTwo := TestTarget(t, tp, &vagrant_server.Target{ResourceId: "id-two", Name: "target-two"})
|
||||
|
||||
// Get by id
|
||||
one, err := tp.Target("id-one", "")
|
||||
|
||||
@ -472,41 +472,20 @@ func (t *Target) init() (err error) {
|
||||
// If the configuration was updated during load, save it so
|
||||
// we can re-apply after loading stored data
|
||||
var conf *vagrant_plugin_sdk.Args_ConfigData
|
||||
if t.target != nil && t.target.Configuration != nil {
|
||||
if t.target.Configuration != nil {
|
||||
conf = t.target.Configuration
|
||||
}
|
||||
|
||||
// First we want to run a lookup if this target already exists
|
||||
if t.target.ResourceId != "" {
|
||||
resp, err := t.Client().FindTarget(t.ctx,
|
||||
&vagrant_server.FindTargetRequest{
|
||||
Target: &vagrant_server.Target{
|
||||
ResourceId: t.target.ResourceId,
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.target = resp.Target
|
||||
} else {
|
||||
for _, pt := range t.project.project.Targets {
|
||||
if t.target.Name == pt.Name {
|
||||
resp, err := t.Client().FindTarget(t.ctx,
|
||||
&vagrant_server.FindTargetRequest{
|
||||
Target: &vagrant_server.Target{
|
||||
ResourceId: pt.ResourceId,
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.target = resp.Target
|
||||
}
|
||||
}
|
||||
// Pull target info
|
||||
resp, err := t.Client().FindTarget(t.ctx,
|
||||
&vagrant_server.FindTargetRequest{
|
||||
Target: t.target,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
t.target = resp.Target
|
||||
|
||||
// If we have configuration data, re-apply it
|
||||
if conf != nil {
|
||||
@ -524,6 +503,10 @@ func (t *Target) init() (err error) {
|
||||
// If we don't have configuration data, just stub
|
||||
if t.target.Configuration == nil {
|
||||
t.target.Configuration = &vagrant_plugin_sdk.Args_ConfigData{}
|
||||
t.vagrantfile = t.project.vagrantfile.clone("target", t)
|
||||
t.vagrantfile.root = &component.ConfigData{
|
||||
Data: map[string]interface{}{},
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -583,58 +566,34 @@ func WithTargetName(name string) TargetOption {
|
||||
|
||||
// Configure target with proto ref
|
||||
func WithTargetRef(r *vagrant_plugin_sdk.Ref_Target) TargetOption {
|
||||
return func(t *Target) (err error) {
|
||||
// Project must be set before we continue
|
||||
if t.project == nil {
|
||||
return fmt.Errorf("project must be set before loading target")
|
||||
}
|
||||
|
||||
return func(t *Target) error {
|
||||
// Target ref must include a resource id or name
|
||||
if r.Name == "" && r.ResourceId == "" {
|
||||
return fmt.Errorf("target ref must include ResourceId and/or Name")
|
||||
}
|
||||
|
||||
var target *vagrant_server.Target
|
||||
// Target ref must include project ref if resource id is empty
|
||||
if r.Name == "" && r.Project == nil {
|
||||
return fmt.Errorf("target ref must include Project for name lookup")
|
||||
}
|
||||
|
||||
result, err := t.Client().FindTarget(t.ctx,
|
||||
&vagrant_server.FindTargetRequest{
|
||||
Target: &vagrant_server.Target{
|
||||
ResourceId: r.ResourceId,
|
||||
Name: r.Name,
|
||||
Project: t.project.Ref().(*vagrant_plugin_sdk.Ref_Project),
|
||||
Project: r.Project,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
// TODO(spox): check for not found and error if something different
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
if result != nil {
|
||||
target = result.Target
|
||||
} else {
|
||||
var result *vagrant_server.UpsertTargetResponse
|
||||
result, err = t.Client().UpsertTarget(t.ctx,
|
||||
&vagrant_server.UpsertTargetRequest{
|
||||
Target: &vagrant_server.Target{
|
||||
Name: r.Name,
|
||||
Project: t.project.Ref().(*vagrant_plugin_sdk.Ref_Project),
|
||||
},
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
target = result.Target
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.Project != nil && target.Project.ResourceId != r.Project.ResourceId {
|
||||
t.logger.Error("invalid project for target",
|
||||
"request-project", r.Project,
|
||||
"target-project", target.Project)
|
||||
|
||||
return fmt.Errorf("target project configuration is invalid")
|
||||
}
|
||||
t.target = target
|
||||
return
|
||||
t.target = result.Target
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -79,8 +79,7 @@ func TestTargetIndexSet(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
tt, err := TestMinimalTarget(t)
|
||||
require.NoError(t, err)
|
||||
tt := TestMinimalTarget(t)
|
||||
|
||||
tt.target.Name = "newName"
|
||||
updated, err := ti.Set(tt)
|
||||
|
||||
@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func TestTargetSpecializeMachine(t *testing.T) {
|
||||
tt, _ := TestMinimalTarget(t)
|
||||
tt := TestMinimalTarget(t)
|
||||
specialized, err := tt.Specialize((*core.Machine)(nil))
|
||||
if err != nil {
|
||||
t.Errorf("Specialize function returned an error")
|
||||
@ -28,8 +28,8 @@ func TestTargetSpecializeMachine(t *testing.T) {
|
||||
|
||||
func TestTargetSpecializeMultiMachine(t *testing.T) {
|
||||
p := TestMinimalProject(t)
|
||||
tt1, _ := TestTarget(t, p, &vagrant_server.Target{Name: "tt1"})
|
||||
tt2, _ := TestTarget(t, p, &vagrant_server.Target{Name: "tt2"})
|
||||
tt1 := TestTarget(t, p, &vagrant_server.Target{Name: "tt1"})
|
||||
tt2 := TestTarget(t, p, &vagrant_server.Target{Name: "tt2"})
|
||||
|
||||
specialized, err := tt1.Specialize((*core.Machine)(nil))
|
||||
if err != nil {
|
||||
@ -53,7 +53,7 @@ func TestTargetSpecializeMultiMachine(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTargetSpecializeBad(t *testing.T) {
|
||||
tt, _ := TestMinimalTarget(t)
|
||||
tt := TestMinimalTarget(t)
|
||||
specialized, err := tt.Specialize((*core.Project)(nil))
|
||||
|
||||
if err != nil {
|
||||
|
||||
@ -105,10 +105,3 @@ func TestBasis(t testing.T, opts ...BasisOption) (b *Basis) {
|
||||
b, _ = NewBasis(context.Background(), append(defaultOpts, opts...)...)
|
||||
return
|
||||
}
|
||||
|
||||
// func WithTestBasisConfig(config *vagrant_plugin_sdk.Vagrantfile_Vagrantfile) BasisOption {
|
||||
// return func(m *Basis) (err error) {
|
||||
// m.basis.Configuration = config
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
|
||||
@ -12,12 +12,17 @@ import (
|
||||
// factories, configuration, etc.
|
||||
func TestProject(t testing.T, opts ...BasisOption) *Project {
|
||||
b := TestBasis(t, opts...)
|
||||
p, _ := b.LoadProject([]ProjectOption{
|
||||
p, err := b.LoadProject([]ProjectOption{
|
||||
WithProjectRef(&vagrant_plugin_sdk.Ref_Project{
|
||||
Basis: b.Ref().(*vagrant_plugin_sdk.Ref_Basis),
|
||||
Name: "test-project"},
|
||||
),
|
||||
}...)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
@ -27,11 +32,16 @@ func TestMinimalProject(t testing.T) *Project {
|
||||
pluginManager := plugin.TestManager(t)
|
||||
b := TestBasis(t, WithPluginManager(pluginManager))
|
||||
|
||||
p, _ := b.LoadProject([]ProjectOption{
|
||||
p, err := b.LoadProject([]ProjectOption{
|
||||
WithProjectRef(&vagrant_plugin_sdk.Ref_Project{
|
||||
Basis: b.Ref().(*vagrant_plugin_sdk.Ref_Basis),
|
||||
Name: "test-project"},
|
||||
),
|
||||
}...)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
@ -2,8 +2,12 @@ package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/imdario/mergo"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"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"
|
||||
@ -14,32 +18,53 @@ import (
|
||||
// TestTarget returns a fully in-memory and side-effect free Target that
|
||||
// can be used for testing. Additional options can be given to provide your own
|
||||
// factories, configuration, etc.
|
||||
func TestTarget(t testing.T, tp *Project, tt *vagrant_server.Target) (target *Target, err error) {
|
||||
testingTarget := ptypes.TestTarget(t, tt)
|
||||
testingTarget.Project = tp.Ref().(*vagrant_plugin_sdk.Ref_Project)
|
||||
tp.basis.client.UpsertTarget(
|
||||
func TestTarget(t testing.T, p *Project, st *vagrant_server.Target, opts ...TestTargetOption) (target *Target) {
|
||||
testingTarget := ptypes.TestTarget(t, st)
|
||||
testingTarget.Project = p.Ref().(*vagrant_plugin_sdk.Ref_Project)
|
||||
_, err := p.basis.client.UpsertTarget(
|
||||
context.Background(),
|
||||
&vagrant_server.UpsertTargetRequest{
|
||||
Project: tp.Ref().(*vagrant_plugin_sdk.Ref_Project),
|
||||
Project: p.Ref().(*vagrant_plugin_sdk.Ref_Project),
|
||||
Target: testingTarget,
|
||||
},
|
||||
)
|
||||
target, err = tp.LoadTarget([]TargetOption{
|
||||
WithTargetRef(&vagrant_plugin_sdk.Ref_Target{Project: tp.Ref().(*vagrant_plugin_sdk.Ref_Project), Name: testingTarget.Name}),
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
target, err = p.LoadTarget([]TargetOption{
|
||||
WithTargetRef(
|
||||
&vagrant_plugin_sdk.Ref_Target{
|
||||
Project: p.Ref().(*vagrant_plugin_sdk.Ref_Project),
|
||||
Name: testingTarget.Name,
|
||||
},
|
||||
),
|
||||
}...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
tp.project.Targets = append(tp.project.Targets, target.Ref().(*vagrant_plugin_sdk.Ref_Target))
|
||||
|
||||
if err = p.refreshProject(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
if oerr := opt(target); oerr != nil {
|
||||
err = multierror.Append(err, oerr)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// TestMinimalTarget uses a minimal project to setup the most basic target
|
||||
// that will work for testing
|
||||
func TestMinimalTarget(t testing.T) (target *Target, err error) {
|
||||
func TestMinimalTarget(t testing.T) (target *Target) {
|
||||
tp := TestMinimalProject(t)
|
||||
tp.basis.client.UpsertTarget(
|
||||
_, err := tp.basis.client.UpsertTarget(
|
||||
context.Background(),
|
||||
&vagrant_server.UpsertTargetRequest{
|
||||
Project: tp.Ref().(*vagrant_plugin_sdk.Ref_Project),
|
||||
@ -49,10 +74,18 @@ func TestMinimalTarget(t testing.T) (target *Target, err error) {
|
||||
},
|
||||
},
|
||||
)
|
||||
target, err = tp.LoadTarget([]TargetOption{
|
||||
WithTargetRef(&vagrant_plugin_sdk.Ref_Target{Project: tp.Ref().(*vagrant_plugin_sdk.Ref_Project), Name: "test-target"}),
|
||||
}...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
target, err = tp.LoadTarget([]TargetOption{
|
||||
WithTargetRef(
|
||||
&vagrant_plugin_sdk.Ref_Target{
|
||||
Project: tp.Ref().(*vagrant_plugin_sdk.Ref_Project),
|
||||
Name: "test-target",
|
||||
},
|
||||
),
|
||||
}...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -63,63 +96,64 @@ func TestMinimalTarget(t testing.T) (target *Target, err error) {
|
||||
// TestMachine returns a fully in-memory and side-effect free Machine that
|
||||
// can be used for testing. Additional options can be given to provide your own
|
||||
// factories, configuration, etc.
|
||||
func TestMachine(t testing.T, tp *Project, opts ...TestMachineOption) (machine *Machine, err error) {
|
||||
tt, _ := TestTarget(t, tp, &vagrant_server.Target{})
|
||||
func TestMachine(t testing.T, tp *Project, opts ...TestTargetOption) (machine *Machine) {
|
||||
tt := TestTarget(t, tp, &vagrant_server.Target{})
|
||||
specialized, err := tt.Specialize((*core.Machine)(nil))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
machine = specialized.(*Machine)
|
||||
for _, opt := range opts {
|
||||
if oerr := opt(machine); oerr != nil {
|
||||
err = multierror.Append(err, oerr)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// TestMinimalMachine uses a minimal project to setup the most basic machine
|
||||
// that will work for testing
|
||||
func TestMinimalMachine(t testing.T) (machine *Machine, err error) {
|
||||
func TestMinimalMachine(t testing.T) (machine *Machine) {
|
||||
tp := TestMinimalProject(t)
|
||||
tt, err := TestTarget(t, tp, &vagrant_server.Target{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
tt := TestTarget(t, tp, &vagrant_server.Target{})
|
||||
specialized, err := tt.Specialize((*core.Machine)(nil))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return nil, err
|
||||
}
|
||||
machine = specialized.(*Machine)
|
||||
WithTestTargetMinimalConfig()(machine)
|
||||
return
|
||||
}
|
||||
|
||||
type TestMachineOption func(*Machine) error
|
||||
type TestTargetOption func(interface{}) error
|
||||
|
||||
func WithTestTargetMinimalConfig() TestMachineOption {
|
||||
return func(m *Machine) (err error) {
|
||||
m.target.Configuration = &vagrant_plugin_sdk.Args_ConfigData{}
|
||||
return
|
||||
func WithTestTargetConfig(config *component.ConfigData) TestTargetOption {
|
||||
return func(raw interface{}) (err error) {
|
||||
switch v := raw.(type) {
|
||||
case *Target:
|
||||
return mergo.Merge(v.vagrantfile.root, config)
|
||||
case *Machine:
|
||||
return mergo.Merge(v.vagrantfile.root, config)
|
||||
default:
|
||||
panic(fmt.Sprintf("Invalid type for TestTargetOption (%T)", raw))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WithTestTargetConfig(config *vagrant_plugin_sdk.Args_ConfigData) TestMachineOption {
|
||||
return func(m *Machine) (err error) {
|
||||
m.target.Configuration = config
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func WithTestTargetProvider(provider string) TestMachineOption {
|
||||
return func(m *Machine) (err error) {
|
||||
m.target.Provider = provider
|
||||
func WithTestTargetProvider(provider string) TestTargetOption {
|
||||
return func(raw interface{}) (err error) {
|
||||
switch v := raw.(type) {
|
||||
case *Target:
|
||||
v.target.Provider = provider
|
||||
case *Machine:
|
||||
v.target.Provider = provider
|
||||
default:
|
||||
panic(fmt.Sprintf("Invalid type for TestTargetOption (%T)", raw))
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -452,14 +452,15 @@ func (v *Vagrantfile) Target(
|
||||
return
|
||||
}
|
||||
|
||||
// Convert to actual Vagrantfile for target setup
|
||||
vf := conf.(*Vagrantfile)
|
||||
|
||||
target, err = v.origin.LoadTarget(
|
||||
WithTargetName(name),
|
||||
WithTargetVagrantfile(vf),
|
||||
)
|
||||
opts := []TargetOption{WithTargetName(name)}
|
||||
var vf *Vagrantfile
|
||||
|
||||
if conf != nil {
|
||||
// Convert to actual Vagrantfile for target setup
|
||||
vf = conf.(*Vagrantfile)
|
||||
opts = append(opts, WithTargetVagrantfile(vf))
|
||||
}
|
||||
target, err = v.origin.LoadTarget(opts...)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -467,21 +468,24 @@ func (v *Vagrantfile) Target(
|
||||
// Since the target config gives us a Vagrantfile which is
|
||||
// attached to the project, we need to clone it and attach
|
||||
// it to the target we loaded
|
||||
rawTarget := target.(*Target)
|
||||
tvf := v.clone(name, rawTarget)
|
||||
if err = tvf.Init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawTarget.vagrantfile = tvf
|
||||
if vf != nil {
|
||||
rawTarget := target.(*Target)
|
||||
tvf := v.clone(name, rawTarget)
|
||||
if err = tvf.Init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rawTarget.vagrantfile = tvf
|
||||
|
||||
if err = vf.Close(); err != nil {
|
||||
return nil, err
|
||||
if err = vf.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Generate a new Vagrantfile for the given target
|
||||
// NOTE: This function may return a nil result without an error
|
||||
// TODO(spox): Provider validation is not currently implemented
|
||||
func (v *Vagrantfile) TargetConfig(
|
||||
name, // name of the target
|
||||
@ -498,11 +502,11 @@ func (v *Vagrantfile) TargetConfig(
|
||||
|
||||
subvm, err := v.GetValue("vm", "__defined_vms", name)
|
||||
if err != nil {
|
||||
v.logger.Error("failed to get subvm",
|
||||
v.logger.Warn("failed to get subvm",
|
||||
"name", name,
|
||||
"error", err,
|
||||
)
|
||||
return nil, err
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if subvm == nil {
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hashicorp/go-memdb"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
"github.com/hashicorp/vagrant-plugin-sdk/proto/vagrant_plugin_sdk"
|
||||
"github.com/hashicorp/vagrant/internal/server/proto/vagrant_server"
|
||||
@ -165,6 +165,9 @@ func (s *State) targetList(
|
||||
result = append(result, &vagrant_plugin_sdk.Ref_Target{
|
||||
ResourceId: next.(*targetIndexRecord).Id,
|
||||
Name: next.(*targetIndexRecord).Name,
|
||||
Project: &vagrant_plugin_sdk.Ref_Project{
|
||||
ResourceId: next.(*targetIndexRecord).ProjectId,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user