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
func GuestCapabilities(pluginName, pluginType *C.char) *C.char {
r := vagrant.Response{}
p, err := getGuestCapsPlugin(pluginName, pluginType)
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
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()
return C.CString(r.Dump())
return r.Dump()
}
//export GuestCapability
func GuestCapability(pluginName, pluginType, cname, cplatform, cargs, cmachine *C.char) *C.char {
r := vagrant.Response{}
p, err := getGuestCapsPlugin(pluginName, pluginType)
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
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 {
r.Error = err
return C.CString(r.Dump())
return r.Dump()
}
var args interface{}
err = json.Unmarshal([]byte(C.GoString(cargs)), &args)
err = json.Unmarshal([]byte(to_gs(cargs)), &args)
if err != nil {
r.Error = err
return C.CString(r.Dump())
return r.Dump()
}
cap := &vagrant.SystemCapability{
Name: C.GoString(cname),
Platform: C.GoString(cplatform)}
Name: to_gs(cname),
Platform: to_gs(cplatform)}
r.Result, r.Error = p.GuestCapabilities.GuestCapability(cap, args, machine)
return C.CString(r.Dump())
return r.Dump()
}
//export HostCapabilities
func HostCapabilities(pluginName, pluginType *C.char) *C.char {
r := vagrant.Response{}
p, err := getHostCapsPlugin(pluginName, pluginType)
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
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()
return C.CString(r.Dump())
return r.Dump()
}
//export HostCapability
func HostCapability(pluginName, pluginType, cname, cplatform, cargs, cenv *C.char) *C.char {
r := vagrant.Response{}
p, err := getHostCapsPlugin(pluginName, pluginType)
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
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 {
r.Error = err
return C.CString(r.Dump())
return r.Dump()
}
var args interface{}
err = json.Unmarshal([]byte(C.GoString(cargs)), &args)
err = json.Unmarshal([]byte(to_gs(cargs)), &args)
if err != nil {
r.Error = err
return C.CString(r.Dump())
return r.Dump()
}
cap := &vagrant.SystemCapability{
Name: C.GoString(cname),
Platform: C.GoString(cplatform)}
Name: to_gs(cname),
Platform: to_gs(cplatform)}
r.Result, r.Error = p.HostCapabilities.HostCapability(cap, args, env)
return C.CString(r.Dump())
return r.Dump()
}
//export ProviderCapabilities
func ProviderCapabilities(pluginName, pluginType *C.char) *C.char {
r := vagrant.Response{}
p, err := getProviderCapsPlugin(pluginName, pluginType)
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
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()
return C.CString(r.Dump())
return r.Dump()
}
//export ProviderCapability
func ProviderCapability(pluginName, pluginType, cname, cprovider, cargs, cmach *C.char) *C.char {
r := vagrant.Response{}
p, err := getProviderCapsPlugin(pluginName, pluginType)
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
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 {
r.Error = err
return C.CString(r.Dump())
return r.Dump()
}
var args interface{}
err = json.Unmarshal([]byte(C.GoString(cargs)), &args)
err = json.Unmarshal([]byte(to_gs(cargs)), &args)
if err != nil {
r.Error = err
return C.CString(r.Dump())
return r.Dump()
}
cap := &vagrant.ProviderCapability{
Name: C.GoString(cname),
Provider: C.GoString(cprovider)}
Name: to_gs(cname),
Provider: to_gs(cprovider)}
r.Result, r.Error = p.ProviderCapabilities.ProviderCapability(cap, args, m)
return C.CString(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
return r.Dump()
}

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"
"encoding/json"
"errors"
"fmt"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin"
@ -12,87 +11,87 @@ import (
//export ConfigLoad
func ConfigLoad(pluginName, pluginType, data *C.char) *C.char {
r := vagrant.Response{}
p, err := getConfigPlugin(pluginName, pluginType)
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
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{}
r.Error = json.Unmarshal([]byte(C.GoString(data)), &cdata)
r.Error = json.Unmarshal([]byte(to_gs(data)), &cdata)
if r.Error != nil {
return C.CString(r.Dump())
return r.Dump()
}
r.Result, r.Error = p.Config.ConfigLoad(cdata)
return C.CString(r.Dump())
return r.Dump()
}
//export ConfigAttributes
func ConfigAttributes(pluginName, pluginType *C.char) *C.char {
r := vagrant.Response{}
p, err := getConfigPlugin(pluginName, pluginType)
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
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()
return C.CString(r.Dump())
return r.Dump()
}
//export ConfigValidate
func ConfigValidate(pluginName, pluginType, data, machData *C.char) *C.char {
var m *vagrant.Machine
r := vagrant.Response{}
p, err := getConfigPlugin(pluginName, pluginType)
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
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{}
r.Error = json.Unmarshal([]byte(C.GoString(data)), &cdata)
r.Error = json.Unmarshal([]byte(to_gs(data)), &cdata)
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 {
return C.CString(r.Dump())
return r.Dump()
}
r.Result, r.Error = p.Config.ConfigValidate(cdata, m)
return C.CString(r.Dump())
return r.Dump()
}
//export ConfigFinalize
func ConfigFinalize(pluginName, pluginType, data *C.char) *C.char {
r := vagrant.Response{}
p, err := getConfigPlugin(pluginName, pluginType)
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
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{}
r.Error = json.Unmarshal([]byte(C.GoString(data)), &cdata)
r.Error = json.Unmarshal([]byte(to_gs(data)), &cdata)
if r.Error == nil {
println("FINALIZE HAS VALID CONFIG")
r.Result, r.Error = p.Config.ConfigFinalize(cdata)
}
fmt.Printf("Full result: %s\n", 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
return r.Dump()
}

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
func Setup(enableLogger, timestamps bool, logLevel *C.char) bool {
lvl := C.GoString(logLevel)
lvl := to_gs(logLevel)
lopts := &hclog.LoggerOptions{Name: "vagrant"}
if enableLogger {
lopts.Output = os.Stderr
@ -32,10 +32,7 @@ func Setup(enableLogger, timestamps bool, logLevel *C.char) bool {
return false
}
Plugins = &plugin.VagrantPlugin{
PluginDirectories: []string{},
Providers: map[string]*plugin.RemoteProvider{},
Logger: vagrant.DefaultLogger().Named("go-plugin")}
Plugins = plugin.VagrantPluginInit()
return true
}
@ -46,7 +43,7 @@ func LoadPlugins(plgpath *C.char) bool {
return false
}
p := C.GoString(plgpath)
p := to_gs(plgpath)
err := Plugins.LoadPlugins(p)
if err != nil {
Plugins.Logger.Error("failed loading plugins",
@ -86,3 +83,13 @@ func Teardown() {
// stub required for build
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"
"encoding/json"
"errors"
"fmt"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin"
@ -13,169 +12,176 @@ import (
//export ListProviders
func ListProviders() *C.char {
list := map[string]interface{}{}
r := vagrant.Response{Result: list}
r := &Response{Result: list}
if Plugins == nil {
return C.CString(r.Dump())
return r.Dump()
}
for n, p := range Plugins.Providers {
list[n] = p.Provider.Info()
}
r.Result = list
return C.CString(r.Dump())
return r.Dump()
}
//export ProviderAction
func ProviderAction(providerName *C.char, actionName *C.char, machData *C.char) *C.char {
var p *plugin.RemoteProvider
var m *vagrant.Machine
r := vagrant.Response{}
p, r.Error = getProvider(providerName)
if r.Error != nil {
return C.CString(r.Dump())
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r.Error = err
return r.Dump()
}
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil)
if r.Error != nil {
return C.CString(r.Dump())
p, ok := i.(*plugin.RemoteProvider)
if !ok {
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)
return C.CString(r.Dump())
return r.Dump()
}
//export ProviderIsInstalled
func ProviderIsInstalled(providerName *C.char, machData *C.char) *C.char {
var p *plugin.RemoteProvider
var m *vagrant.Machine
r := vagrant.Response{}
p, r.Error = getProvider(providerName)
if r.Error != nil {
return C.CString(r.Dump())
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r.Error = err
return r.Dump()
}
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil)
if r.Error != nil {
return C.CString(r.Dump())
p, ok := i.(*plugin.RemoteProvider)
if !ok {
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)
return C.CString(r.Dump())
return r.Dump()
}
//export ProviderIsUsable
func ProviderIsUsable(providerName *C.char, machData *C.char) *C.char {
var p *plugin.RemoteProvider
var m *vagrant.Machine
r := vagrant.Response{}
p, r.Error = getProvider(providerName)
if r.Error != nil {
return C.CString(r.Dump())
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r.Error = err
return r.Dump()
}
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil)
if r.Error != nil {
return C.CString(r.Dump())
p, ok := i.(*plugin.RemoteProvider)
if !ok {
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)
return C.CString(r.Dump())
return r.Dump()
}
//export ProviderMachineIdChanged
func ProviderMachineIdChanged(providerName *C.char, machData *C.char) *C.char {
var p *plugin.RemoteProvider
var m *vagrant.Machine
r := vagrant.Response{}
p, r.Error = getProvider(providerName)
if r.Error != nil {
return C.CString(r.Dump())
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r.Error = err
return r.Dump()
}
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil)
if r.Error != nil {
return C.CString(r.Dump())
p, ok := i.(*plugin.RemoteProvider)
if !ok {
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)
return C.CString(r.Dump())
return r.Dump()
}
//export ProviderRunAction
func ProviderRunAction(providerName *C.char, actName *C.char, runData *C.char, machData *C.char) *C.char {
var p *plugin.RemoteProvider
var m *vagrant.Machine
r := vagrant.Response{}
p, r.Error = getProvider(providerName)
if r.Error != nil {
return C.CString(r.Dump())
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r.Error = err
return r.Dump()
}
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil)
if r.Error != nil {
return C.CString(r.Dump())
p, ok := i.(*plugin.RemoteProvider)
if !ok {
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)
return C.CString(r.Dump())
return r.Dump()
}
//export ProviderSshInfo
func ProviderSshInfo(providerName *C.char, machData *C.char) *C.char {
var p *plugin.RemoteProvider
var m *vagrant.Machine
r := vagrant.Response{}
p, r.Error = getProvider(providerName)
if r.Error != nil {
return C.CString(r.Dump())
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r.Error = err
return r.Dump()
}
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil)
if r.Error != nil {
return C.CString(r.Dump())
p, ok := i.(*plugin.RemoteProvider)
if !ok {
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)
return C.CString(r.Dump())
return r.Dump()
}
//export ProviderState
func ProviderState(providerName *C.char, machData *C.char) *C.char {
var p *plugin.RemoteProvider
var m *vagrant.Machine
r := vagrant.Response{}
p, r.Error = getProvider(providerName)
if r.Error != nil {
return C.CString(r.Dump())
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r.Error = err
return r.Dump()
}
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil)
if r.Error != nil {
return C.CString(r.Dump())
p, ok := i.(*plugin.RemoteProvider)
if !ok {
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)
return C.CString(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
return r.Dump()
}

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

View File

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

View File

@ -6,3 +6,10 @@ type Config interface {
ConfigValidate(data map[string]interface{}, m *Machine) (errors []string, 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 (
"errors"
"fmt"
"os"
"os/exec"
@ -11,6 +12,13 @@ import (
"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 {
Client *go_plugin.Client
Config vagrant.Config
@ -45,9 +53,36 @@ type VagrantPlugin struct {
Providers map[string]*RemoteProvider
SyncedFolders map[string]*RemoteSyncedFolder
PluginDirectories []string
PluginLookup func(name, kind string) (p interface{}, err error)
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 {
for _, p := range v.PluginDirectories {
if p == pluginPath {
@ -78,12 +113,8 @@ func (v *VagrantPlugin) LoadProviders(pluginPath string) error {
client := go_plugin.NewClient(&go_plugin.ClientConfig{
AllowedProtocols: []go_plugin.Protocol{go_plugin.ProtocolGRPC},
Logger: v.Logger,
HandshakeConfig: go_plugin.HandshakeConfig{
MagicCookieKey: "BASIC_PLUGIN",
MagicCookieValue: "hello",
ProtocolVersion: 1,
},
Cmd: exec.Command(providerPath),
HandshakeConfig: Handshake,
Cmd: exec.Command(providerPath),
VersionedPlugins: map[int]go_plugin.PluginSet{
2: {"provider": &ProviderPlugin{}}}})
gclient, err := client.Client()
@ -121,12 +152,8 @@ func (v *VagrantPlugin) LoadSyncedFolders(pluginPath string) error {
client := go_plugin.NewClient(&go_plugin.ClientConfig{
AllowedProtocols: []go_plugin.Protocol{go_plugin.ProtocolGRPC},
Logger: v.Logger,
HandshakeConfig: go_plugin.HandshakeConfig{
MagicCookieKey: "BASIC_PLUGIN",
MagicCookieValue: "hello",
ProtocolVersion: 1,
},
Cmd: exec.Command(folderPath),
HandshakeConfig: Handshake,
Cmd: exec.Command(folderPath),
VersionedPlugins: map[int]go_plugin.PluginSet{
2: {"synced_folders": &SyncedFolderPlugin{}}}})
gclient, err := client.Client()

View File

@ -5,6 +5,8 @@ import (
"encoding/json"
"errors"
"google.golang.org/grpc"
go_plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_caps"
@ -21,6 +23,23 @@ type GuestCapabilitiesPlugin struct {
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 {
GRPCIOServer
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) {
resp = &vagrant_caps.GuestCapabilityResponse{}
var args interface{}
err = json.Unmarshal([]byte(req.Arguments), args)
if err != nil {
if err = json.Unmarshal([]byte(req.Arguments), &args); err != nil {
return
}
machine, err := vagrant.LoadMachine(req.Machine, s.Impl)
@ -67,6 +85,8 @@ func (s *GRPCGuestCapabilitiesServer) GuestCapability(ctx context.Context, req *
}
type GRPCGuestCapabilitiesClient struct {
GRPCCoreClient
GRPCIOClient
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},
Machine: m,
Arguments: string(a)})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
return
}
err = json.Unmarshal([]byte(resp.Result), &result)
return
}
@ -111,6 +138,28 @@ type HostCapabilities interface {
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 {
GRPCIOServer
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) {
resp = &vagrant_caps.HostCapabilityResponse{}
var args interface{}
err = json.Unmarshal([]byte(req.Arguments), args)
if err != nil {
if err = json.Unmarshal([]byte(req.Arguments), &args); err != nil {
return
}
env, err := vagrant.LoadEnvironment(req.Environment, s.Impl)
@ -157,6 +205,8 @@ func (s *GRPCHostCapabilitiesServer) HostCapability(ctx context.Context, req *va
}
type GRPCHostCapabilitiesClient struct {
GRPCCoreClient
GRPCIOClient
client vagrant_caps.HostCapabilitiesClient
}
@ -194,6 +244,9 @@ func (c *GRPCHostCapabilitiesClient) HostCapability(cap *vagrant.SystemCapabilit
Platform: cap.Platform},
Environment: e,
Arguments: string(a)})
if err != nil {
return
}
err = json.Unmarshal([]byte(resp.Result), &result)
return
}
@ -203,6 +256,28 @@ type ProviderCapabilities interface {
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 {
GRPCIOServer
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) {
resp = &vagrant_caps.ProviderCapabilityResponse{}
var args interface{}
err = json.Unmarshal([]byte(req.Arguments), args)
err = json.Unmarshal([]byte(req.Arguments), &args)
if err != nil {
return
}
@ -249,6 +324,8 @@ func (s *GRPCProviderCapabilitiesServer) ProviderCapability(ctx context.Context,
}
type GRPCProviderCapabilitiesClient struct {
GRPCCoreClient
GRPCIOClient
client vagrant_caps.ProviderCapabilitiesClient
}
@ -286,6 +363,9 @@ func (c *GRPCProviderCapabilitiesClient) ProviderCapability(cap *vagrant.Provide
Provider: cap.Provider},
Machine: m,
Arguments: string(a)})
if err != nil {
return
}
err = json.Unmarshal([]byte(resp.Result), &result)
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"
"errors"
"google.golang.org/grpc"
go_plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common"
@ -21,6 +23,23 @@ type ConfigPlugin struct {
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 {
GRPCIOServer
Impl Config
@ -104,6 +123,8 @@ func (s *GRPCConfigServer) ConfigFinalize(ctx context.Context, req *vagrant_conf
}
type GRPCConfigClient struct {
GRPCCoreClient
GRPCIOClient
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"
)
type IO interface {
vagrant.StreamIO
}
type IOPlugin struct {
go_plugin.NetRPCUnsupportedPlugin
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 math "math"
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 (
context "golang.org/x/net/context"
@ -535,6 +536,9 @@ const _ = grpc.SupportPackageIsVersion4
type GuestCapabilitiesClient interface {
GuestCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*CapabilitiesResponse, 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 {
@ -563,10 +567,31 @@ func (c *guestCapabilitiesClient) GuestCapability(ctx context.Context, in *Guest
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.
type GuestCapabilitiesServer interface {
GuestCapabilities(context.Context, *vagrant_common.NullRequest) (*CapabilitiesResponse, 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) {
@ -609,6 +634,42 @@ func _GuestCapabilities_GuestCapability_Handler(srv interface{}, ctx context.Con
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{
ServiceName: "vagrant.caps.GuestCapabilities",
HandlerType: (*GuestCapabilitiesServer)(nil),
@ -621,6 +682,14 @@ var _GuestCapabilities_serviceDesc = grpc.ServiceDesc{
MethodName: "GuestCapability",
Handler: _GuestCapabilities_GuestCapability_Handler,
},
{
MethodName: "Read",
Handler: _GuestCapabilities_Read_Handler,
},
{
MethodName: "Write",
Handler: _GuestCapabilities_Write_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "vagrant_caps/capabilities.proto",
@ -632,6 +701,9 @@ var _GuestCapabilities_serviceDesc = grpc.ServiceDesc{
type HostCapabilitiesClient interface {
HostCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*CapabilitiesResponse, 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 {
@ -660,10 +732,31 @@ func (c *hostCapabilitiesClient) HostCapability(ctx context.Context, in *HostCap
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.
type HostCapabilitiesServer interface {
HostCapabilities(context.Context, *vagrant_common.NullRequest) (*CapabilitiesResponse, 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) {
@ -706,6 +799,42 @@ func _HostCapabilities_HostCapability_Handler(srv interface{}, ctx context.Conte
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{
ServiceName: "vagrant.caps.HostCapabilities",
HandlerType: (*HostCapabilitiesServer)(nil),
@ -718,6 +847,14 @@ var _HostCapabilities_serviceDesc = grpc.ServiceDesc{
MethodName: "HostCapability",
Handler: _HostCapabilities_HostCapability_Handler,
},
{
MethodName: "Read",
Handler: _HostCapabilities_Read_Handler,
},
{
MethodName: "Write",
Handler: _HostCapabilities_Write_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "vagrant_caps/capabilities.proto",
@ -729,6 +866,9 @@ var _HostCapabilities_serviceDesc = grpc.ServiceDesc{
type ProviderCapabilitiesClient interface {
ProviderCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*ProviderCapabilitiesResponse, 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 {
@ -757,10 +897,31 @@ func (c *providerCapabilitiesClient) ProviderCapability(ctx context.Context, in
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.
type ProviderCapabilitiesServer interface {
ProviderCapabilities(context.Context, *vagrant_common.NullRequest) (*ProviderCapabilitiesResponse, 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) {
@ -803,6 +964,42 @@ func _ProviderCapabilities_ProviderCapability_Handler(srv interface{}, ctx conte
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{
ServiceName: "vagrant.caps.ProviderCapabilities",
HandlerType: (*ProviderCapabilitiesServer)(nil),
@ -815,6 +1012,14 @@ var _ProviderCapabilities_serviceDesc = grpc.ServiceDesc{
MethodName: "ProviderCapability",
Handler: _ProviderCapabilities_ProviderCapability_Handler,
},
{
MethodName: "Read",
Handler: _ProviderCapabilities_Read_Handler,
},
{
MethodName: "Write",
Handler: _ProviderCapabilities_Write_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "vagrant_caps/capabilities.proto",
@ -823,37 +1028,40 @@ var _ProviderCapabilities_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("vagrant_caps/capabilities.proto", fileDescriptor_591a3013bd09a9cb) }
var fileDescriptor_591a3013bd09a9cb = []byte{
// 510 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x95, 0xcf, 0x6e, 0xd3, 0x40,
0x10, 0xc6, 0xb5, 0x14, 0x0a, 0x9d, 0x56, 0xfc, 0x59, 0x85, 0x60, 0x4c, 0x25, 0x22, 0x53, 0x44,
0x84, 0x84, 0x2d, 0x85, 0x0b, 0x87, 0x1e, 0x90, 0xa8, 0x28, 0xe2, 0x80, 0x50, 0xe0, 0x56, 0x89,
0x6a, 0x63, 0x16, 0x7b, 0x91, 0xbd, 0x6b, 0x76, 0xd7, 0x11, 0xe5, 0x11, 0xb8, 0x71, 0xe0, 0x8d,
0xb8, 0xf0, 0x16, 0x3c, 0x0a, 0xb2, 0xbd, 0x71, 0xed, 0x7a, 0x5d, 0x97, 0xd2, 0x53, 0x32, 0x93,
0x99, 0xf9, 0xe6, 0xfb, 0xd9, 0x9a, 0xc0, 0xfd, 0x25, 0x89, 0x24, 0xe1, 0xfa, 0x30, 0x24, 0x99,
0x0a, 0x42, 0x92, 0x91, 0x05, 0x4b, 0x98, 0x66, 0x54, 0xf9, 0x99, 0x14, 0x5a, 0xe0, 0x2d, 0x53,
0xe0, 0x17, 0x05, 0xee, 0x41, 0xc4, 0x74, 0x9c, 0x2f, 0xfc, 0x50, 0xa4, 0x41, 0x4c, 0x54, 0xcc,
0x42, 0x21, 0xb3, 0xc0, 0x94, 0x04, 0xf4, 0xab, 0x0e, 0x22, 0xf1, 0x24, 0x4b, 0xf2, 0x88, 0xf1,
0x3a, 0x6b, 0xc2, 0x72, 0x5c, 0x50, 0xcb, 0x89, 0x34, 0x15, 0x3c, 0xa8, 0x3e, 0x2a, 0x29, 0x6f,
0x17, 0xe0, 0xc5, 0x6a, 0x81, 0x23, 0x8c, 0xe1, 0x32, 0x27, 0x29, 0x75, 0xd0, 0x04, 0x4d, 0x37,
0xe6, 0xe5, 0x77, 0xec, 0xc2, 0xb5, 0x2c, 0x21, 0xfa, 0x93, 0x90, 0xa9, 0x73, 0xa9, 0xcc, 0xd7,
0xb1, 0xb7, 0x07, 0xf8, 0xad, 0x14, 0x4b, 0xf6, 0x91, 0xca, 0x33, 0x4c, 0x31, 0x95, 0xf5, 0x14,
0x13, 0x7b, 0xdf, 0x60, 0xbb, 0x33, 0x85, 0x51, 0x35, 0xa7, 0x2a, 0x13, 0x5c, 0x51, 0xbc, 0x07,
0x5b, 0x4d, 0x48, 0x0e, 0x9a, 0xac, 0x4d, 0x37, 0x67, 0x13, 0xbf, 0x49, 0xc9, 0xef, 0xee, 0x31,
0x6f, 0x75, 0xe1, 0x11, 0x5c, 0xa1, 0x52, 0x8a, 0x95, 0x7c, 0x15, 0x78, 0x3f, 0x11, 0xdc, 0xb5,
0xb4, 0xd2, 0x2f, 0x39, 0x55, 0x1a, 0x3f, 0x07, 0xa8, 0x67, 0x1c, 0x95, 0x7e, 0xce, 0xa2, 0xdb,
0xe8, 0xc1, 0x0e, 0x5c, 0x4d, 0x49, 0x18, 0x33, 0x4e, 0x8d, 0xee, 0x2a, 0xc4, 0xdb, 0xb0, 0x41,
0x64, 0x94, 0xa7, 0x94, 0x6b, 0xe5, 0xac, 0x95, 0xbf, 0x1d, 0x27, 0xbc, 0xd7, 0xe0, 0xda, 0xd6,
0x32, 0x44, 0xc6, 0xb0, 0x2e, 0xa9, 0xca, 0x13, 0x6d, 0x18, 0x9b, 0xa8, 0xc7, 0xe3, 0x67, 0x18,
0x59, 0xb9, 0xee, 0x5a, 0xb9, 0x3a, 0x6d, 0x7f, 0xff, 0xc8, 0xf3, 0x3b, 0x82, 0xf1, 0x7e, 0xc1,
0xae, 0x0b, 0xf3, 0x99, 0x05, 0x66, 0xbf, 0xd8, 0x45, 0x40, 0xdc, 0x87, 0x3b, 0x9d, 0x5d, 0xce,
0x45, 0xf0, 0x07, 0x82, 0xdb, 0xaf, 0xc4, 0xc5, 0x9a, 0x9a, 0xc0, 0x26, 0xe5, 0x4b, 0x26, 0x05,
0x2f, 0x96, 0x35, 0x7a, 0xcd, 0xd4, 0x80, 0xb9, 0x97, 0x30, 0x3e, 0xb9, 0xd2, 0x79, 0xbc, 0xcd,
0x7e, 0x23, 0xb8, 0xd5, 0xa6, 0x54, 0x3c, 0xdd, 0xf7, 0xb6, 0xe4, 0xbd, 0x63, 0x63, 0xd5, 0x0d,
0x79, 0x93, 0x27, 0x89, 0x21, 0xe1, 0x7a, 0x3d, 0xae, 0x9b, 0x6f, 0xdc, 0x07, 0xb8, 0x71, 0xe2,
0x81, 0xe0, 0x9d, 0x76, 0x9b, 0xfd, 0xdd, 0x71, 0x1f, 0x0e, 0x54, 0x55, 0xf3, 0x67, 0xbf, 0x10,
0xdc, 0x6c, 0x41, 0x29, 0xb6, 0x7e, 0x67, 0xc9, 0xfd, 0xb7, 0x93, 0x03, 0xb8, 0xde, 0xa6, 0x8f,
0x1f, 0xb4, 0xbb, 0xac, 0xaf, 0x8b, 0xbb, 0x73, 0x7a, 0x91, 0xb1, 0xf1, 0x07, 0xc1, 0xc8, 0x76,
0x11, 0xf1, 0x61, 0x4f, 0xfe, 0x54, 0x3b, 0x8f, 0x07, 0x0e, 0x56, 0xd3, 0x56, 0x64, 0x3d, 0xe8,
0x8f, 0x06, 0x4f, 0x9e, 0x91, 0x9a, 0x0e, 0x17, 0x56, 0x42, 0x8b, 0xf5, 0xf2, 0xef, 0xe7, 0xe9,
0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7b, 0xfc, 0x96, 0xa9, 0x0c, 0x07, 0x00, 0x00,
// 560 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x95, 0x4d, 0x6f, 0xd3, 0x30,
0x18, 0xc7, 0x95, 0xee, 0x05, 0xf6, 0x6c, 0xe2, 0xc5, 0x2a, 0x5d, 0x16, 0x26, 0x51, 0x85, 0x21,
0x2a, 0x24, 0x12, 0xa9, 0x5c, 0x40, 0xda, 0x01, 0x89, 0x89, 0x21, 0x0e, 0x08, 0x75, 0x48, 0x1c,
0x26, 0x31, 0xb9, 0x9d, 0x49, 0x8d, 0x12, 0x3b, 0xd8, 0x4e, 0xc5, 0xf8, 0x08, 0xdc, 0x38, 0xf0,
0x71, 0xb8, 0xf0, 0x2d, 0xf8, 0x36, 0x28, 0x89, 0x93, 0x25, 0x8b, 0xbb, 0x8c, 0xad, 0xd2, 0x4e,
0xed, 0xf3, 0xf8, 0x79, 0xfb, 0xff, 0xec, 0xd8, 0xf0, 0x60, 0x86, 0x03, 0x81, 0x99, 0x3a, 0x9a,
0xe0, 0x58, 0xfa, 0x13, 0x1c, 0xe3, 0x31, 0x0d, 0xa9, 0xa2, 0x44, 0x7a, 0xb1, 0xe0, 0x8a, 0xa3,
0x0d, 0x1d, 0xe0, 0xa5, 0x01, 0xce, 0x61, 0x40, 0xd5, 0x34, 0x19, 0x7b, 0x13, 0x1e, 0xf9, 0x53,
0x2c, 0xa7, 0x74, 0xc2, 0x45, 0xec, 0xeb, 0x10, 0x9f, 0x7c, 0x53, 0x7e, 0xc0, 0x9f, 0xc6, 0x61,
0x12, 0x50, 0x56, 0x7a, 0xb5, 0x99, 0x95, 0xf3, 0xcb, 0x76, 0x3c, 0x8a, 0x38, 0xf3, 0xf3, 0x9f,
0xbc, 0x95, 0x73, 0xb0, 0xa8, 0xe2, 0x94, 0xfb, 0x94, 0xe7, 0x45, 0xdd, 0x5d, 0x80, 0x57, 0x85,
0xaa, 0x13, 0x84, 0x60, 0x99, 0xe1, 0x88, 0xd8, 0x56, 0xdf, 0x1a, 0xac, 0x8d, 0xb2, 0xff, 0xc8,
0x81, 0x9b, 0x71, 0x88, 0xd5, 0x67, 0x2e, 0x22, 0xbb, 0x93, 0xf9, 0x4b, 0xdb, 0xdd, 0x03, 0xf4,
0x5e, 0xf0, 0x19, 0x3d, 0x26, 0xe2, 0x02, 0x55, 0x74, 0x64, 0x59, 0x45, 0xdb, 0xee, 0x77, 0xd8,
0x6e, 0x54, 0xa1, 0x44, 0x8e, 0x88, 0x8c, 0x39, 0x93, 0x04, 0xed, 0xc1, 0x46, 0x95, 0xbc, 0x6d,
0xf5, 0x97, 0x06, 0xeb, 0xc3, 0xbe, 0x57, 0x45, 0xef, 0x35, 0xe7, 0x18, 0xd5, 0xb2, 0x50, 0x17,
0x56, 0x88, 0x10, 0xbc, 0x68, 0x9f, 0x1b, 0xee, 0x2f, 0x0b, 0xb6, 0x0c, 0xa9, 0xe4, 0x6b, 0x42,
0xa4, 0x42, 0x2f, 0x01, 0xca, 0x1a, 0x27, 0x99, 0x9e, 0x8b, 0xf4, 0xad, 0xe4, 0x20, 0x1b, 0x6e,
0x44, 0x78, 0x32, 0xa5, 0x8c, 0xe8, 0xbe, 0x85, 0x89, 0xb6, 0x61, 0x0d, 0x8b, 0x20, 0x89, 0x08,
0x53, 0xd2, 0x5e, 0xca, 0xd6, 0x4e, 0x1d, 0xee, 0x5b, 0x70, 0x4c, 0x63, 0x69, 0x22, 0x3d, 0x58,
0x15, 0x44, 0x26, 0xa1, 0xd2, 0x8c, 0xb5, 0x35, 0x47, 0xe3, 0x17, 0xe8, 0x1a, 0xb9, 0xee, 0x1a,
0xb9, 0xda, 0x75, 0x7d, 0xff, 0xc9, 0xf3, 0x87, 0x05, 0xbd, 0xfd, 0x94, 0x5d, 0x13, 0xe6, 0x73,
0x03, 0xcc, 0xf9, 0xcd, 0x16, 0x01, 0x71, 0x1f, 0x36, 0x1b, 0xb3, 0x5c, 0x8a, 0xe0, 0x4f, 0x0b,
0xee, 0xbd, 0xe1, 0x8b, 0x15, 0xd5, 0x87, 0x75, 0xc2, 0x66, 0x54, 0x70, 0x96, 0x0e, 0xab, 0xfb,
0x55, 0x5d, 0x2d, 0xe2, 0x5e, 0x43, 0xef, 0xec, 0x48, 0x97, 0xd1, 0x36, 0xfc, 0xd3, 0x81, 0xbb,
0x75, 0x4a, 0xe9, 0xee, 0x7e, 0x30, 0x39, 0xef, 0x9f, 0x0a, 0xcb, 0x2f, 0xa6, 0x77, 0x49, 0x18,
0x6a, 0x12, 0x8e, 0x3b, 0x47, 0x75, 0xf5, 0xc4, 0x7d, 0x82, 0xdb, 0x67, 0x36, 0x04, 0xed, 0xd4,
0xd3, 0xcc, 0x67, 0xc7, 0x79, 0xd4, 0x12, 0xa5, 0xeb, 0xbf, 0x80, 0xe5, 0x11, 0xc1, 0xc7, 0x68,
0xb3, 0x0c, 0xa7, 0xdc, 0x4b, 0x3d, 0x45, 0x1d, 0xbb, 0xb9, 0x50, 0x7e, 0x0c, 0x2b, 0x1f, 0x05,
0x55, 0x04, 0xd5, 0x42, 0x32, 0x57, 0x91, 0xbc, 0x65, 0x58, 0xc9, 0xb3, 0x87, 0xbf, 0x3b, 0x70,
0xa7, 0xb6, 0x1b, 0x29, 0xae, 0x03, 0x83, 0xef, 0xca, 0x08, 0x0f, 0xe1, 0x56, 0x7d, 0xdb, 0xd1,
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;
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 {
string name = 1;
@ -59,14 +60,23 @@ message HostCapabilityResponse {
service GuestCapabilities {
rpc GuestCapabilities(vagrant.common.NullRequest) returns (CapabilitiesResponse);
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 {
rpc HostCapabilities(vagrant.common.NullRequest) returns (CapabilitiesResponse);
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 {
rpc ProviderCapabilities(vagrant.common.NullRequest) returns (ProviderCapabilitiesResponse);
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 math "math"
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 (
context "golang.org/x/net/context"
@ -356,6 +357,9 @@ type ConfigClient interface {
ConfigLoad(ctx context.Context, in *LoadRequest, opts ...grpc.CallOption) (*LoadResponse, error)
ConfigValidate(ctx context.Context, in *ValidateRequest, opts ...grpc.CallOption) (*ValidateResponse, 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 {
@ -402,12 +406,33 @@ func (c *configClient) ConfigFinalize(ctx context.Context, in *FinalizeRequest,
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.
type ConfigServer interface {
ConfigAttributes(context.Context, *vagrant_common.NullRequest) (*AttributesResponse, error)
ConfigLoad(context.Context, *LoadRequest) (*LoadResponse, error)
ConfigValidate(context.Context, *ValidateRequest) (*ValidateResponse, 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) {
@ -486,6 +511,42 @@ func _Config_ConfigFinalize_Handler(srv interface{}, ctx context.Context, dec fu
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{
ServiceName: "vagrant.config.Config",
HandlerType: (*ConfigServer)(nil),
@ -506,6 +567,14 @@ var _Config_serviceDesc = grpc.ServiceDesc{
MethodName: "ConfigFinalize",
Handler: _Config_ConfigFinalize_Handler,
},
{
MethodName: "Read",
Handler: _Config_Read_Handler,
},
{
MethodName: "Write",
Handler: _Config_Write_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "vagrant_config/config.proto",
@ -514,28 +583,31 @@ var _Config_serviceDesc = grpc.ServiceDesc{
func init() { proto.RegisterFile("vagrant_config/config.proto", fileDescriptor_952629f1a9a7438c) }
var fileDescriptor_952629f1a9a7438c = []byte{
// 363 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xc1, 0x4b, 0xfb, 0x30,
0x14, 0xc7, 0xd9, 0x7e, 0x3f, 0x27, 0x7b, 0xca, 0x36, 0x82, 0x48, 0xe9, 0x44, 0x67, 0x41, 0xd8,
0xc5, 0x06, 0xf4, 0xe2, 0x41, 0x50, 0x11, 0x14, 0x44, 0x3c, 0x74, 0xe0, 0xc5, 0x83, 0x64, 0x5d,
0x6c, 0x03, 0x6d, 0x52, 0xd3, 0x54, 0xc4, 0xbf, 0xd2, 0x3f, 0x49, 0x4c, 0xd2, 0x75, 0xeb, 0xd6,
0x81, 0xa7, 0xe4, 0xbd, 0x7c, 0xf3, 0x79, 0xc9, 0xfb, 0x3e, 0x18, 0x7e, 0x90, 0x48, 0x12, 0xae,
0x5e, 0x43, 0xc1, 0xdf, 0x58, 0x84, 0xcd, 0xe2, 0x67, 0x52, 0x28, 0x81, 0x7a, 0xf6, 0xd0, 0x37,
0x59, 0xf7, 0x25, 0x62, 0x2a, 0x2e, 0xa6, 0x7e, 0x28, 0x52, 0x1c, 0x93, 0x3c, 0x66, 0xa1, 0x90,
0x19, 0xb6, 0x22, 0x4c, 0x3f, 0x15, 0x8e, 0xc4, 0x69, 0x96, 0x14, 0x11, 0xe3, 0xf3, 0xac, 0x0d,
0x35, 0x10, 0x57, 0xc5, 0xd2, 0x54, 0x70, 0x6c, 0x16, 0x53, 0xcc, 0x7b, 0x00, 0x74, 0xa3, 0x94,
0x64, 0xd3, 0x42, 0xd1, 0x3c, 0xa0, 0x79, 0x26, 0x78, 0x4e, 0xd1, 0x21, 0x00, 0x99, 0x67, 0x9d,
0xd6, 0xe8, 0xdf, 0xb8, 0x1b, 0x2c, 0x64, 0xd0, 0x1e, 0x6c, 0x51, 0x29, 0x85, 0x74, 0xda, 0xa3,
0xd6, 0xb8, 0x1b, 0x98, 0xc0, 0x3b, 0x86, 0x9d, 0x47, 0x41, 0x66, 0x01, 0x7d, 0x2f, 0x68, 0xae,
0x10, 0x82, 0xff, 0x33, 0xa2, 0x88, 0xd3, 0xd2, 0x1a, 0xbd, 0xf7, 0x2e, 0x60, 0xd7, 0x48, 0x6c,
0xa1, 0x35, 0x9a, 0x06, 0xf8, 0x15, 0xf4, 0x9f, 0x49, 0xc2, 0x66, 0x44, 0xd1, 0x0d, 0x05, 0x90,
0x03, 0xdb, 0x29, 0x09, 0x63, 0xc6, 0xa9, 0xbd, 0x5e, 0x86, 0xde, 0x35, 0x0c, 0x2a, 0x80, 0x2d,
0xbf, 0x0f, 0x1d, 0x4d, 0x2f, 0xff, 0x68, 0xa3, 0x86, 0x27, 0x9c, 0x40, 0xff, 0x8e, 0x71, 0x92,
0xb0, 0xaf, 0x4d, 0x4f, 0xf0, 0x2e, 0x61, 0x50, 0xc9, 0xfe, 0xfa, 0xcf, 0xb3, 0xef, 0x36, 0x74,
0x6e, 0xb5, 0xf1, 0x68, 0x02, 0x03, 0xb3, 0xab, 0x1c, 0x42, 0x43, 0xbf, 0x9a, 0x0e, 0x6d, 0xe3,
0x53, 0x91, 0x24, 0xf6, 0x35, 0xae, 0xe7, 0x2f, 0x8f, 0x8e, 0xbf, 0xc6, 0xda, 0x7b, 0x00, 0x03,
0xfd, 0xf5, 0x61, 0x09, 0xa7, 0x6f, 0x2c, 0x18, 0xe8, 0x1e, 0xac, 0x3f, 0xb4, 0xa0, 0x09, 0xf4,
0x0c, 0xa8, 0xec, 0x2a, 0x3a, 0xaa, 0xeb, 0x6b, 0x86, 0xb9, 0xa3, 0x66, 0x41, 0x1d, 0x5a, 0x76,
0x70, 0x15, 0x5a, 0xb3, 0x60, 0x15, 0x5a, 0x6f, 0xfe, 0xb4, 0xa3, 0x47, 0xfd, 0xfc, 0x27, 0x00,
0x00, 0xff, 0xff, 0xe0, 0x00, 0xbf, 0x51, 0x76, 0x03, 0x00, 0x00,
// 415 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0xdf, 0x6b, 0xdb, 0x30,
0x10, 0xc7, 0xc9, 0xf2, 0x63, 0xe4, 0x36, 0x92, 0x20, 0xc6, 0xe6, 0x39, 0x63, 0xcb, 0x0c, 0x83,
0xbc, 0xcc, 0x82, 0xed, 0x65, 0x83, 0xc0, 0x56, 0x0a, 0x2d, 0x94, 0xd2, 0x07, 0x07, 0xda, 0x87,
0x3e, 0x14, 0xc5, 0x56, 0x6d, 0x81, 0x6d, 0xb9, 0xb2, 0x5c, 0x4a, 0xff, 0xc3, 0xfe, 0x57, 0x25,
0x92, 0x1c, 0x27, 0xb6, 0x13, 0x28, 0xf4, 0xc9, 0xba, 0xbb, 0xef, 0x7d, 0x4e, 0xba, 0x3b, 0xc3,
0xf4, 0x9e, 0x84, 0x82, 0xa4, 0xf2, 0xc6, 0xe7, 0xe9, 0x2d, 0x0b, 0xb1, 0xfe, 0xb8, 0x99, 0xe0,
0x92, 0xa3, 0x91, 0x09, 0xba, 0xda, 0x6b, 0x5f, 0x87, 0x4c, 0x46, 0xc5, 0xca, 0xf5, 0x79, 0x82,
0x23, 0x92, 0x47, 0xcc, 0xe7, 0x22, 0xc3, 0x46, 0x84, 0xe9, 0x83, 0xc4, 0x21, 0xff, 0x99, 0xc5,
0x45, 0xc8, 0xd2, 0x8d, 0xd7, 0x98, 0x0a, 0x88, 0xab, 0x62, 0x49, 0xc2, 0x53, 0xac, 0x3f, 0xba,
0x98, 0xbd, 0x7c, 0x2d, 0x38, 0xe3, 0x98, 0x71, 0x0d, 0x75, 0xce, 0x00, 0x1d, 0x49, 0x29, 0xd8,
0xaa, 0x90, 0x34, 0xf7, 0x68, 0x9e, 0xf1, 0x34, 0xa7, 0xe8, 0x2b, 0x00, 0xd9, 0x78, 0xad, 0xce,
0xac, 0x3b, 0x1f, 0x7a, 0x5b, 0x1e, 0xf4, 0x01, 0xfa, 0x54, 0x08, 0x2e, 0xac, 0x37, 0xb3, 0xce,
0x7c, 0xe8, 0x69, 0xc3, 0xf9, 0x0e, 0xef, 0xce, 0x39, 0x09, 0x3c, 0x7a, 0x57, 0xd0, 0x5c, 0x22,
0x04, 0xbd, 0x80, 0x48, 0x62, 0x75, 0x94, 0x46, 0x9d, 0x9d, 0x3f, 0xf0, 0x5e, 0x4b, 0x4c, 0xa1,
0x16, 0xcd, 0x1e, 0xf8, 0x3f, 0x18, 0x5f, 0x92, 0x98, 0x05, 0x44, 0xd2, 0x03, 0x05, 0x90, 0x05,
0x6f, 0x13, 0xe2, 0x47, 0x2c, 0xa5, 0x26, 0xbd, 0x34, 0x9d, 0xff, 0x30, 0xa9, 0x00, 0xa6, 0xfc,
0x47, 0x18, 0x28, 0x7a, 0xf9, 0x46, 0x63, 0xed, 0xb9, 0xc2, 0x0f, 0x18, 0x9f, 0xb0, 0x94, 0xc4,
0xec, 0xf1, 0xd0, 0x15, 0x9c, 0x05, 0x4c, 0x2a, 0xd9, 0x4b, 0xdf, 0xf9, 0xeb, 0xa9, 0x0b, 0x83,
0x63, 0xb5, 0x4d, 0x68, 0x09, 0x13, 0x7d, 0xaa, 0x26, 0x84, 0xa6, 0x6e, 0xb5, 0x72, 0x6a, 0x37,
0x2e, 0x8a, 0x38, 0x36, 0xb7, 0xb1, 0x1d, 0x77, 0x77, 0x1f, 0xdd, 0x96, 0xd1, 0x9e, 0x02, 0x68,
0xe8, 0x7a, 0x0e, 0x3b, 0x38, 0x95, 0xb1, 0x35, 0x40, 0xfb, 0x4b, 0x7b, 0xd0, 0x80, 0x96, 0x30,
0xd2, 0xa0, 0xb2, 0xab, 0xe8, 0x5b, 0x5d, 0x5f, 0x1b, 0x98, 0x3d, 0xdb, 0x2f, 0xa8, 0x43, 0xcb,
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;
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 {
repeated string attributes = 1;
@ -41,4 +42,7 @@ service Config {
rpc ConfigLoad(LoadRequest) returns (LoadResponse);
rpc ConfigValidate(ValidateRequest) returns (ValidateResponse);
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 (
"context"
"encoding/json"
"errors"
"google.golang.org/grpc"
@ -110,19 +111,26 @@ func (c *GRPCProviderClient) MachineIdChanged(m *vagrant.Machine) (err error) {
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)
if err != nil {
return
}
runData, err := json.Marshal(args)
if err != nil {
return
}
resp, err := c.client.RunAction(context.Background(), &vagrant_provider.RunActionRequest{
Name: actName,
Data: runData,
Data: string(runData),
Machine: machData})
if err != nil {
return
}
r = resp.Data
err = json.Unmarshal([]byte(resp.Data), &r)
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
}
@ -178,10 +186,6 @@ func (c *GRPCProviderClient) Name() string {
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) {
client := vagrant_provider.NewProviderClient(c)
return &GRPCProviderClient{
@ -199,12 +203,7 @@ func (p *ProviderPlugin) GRPCClient(ctx context.Context, broker *go_plugin.GRPCB
}, nil
}
type GRPCProviderPlugin struct {
ProviderPlugin
Impl Provider
}
func (p *GRPCProviderPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error {
func (p *ProviderPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error {
p.Impl.Init()
vagrant_provider.RegisterProviderServer(s, &GRPCProviderServer{
Impl: p.Impl,
@ -221,10 +220,6 @@ func (p *GRPCProviderPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Se
return nil
}
func (p *GRPCProviderPlugin) GRPCClient(context.Context, *go_plugin.GRPCBroker, *grpc.ClientConn) (interface{}, error) {
return nil, nil
}
type GRPCProviderServer struct {
GRPCIOServer
GRPCConfigServer
@ -257,12 +252,21 @@ func (s *GRPCProviderServer) RunAction(ctx context.Context, req *vagrant_provide
resp.Error = e.Error()
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 {
resp.Error = e.Error()
return
}
resp.Data = r
result, err := json.Marshal(r)
if err != nil {
return
}
resp.Data = string(result)
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
}
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)
if err != nil {
return
@ -52,7 +52,7 @@ func (c *GRPCSyncedFolderClient) Cleanup(m *vagrant.Machine, o *vagrant.FolderOp
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)
if err != nil {
return
@ -78,7 +78,7 @@ func (c *GRPCSyncedFolderClient) Disable(m *vagrant.Machine, f *vagrant.FolderLi
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)
if err != nil {
return
@ -136,7 +136,7 @@ func (c *GRPCSyncedFolderClient) Name() string {
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)
if err != nil {
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) {
resp = &vagrant_common.EmptyResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil)
machine, err := vagrant.LoadMachine(req.Machine, s.Impl)
if err != nil {
return
}
@ -180,7 +180,7 @@ func (s *GRPCSyncedFolderServer) Cleanup(ctx context.Context, req *vagrant_folde
if err != nil {
return
}
e := s.Impl.Cleanup(machine, &options)
e := s.Impl.Cleanup(machine, options)
if e != nil {
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) {
resp = &vagrant_common.EmptyResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil)
machine, err := vagrant.LoadMachine(req.Machine, s.Impl)
if err != nil {
return
}
@ -203,7 +203,7 @@ func (s *GRPCSyncedFolderServer) Disable(ctx context.Context, req *vagrant_folde
if err != nil {
return
}
e := s.Impl.Disable(machine, &folders, &options)
e := s.Impl.Disable(machine, folders, options)
if e != nil {
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) {
resp = &vagrant_common.EmptyResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil)
machine, err := vagrant.LoadMachine(req.Machine, s.Impl)
if err != nil {
return
}
@ -226,7 +226,7 @@ func (s *GRPCSyncedFolderServer) Enable(ctx context.Context, req *vagrant_folder
if err != nil {
return
}
e := s.Impl.Enable(machine, &folders, &options)
e := s.Impl.Enable(machine, folders, options)
if e != nil {
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) {
resp = &vagrant_common.IsResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil)
machine, err := vagrant.LoadMachine(req.Machine, s.Impl)
if err != nil {
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) {
resp = &vagrant_common.EmptyResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil)
machine, err := vagrant.LoadMachine(req.Machine, s.Impl)
if err != nil {
return
}
@ -274,7 +274,7 @@ func (s *GRPCSyncedFolderServer) Prepare(ctx context.Context, req *vagrant_folde
if err != nil {
return
}
e := s.Impl.Prepare(machine, &folders, &options)
e := s.Impl.Prepare(machine, folders, options)
if e != nil {
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 {
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
}
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)
MachineIdChanged(machData *Machine) error
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)
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 {
Cleanup(m *Machine, opts *FolderOptions) error
Disable(m *Machine, f *FolderList, opts *FolderOptions) error
Enable(m *Machine, f *FolderList, opts *FolderOptions) error
Cleanup(m *Machine, opts FolderOptions) error
Disable(m *Machine, f FolderList, opts FolderOptions) error
Enable(m *Machine, f FolderList, opts FolderOptions) error
Info() *SyncedFolderInfo
IsUsable(m *Machine) (bool, error)
Name() string
Prepare(m *Machine, f *FolderList, opts *FolderOptions) error
Prepare(m *Machine, f FolderList, opts FolderOptions) error
GuestCapabilities
HostCapabilities

View File

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

View File

@ -90,12 +90,16 @@ module Vagrant
# Load given data into the provided machine. This is
# 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 [Vagrant::Machine] machine
# @return [Vagrant::Machine]
def load_machine(data, machine)
if data[:id] != machine.id
machine.id = data[:id]
end
machine
end
@ -157,7 +161,7 @@ module Vagrant
# @return [String]
def name
go_plugin_name.to_s.capitalize.tr("_", "")
go_plugin_name.to_s.split("_").map(&:capitalize).join
end
end

View File

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

View File

@ -60,31 +60,11 @@ module Vagrant
# provider so that it can be interacted with normally within
# Vagrant
class Provider < Vagrant.plugin("2", :provider)
include DirectGoPlugin
# @return [Vagrant::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)
@machine = machine
end
@ -234,21 +214,6 @@ module Vagrant
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
#
# @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