Use Component Options to implement ProviderOptions

* Populates ComponentOptions into plugin structs
* Maps options for legacy Provider Plugins into PluginOptions
* Demos use of PluginOptions in a stub provider
* Honors plugin priority and defaultable settings
This commit is contained in:
Paul Hinze 2022-06-03 16:26:24 -05:00
parent 7341d41c01
commit 8dbe72a5a0
No known key found for this signature in database
GPG Key ID: B69DEDF2D55501C0
13 changed files with 248 additions and 119 deletions

View File

@ -2,9 +2,11 @@ package myplugin
import (
sdk "github.com/hashicorp/vagrant-plugin-sdk"
"github.com/hashicorp/vagrant-plugin-sdk/component"
"github.com/hashicorp/vagrant/builtin/myplugin/command"
communincator "github.com/hashicorp/vagrant/builtin/myplugin/communicator"
"github.com/hashicorp/vagrant/builtin/myplugin/communicator"
"github.com/hashicorp/vagrant/builtin/myplugin/host"
"github.com/hashicorp/vagrant/builtin/myplugin/provider"
"github.com/hashicorp/vagrant/builtin/myplugin/push"
)
@ -19,9 +21,12 @@ var CommandOptions = []sdk.Option{
// &Provider{},
&command.Command{},
&host.AlwaysTrueHost{},
&communincator.DummyCommunicator{},
&communicator.DummyCommunicator{},
&push.Encouragement{},
),
sdk.WithComponent(&provider.Happy{}, &component.ProviderOptions{
Priority: 100,
}),
sdk.WithMappers(StructToCommunincatorOptions),
sdk.WithName("myplugin"),
}

View File

@ -1,75 +0,0 @@
package myplugin
// import (
// "context"
// "github.com/hashicorp/vagrant-plugin-sdk/component"
// "github.com/hashicorp/vagrant-plugin-sdk/docs"
// "github.com/hashicorp/vagrant-plugin-sdk/multistep"
// pb "github.com/hashicorp/vagrant/builtin/myplugin/proto"
// )
// type ProviderConfig struct {
// }
// // Provider is the Provider implementation for myplugin.
// type Provider struct {
// config ProviderConfig
// }
// // Config implements Configurable
// func (p *Provider) Config() (interface{}, error) {
// return &p.config, nil
// }
// func (b *Provider) Documentation() (*docs.Documentation, error) {
// doc, err := docs.New(docs.FromConfig(&ProviderConfig{}))
// if err != nil {
// return nil, err
// }
// return doc, nil
// }
// // UsableFunc implements component.Provider
// func (p *Provider) UsableFunc() interface{} {
// return p.Usable
// }
// // InstalledFunc implements component.Provider
// func (p *Provider) InstalledFunc() interface{} {
// return p.Installed
// }
// // InitFunc implements component.Provider
// func (p *Provider) InitFunc() interface{} {
// return p.Init
// }
// // ActionUpFunc implements component.Provider
// func (p *Provider) ActionUpFunc() interface{} {
// return p.ActionUp
// }
// // TODO
// func (p *Provider) Usable() (bool, error) {
// return true, nil
// }
// func (p *Provider) Installed(context.Context) (bool, error) {
// return true, nil
// }
// // TODO
// func (p *Provider) Init() (bool, error) {
// return true, nil
// }
// // TODO: Take an implementation of core.Machine as an input
// func (c *Provider) ActionUp(ctx context.Context, statebag *multistep.BasicStateBag) (*pb.UpResult, error) {
// return &pb.UpResult{}, nil
// }
// var (
// _ component.Provider = (*Provider)(nil)
// _ component.Configurable = (*Provider)(nil)
// )

View File

@ -0,0 +1,96 @@
package provider
import (
"context"
"github.com/hashicorp/vagrant-plugin-sdk/component"
"github.com/hashicorp/vagrant-plugin-sdk/core"
)
// Happy is a provider that is just happy to be backing your vagrant VMs.
type Happy struct{}
func (p *Happy) Action(name string, args ...interface{}) error {
return nil
}
// ActionFunc implements component.Provider
func (h *Happy) ActionFunc(actionName string) interface{} {
return h.Action
}
func (h *Happy) Capability(name string, args ...interface{}) (interface{}, error) {
return nil, nil
}
// CapabilityFunc implements component.Provider
func (h *Happy) CapabilityFunc(name string) interface{} {
return h.Capability
}
func (h *Happy) HasCapability(n *component.NamedCapability) bool {
return false
}
// HasCapabilityFunc implements component.Provicer
func (h *Happy) HasCapabilityFunc() interface{} {
return h.HasCapability
}
func (h *Happy) MachineIdChanged() error {
return nil
}
// MachineIdChangedFunc implements component.Provicer
func (h *Happy) MachineIdChangedFunc() interface{} {
return h.MachineIdChanged
}
func (h *Happy) Installed(context.Context) (bool, error) {
return true, nil
}
// InstalledFunc implements component.Provider
func (h *Happy) InstalledFunc() interface{} {
return h.Installed
}
func (h *Happy) Init() (bool, error) {
return true, nil
}
// InitFunc implements component.Provider
func (h *Happy) InitFunc() interface{} {
return h.Init
}
func (h *Happy) SshInfo() (*core.SshInfo, error) {
return nil, nil
}
// SshInfoFunc implements component.Provider
func (h *Happy) SshInfoFunc() interface{} {
return h.SshInfo
}
func (h *Happy) State() (*core.MachineState, error) {
return nil, nil
}
// StateFunc implements component.Provider
func (h *Happy) StateFunc() interface{} {
return h.State
}
func (h *Happy) Usable() (bool, error) {
return false, nil
}
// UsableFunc implements component.Provider
func (h *Happy) UsableFunc() interface{} {
return h.Usable
}
var (
_ component.Provider = (*Happy)(nil)
)

View File

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"os"
"sort"
"strings"
"sync"
@ -140,26 +141,33 @@ func (p *Project) DefaultProvider(opts *core.DefaultProviderOptions) (string, er
}
}
usableProviders := []string{}
usableProviders := []*core.NamedPlugin{}
pluginProviders, err := p.basis.plugins.ListPlugins("provider")
if err != nil {
return "", err
}
for _, pp := range pluginProviders {
logger.Debug("considering plugin", "provider", pp.Name)
// Skip excluded providers
if opts.IsExcluded(pp.Name) {
logger.Debug("skipping excluded provider", "provider", pp.Name)
continue
}
// TODO: how to check for defaultable?
plug, err := p.basis.plugins.GetPlugin(pp.Name, pp.Type)
if err != nil {
return "", err
}
plugOpts := plug.Options.(*component.ProviderOptions)
if !plugOpts.Defaultable {
logger.Debug("skipping non-defaultable provider", "provider", pp.Name)
}
// 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 {
@ -171,19 +179,25 @@ func (p *Project) DefaultProvider(opts *core.DefaultProviderOptions) (string, er
}
// If we made it here we have a candidate usable provider
usableProviders = append(usableProviders, pp.Name)
usableProviders = append(usableProviders, plug)
}
logger.Debug("Initial usable provider list", "usableProviders", usableProviders)
// TODO: how to get and sort by provider priority?
// 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)
// 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 {
if u.Name == defaultProvider {
logger.Debug("Using default provider as it was found in usable list",
"provider", u)
return u, nil
return u.Name, nil
}
}
@ -203,7 +217,7 @@ func (p *Project) DefaultProvider(opts *core.DefaultProviderOptions) (string, er
for _, cp := range configProviders {
for _, up := range usableProviders {
if cp == up {
if cp == up.Name {
for _, pp := range preferredProviders {
if cp == pp {
logger.Debug("Using preferred provider detected in configuration and usable",
@ -221,7 +235,7 @@ func (p *Project) DefaultProvider(opts *core.DefaultProviderOptions) (string, er
// be chosen on Mac this way. It must be both configured and usable.
for _, cp := range configProviders {
for _, up := range usableProviders {
if cp == up {
if cp == up.Name {
logger.Debug("Using provider detected in configuration and usable",
"provider", cp)
return cp, nil
@ -233,7 +247,7 @@ func (p *Project) DefaultProvider(opts *core.DefaultProviderOptions) (string, er
// first plugin that reports it is usable.
for _, pp := range preferredProviders {
for _, up := range usableProviders {
if pp == up {
if pp == up.Name {
logger.Debug("Using preffered provider found in usable list",
"provider", pp)
return pp, nil
@ -250,7 +264,7 @@ func (p *Project) DefaultProvider(opts *core.DefaultProviderOptions) (string, er
if len(usableProviders) > 0 {
logger.Debug("Using the first provider from the usable list",
"provider", usableProviders[0])
return usableProviders[0], nil
return usableProviders[0].Name, nil
}
return "", errors.New("No default provider.")

View File

@ -98,12 +98,18 @@ func Factory(
"mappers", mappers,
)
log.Info("plugin components and options",
"components", info.ComponentTypes(),
"options", info.ComponentOptions(),
)
p = &Plugin{
Builtin: false,
Client: rpcClient,
Location: cmd.Path,
Name: info.Name(),
Types: info.ComponentTypes(),
Options: info.ComponentOptions(),
Mappers: mappers,
cleaner: cleanup.New(),
logger: nlog.Named(info.Name()),
@ -136,14 +142,20 @@ func RubyFactory(
rubyClient plugin.ClientProtocol,
name string,
typ component.Type,
optsProto interface{},
) PluginRegistration {
return func(log hclog.Logger) (*Plugin, error) {
options, err := component.UnmarshalOptionsProto(typ, optsProto)
if err != nil {
return nil, err
}
return &Plugin{
Builtin: false,
Client: rubyClient,
Location: "ruby-runtime",
Name: name,
Types: []component.Type{typ},
Options: map[component.Type]interface{}{typ: options},
cleaner: cleanup.New(),
logger: log.ResetNamed(
fmt.Sprintf("vagrant.legacy-plugin.%s.%s", strings.ToLower(typ.String()), name),
@ -164,6 +176,9 @@ type Instance struct {
// Component is the dispensed component
Component interface{}
// Options for component type, see PluginInfo.ComponentOptions
Options interface{}
// Mappers is the list of mappers that this plugin is providing.
Mappers []*argmapper.Func

View File

@ -149,7 +149,7 @@ func (m *Manager) LoadLegacyPlugins(
"type", p.Type,
)
if err = m.register(RubyFactory(r, p.Name, component.Type(p.Type))); err != nil {
if err = m.register(RubyFactory(r, p.Name, component.Type(p.Type), p.Options)); err != nil {
return
}
}
@ -388,7 +388,9 @@ func (m *Manager) Close() (err error) {
return
}
// Implements core.PluginManager
// Implements core.PluginManager. Note this returns a slice of core.NamedPlugin
// with only the Type and Name fields populated. To get a NamedPlugin with
// instance of the plugin you need to call GetPlugin.
func (m *Manager) ListPlugins(typeNames ...string) ([]*core.NamedPlugin, error) {
result := []*core.NamedPlugin{}
for _, n := range typeNames {
@ -426,9 +428,10 @@ func (m *Manager) GetPlugin(name, typ string) (*core.NamedPlugin, error) {
return nil, err
}
v := &core.NamedPlugin{
Name: name,
Type: t.String(),
Plugin: c.Component,
Name: name,
Type: t.String(),
Plugin: c.Component,
Options: c.Options,
}
m.cache.Register(cid, v)

View File

@ -37,13 +37,14 @@ var (
)
type Plugin struct {
Builtin bool // Flags if this plugin is a builtin plugin
Cache cacher.Cache // Cache for plugins to utilize in mappers
Client plugin.ClientProtocol // Client connection to plugin
Location string // Location of the plugin (generally path to binary)
Mappers []*argmapper.Func // Plugin specific mappers
Name string // Name of the plugin
Types []component.Type // Component types supported by this plugin
Builtin bool // Flags if this plugin is a builtin plugin
Cache cacher.Cache // Cache for plugins to utilize in mappers
Client plugin.ClientProtocol // Client connection to plugin
Location string // Location of the plugin (generally path to binary)
Mappers []*argmapper.Func // Plugin specific mappers
Name string // Name of the plugin
Types []component.Type // Component types supported by this plugin
Options map[component.Type]interface{} // Options for supported components
cleaner cleanup.Cleanup // Cleanup tasks to perform on closing
logger hclog.Logger
@ -166,6 +167,7 @@ func (p *Plugin) InstanceOf(
Mappers: p.Mappers,
Name: p.Name,
Type: c,
Options: p.Options[c],
}
// Be sure the instance is close when the plugin is closed

View File

@ -11,7 +11,7 @@ import (
_ "google.golang.org/genproto/googleapis/rpc/errdetails"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
_ "google.golang.org/protobuf/types/known/anypb"
anypb "google.golang.org/protobuf/types/known/anypb"
emptypb "google.golang.org/protobuf/types/known/emptypb"
reflect "reflect"
sync "sync"
@ -168,6 +168,8 @@ type Plugin struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
// type of the plugin
Type Plugin_Type `protobuf:"varint,2,opt,name=type,proto3,enum=hashicorp.vagrant.Plugin_Type" json:"type,omitempty"`
// options for the plugin
Options *anypb.Any `protobuf:"bytes,3,opt,name=options,proto3" json:"options,omitempty"`
}
func (x *Plugin) Reset() {
@ -216,6 +218,13 @@ func (x *Plugin) GetType() Plugin_Type {
return Plugin_UNKNOWN
}
func (x *Plugin) GetOptions() *anypb.Any {
if x != nil {
return x.Options
}
return nil
}
type ParseVagrantfileRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -329,12 +338,15 @@ var file_proto_ruby_vagrant_ruby_server_proto_rawDesc = []byte{
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73,
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f,
0x72, 0x70, 0x2e, 0x76, 0x61, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69,
0x6e, 0x52, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x22, 0xb0, 0x02, 0x0a, 0x06, 0x50,
0x6e, 0x52, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x22, 0xe0, 0x02, 0x0a, 0x06, 0x50,
0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x04, 0x74, 0x79, 0x70,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63,
0x6f, 0x72, 0x70, 0x2e, 0x76, 0x61, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x2e, 0x50, 0x6c, 0x75, 0x67,
0x69, 0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xdd, 0x01,
0x69, 0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2e, 0x0a,
0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xdd, 0x01,
0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57,
0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4f, 0x4d, 0x4d, 0x41, 0x4e, 0x44, 0x10, 0x01,
0x12, 0x10, 0x0a, 0x0c, 0x43, 0x4f, 0x4d, 0x4d, 0x55, 0x4e, 0x49, 0x43, 0x41, 0x54, 0x4f, 0x52,
@ -398,22 +410,24 @@ var file_proto_ruby_vagrant_ruby_server_proto_goTypes = []interface{}{
(*Plugin)(nil), // 2: hashicorp.vagrant.Plugin
(*ParseVagrantfileRequest)(nil), // 3: hashicorp.vagrant.ParseVagrantfileRequest
(*ParseVagrantfileResponse)(nil), // 4: hashicorp.vagrant.ParseVagrantfileResponse
(*vagrant_plugin_sdk.Vagrantfile_Vagrantfile)(nil), // 5: hashicorp.vagrant.sdk.Vagrantfile.Vagrantfile
(*emptypb.Empty)(nil), // 6: google.protobuf.Empty
(*anypb.Any)(nil), // 5: google.protobuf.Any
(*vagrant_plugin_sdk.Vagrantfile_Vagrantfile)(nil), // 6: hashicorp.vagrant.sdk.Vagrantfile.Vagrantfile
(*emptypb.Empty)(nil), // 7: google.protobuf.Empty
}
var file_proto_ruby_vagrant_ruby_server_proto_depIdxs = []int32{
2, // 0: hashicorp.vagrant.GetPluginsResponse.plugins:type_name -> hashicorp.vagrant.Plugin
0, // 1: hashicorp.vagrant.Plugin.type:type_name -> hashicorp.vagrant.Plugin.Type
5, // 2: hashicorp.vagrant.ParseVagrantfileResponse.vagrantfile:type_name -> hashicorp.vagrant.sdk.Vagrantfile.Vagrantfile
6, // 3: hashicorp.vagrant.RubyVagrant.GetPlugins:input_type -> google.protobuf.Empty
3, // 4: hashicorp.vagrant.RubyVagrant.ParseVagrantfile:input_type -> hashicorp.vagrant.ParseVagrantfileRequest
1, // 5: hashicorp.vagrant.RubyVagrant.GetPlugins:output_type -> hashicorp.vagrant.GetPluginsResponse
4, // 6: hashicorp.vagrant.RubyVagrant.ParseVagrantfile:output_type -> hashicorp.vagrant.ParseVagrantfileResponse
5, // [5:7] is the sub-list for method output_type
3, // [3:5] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
5, // 2: hashicorp.vagrant.Plugin.options:type_name -> google.protobuf.Any
6, // 3: hashicorp.vagrant.ParseVagrantfileResponse.vagrantfile:type_name -> hashicorp.vagrant.sdk.Vagrantfile.Vagrantfile
7, // 4: hashicorp.vagrant.RubyVagrant.GetPlugins:input_type -> google.protobuf.Empty
3, // 5: hashicorp.vagrant.RubyVagrant.ParseVagrantfile:input_type -> hashicorp.vagrant.ParseVagrantfileRequest
1, // 6: hashicorp.vagrant.RubyVagrant.GetPlugins:output_type -> hashicorp.vagrant.GetPluginsResponse
4, // 7: hashicorp.vagrant.RubyVagrant.ParseVagrantfile:output_type -> hashicorp.vagrant.ParseVagrantfileResponse
6, // [6:8] is the sub-list for method output_type
4, // [4:6] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_proto_ruby_vagrant_ruby_server_proto_init() }

View File

@ -32,6 +32,9 @@ message Plugin {
// type of the plugin
Type type = 2;
// options for the plugin
google.protobuf.Any options = 3;
// Supported plugin types, the values here MUST match the enum values
// in the Go sdk/component package exactly. A test in internal/server
// validates this.

View File

@ -15,6 +15,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
add_message "hashicorp.vagrant.Plugin" do
optional :name, :string, 1
optional :type, :enum, 2, "hashicorp.vagrant.Plugin.Type"
optional :options, :message, 3, "google.protobuf.Any"
end
add_enum "hashicorp.vagrant.Plugin.Type" do
value :UNKNOWN, 0

View File

@ -440,6 +440,15 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
add_message "hashicorp.vagrant.sdk.PluginInfo.Name" do
optional :name, :string, 1
end
add_message "hashicorp.vagrant.sdk.PluginInfo.ComponentOptionsMap" do
map :options, :uint32, :message, 1, "google.protobuf.Any"
end
add_message "hashicorp.vagrant.sdk.PluginInfo.ProviderOptions" do
optional :priority, :int32, 1
optional :parallel, :bool, 2
optional :box_optional, :bool, 3
optional :defaultable, :bool, 4
end
add_message "hashicorp.vagrant.sdk.PluginManager" do
end
add_message "hashicorp.vagrant.sdk.PluginManager.PluginsRequest" do
@ -1056,6 +1065,8 @@ module Hashicorp
PluginInfo = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginInfo").msgclass
PluginInfo::ComponentList = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginInfo.ComponentList").msgclass
PluginInfo::Name = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginInfo.Name").msgclass
PluginInfo::ComponentOptionsMap = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginInfo.ComponentOptionsMap").msgclass
PluginInfo::ProviderOptions = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginInfo.ProviderOptions").msgclass
PluginManager = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginManager").msgclass
PluginManager::PluginsRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginManager.PluginsRequest").msgclass
PluginManager::PluginsResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hashicorp.vagrant.sdk.PluginManager.PluginsResponse").msgclass

View File

@ -82,6 +82,7 @@ module Hashicorp
self.service_name = 'hashicorp.vagrant.sdk.PluginInfoService'
rpc :ComponentTypes, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::PluginInfo::ComponentList
rpc :ComponentOptions, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::PluginInfo::ComponentOptionsMap
rpc :Name, ::Google::Protobuf::Empty, ::Hashicorp::Vagrant::Sdk::PluginInfo::Name
end

View File

@ -22,7 +22,13 @@ module VagrantPlugins
[:pushes, :PUSH],
[:synced_folders, :SYNCEDFOLDER]].map do |method, const|
plugin_manager.send(method).map do |k, v|
Hashicorp::Vagrant::Plugin.new(name: k, type: Hashicorp::Vagrant::Plugin::Type.const_get(const))
Hashicorp::Vagrant::Plugin.new(
name: k,
type: Hashicorp::Vagrant::Plugin::Type.const_get(const),
options: Google::Protobuf::Any.pack(
_convert_options_to_proto(const, v)
)
)
end
end.flatten
Hashicorp::Vagrant::GetPluginsResponse.new(
@ -79,6 +85,39 @@ module VagrantPlugins
vagrantfile: vagrantfile
)
end
def _convert_options_to_proto(type, class_or_tuple_with_class_and_options)
case type
when :COMMAND
# _, command_options = class_or_tuple_with_class_and_options
return Google::Protobuf::Empty.new
when :COMMUNICATOR
# No options for communicators
return Google::Protobuf::Empty.new
when :GUEST
# No options for guests
return Google::Protobuf::Empty.new
when :HOST
# _, parent = class_or_tuple_with_class_and_options
return Google::Protobuf::Empty.new
when :PROVIDER
_, popts = class_or_tuple_with_class_and_options
return SDK::PluginInfo::ProviderOptions.new(
priority: popts[:priority],
parallel: !!popts[:parallel],
box_optional: !!popts[:box_optional],
defaultable: !!popts[:defaultable],
)
when :PROVISIONER
return Google::Protobuf::Empty.new
when :PUSH
return Google::Protobuf::Empty.new
when :SYNCEDFOLDER
return Google::Protobuf::Empty.new
else
raise "Cannot convert options for unknown component type: #{type}"
end
end
end
end
end