Remove proxy usage. Use binding for management only.

This commit is contained in:
Chris Roberts 2019-04-09 10:44:31 -07:00
parent 5605a6e843
commit fe7ac740df
24 changed files with 762 additions and 2602 deletions

View File

@ -1,162 +0,0 @@
package main
import (
"C"
"context"
"encoding/json"
"errors"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin"
)
//export GuestCapabilities
func GuestCapabilities(pluginName, pluginType *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.GuestCapabilities)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
r.Result, r.Error = p.GuestCapabilities()
return r.Dump()
}
//export GuestCapability
func GuestCapability(pluginName, pluginType, cname, cplatform, cargs, cmachine *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.GuestCapabilities)
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 r.Dump()
}
var args interface{}
err = json.Unmarshal([]byte(to_gs(cargs)), &args)
if err != nil {
r.Error = err
return r.Dump()
}
cap := &vagrant.SystemCapability{
Name: to_gs(cname),
Platform: to_gs(cplatform)}
ctx := context.Background()
r.Result, r.Error = p.GuestCapability(ctx, cap, args, machine)
return r.Dump()
}
//export HostCapabilities
func HostCapabilities(pluginName, pluginType *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.HostCapabilities)
if !ok {
r.Error = errors.New("Failed to load requested plugin")
return r.Dump()
}
r.Result, r.Error = p.HostCapabilities()
return r.Dump()
}
//export HostCapability
func HostCapability(pluginName, pluginType, cname, cplatform, cargs, cenv *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.HostCapabilities)
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 r.Dump()
}
var args interface{}
err = json.Unmarshal([]byte(to_gs(cargs)), &args)
if err != nil {
r.Error = err
return r.Dump()
}
cap := &vagrant.SystemCapability{
Name: to_gs(cname),
Platform: to_gs(cplatform)}
ctx := context.Background()
r.Result, r.Error = p.HostCapability(ctx, cap, args, env)
return r.Dump()
}
//export ProviderCapabilities
func ProviderCapabilities(pluginName, pluginType *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.ProviderCapabilities)
if !ok {
r.Error = errors.New("Failed to load requested plugin")
return r.Dump()
}
r.Result, r.Error = p.ProviderCapabilities()
return r.Dump()
}
//export ProviderCapability
func ProviderCapability(pluginName, pluginType, cname, cprovider, cargs, cmach *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.ProviderCapabilities)
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 r.Dump()
}
var args interface{}
err = json.Unmarshal([]byte(to_gs(cargs)), &args)
if err != nil {
r.Error = err
return r.Dump()
}
cap := &vagrant.ProviderCapability{
Name: to_gs(cname),
Provider: to_gs(cprovider)}
ctx := context.Background()
r.Result, r.Error = p.ProviderCapability(ctx, cap, args, m)
return r.Dump()
}

View File

@ -1,396 +0,0 @@
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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

@ -1,101 +0,0 @@
package main
import (
"C"
"context"
"encoding/json"
"errors"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin"
)
//export ConfigLoad
func ConfigLoad(pluginName, pluginType, data *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.Config)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
var cdata map[string]interface{}
r.Error = json.Unmarshal([]byte(to_gs(data)), &cdata)
if r.Error != nil {
return r.Dump()
}
ctx := context.Background()
r.Result, r.Error = p.ConfigLoad(ctx, cdata)
return r.Dump()
}
//export ConfigAttributes
func ConfigAttributes(pluginName, pluginType *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.Config)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
r.Result, r.Error = p.ConfigAttributes()
return r.Dump()
}
//export ConfigValidate
func ConfigValidate(pluginName, pluginType, data, machData *C.char) *C.char {
var m *vagrant.Machine
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.Config)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
var cdata map[string]interface{}
r.Error = json.Unmarshal([]byte(to_gs(data)), &cdata)
if r.Error != nil {
return r.Dump()
}
m, r.Error = vagrant.LoadMachine(to_gs(machData), nil)
if r.Error != nil {
return r.Dump()
}
ctx := context.Background()
r.Result, r.Error = p.ConfigValidate(ctx, cdata, m)
return r.Dump()
}
//export ConfigFinalize
func ConfigFinalize(pluginName, pluginType, data *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), to_gs(pluginType))
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.Config)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
var cdata map[string]interface{}
r.Error = json.Unmarshal([]byte(to_gs(data)), &cdata)
if r.Error == nil {
ctx := context.Background()
r.Result, r.Error = p.ConfigFinalize(ctx, cdata)
}
return r.Dump()
}

View File

@ -1,195 +0,0 @@
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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

@ -81,6 +81,50 @@ func Teardown() {
Plugins.Logger.Info("plugins have been halted")
}
//export ListProviders
func ListProviders() *C.char {
list := map[string]interface{}{}
r := &Response{Result: list}
if Plugins == nil {
return r.Dump()
}
for n, p := range Plugins.Providers {
info := p.Provider.Info()
c := p.Client.ReattachConfig()
data := map[string]interface{}{
"network": c.Addr.Network(),
"address": c.Addr.String(),
"description": info.Description,
"priority": info.Priority,
}
list[n] = data
}
r.Result = list
return r.Dump()
}
//export ListSyncedFolders
func ListSyncedFolders() *C.char {
list := map[string]interface{}{}
r := &Response{Result: list}
if Plugins == nil {
return r.Dump()
}
for n, p := range Plugins.SyncedFolders {
info := p.SyncedFolder.Info()
c := p.Client.ReattachConfig()
data := map[string]interface{}{
"network": c.Addr.Network(),
"address": c.Addr.String(),
"description": info.Description,
"priority": info.Priority,
}
list[n] = data
}
r.Result = list
return r.Dump()
}
// stub required for build
func main() {}

View File

@ -1,195 +0,0 @@
package main
import (
"C"
"context"
"encoding/json"
"errors"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin"
)
//export ListProviders
func ListProviders() *C.char {
list := map[string]interface{}{}
r := &Response{Result: list}
if Plugins == nil {
return r.Dump()
}
for n, p := range Plugins.Providers {
list[n] = p.Provider.Info()
}
r.Result = list
return r.Dump()
}
//export ProviderAction
func ProviderAction(providerName *C.char, actionName *C.char, machData *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.Provider)
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(actionName)
ctx := context.Background()
r.Result, r.Error = p.Action(ctx, aName, m)
return r.Dump()
}
//export ProviderIsInstalled
func ProviderIsInstalled(providerName *C.char, machData *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.Provider)
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()
}
ctx := context.Background()
r.Result, r.Error = p.IsInstalled(ctx, m)
return r.Dump()
}
//export ProviderIsUsable
func ProviderIsUsable(providerName *C.char, machData *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.Provider)
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()
}
ctx := context.Background()
r.Result, r.Error = p.IsUsable(ctx, m)
return r.Dump()
}
//export ProviderMachineIdChanged
func ProviderMachineIdChanged(providerName *C.char, machData *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.Provider)
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()
}
ctx := context.Background()
r.Error = p.MachineIdChanged(ctx, m)
return r.Dump()
}
//export ProviderRunAction
func ProviderRunAction(providerName *C.char, actName *C.char, runData *C.char, machData *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.Provider)
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()
}
ctx := context.Background()
r.Result, r.Error = p.RunAction(ctx, aName, rData, m)
return r.Dump()
}
//export ProviderSshInfo
func ProviderSshInfo(providerName *C.char, machData *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.Provider)
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()
}
ctx := context.Background()
r.Result, r.Error = p.SshInfo(ctx, m)
return r.Dump()
}
//export ProviderState
func ProviderState(providerName *C.char, machData *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(providerName), "provider")
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.Provider)
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()
}
ctx := context.Background()
r.Result, r.Error = p.State(ctx, m)
return r.Dump()
}

View File

@ -1,306 +0,0 @@
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
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"])
}
}

View File

@ -1,176 +0,0 @@
package main
import (
"C"
"context"
"encoding/json"
"errors"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin"
)
//export ListSyncedFolders
func ListSyncedFolders() *C.char {
list := map[string]interface{}{}
r := &Response{Result: list}
if Plugins == nil {
return r.Dump()
}
for n, p := range Plugins.SyncedFolders {
list[n] = p.SyncedFolder.Info()
}
r.Result = list
return r.Dump()
}
//export SyncedFolderCleanup
func SyncedFolderCleanup(pluginName, machine, opts *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), "synced_folder")
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.SyncedFolder)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
m, err := vagrant.LoadMachine(to_gs(machine), nil)
if err != nil {
r.Error = err
return r.Dump()
}
var o vagrant.FolderOptions
r.Error = json.Unmarshal([]byte(to_gs(opts)), &o)
if r.Error != nil {
return r.Dump()
}
ctx := context.Background()
r.Error = p.Cleanup(ctx, m, o)
return r.Dump()
}
//export SyncedFolderDisable
func SyncedFolderDisable(pluginName, machine, folders, opts *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), "synced_folder")
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.SyncedFolder)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
m, err := vagrant.LoadMachine(to_gs(machine), nil)
if err != nil {
r.Error = err
return r.Dump()
}
var f vagrant.FolderList
r.Error = json.Unmarshal([]byte(to_gs(folders)), &f)
if r.Error != nil {
return r.Dump()
}
var o vagrant.FolderOptions
r.Error = json.Unmarshal([]byte(to_gs(opts)), &o)
if r.Error != nil {
return r.Dump()
}
ctx := context.Background()
r.Error = p.Disable(ctx, m, f, o)
return r.Dump()
}
//export SyncedFolderEnable
func SyncedFolderEnable(pluginName, machine, folders, opts *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), "synced_folder")
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.SyncedFolder)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
m, err := vagrant.LoadMachine(to_gs(machine), nil)
if err != nil {
r.Error = err
return r.Dump()
}
var f vagrant.FolderList
r.Error = json.Unmarshal([]byte(to_gs(folders)), &f)
if r.Error != nil {
return r.Dump()
}
var o vagrant.FolderOptions
r.Error = json.Unmarshal([]byte(to_gs(opts)), &o)
if r.Error != nil {
return r.Dump()
}
ctx := context.Background()
r.Error = p.Enable(ctx, m, f, o)
return r.Dump()
}
//export SyncedFolderIsUsable
func SyncedFolderIsUsable(pluginName, machine *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), "synced_folder")
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.SyncedFolder)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
m, err := vagrant.LoadMachine(to_gs(machine), nil)
if err != nil {
r.Error = err
return r.Dump()
}
ctx := context.Background()
r.Result, r.Error = p.IsUsable(ctx, m)
return r.Dump()
}
//export SyncedFolderPrepare
func SyncedFolderPrepare(pluginName, machine, folders, opts *C.char) *C.char {
r := &Response{}
i, err := Plugins.PluginLookup(to_gs(pluginName), "synced_folder")
if err != nil {
r.Error = err
return r.Dump()
}
p, ok := i.(plugin.SyncedFolder)
if !ok {
r.Error = errors.New("failed to load requested plugin")
return r.Dump()
}
m, err := vagrant.LoadMachine(to_gs(machine), nil)
if err != nil {
r.Error = err
return r.Dump()
}
var f vagrant.FolderList
r.Error = json.Unmarshal([]byte(to_gs(folders)), &f)
if r.Error != nil {
return r.Dump()
}
var o vagrant.FolderOptions
r.Error = json.Unmarshal([]byte(to_gs(opts)), &o)
if r.Error != nil {
return r.Dump()
}
ctx := context.Background()
r.Error = p.Prepare(ctx, m, f, o)
return r.Dump()
}

View File

@ -1,347 +0,0 @@
package main
import (
"testing"
"github.com/hashicorp/go-plugin"
vplugin "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin"
)
func TestSyncedFolder_ListSyncedFolders(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
p := &vplugin.RemoteSyncedFolder{
SyncedFolder: impl}
Plugins = vplugin.VagrantPluginInit()
Plugins.SyncedFolders[impl.Name()] = p
result := ListSyncedFolders()
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_folder"] == nil {
t.Fatalf("bad result")
}
i, ok := r["mock_folder"].(map[string]interface{})
if !ok {
t.Fatalf("bad %#v", r["mock_folder"])
}
if i["description"] != "mock_folder" {
t.Errorf("%s != mock_folder", i["description"])
}
if i["priority"] != 100.0 {
t.Errorf("%d != 100", i["priority"])
}
}
func TestSyncedFolder_SyncedFolderCleanup(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
return
}
result := SyncedFolderCleanup(nil, to_cs("{}"), to_cs("null"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Error != nil {
t.Fatalf("err: %s", resp.Error)
}
}
func TestSyncedFolder_SyncedFolderCleanup_error(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
return
}
result := SyncedFolderCleanup(nil, to_cs("{}"), to_cs("{\"error\":true}"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Error == nil {
t.Fatalf("error expected")
}
}
func TestSyncedFolder_SyncedFolderDisable(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
return
}
result := SyncedFolderDisable(nil, to_cs("{}"), to_cs("{}"), to_cs("null"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Error != nil {
t.Fatalf("err: %s", resp.Error)
}
}
func TestSyncedFolder_SyncedFolderDisable_error(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
return
}
result := SyncedFolderDisable(nil, to_cs("{}"), to_cs("{}"), to_cs("{\"error\":true}"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Error == nil {
t.Fatalf("rror expected")
}
}
func TestSyncedFolder_SyncedFolderEnable(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
return
}
result := SyncedFolderEnable(nil, to_cs("{}"), to_cs("{}"), to_cs("null"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Error != nil {
t.Fatalf("err: %s", resp.Error)
}
}
func TestSyncedFolder_SyncedFolderEnable_error(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
return
}
result := SyncedFolderEnable(nil, to_cs("{}"), to_cs("{}"), to_cs("{\"error\":true}"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Error == nil {
t.Fatalf("rror expected")
}
}
func TestSyncedFolder_SyncedFolderIsUsable(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
return
}
result := SyncedFolderIsUsable(nil, to_cs("{}"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Error != nil {
t.Fatalf("err: %s", resp.Error)
}
usable, ok := resp.Result.(bool)
if !ok {
t.Fatalf("bad %#v", resp.Result)
}
if !usable {
t.Fatalf("bad result")
}
}
func TestSyncedFolder_SyncedFolderPrepare(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
return
}
result := SyncedFolderPrepare(nil, to_cs("{}"), to_cs("{}"), to_cs("null"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Error != nil {
t.Fatalf("err: %s", resp.Error)
}
}
func TestSyncedFolder_SyncedFolderPrepare_error(t *testing.T) {
client, server := plugin.TestPluginGRPCConn(t, map[string]plugin.Plugin{
"folder": &vplugin.SyncedFolderPlugin{Impl: &vplugin.MockSyncedFolder{}}})
defer server.Stop()
defer client.Close()
raw, err := client.Dispense("folder")
if err != nil {
t.Fatalf("err: %s", err)
}
impl, ok := raw.(vplugin.SyncedFolder)
if !ok {
t.Fatalf("bad %#v", raw)
}
Plugins = vplugin.VagrantPluginInit()
Plugins.PluginLookup = func(_, _ string) (r interface{}, err error) {
r = impl
return
}
result := SyncedFolderPrepare(nil, to_cs("{}"), to_cs("{}"), to_cs("{\"error\":true}"))
resp, err := LoadResponse(result)
if err != nil {
t.Fatalf("err: %s", err)
}
if resp.Error == nil {
t.Fatalf("error expected")
}
}

View File

@ -221,5 +221,17 @@ module Vagrant
"#{@name}-#{@version}-#{@provider}" <=>
"#{other.name}-#{other.version}-#{other.provider}"
end
# @return [String]
def to_json(*args)
{
name: name,
provider: provider,
version: version,
directory: directory.to_s,
metadata: metadata,
metadata_url: metadata_url
}.to_json(*args)
end
end
end

View File

@ -927,6 +927,26 @@ module Vagrant
end
end
# @return [String]
def to_json(*args)
{
cwd: cwd,
data_dir: data_dir,
vagrantfile_name: vagrantfile_name,
home_path: home_path,
local_data_path: local_data_path,
tmp_path: tmp_path,
aliases_path: aliases_path,
boxes_path: boxes_path,
gems_path: gems_path,
default_private_key_path: default_private_key_path,
root_path: root_path,
primary_machine_name: primary_machine_name,
machine_names: machine_names,
active_machines: Hash[active_machines]
}.to_json(*args)
end
protected
# Attempt to guess the configured provider in use. Will fallback

View File

@ -1,4 +1,6 @@
module Vagrant
autoload :Proto, "vagrant/go_plugin/vagrant_proto/vagrant_services_pb"
module GoPlugin
# @return [String]

View File

@ -4,174 +4,82 @@ module Vagrant
module GoPlugin
# Contains all capability functionality for go-plugin
module CapabilityPlugin
extend Vagrant::Util::Logger
# Wrapper class for go-plugin defined capabilities
class Capability
include TypedGoPlugin
include GRPCPlugin
end
# @return [Interface]
def self.interface
if !@_interface
@_interface = Interface.new
# Fetch any defined guest capabilites for given plugin and register
# capabilities within given plugin class
#
# @param [Vagrant::Proto::GuestCapabilities::Stub] client Plugin client
# @param [Class] plugin_klass Plugin class to register capabilities
# @param [Symbol] plugin_type Type of plugin
def self.generate_guest_capabilities(client, plugin_klass, plugin_type)
logger.debug("checking for guest capabilities in #{plugin_type} plugin #{plugin_klass}")
result = client.guest_capabilities(Vagrant::Proto::Empty.new)
return if result.capabilities.empty?
logger.debug("guest capabilities support detected in #{plugin_type} plugin #{plugin_klass}")
result.capabilities.each do |cap|
cap_klass = Class.new(Capability).tap do |k|
k.class_eval("def self.#{cap.name}(machine, *args){ plugin_client.guest_capability(" \
"Vagrant::Proto::GuestCapabilityRequest.new(" \
"machine: JSON.dump(machine), arguments: JSON.dump(args)," \
"capability: Vagrant::Proto::SystemCapability.new(" \
"name: '#{cap.name}', platform: '#{cap.platform}'))) }")
end
cap_klass.plugin_client = client
plugin_klass.guest_capability(cap.platform, cap.name) { cap_klass }
end
@_interface
end
# Capability interface to access go-plugin
class Interface
include GoPlugin::Core
typedef :string, :capability_args
typedef :string, :capability_name
typedef :string, :capability_platform
typedef :string, :capability_provider
attach_function :_guest_capabilities, :GuestCapabilities,
[:plugin_name, :plugin_type], :plugin_result
attach_function :_guest_capability, :GuestCapability,
[:plugin_name, :plugin_type, :capability_name, :capability_platform,
:capability_args, :vagrant_machine], :plugin_result
attach_function :_host_capabilities, :HostCapabilities,
[:plugin_name, :plugin_type], :plugin_result
attach_function :_host_capability, :HostCapability,
[:plugin_name, :plugin_type, :capability_name, :capability_platform,
:capability_args, :vagrant_environment], :plugin_result
attach_function :_provider_capabilities, :ProviderCapabilities,
[:plugin_name, :plugin_type], :plugin_result
attach_function :_provider_capability, :ProviderCapability,
[:plugin_name, :plugin_type, :capability_name, :capability_provider,
:capability_args, :vagrant_machine], :plugin_result
# List of supported guest capabilities
#
# @param [String] plugin_name Name of plugin
# @param [String] plugin_type Type of plugin
# @return [Array<Hash>] List of guest capabilities
def guest_capabilities(plugin_name, plugin_type)
load_result { _guest_capabilities(plugin_name.to_s, plugin_type.to_s) }
end
# Execute guest capability
#
# @param [String] plugin_name Name of plugin
# @param [String] plugin_type Type of plugin
# @param [String] cap_name Name of capability
# @param [String] cap_plat Guest platform of capability
# @param [Array<Object>] cap_args Arguments for the capability
# @param [Vagrant::Machine] machine Guest machine
def guest_capability(plugin_name, plugin_type, cap_name, cap_plat, cap_args, machine)
load_result {
_guest_capability(plugin_name.to_s, plugin_type.to_s, cap_name.to_s, cap_plat.to_s,
JSON.dump(cap_args), dump_machine(machine))
}
end
# List of supported host capabilities
#
# @param [String] plugin_name Name of plugin
# @param [String] plugin_type Type of plugin
# @return [Array<Hash>] List of host capabilities
def host_capabilities(plugin_name, plugin_type)
load_result { _host_capabilities(plugin_name.to_s, plugin_type.to_s) }
end
# Execute host capability
#
# @param [String] plugin_name Name of plugin
# @param [String] plugin_type Type of plugin
# @param [String] cap_name Name of capability
# @param [String] cap_plat Host platform of capability
# @param [Array<Object>] cap_args Arguments for the capability
# @param [Vagrant::Environment] env Vagrant environment
def host_capability(plugin_name, plugin_type, cap_name, cap_plat, cap_args, env)
load_result {
_host_capability(plugin_name.to_s, plugin_type.to_s, cap_name.to_s, cap_plat.to_s,
JSON.dump(cap_args), dump_environment(env))
}
end
# List of supported provider capabilities
#
# @param [String] plugin_name Name of plugin
# @param [String] plugin_type Type of plugin
# @return [Array<Hash>] List of provider capabilities
def provider_capabilities(plugin_name, plugin_type)
load_result { _provider_capabilities(plugin_name.to_s, plugin_type.to_s) }
end
# Execute provider capability
#
# @param [String] plugin_name Name of plugin
# @param [String] plugin_type Type of plugin
# @param [String] cap_name Name of capability
# @param [String] cap_prov Provider of capability
# @param [Array<Object>] cap_args Arguments for the capability
# @param [Vagrant::Machine] machine Guest machine
def provider_capability(plugin_name, plugin_type, cap_name, cap_prov, cap_args, machine)
load_result {
_provider_capability(plugin_name.to_s, plugin_type.to_s, cap_name.to_s, cap_prov.to_s,
JSON.dump(cap_args), dump_machine(machine))
}
end
# Fetch any defined guest capabilites for given plugin and register
# capabilities within given plugin class
#
# @param [String] plugin_name Name of plugin
# @param [String] plugin_type Type of plugin
# @param [Class] plugin_klass Plugin class to register capabilities
def generate_guest_capabilities(plugin_name, plugin_type, plugin_klass)
logger.debug("checking for guest capabilities in #{plugin_type} plugin #{plugin_name}")
caps = guest_capabilities(plugin_name.to_s, plugin_type.to_s)
return if !caps || caps.empty?
logger.debug("guest capabilities support detected in #{plugin_type} plugin #{plugin_name}")
caps.each do |cap|
cap_klass = Class.new(Capability).tap do |k|
k.class_eval("def self.#{k[:name]}(machine, *args){ CapabilityPlugin.interface.guest_capability(" \
"plugin_name, plugin_type, '#{k[:name]}', '#{k[:platform]}', args, machine) }")
end
plugin_klass.guest_capability(k[:platform], k[:name])
# Fetch any defined host capabilites for given plugin and register
# capabilities within given plugin class
#
# @param [Vagrant::Proto::HostCapabilities::Stub] client Plugin client
# @param [Class] plugin_klass Plugin class to register capabilities
# @param [Symbol] plugin_type Type of plugin
def self.generate_host_capabilities(client, plugin_klass, plugin_type)
logger.debug("checking for host capabilities in #{plugin_type} plugin #{plugin_klass}")
result = client.host_capabilities(Vagrant::Proto::Empty.new)
return if result.capabilities.empty?
logger.debug("host capabilities support detected in #{plugin_type} plugin #{plugin_klass}")
result.capabilities.each do |cap|
cap_klass = Class.new(Capability).tap do |k|
k.class_eval("def self.#{cap.name}(environment, *args){ plugin_client.host_capability(" \
"Vagrant::Proto::HostCapabilityRequest.new(" \
"environment: JSON.dump(environment), arguments: JSON.dump(args)," \
"capability: Vagrant::Proto::SystemCapability.new(" \
"name: '#{cap.name}', platform: '#{cap.platform}'))) }")
end
cap_klass.plugin_client = client
plugin_klass.host_capability(cap.platform, cap.name) { cap_klass }
end
end
# Fetch any defined host capabilites for given plugin and register
# capabilities within given plugin class
#
# @param [String] plugin_name Name of plugin
# @param [String] plugin_type Type of plugin
# @param [Class] plugin_klass Plugin class to register capabilities
def generate_host_capabilities(plugin_name, plugin_type, plugin_klass)
logger.debug("checking for host capabilities in #{plugin_type} plugin #{plugin_name}")
caps = host_capabilities(plugin_name.to_s, plugin_type.to_s)
return if !caps || caps.empty?
logger.debug("host capabilities support detected in #{plugin_type} plugin #{plugin_name}")
caps.each do |cap|
cap_klass = Class.new(Capability).tap do |k|
k.class_eval("def self.#{k[:name]}(env, *args){ CapabilityPlugin.interface.host_capability(" \
"plugin_name, plugin_type, '#{k[:name]}', '#{k[:platform]}', args, env) }")
end
plugin_klass.host_capability(k[:platform], k[:name])
end
end
# Fetch any defined provider capabilites for given plugin and register
# capabilities within given plugin class
#
# @param [String] plugin_name Name of plugin
# @param [String] plugin_type Type of plugin
# @param [Class] plugin_klass Plugin class to register capabilities
def generate_provider_capabilities(plugin_name, plugin_type, plugin_klass)
logger.debug("checking for provider capabilities in #{plugin_type} plugin #{plugin_name}")
caps = provider_capabilities(plugin_name.to_s, plugin_type.to_s)
return if !caps || caps.empty?
logger.debug("provider capabilities support detected in #{plugin_type} plugin #{plugin_name}")
caps.each do |cap|
cap_klass = Class.new(Capability).tap do |k|
k.class_eval("def self.#{k[:name]}(machine, *args){ CapabilityPlugin.interface.provider_capability(" \
"plugin_name, plugin_type, '#{k[:name]}', '#{k[:provider]}', args, machine) }")
end
plugin_klass.provider_capability(k[:provider], k[:name])
# Fetch any defined provider capabilites for given plugin and register
# capabilities within given plugin class
#
# @param [Vagrant::Proto::ProviderCapabilities::Stub] client Plugin client
# @param [Class] plugin_klass Plugin class to register capabilities
# @param [Symbol] plugin_type Type of plugin
def self.generate_provider_capabilities(client, plugin_klass, plugin_type)
logger.debug("checking for provider capabilities in #{plugin_type} plugin #{plugin_klass}")
result = client.provider_capabilities(Vagrant::Proto::Empty.new)
return if result.capabilities.empty?
logger.debug("provider capabilities support detected in #{plugin_type} plugin #{plugin_klass}")
result.capabilities.each do |cap|
cap_klass = Class.new(Capability).tap do |k|
k.class_eval("def self.#{cap.name}(machine, *args){ plugin_client.provider_capability(" \
"Vagrant::Proto::ProviderCapabilityRequest.new(" \
"machine: JSON.dump(machine), arguments: JSON.dump(args)," \
"capability: Vagrant::Proto::ProviderCapability.new(" \
"name: '#{cap.name}', provider: '#{cap.provider}'))) }")
end
cap_klass.plugin_client = client
plugin_klass.provider_capability(cap.provider, cap.name) { cap_klass }
end
end
end

View File

@ -4,22 +4,51 @@ module Vagrant
module GoPlugin
# Contains all configuration functionality for go-plugin
module ConfigPlugin
# Generate configuration for the parent class
#
# @param [Vagrant::Proto::Config::Stub] client Plugin client
# @param [String] parent_name Parent plugin name
# @param [Class] parent_klass Parent class to register config
# @param [Symbol] parent_type Type of parent class (:provider, :synced_folder, etc)
def self.generate_config(client, parent_name, parent_klass, parent_type)
config_attrs = client.config_attributes(Vagrant::Proto::Empty.new).items
config_klass = Class.new(Config)
config_klass.plugin_client = client
Array(config_attrs).each do |att|
config_klass.instance_eval("attr_accessor :#{att}")
end
parent_klass.config(parent_name, parent_type) { config_klass }
end
# Config plugin class used with go-plugin
class Config < Vagrant.plugin("2", :config)
include TypedGoPlugin
include GRPCPlugin
# Finalize the current configuration
def finalize!
data = local_data
result = ConfigPlugin.interface.finalize(plugin_name, plugin_type, data)
result.each do |key, value|
result = plugin_client.config_finalize(Vagrant::Proto::Configuration.new(
data: JSON.dump(data)))
new_data = Vagrant::Util::HashWithIndifferentAccess.new(JSON.load(result.data))
new_data.each do |key, value|
next if data[key] == value
instance_variable_set("@#{key}", value)
if !self.respond_to?(key)
self.define_singleton_method(key) { instance_variable_get("@#{key}") }
end
end
self
end
# Validate configuration
#
# @param [Vagrant::Machine] machine Guest machine
# @return [Array<String>] list of errors
def validate(machine)
ConfigPlugin.interface.validate(plugin_name, plugin_type, local_data, machine)
result = plugin_client.config_validate(Vagrant::Proto::Configuration.new(
machine: JSON.dump(machine),
data: local_data))
result.items
end
# @return [Hash] currently defined instance variables
@ -32,102 +61,6 @@ module Vagrant
data
end
end
# @return [Interface]
def self.interface
unless @_interface
@_interface = Interface.new
end
@_interface
end
# Config interface to access go-plugin
class Interface
include GoPlugin::Core
typedef :string, :config_name
typedef :string, :config_data
typedef :string, :plugin_type
attach_function :_config_attributes, :ConfigAttributes,
[:plugin_name, :plugin_type], :plugin_result
attach_function :_config_load, :ConfigLoad,
[:plugin_name, :plugin_type, :config_data], :plugin_result
attach_function :_config_validate, :ConfigValidate,
[:plugin_name, :plugin_type, :config_data, :vagrant_machine], :plugin_result
attach_function :_config_finalize, :ConfigFinalize,
[:plugin_name, :plugin_type, :config_data], :plugin_result
# List of all supported configuration attribute names
#
# @param [String] plugin_name Name of plugin
# @param [String] plugin_type Type of plugin
# @return [Array<String>] List of attribute names
def attributes(plugin_name, plugin_type)
load_result { _config_attributes(plugin_name, plugin_type.to_s) }
end
# Load configuration data
#
# @param [String] plugin_name Name of plugin
# @param [String] plugin_type Type of plugin
# @param [Hash] data Configuration data
# @return [Hash] Configuration data
def load(plugin_name, plugin_type, data)
load_result { _config_load(plugin_name, plugin_type, JSON.dump(data)) }
end
# Validate configuration data
#
# @param [String] plugin_name Name of plugin
# @param [String] plugin_type Type of plugin
# @param [Hash] data Configuration data
# @param [Vagrant::Machine] machine Guest machine
# @return [Hash] Any validation errors
def validate(plugin_name, plugin_type, data, machine)
load_result { _config_validate(plugin_name, plugin_type, dump_config(data), dump_machine(machine)) }
end
# Finalize the configuration data
#
# @param [String] plugin_name Name of plugin
# @param [String] plugin_type Type of plugin
# @param [Hash] data Configuration data
# @return [Hash] Configuration data
def finalize(plugin_name, plugin_type, data)
load_result { _config_finalize(plugin_name, plugin_type, dump_config(data)) }
end
# Serialize configuration data
#
# @param [Hash] d Configuration data
# @return [String]
def dump_config(d)
JSON.dump(d)
end
# Fetch any defined configuration support from the given plugin
# and register it within the given plugin class
#
# @param [String] plugin_name Name of plugin
# @param [String] plugin_type Type of plugin
# @param [Class] plugin_klass Plugin class to register configuration
def generate_config(plugin_name, plugin_type, plugin_klass)
logger.debug("checking for configuration support in #{plugin_type} plugin #{plugin_name}")
cattrs = attributes(plugin_name, plugin_type)
return nil if !cattrs || cattrs.empty?
logger.debug("configuration support detected in #{plugin_type} plugin #{plugin_name}")
config_klass = Class.new(Config)
cattrs.each { |att|
config_klass.instance_eval("attr_accessor :#{att}")
}
config_klass.go_plugin_name = plugin_name
config_klass.go_plugin_type = plugin_type
plugin_klass.config(plugin_name.to_sym, plugin_type.to_sym) do
config_klass
end
end
end
end
end
end

View File

@ -11,13 +11,8 @@ module Vagrant
extend FFI::Library
ffi_lib FFI::Platform::LIBC
# TODO: Update this to include OS/ARCH details
ffi_lib File.expand_path("./go-plugin.so", File.dirname(__FILE__))
typedef :string, :vagrant_environment
typedef :string, :vagrant_machine
typedef :string, :plugin_name
typedef :string, :plugin_type
typedef :strptr, :plugin_result
# stdlib functions
@ -27,82 +22,6 @@ module Vagrant
attach_function :free, [:pointer], :void
end
# Generate a Hash representation of the given machine
# which can be serialized and sent to go-plugin
#
# @param [Vagrant::Machine] machine
# @return [String] JSON serialized Hash
def dump_machine(machine)
if !machine.is_a?(Vagrant::Machine)
raise TypeError,
"Expected `Vagrant::Machine` but received `#{machine.class}`"
end
m = {
box: {},
config: machine.config,
data_dir: machine.data_dir,
environment: dump_environment(machine.env),
id: machine.id,
name: machine.name,
provider_config: machine.provider_config,
provider_name: machine.provider_name
}
if machine.box
m[:box] = {
name: machine.box.name,
provider: machine.box.provider,
version: machine.box.version,
directory: machine.box.directory.to_s,
metadata: machine.box.metadata,
metadata_url: machine.box.metadata_url
}
end
m.to_json
end
# Generate a Hash representation of the given environment
# which can be serialized and sent to a go-plugin
#
# @param [Vagrant::Environmment] environment
# @return [Hash] Hash
def dump_environment(environment)
if !environment.is_a?(Vagrant::Environment)
raise TypeError,
"Expected `Vagrant::Environment` but received `#{environment.class}`"
end
e = {
cwd: environment.cwd,
data_dir: environment.data_dir,
vagrantfile_name: environment.vagrantfile_name,
home_path: environment.home_path,
local_data_path: environment.local_data_path,
tmp_path: environment.tmp_path,
aliases_path: environment.aliases_path,
boxes_path: environment.boxes_path,
gems_path: environment.gems_path,
default_private_key_path: environment.default_private_key_path,
root_path: environment.root_path,
primary_machine_name: environment.primary_machine_name,
machine_names: environment.machine_names,
active_machines: Hash[environment.active_machines]
}
end
# Load given data into the provided machine. This is
# used to update the machine with data received from
# 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
# Load the result received from the extension. This will load
# the JSON result, raise an error if detected, and properly
# free the memory associated with the result.
@ -131,71 +50,32 @@ module Vagrant
end
end
module DirectGoPlugin
def self.included(klass)
klass.extend(ClassMethods)
klass.include(InstanceMethods)
end
# Simple module to load into plugin wrapper classes
# to provide expected functionality
module GRPCPlugin
module ClassMethods
# @return [String] plugin name associated to this class
def go_plugin_name
@go_plugin_name
def plugin_client
@_plugin_client
end
def 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 go_plugin_name=(n)
if @go_plugin_name
raise ArgumentError.new("Class plugin name has already been set")
def plugin_client=(c)
if @_plugin_client
raise ArgumentError, "Plugin client has already been set"
end
@go_plugin_name = n
end
# @return [String]
def name
go_plugin_name.to_s.split("_").map(&:capitalize).join
@_plugin_client = c
end
end
module InstanceMethods
def plugin_name
self.class.go_plugin_name
def plugin_client
self.class.plugin_client
end
end
end
module TypedGoPlugin
def self.included(klass)
klass.extend(ClassMethods)
klass.include(Vagrant::Util::Logger)
klass.include(InstanceMethods)
klass.include(DirectGoPlugin)
end
module ClassMethods
def go_plugin_type
@go_plugin_type
end
def go_plugin_type=(t)
if @go_plugin_type
raise ArgumentError.new("Class plugin type has already been set")
end
@go_plugin_type = t.to_s
end
end
module InstanceMethods
def plugin_type
self.class.go_plugin_type
end
klass.extend(ClassMethods)
end
end
end

View File

@ -16,11 +16,27 @@ module Vagrant
attach_function :_setup, :Setup, [:enable_logger, :timestamps, :log_level], :bool
attach_function :_teardown, :Teardown, [], :void
attach_function :_load_plugins, :LoadPlugins, [:plugin_directory], :bool
attach_function :_list_providers, :ListProviders, [], :plugin_result
attach_function :_list_synced_folders, :ListSyncedFolders, [], :plugin_result
def initialize
setup
end
# List of provider plugins currently available
#
# @return [Hash<String,Hash<Info>>]
def list_providers
load_result { _list_providers } || {}
end
# List of synced folder plugins currently available
#
# @return [Hash<String,Hash<Info>>]
def list_synced_folders
load_result { _list_synced_folders } || {}
end
# Load any plugins found at the given directory
#
# @param [String, Pathname] path Directory to load
@ -35,9 +51,9 @@ module Vagrant
# Register all available plugins
def register_plugins
logger.debug("registering provider plugins")
ProviderPlugin.interface.load!
load_providers
logger.debug("registering synced folder plugins")
SyncedFolderPlugin.interface.load!
load_synced_folders
end
# Load the plugins found at the given directory
@ -67,6 +83,84 @@ module Vagrant
def configured?
!!@setup
end
# Load any detected provider plugins
def load_providers
if !@_providers_loaded
@_providers_loaded
logger.debug("provider go-plugins have not been loaded... loading")
list_providers.each do |p_name, p_details|
logger.debug("loading go-plugin provider #{p_name}. details - #{p_details}")
client = Vagrant::Proto::Provider::Stub.new(
"#{p_details[:network]}://#{p_details[:address]}",
:this_channel_is_insecure)
# Create new provider class wrapper
provider_klass = Class.new(ProviderPlugin::Provider)
provider_klass.plugin_client = client
# Create new plugin to register the provider
plugin_klass = Class.new(Vagrant.plugin("2"))
# Define the plugin
plugin_klass.class_eval do
name "#{p_name} Provider"
description p_details[:description]
end
# Register the provider
plugin_klass.provider(p_name.to_sym, priority: p_details.fetch(:priority, 0)) do
provider_klass
end
# Setup any configuration support
ConfigPlugin.generate_config(client, p_name, plugin_klass, :provider)
# Register any guest capabilities
CapabilityPlugin.generate_guest_capabilities(client, plugin_klass, :provider)
# Register any host capabilities
CapabilityPlugin.generate_host_capabilities(client, plugin_klass, :provider)
# Register any provider capabilities
CapabilityPlugin.generate_provider_capabilities(client, plugin_klass, :provider)
logger.debug("completed loading provider go-plugin #{p_name}")
logger.info("loaded go-plugin provider - #{p_name}")
end
else
logger.warn("provider go-plugins have already been loaded. ignoring load request.")
end
end
# Load any detected synced folder plugins
def load_synced_folders
if !@_synced_folders_loaded
@_synced_folders_loaded = true
logger.debug("synced folder go-plugins have not been loaded... loading")
Array(list_synced_folders).each do |f_name, f_details|
logger.debug("loading go-plugin synced folder #{f_name}. details - #{f_details}")
client = Vagrant::Proto::SyncedFolder::Stub.new(
"#{p_details[:network]}://#{p_details[:address]}",
:this_channel_is_insecure)
# Create new synced folder class wrapper
folder_klass = Class.new(SyncedFolderPlugin::SyncedFolder)
folder_klass.plugin_client = client
# Create new plugin to register the synced folder
plugin_klass = Class.new(Vagrant.plugin("2"))
# Define the plugin
plugin_klass.class_eval do
name "#{f_name} Synced Folder"
description f_details[:description]
end
# Register the synced folder
plugin_klass.synced_folder(f_name.to_sym, priority: f_details.fetch(:priority, 10)) do
folder_klass
end
# Register any guest capabilities
CapabilityPlugin.generate_guest_capabilities(client, plugin_klass, :synced_folder)
# Register any host capabilities
CapabilityPlugin.generate_host_capabilities(client, plugin_klass, :synced_folder)
# Register any provider capabilities
CapabilityPlugin.generate_provider_capabilities(client, plugin_klass, :synced_folder)
logger.debug("completed loading synced folder go-plugin #{f_name}")
logger.info("loaded go-plugin synced folder - #{f_name}")
end
else
logger.warn("synced folder go-plugins have already been loaded. ignoring load request.")
end
end
end
end
end

View File

@ -0,0 +1,8 @@
require "vagrant/go_plugin/core"
module Vagrant
module GoPlugin
class ProviderClient
end
end
end

View File

@ -6,22 +6,7 @@ module Vagrant
# Helper class for wrapping actions in a go-plugin into
# something which can be used by Vagrant::Action::Builder
class Action
# @return [String] provider name associated to this class
def self.provider_name
@provider_name
end
# Set the provider name for this class
#
# @param [String] n provider name
# @return [String]
# @note can only be set once
def self.provider_name=(n)
if @provider_name
raise ArgumentError.new("Class provider name has already been set")
end
@provider_name = n.to_s.dup.freeze
end
include GRPCPlugin
# @return [String] action name associated to this class
def self.action_name
@ -44,12 +29,15 @@ module Vagrant
@app = app
end
# Run the action
def call(env)
env_data = env_dump(env)
result = VagrantGoPlugin._provider_run_action(
self.class.go_plugin_name, self.class.go_action_name,
env_data, env[:machine].environment.dump)
result.each_pair do |k, v|
result = plugin_client.run_action(
Vagrant::Proto::ExecuteAction.new(
name: self.class.action_name,
data: JSON.dump(env),
machine: JSON.dump(machine)))
response = JSON.load(result)
response.each_pair do |k, v|
env[k] = v
end
@app.call(env)
@ -60,7 +48,7 @@ module Vagrant
# provider so that it can be interacted with normally within
# Vagrant
class Provider < Vagrant.plugin("2", :provider)
include DirectGoPlugin
include GRPCPlugin
# @return [Vagrant::Machine]
attr_reader :machine
@ -71,7 +59,10 @@ module Vagrant
# @return [String] name of the provider plugin for this class
def provider_name
self.class.go_plugin_name
if !@_name
@_name = plugin_client.name(Vagrant::Proto::Empty.new).name
end
@_name
end
# Get callable action by name
@ -79,121 +70,19 @@ module Vagrant
# @param [Symbol] name name of the action
# @return [Class] callable action class
def action(name)
ProviderPlugin.interface.action(provider_name, name.to_s, machine)
end
# Execute capability with given name
#
# @param [Symbol] name Name of the capability
# @return [Object]
def capability(name, *args)
args = args.map do |arg|
arg.response_to(:to_json) ? arg.to_json : arg.to_s
end
result = ProviderPlugin.interface.capability(provider_name, args.to_json, machine)
begin
JSON.load(result)
rescue
result
end
end
# @return [Boolean] provider is installed
def is_installed?
ProviderPlugin.interface.is_installed(provider_name, machine)
end
# @return [Boolean] provider is usable
def is_usable?
ProviderPlugin.interface.is_usable(provider_name, machine)
end
# @return [nil]
def machine_id_changed
ProviderPlugin.interface.machine_id_changed(provider_name, machine)
nil
end
# @return [Hash] SSH information
def ssh_info
ProviderPlugin.interface.ssh_info(provider_name, machine)
end
# @return [Vagrant::MachineState]
def state
ProviderPlugin.interface.state(provider_name, machine)
end
end
def self.interface
unless @_interface
@_interface = Interface.new
end
@_interface
end
class Interface
include GoPlugin::Core
typedef :string, :action_name
typedef :string, :action_data
typedef :string, :capability_name
typedef :string, :capability_data
typedef :string, :provider_name
# provider plugin functions
attach_function :_provider_action, :ProviderAction,
[:provider_name, :action_name, :vagrant_machine], :plugin_result
attach_function :_provider_capability, :ProviderCapability,
[:provider_name, :capability_name, :capability_data, :vagrant_machine], :plugin_result
attach_function :_provider_is_installed, :ProviderIsInstalled,
[:provider_name, :vagrant_machine], :plugin_result
attach_function :_provider_is_usable, :ProviderIsUsable,
[:provider_name, :vagrant_machine], :plugin_result
attach_function :_provider_machine_id_changed, :ProviderMachineIdChanged,
[:provider_name, :vagrant_machine], :plugin_result
attach_function :_provider_run_action, :ProviderRunAction,
[:provider_name, :action_name, :action_data, :vagrant_machine], :plugin_result
attach_function :_provider_ssh_info, :ProviderSshInfo,
[:provider_name, :vagrant_machine], :plugin_result
attach_function :_provider_state, :ProviderState,
[:provider_name, :vagrant_machine], :plugin_result
attach_function :_list_providers, :ListProviders, [], :plugin_result
# List of provider plugins currently available
#
# @return [Array<String>]
def list_providers
result, ptr = _list_providers
load_result(result, ptr) || []
end
# Get callable action from a provider plugin
#
# @param [String] provider_name provider name for action
# @param [String] action_name name of requested action
# @param [Vagrant::Machine] machine instance of guest
# @return [Action]
def action(provider_name, action_name, machine)
result = load_result { _provider_action(provider_name,
action_name, dump_machine(machine)) }
klasses = Array(result).map do |klass_name|
result = plugin_client.action(
Vagrant::Proto::GenericAction.new(
name: name.to_s,
machine: JSON.dump(machine)))
klasses = result.items.map do |klass_name|
if klass_name.start_with?("self::")
action_name = klass_name.split("::", 2).last
klass = Class.new(Action)
klass.go_provider_name = provider_name
klass.go_action_name = action_name
klass.plugin_client = plugin_client
klass.action_name = action_name
klass.class_eval do
def self.name
"#{provider_name.capitalize}#{action_name.capitalize}".tr("_", "")
action_name.capitalize.tr("_", "")
end
end
klass
@ -202,7 +91,7 @@ module Vagrant
if memo.const_defined?(const)
memo.const_get(const)
else
raise NameError.new "Unknown action class `#{klass_name}`"
raise NameError, "Unknown action class `#{klass_name}`"
end
end
end
@ -214,91 +103,56 @@ module Vagrant
end
end
# Check if provider is installed
# Execute capability with given name
#
# @param [String] provider_name provider name for request
# @param [Vagrant::Machine] machine instance of guest
# @return [Boolean]
def is_installed(provider_name, machine)
result = load_result { _provider_is_installed(provider_name,
dump_machine(machine)) }
result
# @param [Symbol] name Name of the capability
# @return [Object]
def capability(name, *args)
r = plugin_client.provider_capability(
Vagrant::Proto::ProviderCapabilityRequest.new(
capability: Vagrant::Proto::ProviderCapability.new(
name: name.to_s,
provider: provider_name
),
machine: JSON.dump(machine),
arguments: JSON.dump(args)
)
)
JSON.load(r.result)
end
# Check if provider is usable
#
# @param [String] provider_name provider name for request
# @param [Vagrant::Machine] machine instance of guest
# @return [Boolean]
def is_usable(provider_name, machine)
result = load_result { _provider_is_usable(provider_name,
dump_machine(machine)) }
result
# @return [Boolean] provider is installed
def is_installed?
plugin_client.is_installed(Vagrant::Proto::Machine.new(
machine: JSON.dump(machine))).result
end
# Called when the ID of a machine has changed
#
# @param [String] provider_name provider name for request
# @param [Vagrant::Machine] machine instance of guest
def machine_id_changed(provider_name, machine)
load_result { _provider_machine_id_changed(provider_name, dump_machine(machine)) }
# @return [Boolean] provider is usable
def is_usable?
plugin_client.is_usable(Vagrant::Proto::Machine.new(
machine: JSON.dump(machine))).result
end
# @return [nil]
def machine_id_changed
plugin_client.machine_id_changed(Vagrant::Proto::Machine.new(
machine: JSON.dump(machine)))
nil
end
# Get SSH info for guest
#
# @param [String] provider_name provider name for request
# @param [Vagrant::Machine] machine instance of guest
# @return [Hash] SSH information
def ssh_info(provider_name, machine)
load_result { _provider_ssh_info(provider_name, dump_machine(machine)) }
def ssh_info
result = plugin_client.ssh_info(Vagrant::Proto::Machine.new(
machine: JSON.dump(machine))).to_hash
Vagrant::Util::HashWithIndifferentAccess.new(result)
end
# Get state of machine
#
# @param [String] provider_name provider name for request
# @param [Vagrant::Machine] machine instance of guest
# @return [Vagrant::MachineState]
def state(provider_name, machine)
result = load_result { _provider_state(provider_name, dump_machine(machine)) }
Vagrant::MachineState.new(result[:id],
result[:short_description], result[:long_description])
end
# Load any detected provider plugins
def load!
if !@loaded
@loaded = true
logger.debug("provider go-plugins have not been loaded... loading")
list_providers.each do |p_name, p_details|
logger.debug("loading go-plugin provider #{p_name}. details - #{p_details}")
# Create new provider class wrapper
provider_klass = Class.new(Provider)
provider_klass.go_plugin_name = p_name
# Create new plugin to register the provider
plugin_klass = Class.new(Vagrant.plugin("2"))
# Define the plugin
plugin_klass.class_eval do
name "#{p_name} Provider"
description p_details[:description]
end
# Register the provider
plugin_klass.provider(p_name.to_sym, priority: p_details.fetch(:priority, 0)) do
provider_klass
end
# Register any configuration support
ConfigPlugin.interface.generate_config(p_name, :provider, plugin_klass)
# Register any guest capabilities
CapabilityPlugin.interface.generate_guest_capabilities(p_name, :provider, plugin_klass)
# Register any host capabilities
CapabilityPlugin.interface.generate_host_capabilities(p_name, :provider, plugin_klass)
# Register any provider capabilities
CapabilityPlugin.interface.generate_provider_capabilities(p_name, :provider, plugin_klass)
logger.debug("completed loading provider go-plugin #{p_name}")
logger.info("loaded go-plugin provider - #{p_name}")
end
else
logger.warn("provider go-plugins have already been loaded. ignoring load request.")
end
def state
result = plugin_client.state(Vagrant::Proto::Machine.new(
machine: JSON.dump(machine)))
Vagrant::MachineState.new(result.id,
result.short_description, result.long_description)
end
end
end

View File

@ -9,34 +9,61 @@ module Vagrant
# synced folder so that it can be interacted with normally
# within Vagrant
class SyncedFolder < Vagrant.plugin("2", :synced_folder)
include DirectGoPlugin
include GRPCPlugin
# Cleanup synced folders
#
# @param [Vagrant::Machine] machine Vagrant guest
# @param [Hash] opts Folder options
def cleanup(machine, opts)
SyncedFolderPlugin.interface.cleanup(plugin_name, machine, opts)
plugin_client.cleanup(
Vagrant::Proto::SyncedFolders.new(
machine: JSON.dump(machine),
options: JSON.dump(opts),
folders: JSON.dump({})))
nil
end
# Disable synced folders
#
# @param [String] plugin_name Name of plugin
# @param [Vagrant::Machine] machine Vagrant guest
# @param [Hash] folders Folders to enable
# @param [Hash] opts Folder options
def disable(machine, folder, opts)
SyncedFolderPlugin.interface.disable(plugin_name, machine, folder, opts)
def disable(machine, folders, opts)
plugin_client.disable(
Vagrant::Proto::SyncedFolders.new(
machine: JSON.dump(machine),
folders: JSON.dump(folders),
options: JSON.dump(opts)))
nil
end
# Enable synced folders
#
# @param [String] plugin_name Name of plugin
# @param [Vagrant::Machine] machine Vagrant guest
# @param [Hash] folders Folders to enable
# @param [Hash] opts Folder options
def enable(machine, folder, opts)
SyncedFolderPlugin.interface.enable(plugin_name, machine, folder, opts)
def enable(machine, folders, opts)
plugin_client.enable(
Vagrant::Proto::SyncedFolders.new(
machine: JSON.dump(machine),
folders: JSON.dump(folders),
options: JSON.dump(options)))
nil
end
# Prepare synced folders
#
# @param [Vagrant::Machine] machine Vagrant guest
# @param [Hash] folders Folders to enable
# @param [Hash] opts Folder options
def prepare(machine, folders, opts)
plugin_client.prepare(
Vagrant::Proto::SyncedFolders.new(
machine: JSON.dump(machine),
folders: JSON.dump(folders),
options: JSON.dump(options)))
nil
end
# Check if plugin is usable
@ -44,125 +71,17 @@ module Vagrant
# @param [Vagrant::Machine] machine Vagrant guest
# @return [Boolean]
def usable?(machine, raise_error=false)
SyncedFolderPlugin.interface.usable?(plugin_name, machine)
end
end
# @return [Interface]
def self.interface
unless @_interface
@_interface = Interface.new
end
@_interface
end
# Synced folder interface to go-plugin
class Interface
include GoPlugin::Core
typedef :string, :folders
typedef :string, :folder_options
# synced folder plugin functions
attach_function :_cleanup, :SyncedFolderCleanup,
[:plugin_name, :vagrant_machine, :folder_options], :plugin_result
attach_function :_disable, :SyncedFolderDisable,
[:plugin_name, :vagrant_machine, :folders, :folder_options], :plugin_result
attach_function :_enable, :SyncedFolderEnable,
[:plugin_name, :vagrant_machine, :folders, :folder_options], :plugin_result
attach_function :_list_synced_folders, :ListSyncedFolders,
[], :plugin_result
attach_function :_usable, :SyncedFolderIsUsable,
[:plugin_name, :vagrant_machine], :plugin_result
# Cleanup synced folders
#
# @param [String] plugin_name Name of plugin
# @param [Vagrant::Machine] machine Vagrant guest
# @param [Hash] opts Folder options
def cleanup(plugin_name, machine, opts)
load_result {
_cleanup(plugin_name, dump_machine(machine), JSON.dump(opts))
}
plugin_client.is_usable(
Vagrant::Proto::Machine.new(
machine: JSON.dump(machine))).result
end
# Disable synced folders
#
# @param [String] plugin_name Name of plugin
# @param [Vagrant::Machine] machine Vagrant guest
# @param [Hash] folders Folders to enable
# @param [Hash] opts Folder options
def disable(plugin_name, machine, folders, opts)
load_result {
_disable(plugin_name, dump_machine(machine),
JSON.dump(folders), JSON.dump(opts))
}
end
# Enable synced folders
#
# @param [String] plugin_name Name of plugin
# @param [Vagrant::Machine] machine Vagrant guest
# @param [Hash] folders Folders to enable
# @param [Hash] opts Folder options
def enable(plugin_name, machine, folders, opts)
load_result {
_enable(plugin_name, dump_machine(machine),
JSON.dump(folders), JSON.dump(opts))
}
end
# List of available synced folder plugins
#
# @return [Array]
def list_synced_folders
load_result { _list_synced_folders }
end
# Check if plugin is usable
#
# @param [String] plugin_name Name of plugin
# @param [Vagrant::Machine] machine Vagrant guest
# @return [Boolean]
def usable?(plugin_name, machine)
load_result {
_usable(plugin_name, dump_machine(machine))
}
end
# Load any detected synced folder plugins
def load!
if !@loaded
@loaded = true
logger.debug("synced folder go-plugins have not been loaded... loading")
list_synced_folders.each do |f_name, f_details|
logger.debug("loading go-plugin synced folder #{f_name}. details - #{f_details}")
# Create new synced folder class wrapper
folder_klass = Class.new(SyncedFolder)
folder_klass.go_plugin_name = f_name
# Create new plugin to register the synced folder
plugin_klass = Class.new(Vagrant.plugin("2"))
# Define the plugin
plugin_klass.class_eval do
name "#{f_name} Synced Folder"
description f_details[:description]
end
# Register the synced folder
plugin_klass.synced_folder(f_name.to_sym, f_details.fetch(:priority, 10)) do
folder_klass
end
# Register any guest capabilities
CapabilityPlugin.interface.generate_guest_capabilities(f_name, :synced_folder, plugin_klass)
# Register any host capabilities
CapabilityPlugin.interface.generate_host_capabilities(f_name, :synced_folder, plugin_klass)
# Register any provider capabilities
CapabilityPlugin.interface.generate_provider_capabilities(f_name, :synced_folder, plugin_klass)
logger.debug("completed loading synced folder go-plugin #{f_name}")
logger.info("loaded go-plugin synced folder - #{f_name}")
end
else
logger.warn("synced folder go-plugins have already been loaded. ignoring load request.")
# @return [String]
def name
if !@_name
@_name = plugin_client.name(Vagrant::Proto::Empty.new).name
end
@_name
end
end
end

View File

@ -0,0 +1,122 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: vagrant.proto
require 'google/protobuf'
Google::Protobuf::DescriptorPool.generated_pool.build do
add_file("vagrant.proto", :syntax => :proto3) do
add_message "vagrant.proto.Empty" do
end
add_message "vagrant.proto.Machine" do
optional :machine, :string, 1
end
add_message "vagrant.proto.Valid" do
optional :result, :bool, 1
end
add_message "vagrant.proto.Identifier" do
optional :name, :string, 1
end
add_message "vagrant.proto.PluginInfo" do
optional :description, :string, 1
optional :priority, :int64, 2
end
add_message "vagrant.proto.Content" do
optional :target, :string, 1
optional :value, :string, 2
end
add_message "vagrant.proto.WriteResponse" do
optional :length, :int32, 1
end
add_message "vagrant.proto.SystemCapability" do
optional :name, :string, 1
optional :platform, :string, 2
end
add_message "vagrant.proto.ProviderCapability" do
optional :name, :string, 1
optional :provider, :string, 2
end
add_message "vagrant.proto.SystemCapabilityList" do
repeated :capabilities, :message, 1, "vagrant.proto.SystemCapability"
end
add_message "vagrant.proto.ProviderCapabilityList" do
repeated :capabilities, :message, 1, "vagrant.proto.ProviderCapability"
end
add_message "vagrant.proto.GenericResponse" do
optional :result, :string, 1
end
add_message "vagrant.proto.GuestCapabilityRequest" do
optional :capability, :message, 1, "vagrant.proto.SystemCapability"
optional :machine, :string, 2
optional :arguments, :string, 3
end
add_message "vagrant.proto.HostCapabilityRequest" do
optional :capability, :message, 1, "vagrant.proto.SystemCapability"
optional :environment, :string, 2
optional :arguments, :string, 3
end
add_message "vagrant.proto.ProviderCapabilityRequest" do
optional :capability, :message, 1, "vagrant.proto.ProviderCapability"
optional :machine, :string, 2
optional :arguments, :string, 3
end
add_message "vagrant.proto.Configuration" do
optional :data, :string, 1
optional :machine, :string, 2
end
add_message "vagrant.proto.ListResponse" do
repeated :items, :string, 1
end
add_message "vagrant.proto.SyncedFolders" do
optional :machine, :string, 1
optional :folders, :string, 2
optional :options, :string, 3
end
add_message "vagrant.proto.GenericAction" do
optional :name, :string, 1
optional :machine, :string, 2
end
add_message "vagrant.proto.ExecuteAction" do
optional :name, :string, 1
optional :data, :string, 2
optional :machine, :string, 3
end
add_message "vagrant.proto.MachineSshInfo" do
optional :host, :string, 1
optional :port, :int64, 2
optional :private_key_path, :string, 3
optional :username, :string, 4
end
add_message "vagrant.proto.MachineState" do
optional :id, :string, 1
optional :short_description, :string, 2
optional :long_description, :string, 3
end
end
end
module Vagrant
module Proto
Empty = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.Empty").msgclass
Machine = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.Machine").msgclass
Valid = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.Valid").msgclass
Identifier = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.Identifier").msgclass
PluginInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.PluginInfo").msgclass
Content = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.Content").msgclass
WriteResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.WriteResponse").msgclass
SystemCapability = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.SystemCapability").msgclass
ProviderCapability = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.ProviderCapability").msgclass
SystemCapabilityList = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.SystemCapabilityList").msgclass
ProviderCapabilityList = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.ProviderCapabilityList").msgclass
GenericResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.GenericResponse").msgclass
GuestCapabilityRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.GuestCapabilityRequest").msgclass
HostCapabilityRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.HostCapabilityRequest").msgclass
ProviderCapabilityRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.ProviderCapabilityRequest").msgclass
Configuration = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.Configuration").msgclass
ListResponse = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.ListResponse").msgclass
SyncedFolders = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.SyncedFolders").msgclass
GenericAction = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.GenericAction").msgclass
ExecuteAction = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.ExecuteAction").msgclass
MachineSshInfo = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.MachineSshInfo").msgclass
MachineState = Google::Protobuf::DescriptorPool.generated_pool.lookup("vagrant.proto.MachineState").msgclass
end
end

View File

@ -0,0 +1,223 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# Source: vagrant.proto for package 'vagrant.proto'
require 'grpc'
require_relative 'vagrant_pb'
module Vagrant
module Proto
module IO
class Service
include GRPC::GenericService
self.marshal_class_method = :encode
self.unmarshal_class_method = :decode
self.service_name = 'vagrant.proto.IO'
rpc :Read, Identifier, Content
rpc :Write, Content, WriteResponse
end
Stub = Service.rpc_stub_class
end
module GuestCapabilities
class Service
include GRPC::GenericService
self.marshal_class_method = :encode
self.unmarshal_class_method = :decode
self.service_name = 'vagrant.proto.GuestCapabilities'
rpc :GuestCapabilities, Empty, SystemCapabilityList
rpc :GuestCapability, GuestCapabilityRequest, GenericResponse
# IO helpers for streaming (copied from Stream service)
rpc :Read, Identifier, Content
rpc :Write, Content, WriteResponse
end
Stub = Service.rpc_stub_class
end
module HostCapabilities
class Service
include GRPC::GenericService
self.marshal_class_method = :encode
self.unmarshal_class_method = :decode
self.service_name = 'vagrant.proto.HostCapabilities'
rpc :HostCapabilities, Empty, SystemCapabilityList
rpc :HostCapability, HostCapabilityRequest, GenericResponse
# IO helpers for streaming (copied from Stream service)
rpc :Read, Identifier, Content
rpc :Write, Content, WriteResponse
end
Stub = Service.rpc_stub_class
end
module ProviderCapabilities
class Service
include GRPC::GenericService
self.marshal_class_method = :encode
self.unmarshal_class_method = :decode
self.service_name = 'vagrant.proto.ProviderCapabilities'
rpc :ProviderCapabilities, Empty, ProviderCapabilityList
rpc :ProviderCapability, ProviderCapabilityRequest, GenericResponse
# IO helpers for streaming (copied from Stream service)
rpc :Read, Identifier, Content
rpc :Write, Content, WriteResponse
end
Stub = Service.rpc_stub_class
end
module Config
class Service
include GRPC::GenericService
self.marshal_class_method = :encode
self.unmarshal_class_method = :decode
self.service_name = 'vagrant.proto.Config'
rpc :ConfigAttributes, Empty, ListResponse
rpc :ConfigLoad, Configuration, Configuration
rpc :ConfigValidate, Configuration, ListResponse
rpc :ConfigFinalize, Configuration, Configuration
# IO helpers for streaming (copied from Stream service)
rpc :Read, Identifier, Content
rpc :Write, Content, WriteResponse
end
Stub = Service.rpc_stub_class
end
module SyncedFolder
class Service
include GRPC::GenericService
self.marshal_class_method = :encode
self.unmarshal_class_method = :decode
self.service_name = 'vagrant.proto.SyncedFolder'
rpc :Cleanup, SyncedFolders, Empty
rpc :Disable, SyncedFolders, Empty
rpc :Enable, SyncedFolders, Empty
rpc :Info, Empty, PluginInfo
rpc :IsUsable, Machine, Valid
rpc :Name, Empty, Identifier
rpc :Prepare, SyncedFolders, Empty
# IO helpers for streaming (copied from Stream service)
rpc :Read, Identifier, Content
rpc :Write, Content, WriteResponse
# Guest capabilities helpers (copied from GuestCapabilities service)
rpc :GuestCapabilities, Empty, SystemCapabilityList
rpc :GuestCapability, GuestCapabilityRequest, GenericResponse
# Host capabilities helpers (copied from GuestCapabilities service)
rpc :HostCapabilities, Empty, SystemCapabilityList
rpc :HostCapability, HostCapabilityRequest, GenericResponse
end
Stub = Service.rpc_stub_class
end
module Provider
class Service
include GRPC::GenericService
self.marshal_class_method = :encode
self.unmarshal_class_method = :decode
self.service_name = 'vagrant.proto.Provider'
rpc :Action, GenericAction, ListResponse
rpc :Info, Empty, PluginInfo
rpc :IsInstalled, Machine, Valid
rpc :IsUsable, Machine, Valid
rpc :MachineIdChanged, Machine, Machine
rpc :Name, Empty, Identifier
rpc :RunAction, ExecuteAction, GenericResponse
rpc :SshInfo, Machine, MachineSshInfo
rpc :State, Machine, MachineState
# IO helpers for streaming (copied from Stream service)
rpc :Read, Identifier, Content
rpc :Write, Content, WriteResponse
# Config helpers (copied from Config service)
rpc :ConfigAttributes, Empty, ListResponse
rpc :ConfigLoad, Configuration, Configuration
rpc :ConfigValidate, Configuration, ListResponse
rpc :ConfigFinalize, Configuration, Configuration
# Guest capabilities helpers (copied from GuestCapabilities service)
rpc :GuestCapabilities, Empty, SystemCapabilityList
rpc :GuestCapability, GuestCapabilityRequest, GenericResponse
# Host capabilities helpers (copied from HostCapabilities service)
rpc :HostCapabilities, Empty, SystemCapabilityList
rpc :HostCapability, HostCapabilityRequest, GenericResponse
# Provider capabilities helpers (copied from ProviderCapabilities service)
rpc :ProviderCapabilities, Empty, ProviderCapabilityList
rpc :ProviderCapability, ProviderCapabilityRequest, GenericResponse
end
Stub = Service.rpc_stub_class
end
end
end
require 'logger'
# DebugIsTruncated extends the default Logger to truncate debug messages
class DebugIsTruncated < Logger
def debug(s)
super(truncate(s, 1024))
end
# Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
#
# 'Once upon a time in a world far far away'.truncate(27)
# # => "Once upon a time in a wo..."
#
# Pass a string or regexp <tt>:separator</tt> to truncate +text+ at a natural break:
#
# 'Once upon a time in a world far far away'.truncate(27, separator: ' ')
# # => "Once upon a time in a..."
#
# 'Once upon a time in a world far far away'.truncate(27, separator: /\s/)
# # => "Once upon a time in a..."
#
# The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
# for a total length not exceeding <tt>length</tt>:
#
# 'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)')
# # => "And they f... (continued)"
def truncate(s, truncate_at, options = {})
return s unless s.length > truncate_at
omission = options[:omission] || '...'
with_extra_room = truncate_at - omission.length
stop = \
if options[:separator]
rindex(options[:separator], with_extra_room) || with_extra_room
else
with_extra_room
end
"#{s[0, stop]}#{omission}"
end
end
# RubyLogger defines a logger for gRPC based on the standard ruby logger.
module RubyLogger
def logger
LOGGER
end
LOGGER = DebugIsTruncated.new(STDOUT)
LOGGER.level = Logger::DEBUG
end
# GRPC is the general RPC module
module GRPC
# Inject the noop #logger if no module-level logger method has been injected.
extend RubyLogger
end

View File

@ -578,6 +578,20 @@ module Vagrant
end
end
# @return [String]
def to_json(*args)
{
box: box,
config: config,
data_dir: data_dir,
environment: env,
id: id,
name: name,
provider_config: provider_config,
provider_name: provider_name
}.to_json(*args)
end
protected
# Returns the path to the file that stores the UID.

View File

@ -14,6 +14,9 @@ module Vagrant
super(&block)
hash.each do |key, value|
if value.is_a?(Hash) && !value.is_a?(self.class)
value = self.class.new(value)
end
self[convert_key(key)] = value
end
end

View File

@ -23,6 +23,8 @@ Gem::Specification.new do |s|
s.add_dependency "erubis", "~> 2.7.0"
s.add_dependency "i18n", "~> 1.1.1"
s.add_dependency "listen", "~> 3.1.5"
s.add_dependency "grpc", "~> 1.19.0"
s.add_dependency "grpc-tools", "~> 1.19.0"
s.add_dependency "hashicorp-checkpoint", "~> 0.1.5"
s.add_dependency "log4r", "~> 1.1.9", "< 1.1.11"
s.add_dependency "net-ssh", "~> 5.1.0"