Adding test coverage

This commit is contained in:
Chris Roberts 2019-03-05 10:42:56 -08:00
parent 8aa0fd9445
commit 9499553706
39 changed files with 3703 additions and 470 deletions

View File

@ -11,168 +11,148 @@ import (
//export GuestCapabilities //export GuestCapabilities
func GuestCapabilities(pluginName, pluginType *C.char) *C.char { func GuestCapabilities(pluginName, pluginType *C.char) *C.char {
r := vagrant.Response{} r := &Response{}
p, err := getGuestCapsPlugin(pluginName, pluginType) i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
}
p, ok := i.(*plugin.RemoteGuestCapabilities)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
} }
r.Result, r.Error = p.GuestCapabilities.GuestCapabilities() r.Result, r.Error = p.GuestCapabilities.GuestCapabilities()
return C.CString(r.Dump()) return r.Dump()
} }
//export GuestCapability //export GuestCapability
func GuestCapability(pluginName, pluginType, cname, cplatform, cargs, cmachine *C.char) *C.char { func GuestCapability(pluginName, pluginType, cname, cplatform, cargs, cmachine *C.char) *C.char {
r := vagrant.Response{} r := &Response{}
p, err := getGuestCapsPlugin(pluginName, pluginType) i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
machine, err := vagrant.LoadMachine(C.GoString(cmachine), nil) p, ok := i.(*plugin.RemoteGuestCapabilities)
if !ok {
r.Error = errors.New("Failed to load requested plugin")
return r.Dump()
}
machine, err := vagrant.LoadMachine(to_gs(cmachine), nil)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
var args interface{} var args interface{}
err = json.Unmarshal([]byte(C.GoString(cargs)), &args) err = json.Unmarshal([]byte(to_gs(cargs)), &args)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
cap := &vagrant.SystemCapability{ cap := &vagrant.SystemCapability{
Name: C.GoString(cname), Name: to_gs(cname),
Platform: C.GoString(cplatform)} Platform: to_gs(cplatform)}
r.Result, r.Error = p.GuestCapabilities.GuestCapability(cap, args, machine) r.Result, r.Error = p.GuestCapabilities.GuestCapability(cap, args, machine)
return C.CString(r.Dump()) return r.Dump()
} }
//export HostCapabilities //export HostCapabilities
func HostCapabilities(pluginName, pluginType *C.char) *C.char { func HostCapabilities(pluginName, pluginType *C.char) *C.char {
r := vagrant.Response{} r := &Response{}
p, err := getHostCapsPlugin(pluginName, pluginType) i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
p, ok := i.(*plugin.RemoteHostCapabilities)
if !ok {
r.Error = errors.New("Failed to load requested plugin")
return r.Dump()
}
r.Result, r.Error = p.HostCapabilities.HostCapabilities() r.Result, r.Error = p.HostCapabilities.HostCapabilities()
return C.CString(r.Dump()) return r.Dump()
} }
//export HostCapability //export HostCapability
func HostCapability(pluginName, pluginType, cname, cplatform, cargs, cenv *C.char) *C.char { func HostCapability(pluginName, pluginType, cname, cplatform, cargs, cenv *C.char) *C.char {
r := vagrant.Response{} r := &Response{}
p, err := getHostCapsPlugin(pluginName, pluginType) i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
env, err := vagrant.LoadEnvironment(C.GoString(cenv), nil) p, ok := i.(*plugin.RemoteHostCapabilities)
if !ok {
r.Error = errors.New("Failed to load requested plugin")
return r.Dump()
}
env, err := vagrant.LoadEnvironment(to_gs(cenv), nil)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
var args interface{} var args interface{}
err = json.Unmarshal([]byte(C.GoString(cargs)), &args) err = json.Unmarshal([]byte(to_gs(cargs)), &args)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
cap := &vagrant.SystemCapability{ cap := &vagrant.SystemCapability{
Name: C.GoString(cname), Name: to_gs(cname),
Platform: C.GoString(cplatform)} Platform: to_gs(cplatform)}
r.Result, r.Error = p.HostCapabilities.HostCapability(cap, args, env) r.Result, r.Error = p.HostCapabilities.HostCapability(cap, args, env)
return C.CString(r.Dump()) return r.Dump()
} }
//export ProviderCapabilities //export ProviderCapabilities
func ProviderCapabilities(pluginName, pluginType *C.char) *C.char { func ProviderCapabilities(pluginName, pluginType *C.char) *C.char {
r := vagrant.Response{} r := &Response{}
p, err := getProviderCapsPlugin(pluginName, pluginType) i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
p, ok := i.(*plugin.RemoteProviderCapabilities)
if !ok {
r.Error = errors.New("Failed to load requested plugin")
return r.Dump()
}
r.Result, r.Error = p.ProviderCapabilities.ProviderCapabilities() r.Result, r.Error = p.ProviderCapabilities.ProviderCapabilities()
return C.CString(r.Dump()) return r.Dump()
} }
//export ProviderCapability //export ProviderCapability
func ProviderCapability(pluginName, pluginType, cname, cprovider, cargs, cmach *C.char) *C.char { func ProviderCapability(pluginName, pluginType, cname, cprovider, cargs, cmach *C.char) *C.char {
r := vagrant.Response{} r := &Response{}
p, err := getProviderCapsPlugin(pluginName, pluginType) i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
m, err := vagrant.LoadMachine(C.GoString(cmach), nil) p, ok := i.(*plugin.RemoteProviderCapabilities)
if !ok {
r.Error = errors.New("Failed to load requested plugin")
return r.Dump()
}
m, err := vagrant.LoadMachine(to_gs(cmach), nil)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
var args interface{} var args interface{}
err = json.Unmarshal([]byte(C.GoString(cargs)), &args) err = json.Unmarshal([]byte(to_gs(cargs)), &args)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
cap := &vagrant.ProviderCapability{ cap := &vagrant.ProviderCapability{
Name: C.GoString(cname), Name: to_gs(cname),
Provider: C.GoString(cprovider)} Provider: to_gs(cprovider)}
r.Result, r.Error = p.ProviderCapabilities.ProviderCapability(cap, args, m) r.Result, r.Error = p.ProviderCapabilities.ProviderCapability(cap, args, m)
return C.CString(r.Dump()) return r.Dump()
}
func getProviderCapsPlugin(pluginName, pluginType *C.char) (c *plugin.RemoteProviderCapabilities, err error) {
pname := C.GoString(pluginName)
ptype := C.GoString(pluginType)
if ptype == "provider" {
p, ok := Plugins.Providers[pname]
if ok {
c = &plugin.RemoteProviderCapabilities{
Client: p.Client,
ProviderCapabilities: p.Provider}
}
}
if c == nil {
err = errors.New("Failed to locate requested plugin")
}
return
}
func getGuestCapsPlugin(pluginName, pluginType *C.char) (c *plugin.RemoteGuestCapabilities, err error) {
pname := C.GoString(pluginName)
ptype := C.GoString(pluginType)
if ptype == "provider" {
p, ok := Plugins.Providers[pname]
if ok {
c = &plugin.RemoteGuestCapabilities{
Client: p.Client,
GuestCapabilities: p.Provider}
}
}
if c == nil {
err = errors.New("Failed to locate requested plugin")
}
return
}
func getHostCapsPlugin(pluginName, pluginType *C.char) (c *plugin.RemoteHostCapabilities, err error) {
pname := C.GoString(pluginName)
ptype := C.GoString(pluginType)
if ptype == "provider" {
p, ok := Plugins.Providers[pname]
if ok {
c = &plugin.RemoteHostCapabilities{
Client: p.Client,
HostCapabilities: p.Provider}
}
}
if c == nil {
err = errors.New("Failed to locate requested plugin")
}
return
} }

View File

@ -0,0 +1,414 @@
package main
import (
"encoding/json"
"testing"
"github.com/hashicorp/go-plugin"
vplugin "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin"
)
func TestCapabilities_GuestCapabilities(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &vplugin.GuestCapabilitiesPlugin{Impl: &vplugin.MockGuestCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.GuestCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteGuestCapabilities{
GuestCapabilities: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
result := GuestCapabilities(nil, nil)
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
caps, ok := resp.Result.([]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
cap, ok := caps[0].(map[string]interface{})
if !ok {
t.Fatalf("bad %#v", caps[0])
}
if cap["name"] != "test_cap" {
t.Errorf("%s != test_cap", cap["name"])
}
if cap["platform"] != "testOS" {
t.Errorf("%s != testOS", cap["platform"])
}
}
func TestCapabilities_GuestCapability(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &vplugin.GuestCapabilitiesPlugin{Impl: &vplugin.MockGuestCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.GuestCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteGuestCapabilities{
GuestCapabilities: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
a, err := json.Marshal([]string{"test_arg", "other_arg"})
if err != nil {
t.Fatalf("err: %s", err)
}
args := string(a)
result := GuestCapability(nil, nil, to_cs("test_cap"), to_cs("test_platform"), to_cs(args), to_cs("{}"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
r, ok := resp.Result.([]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if r[0] != "test_cap" {
t.Errorf("%s != test_cap", r[0])
}
if r[1] != "test_arg" {
t.Errorf("%s != test_arg", r[1])
}
}
func TestCapabilities_GuestCapability_noargs(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &vplugin.GuestCapabilitiesPlugin{Impl: &vplugin.MockGuestCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.GuestCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteGuestCapabilities{
GuestCapabilities: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
result := GuestCapability(nil, nil, to_cs("test_cap"), to_cs("test_platform"), to_cs("null"), to_cs("{}"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s - %s", err, to_gs(result))
}
r, ok := resp.Result.([]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if len(r) != 1 {
t.Errorf("%d != 1", len(r))
}
if r[0] != "test_cap" {
t.Errorf("%s != test_cap", r[0])
}
}
func TestCapabilities_HostCapabilities(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &vplugin.HostCapabilitiesPlugin{Impl: &vplugin.MockHostCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.HostCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteHostCapabilities{
HostCapabilities: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
result := HostCapabilities(nil, nil)
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
caps, ok := resp.Result.([]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
cap, ok := caps[0].(map[string]interface{})
if !ok {
t.Fatalf("bad %#v", caps[0])
}
if cap["name"] != "test_cap" {
t.Errorf("%s != test_cap", cap["name"])
}
if cap["platform"] != "testOS" {
t.Errorf("%s != testOS", cap["platform"])
}
}
func TestCapabilities_HostCapability(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &vplugin.HostCapabilitiesPlugin{Impl: &vplugin.MockHostCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.HostCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteHostCapabilities{
HostCapabilities: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
a, err := json.Marshal([]string{"test_arg", "other_arg"})
if err != nil {
t.Fatalf("err: %s", err)
}
args := string(a)
result := HostCapability(nil, nil, to_cs("test_cap"), to_cs("test_platform"), to_cs(args), to_cs("{}"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
r, ok := resp.Result.([]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if r[0] != "test_cap" {
t.Errorf("%s != test_cap", r[0])
}
if r[1] != "test_arg" {
t.Errorf("%s != test_arg", r[1])
}
}
func TestCapabilities_HostCapability_noargs(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &vplugin.HostCapabilitiesPlugin{Impl: &vplugin.MockHostCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.HostCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteHostCapabilities{
HostCapabilities: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
result := HostCapability(nil, nil, to_cs("test_cap"), to_cs("test_platform"), to_cs("null"), to_cs("{}"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s - %s", err, to_gs(result))
}
r, ok := resp.Result.([]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if len(r) != 1 {
t.Errorf("%d != 1", len(r))
}
if r[0] != "test_cap" {
t.Errorf("%s != test_cap", r[0])
}
}
func TestCapabilities_ProviderCapabilities(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &vplugin.ProviderCapabilitiesPlugin{Impl: &vplugin.MockProviderCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.ProviderCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteProviderCapabilities{
ProviderCapabilities: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
result := ProviderCapabilities(nil, nil)
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
caps, ok := resp.Result.([]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
cap, ok := caps[0].(map[string]interface{})
if !ok {
t.Fatalf("bad %#v", caps[0])
}
if cap["name"] != "test_cap" {
t.Errorf("%s != test_cap", cap["name"])
}
if cap["provider"] != "testProvider" {
t.Errorf("%s != testProvider", cap["provider"])
}
}
func TestCapabilities_ProviderCapability(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &vplugin.ProviderCapabilitiesPlugin{Impl: &vplugin.MockProviderCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.ProviderCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteProviderCapabilities{
ProviderCapabilities: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
a, err := json.Marshal([]string{"test_arg", "other_arg"})
if err != nil {
t.Fatalf("err: %s", err)
}
args := string(a)
result := ProviderCapability(nil, nil, to_cs("test_cap"), to_cs("test_provider"), to_cs(args), to_cs("{}"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
r, ok := resp.Result.([]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if r[0] != "test_cap" {
t.Errorf("%s != test_cap", r[0])
}
if r[1] != "test_arg" {
t.Errorf("%s != test_arg", r[1])
}
}
func TestCapabilities_ProviderCapability_noargs(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &vplugin.ProviderCapabilitiesPlugin{Impl: &vplugin.MockProviderCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.ProviderCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteProviderCapabilities{
ProviderCapabilities: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
result := ProviderCapability(nil, nil, to_cs("test_cap"), to_cs("test_provider"), to_cs("null"), to_cs("{}"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s - %s", err, to_gs(result))
}
r, ok := resp.Result.([]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if len(r) != 1 {
t.Errorf("%d != 1", len(r))
}
if r[0] != "test_cap" {
t.Errorf("%s != test_cap", r[0])
}
}

View File

@ -4,7 +4,6 @@ import (
"C" "C"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant" "github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin" "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin"
@ -12,87 +11,87 @@ import (
//export ConfigLoad //export ConfigLoad
func ConfigLoad(pluginName, pluginType, data *C.char) *C.char { func ConfigLoad(pluginName, pluginType, data *C.char) *C.char {
r := vagrant.Response{} r := &Response{}
p, err := getConfigPlugin(pluginName, pluginType) i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
}
p, ok := i.(*plugin.RemoteConfig)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
} }
var cdata map[string]interface{} var cdata map[string]interface{}
r.Error = json.Unmarshal([]byte(C.GoString(data)), &cdata) r.Error = json.Unmarshal([]byte(to_gs(data)), &cdata)
if r.Error != nil { if r.Error != nil {
return C.CString(r.Dump()) return r.Dump()
} }
r.Result, r.Error = p.Config.ConfigLoad(cdata) r.Result, r.Error = p.Config.ConfigLoad(cdata)
return C.CString(r.Dump()) return r.Dump()
} }
//export ConfigAttributes //export ConfigAttributes
func ConfigAttributes(pluginName, pluginType *C.char) *C.char { func ConfigAttributes(pluginName, pluginType *C.char) *C.char {
r := vagrant.Response{} r := &Response{}
p, err := getConfigPlugin(pluginName, pluginType) i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
}
p, ok := i.(*plugin.RemoteConfig)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
} }
r.Result, r.Error = p.Config.ConfigAttributes() r.Result, r.Error = p.Config.ConfigAttributes()
return C.CString(r.Dump()) return r.Dump()
} }
//export ConfigValidate //export ConfigValidate
func ConfigValidate(pluginName, pluginType, data, machData *C.char) *C.char { func ConfigValidate(pluginName, pluginType, data, machData *C.char) *C.char {
var m *vagrant.Machine var m *vagrant.Machine
r := vagrant.Response{} r := &Response{}
p, err := getConfigPlugin(pluginName, pluginType) i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
}
p, ok := i.(*plugin.RemoteConfig)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
} }
var cdata map[string]interface{} var cdata map[string]interface{}
r.Error = json.Unmarshal([]byte(C.GoString(data)), &cdata) r.Error = json.Unmarshal([]byte(to_gs(data)), &cdata)
if r.Error != nil { if r.Error != nil {
return C.CString(r.Dump()) return r.Dump()
} }
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil) m, r.Error = vagrant.LoadMachine(to_gs(machData), nil)
if r.Error != nil { if r.Error != nil {
return C.CString(r.Dump()) return r.Dump()
} }
r.Result, r.Error = p.Config.ConfigValidate(cdata, m) r.Result, r.Error = p.Config.ConfigValidate(cdata, m)
return C.CString(r.Dump()) return r.Dump()
} }
//export ConfigFinalize //export ConfigFinalize
func ConfigFinalize(pluginName, pluginType, data *C.char) *C.char { func ConfigFinalize(pluginName, pluginType, data *C.char) *C.char {
r := vagrant.Response{} r := &Response{}
p, err := getConfigPlugin(pluginName, pluginType) i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
}
p, ok := i.(*plugin.RemoteConfig)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
} }
var cdata map[string]interface{} var cdata map[string]interface{}
r.Error = json.Unmarshal([]byte(C.GoString(data)), &cdata) r.Error = json.Unmarshal([]byte(to_gs(data)), &cdata)
if r.Error == nil { if r.Error == nil {
println("FINALIZE HAS VALID CONFIG")
r.Result, r.Error = p.Config.ConfigFinalize(cdata) r.Result, r.Error = p.Config.ConfigFinalize(cdata)
} }
fmt.Printf("Full result: %s\n", r.Dump()) return r.Dump()
return C.CString(r.Dump())
}
func getConfigPlugin(pluginName, pluginType *C.char) (c *plugin.RemoteConfig, err error) {
pname := C.GoString(pluginName)
ptype := C.GoString(pluginType)
if ptype == "provider" {
p, ok := Plugins.Providers[pname]
if ok {
c = &plugin.RemoteConfig{
Client: p.Client,
Config: p.Provider}
}
}
if c == nil {
err = errors.New("Failed to locate requested plugin")
}
return
} }

View File

@ -0,0 +1,203 @@
package main
import (
"encoding/json"
"testing"
"github.com/hashicorp/go-plugin"
vplugin "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin"
)
func TestConfig_Load(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"config": &vplugin.ConfigPlugin{Impl: &vplugin.MockConfig{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("config")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.Config)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteConfig{
Config: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
data := map[string]string{"test_key": "custom_val"}
s, err := json.Marshal(data)
if err != nil {
t.Fatalf("err: %s", err)
}
result := ConfigLoad(nil, nil, to_cs(string(s)))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Error != nil {
t.Fatalf("err: %s", resp.Error)
}
config, ok := resp.Result.(map[string]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if config["test_key"] != "test_val" {
t.Errorf("%s != test_val", config["test_key"])
}
if config["sent_key"] != "custom_val" {
t.Errorf("%s != custom_val", config["sent_key"])
}
}
func TestConfig_Attributes(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"config": &vplugin.ConfigPlugin{Impl: &vplugin.MockConfig{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("config")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.Config)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteConfig{
Config: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
result := ConfigAttributes(nil, nil)
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Error != nil {
t.Fatalf("err: %s", resp.Error)
}
attrs, ok := resp.Result.([]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if len(attrs) != 2 {
t.Fatalf("%d != 2", len(attrs))
}
if attrs[0] != "fubar" {
t.Errorf("%s != fubar", attrs[0])
}
if attrs[1] != "foobar" {
t.Errorf("%s != foobar", attrs[1])
}
}
func TestConfig_Validate(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"config": &vplugin.ConfigPlugin{Impl: &vplugin.MockConfig{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("config")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.Config)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteConfig{
Config: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
data := map[string]string{"test_key": "custom_val"}
s, err := json.Marshal(data)
if err != nil {
t.Fatalf("err: %s", err)
}
result := ConfigValidate(nil, nil, to_cs(string(s)), to_cs("{}"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Error != nil {
t.Fatalf("err: %s", resp.Error)
}
errs, ok := resp.Result.([]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if len(errs) != 1 {
t.Fatalf("%d != 1", len(errs))
}
if errs[0] != "test error" {
t.Errorf("%s != test error", errs[0])
}
}
func TestConfig_Finalize(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"config": &vplugin.ConfigPlugin{Impl: &vplugin.MockConfig{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("config")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.Config)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteConfig{
Config: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
data := map[string]string{"test_key": "custom_val"}
s, err := json.Marshal(data)
if err != nil {
t.Fatalf("err: %s", err)
}
result := ConfigFinalize(nil, nil, to_cs(string(s)))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Error != nil {
t.Fatalf("err: %s", resp.Error)
}
config, ok := resp.Result.(map[string]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if config["test_key"] != "custom_val-updated" {
t.Errorf("%s != custom_val-updated", config["test_key"])
}
}

View File

@ -14,7 +14,7 @@ var Plugins *plugin.VagrantPlugin
//export Setup //export Setup
func Setup(enableLogger, timestamps bool, logLevel *C.char) bool { func Setup(enableLogger, timestamps bool, logLevel *C.char) bool {
lvl := C.GoString(logLevel) lvl := to_gs(logLevel)
lopts := &hclog.LoggerOptions{Name: "vagrant"} lopts := &hclog.LoggerOptions{Name: "vagrant"}
if enableLogger { if enableLogger {
lopts.Output = os.Stderr lopts.Output = os.Stderr
@ -32,10 +32,7 @@ func Setup(enableLogger, timestamps bool, logLevel *C.char) bool {
return false return false
} }
Plugins = &plugin.VagrantPlugin{ Plugins = plugin.VagrantPluginInit()
PluginDirectories: []string{},
Providers: map[string]*plugin.RemoteProvider{},
Logger: vagrant.DefaultLogger().Named("go-plugin")}
return true return true
} }
@ -46,7 +43,7 @@ func LoadPlugins(plgpath *C.char) bool {
return false return false
} }
p := C.GoString(plgpath) p := to_gs(plgpath)
err := Plugins.LoadPlugins(p) err := Plugins.LoadPlugins(p)
if err != nil { if err != nil {
Plugins.Logger.Error("failed loading plugins", Plugins.Logger.Error("failed loading plugins",
@ -86,3 +83,13 @@ func Teardown() {
// stub required for build // stub required for build
func main() {} func main() {}
// helper to convert c string to go string
func to_gs(s *C.char) string {
return C.GoString(s)
}
// helper to convert go string to c string
func to_cs(s string) *C.char {
return C.CString(s)
}

View File

@ -4,7 +4,6 @@ import (
"C" "C"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant" "github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin" "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin"
@ -13,169 +12,176 @@ import (
//export ListProviders //export ListProviders
func ListProviders() *C.char { func ListProviders() *C.char {
list := map[string]interface{}{} list := map[string]interface{}{}
r := vagrant.Response{Result: list} r := &Response{Result: list}
if Plugins == nil { if Plugins == nil {
return C.CString(r.Dump()) return r.Dump()
} }
for n, p := range Plugins.Providers { for n, p := range Plugins.Providers {
list[n] = p.Provider.Info() list[n] = p.Provider.Info()
} }
r.Result = list r.Result = list
return C.CString(r.Dump()) return r.Dump()
} }
//export ProviderAction //export ProviderAction
func ProviderAction(providerName *C.char, actionName *C.char, machData *C.char) *C.char { func ProviderAction(providerName *C.char, actionName *C.char, machData *C.char) *C.char {
var p *plugin.RemoteProvider r := &Response{}
var m *vagrant.Machine i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r := vagrant.Response{} r.Error = err
p, r.Error = getProvider(providerName) return r.Dump()
if r.Error != nil {
return C.CString(r.Dump())
} }
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil) p, ok := i.(*plugin.RemoteProvider)
if r.Error != nil { if !ok {
return C.CString(r.Dump()) r.Error = errors.New("failed to load requested plugin")
return r.Dump()
} }
aName := C.GoString(actionName) m, err := vagrant.LoadMachine(to_gs(machData), nil)
if err != nil {
r.Error = err
return r.Dump()
}
aName := to_gs(actionName)
r.Result, r.Error = p.Provider.Action(aName, m) r.Result, r.Error = p.Provider.Action(aName, m)
return C.CString(r.Dump()) return r.Dump()
} }
//export ProviderIsInstalled //export ProviderIsInstalled
func ProviderIsInstalled(providerName *C.char, machData *C.char) *C.char { func ProviderIsInstalled(providerName *C.char, machData *C.char) *C.char {
var p *plugin.RemoteProvider r := &Response{}
var m *vagrant.Machine i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r := vagrant.Response{} r.Error = err
p, r.Error = getProvider(providerName) return r.Dump()
if r.Error != nil {
return C.CString(r.Dump())
} }
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil) p, ok := i.(*plugin.RemoteProvider)
if r.Error != nil { if !ok {
return C.CString(r.Dump()) r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
m, err := vagrant.LoadMachine(to_gs(machData), nil)
if err != nil {
r.Error = err
return r.Dump()
} }
r.Result, r.Error = p.Provider.IsInstalled(m) r.Result, r.Error = p.Provider.IsInstalled(m)
return C.CString(r.Dump()) return r.Dump()
} }
//export ProviderIsUsable //export ProviderIsUsable
func ProviderIsUsable(providerName *C.char, machData *C.char) *C.char { func ProviderIsUsable(providerName *C.char, machData *C.char) *C.char {
var p *plugin.RemoteProvider r := &Response{}
var m *vagrant.Machine i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r := vagrant.Response{} r.Error = err
p, r.Error = getProvider(providerName) return r.Dump()
if r.Error != nil {
return C.CString(r.Dump())
} }
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil) p, ok := i.(*plugin.RemoteProvider)
if r.Error != nil { if !ok {
return C.CString(r.Dump()) r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
m, err := vagrant.LoadMachine(to_gs(machData), nil)
if err != nil {
r.Error = err
return r.Dump()
} }
r.Result, r.Error = p.Provider.IsUsable(m) r.Result, r.Error = p.Provider.IsUsable(m)
return C.CString(r.Dump()) return r.Dump()
} }
//export ProviderMachineIdChanged //export ProviderMachineIdChanged
func ProviderMachineIdChanged(providerName *C.char, machData *C.char) *C.char { func ProviderMachineIdChanged(providerName *C.char, machData *C.char) *C.char {
var p *plugin.RemoteProvider r := &Response{}
var m *vagrant.Machine i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r := vagrant.Response{} r.Error = err
p, r.Error = getProvider(providerName) return r.Dump()
if r.Error != nil {
return C.CString(r.Dump())
} }
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil) p, ok := i.(*plugin.RemoteProvider)
if r.Error != nil { if !ok {
return C.CString(r.Dump()) r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
m, err := vagrant.LoadMachine(to_gs(machData), nil)
if err != nil {
r.Error = err
return r.Dump()
} }
r.Error = p.Provider.MachineIdChanged(m) r.Error = p.Provider.MachineIdChanged(m)
return C.CString(r.Dump()) return r.Dump()
} }
//export ProviderRunAction //export ProviderRunAction
func ProviderRunAction(providerName *C.char, actName *C.char, runData *C.char, machData *C.char) *C.char { func ProviderRunAction(providerName *C.char, actName *C.char, runData *C.char, machData *C.char) *C.char {
var p *plugin.RemoteProvider r := &Response{}
var m *vagrant.Machine i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r := vagrant.Response{} r.Error = err
p, r.Error = getProvider(providerName) return r.Dump()
if r.Error != nil {
return C.CString(r.Dump())
} }
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil) p, ok := i.(*plugin.RemoteProvider)
if r.Error != nil { if !ok {
return C.CString(r.Dump()) r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
m, err := vagrant.LoadMachine(to_gs(machData), nil)
if err != nil {
r.Error = err
return r.Dump()
}
aName := to_gs(actName)
var rData interface{}
err = json.Unmarshal([]byte(to_gs(runData)), &rData)
if err != nil {
r.Error = err
return r.Dump()
} }
aName := C.GoString(actName)
rData := C.GoString(runData)
r.Result, r.Error = p.Provider.RunAction(aName, rData, m) r.Result, r.Error = p.Provider.RunAction(aName, rData, m)
return C.CString(r.Dump()) return r.Dump()
} }
//export ProviderSshInfo //export ProviderSshInfo
func ProviderSshInfo(providerName *C.char, machData *C.char) *C.char { func ProviderSshInfo(providerName *C.char, machData *C.char) *C.char {
var p *plugin.RemoteProvider r := &Response{}
var m *vagrant.Machine i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r := vagrant.Response{} r.Error = err
p, r.Error = getProvider(providerName) return r.Dump()
if r.Error != nil {
return C.CString(r.Dump())
} }
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil) p, ok := i.(*plugin.RemoteProvider)
if r.Error != nil { if !ok {
return C.CString(r.Dump()) r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
m, err := vagrant.LoadMachine(to_gs(machData), nil)
if err != nil {
r.Error = err
return r.Dump()
} }
r.Result, r.Error = p.Provider.SshInfo(m) r.Result, r.Error = p.Provider.SshInfo(m)
return C.CString(r.Dump()) return r.Dump()
} }
//export ProviderState //export ProviderState
func ProviderState(providerName *C.char, machData *C.char) *C.char { func ProviderState(providerName *C.char, machData *C.char) *C.char {
var p *plugin.RemoteProvider r := &Response{}
var m *vagrant.Machine i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r := vagrant.Response{} r.Error = err
p, r.Error = getProvider(providerName) return r.Dump()
if r.Error != nil {
return C.CString(r.Dump())
} }
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil) p, ok := i.(*plugin.RemoteProvider)
if r.Error != nil { if !ok {
return C.CString(r.Dump()) r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
m, err := vagrant.LoadMachine(to_gs(machData), nil)
if err != nil {
r.Error = err
return r.Dump()
} }
r.Result, r.Error = p.Provider.State(m) r.Result, r.Error = p.Provider.State(m)
return C.CString(r.Dump()) return r.Dump()
}
func getProvider(pName *C.char) (*plugin.RemoteProvider, error) {
providerName := C.GoString(pName)
p, ok := Plugins.Providers[providerName]
if !ok {
Plugins.Logger.Error("error fetching plugin", "type", "provider",
"name", providerName, "reason", "not found")
return nil, errors.New(fmt.Sprintf(
"failed to locate provider plugin `%s`", providerName))
}
return p, nil
}
// Loads the machine data JSON string to ensure that it is
// valid JSON. Returns the converted GoString to be used
// internally
func validateMachine(machineData *C.char) (string, error) {
mData := C.GoString(machineData)
Plugins.Logger.Debug("received machine info", "data", mData)
err := json.Unmarshal([]byte(mData), &vagrant.Machine{})
if err != nil {
fmt.Printf("Error: %s\n", err)
err = errors.New(fmt.Sprintf(
"failed to load vagrant environment information - %s", err))
}
return mData, err
} }

View File

@ -0,0 +1,320 @@
package main
import (
"encoding/json"
"testing"
"github.com/hashicorp/go-plugin"
vplugin "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin"
)
func TestProvider_ListProviders(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &vplugin.ProviderPlugin{Impl: &vplugin.MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteProvider{
Provider: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.Providers[impl.Name()] = p
result := ListProviders()
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Error != nil {
t.Fatalf("err: %s", err)
}
r, ok := resp.Result.(map[string]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if r["mock_provider"] == nil {
t.Fatalf("bad result")
}
i, ok := r["mock_provider"].(map[string]interface{})
if !ok {
t.Fatalf("bad %#v", r["mock_provider"])
}
if i["description"] != "Custom" {
t.Errorf("%s != Custom", i["description"])
}
if i["priority"] != 10.0 {
t.Errorf("%d != 10", i["priority"])
}
}
func TestProvider_ProviderAction(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &vplugin.ProviderPlugin{Impl: &vplugin.MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteProvider{
Provider: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
result := ProviderAction(nil, to_cs("valid"), to_cs("{}"))
resp, err := LoadResponse(result)
if resp.Error != nil {
t.Fatalf("err: %s", resp.Error)
}
r := resp.Result.([]interface{})
if r[0] != "self::DoTask" {
t.Errorf("%s != self::DoTask", r[0])
}
}
func TestProvider_ProviderIsInstalled(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &vplugin.ProviderPlugin{Impl: &vplugin.MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteProvider{
Provider: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
result := ProviderIsInstalled(nil, to_cs("{}"))
resp, err := LoadResponse(result)
if resp.Error != nil {
t.Fatalf("err: %s", resp.Error)
}
if !resp.Result.(bool) {
t.Errorf("bad result")
}
}
func TestProvider_ProviderIsUsable(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &vplugin.ProviderPlugin{Impl: &vplugin.MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteProvider{
Provider: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
result := ProviderIsUsable(nil, to_cs("{}"))
resp, err := LoadResponse(result)
if resp.Error != nil {
t.Fatalf("err: %s", resp.Error)
}
if !resp.Result.(bool) {
t.Errorf("bad result")
}
}
func TestProvider_ProviderMachineIdChanged(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &vplugin.ProviderPlugin{Impl: &vplugin.MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteProvider{
Provider: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
result := ProviderMachineIdChanged(nil, to_cs("{}"))
resp, err := LoadResponse(result)
if resp.Error != nil {
t.Fatalf("err: %s", resp.Error)
}
}
func TestProvider_ProviderRunAction(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &vplugin.ProviderPlugin{Impl: &vplugin.MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteProvider{
Provider: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
a, err := json.Marshal([]string{"test_arg"})
args := string(a)
result := ProviderRunAction(nil, to_cs("valid"), to_cs(args), to_cs("{}"))
resp, err := LoadResponse(result)
if resp.Error != nil {
t.Fatalf("err: %s", err)
}
r, ok := resp.Result.([]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if r[0] != "valid" {
t.Errorf("%s != valid", r[0])
}
if r[1] != "test_arg" {
t.Errorf("%s != test_arg", r[1])
}
}
func TestProvider_ProviderSshInfo(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &vplugin.ProviderPlugin{Impl: &vplugin.MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteProvider{
Provider: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
result := ProviderSshInfo(nil, to_cs("{}"))
resp, err := LoadResponse(result)
if resp.Error != nil {
t.Fatalf("err: %s", err)
}
r, ok := resp.Result.(map[string]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if r["host"] != "localhost" {
t.Errorf("%s != localhost", r["host"])
}
if r["port"] != 2222.0 {
t.Errorf("%d != 2222", r["port"])
}
}
func TestProvider_ProviderState(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &vplugin.ProviderPlugin{Impl: &vplugin.MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteProvider{
Provider: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = p
return
}
result := ProviderState(nil, to_cs("{}"))
resp, err := LoadResponse(result)
if resp.Error != nil {
t.Fatalf("err: %s", err)
}
r, ok := resp.Result.(map[string]interface{})
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if r["id"] != "default" {
t.Errorf("%s != default", r["id"])
}
if r["short_description"] != "running" {
t.Errorf("%s != running", r["short_description"])
}
}

48
ext/go-plugin/response.go Normal file
View File

@ -0,0 +1,48 @@
package main
import (
"C"
"encoding/json"
"errors"
"fmt"
)
type Response struct {
Error error `json:"error"`
Result interface{} `json:"result"`
}
// Serialize the response into a JSON C string
func (r *Response) Dump() *C.char {
tmp := map[string]interface{}{}
if r.Error != nil {
tmp["error"] = r.Error.Error()
} else {
tmp["error"] = nil
}
tmp["result"] = r.Result
result, err := json.Marshal(tmp)
if err != nil {
return to_cs(fmt.Sprintf(`{"error": "failed to encode response - %s"}`, err))
}
return to_cs(string(result[:]))
}
// Load a new response from a JSON C string
func LoadResponse(s *C.char) (r *Response, err error) {
tmp := map[string]interface{}{}
st := []byte(to_gs(s))
r = &Response{}
err = json.Unmarshal(st, &tmp)
if tmp["error"] != nil {
e, ok := tmp["error"].(string)
if !ok {
err = errors.New(
fmt.Sprintf("cannot load error content - %s", tmp["error"]))
return
}
r.Error = errors.New(e)
}
r.Result = tmp["result"]
return
}

View File

@ -12,135 +12,135 @@ import (
//export ListSyncedFolders //export ListSyncedFolders
func ListSyncedFolders() *C.char { func ListSyncedFolders() *C.char {
list := map[string]interface{}{} list := map[string]interface{}{}
r := vagrant.Response{Result: list} r := &Response{Result: list}
if Plugins == nil { if Plugins == nil {
return C.CString(r.Dump()) return r.Dump()
} }
for n, p := range Plugins.SyncedFolders { for n, p := range Plugins.SyncedFolders {
list[n] = p.SyncedFolder.Info() list[n] = p.SyncedFolder.Info()
} }
r.Result = list r.Result = list
return C.CString(r.Dump()) return r.Dump()
} }
//export SyncedFolderCleanup //export SyncedFolderCleanup
func SyncedFolderCleanup(pluginName, machine, opts *C.char) *C.char { func SyncedFolderCleanup(pluginName, machine, opts *C.char) *C.char {
r := vagrant.Response{} r := &Response{}
p, err := getSyncedFolderPlugin(pluginName) p, err := getSyncedFolderPlugin(pluginName)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
m, err := vagrant.LoadMachine(C.GoString(machine), nil) m, err := vagrant.LoadMachine(C.GoString(machine), nil)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
var o vagrant.FolderOptions var o vagrant.FolderOptions
r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o) r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o)
if r.Error != nil { if r.Error != nil {
return C.CString(r.Dump()) return r.Dump()
} }
r.Error = p.SyncedFolder.Cleanup(m, &o) r.Error = p.SyncedFolder.Cleanup(m, o)
return C.CString(r.Dump()) return r.Dump()
} }
//export SyncedFolderDisable //export SyncedFolderDisable
func SyncedFolderDisable(pluginName, machine, folders, opts *C.char) *C.char { func SyncedFolderDisable(pluginName, machine, folders, opts *C.char) *C.char {
r := vagrant.Response{} r := &Response{}
p, err := getSyncedFolderPlugin(pluginName) p, err := getSyncedFolderPlugin(pluginName)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
m, err := vagrant.LoadMachine(C.GoString(machine), nil) m, err := vagrant.LoadMachine(C.GoString(machine), nil)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
var f vagrant.FolderList var f vagrant.FolderList
r.Error = json.Unmarshal([]byte(C.GoString(folders)), &f) r.Error = json.Unmarshal([]byte(C.GoString(folders)), &f)
if r.Error != nil { if r.Error != nil {
return C.CString(r.Dump()) return r.Dump()
} }
var o vagrant.FolderOptions var o vagrant.FolderOptions
r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o) r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o)
if r.Error != nil { if r.Error != nil {
return C.CString(r.Dump()) return r.Dump()
} }
r.Error = p.SyncedFolder.Disable(m, &f, &o) r.Error = p.SyncedFolder.Disable(m, f, o)
return C.CString(r.Dump()) return r.Dump()
} }
//export SyncedFolderEnable //export SyncedFolderEnable
func SyncedFolderEnable(pluginName, machine, folders, opts *C.char) *C.char { func SyncedFolderEnable(pluginName, machine, folders, opts *C.char) *C.char {
r := vagrant.Response{} r := &Response{}
p, err := getSyncedFolderPlugin(pluginName) p, err := getSyncedFolderPlugin(pluginName)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
m, err := vagrant.LoadMachine(C.GoString(machine), nil) m, err := vagrant.LoadMachine(C.GoString(machine), nil)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
var f vagrant.FolderList var f vagrant.FolderList
r.Error = json.Unmarshal([]byte(C.GoString(folders)), &f) r.Error = json.Unmarshal([]byte(C.GoString(folders)), &f)
if r.Error != nil { if r.Error != nil {
return C.CString(r.Dump()) return r.Dump()
} }
var o vagrant.FolderOptions var o vagrant.FolderOptions
r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o) r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o)
if r.Error != nil { if r.Error != nil {
return C.CString(r.Dump()) return r.Dump()
} }
r.Error = p.SyncedFolder.Enable(m, &f, &o) r.Error = p.SyncedFolder.Enable(m, f, o)
return C.CString(r.Dump()) return r.Dump()
} }
//export SyncedFolderIsUsable //export SyncedFolderIsUsable
func SyncedFolderIsUsable(pluginName, machine *C.char) *C.char { func SyncedFolderIsUsable(pluginName, machine *C.char) *C.char {
r := vagrant.Response{} r := &Response{}
p, err := getSyncedFolderPlugin(pluginName) p, err := getSyncedFolderPlugin(pluginName)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
m, err := vagrant.LoadMachine(C.GoString(machine), nil) m, err := vagrant.LoadMachine(C.GoString(machine), nil)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
r.Result, r.Error = p.SyncedFolder.IsUsable(m) r.Result, r.Error = p.SyncedFolder.IsUsable(m)
return C.CString(r.Dump()) return r.Dump()
} }
//export SyncedFolderPrepare //export SyncedFolderPrepare
func SyncedFolderPrepare(pluginName, machine, folders, opts *C.char) *C.char { func SyncedFolderPrepare(pluginName, machine, folders, opts *C.char) *C.char {
r := vagrant.Response{} r := &Response{}
p, err := getSyncedFolderPlugin(pluginName) p, err := getSyncedFolderPlugin(pluginName)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
m, err := vagrant.LoadMachine(C.GoString(machine), nil) m, err := vagrant.LoadMachine(C.GoString(machine), nil)
if err != nil { if err != nil {
r.Error = err r.Error = err
return C.CString(r.Dump()) return r.Dump()
} }
var f vagrant.FolderList var f vagrant.FolderList
r.Error = json.Unmarshal([]byte(C.GoString(folders)), &f) r.Error = json.Unmarshal([]byte(C.GoString(folders)), &f)
if r.Error != nil { if r.Error != nil {
return C.CString(r.Dump()) return r.Dump()
} }
var o vagrant.FolderOptions var o vagrant.FolderOptions
r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o) r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o)
if r.Error != nil { if r.Error != nil {
return C.CString(r.Dump()) return r.Dump()
} }
r.Error = p.SyncedFolder.Prepare(m, &f, &o) r.Error = p.SyncedFolder.Prepare(m, f, o)
return C.CString(r.Dump()) return r.Dump()
} }
func getSyncedFolderPlugin(pluginName *C.char) (c *plugin.RemoteSyncedFolder, err error) { func getSyncedFolderPlugin(pluginName *C.char) (c *plugin.RemoteSyncedFolder, err error) {

View File

@ -7,7 +7,7 @@ type SystemCapability struct {
type ProviderCapability struct { type ProviderCapability struct {
Name string `json:"name"` Name string `json:"name"`
Provider string `json:"name"` Provider string `json:"provider"`
} }
type GuestCapabilities interface { type GuestCapabilities interface {

View File

@ -6,3 +6,10 @@ type Config interface {
ConfigValidate(data map[string]interface{}, m *Machine) (errors []string, err error) ConfigValidate(data map[string]interface{}, m *Machine) (errors []string, err error)
ConfigFinalize(data map[string]interface{}) (finaldata map[string]interface{}, err error) ConfigFinalize(data map[string]interface{}) (finaldata map[string]interface{}, err error)
} }
type NoConfig struct{}
func (c *NoConfig) ConfigAttributes() (a []string, e error) { return }
func (c *NoConfig) ConfigLoad(map[string]interface{}) (d map[string]interface{}, e error) { return }
func (c *NoConfig) ConfigValidate(map[string]interface{}, *Machine) (es []string, e error) { return }
func (c *NoConfig) ConfigFinalize(map[string]interface{}) (f map[string]interface{}, e error) { return }

View File

@ -2,6 +2,7 @@ package plugin
import ( import (
"errors" "errors"
"fmt"
"os" "os"
"os/exec" "os/exec"
@ -11,6 +12,13 @@ import (
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant" "github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
) )
var (
Handshake = go_plugin.HandshakeConfig{
MagicCookieKey: "VAGRANT_PLUGIN_MAGIC_COOKIE",
MagicCookieValue: "1561a662a76642f98df77ad025aa13a9b16225d93f90475e91090fbe577317ed",
ProtocolVersion: 1}
)
type RemoteConfig struct { type RemoteConfig struct {
Client *go_plugin.Client Client *go_plugin.Client
Config vagrant.Config Config vagrant.Config
@ -45,9 +53,36 @@ type VagrantPlugin struct {
Providers map[string]*RemoteProvider Providers map[string]*RemoteProvider
SyncedFolders map[string]*RemoteSyncedFolder SyncedFolders map[string]*RemoteSyncedFolder
PluginDirectories []string PluginDirectories []string
PluginLookup func(name, kind string) (p interface{}, err error)
Logger hclog.Logger Logger hclog.Logger
} }
func VagrantPluginInit() *VagrantPlugin {
v := &VagrantPlugin{
PluginDirectories: []string{},
Providers: map[string]*RemoteProvider{},
SyncedFolders: map[string]*RemoteSyncedFolder{},
Logger: vagrant.DefaultLogger().Named("go-plugin")}
v.PluginLookup = v.DefaultPluginLookup
return v
}
func (v *VagrantPlugin) DefaultPluginLookup(name, kind string) (p interface{}, err error) {
switch kind {
case "provider":
p = v.Providers[name]
case "synced_folder":
p = v.SyncedFolders[name]
default:
err = errors.New("invalid plugin type")
return
}
if p == nil {
err = errors.New(fmt.Sprintf("Failed to locate %s plugin of type %s", name, kind))
}
return
}
func (v *VagrantPlugin) LoadPlugins(pluginPath string) error { func (v *VagrantPlugin) LoadPlugins(pluginPath string) error {
for _, p := range v.PluginDirectories { for _, p := range v.PluginDirectories {
if p == pluginPath { if p == pluginPath {
@ -78,11 +113,7 @@ func (v *VagrantPlugin) LoadProviders(pluginPath string) error {
client := go_plugin.NewClient(&go_plugin.ClientConfig{ client := go_plugin.NewClient(&go_plugin.ClientConfig{
AllowedProtocols: []go_plugin.Protocol{go_plugin.ProtocolGRPC}, AllowedProtocols: []go_plugin.Protocol{go_plugin.ProtocolGRPC},
Logger: v.Logger, Logger: v.Logger,
HandshakeConfig: go_plugin.HandshakeConfig{ HandshakeConfig: Handshake,
MagicCookieKey: "BASIC_PLUGIN",
MagicCookieValue: "hello",
ProtocolVersion: 1,
},
Cmd: exec.Command(providerPath), Cmd: exec.Command(providerPath),
VersionedPlugins: map[int]go_plugin.PluginSet{ VersionedPlugins: map[int]go_plugin.PluginSet{
2: {"provider": &ProviderPlugin{}}}}) 2: {"provider": &ProviderPlugin{}}}})
@ -121,11 +152,7 @@ func (v *VagrantPlugin) LoadSyncedFolders(pluginPath string) error {
client := go_plugin.NewClient(&go_plugin.ClientConfig{ client := go_plugin.NewClient(&go_plugin.ClientConfig{
AllowedProtocols: []go_plugin.Protocol{go_plugin.ProtocolGRPC}, AllowedProtocols: []go_plugin.Protocol{go_plugin.ProtocolGRPC},
Logger: v.Logger, Logger: v.Logger,
HandshakeConfig: go_plugin.HandshakeConfig{ HandshakeConfig: Handshake,
MagicCookieKey: "BASIC_PLUGIN",
MagicCookieValue: "hello",
ProtocolVersion: 1,
},
Cmd: exec.Command(folderPath), Cmd: exec.Command(folderPath),
VersionedPlugins: map[int]go_plugin.PluginSet{ VersionedPlugins: map[int]go_plugin.PluginSet{
2: {"synced_folders": &SyncedFolderPlugin{}}}}) 2: {"synced_folders": &SyncedFolderPlugin{}}}})

View File

@ -5,6 +5,8 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"google.golang.org/grpc"
go_plugin "github.com/hashicorp/go-plugin" go_plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant" "github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_caps" "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_caps"
@ -21,6 +23,23 @@ type GuestCapabilitiesPlugin struct {
Impl GuestCapabilities Impl GuestCapabilities
} }
func (g *GuestCapabilitiesPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error {
g.Impl.Init()
vagrant_caps.RegisterGuestCapabilitiesServer(s, &GRPCGuestCapabilitiesServer{
Impl: g.Impl,
GRPCIOServer: GRPCIOServer{
Impl: g.Impl}})
return nil
}
func (g *GuestCapabilitiesPlugin) GRPCClient(ctx context.Context, broker *go_plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
client := vagrant_caps.NewGuestCapabilitiesClient(c)
return &GRPCGuestCapabilitiesClient{
client: client,
GRPCIOClient: GRPCIOClient{
client: client}}, nil
}
type GRPCGuestCapabilitiesServer struct { type GRPCGuestCapabilitiesServer struct {
GRPCIOServer GRPCIOServer
Impl GuestCapabilities Impl GuestCapabilities
@ -43,8 +62,7 @@ func (s *GRPCGuestCapabilitiesServer) GuestCapabilities(ctx context.Context, req
func (s *GRPCGuestCapabilitiesServer) GuestCapability(ctx context.Context, req *vagrant_caps.GuestCapabilityRequest) (resp *vagrant_caps.GuestCapabilityResponse, err error) { func (s *GRPCGuestCapabilitiesServer) GuestCapability(ctx context.Context, req *vagrant_caps.GuestCapabilityRequest) (resp *vagrant_caps.GuestCapabilityResponse, err error) {
resp = &vagrant_caps.GuestCapabilityResponse{} resp = &vagrant_caps.GuestCapabilityResponse{}
var args interface{} var args interface{}
err = json.Unmarshal([]byte(req.Arguments), args) if err = json.Unmarshal([]byte(req.Arguments), &args); err != nil {
if err != nil {
return return
} }
machine, err := vagrant.LoadMachine(req.Machine, s.Impl) machine, err := vagrant.LoadMachine(req.Machine, s.Impl)
@ -67,6 +85,8 @@ func (s *GRPCGuestCapabilitiesServer) GuestCapability(ctx context.Context, req *
} }
type GRPCGuestCapabilitiesClient struct { type GRPCGuestCapabilitiesClient struct {
GRPCCoreClient
GRPCIOClient
client vagrant_caps.GuestCapabilitiesClient client vagrant_caps.GuestCapabilitiesClient
} }
@ -102,6 +122,13 @@ func (c *GRPCGuestCapabilitiesClient) GuestCapability(cap *vagrant.SystemCapabil
Capability: &vagrant_caps.Capability{Name: cap.Name, Platform: cap.Platform}, Capability: &vagrant_caps.Capability{Name: cap.Name, Platform: cap.Platform},
Machine: m, Machine: m,
Arguments: string(a)}) Arguments: string(a)})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
return
}
err = json.Unmarshal([]byte(resp.Result), &result) err = json.Unmarshal([]byte(resp.Result), &result)
return return
} }
@ -111,6 +138,28 @@ type HostCapabilities interface {
Meta Meta
} }
type HostCapabilitiesPlugin struct {
go_plugin.NetRPCUnsupportedPlugin
Impl HostCapabilities
}
func (h *HostCapabilitiesPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error {
h.Impl.Init()
vagrant_caps.RegisterHostCapabilitiesServer(s, &GRPCHostCapabilitiesServer{
Impl: h.Impl,
GRPCIOServer: GRPCIOServer{
Impl: h.Impl}})
return nil
}
func (h *HostCapabilitiesPlugin) GRPCClient(ctx context.Context, broker *go_plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
client := vagrant_caps.NewHostCapabilitiesClient(c)
return &GRPCHostCapabilitiesClient{
client: client,
GRPCIOClient: GRPCIOClient{
client: client}}, nil
}
type GRPCHostCapabilitiesServer struct { type GRPCHostCapabilitiesServer struct {
GRPCIOServer GRPCIOServer
Impl HostCapabilities Impl HostCapabilities
@ -133,8 +182,7 @@ func (s *GRPCHostCapabilitiesServer) HostCapabilities(ctx context.Context, req *
func (s *GRPCHostCapabilitiesServer) HostCapability(ctx context.Context, req *vagrant_caps.HostCapabilityRequest) (resp *vagrant_caps.HostCapabilityResponse, err error) { func (s *GRPCHostCapabilitiesServer) HostCapability(ctx context.Context, req *vagrant_caps.HostCapabilityRequest) (resp *vagrant_caps.HostCapabilityResponse, err error) {
resp = &vagrant_caps.HostCapabilityResponse{} resp = &vagrant_caps.HostCapabilityResponse{}
var args interface{} var args interface{}
err = json.Unmarshal([]byte(req.Arguments), args) if err = json.Unmarshal([]byte(req.Arguments), &args); err != nil {
if err != nil {
return return
} }
env, err := vagrant.LoadEnvironment(req.Environment, s.Impl) env, err := vagrant.LoadEnvironment(req.Environment, s.Impl)
@ -157,6 +205,8 @@ func (s *GRPCHostCapabilitiesServer) HostCapability(ctx context.Context, req *va
} }
type GRPCHostCapabilitiesClient struct { type GRPCHostCapabilitiesClient struct {
GRPCCoreClient
GRPCIOClient
client vagrant_caps.HostCapabilitiesClient client vagrant_caps.HostCapabilitiesClient
} }
@ -194,6 +244,9 @@ func (c *GRPCHostCapabilitiesClient) HostCapability(cap *vagrant.SystemCapabilit
Platform: cap.Platform}, Platform: cap.Platform},
Environment: e, Environment: e,
Arguments: string(a)}) Arguments: string(a)})
if err != nil {
return
}
err = json.Unmarshal([]byte(resp.Result), &result) err = json.Unmarshal([]byte(resp.Result), &result)
return return
} }
@ -203,6 +256,28 @@ type ProviderCapabilities interface {
Meta Meta
} }
type ProviderCapabilitiesPlugin struct {
go_plugin.NetRPCUnsupportedPlugin
Impl ProviderCapabilities
}
func (p *ProviderCapabilitiesPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error {
p.Impl.Init()
vagrant_caps.RegisterProviderCapabilitiesServer(s, &GRPCProviderCapabilitiesServer{
Impl: p.Impl,
GRPCIOServer: GRPCIOServer{
Impl: p.Impl}})
return nil
}
func (p *ProviderCapabilitiesPlugin) GRPCClient(ctx context.Context, broker *go_plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
client := vagrant_caps.NewProviderCapabilitiesClient(c)
return &GRPCProviderCapabilitiesClient{
client: client,
GRPCIOClient: GRPCIOClient{
client: client}}, nil
}
type GRPCProviderCapabilitiesServer struct { type GRPCProviderCapabilitiesServer struct {
GRPCIOServer GRPCIOServer
Impl ProviderCapabilities Impl ProviderCapabilities
@ -225,7 +300,7 @@ func (s *GRPCProviderCapabilitiesServer) ProviderCapabilities(ctx context.Contex
func (s *GRPCProviderCapabilitiesServer) ProviderCapability(ctx context.Context, req *vagrant_caps.ProviderCapabilityRequest) (resp *vagrant_caps.ProviderCapabilityResponse, err error) { func (s *GRPCProviderCapabilitiesServer) ProviderCapability(ctx context.Context, req *vagrant_caps.ProviderCapabilityRequest) (resp *vagrant_caps.ProviderCapabilityResponse, err error) {
resp = &vagrant_caps.ProviderCapabilityResponse{} resp = &vagrant_caps.ProviderCapabilityResponse{}
var args interface{} var args interface{}
err = json.Unmarshal([]byte(req.Arguments), args) err = json.Unmarshal([]byte(req.Arguments), &args)
if err != nil { if err != nil {
return return
} }
@ -249,6 +324,8 @@ func (s *GRPCProviderCapabilitiesServer) ProviderCapability(ctx context.Context,
} }
type GRPCProviderCapabilitiesClient struct { type GRPCProviderCapabilitiesClient struct {
GRPCCoreClient
GRPCIOClient
client vagrant_caps.ProviderCapabilitiesClient client vagrant_caps.ProviderCapabilitiesClient
} }
@ -286,6 +363,9 @@ func (c *GRPCProviderCapabilitiesClient) ProviderCapability(cap *vagrant.Provide
Provider: cap.Provider}, Provider: cap.Provider},
Machine: m, Machine: m,
Arguments: string(a)}) Arguments: string(a)})
if err != nil {
return
}
err = json.Unmarshal([]byte(resp.Result), &result) err = json.Unmarshal([]byte(resp.Result), &result)
return return
} }

View File

@ -0,0 +1,311 @@
package plugin
import (
"testing"
"github.com/hashicorp/go-plugin"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
)
func TestCapabilities_GuestCapabilities(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &GuestCapabilitiesPlugin{Impl: &MockGuestCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(GuestCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
resp, err := impl.GuestCapabilities()
if err != nil {
t.Fatalf("bad resp: %s", err)
}
if len(resp) != 1 {
t.Fatalf("length %d != 1", len(resp))
}
if resp[0].Name != "test_cap" {
t.Errorf("name - %s != test_cap", resp[0].Name)
}
if resp[0].Platform != "testOS" {
t.Errorf("platform - %s != testOS", resp[0].Platform)
}
}
func TestCapabilities_GuestCapability(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &GuestCapabilitiesPlugin{Impl: &MockGuestCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(GuestCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
cap := &vagrant.SystemCapability{
Name: "test_cap",
Platform: "TestOS"}
m := &vagrant.Machine{}
args := []string{"test_value", "next_test_value"}
resp, err := impl.GuestCapability(cap, args, m)
if err != nil {
t.Fatalf("bad resp: %s", err)
}
result, ok := resp.([]interface{})
if !ok {
t.Fatalf("bad %#v", result)
}
if result[0] != "test_cap" {
t.Errorf("%s != test_cap", result[0])
}
if result[1] != "test_value" {
t.Errorf("%s != test_value", result[1])
}
}
func TestCapabilities_GuestCapability_noargs(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &GuestCapabilitiesPlugin{Impl: &MockGuestCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(GuestCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
cap := &vagrant.SystemCapability{
Name: "test_cap",
Platform: "TestOS"}
m := &vagrant.Machine{}
var args interface{}
args = nil
resp, err := impl.GuestCapability(cap, args, m)
if err != nil {
t.Fatalf("bad resp: %s", err)
}
result, ok := resp.([]interface{})
if !ok {
t.Fatalf("bad %#v", result)
}
if result[0] != "test_cap" {
t.Errorf("%s != test_cap", result[0])
}
}
func TestCapabilities_HostCapabilities(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &HostCapabilitiesPlugin{Impl: &MockHostCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(HostCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
resp, err := impl.HostCapabilities()
if err != nil {
t.Fatalf("bad resp: %s", err)
}
if len(resp) != 1 {
t.Fatalf("length %d != 1", len(resp))
}
if resp[0].Name != "test_cap" {
t.Errorf("name - %s != test_cap", resp[0].Name)
}
if resp[0].Platform != "testOS" {
t.Errorf("platform - %s != testOS", resp[0].Platform)
}
}
func TestCapabilities_HostCapability(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &HostCapabilitiesPlugin{Impl: &MockHostCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(HostCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
cap := &vagrant.SystemCapability{
Name: "test_cap",
Platform: "TestOS"}
e := &vagrant.Environment{}
args := []string{"test_value", "next_test_value"}
resp, err := impl.HostCapability(cap, args, e)
if err != nil {
t.Fatalf("bad resp: %s", err)
}
result, ok := resp.([]interface{})
if !ok {
t.Fatalf("bad %#v", result)
}
if result[0] != "test_cap" {
t.Errorf("%s != test_cap", result[0])
}
if result[1] != "test_value" {
t.Errorf("%s != test_value", result[1])
}
}
func TestCapabilities_HostCapability_noargs(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &HostCapabilitiesPlugin{Impl: &MockHostCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(HostCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
cap := &vagrant.SystemCapability{
Name: "test_cap",
Platform: "TestOS"}
e := &vagrant.Environment{}
var args interface{}
args = nil
resp, err := impl.HostCapability(cap, args, e)
if err != nil {
t.Fatalf("bad resp: %s", err)
}
result, ok := resp.([]interface{})
if !ok {
t.Fatalf("bad %#v", result)
}
if result[0] != "test_cap" {
t.Errorf("%s != test_cap", result[0])
}
}
func TestCapabilities_ProviderCapabilities(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &ProviderCapabilitiesPlugin{Impl: &MockProviderCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(ProviderCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
resp, err := impl.ProviderCapabilities()
if err != nil {
t.Fatalf("bad resp: %s", err)
}
if len(resp) != 1 {
t.Fatalf("length %d != 1", len(resp))
}
if resp[0].Name != "test_cap" {
t.Errorf("name - %s != test_cap", resp[0].Name)
}
if resp[0].Provider != "testProvider" {
t.Errorf("provider - %s != testProvdier", resp[0].Provider)
}
}
func TestCapabilities_ProviderCapability(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &ProviderCapabilitiesPlugin{Impl: &MockProviderCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(ProviderCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
cap := &vagrant.ProviderCapability{
Name: "test_cap",
Provider: "test_provider"}
m := &vagrant.Machine{}
args := []string{"test_value", "next_test_value"}
resp, err := impl.ProviderCapability(cap, args, m)
if err != nil {
t.Fatalf("bad resp: %s", err)
}
result, ok := resp.([]interface{})
if !ok {
t.Fatalf("bad %#v", result)
}
if result[0] != "test_cap" {
t.Errorf("%s != test_cap", result[0])
}
if result[1] != "test_value" {
t.Errorf("%s != test_value", result[1])
}
}
func TestCapabilities_ProviderCapability_noargs(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"caps": &ProviderCapabilitiesPlugin{Impl: &MockProviderCapabilities{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("caps")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(ProviderCapabilities)
if !ok {
t.Fatalf("bad %#v", raw)
}
cap := &vagrant.ProviderCapability{
Name: "test_cap",
Provider: "test_provider"}
m := &vagrant.Machine{}
var args interface{}
args = nil
resp, err := impl.ProviderCapability(cap, args, m)
if err != nil {
t.Fatalf("bad resp: %s", err)
}
result, ok := resp.([]interface{})
if !ok {
t.Fatalf("bad %#v", result)
}
if result[0] != "test_cap" {
t.Errorf("%s != test_cap", result[0])
}
}

View File

@ -5,6 +5,8 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"google.golang.org/grpc"
go_plugin "github.com/hashicorp/go-plugin" go_plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant" "github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common" "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common"
@ -21,6 +23,23 @@ type ConfigPlugin struct {
Impl Config Impl Config
} }
func (c *ConfigPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error {
c.Impl.Init()
vagrant_config.RegisterConfigServer(s, &GRPCConfigServer{
Impl: c.Impl,
GRPCIOServer: GRPCIOServer{
Impl: c.Impl}})
return nil
}
func (c *ConfigPlugin) GRPCClient(ctx context.Context, broker *go_plugin.GRPCBroker, con *grpc.ClientConn) (interface{}, error) {
client := vagrant_config.NewConfigClient(con)
return &GRPCConfigClient{
client: client,
GRPCIOClient: GRPCIOClient{
client: client}}, nil
}
type GRPCConfigServer struct { type GRPCConfigServer struct {
GRPCIOServer GRPCIOServer
Impl Config Impl Config
@ -104,6 +123,8 @@ func (s *GRPCConfigServer) ConfigFinalize(ctx context.Context, req *vagrant_conf
} }
type GRPCConfigClient struct { type GRPCConfigClient struct {
GRPCCoreClient
GRPCIOClient
client vagrant_config.ConfigClient client vagrant_config.ConfigClient
} }

View File

@ -0,0 +1,131 @@
package plugin
import (
"testing"
"github.com/hashicorp/go-plugin"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
)
func TestConfigPlugin_Attributes(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"configs": &ConfigPlugin{Impl: &MockConfig{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("configs")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Config)
if !ok {
t.Fatalf("bad %#v", raw)
}
resp, err := impl.ConfigAttributes()
if err != nil {
t.Fatalf("bad resp %s", err)
}
if resp[0] != "fubar" {
t.Errorf("%s != fubar", resp[0])
}
if resp[1] != "foobar" {
t.Errorf("%s != foobar", resp[1])
}
}
func TestConfigPlugin_Load(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"configs": &ConfigPlugin{Impl: &MockConfig{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("configs")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Config)
if !ok {
t.Fatalf("bad %#v", raw)
}
data := map[string]interface{}{}
resp, err := impl.ConfigLoad(data)
if err != nil {
t.Fatalf("bad resp: %s", err)
}
if _, ok := resp["test_key"]; !ok {
t.Fatalf("bad resp content %#v", resp)
}
v := resp["test_key"].(string)
if v != "test_val" {
t.Errorf("%s != test_val", v)
}
}
func TestConfigPlugin_Validate(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"configs": &ConfigPlugin{Impl: &MockConfig{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("configs")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Config)
if !ok {
t.Fatalf("bad %#v", raw)
}
data := map[string]interface{}{}
machine := &vagrant.Machine{}
resp, err := impl.ConfigValidate(data, machine)
if err != nil {
t.Fatalf("bad resp: %s", err)
}
if len(resp) != 1 {
t.Fatalf("bad size %d != 1", len(resp))
}
if resp[0] != "test error" {
t.Errorf("%s != test error", resp[0])
}
}
func TestConfigPlugin_Finalize(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"configs": &ConfigPlugin{Impl: &MockConfig{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("configs")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Config)
if !ok {
t.Fatalf("bad %#v", raw)
}
data := map[string]interface{}{
"test_key": "test_val",
"other_key": "other_val"}
resp, err := impl.ConfigFinalize(data)
if err != nil {
t.Fatalf("bad resp: %s", err)
}
if _, ok := resp["test_key"]; !ok {
t.Fatalf("bad resp content %#v", resp)
}
v := resp["test_key"].(string)
if v != "test_val-updated" {
t.Errorf("%s != test_val-updated", v)
}
v = resp["other_key"].(string)
if v != "other_val-updated" {
t.Errorf("%s != other_val-updated", v)
}
}

View File

@ -11,6 +11,10 @@ import (
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_io" "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_io"
) )
type IO interface {
vagrant.StreamIO
}
type IOPlugin struct { type IOPlugin struct {
go_plugin.NetRPCUnsupportedPlugin go_plugin.NetRPCUnsupportedPlugin
Impl vagrant.StreamIO Impl vagrant.StreamIO

View File

@ -0,0 +1,89 @@
package plugin
import (
"testing"
"github.com/hashicorp/go-plugin"
)
type MockIO struct {
Core
}
func TestIO_ReadWrite(t *testing.T) {
ioplugin := &MockIO{}
ioplugin.Init()
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"io": &IOPlugin{Impl: ioplugin}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("io")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(IO)
if !ok {
t.Fatalf("bad %#v", raw)
}
go func() {
length, err := impl.Write("test_message", "stdout")
if err != nil {
t.Fatalf("bad write: %s", err)
}
if length != len("test_message") {
t.Fatalf("bad length %d != %d", length, len("test_message"))
}
}()
resp, err := impl.Read("stdout")
if err != nil {
t.Fatalf("bad read: %s", err)
}
if resp != "test_message" {
t.Errorf("%s != test_message", resp)
}
}
func TestIO_Write_bad(t *testing.T) {
ioplugin := &MockIO{}
ioplugin.Init()
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"io": &IOPlugin{Impl: ioplugin}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("io")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(IO)
if !ok {
t.Fatalf("bad %#v", raw)
}
_, err = impl.Write("test_message", "bad-target")
if err == nil {
t.Fatalf("illegal write")
}
}
func TestIO_Read_bad(t *testing.T) {
ioplugin := &MockIO{}
ioplugin.Init()
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"io": &IOPlugin{Impl: ioplugin}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("io")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(IO)
if !ok {
t.Fatalf("bad %#v", raw)
}
_, err = impl.Read("bad-target")
if err == nil {
t.Fatalf("illegal read")
}
}

View File

@ -0,0 +1,176 @@
package plugin
import (
"errors"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
)
type MockGuestCapabilities struct{ Core }
func (g *MockGuestCapabilities) GuestCapabilities() (caps []vagrant.SystemCapability, err error) {
caps = []vagrant.SystemCapability{
vagrant.SystemCapability{Name: "test_cap", Platform: "testOS"}}
return
}
func (g *MockGuestCapabilities) GuestCapability(cap *vagrant.SystemCapability, args interface{}, m *vagrant.Machine) (result interface{}, err error) {
if args != nil {
arguments := args.([]interface{})
if len(arguments) > 0 {
result = []string{
cap.Name,
arguments[0].(string)}
return
}
}
result = []string{cap.Name}
return
}
type MockHostCapabilities struct{ Core }
func (h *MockHostCapabilities) HostCapabilities() (caps []vagrant.SystemCapability, err error) {
caps = []vagrant.SystemCapability{
vagrant.SystemCapability{Name: "test_cap", Platform: "testOS"}}
return
}
func (h *MockHostCapabilities) HostCapability(cap *vagrant.SystemCapability, args interface{}, e *vagrant.Environment) (result interface{}, err error) {
if args != nil {
arguments := args.([]interface{})
if len(arguments) > 0 {
result = []string{
cap.Name,
arguments[0].(string)}
return
}
}
result = []string{cap.Name}
return
}
type MockProviderCapabilities struct{ Core }
func (p *MockProviderCapabilities) ProviderCapabilities() (caps []vagrant.ProviderCapability, err error) {
caps = []vagrant.ProviderCapability{
vagrant.ProviderCapability{Name: "test_cap", Provider: "testProvider"}}
return
}
func (p *MockProviderCapabilities) ProviderCapability(cap *vagrant.ProviderCapability, args interface{}, m *vagrant.Machine) (result interface{}, err error) {
if args != nil {
arguments := args.([]interface{})
if len(arguments) > 0 {
result = []string{
cap.Name,
arguments[0].(string)}
return
}
}
result = []string{cap.Name}
return
}
type MockConfig struct {
Core
}
func (c *MockConfig) ConfigAttributes() (attrs []string, err error) {
attrs = []string{"fubar", "foobar"}
return
}
func (c *MockConfig) ConfigLoad(data map[string]interface{}) (loaddata map[string]interface{}, err error) {
loaddata = map[string]interface{}{
"test_key": "test_val"}
if data["test_key"] != nil {
loaddata["sent_key"] = data["test_key"]
}
return
}
func (c *MockConfig) ConfigValidate(data map[string]interface{}, m *vagrant.Machine) (errors []string, err error) {
errors = []string{"test error"}
return
}
func (c *MockConfig) ConfigFinalize(data map[string]interface{}) (finaldata map[string]interface{}, err error) {
finaldata = make(map[string]interface{})
for key, tval := range data {
val := tval.(string)
finaldata[key] = val + "-updated"
}
return
}
type MockProvider struct {
Core
vagrant.NoConfig
vagrant.NoGuestCapabilities
vagrant.NoHostCapabilities
vagrant.NoProviderCapabilities
}
func (c *MockProvider) Action(actionName string, m *vagrant.Machine) (actions []string, err error) {
if actionName == "valid" {
actions = []string{"self::DoTask"}
} else {
err = errors.New("Unknown action requested")
}
return
}
func (c *MockProvider) IsInstalled(m *vagrant.Machine) (bool, error) {
return true, nil
}
func (c *MockProvider) IsUsable(m *vagrant.Machine) (bool, error) {
return true, nil
}
func (c *MockProvider) MachineIdChanged(m *vagrant.Machine) error {
return nil
}
func (c *MockProvider) Name() string {
return "mock_provider"
}
func (c *MockProvider) RunAction(actionName string, args interface{}, m *vagrant.Machine) (r interface{}, err error) {
if actionName != "valid" && actionName != "send_output" {
err = errors.New("invalid action name")
return
}
if actionName == "send_output" {
m.UI.Say("test_output_p")
}
var arguments []interface{}
if args != nil {
arguments = args.([]interface{})
} else {
arguments = []interface{}{"unset"}
}
r = []string{
actionName,
arguments[0].(string)}
return
}
func (c *MockProvider) SshInfo(m *vagrant.Machine) (*vagrant.SshInfo, error) {
return &vagrant.SshInfo{
Host: "localhost",
Port: 2222}, nil
}
func (c *MockProvider) State(m *vagrant.Machine) (*vagrant.MachineState, error) {
return &vagrant.MachineState{
Id: "default",
ShortDesc: "running"}, nil
}
func (c *MockProvider) Info() *vagrant.ProviderInfo {
return &vagrant.ProviderInfo{
Description: "Custom",
Priority: 10}
}

View File

@ -7,6 +7,7 @@ import proto "github.com/golang/protobuf/proto"
import fmt "fmt" import fmt "fmt"
import math "math" import math "math"
import vagrant_common "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common" import vagrant_common "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common"
import vagrant_io "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_io"
import ( import (
context "golang.org/x/net/context" context "golang.org/x/net/context"
@ -535,6 +536,9 @@ const _ = grpc.SupportPackageIsVersion4
type GuestCapabilitiesClient interface { type GuestCapabilitiesClient interface {
GuestCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*CapabilitiesResponse, error) GuestCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*CapabilitiesResponse, error)
GuestCapability(ctx context.Context, in *GuestCapabilityRequest, opts ...grpc.CallOption) (*GuestCapabilityResponse, error) GuestCapability(ctx context.Context, in *GuestCapabilityRequest, opts ...grpc.CallOption) (*GuestCapabilityResponse, error)
// These are IO helpers for streaming
Read(ctx context.Context, in *vagrant_io.ReadRequest, opts ...grpc.CallOption) (*vagrant_io.ReadResponse, error)
Write(ctx context.Context, in *vagrant_io.WriteRequest, opts ...grpc.CallOption) (*vagrant_io.WriteResponse, error)
} }
type guestCapabilitiesClient struct { type guestCapabilitiesClient struct {
@ -563,10 +567,31 @@ func (c *guestCapabilitiesClient) GuestCapability(ctx context.Context, in *Guest
return out, nil return out, nil
} }
func (c *guestCapabilitiesClient) Read(ctx context.Context, in *vagrant_io.ReadRequest, opts ...grpc.CallOption) (*vagrant_io.ReadResponse, error) {
out := new(vagrant_io.ReadResponse)
err := c.cc.Invoke(ctx, "/vagrant.caps.GuestCapabilities/Read", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *guestCapabilitiesClient) Write(ctx context.Context, in *vagrant_io.WriteRequest, opts ...grpc.CallOption) (*vagrant_io.WriteResponse, error) {
out := new(vagrant_io.WriteResponse)
err := c.cc.Invoke(ctx, "/vagrant.caps.GuestCapabilities/Write", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// GuestCapabilitiesServer is the server API for GuestCapabilities service. // GuestCapabilitiesServer is the server API for GuestCapabilities service.
type GuestCapabilitiesServer interface { type GuestCapabilitiesServer interface {
GuestCapabilities(context.Context, *vagrant_common.NullRequest) (*CapabilitiesResponse, error) GuestCapabilities(context.Context, *vagrant_common.NullRequest) (*CapabilitiesResponse, error)
GuestCapability(context.Context, *GuestCapabilityRequest) (*GuestCapabilityResponse, error) GuestCapability(context.Context, *GuestCapabilityRequest) (*GuestCapabilityResponse, error)
// These are IO helpers for streaming
Read(context.Context, *vagrant_io.ReadRequest) (*vagrant_io.ReadResponse, error)
Write(context.Context, *vagrant_io.WriteRequest) (*vagrant_io.WriteResponse, error)
} }
func RegisterGuestCapabilitiesServer(s *grpc.Server, srv GuestCapabilitiesServer) { func RegisterGuestCapabilitiesServer(s *grpc.Server, srv GuestCapabilitiesServer) {
@ -609,6 +634,42 @@ func _GuestCapabilities_GuestCapability_Handler(srv interface{}, ctx context.Con
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _GuestCapabilities_Read_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_io.ReadRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GuestCapabilitiesServer).Read(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.caps.GuestCapabilities/Read",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GuestCapabilitiesServer).Read(ctx, req.(*vagrant_io.ReadRequest))
}
return interceptor(ctx, in, info, handler)
}
func _GuestCapabilities_Write_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_io.WriteRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GuestCapabilitiesServer).Write(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.caps.GuestCapabilities/Write",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GuestCapabilitiesServer).Write(ctx, req.(*vagrant_io.WriteRequest))
}
return interceptor(ctx, in, info, handler)
}
var _GuestCapabilities_serviceDesc = grpc.ServiceDesc{ var _GuestCapabilities_serviceDesc = grpc.ServiceDesc{
ServiceName: "vagrant.caps.GuestCapabilities", ServiceName: "vagrant.caps.GuestCapabilities",
HandlerType: (*GuestCapabilitiesServer)(nil), HandlerType: (*GuestCapabilitiesServer)(nil),
@ -621,6 +682,14 @@ var _GuestCapabilities_serviceDesc = grpc.ServiceDesc{
MethodName: "GuestCapability", MethodName: "GuestCapability",
Handler: _GuestCapabilities_GuestCapability_Handler, Handler: _GuestCapabilities_GuestCapability_Handler,
}, },
{
MethodName: "Read",
Handler: _GuestCapabilities_Read_Handler,
},
{
MethodName: "Write",
Handler: _GuestCapabilities_Write_Handler,
},
}, },
Streams: []grpc.StreamDesc{}, Streams: []grpc.StreamDesc{},
Metadata: "vagrant_caps/capabilities.proto", Metadata: "vagrant_caps/capabilities.proto",
@ -632,6 +701,9 @@ var _GuestCapabilities_serviceDesc = grpc.ServiceDesc{
type HostCapabilitiesClient interface { type HostCapabilitiesClient interface {
HostCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*CapabilitiesResponse, error) HostCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*CapabilitiesResponse, error)
HostCapability(ctx context.Context, in *HostCapabilityRequest, opts ...grpc.CallOption) (*HostCapabilityResponse, error) HostCapability(ctx context.Context, in *HostCapabilityRequest, opts ...grpc.CallOption) (*HostCapabilityResponse, error)
// These are IO helpers for streaming
Read(ctx context.Context, in *vagrant_io.ReadRequest, opts ...grpc.CallOption) (*vagrant_io.ReadResponse, error)
Write(ctx context.Context, in *vagrant_io.WriteRequest, opts ...grpc.CallOption) (*vagrant_io.WriteResponse, error)
} }
type hostCapabilitiesClient struct { type hostCapabilitiesClient struct {
@ -660,10 +732,31 @@ func (c *hostCapabilitiesClient) HostCapability(ctx context.Context, in *HostCap
return out, nil return out, nil
} }
func (c *hostCapabilitiesClient) Read(ctx context.Context, in *vagrant_io.ReadRequest, opts ...grpc.CallOption) (*vagrant_io.ReadResponse, error) {
out := new(vagrant_io.ReadResponse)
err := c.cc.Invoke(ctx, "/vagrant.caps.HostCapabilities/Read", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *hostCapabilitiesClient) Write(ctx context.Context, in *vagrant_io.WriteRequest, opts ...grpc.CallOption) (*vagrant_io.WriteResponse, error) {
out := new(vagrant_io.WriteResponse)
err := c.cc.Invoke(ctx, "/vagrant.caps.HostCapabilities/Write", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// HostCapabilitiesServer is the server API for HostCapabilities service. // HostCapabilitiesServer is the server API for HostCapabilities service.
type HostCapabilitiesServer interface { type HostCapabilitiesServer interface {
HostCapabilities(context.Context, *vagrant_common.NullRequest) (*CapabilitiesResponse, error) HostCapabilities(context.Context, *vagrant_common.NullRequest) (*CapabilitiesResponse, error)
HostCapability(context.Context, *HostCapabilityRequest) (*HostCapabilityResponse, error) HostCapability(context.Context, *HostCapabilityRequest) (*HostCapabilityResponse, error)
// These are IO helpers for streaming
Read(context.Context, *vagrant_io.ReadRequest) (*vagrant_io.ReadResponse, error)
Write(context.Context, *vagrant_io.WriteRequest) (*vagrant_io.WriteResponse, error)
} }
func RegisterHostCapabilitiesServer(s *grpc.Server, srv HostCapabilitiesServer) { func RegisterHostCapabilitiesServer(s *grpc.Server, srv HostCapabilitiesServer) {
@ -706,6 +799,42 @@ func _HostCapabilities_HostCapability_Handler(srv interface{}, ctx context.Conte
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _HostCapabilities_Read_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_io.ReadRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HostCapabilitiesServer).Read(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.caps.HostCapabilities/Read",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HostCapabilitiesServer).Read(ctx, req.(*vagrant_io.ReadRequest))
}
return interceptor(ctx, in, info, handler)
}
func _HostCapabilities_Write_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_io.WriteRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HostCapabilitiesServer).Write(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.caps.HostCapabilities/Write",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HostCapabilitiesServer).Write(ctx, req.(*vagrant_io.WriteRequest))
}
return interceptor(ctx, in, info, handler)
}
var _HostCapabilities_serviceDesc = grpc.ServiceDesc{ var _HostCapabilities_serviceDesc = grpc.ServiceDesc{
ServiceName: "vagrant.caps.HostCapabilities", ServiceName: "vagrant.caps.HostCapabilities",
HandlerType: (*HostCapabilitiesServer)(nil), HandlerType: (*HostCapabilitiesServer)(nil),
@ -718,6 +847,14 @@ var _HostCapabilities_serviceDesc = grpc.ServiceDesc{
MethodName: "HostCapability", MethodName: "HostCapability",
Handler: _HostCapabilities_HostCapability_Handler, Handler: _HostCapabilities_HostCapability_Handler,
}, },
{
MethodName: "Read",
Handler: _HostCapabilities_Read_Handler,
},
{
MethodName: "Write",
Handler: _HostCapabilities_Write_Handler,
},
}, },
Streams: []grpc.StreamDesc{}, Streams: []grpc.StreamDesc{},
Metadata: "vagrant_caps/capabilities.proto", Metadata: "vagrant_caps/capabilities.proto",
@ -729,6 +866,9 @@ var _HostCapabilities_serviceDesc = grpc.ServiceDesc{
type ProviderCapabilitiesClient interface { type ProviderCapabilitiesClient interface {
ProviderCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*ProviderCapabilitiesResponse, error) ProviderCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*ProviderCapabilitiesResponse, error)
ProviderCapability(ctx context.Context, in *ProviderCapabilityRequest, opts ...grpc.CallOption) (*ProviderCapabilityResponse, error) ProviderCapability(ctx context.Context, in *ProviderCapabilityRequest, opts ...grpc.CallOption) (*ProviderCapabilityResponse, error)
// These are IO helpers for streaming
Read(ctx context.Context, in *vagrant_io.ReadRequest, opts ...grpc.CallOption) (*vagrant_io.ReadResponse, error)
Write(ctx context.Context, in *vagrant_io.WriteRequest, opts ...grpc.CallOption) (*vagrant_io.WriteResponse, error)
} }
type providerCapabilitiesClient struct { type providerCapabilitiesClient struct {
@ -757,10 +897,31 @@ func (c *providerCapabilitiesClient) ProviderCapability(ctx context.Context, in
return out, nil return out, nil
} }
func (c *providerCapabilitiesClient) Read(ctx context.Context, in *vagrant_io.ReadRequest, opts ...grpc.CallOption) (*vagrant_io.ReadResponse, error) {
out := new(vagrant_io.ReadResponse)
err := c.cc.Invoke(ctx, "/vagrant.caps.ProviderCapabilities/Read", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *providerCapabilitiesClient) Write(ctx context.Context, in *vagrant_io.WriteRequest, opts ...grpc.CallOption) (*vagrant_io.WriteResponse, error) {
out := new(vagrant_io.WriteResponse)
err := c.cc.Invoke(ctx, "/vagrant.caps.ProviderCapabilities/Write", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ProviderCapabilitiesServer is the server API for ProviderCapabilities service. // ProviderCapabilitiesServer is the server API for ProviderCapabilities service.
type ProviderCapabilitiesServer interface { type ProviderCapabilitiesServer interface {
ProviderCapabilities(context.Context, *vagrant_common.NullRequest) (*ProviderCapabilitiesResponse, error) ProviderCapabilities(context.Context, *vagrant_common.NullRequest) (*ProviderCapabilitiesResponse, error)
ProviderCapability(context.Context, *ProviderCapabilityRequest) (*ProviderCapabilityResponse, error) ProviderCapability(context.Context, *ProviderCapabilityRequest) (*ProviderCapabilityResponse, error)
// These are IO helpers for streaming
Read(context.Context, *vagrant_io.ReadRequest) (*vagrant_io.ReadResponse, error)
Write(context.Context, *vagrant_io.WriteRequest) (*vagrant_io.WriteResponse, error)
} }
func RegisterProviderCapabilitiesServer(s *grpc.Server, srv ProviderCapabilitiesServer) { func RegisterProviderCapabilitiesServer(s *grpc.Server, srv ProviderCapabilitiesServer) {
@ -803,6 +964,42 @@ func _ProviderCapabilities_ProviderCapability_Handler(srv interface{}, ctx conte
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _ProviderCapabilities_Read_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_io.ReadRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProviderCapabilitiesServer).Read(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.caps.ProviderCapabilities/Read",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProviderCapabilitiesServer).Read(ctx, req.(*vagrant_io.ReadRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ProviderCapabilities_Write_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_io.WriteRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProviderCapabilitiesServer).Write(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.caps.ProviderCapabilities/Write",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProviderCapabilitiesServer).Write(ctx, req.(*vagrant_io.WriteRequest))
}
return interceptor(ctx, in, info, handler)
}
var _ProviderCapabilities_serviceDesc = grpc.ServiceDesc{ var _ProviderCapabilities_serviceDesc = grpc.ServiceDesc{
ServiceName: "vagrant.caps.ProviderCapabilities", ServiceName: "vagrant.caps.ProviderCapabilities",
HandlerType: (*ProviderCapabilitiesServer)(nil), HandlerType: (*ProviderCapabilitiesServer)(nil),
@ -815,6 +1012,14 @@ var _ProviderCapabilities_serviceDesc = grpc.ServiceDesc{
MethodName: "ProviderCapability", MethodName: "ProviderCapability",
Handler: _ProviderCapabilities_ProviderCapability_Handler, Handler: _ProviderCapabilities_ProviderCapability_Handler,
}, },
{
MethodName: "Read",
Handler: _ProviderCapabilities_Read_Handler,
},
{
MethodName: "Write",
Handler: _ProviderCapabilities_Write_Handler,
},
}, },
Streams: []grpc.StreamDesc{}, Streams: []grpc.StreamDesc{},
Metadata: "vagrant_caps/capabilities.proto", Metadata: "vagrant_caps/capabilities.proto",
@ -823,37 +1028,40 @@ var _ProviderCapabilities_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("vagrant_caps/capabilities.proto", fileDescriptor_591a3013bd09a9cb) } func init() { proto.RegisterFile("vagrant_caps/capabilities.proto", fileDescriptor_591a3013bd09a9cb) }
var fileDescriptor_591a3013bd09a9cb = []byte{ var fileDescriptor_591a3013bd09a9cb = []byte{
// 510 bytes of a gzipped FileDescriptorProto // 560 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x95, 0xcf, 0x6e, 0xd3, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x95, 0x4d, 0x6f, 0xd3, 0x30,
0x10, 0xc6, 0xb5, 0x14, 0x0a, 0x9d, 0x56, 0xfc, 0x59, 0x85, 0x60, 0x4c, 0x25, 0x22, 0x53, 0x44, 0x18, 0xc7, 0x95, 0xee, 0x05, 0xf6, 0x6c, 0xe2, 0xc5, 0x2a, 0x5d, 0x16, 0x26, 0x51, 0x85, 0x21,
0x84, 0x84, 0x2d, 0x85, 0x0b, 0x87, 0x1e, 0x90, 0xa8, 0x28, 0xe2, 0x80, 0x50, 0xe0, 0x56, 0x89, 0x2a, 0x24, 0x12, 0xa9, 0x5c, 0x40, 0xda, 0x01, 0x89, 0x89, 0x21, 0x0e, 0x08, 0x75, 0x48, 0x1c,
0x6a, 0x63, 0x16, 0x7b, 0x91, 0xbd, 0x6b, 0x76, 0xd7, 0x11, 0xe5, 0x11, 0xb8, 0x71, 0xe0, 0x8d, 0x26, 0x31, 0xb9, 0x9d, 0x49, 0x8d, 0x12, 0x3b, 0xd8, 0x4e, 0xc5, 0xf8, 0x08, 0xdc, 0x38, 0xf0,
0xb8, 0xf0, 0x16, 0x3c, 0x0a, 0xb2, 0xbd, 0x71, 0xed, 0x7a, 0x5d, 0x97, 0xd2, 0x53, 0x32, 0x93, 0x71, 0xb8, 0xf0, 0x2d, 0xf8, 0x36, 0x28, 0x89, 0x93, 0x25, 0x8b, 0xbb, 0x8c, 0xad, 0xd2, 0x4e,
0x99, 0xf9, 0xe6, 0xfb, 0xd9, 0x9a, 0xc0, 0xfd, 0x25, 0x89, 0x24, 0xe1, 0xfa, 0x30, 0x24, 0x99, 0xed, 0xf3, 0xf8, 0x79, 0xfb, 0xff, 0xec, 0xd8, 0xf0, 0x60, 0x86, 0x03, 0x81, 0x99, 0x3a, 0x9a,
0x0a, 0x42, 0x92, 0x91, 0x05, 0x4b, 0x98, 0x66, 0x54, 0xf9, 0x99, 0x14, 0x5a, 0xe0, 0x2d, 0x53, 0xe0, 0x58, 0xfa, 0x13, 0x1c, 0xe3, 0x31, 0x0d, 0xa9, 0xa2, 0x44, 0x7a, 0xb1, 0xe0, 0x8a, 0xa3,
0xe0, 0x17, 0x05, 0xee, 0x41, 0xc4, 0x74, 0x9c, 0x2f, 0xfc, 0x50, 0xa4, 0x41, 0x4c, 0x54, 0xcc, 0x0d, 0x1d, 0xe0, 0xa5, 0x01, 0xce, 0x61, 0x40, 0xd5, 0x34, 0x19, 0x7b, 0x13, 0x1e, 0xf9, 0x53,
0x42, 0x21, 0xb3, 0xc0, 0x94, 0x04, 0xf4, 0xab, 0x0e, 0x22, 0xf1, 0x24, 0x4b, 0xf2, 0x88, 0xf1, 0x2c, 0xa7, 0x74, 0xc2, 0x45, 0xec, 0xeb, 0x10, 0x9f, 0x7c, 0x53, 0x7e, 0xc0, 0x9f, 0xc6, 0x61,
0x3a, 0x6b, 0xc2, 0x72, 0x5c, 0x50, 0xcb, 0x89, 0x34, 0x15, 0x3c, 0xa8, 0x3e, 0x2a, 0x29, 0x6f, 0x12, 0x50, 0x56, 0x7a, 0xb5, 0x99, 0x95, 0xf3, 0xcb, 0x76, 0x3c, 0x8a, 0x38, 0xf3, 0xf3, 0x9f,
0x17, 0xe0, 0xc5, 0x6a, 0x81, 0x23, 0x8c, 0xe1, 0x32, 0x27, 0x29, 0x75, 0xd0, 0x04, 0x4d, 0x37, 0xbc, 0x95, 0x73, 0xb0, 0xa8, 0xe2, 0x94, 0xfb, 0x94, 0xe7, 0x45, 0xdd, 0x5d, 0x80, 0x57, 0x85,
0xe6, 0xe5, 0x77, 0xec, 0xc2, 0xb5, 0x2c, 0x21, 0xfa, 0x93, 0x90, 0xa9, 0x73, 0xa9, 0xcc, 0xd7, 0xaa, 0x13, 0x84, 0x60, 0x99, 0xe1, 0x88, 0xd8, 0x56, 0xdf, 0x1a, 0xac, 0x8d, 0xb2, 0xff, 0xc8,
0xb1, 0xb7, 0x07, 0xf8, 0xad, 0x14, 0x4b, 0xf6, 0x91, 0xca, 0x33, 0x4c, 0x31, 0x95, 0xf5, 0x14, 0x81, 0x9b, 0x71, 0x88, 0xd5, 0x67, 0x2e, 0x22, 0xbb, 0x93, 0xf9, 0x4b, 0xdb, 0xdd, 0x03, 0xf4,
0x13, 0x7b, 0xdf, 0x60, 0xbb, 0x33, 0x85, 0x51, 0x35, 0xa7, 0x2a, 0x13, 0x5c, 0x51, 0xbc, 0x07, 0x5e, 0xf0, 0x19, 0x3d, 0x26, 0xe2, 0x02, 0x55, 0x74, 0x64, 0x59, 0x45, 0xdb, 0xee, 0x77, 0xd8,
0x5b, 0x4d, 0x48, 0x0e, 0x9a, 0xac, 0x4d, 0x37, 0x67, 0x13, 0xbf, 0x49, 0xc9, 0xef, 0xee, 0x31, 0x6e, 0x54, 0xa1, 0x44, 0x8e, 0x88, 0x8c, 0x39, 0x93, 0x04, 0xed, 0xc1, 0x46, 0x95, 0xbc, 0x6d,
0x6f, 0x75, 0xe1, 0x11, 0x5c, 0xa1, 0x52, 0x8a, 0x95, 0x7c, 0x15, 0x78, 0x3f, 0x11, 0xdc, 0xb5, 0xf5, 0x97, 0x06, 0xeb, 0xc3, 0xbe, 0x57, 0x45, 0xef, 0x35, 0xe7, 0x18, 0xd5, 0xb2, 0x50, 0x17,
0xb4, 0xd2, 0x2f, 0x39, 0x55, 0x1a, 0x3f, 0x07, 0xa8, 0x67, 0x1c, 0x95, 0x7e, 0xce, 0xa2, 0xdb, 0x56, 0x88, 0x10, 0xbc, 0x68, 0x9f, 0x1b, 0xee, 0x2f, 0x0b, 0xb6, 0x0c, 0xa9, 0xe4, 0x6b, 0x42,
0xe8, 0xc1, 0x0e, 0x5c, 0x4d, 0x49, 0x18, 0x33, 0x4e, 0x8d, 0xee, 0x2a, 0xc4, 0xdb, 0xb0, 0x41, 0xa4, 0x42, 0x2f, 0x01, 0xca, 0x1a, 0x27, 0x99, 0x9e, 0x8b, 0xf4, 0xad, 0xe4, 0x20, 0x1b, 0x6e,
0x64, 0x94, 0xa7, 0x94, 0x6b, 0xe5, 0xac, 0x95, 0xbf, 0x1d, 0x27, 0xbc, 0xd7, 0xe0, 0xda, 0xd6, 0x44, 0x78, 0x32, 0xa5, 0x8c, 0xe8, 0xbe, 0x85, 0x89, 0xb6, 0x61, 0x0d, 0x8b, 0x20, 0x89, 0x08,
0x32, 0x44, 0xc6, 0xb0, 0x2e, 0xa9, 0xca, 0x13, 0x6d, 0x18, 0x9b, 0xa8, 0xc7, 0xe3, 0x67, 0x18, 0x53, 0xd2, 0x5e, 0xca, 0xd6, 0x4e, 0x1d, 0xee, 0x5b, 0x70, 0x4c, 0x63, 0x69, 0x22, 0x3d, 0x58,
0x59, 0xb9, 0xee, 0x5a, 0xb9, 0x3a, 0x6d, 0x7f, 0xff, 0xc8, 0xf3, 0x3b, 0x82, 0xf1, 0x7e, 0xc1, 0x15, 0x44, 0x26, 0xa1, 0xd2, 0x8c, 0xb5, 0x35, 0x47, 0xe3, 0x17, 0xe8, 0x1a, 0xb9, 0xee, 0x1a,
0xae, 0x0b, 0xf3, 0x99, 0x05, 0x66, 0xbf, 0xd8, 0x45, 0x40, 0xdc, 0x87, 0x3b, 0x9d, 0x5d, 0xce, 0xb9, 0xda, 0x75, 0x7d, 0xff, 0xc9, 0xf3, 0x87, 0x05, 0xbd, 0xfd, 0x94, 0x5d, 0x13, 0xe6, 0x73,
0x45, 0xf0, 0x07, 0x82, 0xdb, 0xaf, 0xc4, 0xc5, 0x9a, 0x9a, 0xc0, 0x26, 0xe5, 0x4b, 0x26, 0x05, 0x03, 0xcc, 0xf9, 0xcd, 0x16, 0x01, 0x71, 0x1f, 0x36, 0x1b, 0xb3, 0x5c, 0x8a, 0xe0, 0x4f, 0x0b,
0x2f, 0x96, 0x35, 0x7a, 0xcd, 0xd4, 0x80, 0xb9, 0x97, 0x30, 0x3e, 0xb9, 0xd2, 0x79, 0xbc, 0xcd, 0xee, 0xbd, 0xe1, 0x8b, 0x15, 0xd5, 0x87, 0x75, 0xc2, 0x66, 0x54, 0x70, 0x96, 0x0e, 0xab, 0xfb,
0x7e, 0x23, 0xb8, 0xd5, 0xa6, 0x54, 0x3c, 0xdd, 0xf7, 0xb6, 0xe4, 0xbd, 0x63, 0x63, 0xd5, 0x0d, 0x55, 0x5d, 0x2d, 0xe2, 0x5e, 0x43, 0xef, 0xec, 0x48, 0x97, 0xd1, 0x36, 0xfc, 0xd3, 0x81, 0xbb,
0x79, 0x93, 0x27, 0x89, 0x21, 0xe1, 0x7a, 0x3d, 0xae, 0x9b, 0x6f, 0xdc, 0x07, 0xb8, 0x71, 0xe2, 0x75, 0x4a, 0xe9, 0xee, 0x7e, 0x30, 0x39, 0xef, 0x9f, 0x0a, 0xcb, 0x2f, 0xa6, 0x77, 0x49, 0x18,
0x81, 0xe0, 0x9d, 0x76, 0x9b, 0xfd, 0xdd, 0x71, 0x1f, 0x0e, 0x54, 0x55, 0xf3, 0x67, 0xbf, 0x10, 0x6a, 0x12, 0x8e, 0x3b, 0x47, 0x75, 0xf5, 0xc4, 0x7d, 0x82, 0xdb, 0x67, 0x36, 0x04, 0xed, 0xd4,
0xdc, 0x6c, 0x41, 0x29, 0xb6, 0x7e, 0x67, 0xc9, 0xfd, 0xb7, 0x93, 0x03, 0xb8, 0xde, 0xa6, 0x8f, 0xd3, 0xcc, 0x67, 0xc7, 0x79, 0xd4, 0x12, 0xa5, 0xeb, 0xbf, 0x80, 0xe5, 0x11, 0xc1, 0xc7, 0x68,
0x1f, 0xb4, 0xbb, 0xac, 0xaf, 0x8b, 0xbb, 0x73, 0x7a, 0x91, 0xb1, 0xf1, 0x07, 0xc1, 0xc8, 0x76, 0xb3, 0x0c, 0xa7, 0xdc, 0x4b, 0x3d, 0x45, 0x1d, 0xbb, 0xb9, 0x50, 0x7e, 0x0c, 0x2b, 0x1f, 0x05,
0x11, 0xf1, 0x61, 0x4f, 0xfe, 0x54, 0x3b, 0x8f, 0x07, 0x0e, 0x56, 0xd3, 0x56, 0x64, 0x3d, 0xe8, 0x55, 0x04, 0xd5, 0x42, 0x32, 0x57, 0x91, 0xbc, 0x65, 0x58, 0xc9, 0xb3, 0x87, 0xbf, 0x3b, 0x70,
0x8f, 0x06, 0x4f, 0x9e, 0x91, 0x9a, 0x0e, 0x17, 0x56, 0x42, 0x8b, 0xf5, 0xf2, 0xef, 0xe7, 0xe9, 0xa7, 0xb6, 0x1b, 0x29, 0xae, 0x03, 0x83, 0xef, 0xca, 0x08, 0x0f, 0xe1, 0x56, 0x7d, 0xdb, 0xd1,
0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7b, 0xfc, 0x96, 0xa9, 0x0c, 0x07, 0x00, 0x00, 0xc3, 0x7a, 0x96, 0xf1, 0x9c, 0x3a, 0x3b, 0xe7, 0x07, 0x5d, 0x37, 0xbf, 0xbf, 0x1d, 0xe8, 0x9a,
0xde, 0x00, 0x74, 0x34, 0xc7, 0x7f, 0x2e, 0xc7, 0x27, 0x2d, 0x57, 0x74, 0x95, 0x67, 0x60, 0x7c,
0xc2, 0x1e, 0xb7, 0x5e, 0xf2, 0xba, 0xd5, 0xa0, 0x3d, 0xf0, 0x9a, 0xd9, 0x8e, 0x57, 0xb3, 0x97,
0xfe, 0xd9, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x37, 0xe6, 0x14, 0x9d, 0xcc, 0x08, 0x00, 0x00,
} }

View File

@ -2,6 +2,7 @@ syntax = "proto3";
package vagrant.caps; package vagrant.caps;
import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common/common.proto"; import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common/common.proto";
import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_io/io.proto";
message Capability { message Capability {
string name = 1; string name = 1;
@ -59,14 +60,23 @@ message HostCapabilityResponse {
service GuestCapabilities { service GuestCapabilities {
rpc GuestCapabilities(vagrant.common.NullRequest) returns (CapabilitiesResponse); rpc GuestCapabilities(vagrant.common.NullRequest) returns (CapabilitiesResponse);
rpc GuestCapability(GuestCapabilityRequest) returns (GuestCapabilityResponse); rpc GuestCapability(GuestCapabilityRequest) returns (GuestCapabilityResponse);
// These are IO helpers for streaming
rpc Read(vagrant.io.ReadRequest) returns (vagrant.io.ReadResponse);
rpc Write(vagrant.io.WriteRequest) returns (vagrant.io.WriteResponse);
} }
service HostCapabilities { service HostCapabilities {
rpc HostCapabilities(vagrant.common.NullRequest) returns (CapabilitiesResponse); rpc HostCapabilities(vagrant.common.NullRequest) returns (CapabilitiesResponse);
rpc HostCapability(HostCapabilityRequest) returns (HostCapabilityResponse); rpc HostCapability(HostCapabilityRequest) returns (HostCapabilityResponse);
// These are IO helpers for streaming
rpc Read(vagrant.io.ReadRequest) returns (vagrant.io.ReadResponse);
rpc Write(vagrant.io.WriteRequest) returns (vagrant.io.WriteResponse);
} }
service ProviderCapabilities { service ProviderCapabilities {
rpc ProviderCapabilities(vagrant.common.NullRequest) returns (ProviderCapabilitiesResponse); rpc ProviderCapabilities(vagrant.common.NullRequest) returns (ProviderCapabilitiesResponse);
rpc ProviderCapability(ProviderCapabilityRequest) returns (ProviderCapabilityResponse); rpc ProviderCapability(ProviderCapabilityRequest) returns (ProviderCapabilityResponse);
// These are IO helpers for streaming
rpc Read(vagrant.io.ReadRequest) returns (vagrant.io.ReadResponse);
rpc Write(vagrant.io.WriteRequest) returns (vagrant.io.WriteResponse);
} }

View File

@ -7,6 +7,7 @@ import proto "github.com/golang/protobuf/proto"
import fmt "fmt" import fmt "fmt"
import math "math" import math "math"
import vagrant_common "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common" import vagrant_common "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common"
import vagrant_io "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_io"
import ( import (
context "golang.org/x/net/context" context "golang.org/x/net/context"
@ -356,6 +357,9 @@ type ConfigClient interface {
ConfigLoad(ctx context.Context, in *LoadRequest, opts ...grpc.CallOption) (*LoadResponse, error) ConfigLoad(ctx context.Context, in *LoadRequest, opts ...grpc.CallOption) (*LoadResponse, error)
ConfigValidate(ctx context.Context, in *ValidateRequest, opts ...grpc.CallOption) (*ValidateResponse, error) ConfigValidate(ctx context.Context, in *ValidateRequest, opts ...grpc.CallOption) (*ValidateResponse, error)
ConfigFinalize(ctx context.Context, in *FinalizeRequest, opts ...grpc.CallOption) (*FinalizeResponse, error) ConfigFinalize(ctx context.Context, in *FinalizeRequest, opts ...grpc.CallOption) (*FinalizeResponse, error)
// These are IO helpers for streaming
Read(ctx context.Context, in *vagrant_io.ReadRequest, opts ...grpc.CallOption) (*vagrant_io.ReadResponse, error)
Write(ctx context.Context, in *vagrant_io.WriteRequest, opts ...grpc.CallOption) (*vagrant_io.WriteResponse, error)
} }
type configClient struct { type configClient struct {
@ -402,12 +406,33 @@ func (c *configClient) ConfigFinalize(ctx context.Context, in *FinalizeRequest,
return out, nil return out, nil
} }
func (c *configClient) Read(ctx context.Context, in *vagrant_io.ReadRequest, opts ...grpc.CallOption) (*vagrant_io.ReadResponse, error) {
out := new(vagrant_io.ReadResponse)
err := c.cc.Invoke(ctx, "/vagrant.config.Config/Read", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *configClient) Write(ctx context.Context, in *vagrant_io.WriteRequest, opts ...grpc.CallOption) (*vagrant_io.WriteResponse, error) {
out := new(vagrant_io.WriteResponse)
err := c.cc.Invoke(ctx, "/vagrant.config.Config/Write", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ConfigServer is the server API for Config service. // ConfigServer is the server API for Config service.
type ConfigServer interface { type ConfigServer interface {
ConfigAttributes(context.Context, *vagrant_common.NullRequest) (*AttributesResponse, error) ConfigAttributes(context.Context, *vagrant_common.NullRequest) (*AttributesResponse, error)
ConfigLoad(context.Context, *LoadRequest) (*LoadResponse, error) ConfigLoad(context.Context, *LoadRequest) (*LoadResponse, error)
ConfigValidate(context.Context, *ValidateRequest) (*ValidateResponse, error) ConfigValidate(context.Context, *ValidateRequest) (*ValidateResponse, error)
ConfigFinalize(context.Context, *FinalizeRequest) (*FinalizeResponse, error) ConfigFinalize(context.Context, *FinalizeRequest) (*FinalizeResponse, error)
// These are IO helpers for streaming
Read(context.Context, *vagrant_io.ReadRequest) (*vagrant_io.ReadResponse, error)
Write(context.Context, *vagrant_io.WriteRequest) (*vagrant_io.WriteResponse, error)
} }
func RegisterConfigServer(s *grpc.Server, srv ConfigServer) { func RegisterConfigServer(s *grpc.Server, srv ConfigServer) {
@ -486,6 +511,42 @@ func _Config_ConfigFinalize_Handler(srv interface{}, ctx context.Context, dec fu
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _Config_Read_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_io.ReadRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ConfigServer).Read(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.config.Config/Read",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ConfigServer).Read(ctx, req.(*vagrant_io.ReadRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Config_Write_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_io.WriteRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ConfigServer).Write(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.config.Config/Write",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ConfigServer).Write(ctx, req.(*vagrant_io.WriteRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Config_serviceDesc = grpc.ServiceDesc{ var _Config_serviceDesc = grpc.ServiceDesc{
ServiceName: "vagrant.config.Config", ServiceName: "vagrant.config.Config",
HandlerType: (*ConfigServer)(nil), HandlerType: (*ConfigServer)(nil),
@ -506,6 +567,14 @@ var _Config_serviceDesc = grpc.ServiceDesc{
MethodName: "ConfigFinalize", MethodName: "ConfigFinalize",
Handler: _Config_ConfigFinalize_Handler, Handler: _Config_ConfigFinalize_Handler,
}, },
{
MethodName: "Read",
Handler: _Config_Read_Handler,
},
{
MethodName: "Write",
Handler: _Config_Write_Handler,
},
}, },
Streams: []grpc.StreamDesc{}, Streams: []grpc.StreamDesc{},
Metadata: "vagrant_config/config.proto", Metadata: "vagrant_config/config.proto",
@ -514,28 +583,31 @@ var _Config_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("vagrant_config/config.proto", fileDescriptor_952629f1a9a7438c) } func init() { proto.RegisterFile("vagrant_config/config.proto", fileDescriptor_952629f1a9a7438c) }
var fileDescriptor_952629f1a9a7438c = []byte{ var fileDescriptor_952629f1a9a7438c = []byte{
// 363 bytes of a gzipped FileDescriptorProto // 415 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xc1, 0x4b, 0xfb, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0xdf, 0x6b, 0xdb, 0x30,
0x14, 0xc7, 0xd9, 0x7e, 0x3f, 0x27, 0x7b, 0xca, 0x36, 0x82, 0x48, 0xe9, 0x44, 0x67, 0x41, 0xd8, 0x10, 0xc7, 0xc9, 0xf2, 0x63, 0xe4, 0x36, 0x92, 0x20, 0xc6, 0xe6, 0x39, 0x63, 0xcb, 0x0c, 0x83,
0xc5, 0x06, 0xf4, 0xe2, 0x41, 0x50, 0x11, 0x14, 0x44, 0x3c, 0x74, 0xe0, 0xc5, 0x83, 0x64, 0x5d, 0xbc, 0xcc, 0x82, 0xed, 0x65, 0x83, 0xc0, 0x56, 0x0a, 0x2d, 0x94, 0xd2, 0x07, 0x07, 0xda, 0x87,
0x6c, 0x03, 0x6d, 0x52, 0xd3, 0x54, 0xc4, 0xbf, 0xd2, 0x3f, 0x49, 0x4c, 0xd2, 0x75, 0xeb, 0xd6, 0x3e, 0x14, 0xc5, 0x56, 0x6d, 0x81, 0x6d, 0xb9, 0xb2, 0x5c, 0x4a, 0xff, 0xc3, 0xfe, 0x57, 0x25,
0x81, 0xa7, 0xe4, 0xbd, 0x7c, 0xf3, 0x79, 0xc9, 0xfb, 0x3e, 0x18, 0x7e, 0x90, 0x48, 0x12, 0xae, 0x92, 0x1c, 0x27, 0xb6, 0x13, 0x28, 0xf4, 0xc9, 0xba, 0xbb, 0xef, 0x7d, 0x4e, 0xba, 0x3b, 0xc3,
0x5e, 0x43, 0xc1, 0xdf, 0x58, 0x84, 0xcd, 0xe2, 0x67, 0x52, 0x28, 0x81, 0x7a, 0xf6, 0xd0, 0x37, 0xf4, 0x9e, 0x84, 0x82, 0xa4, 0xf2, 0xc6, 0xe7, 0xe9, 0x2d, 0x0b, 0xb1, 0xfe, 0xb8, 0x99, 0xe0,
0x59, 0xf7, 0x25, 0x62, 0x2a, 0x2e, 0xa6, 0x7e, 0x28, 0x52, 0x1c, 0x93, 0x3c, 0x66, 0xa1, 0x90, 0x92, 0xa3, 0x91, 0x09, 0xba, 0xda, 0x6b, 0x5f, 0x87, 0x4c, 0x46, 0xc5, 0xca, 0xf5, 0x79, 0x82,
0x19, 0xb6, 0x22, 0x4c, 0x3f, 0x15, 0x8e, 0xc4, 0x69, 0x96, 0x14, 0x11, 0xe3, 0xf3, 0xac, 0x0d, 0x23, 0x92, 0x47, 0xcc, 0xe7, 0x22, 0xc3, 0x46, 0x84, 0xe9, 0x83, 0xc4, 0x21, 0xff, 0x99, 0xc5,
0x35, 0x10, 0x57, 0xc5, 0xd2, 0x54, 0x70, 0x6c, 0x16, 0x53, 0xcc, 0x7b, 0x00, 0x74, 0xa3, 0x94, 0x45, 0xc8, 0xd2, 0x8d, 0xd7, 0x98, 0x0a, 0x88, 0xab, 0x62, 0x49, 0xc2, 0x53, 0xac, 0x3f, 0xba,
0x64, 0xd3, 0x42, 0xd1, 0x3c, 0xa0, 0x79, 0x26, 0x78, 0x4e, 0xd1, 0x21, 0x00, 0x99, 0x67, 0x9d, 0x98, 0xbd, 0x7c, 0x2d, 0x38, 0xe3, 0x98, 0x71, 0x0d, 0x75, 0xce, 0x00, 0x1d, 0x49, 0x29, 0xd8,
0xd6, 0xe8, 0xdf, 0xb8, 0x1b, 0x2c, 0x64, 0xd0, 0x1e, 0x6c, 0x51, 0x29, 0x85, 0x74, 0xda, 0xa3, 0xaa, 0x90, 0x34, 0xf7, 0x68, 0x9e, 0xf1, 0x34, 0xa7, 0xe8, 0x2b, 0x00, 0xd9, 0x78, 0xad, 0xce,
0xd6, 0xb8, 0x1b, 0x98, 0xc0, 0x3b, 0x86, 0x9d, 0x47, 0x41, 0x66, 0x01, 0x7d, 0x2f, 0x68, 0xae, 0xac, 0x3b, 0x1f, 0x7a, 0x5b, 0x1e, 0xf4, 0x01, 0xfa, 0x54, 0x08, 0x2e, 0xac, 0x37, 0xb3, 0xce,
0x10, 0x82, 0xff, 0x33, 0xa2, 0x88, 0xd3, 0xd2, 0x1a, 0xbd, 0xf7, 0x2e, 0x60, 0xd7, 0x48, 0x6c, 0x7c, 0xe8, 0x69, 0xc3, 0xf9, 0x0e, 0xef, 0xce, 0x39, 0x09, 0x3c, 0x7a, 0x57, 0xd0, 0x5c, 0x22,
0xa1, 0x35, 0x9a, 0x06, 0xf8, 0x15, 0xf4, 0x9f, 0x49, 0xc2, 0x66, 0x44, 0xd1, 0x0d, 0x05, 0x90, 0x04, 0xbd, 0x80, 0x48, 0x62, 0x75, 0x94, 0x46, 0x9d, 0x9d, 0x3f, 0xf0, 0x5e, 0x4b, 0x4c, 0xa1,
0x03, 0xdb, 0x29, 0x09, 0x63, 0xc6, 0xa9, 0xbd, 0x5e, 0x86, 0xde, 0x35, 0x0c, 0x2a, 0x80, 0x2d, 0x16, 0xcd, 0x1e, 0xf8, 0x3f, 0x18, 0x5f, 0x92, 0x98, 0x05, 0x44, 0xd2, 0x03, 0x05, 0x90, 0x05,
0xbf, 0x0f, 0x1d, 0x4d, 0x2f, 0xff, 0x68, 0xa3, 0x86, 0x27, 0x9c, 0x40, 0xff, 0x8e, 0x71, 0x92, 0x6f, 0x13, 0xe2, 0x47, 0x2c, 0xa5, 0x26, 0xbd, 0x34, 0x9d, 0xff, 0x30, 0xa9, 0x00, 0xa6, 0xfc,
0xb0, 0xaf, 0x4d, 0x4f, 0xf0, 0x2e, 0x61, 0x50, 0xc9, 0xfe, 0xfa, 0xcf, 0xb3, 0xef, 0x36, 0x74, 0x47, 0x18, 0x28, 0x7a, 0xf9, 0x46, 0x63, 0xed, 0xb9, 0xc2, 0x0f, 0x18, 0x9f, 0xb0, 0x94, 0xc4,
0x6e, 0xb5, 0xf1, 0x68, 0x02, 0x03, 0xb3, 0xab, 0x1c, 0x42, 0x43, 0xbf, 0x9a, 0x0e, 0x6d, 0xe3, 0xec, 0xf1, 0xd0, 0x15, 0x9c, 0x05, 0x4c, 0x2a, 0xd9, 0x4b, 0xdf, 0xf9, 0xeb, 0xa9, 0x0b, 0x83,
0x53, 0x91, 0x24, 0xf6, 0x35, 0xae, 0xe7, 0x2f, 0x8f, 0x8e, 0xbf, 0xc6, 0xda, 0x7b, 0x00, 0x03, 0x63, 0xb5, 0x4d, 0x68, 0x09, 0x13, 0x7d, 0xaa, 0x26, 0x84, 0xa6, 0x6e, 0xb5, 0x72, 0x6a, 0x37,
0xfd, 0xf5, 0x61, 0x09, 0xa7, 0x6f, 0x2c, 0x18, 0xe8, 0x1e, 0xac, 0x3f, 0xb4, 0xa0, 0x09, 0xf4, 0x2e, 0x8a, 0x38, 0x36, 0xb7, 0xb1, 0x1d, 0x77, 0x77, 0x1f, 0xdd, 0x96, 0xd1, 0x9e, 0x02, 0x68,
0x0c, 0xa8, 0xec, 0x2a, 0x3a, 0xaa, 0xeb, 0x6b, 0x86, 0xb9, 0xa3, 0x66, 0x41, 0x1d, 0x5a, 0x76, 0xe8, 0x7a, 0x0e, 0x3b, 0x38, 0x95, 0xb1, 0x35, 0x40, 0xfb, 0x4b, 0x7b, 0xd0, 0x80, 0x96, 0x30,
0x70, 0x15, 0x5a, 0xb3, 0x60, 0x15, 0x5a, 0x6f, 0xfe, 0xb4, 0xa3, 0x47, 0xfd, 0xfc, 0x27, 0x00, 0xd2, 0xa0, 0xb2, 0xab, 0xe8, 0x5b, 0x5d, 0x5f, 0x1b, 0x98, 0x3d, 0xdb, 0x2f, 0xa8, 0x43, 0xcb,
0x00, 0xff, 0xff, 0xe0, 0x00, 0xbf, 0x51, 0x76, 0x03, 0x00, 0x00, 0x0e, 0x36, 0xa1, 0xb5, 0x11, 0x34, 0xa1, 0x8d, 0xe6, 0xff, 0x85, 0x9e, 0x47, 0x49, 0x80, 0x3e,
0x6d, 0x94, 0x8c, 0xbb, 0x6b, 0x4f, 0x89, 0xb0, 0x9a, 0x01, 0x93, 0xba, 0x80, 0xfe, 0x95, 0x60,
0x92, 0xa2, 0x1d, 0x89, 0x72, 0x95, 0xc9, 0x9f, 0x5b, 0x22, 0x3a, 0x7b, 0x35, 0x50, 0xff, 0xd8,
0xef, 0xe7, 0x00, 0x00, 0x00, 0xff, 0xff, 0x5f, 0x44, 0xad, 0xc6, 0x44, 0x04, 0x00, 0x00,
} }

View File

@ -2,6 +2,7 @@ syntax = "proto3";
package vagrant.config; package vagrant.config;
import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common/common.proto"; import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common/common.proto";
import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_io/io.proto";
message AttributesResponse { message AttributesResponse {
repeated string attributes = 1; repeated string attributes = 1;
@ -41,4 +42,7 @@ service Config {
rpc ConfigLoad(LoadRequest) returns (LoadResponse); rpc ConfigLoad(LoadRequest) returns (LoadResponse);
rpc ConfigValidate(ValidateRequest) returns (ValidateResponse); rpc ConfigValidate(ValidateRequest) returns (ValidateResponse);
rpc ConfigFinalize(FinalizeRequest) returns (FinalizeResponse); rpc ConfigFinalize(FinalizeRequest) returns (FinalizeResponse);
// These are IO helpers for streaming
rpc Read(vagrant.io.ReadRequest) returns (vagrant.io.ReadResponse);
rpc Write(vagrant.io.WriteRequest) returns (vagrant.io.WriteResponse);
} }

View File

@ -2,6 +2,7 @@ package plugin
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"google.golang.org/grpc" "google.golang.org/grpc"
@ -110,19 +111,26 @@ func (c *GRPCProviderClient) MachineIdChanged(m *vagrant.Machine) (err error) {
return return
} }
func (c *GRPCProviderClient) RunAction(actName string, runData string, m *vagrant.Machine) (r string, err error) { func (c *GRPCProviderClient) RunAction(actName string, args interface{}, m *vagrant.Machine) (r interface{}, err error) {
machData, err := vagrant.DumpMachine(m) machData, err := vagrant.DumpMachine(m)
if err != nil { if err != nil {
return return
} }
runData, err := json.Marshal(args)
if err != nil {
return
}
resp, err := c.client.RunAction(context.Background(), &vagrant_provider.RunActionRequest{ resp, err := c.client.RunAction(context.Background(), &vagrant_provider.RunActionRequest{
Name: actName, Name: actName,
Data: runData, Data: string(runData),
Machine: machData}) Machine: machData})
if err != nil { if err != nil {
return return
} }
r = resp.Data err = json.Unmarshal([]byte(resp.Data), &r)
if err != nil {
return
}
if resp.Error != "" { if resp.Error != "" {
err = errors.New(resp.Error) err = errors.New(resp.Error)
} }
@ -178,10 +186,6 @@ func (c *GRPCProviderClient) Name() string {
return resp.Name return resp.Name
} }
func (p *ProviderPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error {
return nil
}
func (p *ProviderPlugin) GRPCClient(ctx context.Context, broker *go_plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) { func (p *ProviderPlugin) GRPCClient(ctx context.Context, broker *go_plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
client := vagrant_provider.NewProviderClient(c) client := vagrant_provider.NewProviderClient(c)
return &GRPCProviderClient{ return &GRPCProviderClient{
@ -199,12 +203,7 @@ func (p *ProviderPlugin) GRPCClient(ctx context.Context, broker *go_plugin.GRPCB
}, nil }, nil
} }
type GRPCProviderPlugin struct { func (p *ProviderPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error {
ProviderPlugin
Impl Provider
}
func (p *GRPCProviderPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error {
p.Impl.Init() p.Impl.Init()
vagrant_provider.RegisterProviderServer(s, &GRPCProviderServer{ vagrant_provider.RegisterProviderServer(s, &GRPCProviderServer{
Impl: p.Impl, Impl: p.Impl,
@ -221,10 +220,6 @@ func (p *GRPCProviderPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Se
return nil return nil
} }
func (p *GRPCProviderPlugin) GRPCClient(context.Context, *go_plugin.GRPCBroker, *grpc.ClientConn) (interface{}, error) {
return nil, nil
}
type GRPCProviderServer struct { type GRPCProviderServer struct {
GRPCIOServer GRPCIOServer
GRPCConfigServer GRPCConfigServer
@ -257,12 +252,21 @@ func (s *GRPCProviderServer) RunAction(ctx context.Context, req *vagrant_provide
resp.Error = e.Error() resp.Error = e.Error()
return return
} }
r, e := s.Impl.RunAction(req.Name, req.Data, m) var args interface{}
err = json.Unmarshal([]byte(req.Data), &args)
if err != nil {
return
}
r, e := s.Impl.RunAction(req.Name, args, m)
if e != nil { if e != nil {
resp.Error = e.Error() resp.Error = e.Error()
return return
} }
resp.Data = r result, err := json.Marshal(r)
if err != nil {
return
}
resp.Data = string(result)
return return
} }

View File

@ -0,0 +1,313 @@
package plugin
import (
"strings"
"testing"
"github.com/hashicorp/go-plugin"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
)
func TestProvider_Action(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &ProviderPlugin{Impl: &MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
resp, err := impl.Action("valid", &vagrant.Machine{})
if err != nil {
t.Fatalf("bad resp: %s", err)
}
if resp[0] != "self::DoTask" {
t.Errorf("%s != self::DoTask", resp[0])
}
}
func TestProvider_Action_invalid(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &ProviderPlugin{Impl: &MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
_, err = impl.Action("invalid", &vagrant.Machine{})
if err == nil {
t.Errorf("illegal action")
}
}
func TestProvider_IsInstalled(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &ProviderPlugin{Impl: &MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
installed, err := impl.IsInstalled(&vagrant.Machine{})
if err != nil {
t.Fatalf("bad resp: %s", err)
}
if !installed {
t.Errorf("bad result")
}
}
func TestProvider_IsUsable(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &ProviderPlugin{Impl: &MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
usable, err := impl.IsUsable(&vagrant.Machine{})
if err != nil {
t.Fatalf("bad resp: %s", err)
}
if !usable {
t.Errorf("bad result")
}
}
func TestProvider_MachineIdChanged(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &ProviderPlugin{Impl: &MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
err = impl.MachineIdChanged(&vagrant.Machine{})
if err != nil {
t.Errorf("err: %s", err)
}
}
func TestProvider_Name(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &ProviderPlugin{Impl: &MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
resp := impl.Name()
if resp != "mock_provider" {
t.Errorf("%s != mock_provider", resp)
}
}
func TestProvider_RunAction(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &ProviderPlugin{Impl: &MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
args := []string{"test_arg", "other_arg"}
m := &vagrant.Machine{}
resp, err := impl.RunAction("valid", args, m)
if err != nil {
t.Fatalf("bad resp: %s", err)
}
result := resp.([]interface{})
if result[0] != "valid" {
t.Errorf("%s != valid", result[0])
}
if result[1] != "test_arg" {
t.Errorf("%s != test_arg", result[1])
}
}
func TestProvider_RunAction_invalid(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &ProviderPlugin{Impl: &MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
args := []string{"test_arg", "other_arg"}
m := &vagrant.Machine{}
_, err = impl.RunAction("invalid", args, m)
if err == nil {
t.Fatalf("illegal action run")
}
}
func TestProvider_SshInfo(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &ProviderPlugin{Impl: &MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
resp, err := impl.SshInfo(&vagrant.Machine{})
if err != nil {
t.Fatalf("invalid resp: %s", err)
}
if resp.Host != "localhost" {
t.Errorf("%s != localhost", resp.Host)
}
if resp.Port != 2222 {
t.Errorf("%d != 2222", resp.Port)
}
}
func TestProvider_State(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &ProviderPlugin{Impl: &MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
resp, err := impl.State(&vagrant.Machine{})
if err != nil {
t.Fatalf("invalid resp: %s", err)
}
if resp.Id != "default" {
t.Errorf("%s != default", resp.Id)
}
if resp.ShortDesc != "running" {
t.Errorf("%s != running", resp.ShortDesc)
}
}
func TestProvider_Info(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &ProviderPlugin{Impl: &MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
resp := impl.Info()
if resp.Description != "Custom" {
t.Errorf("%s != Custom", resp.Description)
}
if resp.Priority != 10 {
t.Errorf("%d != 10", resp.Priority)
}
}
func TestProvider_MachineUI_output(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"provider": &ProviderPlugin{Impl: &MockProvider{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("provider")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(Provider)
if !ok {
t.Fatalf("bad %#v", raw)
}
go func() {
_, err = impl.RunAction("send_output", nil, &vagrant.Machine{})
if err != nil {
t.Fatalf("bad resp: %s", err)
}
}()
resp, err := impl.Read("stdout")
if err != nil {
t.Fatalf("bad resp: %s", err)
}
if !strings.Contains(resp, "test_output_p") {
t.Errorf("%s !~ test_output_p", resp)
}
}

View File

@ -31,7 +31,7 @@ type GRPCSyncedFolderClient struct {
client vagrant_folder.SyncedFolderClient client vagrant_folder.SyncedFolderClient
} }
func (c *GRPCSyncedFolderClient) Cleanup(m *vagrant.Machine, o *vagrant.FolderOptions) (err error) { func (c *GRPCSyncedFolderClient) Cleanup(m *vagrant.Machine, o vagrant.FolderOptions) (err error) {
machine, err := vagrant.DumpMachine(m) machine, err := vagrant.DumpMachine(m)
if err != nil { if err != nil {
return return
@ -52,7 +52,7 @@ func (c *GRPCSyncedFolderClient) Cleanup(m *vagrant.Machine, o *vagrant.FolderOp
return return
} }
func (c *GRPCSyncedFolderClient) Disable(m *vagrant.Machine, f *vagrant.FolderList, o *vagrant.FolderOptions) (err error) { func (c *GRPCSyncedFolderClient) Disable(m *vagrant.Machine, f vagrant.FolderList, o vagrant.FolderOptions) (err error) {
machine, err := vagrant.DumpMachine(m) machine, err := vagrant.DumpMachine(m)
if err != nil { if err != nil {
return return
@ -78,7 +78,7 @@ func (c *GRPCSyncedFolderClient) Disable(m *vagrant.Machine, f *vagrant.FolderLi
return return
} }
func (c *GRPCSyncedFolderClient) Enable(m *vagrant.Machine, f *vagrant.FolderList, o *vagrant.FolderOptions) (err error) { func (c *GRPCSyncedFolderClient) Enable(m *vagrant.Machine, f vagrant.FolderList, o vagrant.FolderOptions) (err error) {
machine, err := vagrant.DumpMachine(m) machine, err := vagrant.DumpMachine(m)
if err != nil { if err != nil {
return return
@ -136,7 +136,7 @@ func (c *GRPCSyncedFolderClient) Name() string {
return resp.Name return resp.Name
} }
func (c *GRPCSyncedFolderClient) Prepare(m *vagrant.Machine, f *vagrant.FolderList, o *vagrant.FolderOptions) (err error) { func (c *GRPCSyncedFolderClient) Prepare(m *vagrant.Machine, f vagrant.FolderList, o vagrant.FolderOptions) (err error) {
machine, err := vagrant.DumpMachine(m) machine, err := vagrant.DumpMachine(m)
if err != nil { if err != nil {
return return
@ -171,7 +171,7 @@ type GRPCSyncedFolderServer struct {
func (s *GRPCSyncedFolderServer) Cleanup(ctx context.Context, req *vagrant_folder.CleanupRequest) (resp *vagrant_common.EmptyResponse, err error) { func (s *GRPCSyncedFolderServer) Cleanup(ctx context.Context, req *vagrant_folder.CleanupRequest) (resp *vagrant_common.EmptyResponse, err error) {
resp = &vagrant_common.EmptyResponse{} resp = &vagrant_common.EmptyResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil) machine, err := vagrant.LoadMachine(req.Machine, s.Impl)
if err != nil { if err != nil {
return return
} }
@ -180,7 +180,7 @@ func (s *GRPCSyncedFolderServer) Cleanup(ctx context.Context, req *vagrant_folde
if err != nil { if err != nil {
return return
} }
e := s.Impl.Cleanup(machine, &options) e := s.Impl.Cleanup(machine, options)
if e != nil { if e != nil {
resp.Error = e.Error() resp.Error = e.Error()
} }
@ -189,7 +189,7 @@ func (s *GRPCSyncedFolderServer) Cleanup(ctx context.Context, req *vagrant_folde
func (s *GRPCSyncedFolderServer) Disable(ctx context.Context, req *vagrant_folder.Request) (resp *vagrant_common.EmptyResponse, err error) { func (s *GRPCSyncedFolderServer) Disable(ctx context.Context, req *vagrant_folder.Request) (resp *vagrant_common.EmptyResponse, err error) {
resp = &vagrant_common.EmptyResponse{} resp = &vagrant_common.EmptyResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil) machine, err := vagrant.LoadMachine(req.Machine, s.Impl)
if err != nil { if err != nil {
return return
} }
@ -203,7 +203,7 @@ func (s *GRPCSyncedFolderServer) Disable(ctx context.Context, req *vagrant_folde
if err != nil { if err != nil {
return return
} }
e := s.Impl.Disable(machine, &folders, &options) e := s.Impl.Disable(machine, folders, options)
if e != nil { if e != nil {
resp.Error = e.Error() resp.Error = e.Error()
} }
@ -212,7 +212,7 @@ func (s *GRPCSyncedFolderServer) Disable(ctx context.Context, req *vagrant_folde
func (s *GRPCSyncedFolderServer) Enable(ctx context.Context, req *vagrant_folder.Request) (resp *vagrant_common.EmptyResponse, err error) { func (s *GRPCSyncedFolderServer) Enable(ctx context.Context, req *vagrant_folder.Request) (resp *vagrant_common.EmptyResponse, err error) {
resp = &vagrant_common.EmptyResponse{} resp = &vagrant_common.EmptyResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil) machine, err := vagrant.LoadMachine(req.Machine, s.Impl)
if err != nil { if err != nil {
return return
} }
@ -226,7 +226,7 @@ func (s *GRPCSyncedFolderServer) Enable(ctx context.Context, req *vagrant_folder
if err != nil { if err != nil {
return return
} }
e := s.Impl.Enable(machine, &folders, &options) e := s.Impl.Enable(machine, folders, options)
if e != nil { if e != nil {
resp.Error = e.Error() resp.Error = e.Error()
} }
@ -242,7 +242,7 @@ func (s *GRPCSyncedFolderServer) Info(ctx context.Context, req *vagrant_common.N
func (s *GRPCSyncedFolderServer) IsUsable(ctx context.Context, req *vagrant_common.EmptyRequest) (resp *vagrant_common.IsResponse, err error) { func (s *GRPCSyncedFolderServer) IsUsable(ctx context.Context, req *vagrant_common.EmptyRequest) (resp *vagrant_common.IsResponse, err error) {
resp = &vagrant_common.IsResponse{} resp = &vagrant_common.IsResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil) machine, err := vagrant.LoadMachine(req.Machine, s.Impl)
if err != nil { if err != nil {
return return
} }
@ -260,7 +260,7 @@ func (s *GRPCSyncedFolderServer) Name(ctx context.Context, req *vagrant_common.N
func (s *GRPCSyncedFolderServer) Prepare(ctx context.Context, req *vagrant_folder.Request) (resp *vagrant_common.EmptyResponse, err error) { func (s *GRPCSyncedFolderServer) Prepare(ctx context.Context, req *vagrant_folder.Request) (resp *vagrant_common.EmptyResponse, err error) {
resp = &vagrant_common.EmptyResponse{} resp = &vagrant_common.EmptyResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil) machine, err := vagrant.LoadMachine(req.Machine, s.Impl)
if err != nil { if err != nil {
return return
} }
@ -274,7 +274,7 @@ func (s *GRPCSyncedFolderServer) Prepare(ctx context.Context, req *vagrant_folde
if err != nil { if err != nil {
return return
} }
e := s.Impl.Prepare(machine, &folders, &options) e := s.Impl.Prepare(machine, folders, options)
if e != nil { if e != nil {
resp.Error = e.Error() resp.Error = e.Error()
} }
@ -282,10 +282,27 @@ func (s *GRPCSyncedFolderServer) Prepare(ctx context.Context, req *vagrant_folde
} }
func (f *SyncedFolderPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error { func (f *SyncedFolderPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error {
vagrant_folder.RegisterSyncedFolderServer(s, &GRPCSyncedFolderServer{Impl: f.Impl}) f.Impl.Init()
vagrant_folder.RegisterSyncedFolderServer(s,
&GRPCSyncedFolderServer{
Impl: f.Impl,
GRPCIOServer: GRPCIOServer{
Impl: f.Impl},
GRPCGuestCapabilitiesServer: GRPCGuestCapabilitiesServer{
Impl: f.Impl},
GRPCHostCapabilitiesServer: GRPCHostCapabilitiesServer{
Impl: f.Impl}})
return nil return nil
} }
func (f *SyncedFolderPlugin) GRPCClient(ctx context.Context, broker *go_plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) { func (f *SyncedFolderPlugin) GRPCClient(ctx context.Context, broker *go_plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
return &GRPCSyncedFolderClient{client: vagrant_folder.NewSyncedFolderClient(c)}, nil client := vagrant_folder.NewSyncedFolderClient(c)
return &GRPCSyncedFolderClient{
GRPCIOClient: GRPCIOClient{
client: client},
GRPCGuestCapabilitiesClient: GRPCGuestCapabilitiesClient{
client: client},
GRPCHostCapabilitiesClient: GRPCHostCapabilitiesClient{
client: client},
client: client}, nil
} }

View File

@ -0,0 +1,368 @@
package plugin
import (
"errors"
"strings"
"testing"
"github.com/hashicorp/go-plugin"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
)
type MockSyncedFolder struct {
Core
vagrant.NoGuestCapabilities
vagrant.NoHostCapabilities
}
func (s *MockSyncedFolder) Cleanup(m *vagrant.Machine, opts vagrant.FolderOptions) error {
if opts != nil {
err, _ := opts["error"].(bool)
ui, _ := opts["ui"].(bool)
if err {
return errors.New("cleanup error")
}
if ui {
m.UI.Say("test_output_sf")
return nil
}
}
return nil
}
func (s *MockSyncedFolder) Disable(m *vagrant.Machine, f vagrant.FolderList, opts vagrant.FolderOptions) error {
if opts != nil && opts["error"].(bool) {
return errors.New("disable error")
}
return nil
}
func (s *MockSyncedFolder) Enable(m *vagrant.Machine, f vagrant.FolderList, opts vagrant.FolderOptions) error {
if opts != nil && opts["error"].(bool) {
return errors.New("enable error")
}
return nil
}
func (s *MockSyncedFolder) Info() *vagrant.SyncedFolderInfo {
return &vagrant.SyncedFolderInfo{
Description: "mock_folder",
Priority: 100}
}
func (s *MockSyncedFolder) IsUsable(m *vagrant.Machine) (bool, error) {
return true, nil
}
func (s *MockSyncedFolder) Name() string {
return "mock_folder"
}
func (s *MockSyncedFolder) Prepare(m *vagrant.Machine, f vagrant.FolderList, opts vagrant.FolderOptions) error {
if opts != nil && opts["error"].(bool) {
return errors.New("prepare error")
}
return nil
}
func TestSyncedFolder_Cleanup(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &SyncedFolderPlugin{Impl: &MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
err = impl.Cleanup(&vagrant.Machine{}, nil)
if err != nil {
t.Fatalf("bad resp: %s", err)
}
}
func TestSyncedFolder_Cleanup_error(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &SyncedFolderPlugin{Impl: &MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
args := map[string]interface{}{
"error": true}
err = impl.Cleanup(&vagrant.Machine{}, args)
if err == nil {
t.Fatalf("illegal cleanup")
}
if err.Error() != "cleanup error" {
t.Errorf("%s != cleanup error", err.Error())
}
}
func TestSyncedFolder_Disable(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &SyncedFolderPlugin{Impl: &MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
err = impl.Disable(&vagrant.Machine{}, nil, nil)
if err != nil {
t.Fatalf("bad resp: %s", err)
}
}
func TestSyncedFolder_Disable_error(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &SyncedFolderPlugin{Impl: &MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
folders := map[string]interface{}{
"folder_name": "options"}
args := map[string]interface{}{
"error": true}
err = impl.Disable(&vagrant.Machine{}, folders, args)
if err == nil {
t.Fatalf("illegal disable")
}
if err.Error() != "disable error" {
t.Errorf("%s != disable error", err.Error())
}
}
func TestSyncedFolder_Enable(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &SyncedFolderPlugin{Impl: &MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
err = impl.Enable(&vagrant.Machine{}, nil, nil)
if err != nil {
t.Fatalf("bad resp: %s", err)
}
}
func TestSyncedFolder_Enable_error(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &SyncedFolderPlugin{Impl: &MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
folders := map[string]interface{}{
"folder_name": "options"}
args := map[string]interface{}{
"error": true}
err = impl.Enable(&vagrant.Machine{}, folders, args)
if err == nil {
t.Fatalf("illegal enable")
}
if err.Error() != "enable error" {
t.Errorf("%s != enable error", err.Error())
}
}
func TestSyncedFolder_Prepare(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &SyncedFolderPlugin{Impl: &MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
err = impl.Prepare(&vagrant.Machine{}, nil, nil)
if err != nil {
t.Fatalf("bad resp: %s", err)
}
}
func TestSyncedFolder_Prepare_error(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &SyncedFolderPlugin{Impl: &MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
folders := map[string]interface{}{
"folder_name": "options"}
args := map[string]interface{}{
"error": true}
err = impl.Prepare(&vagrant.Machine{}, folders, args)
if err == nil {
t.Fatalf("illegal prepare")
}
if err.Error() != "prepare error" {
t.Errorf("%s != prepare error", err.Error())
}
}
func TestSyncedFolder_Info(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &SyncedFolderPlugin{Impl: &MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
resp := impl.Info()
if resp == nil {
t.Fatalf("bad resp")
}
if resp.Description != "mock_folder" {
t.Errorf("%s != mock_folder", resp.Description)
}
if resp.Priority != 100 {
t.Errorf("%d != 100", resp.Priority)
}
}
func TestSyncedFolder_IsUsable(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &SyncedFolderPlugin{Impl: &MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
resp, err := impl.IsUsable(&vagrant.Machine{})
if err != nil {
t.Fatalf("bad resp: %s", err)
}
if !resp {
t.Errorf("bad result")
}
}
func TestSyncedFolder_Name(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &SyncedFolderPlugin{Impl: &MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
resp := impl.Name()
if resp != "mock_folder" {
t.Errorf("%s != mock_folder", resp)
}
}
func TestSyncedFolder_MachineUI_output(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &SyncedFolderPlugin{Impl: &MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
go func() {
err := impl.Cleanup(&vagrant.Machine{}, map[string]interface{}{"ui": true})
if err != nil {
t.Fatalf("bad resp: %s", err)
}
}()
resp, err := impl.Read("stdout")
if err != nil {
t.Fatalf("bad resp: %s", err)
}
if !strings.Contains(resp, "test_output") {
t.Errorf("%s !~ test_output", resp)
}
}

View File

@ -7,7 +7,7 @@ type Provider interface {
IsUsable(machData *Machine) (bool, error) IsUsable(machData *Machine) (bool, error)
MachineIdChanged(machData *Machine) error MachineIdChanged(machData *Machine) error
Name() string Name() string
RunAction(actionName string, data string, machData *Machine) (string, error) RunAction(actionName string, args interface{}, machData *Machine) (interface{}, error)
SshInfo(machData *Machine) (*SshInfo, error) SshInfo(machData *Machine) (*SshInfo, error)
State(machData *Machine) (*MachineState, error) State(machData *Machine) (*MachineState, error)

View File

@ -1,20 +0,0 @@
package vagrant
import (
"encoding/json"
"fmt"
)
type Response struct {
Error error `json:"error"`
Result interface{} `json:"result"`
}
// Serialize the response into a JSON string
func (r Response) Dump() string {
result, err := json.Marshal(r)
if err != nil {
return fmt.Sprintf(`{"error": "failed to encode response - %s"}`, err)
}
return string(result[:])
}

View File

@ -9,13 +9,13 @@ type SyncedFolderInfo struct {
} }
type SyncedFolder interface { type SyncedFolder interface {
Cleanup(m *Machine, opts *FolderOptions) error Cleanup(m *Machine, opts FolderOptions) error
Disable(m *Machine, f *FolderList, opts *FolderOptions) error Disable(m *Machine, f FolderList, opts FolderOptions) error
Enable(m *Machine, f *FolderList, opts *FolderOptions) error Enable(m *Machine, f FolderList, opts FolderOptions) error
Info() *SyncedFolderInfo Info() *SyncedFolderInfo
IsUsable(m *Machine) (bool, error) IsUsable(m *Machine) (bool, error)
Name() string Name() string
Prepare(m *Machine, f *FolderList, opts *FolderOptions) error Prepare(m *Machine, f FolderList, opts FolderOptions) error
GuestCapabilities GuestCapabilities
HostCapabilities HostCapabilities

View File

@ -6,12 +6,12 @@ module Vagrant
module CapabilityPlugin module CapabilityPlugin
# Wrapper class for go-plugin defined capabilities # Wrapper class for go-plugin defined capabilities
class Capability class Capability
extend TypedGoPlugin include TypedGoPlugin
end end
# @return [Interface] # @return [Interface]
def self.interface def self.interface
unless @_interface if !@_interface
@_interface = Interface.new @_interface = Interface.new
end end
@_interface @_interface

View File

@ -90,12 +90,16 @@ module Vagrant
# Load given data into the provided machine. This is # Load given data into the provided machine. This is
# used to update the machine with data received from # used to update the machine with data received from
# go-plugins # go-plugins. Currently the only modification applied
# is an ID change.
# #
# @param [Hash] data Machine data from go-plugin # @param [Hash] data Machine data from go-plugin
# @param [Vagrant::Machine] machine # @param [Vagrant::Machine] machine
# @return [Vagrant::Machine] # @return [Vagrant::Machine]
def load_machine(data, machine) def load_machine(data, machine)
if data[:id] != machine.id
machine.id = data[:id]
end
machine machine
end end
@ -157,7 +161,7 @@ module Vagrant
# @return [String] # @return [String]
def name def name
go_plugin_name.to_s.capitalize.tr("_", "") go_plugin_name.to_s.split("_").map(&:capitalize).join
end end
end end

View File

@ -7,10 +7,9 @@ module Vagrant
include Util::Logger include Util::Logger
# @return [Manager] # @return [Manager]
def self.instance(env=nil) def self.instance
@instance ||= self.new if !@instance
if env @instance = self.new
@instance.envirnoment = env
end end
@instance @instance
end end

View File

@ -60,31 +60,11 @@ module Vagrant
# provider so that it can be interacted with normally within # provider so that it can be interacted with normally within
# Vagrant # Vagrant
class Provider < Vagrant.plugin("2", :provider) class Provider < Vagrant.plugin("2", :provider)
include DirectGoPlugin
# @return [Vagrant::Machine] # @return [Vagrant::Machine]
attr_reader :machine attr_reader :machine
# @return [String] plugin name associated to this class
def self.go_plugin_name
@go_plugin_name
end
# Set the plugin name for this class
#
# @param [String] n plugin name
# @return [String]
# @note can only be set once
def self.go_plugin_name=(n)
if @go_plugin_name
raise ArgumentError.new("Class plugin name has already been set")
end
@go_plugin_name = n
end
# @return [String]
def self.name
go_plugin_name.to_s.capitalize.tr("_", "")
end
def initialize(machine) def initialize(machine)
@machine = machine @machine = machine
end end
@ -234,21 +214,6 @@ module Vagrant
end end
end end
def capability
end
# Check if provider has requested capability
#
# @param [String] provider_name provider name for request
# @param [String] capability_name name of the capability
# @param [Vagrant::Machine] machine instance of guest
# @return [Boolean]
def has_capability(provider_name, capability_name, machine)
result = load_result { _provider_has_capability(provider_name,
capability_name, dump_machine(machine)) }
result
end
# Check if provider is installed # Check if provider is installed
# #
# @param [String] provider_name provider name for request # @param [String] provider_name provider name for request

View File

@ -0,0 +1,19 @@
require_relative "../../base"
describe Vagrant::GoPlugin::CapabilityPlugin do
describe Vagrant::GoPlugin::CapabilityPlugin::Capability do
it "should be a TypedGoPlugin" do
expect(described_class.ancestors).to include(Vagrant::GoPlugin::TypedGoPlugin)
end
end
describe ".interface" do
it "should create an interface instance" do
expect(described_class.interface).to be_a(Vagrant::GoPlugin::CapabilityHost::Interface)
end
it "should cache generated interface" do
expect(described_class.interface).to be(described_class.interface)
end
end
end

View File

@ -0,0 +1,214 @@
require_relative "../../base"
describe Vagrant::GoPlugin::Core do
include_context "unit"
let(:subject_class) { Class.new.tap { |c| c.include(described_class) } }
let(:subject) { subject_class.new }
let(:name) { "foo" }
let(:provider) { new_provider_mock }
let(:provider_cls) do
obj = double("provider_cls")
allow(obj).to receive(:new).and_return(provider)
obj
end
let(:provider_config) { Object.new }
let(:provider_name) { :test }
let(:provider_options) { {} }
let(:base) { false }
let(:box) do
double("box",
name: "foo",
provider: :dummy,
version: "1.0",
directory: "box dir",
metadata: nil,
metadata_url: nil)
end
let(:config) { env.vagrantfile.config }
let(:data_dir) { Pathname.new(Dir.mktmpdir("vagrant-machine-data-dir")) }
let(:env) do
# We need to create a Vagrantfile so that this test environment
# has a proper root path
test_env.vagrantfile("")
# Create the Vagrant::Environment instance
test_env.create_vagrant_env
end
let(:test_env) { isolated_environment }
let(:machine) {
Vagrant::Machine.new(name, provider_name, provider_cls, provider_config,
provider_options, config, data_dir, box,
env, env.vagrantfile, base)
}
def new_provider_mock
double("provider").tap do |obj|
allow(obj).to receive(:_initialize)
.with(provider_name, anything).and_return(nil)
allow(obj).to receive(:machine_id_changed).and_return(nil)
allow(obj).to receive(:state).and_return(Vagrant::MachineState.new(
:created, "", ""))
end
end
describe "#dump_machine" do
it "should raise error when argument is not a Vagrant Machine" do
expect { subject.dump_machine(:value) }.to raise_error(TypeError)
end
it "should dump machine to JSON string" do
expect(subject.dump_machine(machine)).to be_a(String)
end
it "should dump machine information" do
val = subject.dump_machine(machine)
result = JSON.load(val)
expect(result["name"]).to eq(machine.name)
expect(result["provider_name"]).to eq(machine.provider_name.to_s)
expect(result["data_dir"]).to eq(machine.data_dir.to_s)
end
it "should dump box information" do
val = subject.dump_machine(machine)
result = JSON.load(val)
expect(result["box"]).to_not be_nil
expect(result["box"]["name"]).to eq("foo")
end
it "should dump environment information" do
val = subject.dump_machine(machine)
result = JSON.load(val)
expect(result["environment"]).to_not be_nil
expect(result["environment"]["cwd"]).to eq(machine.env.cwd.to_s)
end
end
describe "#dump_environment" do
it "should dump environment to Hash" do
expect(subject.dump_environment(env)).to be_a(Hash)
end
it "should include environment information" do
result = subject.dump_environment(env)
expect(result[:cwd]).to eq(env.cwd)
expect(result[:data_dir]).to eq(env.data_dir)
end
end
describe "#load_machine" do
it "should set ID if ID has changed" do
expect(machine).to receive(:id=).with("newid")
subject.load_machine({id: "newid"}, machine)
end
it "should not set ID if ID has not changed" do
expect(machine).not_to receive(:id=)
subject.load_machine({id: machine.id}, machine)
end
end
end
describe Vagrant::GoPlugin::DirectGoPlugin do
let(:subject_class) { Class.new.tap { |c| c.include(described_class) } }
let(:subject) { subject_class.new }
describe ".go_plugin_name" do
it "should return nil by default" do
expect(subject_class.go_plugin_name).to be_nil
end
it "should return assigned name when assigned" do
subject_class.go_plugin_name = :test
expect(subject_class.go_plugin_name).to eq(:test)
end
end
describe ".go_plugin_name=" do
it "should allow for setting the plugin name" do
subject_class.go_plugin_name = :test_plugin
expect(subject_class.go_plugin_name).to eq(:test_plugin)
end
it "should raise error when name has already been set" do
subject_class.go_plugin_name = :test_plugin
expect {
subject_class.go_plugin_name = :different_plugin
}.to raise_error(ArgumentError)
end
end
describe ".plugin_name" do
it "should proxy to .go_plugin_name" do
expect(subject_class).to receive(:go_plugin_name)
subject_class.plugin_name
end
end
describe ".name" do
it "should default to empty string" do
expect(subject_class.name).to eq("")
end
it "should camel case the go_plugin_name" do
subject_class.go_plugin_name = "test_vagrant_plugin"
expect(subject_class.name).to eq("TestVagrantPlugin")
end
end
describe "#plugin_name" do
it "should proxy to .go_plugin_name" do
expect(subject_class).to receive(:go_plugin_name)
subject.plugin_name
end
end
end
describe Vagrant::GoPlugin::TypedGoPlugin do
let(:subject_class) { Class.new.tap { |c| c.include(described_class) } }
let(:subject) { subject_class.new }
it "should include DirectGoPlugin" do
expect(subject_class.ancestors).to include(Vagrant::GoPlugin::DirectGoPlugin)
end
describe ".go_plugin_type" do
it "should be nil by default" do
expect(subject_class.go_plugin_type).to be_nil
end
it "should return assigned type when set" do
subject_class.go_plugin_type = "provider"
expect(subject_class.go_plugin_type).to eq("provider")
end
end
describe ".go_plugin_type=" do
it "should allow setting plugin type" do
subject_class.go_plugin_type = "test_type"
expect(subject_class.go_plugin_type).to eq("test_type")
end
it "should convert plugin type value to string" do
subject_class.go_plugin_type = :test_type
expect(subject_class.go_plugin_type).to eq("test_type")
end
it "should raise an error when type has already been set" do
subject_class.go_plugin_type = :test_type
expect {
subject_class.go_plugin_type = :different_type
}.to raise_error(ArgumentError)
end
end
describe "#plugin_type" do
it "should proxy to .go_plugin_type" do
expect(subject_class).to receive(:go_plugin_type)
subject.plugin_type
end
end
end

View File

@ -0,0 +1,56 @@
require_relative "../../base"
describe Vagrant::GoPlugin::Interface do
before do
allow_any_instance_of(described_class).to receive(:_setup)
end
describe "#load_plugins" do
let(:path) { double("path", to_s: "path") }
it "should raise error if path is not a directory" do
expect(File).to receive(:directory?).with(path.to_s).and_return(false)
expect { subject.load_plugins(path) }.to raise_error(ArgumentError)
end
it "should load plugins if path is a directory" do
expect(File).to receive(:directory?).with(path.to_s).and_return(true)
expect(subject).to receive(:_load_plugins).with(path.to_s)
subject.load_plugins(path)
end
end
describe "#register_plugins" do
it "should load Provider and SyncedFolder plugins" do
expect(Vagrant::GoPlugin::ProviderPlugin).to receive_message_chain(:interface, :load!)
expect(Vagrant::GoPlugin::SyncedFolderPlugin).to receive_message_chain(:interface, :load!)
subject.register_plugins
end
end
describe "#setup" do
after { subject }
it "should register at_exit action" do
expect(Kernel).to receive(:at_exit)
subject
end
it "should run the setup action" do
expect_any_instance_of(described_class).to receive(:_setup)
end
it "should only run the setup process once" do
expect_any_instance_of(described_class).to receive(:_setup).once
expect(subject.logger).to receive(:warn)
subject.setup
end
end
describe "#teardown" do
it "should run the teardown action" do
expect(subject).to receive(:_teardown)
subject.teardown
end
end
end

View File

@ -0,0 +1,148 @@
require_relative "../../base"
describe Vagrant::GoPlugin::Manager do
include_context "unit"
let(:env) do
test_env.vagrantfile("")
test_env.create_vagrant_env
end
before do
allow(FileUtils).to receive(:mkdir_p)
end
describe ".instance" do
it "should return instance of manager" do
expect(described_class.instance).to be_a(described_class)
end
it "should cache instance" do
expect(described_class.instance).to be(described_class.instance)
end
end
describe ".new" do
it "should create the installation directory" do
expect(FileUtils).to receive(:mkdir_p).with(Vagrant::GoPlugin::INSTALL_DIRECTORY)
subject
end
it "should create installation temporary directory" do
expect(FileUtils).to receive(:mkdir_p).with(/tmp$/)
subject
end
it "should generate user state file" do
expect(subject.user_file).to be_a(Vagrant::Plugin::StateFile)
end
end
describe "#globalize!" do
let(:entries) { [double("entry1"), double("entry2")] }
before do
allow(File).to receive(:directory?).and_return(false)
allow(Dir).to receive(:glob).and_return(entries)
allow(Vagrant::GoPlugin).to receive_message_chain(:interface, :register_plugins)
end
context "when entries are not directories" do
before { allow(File).to receive(:directory?).and_return(false) }
it "should not load any plugins" do
interface = double("interface", register_plugins: nil)
allow(Vagrant::GoPlugin).to receive(:interface).and_return(interface)
expect(interface).not_to receive(:load_plugins)
subject.globalize!
end
end
context "when entries are directories" do
before { allow(File).to receive(:directory?).and_return(true) }
it "should load all entries" do
expect(Vagrant::GoPlugin).to receive_message_chain(:interface, :load_plugins).with(entries.first)
expect(Vagrant::GoPlugin).to receive_message_chain(:interface, :load_plugins).with(entries.last)
subject.globalize!
end
end
it "should register plugins after loading" do
expect(Vagrant::GoPlugin).to receive_message_chain(:interface, :register_plugins)
subject.globalize!
end
end
describe "#localize!" do
end
describe "#install_plugin" do
let(:plugin_name) { "test_plugin_name" }
let(:remote_source) { double("remote_source") }
let(:downloader) { double("downloader", download!: nil) }
before do
allow(FileUtils).to receive(:mkdir_p)
allow(Dir).to receive(:mktmpdir)
allow(Vagrant::Util::Downloader).to receive(:new).and_return(downloader)
allow(Zip::File).to receive(:open)
end
after { subject.install_plugin(plugin_name, remote_source) }
it "should create plugin directory for plugin name" do
expect(FileUtils).to receive(:mkdir_p).with(/test_plugin_name$/)
end
it "should create a temporary directory to download and unpack" do
expect(Dir).to receive(:mktmpdir).with(/go-plugin/, any_args)
end
it "should download the remote file" do
expect(Dir).to receive(:mktmpdir).with(any_args).and_yield("tmpdir")
expect(downloader).to receive(:download!)
end
it "should unzip the downloaded file" do
expect(Dir).to receive(:mktmpdir).with(any_args).and_yield("tmpdir")
expect(Zip::File).to receive(:open).with(/plugin.zip/)
end
it "should add the plugin to the user file" do
expect(subject.user_file).to receive(:add_go_plugin).and_call_original
expect(subject.user_file.has_go_plugin?("test_plugin_name")).to be_truthy
end
end
describe "#uninstall_plugin" do
let(:plugin_name) { "test_plugin_name" }
before do
allow(File).to receive(:directory?).and_call_original
allow(FileUtils).to receive(:rm_rf)
end
after { subject.uninstall_plugin(plugin_name) }
it "should remove plugin path when installed" do
expect(File).to receive(:directory?).with(/test_plugin_name/).and_return(true)
expect(FileUtils).to receive(:rm_rf).with(/test_plugin_name/)
end
it "should not remove plugin path when not installed" do
expect(File).to receive(:directory?).with(/test_plugin_name/).and_return(false)
expect(FileUtils).not_to receive(:rm_rf).with(/test_plugin_name/)
end
it "should have plugin name removed from user file when installed" do
expect(File).to receive(:directory?).with(/test_plugin_name/).and_return(true)
expect(subject.user_file).to receive(:remove_go_plugin).with(plugin_name)
end
it "should have plugin name removed from user file when not installed" do
expect(File).to receive(:directory?).with(/test_plugin_name/).and_return(false)
expect(subject.user_file).to receive(:remove_go_plugin).with(plugin_name)
end
end
end

View File

@ -0,0 +1,29 @@
require_relative "../base"
describe Vagrant::GoPlugin do
describe "INSTALL_DIRECTORY constant" do
let(:subject) { described_class.const_get(:INSTALL_DIRECTORY) }
it "should be a String" do
expect(subject).to be_a(String)
end
it "should be frozen" do
expect(subject).to be_frozen
end
it "should be within the user data path" do
expect(subject).to start_with(Vagrant.user_data_path.to_s)
end
end
describe ".interface" do
it "should return an interface instance" do
expect(described_class.interface).to be_a(Vagrant::GoPlugin::Interface)
end
it "should cache the interface instance" do
expect(described_class.interface).to be(described_class.interface)
end
end
end