Merge pull request #268 from hashicorp/port-default-provider
Port default provider
This commit is contained in:
commit
f21f76b41d
7
.gitignore
vendored
7
.gitignore
vendored
@ -63,3 +63,10 @@ cover.out
|
||||
|
||||
# nektos/act secrets file
|
||||
.secrets
|
||||
|
||||
# delve debug binary
|
||||
__debug_bin
|
||||
|
||||
# solargraph (ruby lsp) & rubocop
|
||||
.solargraph.yml
|
||||
.rubocop.yml
|
||||
|
||||
@ -132,7 +132,7 @@ func (c *Command) ExecuteInfo(trm terminal.UI, p plugincore.Project) int32 {
|
||||
ptrm.Output("YAY! This is project specific output!")
|
||||
}
|
||||
|
||||
t, err := p.Target("one")
|
||||
t, err := p.Target("one", "")
|
||||
if err != nil {
|
||||
trm.Output("Failed to load `one' target -- " + err.Error())
|
||||
return 1
|
||||
|
||||
2
go.mod
2
go.mod
@ -45,7 +45,7 @@ require (
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.7.1-0.20201023000745-3de61ecba298
|
||||
github.com/hashicorp/nomad/api v0.0.0-20200814140818-42de70466a9d
|
||||
github.com/hashicorp/vagrant-plugin-sdk v0.0.0-20220524143830-80e9a67614d0
|
||||
github.com/hashicorp/vagrant-plugin-sdk v0.0.0-20220525200400-f1459dc0d92b
|
||||
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect
|
||||
github.com/imdario/mergo v0.3.11
|
||||
github.com/improbable-eng/grpc-web v0.13.0
|
||||
|
||||
6
go.sum
6
go.sum
@ -355,10 +355,8 @@ github.com/hashicorp/hcl/v2 v2.7.1-0.20201023000745-3de61ecba298 h1:pLsdnvAlWuZ9
|
||||
github.com/hashicorp/hcl/v2 v2.7.1-0.20201023000745-3de61ecba298/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY=
|
||||
github.com/hashicorp/nomad/api v0.0.0-20200814140818-42de70466a9d h1:afuZ/KNbxwUgjEzq2NXO2bRKZgsIJQgFxgIRGETF0/A=
|
||||
github.com/hashicorp/nomad/api v0.0.0-20200814140818-42de70466a9d/go.mod h1:DCi2k47yuUDzf2qWAK8E1RVmWgz/lc0jZQeEnICTxmY=
|
||||
github.com/hashicorp/vagrant-plugin-sdk v0.0.0-20220513172229-62750f6e1ce7 h1:4d/nNs0gKLHkm9Ra/bdQTvxWSz0ctvwaOUFrZD/4pN4=
|
||||
github.com/hashicorp/vagrant-plugin-sdk v0.0.0-20220513172229-62750f6e1ce7/go.mod h1:KWfWOiotOWKiAqdroXVc7GUFnuOzlzhnRkGTV9Js7/s=
|
||||
github.com/hashicorp/vagrant-plugin-sdk v0.0.0-20220524143830-80e9a67614d0 h1:oHSg3GwN9Wk4Fa94Ozx9et+hUesiPe4bdjyp0uIv5Qo=
|
||||
github.com/hashicorp/vagrant-plugin-sdk v0.0.0-20220524143830-80e9a67614d0/go.mod h1:KWfWOiotOWKiAqdroXVc7GUFnuOzlzhnRkGTV9Js7/s=
|
||||
github.com/hashicorp/vagrant-plugin-sdk v0.0.0-20220525200400-f1459dc0d92b h1:GidqljOXwQSIFn+nk4DOpa0kpR/1x/yS/yCNnA7sUFE=
|
||||
github.com/hashicorp/vagrant-plugin-sdk v0.0.0-20220525200400-f1459dc0d92b/go.mod h1:KWfWOiotOWKiAqdroXVc7GUFnuOzlzhnRkGTV9Js7/s=
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce h1:7UnVY3T/ZnHUrfviiAgIUjg2PXxsQfs5bphsG8F7Keo=
|
||||
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||
|
||||
@ -159,20 +159,6 @@ func (p *Project) LoadTarget(n string) (*Target, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TODO: Determine default provider by implementing algorithm from
|
||||
// https://www.vagrantup.com/docs/providers/basic_usage#default-provider
|
||||
//
|
||||
// Currently blocked on being able to parse Vagrantfile
|
||||
func (p *Project) GetDefaultProvider(exclude []string, forceDefault bool, checkUsable bool) (provider string, err error) {
|
||||
defaultProvider := os.Getenv("VAGRANT_DEFAULT_PROVIDER")
|
||||
if defaultProvider != "" && forceDefault {
|
||||
return defaultProvider, nil
|
||||
}
|
||||
|
||||
// HACK: This should throw an error if no default provider is found
|
||||
return "virtualbox", nil
|
||||
}
|
||||
|
||||
func (p *Project) UI() terminal.UI {
|
||||
return p.ui
|
||||
}
|
||||
|
||||
@ -231,6 +231,88 @@ func StringToPathFunc() mapstructure.DecodeHookFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// TEMP: until we have plugin priority being sent along at registration, we are
|
||||
// manually mirroring the plugin priorities from legacy vagrant
|
||||
func syncedFolderPriority(name string) int {
|
||||
switch name {
|
||||
case "nfs":
|
||||
return 5
|
||||
case "rsync":
|
||||
return 5
|
||||
case "smb":
|
||||
return 7
|
||||
default: // covers virtualbox, docker, vmware
|
||||
return 10
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Machine) defaultSyncedFolderType() (folderType *string, err error) {
|
||||
logger := m.logger.Named("default-synced-folder-type")
|
||||
|
||||
// Get all available synced folder plugins
|
||||
syncedFolders, err := m.project.basis.typeComponents(m.ctx, component.SyncedFolderType)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Get all plugin components
|
||||
components := make([]*Component, 0, len(syncedFolders))
|
||||
for _, value := range syncedFolders {
|
||||
components = append(components, value)
|
||||
}
|
||||
|
||||
// Sort by plugin priority. Higher is first
|
||||
sort.SliceStable(components, func(i, j int) bool {
|
||||
return syncedFolderPriority(components[i].Info.Name) > syncedFolderPriority(components[j].Info.Name)
|
||||
})
|
||||
|
||||
names := make([]string, 0, len(components))
|
||||
for _, c := range components {
|
||||
names = append(names, c.Info.Name)
|
||||
}
|
||||
logger.Debug("Sorted synced folder plugins", "names", names)
|
||||
|
||||
// Remove unallowed types
|
||||
config := m.target.Configuration
|
||||
machineConfig := config.ConfigVm
|
||||
if len(machineConfig.AllowedSyncedFolderTypes) > 0 {
|
||||
allowed := make(map[string]struct{})
|
||||
for _, a := range machineConfig.AllowedSyncedFolderTypes {
|
||||
allowed[a] = struct{}{}
|
||||
}
|
||||
k := 0
|
||||
for _, c := range components {
|
||||
if _, ok := allowed[c.Info.Name]; ok {
|
||||
components[k] = c
|
||||
k++
|
||||
} else {
|
||||
logger.Debug("removing disallowed plugin", "type", c.Info.Name)
|
||||
}
|
||||
}
|
||||
components = components[:k]
|
||||
}
|
||||
|
||||
for _, component := range components {
|
||||
syncedFolder := component.Value.(core.SyncedFolder)
|
||||
usable, err := syncedFolder.Usable(m)
|
||||
if err != nil {
|
||||
logger.Error("synced folder error on usable check",
|
||||
"plugin", component.Info.Name,
|
||||
"type", "SyncedFolder",
|
||||
"error", err)
|
||||
continue
|
||||
}
|
||||
if usable {
|
||||
logger.Info("returning default", "name", component.Info.Name)
|
||||
return &component.Info.Name, nil
|
||||
} else {
|
||||
logger.Debug("skipping unusable plugin", "name", component.Info.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to detect guest plugin for current platform")
|
||||
}
|
||||
|
||||
// SyncedFolders implements core.Machine
|
||||
func (m *Machine) SyncedFolders() (folders []*core.MachineSyncedFolder, err error) {
|
||||
config := m.target.Configuration
|
||||
@ -239,10 +321,11 @@ func (m *Machine) SyncedFolders() (folders []*core.MachineSyncedFolder, err erro
|
||||
|
||||
folders = []*core.MachineSyncedFolder{}
|
||||
for _, folder := range syncedFolders {
|
||||
if folder.Type == nil {
|
||||
// TODO: get default synced folder type
|
||||
defaultType := "virtualbox"
|
||||
folder.Type = &defaultType
|
||||
if folder.GetType() == "" {
|
||||
folder.Type, err = m.defaultSyncedFolderType()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
lookup := "syncedfolder_" + *(folder.Type)
|
||||
v := m.cache.Get(lookup)
|
||||
|
||||
@ -101,6 +101,7 @@ func TestMachineGetNonExistentBox(t *testing.T) {
|
||||
WithTestTargetConfig(&vagrant_plugin_sdk.Vagrantfile_MachineConfig{
|
||||
ConfigVm: &vagrant_plugin_sdk.Vagrantfile_ConfigVM{Box: "somebox"},
|
||||
}),
|
||||
WithTestTargetProvider("testprovider"),
|
||||
)
|
||||
|
||||
box, err := tm.Box()
|
||||
@ -110,7 +111,7 @@ func TestMachineGetNonExistentBox(t *testing.T) {
|
||||
require.Equal(t, name, "somebox")
|
||||
provider, err := box.Provider()
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, provider)
|
||||
require.Equal(t, provider, "testprovider")
|
||||
metaurl, err := box.MetadataURL()
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, metaurl)
|
||||
@ -283,6 +284,7 @@ func syncedFolderPlugin(t *testing.T, name string) *plugin.Plugin {
|
||||
plugin.WithPluginTypes(component.SyncedFolderType),
|
||||
)
|
||||
}
|
||||
|
||||
func TestMachineSyncedFolders(t *testing.T) {
|
||||
mySyncedFolder := syncedFolderPlugin(t, "mysyncedfolder")
|
||||
myOtherSyncedFolder := syncedFolderPlugin(t, "myothersyncedfolder")
|
||||
|
||||
@ -3,6 +3,8 @@ package core
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@ -66,7 +68,7 @@ func (p *Project) ActiveTargets() (activeTargets []core.Target, err error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if st == core.CREATED {
|
||||
if st.IsActive() {
|
||||
activeTargets = append(activeTargets, t)
|
||||
}
|
||||
}
|
||||
@ -99,10 +101,159 @@ func (p *Project) DefaultPrivateKey() (path path.Path, err error) {
|
||||
}
|
||||
|
||||
// DefaultProvider implements core.Project
|
||||
func (p *Project) DefaultProvider() (name string, err error) {
|
||||
// TODO: This needs to implement the default provider algorithm
|
||||
// from https://www.vagrantup.com/docs/providers/basic_usage.html#default-provider
|
||||
return "virtualbox", nil
|
||||
func (p *Project) DefaultProvider(opts *core.DefaultProviderOptions) (string, error) {
|
||||
logger := p.logger.Named("default-provider")
|
||||
logger.Debug("Searching for default provider", "options", fmt.Sprintf("%#v", opts))
|
||||
// Algorithm ported from Vagrant::Environment#default_provider; structure
|
||||
// and comments mirrored from there.
|
||||
|
||||
// Implement the algorithm from
|
||||
// https://www.vagrantup.com/docs/providers/basic_usage.html#default-provider
|
||||
// with additional steps 2.5 and 3.5 from
|
||||
// https://bugzilla.redhat.com/show_bug.cgi?id=1444492
|
||||
// to allow system-configured provider priorities.
|
||||
//
|
||||
// 1. The --provider flag on a vagrant up is chosen above all else, if it is
|
||||
// present.
|
||||
//
|
||||
// (Step 1 is done by the caller; this method is only called if --provider
|
||||
// wasn't given.)
|
||||
//
|
||||
// 2. If the VAGRANT_DEFAULT_PROVIDER environmental variable is set, it
|
||||
// takes next priority and will be the provider chosen.
|
||||
defaultProvider := os.Getenv("VAGRANT_DEFAULT_PROVIDER")
|
||||
if defaultProvider != "" && opts.ForceDefault {
|
||||
logger.Debug("Using forced default provider", "provider", defaultProvider)
|
||||
return defaultProvider, nil
|
||||
}
|
||||
|
||||
// Get the list of providers in our configuration, in order
|
||||
configProviders := []string{}
|
||||
for _, m := range p.project.GetConfiguration().GetMachineConfigs() {
|
||||
// If a MachineName is provided - we're only looking at providers
|
||||
// scoped to that machine name
|
||||
if opts.MachineName != "" && opts.MachineName != m.GetName() {
|
||||
continue
|
||||
}
|
||||
for _, p := range m.GetConfigVm().GetProviders() {
|
||||
configProviders = append(configProviders, p.GetType())
|
||||
}
|
||||
}
|
||||
|
||||
usableProviders := []string{}
|
||||
pluginProviders, err := p.basis.plugins.ListPlugins("provider")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, pp := range pluginProviders {
|
||||
// Skip excluded providers
|
||||
if opts.IsExcluded(pp.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: how to check for defaultable?
|
||||
|
||||
// Skip the providers that aren't usable.
|
||||
if opts.CheckUsable {
|
||||
logger.Debug("Checking usable on provider", "provider", pp.Name)
|
||||
plug, err := p.basis.plugins.GetPlugin(pp.Name, pp.Type)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
pluginImpl := plug.Plugin.(core.Provider)
|
||||
usable, err := pluginImpl.Usable()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !usable {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// If we made it here we have a candidate usable provider
|
||||
usableProviders = append(usableProviders, pp.Name)
|
||||
}
|
||||
logger.Debug("Initial usable provider list", "usableProviders", usableProviders)
|
||||
|
||||
// TODO: how to get and sort by provider priority?
|
||||
|
||||
// If we're not forcing the default, but it's usable and hasn't been
|
||||
// otherwise excluded, return it now.
|
||||
for _, u := range usableProviders {
|
||||
if u == defaultProvider {
|
||||
logger.Debug("Using default provider as it was found in usable list",
|
||||
"provider", u)
|
||||
return u, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 2.5. Vagrant will go through all of the config.vm.provider calls in the
|
||||
// Vagrantfile and try each in order. It will choose the first
|
||||
// provider that is usable and listed in VAGRANT_PREFERRED_PROVIDERS.
|
||||
preferredProviders := strings.Split(os.Getenv("VAGRANT_PREFERRED_PROVIDERS"), ",")
|
||||
k := 0
|
||||
for _, pp := range preferredProviders {
|
||||
spp := strings.TrimSpace(pp) // .map { s.strip }
|
||||
if spp != "" { // .select { !s.empty? }
|
||||
preferredProviders[k] = spp
|
||||
k++
|
||||
}
|
||||
}
|
||||
preferredProviders = preferredProviders[:k]
|
||||
|
||||
for _, cp := range configProviders {
|
||||
for _, up := range usableProviders {
|
||||
if cp == up {
|
||||
for _, pp := range preferredProviders {
|
||||
if cp == pp {
|
||||
logger.Debug("Using preferred provider detected in configuration and usable",
|
||||
"provider", pp)
|
||||
return pp, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Vagrant will go through all of the config.vm.provider calls in the
|
||||
// Vagrantfile and try each in order. It will choose the first provider
|
||||
// that is usable. For example, if you configure Hyper-V, it will never
|
||||
// be chosen on Mac this way. It must be both configured and usable.
|
||||
for _, cp := range configProviders {
|
||||
for _, up := range usableProviders {
|
||||
if cp == up {
|
||||
logger.Debug("Using provider detected in configuration and usable",
|
||||
"provider", cp)
|
||||
return cp, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3.5. Vagrant will go through VAGRANT_PREFERRED_PROVIDERS and find the
|
||||
// first plugin that reports it is usable.
|
||||
for _, pp := range preferredProviders {
|
||||
for _, up := range usableProviders {
|
||||
if pp == up {
|
||||
logger.Debug("Using preffered provider found in usable list",
|
||||
"provider", pp)
|
||||
return pp, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Vagrant will go through all installed provider plugins (including the
|
||||
// ones that come with Vagrant), and find the first plugin that reports
|
||||
// it is usable. There is a priority system here: systems that are known
|
||||
// better have a higher priority than systems that are worse. For
|
||||
// example, if you have the VMware provider installed, it will always
|
||||
// take priority over VirtualBox.
|
||||
if len(usableProviders) > 0 {
|
||||
logger.Debug("Using the first provider from the usable list",
|
||||
"provider", usableProviders[0])
|
||||
return usableProviders[0], nil
|
||||
}
|
||||
|
||||
return "", errors.New("No default provider.")
|
||||
}
|
||||
|
||||
// Home implements core.Project
|
||||
@ -138,13 +289,26 @@ func (p *Project) RootPath() (path path.Path, err error) {
|
||||
}
|
||||
|
||||
// Target implements core.Project
|
||||
func (p *Project) Target(nameOrId string) (core.Target, error) {
|
||||
func (p *Project) Target(nameOrId string, provider string) (core.Target, error) {
|
||||
if t, ok := p.targets[nameOrId]; ok {
|
||||
return t, nil
|
||||
}
|
||||
// Check for name or id
|
||||
for _, t := range p.targets {
|
||||
if t.target.Name == nameOrId {
|
||||
// TODO: Because we don't have provider selection fully ported
|
||||
// over, there are cases where a target is loaded without a
|
||||
// provider being set on it. For now we're just handling that here
|
||||
// on lookup, but once we know for sure that any Target that exists
|
||||
// already knows what its provider is, this should be able to be
|
||||
// removed.
|
||||
st, err := t.State()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if provider != "" && !st.IsActive() {
|
||||
t.target.Provider = provider
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
if t.target.ResourceId == nameOrId {
|
||||
@ -160,6 +324,7 @@ func (p *Project) Target(nameOrId string) (core.Target, error) {
|
||||
ResourceId: nameOrId,
|
||||
},
|
||||
),
|
||||
WithProvider(provider),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -45,17 +45,17 @@ func TestProjectGetTarget(t *testing.T) {
|
||||
}
|
||||
|
||||
// Get by id
|
||||
one, err := tp.Target("id-one")
|
||||
one, err := tp.Target("id-one", "")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, targetOne, one)
|
||||
|
||||
// Get by name
|
||||
two, err := tp.Target("target-two")
|
||||
two, err := tp.Target("target-two", "")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, targetTwo, two)
|
||||
|
||||
// Get target that doesn't exist
|
||||
noexist, err := tp.Target("ohnooooo")
|
||||
noexist, err := tp.Target("ohnooooo", "")
|
||||
require.Error(t, err)
|
||||
require.Nil(t, noexist)
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -98,6 +99,9 @@ func (t *Target) Provider() (p core.Provider, err error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if providerName == "" {
|
||||
return nil, errors.New("cannot fetch provider for target when provider name is blank")
|
||||
}
|
||||
provider, err := t.project.basis.component(
|
||||
t.ctx, component.ProviderType, providerName)
|
||||
|
||||
@ -110,10 +114,8 @@ func (t *Target) Provider() (p core.Provider, err error) {
|
||||
}
|
||||
|
||||
// ProviderName implements core.Target
|
||||
// TODO: Use actual value once provider is set on the go side
|
||||
func (t *Target) ProviderName() (string, error) {
|
||||
// return t.target.Provider, nil
|
||||
return "virtualbox", nil
|
||||
return t.target.Provider, nil
|
||||
}
|
||||
|
||||
// Communicate implements core.Target
|
||||
@ -410,7 +412,7 @@ type TargetOption func(*Target) error
|
||||
|
||||
func WithTargetName(name string) TargetOption {
|
||||
return func(t *Target) (err error) {
|
||||
if ex, _ := t.project.Target(name); ex != nil {
|
||||
if ex, _ := t.project.Target(name, ""); ex != nil {
|
||||
if et, ok := ex.(*Target); ok {
|
||||
t.target = et.target
|
||||
}
|
||||
@ -484,4 +486,13 @@ func WithTargetRef(r *vagrant_plugin_sdk.Ref_Target) TargetOption {
|
||||
}
|
||||
}
|
||||
|
||||
func WithProvider(provider string) TargetOption {
|
||||
return func(t *Target) (err error) {
|
||||
if t != nil && t.target != nil && provider != "" {
|
||||
t.target.Provider = provider
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var _ core.Target = (*Target)(nil)
|
||||
|
||||
@ -47,15 +47,7 @@ func (t *TargetIndex) Get(uuid string) (entry core.Target, err error) {
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
// Search name if not found by uuid
|
||||
result, err = t.client.FindTarget(t.ctx, &vagrant_server.FindTargetRequest{
|
||||
Target: &vagrant_server.Target{
|
||||
Name: uuid,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
return t.loadTarget(&vagrant_plugin_sdk.Ref_Target{
|
||||
ResourceId: result.Target.ResourceId,
|
||||
|
||||
@ -44,12 +44,6 @@ func TestTargetIndexGet(t *testing.T) {
|
||||
// Add targets
|
||||
projectTargets(t, tp, 3)
|
||||
|
||||
// Get by target name
|
||||
target, err = ti.Get("target-1")
|
||||
require.NoError(t, err)
|
||||
rid, _ := target.ResourceId()
|
||||
require.Equal(t, rid, "id-1")
|
||||
|
||||
// Get by target id
|
||||
target, err = ti.Get("uuid-1")
|
||||
require.NoError(t, err)
|
||||
@ -72,11 +66,6 @@ func TestTargetIndexIncludes(t *testing.T) {
|
||||
// Add targets
|
||||
projectTargets(t, tp, 3)
|
||||
|
||||
// Includes by target name
|
||||
exists, err = ti.Includes("target-1")
|
||||
require.NoError(t, err)
|
||||
require.True(t, exists)
|
||||
|
||||
// Includes by target id
|
||||
exists, err = ti.Includes("uuid-1")
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -72,6 +72,7 @@ func BuildTestSyncedFolderPlugin(parent string) *TestSyncedFolderPlugin {
|
||||
p.On("Seed", mock.AnythingOfType("*core.Seeds")).Return(nil)
|
||||
p.On("Seeds").Return(core.NewSeeds(), nil)
|
||||
p.On("Parent").Return(parent, nil)
|
||||
p.On("Usable", mock.AnythingOfType("*core.Machine")).Return(true, nil)
|
||||
return p
|
||||
}
|
||||
|
||||
|
||||
@ -101,3 +101,10 @@ func WithTestTargetConfig(config *vagrant_plugin_sdk.Vagrantfile_MachineConfig)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func WithTestTargetProvider(provider string) TestMachineOption {
|
||||
return func(m *Machine) (err error) {
|
||||
m.target.Provider = provider
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,6 +304,12 @@ module Vagrant
|
||||
# This returns the provider name for the default provider for this
|
||||
# environment.
|
||||
#
|
||||
# @param check_usable [Boolean] (true) whether to filter for `.usable?` providers
|
||||
# @param exclude [Array<Symbol>] ([]) list of provider names to exclude from
|
||||
# consideration
|
||||
# @param force_default [Boolean] (true) whether to prefer the value of
|
||||
# VAGRANT_DEFAULT_PROVIDER over other strategies if it is set
|
||||
# @param machine [Symbol] (nil) a machine name to scope this lookup
|
||||
# @return [Symbol] Name of the default provider.
|
||||
def default_provider(**opts)
|
||||
opts[:exclude] = Set.new(opts[:exclude]) if opts[:exclude]
|
||||
@ -974,7 +980,7 @@ module Vagrant
|
||||
provider = guess_provider
|
||||
vagrantfile.machine_names.each do |mname|
|
||||
ldp = @local_data_path.join("machines/#{mname}/#{provider}") if @local_data_path
|
||||
plugins << vagrantfile.machine_config(mname, guess_provider, boxes, ldp, false)[:config]
|
||||
plugins << vagrantfile.machine_config(mname, provider, boxes, ldp, false)[:config]
|
||||
end
|
||||
result = plugins.reverse.inject(Vagrant::Util::HashWithIndifferentAccess.new) do |memo, val|
|
||||
Vagrant::Util::DeepMerge.deep_merge(memo, val.vagrant.plugins)
|
||||
|
||||
@ -102,15 +102,16 @@ module Vagrant
|
||||
end
|
||||
|
||||
def default_provider(**opts)
|
||||
client.respond_to?(:default_provider) && client.default_provider.to_sym
|
||||
client.respond_to?(:default_provider) && client.default_provider(opts)
|
||||
end
|
||||
|
||||
# Gets a target (machine) by name
|
||||
#
|
||||
# @param [String] machine name
|
||||
# @param [String] provider name
|
||||
# return [VagrantPlugins::CommandServe::Client::Machine]
|
||||
def get_target(name)
|
||||
client.target(name)
|
||||
def get_target(name, provider)
|
||||
client.target(name, provider)
|
||||
end
|
||||
|
||||
# Returns the host object associated with this environment.
|
||||
@ -126,8 +127,8 @@ module Vagrant
|
||||
|
||||
# @param [String] machine name
|
||||
# return [Vagrant::Machine]
|
||||
def machine(name, *_, **_)
|
||||
client.machine(name)
|
||||
def machine(name, provider, **_)
|
||||
client.machine(name, provider)
|
||||
end
|
||||
|
||||
def machine_names
|
||||
|
||||
@ -30,7 +30,7 @@ module Vagrant
|
||||
@logger = Log4r::Logger.new("vagrant::machine")
|
||||
if !env.nil? && client.nil?
|
||||
@env = env
|
||||
@client = env.get_target(name)
|
||||
@client = env.get_target(name, provider_name)
|
||||
else
|
||||
@client = client
|
||||
@env = client.environment
|
||||
|
||||
@ -31,6 +31,25 @@ module Vagrant
|
||||
client.action(@machine.to_proto, name)
|
||||
end
|
||||
|
||||
# Executes the capability with the given name, optionally passing more
|
||||
# arguments onwards to the capability. If the capability returns a value,
|
||||
# it will be returned.
|
||||
#
|
||||
# @param [Symbol] cap_name Name of the capability
|
||||
def capability(cap_name, *args)
|
||||
@logger.debug("running remote provider capability #{cap_name} with args #{args}")
|
||||
client.capability(cap_name, *args)
|
||||
end
|
||||
|
||||
# Tests whether the given capability is possible.
|
||||
#
|
||||
# @param [Symbol] cap_name Capability name
|
||||
# @return [Boolean]
|
||||
def capability?(cap_name)
|
||||
@logger.debug("checking for remote provider capability #{cap_name}")
|
||||
client.has_capability?(cap_name)
|
||||
end
|
||||
|
||||
def machine_id_changed
|
||||
client.machine_id_changed(@machine.to_proto)
|
||||
end
|
||||
|
||||
@ -668,6 +668,12 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
|
||||
add_message "hashicorp.vagrant.sdk.Project.CwdResponse" do
|
||||
optional :path, :string, 1
|
||||
end
|
||||
add_message "hashicorp.vagrant.sdk.Project.DefaultProviderRequest" do
|
||||
optional :check_usable, :bool, 1
|
||||
repeated :exclude, :string, 2
|
||||
optional :force_default, :bool, 3
|
||||
optional :machine_name, :string, 4
|
||||
end
|
||||
add_message "hashicorp.vagrant.sdk.Project.DefaultProviderResponse" do
|
||||
optional :provider_name, :string, 1
|
||||
end
|
||||
@ -685,6 +691,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
|
||||
end
|
||||
add_message "hashicorp.vagrant.sdk.Project.TargetRequest" do
|
||||
optional :name, :string, 1
|
||||
optional :provider, :string, 2
|
||||
end
|
||||
add_message "hashicorp.vagrant.sdk.Project.TargetNamesResponse" do
|
||||
repeated :names, :string, 1
|
||||
@ -1114,6 +1121,7 @@ module Hashicorp
|
||||
Project::ActiveTargetsResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.Project.ActiveTargetsResponse").msgclass
|
||||
Project::ConfigResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.Project.ConfigResponse").msgclass
|
||||
Project::CwdResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.Project.CwdResponse").msgclass
|
||||
Project::DefaultProviderRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.Project.DefaultProviderRequest").msgclass
|
||||
Project::DefaultProviderResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.Project.DefaultProviderResponse").msgclass
|
||||
Project::HomeResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.Project.HomeResponse").msgclass
|
||||
Project::LocalDataResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.Project.LocalDataResponse").msgclass
|
||||
|
||||
@ -472,7 +472,7 @@ module Hashicorp
|
||||
rpc :CWD, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::Path
|
||||
rpc :DataDir, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::DataDir::Project
|
||||
rpc :DefaultPrivateKey, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::Path
|
||||
rpc :DefaultProvider, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Project::DefaultProviderResponse
|
||||
rpc :DefaultProvider, ::Hashicorp::Vagrant::Sdk::Project::DefaultProviderRequest, ::Hashicorp::Vagrant::Sdk::Project::DefaultProviderResponse
|
||||
rpc :Home, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::Path
|
||||
rpc :Host, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::Host
|
||||
rpc :LocalData, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::Path
|
||||
|
||||
@ -81,7 +81,6 @@ module Vagrant
|
||||
return Machine.new(name, provider, provider_cls, provider_config,
|
||||
provider_options, config, data_path, box, env, self)
|
||||
end
|
||||
|
||||
# Returns the configuration for a single machine.
|
||||
#
|
||||
# When loading a box Vagrantfile, it will be prepended to the
|
||||
|
||||
@ -54,10 +54,15 @@ module VagrantPlugins
|
||||
resp.path
|
||||
end
|
||||
|
||||
# return [String]
|
||||
def default_provider
|
||||
resp = client.default_provider(Empty.new)
|
||||
resp.provider_name
|
||||
def default_provider(opts)
|
||||
req = ::Hashicorp::Vagrant::Sdk::Project::DefaultProviderRequest.new(
|
||||
exclude: opts.fetch(:exclude, []),
|
||||
force_default: opts.fetch(:force_default, true),
|
||||
check_usable: opts.fetch(:check_usable, true),
|
||||
machine_name: opts[:machine],
|
||||
)
|
||||
resp = client.default_provider(req)
|
||||
resp.provider_name.to_sym
|
||||
end
|
||||
|
||||
# return [String]
|
||||
@ -79,8 +84,11 @@ module VagrantPlugins
|
||||
end
|
||||
|
||||
# return [Vagrant::Machine]
|
||||
def machine(name)
|
||||
t = client.target(SDK::Project::TargetRequest.new(name: name))
|
||||
def machine(name, provider)
|
||||
t = client.target(SDK::Project::TargetRequest.new(
|
||||
name: name,
|
||||
provider: provider,
|
||||
))
|
||||
machine = mapper.map(t, to: Vagrant::Machine)
|
||||
return machine
|
||||
end
|
||||
@ -124,9 +132,14 @@ module VagrantPlugins
|
||||
|
||||
# Returns a machine client for the given name
|
||||
# return [VagrantPlugins::CommandServe::Client::Target::Machine]
|
||||
def target(name)
|
||||
def target(name, provider)
|
||||
target = Target.load(
|
||||
client.target(SDK::Project::TargetRequest.new(name: name)),
|
||||
client.target(
|
||||
SDK::Project::TargetRequest.new(
|
||||
name: name,
|
||||
provider: provider,
|
||||
)
|
||||
),
|
||||
broker: broker
|
||||
)
|
||||
target.to_machine
|
||||
|
||||
@ -13,7 +13,7 @@ module VagrantPlugins
|
||||
:DESTROYED,
|
||||
].freeze
|
||||
|
||||
# @return [SDK::Ref::Target] proto reference for this target
|
||||
# @return [Hashicorp::Vagrant::Sdk::Ref::Target] proto reference for this target
|
||||
def ref
|
||||
SDK::Ref::Target.new(resource_id: resource_id)
|
||||
end
|
||||
|
||||
@ -2,7 +2,7 @@ module VagrantPlugins
|
||||
module CommandServe
|
||||
class Client
|
||||
class TargetIndex < Client
|
||||
# @param [string]
|
||||
# @param [String]
|
||||
# @return [Boolean] true if delete is successful
|
||||
def delete(ident)
|
||||
logger.debug("deleting machine with id #{ident} from index")
|
||||
@ -14,8 +14,8 @@ module VagrantPlugins
|
||||
true
|
||||
end
|
||||
|
||||
# @param [string]
|
||||
# @return [MachineIndex::Entry]
|
||||
# @param [String]
|
||||
# @return [Vagrant::MachineIndex::Entry]
|
||||
def get(ident)
|
||||
logger.debug("getting machine with id #{ident} from index")
|
||||
begin
|
||||
@ -31,7 +31,7 @@ module VagrantPlugins
|
||||
end
|
||||
end
|
||||
|
||||
# @param [string]
|
||||
# @param [String]
|
||||
# @return [Boolean]
|
||||
def include?(ident)
|
||||
logger.debug("checking for machine with id #{ident} in index")
|
||||
@ -42,8 +42,8 @@ module VagrantPlugins
|
||||
).exists
|
||||
end
|
||||
|
||||
# @param [MachineIndex::Entry]
|
||||
# @return [MachineIndex::Entry]
|
||||
# @param [Vagrant::MachineIndex::Entry]
|
||||
# @return [Vagrant::MachineIndex::Entry]
|
||||
def set(entry)
|
||||
logger.debug("setting machine #{entry} in index")
|
||||
if entry.id.to_s.empty?
|
||||
@ -62,7 +62,7 @@ module VagrantPlugins
|
||||
end
|
||||
|
||||
# Get all targets
|
||||
# @return [Array<MachineIndex::Entry>]
|
||||
# @return [Array<Vagrant::MachineIndex::Entry>]
|
||||
def all
|
||||
logger.debug("getting all machines")
|
||||
client.all(Empty.new).targets.map do |t_ref|
|
||||
|
||||
@ -20,14 +20,14 @@ module VagrantPlugins
|
||||
attr_reader :name
|
||||
# @return [Class] type of the argument
|
||||
attr_reader :type
|
||||
# @return [Callable] callable that can validate argument
|
||||
# @return [#call] callable that can validate argument
|
||||
attr_reader :validator
|
||||
|
||||
# Create a new input
|
||||
#
|
||||
# @param type [Class] Type of the input
|
||||
# @param validator [Callable] Callable to validate argument (optional)
|
||||
# @yield Callable to validate argument (optional)
|
||||
# @param validator [#call] Callable to validate argument (optional)
|
||||
# @yield #call to validate argument (optional)
|
||||
def initialize(type:, validator: nil, &block)
|
||||
if !type.is_a?(Class) && !type.is_a?(Module)
|
||||
raise ArgumentError,
|
||||
@ -107,14 +107,14 @@ module VagrantPlugins
|
||||
attr_reader :inputs
|
||||
# @return [Class, nil] type of output
|
||||
attr_reader :output
|
||||
# @return [Callable] callable to perform mapping
|
||||
# @return [#call] callable to perform mapping
|
||||
attr_reader :func
|
||||
|
||||
# Create a new mapper instance
|
||||
#
|
||||
# @param inputs [Array<Input>] List of inputs for mapper
|
||||
# @param output [Class] Type of output value
|
||||
# @param func [Callable] Callable to perform mapping
|
||||
# @param func [#call] Callable to perform mapping
|
||||
def initialize(inputs:, output:, func:)
|
||||
Array(inputs).each do |i|
|
||||
if !i.is_a?(Input)
|
||||
|
||||
@ -9,7 +9,7 @@ module VagrantPlugins
|
||||
super
|
||||
caps = Vagrant.plugin("2").local_manager.provider_capabilities
|
||||
default_args = {
|
||||
Client::Target::Machine => SDK::Args::Target::Machine
|
||||
Vagrant::Machine => SDK::Args::Target::Machine
|
||||
}
|
||||
initialize_capability_platform!(caps, default_args)
|
||||
end
|
||||
|
||||
@ -755,7 +755,12 @@ module VagrantPlugins
|
||||
@allow_fstab_modification = true if @allow_fstab_modification == UNSET_VALUE
|
||||
end
|
||||
|
||||
if !box && !clone && !machine.provider_options[:box_optional]
|
||||
# HACK(phinze): We cannot honor box_optional in gogo yet so we are
|
||||
# temporarily hacking in a workaround which explicitly looks for docker
|
||||
# instead of the option itself. Once plugin metadata is implemented
|
||||
# this conditional should be reverted to the commented line below
|
||||
# if !box && !clone && !machine.provider_options[:box_optional]
|
||||
if !box && !clone && machine.provider_name != :docker
|
||||
errors << I18n.t("vagrant.config.vm.box_missing")
|
||||
end
|
||||
|
||||
|
||||
@ -100,6 +100,8 @@ describe VagrantPlugins::Kernel_V2::VMConfig do
|
||||
end
|
||||
|
||||
it "is not required if the provider says so" do
|
||||
# TODO: reenable this test once provider options are implemented
|
||||
pending "removal of temporary workaround"
|
||||
machine.provider_options[:box_optional] = true
|
||||
subject.box = nil
|
||||
subject.finalize!
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user