Fix init and other commands that run without a project

The Basis needs to be able to respond to Vagrantfile() and
DefaultProvider() to make it through Vagrant::Environment
initialization.

Depends on https://github.com/hashicorp/vagrant-plugin-sdk/pull/178
This commit is contained in:
Paul Hinze 2022-06-29 15:39:47 -05:00
parent 25d00b4ff4
commit fb2a102c71
No known key found for this signature in database
GPG Key ID: 70B94C31D170FB29
5 changed files with 115 additions and 4 deletions

View File

@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"sync"
@ -12,6 +13,7 @@ import (
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-multierror"
goplugin "github.com/hashicorp/go-plugin"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto"
"github.com/hashicorp/vagrant-plugin-sdk/component"
@ -404,6 +406,96 @@ func (b *Basis) DefaultPrivateKey() (path path.Path, err error) {
return b.dir.DataDir().Join("insecure_private_key"), nil
}
// DefaultProvider implements core.Basis
// This is a subset of the Project.DefaultProvider() algorithm, just the parts
// that make sense when you don't have a Vagrantfile
func (b *Basis) DefaultProvider() (string, error) {
logger := b.logger.Named("default-provider")
logger.Debug("Searching for default provider")
defaultProvider := os.Getenv("VAGRANT_DEFAULT_PROVIDER")
if defaultProvider != "" {
logger.Debug("Using VAGRANT_DEFAULT_PROVIDER", "provider", defaultProvider)
return defaultProvider, nil
}
usableProviders := []*core.NamedPlugin{}
pluginProviders, err := b.plugins.ListPlugins("provider")
if err != nil {
return "", err
}
for _, pp := range pluginProviders {
logger.Debug("considering plugin", "provider", pp.Name)
plug, err := b.plugins.GetPlugin(pp.Name, pp.Type)
if err != nil {
return "", err
}
plugOpts := plug.Options.(*component.ProviderOptions)
logger.Debug("got provider options", "options", fmt.Sprintf("%#v", plugOpts))
// Skip providers that can't be defaulted.
if !plugOpts.Defaultable {
logger.Debug("skipping non-defaultable provider", "provider", pp.Name)
continue
}
// Skip the providers that aren't usable.
logger.Debug("Checking usable on provider", "provider", pp.Name)
pluginImpl := plug.Plugin.(core.Provider)
usable, err := pluginImpl.Usable()
if err != nil {
return "", err
}
if !usable {
logger.Debug("Skipping unusable provider", "provider", pp.Name)
continue
}
// If we made it here we have a candidate usable provider
usableProviders = append(usableProviders, plug)
}
logger.Debug("Initial usable provider list", "usableProviders", usableProviders)
// Sort by plugin priority, higher is first
sort.SliceStable(usableProviders, func(i, j int) bool {
iPriority := usableProviders[i].Options.(*component.ProviderOptions).Priority
jPriority := usableProviders[j].Options.(*component.ProviderOptions).Priority
return iPriority > jPriority
})
logger.Debug("Priority sorted usable provider list", "usableProviders", usableProviders)
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 _, pp := range preferredProviders {
for _, up := range usableProviders {
if pp == up.Name {
logger.Debug("Using preffered provider found in usable list",
"provider", pp)
return pp, nil
}
}
}
if len(usableProviders) > 0 {
logger.Debug("Using the first provider from the usable list",
"provider", usableProviders[0])
return usableProviders[0].Name, nil
}
return "", errors.New("No default provider.")
}
// Implements core.Basis
// Returns all the registered plugins of the types specified
func (b *Basis) Plugins(types ...string) (plugins []*core.NamedPlugin, err error) {
@ -801,6 +893,10 @@ func (b *Basis) TargetIndex() (core.TargetIndex, error) {
return b.index, nil
}
func (b *Basis) Vagrantfile() (core.Vagrantfile, error) {
return b.vagrantfile, nil
}
// Returns the list of all known components
func (b *Basis) Components(ctx context.Context) ([]*Component, error) {
return b.components(b.ctx)

View File

@ -102,7 +102,7 @@ module Vagrant
end
def default_provider(**opts)
client.respond_to?(:default_provider) && client.default_provider(opts)
client.default_provider(**opts)
end
# Gets a target (machine) by name

View File

@ -660,6 +660,9 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
add_message "hashicorp.vagrant.sdk.Basis.ResourceIdResponse" do
optional :resource_id, :string, 1
end
add_message "hashicorp.vagrant.sdk.Basis.DefaultProviderResponse" do
optional :provider_name, :string, 1
end
add_message "hashicorp.vagrant.sdk.Target" do
end
add_message "hashicorp.vagrant.sdk.Target.ResourceIdResponse" do
@ -1164,6 +1167,7 @@ module Hashicorp
Ref::Machine = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.Ref.Machine").msgclass
Basis = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.Basis").msgclass
Basis::ResourceIdResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.Basis.ResourceIdResponse").msgclass
Basis::DefaultProviderResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.Basis.DefaultProviderResponse").msgclass
Target = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.Target").msgclass
Target::ResourceIdResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.Target.ResourceIdResponse").msgclass
Target::RecordResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.Target.RecordResponse").msgclass

View File

@ -356,14 +356,16 @@ module Hashicorp
self.unmarshal_class_method = :decode
self.service_name = 'hashicorp.vagrant.sdk.BasisService'
rpc :Boxes, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::BoxCollection
rpc :CWD, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::Path
rpc :DataDir, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::DataDir::Basis
rpc :DefaultPrivateKey, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::Path
rpc :UI, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::TerminalUI
rpc :DefaultProvider, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Basis::DefaultProviderResponse
rpc :Host, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::Host
rpc :Boxes, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::BoxCollection
rpc :TargetIndex, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::TargetIndex
rpc :ResourceId, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Basis::ResourceIdResponse
rpc :TargetIndex, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::TargetIndex
rpc :Vagrantfile, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::Vagrantfile
rpc :UI, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::TerminalUI
rpc :Seed, ::Hashicorp::Vagrant::Sdk::Args::Seeds, ::Google::Protobuf::Empty
rpc :Seeds, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::Args::Seeds
end

View File

@ -30,6 +30,11 @@ module VagrantPlugins
resp.path
end
def default_provider(**opts)
resp = client.default_provider(Empty.new)
resp.provider_name.to_sym
end
def target_index
TargetIndex.load(
client.target_index(Empty.new),
@ -37,6 +42,10 @@ module VagrantPlugins
)
end
def vagrantfile
client.vagrantfile(Empty.new).to_ruby
end
# @return [Terminal]
def ui
begin