Add basic support for go-plugin

This commit is contained in:
Chris Roberts 2018-12-06 14:07:01 -08:00
parent b28e6d95a6
commit b11c86528a
86 changed files with 11405 additions and 18 deletions

3
.gitignore vendored
View File

@ -48,5 +48,8 @@ doc/
.ruby-version
.rvmrc
*.so
*.bundle
# Box storage for spec
test/vagrant-spec/boxes/*.box

View File

@ -1,5 +1,10 @@
require 'rubygems'
require 'bundler/setup'
require 'rake/extensiontask'
Rake::ExtensionTask.new "go-plugin" do |ext|
ext.lib_dir = "lib/vagrant/go_plugin"
end
# Immediately sync all stdout so that tools like buildbot can
# immediately load in the output.

4
Vagrantfile vendored
View File

@ -14,6 +14,10 @@ Vagrant.configure("2") do |config|
end
end
config.vm.provider :vmware_desktop do |v, override|
v.foobar = 'hi'
end
config.vm.provision "shell", inline: $shell
config.push.define "www", strategy: "local-exec" do |push|

View File

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

98
ext/go-plugin/config.go Normal file
View File

@ -0,0 +1,98 @@
package main
import (
"C"
"encoding/json"
"errors"
"fmt"
"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 := vagrant.Response{}
p, err := getConfigPlugin(pluginName, pluginType)
if err != nil {
r.Error = err
return C.CString(r.Dump())
}
var cdata map[string]interface{}
r.Error = json.Unmarshal([]byte(C.GoString(data)), &cdata)
if r.Error != nil {
return C.CString(r.Dump())
}
r.Result, r.Error = p.Config.ConfigLoad(cdata)
return C.CString(r.Dump())
}
//export ConfigAttributes
func ConfigAttributes(pluginName, pluginType *C.char) *C.char {
r := vagrant.Response{}
p, err := getConfigPlugin(pluginName, pluginType)
if err != nil {
r.Error = err
return C.CString(r.Dump())
}
r.Result, r.Error = p.Config.ConfigAttributes()
return C.CString(r.Dump())
}
//export ConfigValidate
func ConfigValidate(pluginName, pluginType, data, machData *C.char) *C.char {
var m *vagrant.Machine
r := vagrant.Response{}
p, err := getConfigPlugin(pluginName, pluginType)
if err != nil {
r.Error = err
return C.CString(r.Dump())
}
var cdata map[string]interface{}
r.Error = json.Unmarshal([]byte(C.GoString(data)), &cdata)
if r.Error != nil {
return C.CString(r.Dump())
}
m, r.Error = vagrant.LoadMachine(C.GoString(machData), nil)
if r.Error != nil {
return C.CString(r.Dump())
}
r.Result, r.Error = p.Config.ConfigValidate(cdata, m)
return C.CString(r.Dump())
}
//export ConfigFinalize
func ConfigFinalize(pluginName, pluginType, data *C.char) *C.char {
r := vagrant.Response{}
p, err := getConfigPlugin(pluginName, pluginType)
if err != nil {
r.Error = err
return C.CString(r.Dump())
}
var cdata map[string]interface{}
r.Error = json.Unmarshal([]byte(C.GoString(data)), &cdata)
if r.Error == nil {
println("FINALIZE HAS VALID CONFIG")
r.Result, r.Error = p.Config.ConfigFinalize(cdata)
}
fmt.Printf("Full result: %s\n", r.Dump())
return C.CString(r.Dump())
}
func getConfigPlugin(pluginName, pluginType *C.char) (c *plugin.RemoteConfig, err error) {
pname := C.GoString(pluginName)
ptype := C.GoString(pluginType)
if ptype == "provider" {
p, ok := Plugins.Providers[pname]
if ok {
c = &plugin.RemoteConfig{
Client: p.Client,
Config: p.Provider}
}
}
if c == nil {
err = errors.New("Failed to locate requested plugin")
}
return
}

68
ext/go-plugin/extconf.rb Normal file
View File

@ -0,0 +1,68 @@
lib = File.expand_path('./../../../lib', File.expand_path(__FILE__))
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'mkmf'
require 'time'
find_executable('go')
go_version = /go version go(\d+\.\d+)/.match(`go version`).captures.first
raise "'go' version >=1.5.0 is required, found go #{go_version}" unless Gem::Dependency.new('', '>=1.5.0').match?('', go_version)
makefile = "Makefile"
makefile_content = <<MFEND
NAME := #{File.basename(File.dirname(File.expand_path(__FILE__)))}
BINARY := ${NAME}.so
V = 0
Q1 = $(V:1=)
Q = $(Q1:0=@)
ECHO1 = $(V:1=@:)
ECHO = $(ECHO1:0=@echo)
SOURCEDIR=.
SOURCES := $(shell find $(SOURCEDIR) -maxdepth 0 -name '*.go')
VERSION=1.0
BUILD_DATE=#{Time.now.iso8601}
cflags= $(optflags) $(warnflags)
optflags= -O3 -fno-fast-math
warnflags= -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wunused-variable -Wpointer-arith -Wwrite-strings -Wimplicit-function-declaration -Wdiv-by-zero -Wdeprecated-declarations
CCDLFLAGS= -fno-common
INCFLAGS= -I#{RbConfig::CONFIG['rubyhdrdir']}/ -I#{RbConfig::CONFIG['rubyarchhdrdir']}/ -I$(SOURCEDIR)
CFLAGS= $(CCDLFLAGS) $(cflags) -fno-common -pipe $(INCFLAGS)
LDFLAGS=-L#{RbConfig::CONFIG['libdir']} #{RbConfig::CONFIG['LIBRUBYARG']}
.DEFAULT_GOAL := $(BINARY)
.PHONY: help
help:
${ECHO} ${VERSION}
${ECHO} ${BUILD_DATE}
all:
make clean
$(BINARY)
$(BINARY): $(SOURCES)
CGO_CFLAGS="${CFLAGS}" CGO_LDFLAGS="${LDFLAGS}" go build -buildmode=c-shared -o ${BINARY} #{File.dirname(__FILE__)}/../../ext/${NAME}/
.PHONY: install
install:
# go install ${LDFLAGS} ./...
.PHONY: clean
clean:
if [ -f ${BINARY} ] ; then rm ${BINARY} ; fi
if [ -f lib/${BINARY} ] ; then rm lib/${BINARY} ; fi
MFEND
puts "creating Makefile"
File.open(makefile, 'w') do |f|
f.write(makefile_content.gsub!(/(?:^|\G) {2}/m,"\t"))
end
$makefile_created = true

View File

@ -0,0 +1,88 @@
package main
import (
"C"
"io/ioutil"
"os"
hclog "github.com/hashicorp/go-hclog"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin"
)
var Plugins *plugin.VagrantPlugin
//export Setup
func Setup(enableLogger, timestamps bool, logLevel *C.char) bool {
lvl := C.GoString(logLevel)
lopts := &hclog.LoggerOptions{Name: "vagrant"}
if enableLogger {
lopts.Output = os.Stderr
} else {
lopts.Output = ioutil.Discard
}
if !timestamps {
lopts.TimeFormat = " "
}
lopts.Level = hclog.LevelFromString(lvl)
vagrant.SetDefaultLogger(hclog.New(lopts))
if Plugins != nil {
Plugins.Logger.Error("plugins setup failure", "error", "already setup")
return false
}
Plugins = &plugin.VagrantPlugin{
PluginDirectories: []string{},
Providers: map[string]*plugin.RemoteProvider{},
Logger: vagrant.DefaultLogger().Named("go-plugin")}
return true
}
//export LoadPlugins
func LoadPlugins(plgpath *C.char) bool {
if Plugins == nil {
vagrant.DefaultLogger().Error("cannot load plugins", "error", "not setup")
return false
}
p := C.GoString(plgpath)
err := Plugins.LoadPlugins(p)
if err != nil {
Plugins.Logger.Error("failed loading plugins",
"path", p, "error", err)
return false
}
Plugins.Logger.Info("plugins successfully loaded", "path", p)
return true
}
//export Reset
func Reset() {
if Plugins != nil {
Plugins.Logger.Info("resetting loaded plugins")
Teardown()
dirs := Plugins.PluginDirectories
Plugins.PluginDirectories = []string{}
for _, p := range dirs {
Plugins.LoadPlugins(p)
}
} else {
Plugins.Logger.Warn("plugin reset failure", "error", "not setup")
}
}
//export Teardown
func Teardown() {
// only teardown if setup
if Plugins == nil {
vagrant.DefaultLogger().Error("cannot teardown plugins", "error", "not setup")
return
}
Plugins.Logger.Debug("tearing down any active plugins")
Plugins.Kill()
Plugins.Logger.Info("plugins have been halted")
}
// stub required for build
func main() {}

181
ext/go-plugin/provider.go Normal file
View File

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

View File

@ -0,0 +1,157 @@
package main
import (
"C"
"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 := vagrant.Response{Result: list}
if Plugins == nil {
return C.CString(r.Dump())
}
for n, p := range Plugins.SyncedFolders {
list[n] = p.SyncedFolder.Info()
}
r.Result = list
return C.CString(r.Dump())
}
//export SyncedFolderCleanup
func SyncedFolderCleanup(pluginName, machine, opts *C.char) *C.char {
r := vagrant.Response{}
p, err := getSyncedFolderPlugin(pluginName)
if err != nil {
r.Error = err
return C.CString(r.Dump())
}
m, err := vagrant.LoadMachine(C.GoString(machine), nil)
if err != nil {
r.Error = err
return C.CString(r.Dump())
}
var o vagrant.FolderOptions
r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o)
if r.Error != nil {
return C.CString(r.Dump())
}
r.Error = p.SyncedFolder.Cleanup(m, &o)
return C.CString(r.Dump())
}
//export SyncedFolderDisable
func SyncedFolderDisable(pluginName, machine, folders, opts *C.char) *C.char {
r := vagrant.Response{}
p, err := getSyncedFolderPlugin(pluginName)
if err != nil {
r.Error = err
return C.CString(r.Dump())
}
m, err := vagrant.LoadMachine(C.GoString(machine), nil)
if err != nil {
r.Error = err
return C.CString(r.Dump())
}
var f vagrant.FolderList
r.Error = json.Unmarshal([]byte(C.GoString(folders)), &f)
if r.Error != nil {
return C.CString(r.Dump())
}
var o vagrant.FolderOptions
r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o)
if r.Error != nil {
return C.CString(r.Dump())
}
r.Error = p.SyncedFolder.Disable(m, &f, &o)
return C.CString(r.Dump())
}
//export SyncedFolderEnable
func SyncedFolderEnable(pluginName, machine, folders, opts *C.char) *C.char {
r := vagrant.Response{}
p, err := getSyncedFolderPlugin(pluginName)
if err != nil {
r.Error = err
return C.CString(r.Dump())
}
m, err := vagrant.LoadMachine(C.GoString(machine), nil)
if err != nil {
r.Error = err
return C.CString(r.Dump())
}
var f vagrant.FolderList
r.Error = json.Unmarshal([]byte(C.GoString(folders)), &f)
if r.Error != nil {
return C.CString(r.Dump())
}
var o vagrant.FolderOptions
r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o)
if r.Error != nil {
return C.CString(r.Dump())
}
r.Error = p.SyncedFolder.Enable(m, &f, &o)
return C.CString(r.Dump())
}
//export SyncedFolderIsUsable
func SyncedFolderIsUsable(pluginName, machine *C.char) *C.char {
r := vagrant.Response{}
p, err := getSyncedFolderPlugin(pluginName)
if err != nil {
r.Error = err
return C.CString(r.Dump())
}
m, err := vagrant.LoadMachine(C.GoString(machine), nil)
if err != nil {
r.Error = err
return C.CString(r.Dump())
}
r.Result, r.Error = p.SyncedFolder.IsUsable(m)
return C.CString(r.Dump())
}
//export SyncedFolderPrepare
func SyncedFolderPrepare(pluginName, machine, folders, opts *C.char) *C.char {
r := vagrant.Response{}
p, err := getSyncedFolderPlugin(pluginName)
if err != nil {
r.Error = err
return C.CString(r.Dump())
}
m, err := vagrant.LoadMachine(C.GoString(machine), nil)
if err != nil {
r.Error = err
return C.CString(r.Dump())
}
var f vagrant.FolderList
r.Error = json.Unmarshal([]byte(C.GoString(folders)), &f)
if r.Error != nil {
return C.CString(r.Dump())
}
var o vagrant.FolderOptions
r.Error = json.Unmarshal([]byte(C.GoString(opts)), &o)
if r.Error != nil {
return C.CString(r.Dump())
}
r.Error = p.SyncedFolder.Prepare(m, &f, &o)
return C.CString(r.Dump())
}
func getSyncedFolderPlugin(pluginName *C.char) (c *plugin.RemoteSyncedFolder, err error) {
pname := C.GoString(pluginName)
p, ok := Plugins.SyncedFolders[pname]
if !ok {
err = errors.New("Failed to locate requested plugin")
return
}
c = &plugin.RemoteSyncedFolder{
Client: p.Client,
SyncedFolder: p.SyncedFolder}
return
}

View File

@ -0,0 +1,10 @@
package vagrant
type Box struct {
Name string `json:"name"`
Provider string `json:"provider"`
Version string `json:"version"`
Directory string `json:"directory"`
Metadata map[string]string `json:"metadata"`
MetadataURL string `json:"metadata_url"`
}

View File

@ -0,0 +1,57 @@
package vagrant
type SystemCapability struct {
Name string `json:"name"`
Platform string `json:"platform"`
}
type ProviderCapability struct {
Name string `json:"name"`
Provider string `json:"name"`
}
type GuestCapabilities interface {
GuestCapabilities() (caps []SystemCapability, err error)
GuestCapability(cap *SystemCapability, args interface{}, machine *Machine) (result interface{}, err error)
}
type HostCapabilities interface {
HostCapabilities() (caps []SystemCapability, err error)
HostCapability(cap *SystemCapability, args interface{}, env *Environment) (result interface{}, err error)
}
type ProviderCapabilities interface {
ProviderCapabilities() (caps []ProviderCapability, err error)
ProviderCapability(cap *ProviderCapability, args interface{}, machine *Machine) (result interface{}, err error)
}
type NoGuestCapabilities struct{}
type NoHostCapabilities struct{}
type NoProviderCapabilities struct{}
func (g *NoGuestCapabilities) GuestCapabilities() (caps []SystemCapability, err error) {
caps = make([]SystemCapability, 0)
return
}
func (g *NoGuestCapabilities) GuestCapability(c *SystemCapability, a interface{}, m *Machine) (r interface{}, err error) {
return
}
func (h *NoHostCapabilities) HostCapabilities() (caps []SystemCapability, err error) {
caps = make([]SystemCapability, 0)
return
}
func (h *NoHostCapabilities) HostCapability(c *SystemCapability, a interface{}, e *Environment) (r interface{}, err error) {
return
}
func (p *NoProviderCapabilities) ProviderCapabilities() (caps []ProviderCapability, err error) {
caps = make([]ProviderCapability, 0)
return
}
func (p *NoProviderCapabilities) ProviderCapability(cap *ProviderCapability, args interface{}, machine *Machine) (result interface{}, err error) {
return
}

View File

@ -0,0 +1,77 @@
package vagrant
import (
"testing"
)
func TestNoGuestCapabilities(t *testing.T) {
g := NoGuestCapabilities{}
caps, err := g.GuestCapabilities()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if len(caps) != 0 {
t.Fatalf("guest capabilities should be empty")
}
}
func TestNoGuestCapability(t *testing.T) {
g := NoGuestCapabilities{}
m := &Machine{}
cap := &SystemCapability{"Test", "Test"}
r, err := g.GuestCapability(cap, "args", m)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if r != nil {
t.Fatalf("capability returned unexpected result")
}
}
func TestNoHostCapabilities(t *testing.T) {
h := NoHostCapabilities{}
caps, err := h.HostCapabilities()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if len(caps) != 0 {
t.Fatalf("host capabilities should be empty")
}
}
func TestNoHostCapability(t *testing.T) {
h := NoHostCapabilities{}
e := &Environment{}
cap := &SystemCapability{"Test", "Test"}
r, err := h.HostCapability(cap, "args", e)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if r != nil {
t.Fatalf("capability returned unexpected result")
}
}
func TestNoProviderCapabilities(t *testing.T) {
p := NoProviderCapabilities{}
caps, err := p.ProviderCapabilities()
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if len(caps) != 0 {
t.Fatalf("provider capabilities should be empty")
}
}
func TestNoProviderCapability(t *testing.T) {
p := NoProviderCapabilities{}
m := &Machine{}
cap := &ProviderCapability{"Test", "Test"}
r, err := p.ProviderCapability(cap, "args", m)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if r != nil {
t.Fatalf("capability returned unexpected result")
}
}

View File

@ -0,0 +1,202 @@
package communicator
import (
"fmt"
"io"
"strings"
"sync"
"unicode"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/mitchellh/iochan"
)
// CmdDisconnect is a sentinel value to indicate a RemoteCmd
// exited because the remote side disconnected us.
const CmdDisconnect int = 2300218
// Cmd represents a remote command being prepared or run.
type Cmd struct {
// Command is the command to run remotely. This is executed as if
// it were a shell command, so you are expected to do any shell escaping
// necessary.
Command string
// Stdin specifies the process's standard input. If Stdin is
// nil, the process reads from an empty bytes.Buffer.
Stdin io.Reader
// Stdout and Stderr represent the process's standard output and
// error.
//
// If either is nil, it will be set to ioutil.Discard.
Stdout io.Writer
Stderr io.Writer
// Once Wait returns, his will contain the exit code of the process.
exitStatus int
// Internal fields
exitCh chan struct{}
// err is used to store any error reported by the Communicator during
// execution.
err error
// This thing is a mutex, lock when making modifications concurrently
sync.Mutex
}
// Init must be called by the Communicator before executing the command.
func (c *Cmd) Init() {
c.Lock()
defer c.Unlock()
c.exitCh = make(chan struct{})
}
// SetExitStatus stores the exit status of the remote command as well as any
// communicator related error. SetExitStatus then unblocks any pending calls
// to Wait.
// This should only be called by communicators executing the remote.Cmd.
func (c *Cmd) SetExitStatus(status int, err error) {
c.Lock()
defer c.Unlock()
c.exitStatus = status
c.err = err
close(c.exitCh)
}
// StartWithUi runs the remote command and streams the output to any
// configured Writers for stdout/stderr, while also writing each line
// as it comes to a Ui.
func (r *Cmd) StartWithUi(c Communicator, ui vagrant.Ui) error {
stdout_r, stdout_w := io.Pipe()
stderr_r, stderr_w := io.Pipe()
defer stdout_w.Close()
defer stderr_w.Close()
// Retain the original stdout/stderr that we can replace back in.
originalStdout := r.Stdout
originalStderr := r.Stderr
defer func() {
r.Lock()
defer r.Unlock()
r.Stdout = originalStdout
r.Stderr = originalStderr
}()
// Set the writers for the output so that we get it streamed to us
if r.Stdout == nil {
r.Stdout = stdout_w
} else {
r.Stdout = io.MultiWriter(r.Stdout, stdout_w)
}
if r.Stderr == nil {
r.Stderr = stderr_w
} else {
r.Stderr = io.MultiWriter(r.Stderr, stderr_w)
}
// Start the command
if err := c.Start(r); err != nil {
return err
}
// Create the channels we'll use for data
exitCh := make(chan struct{})
stdoutCh := iochan.DelimReader(stdout_r, '\n')
stderrCh := iochan.DelimReader(stderr_r, '\n')
// Start the goroutine to watch for the exit
go func() {
defer close(exitCh)
defer stdout_w.Close()
defer stderr_w.Close()
r.Wait()
}()
// Loop and get all our output
OutputLoop:
for {
select {
case output := <-stderrCh:
if output != "" {
ui.Say(r.cleanOutputLine(output))
}
case output := <-stdoutCh:
if output != "" {
ui.Say(r.cleanOutputLine(output))
}
case <-exitCh:
break OutputLoop
}
}
// Make sure we finish off stdout/stderr because we may have gotten
// a message from the exit channel before finishing these first.
for output := range stdoutCh {
ui.Say(r.cleanOutputLine(output))
}
for output := range stderrCh {
ui.Say(r.cleanOutputLine(output))
}
return nil
}
// Wait waits for the remote command to complete.
// Wait may return an error from the communicator, or an ExitError if the
// process exits with a non-zero exit status.
func (c *Cmd) Wait() error {
<-c.exitCh
c.Lock()
defer c.Unlock()
if c.err != nil || c.exitStatus != 0 {
return &ExitError{
Command: c.Command,
ExitStatus: c.exitStatus,
Err: c.err,
}
}
return nil
}
// cleanOutputLine cleans up a line so that '\r' don't muck up the
// UI output when we're reading from a remote command.
func (r *Cmd) cleanOutputLine(line string) string {
// Trim surrounding whitespace
line = strings.TrimRightFunc(line, unicode.IsSpace)
// Trim up to the first carriage return, since that text would be
// lost anyways.
idx := strings.LastIndex(line, "\r")
if idx > -1 {
line = line[idx+1:]
}
return line
}
// ExitError is returned by Wait to indicate and error executing the remote
// command, or a non-zero exit status.
type ExitError struct {
Command string
ExitStatus int
Err error
}
func (e *ExitError) Error() string {
if e.Err != nil {
return fmt.Sprintf("error executing %q: %v", e.Command, e.Err)
}
return fmt.Sprintf("%q exit status: %d", e.Command, e.ExitStatus)
}

View File

@ -0,0 +1 @@
package communicator

View File

@ -0,0 +1,117 @@
package communicator
import (
"context"
"fmt"
"io"
"os"
"sync/atomic"
"time"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
)
type Communicator interface {
Connect() error
Disconnect() error
Timeout() time.Duration
Start(*Cmd) error
Download(path string, output io.Writer) error
DownloadDir(dst, src string, excludes []string) error
Upload(dst string, src io.Reader, srcinfo *os.FileInfo) error
UploadDir(dst, src string, excludes []string) error
}
// maxBackoffDelay is the maximum delay between retry attempts
var maxBackoffDelay = 20 * time.Second
var initialBackoffDelay = time.Second
var logger = vagrant.DefaultLogger().Named("communicator")
// Fatal is an interface that error values can return to halt Retry
type Fatal interface {
FatalError() error
}
// Retry retries the function f until it returns a nil error, a Fatal error, or
// the context expires.
func Retry(ctx context.Context, f func() error) error {
// container for atomic error value
type errWrap struct {
E error
}
// Try the function in a goroutine
var errVal atomic.Value
doneCh := make(chan struct{})
go func() {
defer close(doneCh)
delay := time.Duration(0)
for {
// If our context ended, we want to exit right away.
select {
case <-ctx.Done():
return
case <-time.After(delay):
}
// Try the function call
err := f()
// return if we have no error, or a FatalError
done := false
switch e := err.(type) {
case nil:
done = true
case Fatal:
err = e.FatalError()
done = true
}
errVal.Store(errWrap{err})
if done {
return
}
logger.Warn("retryable error", "error", err)
delay *= 2
if delay == 0 {
delay = initialBackoffDelay
}
if delay > maxBackoffDelay {
delay = maxBackoffDelay
}
logger.Info("sleeping for retry", "duration", delay)
}
}()
// Wait for completion
select {
case <-ctx.Done():
case <-doneCh:
}
var lastErr error
// Check if we got an error executing
if ev, ok := errVal.Load().(errWrap); ok {
lastErr = ev.E
}
// Check if we have a context error to check if we're interrupted or timeout
switch ctx.Err() {
case context.Canceled:
return fmt.Errorf("interrupted - last error: %v", lastErr)
case context.DeadlineExceeded:
return fmt.Errorf("timeout - last error: %v", lastErr)
}
if lastErr != nil {
return lastErr
}
return nil
}

View File

@ -0,0 +1,59 @@
package none
import (
"errors"
"io"
"os"
"time"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/communicator"
)
type Communicator struct {
config string
}
// Creates a null vagrant.Communicator implementation. This takes
// an already existing configuration.
func New(config string) (result *Communicator, err error) {
// Establish an initial connection and connect
result = &Communicator{
config: config,
}
return
}
func (c *Communicator) Connect() (err error) {
return
}
func (c *Communicator) Disconnect() (err error) {
return
}
func (c *Communicator) Start(cmd *communicator.Cmd) (err error) {
cmd.Init()
cmd.SetExitStatus(0, nil)
return
}
func (c *Communicator) Upload(path string, input io.Reader, fi *os.FileInfo) error {
return errors.New("Upload is not implemented when communicator = 'none'")
}
func (c *Communicator) UploadDir(dst string, src string, excl []string) error {
return errors.New("UploadDir is not implemented when communicator = 'none'")
}
func (c *Communicator) Download(path string, output io.Writer) error {
return errors.New("Download is not implemented when communicator = 'none'")
}
func (c *Communicator) DownloadDir(dst string, src string, excl []string) error {
return errors.New("DownloadDir is not implemented when communicator = 'none'")
}
func (c *Communicator) Timeout() time.Duration {
return 0
}

View File

@ -0,0 +1,12 @@
package none
import (
"testing"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/communicator"
)
func TestCommIsCommunicator(t *testing.T) {
// Force failure with explanation of why it's not valid
var _ communicator.Communicator = new(Communicator)
}

View File

@ -0,0 +1,949 @@
package ssh
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/communicator"
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
// ErrHandshakeTimeout is returned from New() whenever we're unable to establish
// an ssh connection within a certain timeframe. By default the handshake time-
// out period is 1 minute. You can change it with Config.HandshakeTimeout.
var ErrHandshakeTimeout = fmt.Errorf("Timeout during SSH handshake")
var logger = vagrant.DefaultLogger().Named("communicator.ssh")
type Communicator struct {
client *ssh.Client
config *Config
conn net.Conn
address string
}
// Config is the structure used to configure the SSH communicator.
type Config struct {
// The configuration of the Go SSH connection
SSHConfig *ssh.ClientConfig
// Connection returns a new connection. The current connection
// in use will be closed as part of the Close method, or in the
// case an error occurs.
Connection func() (net.Conn, error)
// Pty, if true, will request a pty from the remote end.
Pty bool
// DisableAgentForwarding, if true, will not forward the SSH agent.
DisableAgentForwarding bool
// HandshakeTimeout limits the amount of time we'll wait to handshake before
// saying the connection failed.
HandshakeTimeout time.Duration
// UseSftp, if true, sftp will be used instead of scp for file transfers
UseSftp bool
// KeepAliveInterval sets how often we send a channel request to the
// server. A value < 0 disables.
KeepAliveInterval time.Duration
// Timeout is how long to wait for a read or write to succeed.
Timeout time.Duration
}
// Creates a new vagrant.Communicator implementation over SSH. This takes
// an already existing TCP connection and SSH configuration.
func New(address string, config *Config) (result *Communicator, err error) {
// Establish an initial connection and connect
result = &Communicator{
config: config,
address: address,
}
// reset the logger in case custom default has been set
logger = vagrant.DefaultLogger().Named("communicator.ssh")
return
}
func (c *Communicator) Connect() error {
return c.reconnect()
}
func (c *Communicator) Disconnect() (err error) {
if c.conn != nil {
logger.Info("closing connection")
err = c.conn.Close()
} else {
err = errors.New("No connection currently established to close")
}
return
}
func (c *Communicator) Timeout() time.Duration {
return c.config.Timeout
}
func (c *Communicator) Start(cmd *communicator.Cmd) (err error) {
session, err := c.newSession()
if err != nil {
return
}
// Setup our session
session.Stdin = cmd.Stdin
session.Stdout = cmd.Stdout
session.Stderr = cmd.Stderr
if c.config.Pty {
// Request a PTY
termModes := ssh.TerminalModes{
ssh.ECHO: 0, // do not echo
ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}
if err = session.RequestPty("xterm", 40, 80, termModes); err != nil {
return
}
}
logger.Debug("starting remote command", "command", cmd.Command)
err = session.Start(cmd.Command + "\n")
if err != nil {
return
}
go func() {
if c.config.KeepAliveInterval <= 0 {
return
}
c := time.NewTicker(c.config.KeepAliveInterval)
defer c.Stop()
for range c.C {
_, err := session.SendRequest("keepalive@vagrantup.com", true, nil)
if err != nil {
return
}
}
}()
// Start a goroutine to wait for the session to end and set the
// exit boolean and status.
go func() {
defer session.Close()
err := session.Wait()
exitStatus := 0
if err != nil {
switch err.(type) {
case *ssh.ExitError:
exitStatus = err.(*ssh.ExitError).ExitStatus()
logger.Error("remote command exited non-zero",
"exitcode", exitStatus, "command", cmd.Command)
case *ssh.ExitMissingError:
logger.Error("remote command exited without exit status or exit signal",
"command", cmd.Command)
exitStatus = communicator.CmdDisconnect
default:
logger.Error("error waiting for ssh session", "error", err)
}
}
cmd.SetExitStatus(exitStatus, err)
}()
return
}
func (c *Communicator) Upload(path string, input io.Reader, fi *os.FileInfo) error {
if c.config.UseSftp {
return c.sftpUploadSession(path, input, fi)
} else {
return c.scpUploadSession(path, input, fi)
}
}
func (c *Communicator) UploadDir(dst string, src string, excl []string) error {
logger.Debug("uploading directory", "source", src, "destination", dst)
if c.config.UseSftp {
return c.sftpUploadDirSession(dst, src, excl)
} else {
return c.scpUploadDirSession(dst, src, excl)
}
}
func (c *Communicator) DownloadDir(src string, dst string, excl []string) error {
logger.Debug("downloading directory", "source", src, "destination", dst)
scpFunc := func(w io.Writer, stdoutR *bufio.Reader) error {
dirStack := []string{dst}
for {
fmt.Fprint(w, "\x00")
// read file info
fi, err := stdoutR.ReadString('\n')
if err != nil {
return err
}
if len(fi) < 0 {
return fmt.Errorf("empty response from server")
}
switch fi[0] {
case '\x01', '\x02':
return fmt.Errorf("%s", fi[1:])
case 'C', 'D':
break
case 'E':
dirStack = dirStack[:len(dirStack)-1]
if len(dirStack) == 0 {
fmt.Fprint(w, "\x00")
return nil
}
continue
default:
return fmt.Errorf("unexpected server response (%x)", fi[0])
}
var mode int64
var size int64
var name string
logger.Debug("download directory", "str", fi)
n, err := fmt.Sscanf(fi[1:], "%o %d %s", &mode, &size, &name)
if err != nil || n != 3 {
return fmt.Errorf("can't parse server response (%s)", fi)
}
if size < 0 {
return fmt.Errorf("negative file size")
}
logger.Debug("download directory", "mode", mode, "size", size, "name", name)
dst = filepath.Join(dirStack...)
switch fi[0] {
case 'D':
err = os.MkdirAll(filepath.Join(dst, name), os.FileMode(mode))
if err != nil {
return err
}
dirStack = append(dirStack, name)
continue
case 'C':
fmt.Fprint(w, "\x00")
err = scpDownloadFile(filepath.Join(dst, name), stdoutR, size, os.FileMode(mode))
if err != nil {
return err
}
}
if err := checkSCPStatus(stdoutR); err != nil {
return err
}
}
}
return c.scpSession("scp -vrf "+src, scpFunc)
}
func (c *Communicator) Download(path string, output io.Writer) error {
if c.config.UseSftp {
return c.sftpDownloadSession(path, output)
}
return c.scpDownloadSession(path, output)
}
func (c *Communicator) newSession() (session *ssh.Session, err error) {
logger.Debug("opening new ssh session")
if c.client == nil {
err = errors.New("client not available")
} else {
session, err = c.client.NewSession()
}
if err != nil {
logger.Error("ssh session open failure", "error", err)
if err := c.reconnect(); err != nil {
return nil, err
}
if c.client == nil {
return nil, errors.New("client not available")
} else {
return c.client.NewSession()
}
}
return session, nil
}
func (c *Communicator) reconnect() (err error) {
// Ignore errors here because we don't care if it fails
c.Disconnect()
// Set the conn and client to nil since we'll recreate it
c.conn = nil
c.client = nil
logger.Debug("reconnection to tcp connection for ssh")
c.conn, err = c.config.Connection()
if err != nil {
// Explicitly set this to the REAL nil. Connection() can return
// a nil implementation of net.Conn which will make the
// "if c.conn == nil" check fail above. Read here for more information
// on this psychotic language feature:
//
// http://golang.org/doc/faq#nil_error
c.conn = nil
logger.Error("reconnection failure", "error", err)
return
}
if c.config.Timeout > 0 {
c.conn = &timeoutConn{c.conn, c.config.Timeout, c.config.Timeout}
}
logger.Debug("handshaking with ssh")
// Default timeout to 1 minute if it wasn't specified (zero value). For
// when you need to handshake from low orbit.
var duration time.Duration
if c.config.HandshakeTimeout == 0 {
duration = 1 * time.Minute
} else {
duration = c.config.HandshakeTimeout
}
connectionEstablished := make(chan struct{}, 1)
var sshConn ssh.Conn
var sshChan <-chan ssh.NewChannel
var req <-chan *ssh.Request
go func() {
sshConn, sshChan, req, err = ssh.NewClientConn(c.conn, c.address, c.config.SSHConfig)
close(connectionEstablished)
}()
select {
case <-connectionEstablished:
// We don't need to do anything here. We just want select to block until
// we connect or timeout.
case <-time.After(duration):
if c.conn != nil {
c.conn.Close()
}
if sshConn != nil {
sshConn.Close()
}
return ErrHandshakeTimeout
}
if err != nil {
return
}
logger.Debug("handshake complete")
if sshConn != nil {
c.client = ssh.NewClient(sshConn, sshChan, req)
}
c.connectToAgent()
return
}
func (c *Communicator) connectToAgent() {
if c.client == nil {
return
}
if c.config.DisableAgentForwarding {
logger.Info("SSH agent forwarding is disabled")
return
}
// open connection to the local agent
socketLocation := os.Getenv("SSH_AUTH_SOCK")
if socketLocation == "" {
logger.Info("no local agent socket, will not connect agent")
return
}
agentConn, err := net.Dial("unix", socketLocation)
if err != nil {
logger.Error("could not connect to local agent socket", "path", socketLocation)
return
}
// create agent and add in auth
forwardingAgent := agent.NewClient(agentConn)
if forwardingAgent == nil {
logger.Error("could not create agent client")
agentConn.Close()
return
}
// add callback for forwarding agent to SSH config
// XXX - might want to handle reconnects appending multiple callbacks
auth := ssh.PublicKeysCallback(forwardingAgent.Signers)
c.config.SSHConfig.Auth = append(c.config.SSHConfig.Auth, auth)
agent.ForwardToAgent(c.client, forwardingAgent)
// Setup a session to request agent forwarding
session, err := c.newSession()
if err != nil {
return
}
defer session.Close()
err = agent.RequestAgentForwarding(session)
if err != nil {
logger.Error("request agent forwarding failed", "error", err)
return
}
logger.Info("agent forwarding enabled")
return
}
func (c *Communicator) sftpUploadSession(path string, input io.Reader, fi *os.FileInfo) error {
sftpFunc := func(client *sftp.Client) error {
return c.sftpUploadFile(path, input, client, fi)
}
return c.sftpSession(sftpFunc)
}
func (c *Communicator) sftpUploadFile(path string, input io.Reader, client *sftp.Client, fi *os.FileInfo) error {
logger.Debug("sftp uploading", "path", path)
f, err := client.Create(path)
if err != nil {
return err
}
defer f.Close()
if _, err = io.Copy(f, input); err != nil {
return err
}
if fi != nil && (*fi).Mode().IsRegular() {
mode := (*fi).Mode().Perm()
err = client.Chmod(path, mode)
if err != nil {
return err
}
}
return nil
}
func (c *Communicator) sftpUploadDirSession(dst string, src string, excl []string) error {
sftpFunc := func(client *sftp.Client) error {
rootDst := dst
if src[len(src)-1] != '/' {
logger.Debug("no trailing slash, creating the source directory name")
rootDst = filepath.Join(dst, filepath.Base(src))
}
walkFunc := func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// Calculate the final destination using the
// base source and root destination
relSrc, err := filepath.Rel(src, path)
if err != nil {
return err
}
finalDst := filepath.Join(rootDst, relSrc)
// In Windows, Join uses backslashes which we don't want to get
// to the sftp server
finalDst = filepath.ToSlash(finalDst)
// Skip the creation of the target destination directory since
// it should exist and we might not even own it
if finalDst == dst {
return nil
}
return c.sftpVisitFile(finalDst, path, info, client)
}
return filepath.Walk(src, walkFunc)
}
return c.sftpSession(sftpFunc)
}
func (c *Communicator) sftpMkdir(path string, client *sftp.Client, fi os.FileInfo) error {
logger.Debug("sftp create directory", "path", path)
if err := client.Mkdir(path); err != nil {
// Do not consider it an error if the directory existed
remoteFi, fiErr := client.Lstat(path)
if fiErr != nil || !remoteFi.IsDir() {
return err
}
}
mode := fi.Mode().Perm()
if err := client.Chmod(path, mode); err != nil {
return err
}
return nil
}
func (c *Communicator) sftpVisitFile(dst string, src string, fi os.FileInfo, client *sftp.Client) error {
if !fi.IsDir() {
f, err := os.Open(src)
if err != nil {
return err
}
defer f.Close()
return c.sftpUploadFile(dst, f, client, &fi)
} else {
err := c.sftpMkdir(dst, client, fi)
return err
}
}
func (c *Communicator) sftpDownloadSession(path string, output io.Writer) error {
sftpFunc := func(client *sftp.Client) error {
f, err := client.Open(path)
if err != nil {
return err
}
defer f.Close()
if _, err = io.Copy(output, f); err != nil {
return err
}
return nil
}
return c.sftpSession(sftpFunc)
}
func (c *Communicator) sftpSession(f func(*sftp.Client) error) error {
client, err := c.newSftpClient()
if err != nil {
return fmt.Errorf("sftpSession error: %s", err.Error())
}
defer client.Close()
return f(client)
}
func (c *Communicator) newSftpClient() (*sftp.Client, error) {
session, err := c.newSession()
if err != nil {
return nil, err
}
if err := session.RequestSubsystem("sftp"); err != nil {
return nil, err
}
pw, err := session.StdinPipe()
if err != nil {
return nil, err
}
pr, err := session.StdoutPipe()
if err != nil {
return nil, err
}
// Capture stdout so we can return errors to the user
var stdout bytes.Buffer
tee := io.TeeReader(pr, &stdout)
client, err := sftp.NewClientPipe(tee, pw)
if err != nil && stdout.Len() > 0 {
logger.Error("upload failed", "error", stdout.Bytes())
}
return client, err
}
func (c *Communicator) scpUploadSession(path string, input io.Reader, fi *os.FileInfo) error {
// The target directory and file for talking the SCP protocol
target_dir := filepath.Dir(path)
target_file := filepath.Base(path)
// On windows, filepath.Dir uses backslash separators (ie. "\tmp").
// This does not work when the target host is unix. Switch to forward slash
// which works for unix and windows
target_dir = filepath.ToSlash(target_dir)
// Escape spaces in remote directory
target_dir = strings.Replace(target_dir, " ", "\\ ", -1)
scpFunc := func(w io.Writer, stdoutR *bufio.Reader) error {
return scpUploadFile(target_file, input, w, stdoutR, fi)
}
return c.scpSession("scp -vt "+target_dir, scpFunc)
}
func (c *Communicator) scpUploadDirSession(dst string, src string, excl []string) error {
scpFunc := func(w io.Writer, r *bufio.Reader) error {
uploadEntries := func() error {
f, err := os.Open(src)
if err != nil {
return err
}
defer f.Close()
entries, err := f.Readdir(-1)
if err != nil {
return err
}
return scpUploadDir(src, entries, w, r)
}
if src[len(src)-1] != '/' {
logger.Debug("no trailing slash, creating the source directory name")
fi, err := os.Stat(src)
if err != nil {
return err
}
return scpUploadDirProtocol(filepath.Base(src), w, r, uploadEntries, fi)
} else {
// Trailing slash, so only upload the contents
return uploadEntries()
}
}
return c.scpSession("scp -rvt "+dst, scpFunc)
}
func (c *Communicator) scpDownloadSession(path string, output io.Writer) error {
scpFunc := func(w io.Writer, stdoutR *bufio.Reader) error {
fmt.Fprint(w, "\x00")
// read file info
fi, err := stdoutR.ReadString('\n')
if err != nil {
return err
}
if len(fi) < 0 {
return fmt.Errorf("empty response from server")
}
switch fi[0] {
case '\x01', '\x02':
return fmt.Errorf("%s", fi[1:])
case 'C':
case 'D':
return fmt.Errorf("remote file is directory")
default:
return fmt.Errorf("unexpected server response (%x)", fi[0])
}
var mode string
var size int64
n, err := fmt.Sscanf(fi, "%6s %d ", &mode, &size)
if err != nil || n != 2 {
return fmt.Errorf("can't parse server response (%s)", fi)
}
if size < 0 {
return fmt.Errorf("negative file size")
}
fmt.Fprint(w, "\x00")
if _, err := io.CopyN(output, stdoutR, size); err != nil {
return err
}
fmt.Fprint(w, "\x00")
return checkSCPStatus(stdoutR)
}
if !strings.Contains(path, " ") {
return c.scpSession("scp -vf "+path, scpFunc)
}
return c.scpSession("scp -vf "+strconv.Quote(path), scpFunc)
}
func (c *Communicator) scpSession(scpCommand string, f func(io.Writer, *bufio.Reader) error) error {
session, err := c.newSession()
if err != nil {
return err
}
defer session.Close()
// Get a pipe to stdin so that we can send data down
stdinW, err := session.StdinPipe()
if err != nil {
return err
}
// We only want to close once, so we nil w after we close it,
// and only close in the defer if it hasn't been closed already.
defer func() {
if stdinW != nil {
stdinW.Close()
}
}()
// Get a pipe to stdout so that we can get responses back
stdoutPipe, err := session.StdoutPipe()
if err != nil {
return err
}
stdoutR := bufio.NewReader(stdoutPipe)
// Set stderr to a bytes buffer
stderr := new(bytes.Buffer)
session.Stderr = stderr
// Start the sink mode on the other side
// TODO(mitchellh): There are probably issues with shell escaping the path
logger.Debug("starting remote scp process", "command", scpCommand)
if err := session.Start(scpCommand); err != nil {
return err
}
// Call our callback that executes in the context of SCP. We ignore
// EOF errors if they occur because it usually means that SCP prematurely
// ended on the other side.
logger.Debug("started scp session, beginning transfers")
if err := f(stdinW, stdoutR); err != nil && err != io.EOF {
return err
}
// Close the stdin, which sends an EOF, and then set w to nil so that
// our defer func doesn't close it again since that is unsafe with
// the Go SSH package.
logger.Debug("scp sessiono complete, closing stdin pipe")
stdinW.Close()
stdinW = nil
// Wait for the SCP connection to close, meaning it has consumed all
// our data and has completed. Or has errored.
logger.Debug("waiting for ssh session to complete")
err = session.Wait()
if err != nil {
if exitErr, ok := err.(*ssh.ExitError); ok {
// Otherwise, we have an ExitError, meaning we can just read
// the exit status
logger.Debug("non-zero exit status", "exitcode", exitErr.ExitStatus())
stdoutB, err := ioutil.ReadAll(stdoutR)
if err != nil {
return err
}
logger.Debug("scp output", "output", stdoutB)
// If we exited with status 127, it means SCP isn't available.
// Return a more descriptive error for that.
if exitErr.ExitStatus() == 127 {
return errors.New(
"SCP failed to start. This usually means that SCP is not\n" +
"properly installed on the remote system.")
}
}
return err
}
logger.Debug("scp stderr", "length", stderr.Len(), "content", stderr.String())
return nil
}
// checkSCPStatus checks that a prior command sent to SCP completed
// successfully. If it did not complete successfully, an error will
// be returned.
func checkSCPStatus(r *bufio.Reader) error {
code, err := r.ReadByte()
if err != nil {
return err
}
if code != 0 {
// Treat any non-zero (really 1 and 2) as fatal errors
message, _, err := r.ReadLine()
if err != nil {
return fmt.Errorf("Error reading error message: %s", err)
}
return errors.New(string(message))
}
return nil
}
func scpDownloadFile(dst string, src io.Reader, size int64, mode os.FileMode) error {
f, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode)
if err != nil {
return err
}
defer f.Close()
if _, err := io.CopyN(f, src, size); err != nil {
return err
}
return nil
}
func scpUploadFile(dst string, src io.Reader, w io.Writer, r *bufio.Reader, fi *os.FileInfo) error {
var mode os.FileMode
var size int64
if fi != nil && (*fi).Mode().IsRegular() {
mode = (*fi).Mode().Perm()
size = (*fi).Size()
} else {
// Create a temporary file where we can copy the contents of the src
// so that we can determine the length, since SCP is length-prefixed.
tf, err := ioutil.TempFile("", "vagrant-upload")
if err != nil {
return fmt.Errorf("Error creating temporary file for upload: %s", err)
}
defer os.Remove(tf.Name())
defer tf.Close()
mode = 0644
logger.Debug("copying input data to temporary file to read length")
if _, err := io.Copy(tf, src); err != nil {
return fmt.Errorf("Error copying input data into local temporary "+
"file. Check that TEMPDIR has enough space. Error: %s", err)
}
// Sync the file so that the contents are definitely on disk, then
// read the length of it.
if err := tf.Sync(); err != nil {
return fmt.Errorf("Error creating temporary file for upload: %s", err)
}
// Seek the file to the beginning so we can re-read all of it
if _, err := tf.Seek(0, 0); err != nil {
return fmt.Errorf("Error creating temporary file for upload: %s", err)
}
tfi, err := tf.Stat()
if err != nil {
return fmt.Errorf("Error creating temporary file for upload: %s", err)
}
size = tfi.Size()
src = tf
}
// Start the protocol
perms := fmt.Sprintf("C%04o", mode)
logger.Debug("scp uploading", "path", dst, "perms", perms, "size", size)
fmt.Fprintln(w, perms, size, dst)
if err := checkSCPStatus(r); err != nil {
return err
}
if _, err := io.CopyN(w, src, size); err != nil {
return err
}
fmt.Fprint(w, "\x00")
return checkSCPStatus(r)
}
func scpUploadDirProtocol(name string, w io.Writer, r *bufio.Reader, f func() error, fi os.FileInfo) error {
logger.Debug("scp directory upload", "path", name)
mode := fi.Mode().Perm()
perms := fmt.Sprintf("D%04o 0", mode)
fmt.Fprintln(w, perms, name)
err := checkSCPStatus(r)
if err != nil {
return err
}
if err := f(); err != nil {
return err
}
fmt.Fprintln(w, "E")
return err
}
func scpUploadDir(root string, fs []os.FileInfo, w io.Writer, r *bufio.Reader) error {
for _, fi := range fs {
realPath := filepath.Join(root, fi.Name())
// Track if this is actually a symlink to a directory. If it is
// a symlink to a file we don't do any special behavior because uploading
// a file just works. If it is a directory, we need to know so we
// treat it as such.
isSymlinkToDir := false
if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
symPath, err := filepath.EvalSymlinks(realPath)
if err != nil {
return err
}
symFi, err := os.Lstat(symPath)
if err != nil {
return err
}
isSymlinkToDir = symFi.IsDir()
}
if !fi.IsDir() && !isSymlinkToDir {
// It is a regular file (or symlink to a file), just upload it
f, err := os.Open(realPath)
if err != nil {
return err
}
err = func() error {
defer f.Close()
return scpUploadFile(fi.Name(), f, w, r, &fi)
}()
if err != nil {
return err
}
continue
}
// It is a directory, recursively upload
err := scpUploadDirProtocol(fi.Name(), w, r, func() error {
f, err := os.Open(realPath)
if err != nil {
return err
}
defer f.Close()
entries, err := f.Readdir(-1)
if err != nil {
return err
}
return scpUploadDir(realPath, entries, w, r)
}, fi)
if err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,235 @@
// +build !race
package ssh
import (
"bytes"
"fmt"
"net"
"testing"
"time"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/communicator"
"golang.org/x/crypto/ssh"
)
// private key for mock server
const testServerPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA19lGVsTqIT5iiNYRgnoY1CwkbETW5cq+Rzk5v/kTlf31XpSU
70HVWkbTERECjaYdXM2gGcbb+sxpq6GtXf1M3kVomycqhxwhPv4Cr6Xp4WT/jkFx
9z+FFzpeodGJWjOH6L2H5uX1Cvr9EDdQp9t9/J32/qBFntY8GwoUI/y/1MSTmMiF
tupdMODN064vd3gyMKTwrlQ8tZM6aYuyOPsutLlUY7M5x5FwMDYvnPDSeyT/Iw0z
s3B+NCyqeeMd2T7YzQFnRATj0M7rM5LoSs7DVqVriOEABssFyLj31PboaoLhOKgc
qoM9khkNzr7FHVvi+DhYM2jD0DwvqZLN6NmnLwIDAQABAoIBAQCGVj+kuSFOV1lT
+IclQYA6bM6uY5mroqcSBNegVxCNhWU03BxlW//BE9tA/+kq53vWylMeN9mpGZea
riEMIh25KFGWXqXlOOioH8bkMsqA8S7sBmc7jljyv+0toQ9vCCtJ+sueNPhxQQxH
D2YvUjfzBQ04I9+wn30BByDJ1QA/FoPsunxIOUCcRBE/7jxuLYcpR+JvEF68yYIh
atXRld4W4in7T65YDR8jK1Uj9XAcNeDYNpT/M6oFLx1aPIlkG86aCWRO19S1jLPT
b1ZAKHHxPMCVkSYW0RqvIgLXQOR62D0Zne6/2wtzJkk5UCjkSQ2z7ZzJpMkWgDgN
ifCULFPBAoGBAPoMZ5q1w+zB+knXUD33n1J+niN6TZHJulpf2w5zsW+m2K6Zn62M
MXndXlVAHtk6p02q9kxHdgov34Uo8VpuNjbS1+abGFTI8NZgFo+bsDxJdItemwC4
KJ7L1iz39hRN/ZylMRLz5uTYRGddCkeIHhiG2h7zohH/MaYzUacXEEy3AoGBANz8
e/msleB+iXC0cXKwds26N4hyMdAFE5qAqJXvV3S2W8JZnmU+sS7vPAWMYPlERPk1
D8Q2eXqdPIkAWBhrx4RxD7rNc5qFNcQWEhCIxC9fccluH1y5g2M+4jpMX2CT8Uv+
3z+NoJ5uDTXZTnLCfoZzgZ4nCZVZ+6iU5U1+YXFJAoGBANLPpIV920n/nJmmquMj
orI1R/QXR9Cy56cMC65agezlGOfTYxk5Cfl5Ve+/2IJCfgzwJyjWUsFx7RviEeGw
64o7JoUom1HX+5xxdHPsyZ96OoTJ5RqtKKoApnhRMamau0fWydH1yeOEJd+TRHhc
XStGfhz8QNa1dVFvENczja1vAoGABGWhsd4VPVpHMc7lUvrf4kgKQtTC2PjA4xoc
QJ96hf/642sVE76jl+N6tkGMzGjnVm4P2j+bOy1VvwQavKGoXqJBRd5Apppv727g
/SM7hBXKFc/zH80xKBBgP/i1DR7kdjakCoeu4ngeGywvu2jTS6mQsqzkK+yWbUxJ
I7mYBsECgYB/KNXlTEpXtz/kwWCHFSYA8U74l7zZbVD8ul0e56JDK+lLcJ0tJffk
gqnBycHj6AhEycjda75cs+0zybZvN4x65KZHOGW/O/7OAWEcZP5TPb3zf9ned3Hl
NsZoFj52ponUM6+99A2CmezFCN16c4mbA//luWF+k3VVqR6BpkrhKw==
-----END RSA PRIVATE KEY-----`
var serverConfig = &ssh.ServerConfig{
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
if c.User() == "user" && string(pass) == "pass" {
return nil, nil
}
return nil, fmt.Errorf("password rejected for %q", c.User())
},
}
func init() {
// Parse and set the private key of the server, required to accept connections
signer, err := ssh.ParsePrivateKey([]byte(testServerPrivateKey))
if err != nil {
panic("unable to parse private key: " + err.Error())
}
serverConfig.AddHostKey(signer)
}
func newMockLineServer(t *testing.T) string {
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to listen for connection: %s", err)
}
go func() {
defer l.Close()
c, err := l.Accept()
if err != nil {
t.Errorf("Unable to accept incoming connection: %s", err)
}
defer c.Close()
conn, chans, _, err := ssh.NewServerConn(c, serverConfig)
if err != nil {
t.Logf("Handshaking error: %v", err)
}
t.Log("Accepted SSH connection")
for newChannel := range chans {
channel, _, err := newChannel.Accept()
if err != nil {
t.Errorf("Unable to accept channel.")
}
t.Log("Accepted channel")
go func(channelType string) {
defer channel.Close()
conn.OpenChannel(channelType, nil)
}(newChannel.ChannelType())
}
conn.Close()
}()
return l.Addr().String()
}
func newMockBrokenServer(t *testing.T) string {
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("Unable tp listen for connection: %s", err)
}
go func() {
defer l.Close()
c, err := l.Accept()
if err != nil {
t.Errorf("Unable to accept incoming connection: %s", err)
}
defer c.Close()
// This should block for a period of time longer than our timeout in
// the test case. That way we invoke a failure scenario.
t.Log("Block on handshaking for SSH connection")
time.Sleep(5 * time.Second)
}()
return l.Addr().String()
}
func TestCommIsCommunicator(t *testing.T) {
var raw interface{}
raw = &Communicator{}
if _, ok := raw.(communicator.Communicator); !ok {
t.Fatalf("Communicator must be a communicator")
}
}
func TestNew_Invalid(t *testing.T) {
clientConfig := &ssh.ClientConfig{
User: "user",
Auth: []ssh.AuthMethod{
ssh.Password("i-am-invalid"),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
address := newMockLineServer(t)
conn := func() (net.Conn, error) {
conn, err := net.Dial("tcp", address)
if err != nil {
t.Errorf("Unable to accept incoming connection: %v", err)
}
return conn, err
}
config := &Config{
Connection: conn,
SSHConfig: clientConfig,
}
comm, err := New(address, config)
if err != nil {
t.Fatalf("Failed to setup communicator: %s", err)
}
err = comm.Connect()
if err == nil {
t.Fatal("should have had an error connecting")
}
}
func TestStart(t *testing.T) {
clientConfig := &ssh.ClientConfig{
User: "user",
Auth: []ssh.AuthMethod{
ssh.Password("pass"),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
address := newMockLineServer(t)
conn := func() (net.Conn, error) {
conn, err := net.Dial("tcp", address)
if err != nil {
t.Fatalf("unable to dial to remote side: %s", err)
}
return conn, err
}
config := &Config{
Connection: conn,
SSHConfig: clientConfig,
}
client, err := New(address, config)
if err != nil {
t.Fatalf("error connecting to SSH: %s", err)
}
cmd := &communicator.Cmd{
Command: "echo foo",
Stdout: new(bytes.Buffer),
}
client.Start(cmd)
}
func TestHandshakeTimeout(t *testing.T) {
clientConfig := &ssh.ClientConfig{
User: "user",
Auth: []ssh.AuthMethod{
ssh.Password("pass"),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
address := newMockBrokenServer(t)
conn := func() (net.Conn, error) {
conn, err := net.Dial("tcp", address)
if err != nil {
t.Fatalf("unable to dial to remote side: %s", err)
}
return conn, err
}
config := &Config{
Connection: conn,
SSHConfig: clientConfig,
HandshakeTimeout: 50 * time.Millisecond,
}
comm, err := New(address, config)
if err != nil {
t.Fatalf("Failed to setup communicator: %s", err)
}
err = comm.Connect()
if err != ErrHandshakeTimeout {
// Note: there's another error that can come back from this call:
// ssh: handshake failed: EOF
// This should appear in cases where the handshake fails because of
// malformed (or no) data sent back by the server, but should not happen
// in a timeout scenario.
t.Fatalf("Expected handshake timeout, got: %s", err)
}
}

View File

@ -0,0 +1,88 @@
package ssh
import (
"fmt"
"net"
"time"
"golang.org/x/crypto/ssh"
"golang.org/x/net/proxy"
)
// ConnectFunc is a convenience method for returning a function
// that just uses net.Dial to communicate with the remote end that
// is suitable for use with the SSH communicator configuration.
func ConnectFunc(network, addr string) func() (net.Conn, error) {
return func() (net.Conn, error) {
c, err := net.DialTimeout(network, addr, 15*time.Second)
if err != nil {
return nil, err
}
if tcpConn, ok := c.(*net.TCPConn); ok {
tcpConn.SetKeepAlive(true)
tcpConn.SetKeepAlivePeriod(5 * time.Second)
}
return c, nil
}
}
// ProxyConnectFunc is a convenience method for returning a function
// that connects to a host using SOCKS5 proxy
func ProxyConnectFunc(socksProxy string, socksAuth *proxy.Auth, network, addr string) func() (net.Conn, error) {
return func() (net.Conn, error) {
// create a socks5 dialer
dialer, err := proxy.SOCKS5("tcp", socksProxy, socksAuth, proxy.Direct)
if err != nil {
return nil, fmt.Errorf("Can't connect to the proxy: %s", err)
}
c, err := dialer.Dial(network, addr)
if err != nil {
return nil, err
}
return c, nil
}
}
// BastionConnectFunc is a convenience method for returning a function
// that connects to a host over a bastion connection.
func BastionConnectFunc(
bProto string,
bAddr string,
bConf *ssh.ClientConfig,
proto string,
addr string) func() (net.Conn, error) {
return func() (net.Conn, error) {
// Connect to the bastion
bastion, err := ssh.Dial(bProto, bAddr, bConf)
if err != nil {
return nil, fmt.Errorf("Error connecting to bastion: %s", err)
}
// Connect through to the end host
conn, err := bastion.Dial(proto, addr)
if err != nil {
bastion.Close()
return nil, err
}
// Wrap it up so we close both things properly
return &bastionConn{
Conn: conn,
Bastion: bastion,
}, nil
}
}
type bastionConn struct {
net.Conn
Bastion *ssh.Client
}
func (c *bastionConn) Close() error {
c.Conn.Close()
return c.Bastion.Close()
}

View File

@ -0,0 +1,30 @@
package ssh
import (
"net"
"time"
)
// timeoutConn wraps a net.Conn, and sets a deadline for every read
// and write operation.
type timeoutConn struct {
net.Conn
ReadTimeout time.Duration
WriteTimeout time.Duration
}
func (c *timeoutConn) Read(b []byte) (int, error) {
err := c.Conn.SetReadDeadline(time.Now().Add(c.ReadTimeout))
if err != nil {
return 0, err
}
return c.Conn.Read(b)
}
func (c *timeoutConn) Write(b []byte) (int, error) {
err := c.Conn.SetWriteDeadline(time.Now().Add(c.WriteTimeout))
if err != nil {
return 0, err
}
return c.Conn.Write(b)
}

View File

@ -0,0 +1,25 @@
package ssh
import (
"golang.org/x/crypto/ssh"
)
// An implementation of ssh.KeyboardInteractiveChallenge that simply sends
// back the password for all questions. The questions are logged.
func PasswordKeyboardInteractive(password string) ssh.KeyboardInteractiveChallenge {
return func(user, instruction string, questions []string, echos []bool) ([]string, error) {
logger.Info("keyboard interactive challenge", "user", user,
"instructions", instruction)
for i, question := range questions {
logger.Info("challenge question", "number", i+1, "question", question)
}
// Just send the password back for all questions
answers := make([]string, len(questions))
for i := range answers {
answers[i] = password
}
return answers, nil
}
}

View File

@ -0,0 +1,28 @@
package ssh
import (
"reflect"
"testing"
"golang.org/x/crypto/ssh"
)
func TestPasswordKeyboardInteractive_Impl(t *testing.T) {
var raw interface{}
raw = PasswordKeyboardInteractive("foo")
if _, ok := raw.(ssh.KeyboardInteractiveChallenge); !ok {
t.Fatal("PasswordKeyboardInteractive must implement KeyboardInteractiveChallenge")
}
}
func TestPasswordKeyboardInteractive_Challenge(t *testing.T) {
p := PasswordKeyboardInteractive("foo")
result, err := p("foo", "bar", []string{"one", "two"}, nil)
if err != nil {
t.Fatalf("err not nil: %s", err)
}
if !reflect.DeepEqual(result, []string{"foo", "foo"}) {
t.Fatalf("invalid password: %#v", result)
}
}

View File

@ -0,0 +1,257 @@
package winrm
import (
"encoding/base64"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/communicator"
"github.com/masterzen/winrm"
"github.com/packer-community/winrmcp/winrmcp"
)
var logger = vagrant.DefaultLogger().Named("communicator.winrm")
// Communicator represents the WinRM communicator
type Communicator struct {
config *Config
client *winrm.Client
endpoint *winrm.Endpoint
}
// New creates a new communicator implementation over WinRM.
func New(config *Config) (*Communicator, error) {
endpoint := &winrm.Endpoint{
Host: config.Host,
Port: config.Port,
HTTPS: config.Https,
Insecure: config.Insecure,
/*
TODO
HTTPS: connInfo.HTTPS,
Insecure: connInfo.Insecure,
CACert: connInfo.CACert,
*/
}
// Create the client
params := *winrm.DefaultParameters
if config.TransportDecorator != nil {
params.TransportDecorator = config.TransportDecorator
}
params.Timeout = formatDuration(config.Timeout)
client, err := winrm.NewClientWithParameters(
endpoint, config.Username, config.Password, &params)
if err != nil {
return nil, err
}
return &Communicator{
config: config,
client: client,
endpoint: endpoint,
}, nil
}
func (c *Communicator) Connect() (err error) {
// Create the shell to verify the connection
logger.Debug("connecting to remote shell")
shell, err := c.client.CreateShell()
if err != nil {
logger.Error("connection failure", "error", err)
return
}
if err = shell.Close(); err != nil {
logger.Error("connection close failure", "error", err)
}
return
}
// Start implementation of communicator.Communicator interface
func (c *Communicator) Start(rc *communicator.Cmd) error {
shell, err := c.client.CreateShell()
if err != nil {
return err
}
logger.Info("starting remote command", "commmand", rc.Command)
rc.Init()
cmd, err := shell.Execute(rc.Command)
if err != nil {
return err
}
go runCommand(shell, cmd, rc)
return nil
}
func runCommand(shell *winrm.Shell, cmd *winrm.Command, rc *communicator.Cmd) {
defer shell.Close()
var wg sync.WaitGroup
copyFunc := func(w io.Writer, r io.Reader) {
defer wg.Done()
io.Copy(w, r)
}
if rc.Stdout != nil && cmd.Stdout != nil {
wg.Add(1)
go copyFunc(rc.Stdout, cmd.Stdout)
} else {
logger.Warn("failed to read stdout", "command", rc.Command)
}
if rc.Stderr != nil && cmd.Stderr != nil {
wg.Add(1)
go copyFunc(rc.Stderr, cmd.Stderr)
} else {
logger.Warn("failed to read stderr", "command", rc.Command)
}
cmd.Wait()
wg.Wait()
code := cmd.ExitCode()
logger.Info("command complete", "exitcode", code, "command", rc.Command)
rc.SetExitStatus(code, nil)
}
// Upload implementation of communicator.Communicator interface
func (c *Communicator) Upload(path string, input io.Reader, fi *os.FileInfo) error {
wcp, err := c.newCopyClient()
if err != nil {
return fmt.Errorf("Was unable to create winrm client: %s", err)
}
if strings.HasSuffix(path, `\`) {
// path is a directory
path += filepath.Base((*fi).Name())
}
logger.Info("uploading file", "path", path)
return wcp.Write(path, input)
}
// UploadDir implementation of communicator.Communicator interface
func (c *Communicator) UploadDir(dst string, src string, exclude []string) error {
if !strings.HasSuffix(src, "/") {
dst = fmt.Sprintf("%s\\%s", dst, filepath.Base(src))
}
logger.Info("uploading directory", "source", src, "destination", dst)
wcp, err := c.newCopyClient()
if err != nil {
return err
}
return wcp.Copy(src, dst)
}
func (c *Communicator) Download(src string, dst io.Writer) error {
client, err := c.newWinRMClient()
if err != nil {
return err
}
encodeScript := `$file=[System.IO.File]::ReadAllBytes("%s"); Write-Output $([System.Convert]::ToBase64String($file))`
base64DecodePipe := &Base64Pipe{w: dst}
cmd := winrm.Powershell(fmt.Sprintf(encodeScript, src))
_, err = client.Run(cmd, base64DecodePipe, ioutil.Discard)
return err
}
func (c *Communicator) DownloadDir(src string, dst string, exclude []string) error {
return fmt.Errorf("WinRM doesn't support download dir.")
}
func (c *Communicator) getClientConfig() *winrmcp.Config {
return &winrmcp.Config{
Auth: winrmcp.Auth{
User: c.config.Username,
Password: c.config.Password,
},
Https: c.config.Https,
Insecure: c.config.Insecure,
OperationTimeout: c.config.Timeout,
MaxOperationsPerShell: 15, // lowest common denominator
TransportDecorator: c.config.TransportDecorator,
}
}
func (c *Communicator) newCopyClient() (*winrmcp.Winrmcp, error) {
addr := fmt.Sprintf("%s:%d", c.endpoint.Host, c.endpoint.Port)
clientConfig := c.getClientConfig()
return winrmcp.New(addr, clientConfig)
}
func (c *Communicator) newWinRMClient() (*winrm.Client, error) {
conf := c.getClientConfig()
// Shamelessly borrowed from the winrmcp client to ensure
// that the client is configured using the same defaulting behaviors that
// winrmcp uses even we we aren't using winrmcp. This ensures similar
// behavior between upload, download, and copy functions. We can't use the
// one generated by winrmcp because it isn't exported.
var endpoint *winrm.Endpoint
endpoint = &winrm.Endpoint{
Host: c.endpoint.Host,
Port: c.endpoint.Port,
HTTPS: conf.Https,
Insecure: conf.Insecure,
TLSServerName: conf.TLSServerName,
CACert: conf.CACertBytes,
Timeout: conf.ConnectTimeout,
}
params := winrm.NewParameters(
winrm.DefaultParameters.Timeout,
winrm.DefaultParameters.Locale,
winrm.DefaultParameters.EnvelopeSize,
)
params.TransportDecorator = conf.TransportDecorator
params.Timeout = "PT3M"
client, err := winrm.NewClientWithParameters(
endpoint, conf.Auth.User, conf.Auth.Password, params)
return client, err
}
type Base64Pipe struct {
w io.Writer // underlying writer (file, buffer)
}
func (d *Base64Pipe) ReadFrom(r io.Reader) (int64, error) {
b, err := ioutil.ReadAll(r)
if err != nil {
return 0, err
}
var i int
i, err = d.Write(b)
if err != nil {
return 0, err
}
return int64(i), err
}
func (d *Base64Pipe) Write(p []byte) (int, error) {
dst := make([]byte, base64.StdEncoding.DecodedLen(len(p)))
decodedBytes, err := base64.StdEncoding.Decode(dst, p)
if err != nil {
return 0, err
}
return d.w.Write(dst[0:decodedBytes])
}

View File

@ -0,0 +1,123 @@
package winrm
import (
"bytes"
"io"
"strings"
"testing"
"time"
"github.com/dylanmei/winrmtest"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/communicator"
)
const PAYLOAD = "stuff"
const BASE64_ENCODED_PAYLOAD = "c3R1ZmY="
func newMockWinRMServer(t *testing.T) *winrmtest.Remote {
wrm := winrmtest.NewRemote()
wrm.CommandFunc(
winrmtest.MatchText("echo foo"),
func(out, err io.Writer) int {
out.Write([]byte("foo"))
return 0
})
wrm.CommandFunc(
winrmtest.MatchPattern(`^echo c29tZXRoaW5n >> ".*"$`),
func(out, err io.Writer) int {
return 0
})
wrm.CommandFunc(
winrmtest.MatchPattern(`^echo `+BASE64_ENCODED_PAYLOAD+` >> ".*"$`),
func(out, err io.Writer) int {
return 0
})
wrm.CommandFunc(
winrmtest.MatchPattern(`^powershell.exe -EncodedCommand .*$`),
func(out, err io.Writer) int {
out.Write([]byte(BASE64_ENCODED_PAYLOAD))
return 0
})
wrm.CommandFunc(
winrmtest.MatchText("powershell"),
func(out, err io.Writer) int {
return 0
})
wrm.CommandFunc(
winrmtest.MatchText(`powershell -Command "(Get-Item C:/Temp/vagrant.cmd) -is [System.IO.DirectoryInfo]"`),
func(out, err io.Writer) int {
out.Write([]byte("False"))
return 0
})
return wrm
}
func TestStart(t *testing.T) {
wrm := newMockWinRMServer(t)
defer wrm.Close()
c, err := New(&Config{
Host: wrm.Host,
Port: wrm.Port,
Username: "user",
Password: "pass",
Timeout: 30 * time.Second,
})
if err != nil {
t.Fatalf("error creating communicator: %s", err)
}
var cmd communicator.Cmd
stdout := new(bytes.Buffer)
cmd.Command = "echo foo"
cmd.Stdout = stdout
err = c.Start(&cmd)
if err != nil {
t.Fatalf("error executing remote command: %s", err)
}
cmd.Wait()
if stdout.String() != "foo" {
t.Fatalf("bad command response: expected %q, got %q", "foo", stdout.String())
}
}
func TestUpload(t *testing.T) {
wrm := newMockWinRMServer(t)
defer wrm.Close()
c, err := New(&Config{
Host: wrm.Host,
Port: wrm.Port,
Username: "user",
Password: "pass",
Timeout: 30 * time.Second,
})
if err != nil {
t.Fatalf("error creating communicator: %s", err)
}
file := "C:/Temp/vagrant.cmd"
err = c.Upload(file, strings.NewReader(PAYLOAD), nil)
if err != nil {
t.Fatalf("error uploading file: %s", err)
}
dest := new(bytes.Buffer)
err = c.Download(file, dest)
if err != nil {
t.Fatalf("error downloading file: %s", err)
}
downloadedPayload := dest.String()
if downloadedPayload != PAYLOAD {
t.Fatalf("files are not equal: expected [%s] length: %v, got [%s] length %v", PAYLOAD, len(PAYLOAD), downloadedPayload, len(downloadedPayload))
}
}

View File

@ -0,0 +1,19 @@
package winrm
import (
"time"
"github.com/masterzen/winrm"
)
// Config is used to configure the WinRM connection
type Config struct {
Host string
Port int
Username string
Password string
Timeout time.Duration
Https bool
Insecure bool
TransportDecorator func() winrm.Transporter
}

View File

@ -0,0 +1,32 @@
package winrm
import (
"fmt"
"time"
)
// formatDuration formats the given time.Duration into an ISO8601
// duration string.
func formatDuration(duration time.Duration) string {
// We're not supporting negative durations
if duration.Seconds() <= 0 {
return "PT0S"
}
h := int(duration.Hours())
m := int(duration.Minutes()) - (h * 60)
s := int(duration.Seconds()) - (h*3600 + m*60)
res := "PT"
if h > 0 {
res = fmt.Sprintf("%s%dH", res, h)
}
if m > 0 {
res = fmt.Sprintf("%s%dM", res, m)
}
if s > 0 {
res = fmt.Sprintf("%s%dS", res, s)
}
return res
}

View File

@ -0,0 +1,36 @@
package winrm
import (
"testing"
"time"
)
func TestFormatDuration(t *testing.T) {
// Test complex duration with hours, minutes, seconds
d := time.Duration(3701) * time.Second
s := formatDuration(d)
if s != "PT1H1M41S" {
t.Fatalf("bad ISO 8601 duration string: %s", s)
}
// Test only minutes duration
d = time.Duration(20) * time.Minute
s = formatDuration(d)
if s != "PT20M" {
t.Fatalf("bad ISO 8601 duration string for 20M: %s", s)
}
// Test only seconds
d = time.Duration(1) * time.Second
s = formatDuration(d)
if s != "PT1S" {
t.Fatalf("bad ISO 8601 duration string for 1S: %s", s)
}
// Test negative duration (unsupported)
d = time.Duration(-1) * time.Second
s = formatDuration(d)
if s != "PT0S" {
t.Fatalf("bad ISO 8601 duration string for negative: %s", s)
}
}

View File

@ -0,0 +1,8 @@
package vagrant
type Config interface {
ConfigAttributes() (attrs []string, err error)
ConfigLoad(data map[string]interface{}) (loaddata map[string]interface{}, err error)
ConfigValidate(data map[string]interface{}, m *Machine) (errors []string, err error)
ConfigFinalize(data map[string]interface{}) (finaldata map[string]interface{}, err error)
}

View File

@ -0,0 +1,64 @@
package vagrant
import (
"encoding/json"
"io"
"os"
)
type Environment struct {
ActiveMachines map[string]string `json:"active_machines,omitempty"`
AliasesPath string `json:"aliases_path,omitempty"`
BoxesPath string `json:"boxes_path,omitempty"`
CWD string `json:"cwd,omitempty"`
DataDir string `json:"data_dir,omitempty"`
DefaultPrivateKeyPath string `json:"default_private_key_path,omitempty"`
GemsPath string `json:"gems_path,omitempty"`
HomePath string `json:"home_path,omitempty"`
LocalDataPath string `json:"local_data_path,omitempty"`
MachineNames []string `json:"machine_names,omitempty"`
PrimaryMachineName string `json:"primary_machine_name,omitempty"`
RootPath string `json:"root_path,omitempty"`
TmpPath string `json:"tmp_path,omitempty"`
VagrantfileName string `json:"vagrantfile_name,omitempty"`
UI Ui `json:"-"`
}
func DumpEnvironment(e *Environment) (s string, err error) {
DefaultLogger().Debug("dumping environment to serialized data")
b, err := json.Marshal(e)
if err != nil {
DefaultLogger().Error("environment dump failure", "error", err)
return
}
s = string(b)
return
}
func LoadEnvironment(edata string, ios IOServer) (e *Environment, err error) {
DefaultLogger().Debug("loading environment from serialized data")
e = &Environment{}
err = json.Unmarshal([]byte(edata), e)
if err != nil {
return
}
var stdout io.Writer
var stderr io.Writer
if ios == nil {
stdout = os.Stdout
stderr = os.Stderr
} else {
stdout = &IOWriter{target: "stdout", srv: ios}
stderr = &IOWriter{target: "stderr", srv: ios}
}
e.UI = &TargetedUi{
Target: "vagrant",
Ui: &ColoredUi{
ErrorColor: UiColorRed,
Ui: &BasicUi{
Reader: os.Stdin,
Writer: stdout,
ErrorWriter: stderr},
}}
return
}

View File

@ -0,0 +1,63 @@
package vagrant
import (
"strings"
"testing"
)
func TestLoadEnvironment(t *testing.T) {
env, err := LoadEnvironment("{}", nil)
if err != nil {
t.Fatalf("unexpected load error: %s", err)
}
if env.UI == nil {
t.Fatalf("no UI configured for environment")
}
}
func TestBadLoadEnvironment(t *testing.T) {
_, err := LoadEnvironment("ack", nil)
if err == nil {
t.Fatalf("expected load error but none provided")
}
}
func TestLoadEnvironmentUIStdout(t *testing.T) {
iosrv := buildio()
env, err := LoadEnvironment("{}", iosrv)
if err != nil {
t.Fatalf("unexpected load error: %s", err)
}
go func() { env.UI.Info("test string") }()
str := <-iosrv.Streams()["stdout"]
if !strings.Contains(str, "test string") {
t.Fatalf("unexpected output: %s", str)
}
}
func TestLoadEnvironmentUIStderr(t *testing.T) {
iosrv := buildio()
env, err := LoadEnvironment("{}", iosrv)
if err != nil {
t.Fatalf("unexpected load error: %s", err)
}
go func() { env.UI.Error("test string") }()
str, err := iosrv.Read("stderr")
if !strings.Contains(str, "test string") {
t.Fatalf("unexpected output: %s", str)
}
}
func TestDumpEnvironment(t *testing.T) {
env, err := LoadEnvironment("{}", nil)
if err != nil {
t.Fatalf("unexpected load error: %s", err)
}
d, err := DumpEnvironment(env)
if err != nil {
t.Fatalf("unexpected dump error: %s", err)
}
if d != "{}" {
t.Fatalf("unexpected dump information: %s", d)
}
}

View File

@ -0,0 +1,17 @@
package vagrant
import (
hclog "github.com/hashicorp/go-hclog"
)
var GlobalIOServer *IOServer
var defaultLogger = hclog.Default().Named("vagrant")
func DefaultLogger() hclog.Logger {
return defaultLogger
}
func SetDefaultLogger(l hclog.Logger) {
defaultLogger = l
}

View File

@ -0,0 +1,53 @@
package vagrant
import (
"errors"
)
type StreamIO interface {
Read(target string) (content string, err error)
Write(content, target string) (n int, err error)
}
type IOServer interface {
Streams() map[string]chan (string)
StreamIO
}
type IOSrv struct {
Targets map[string]chan (string)
}
func (i *IOSrv) Streams() map[string]chan (string) {
return i.Targets
}
type IOWriter struct {
target string
srv IOServer
}
func (i *IOWriter) Write(b []byte) (n int, err error) {
content := string(b)
n, err = i.srv.Write(content, i.target)
return
}
func (i *IOSrv) Read(target string) (content string, err error) {
if _, ok := i.Streams()[target]; !ok {
err = errors.New("Unknown target defined")
return
}
content = <-i.Streams()[target]
return
}
func (i *IOSrv) Write(content, target string) (n int, err error) {
if _, ok := i.Streams()[target]; !ok {
err = errors.New("Unknown target defined")
return
}
i.Streams()[target] <- content
n = len(content)
return
}

View File

@ -0,0 +1,48 @@
package vagrant
import (
"testing"
)
func buildio() IOServer {
return &IOSrv{
Targets: map[string]chan (string){
"stdout": make(chan string),
"stderr": make(chan string)}}
}
func TestIOSrvWrite(t *testing.T) {
iosrv := buildio()
var i int
go func() { i, _ = iosrv.Write("test string", "stdout") }()
_, _ = iosrv.Read("stdout")
if i != len("test string") {
t.Fatalf("unexpected write bytes %d != %d",
len("test string"), i)
}
}
func TestIOSrvRead(t *testing.T) {
iosrv := buildio()
go func() { _, _ = iosrv.Write("test string", "stdout") }()
r, _ := iosrv.Read("stdout")
if r != "test string" {
t.Fatalf("unexpected read result: %s", r)
}
}
func TestIOSrvWriteBadTarget(t *testing.T) {
iosrv := buildio()
_, err := iosrv.Write("test string", "stdno")
if err == nil {
t.Fatalf("expected error on write")
}
}
func TestIOSrvReadBadTarget(t *testing.T) {
iosrv := buildio()
_, err := iosrv.Read("stdno")
if err == nil {
t.Fatalf("expected error on read")
}
}

View File

@ -0,0 +1,59 @@
package vagrant
import (
"encoding/json"
"io"
"os"
)
type Machine struct {
Box Box `json:"box"`
Config map[string]interface{} `json:"config"`
DataDir string `json:"data_dir,omitempty"`
Env Environment `json:"environment"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
ProviderConfig map[string]interface{} `json:"provider_config"`
ProviderName string `json:"provider_name,omitempty"`
ProviderOptions map[string]string `json:"provider_options"`
UI Ui `json:"-"`
}
func DumpMachine(m *Machine) (s string, err error) {
DefaultLogger().Debug("dumping machine to serialized data")
b, err := json.Marshal(m)
if err != nil {
DefaultLogger().Debug("machine dump failure", "error", err)
return
}
s = string(b)
return
}
func LoadMachine(mdata string, ios IOServer) (m *Machine, err error) {
DefaultLogger().Debug("loading machine from serialized data")
m = &Machine{}
err = json.Unmarshal([]byte(mdata), m)
if err != nil {
return
}
var stdout io.Writer
var stderr io.Writer
if ios == nil {
stdout = os.Stdout
stderr = os.Stderr
} else {
stdout = &IOWriter{target: "stdout", srv: ios}
stderr = &IOWriter{target: "stderr", srv: ios}
}
m.UI = &TargetedUi{
Target: m.Name,
Ui: &ColoredUi{
ErrorColor: UiColorRed,
Ui: &BasicUi{
Reader: os.Stdin,
Writer: stdout,
ErrorWriter: stderr},
}}
return
}

View File

@ -0,0 +1,7 @@
package vagrant
type MachineState struct {
Id string `json:"id"`
ShortDesc string `json:"short_description"`
LongDesc string `json:"long_description"`
}

View File

@ -0,0 +1,53 @@
package vagrant
import (
"strings"
"testing"
)
func TestMachineLoad(t *testing.T) {
_, err := LoadMachine("{}", nil)
if err != nil {
t.Fatalf("failed to load machine: %s", err)
}
}
func TestMachineDump(t *testing.T) {
m, err := LoadMachine("{}", nil)
if err != nil {
t.Fatalf("unexpected load error: %s", err)
}
_, err = DumpMachine(m)
if err != nil {
t.Fatalf("failed to dump machine: %s", err)
}
}
func TestMachineUI(t *testing.T) {
iosrv := buildio()
m, err := LoadMachine("{}", iosrv)
if err != nil {
t.Fatalf("unexpected load error: %s", err)
}
go func() { m.UI.Info("test string") }()
r, _ := iosrv.Read("stdout")
if !strings.Contains(r, "test string") {
t.Fatalf("unexpected read result: %s", r)
}
}
func TestMachineUINamed(t *testing.T) {
iosrv := buildio()
m, err := LoadMachine("{\"name\":\"plugintest\"}", iosrv)
if err != nil {
t.Fatalf("unexpected load error: %s", err)
}
go func() { m.UI.Info("test string") }()
r, _ := iosrv.Read("stdout")
if !strings.Contains(r, "test string") {
t.Fatalf("unexpected read result: %s", r)
}
if !strings.Contains(r, "plugintest") {
t.Fatalf("output does not contain name: %s", r)
}
}

View File

@ -0,0 +1,186 @@
package plugin
import (
"errors"
"os"
"os/exec"
hclog "github.com/hashicorp/go-hclog"
go_plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
)
type RemoteConfig struct {
Client *go_plugin.Client
Config vagrant.Config
}
type RemoteProvider struct {
Client *go_plugin.Client
Provider Provider
}
type RemoteGuestCapabilities struct {
Client *go_plugin.Client
GuestCapabilities vagrant.GuestCapabilities
}
type RemoteHostCapabilities struct {
Client *go_plugin.Client
HostCapabilities vagrant.HostCapabilities
}
type RemoteProviderCapabilities struct {
Client *go_plugin.Client
ProviderCapabilities vagrant.ProviderCapabilities
}
type RemoteSyncedFolder struct {
Client *go_plugin.Client
SyncedFolder vagrant.SyncedFolder
}
type VagrantPlugin struct {
Providers map[string]*RemoteProvider
SyncedFolders map[string]*RemoteSyncedFolder
PluginDirectories []string
Logger hclog.Logger
}
func (v *VagrantPlugin) LoadPlugins(pluginPath string) error {
for _, p := range v.PluginDirectories {
if p == pluginPath {
v.Logger.Error("plugin directory path already loaded", "path", pluginPath)
return errors.New("plugin directory already loaded")
}
}
v.PluginDirectories = append(v.PluginDirectories, pluginPath)
if err := v.LoadProviders(pluginPath); err != nil {
return err
}
if err := v.LoadSyncedFolders(pluginPath); err != nil {
return err
}
return nil
}
func (v *VagrantPlugin) LoadProviders(pluginPath string) error {
providerPaths, err := go_plugin.Discover("*_provider", pluginPath)
if err != nil {
v.Logger.Error("error during plugin discovery", "type", "provider",
"error", err, "path", pluginPath)
return err
}
for _, providerPath := range providerPaths {
v.Logger.Info("loading provider plugin", "path", providerPath)
client := go_plugin.NewClient(&go_plugin.ClientConfig{
AllowedProtocols: []go_plugin.Protocol{go_plugin.ProtocolGRPC},
Logger: v.Logger,
HandshakeConfig: go_plugin.HandshakeConfig{
MagicCookieKey: "BASIC_PLUGIN",
MagicCookieValue: "hello",
ProtocolVersion: 1,
},
Cmd: exec.Command(providerPath),
VersionedPlugins: map[int]go_plugin.PluginSet{
2: {"provider": &ProviderPlugin{}}}})
gclient, err := client.Client()
if err != nil {
v.Logger.Error("error loading provider client", "error", err, "path", providerPath)
return err
}
raw, err := gclient.Dispense("provider")
if err != nil {
v.Logger.Error("error loading provider plugin", "error", err, "path", providerPath)
return err
}
prov := raw.(Provider)
n := prov.Name()
v.Providers[n] = &RemoteProvider{
Client: client,
Provider: prov}
v.Logger.Info("plugin loaded", "type", "provider", "name", n, "path", providerPath)
go v.StreamIO("stdout", prov, n, "provider")
go v.StreamIO("stderr", prov, n, "provider")
}
return nil
}
func (v *VagrantPlugin) LoadSyncedFolders(pluginPath string) error {
folderPaths, err := go_plugin.Discover("*_synced_folder", pluginPath)
if err != nil {
v.Logger.Error("error during plugin discovery", "type", "synced_folder",
"error", err, "path", pluginPath)
return err
}
for _, folderPath := range folderPaths {
v.Logger.Info("loading synced_folder plugin", "path", folderPath)
client := go_plugin.NewClient(&go_plugin.ClientConfig{
AllowedProtocols: []go_plugin.Protocol{go_plugin.ProtocolGRPC},
Logger: v.Logger,
HandshakeConfig: go_plugin.HandshakeConfig{
MagicCookieKey: "BASIC_PLUGIN",
MagicCookieValue: "hello",
ProtocolVersion: 1,
},
Cmd: exec.Command(folderPath),
VersionedPlugins: map[int]go_plugin.PluginSet{
2: {"synced_folders": &SyncedFolderPlugin{}}}})
gclient, err := client.Client()
if err != nil {
v.Logger.Error("error loading synced_folder client", "error", err, "path", folderPath)
return err
}
raw, err := gclient.Dispense("synced_folder")
if err != nil {
v.Logger.Error("error loading synced_folder plugin", "error", err, "path", folderPath)
return err
}
fold := raw.(SyncedFolder)
n := fold.Name()
v.SyncedFolders[n] = &RemoteSyncedFolder{
Client: client,
SyncedFolder: fold}
v.Logger.Info("plugin loaded", "type", "synced_folder", "name", n, "path", folderPath)
go v.StreamIO("stdout", fold, n, "synced_folder")
go v.StreamIO("stderr", fold, n, "synced_folder")
}
return nil
}
func (v *VagrantPlugin) StreamIO(target string, i vagrant.IOServer, name, kind string) {
v.Logger.Info("starting plugin IO streaming", "target", target, "plugin", name, "type", kind)
for {
str, err := i.Read(target)
if err != nil {
v.Logger.Error("plugin IO streaming failure", "target", target, "plugin", name,
"type", kind, "error", err)
break
}
v.Logger.Debug("received plugin IO content", "target", target, "plugin", name,
"type", kind, "content", str)
if target == "stdout" {
os.Stdout.Write([]byte(str))
} else if target == "stderr" {
os.Stderr.Write([]byte(str))
}
}
v.Logger.Info("completed plugin IO streaming", "target", target, "plugin", name, "type", kind)
}
func (v *VagrantPlugin) Kill() {
v.Logger.Debug("killing all running plugins")
for n, p := range v.Providers {
v.Logger.Debug("killing plugin", "name", n, "type", "provider")
p.Client.Kill()
v.Logger.Info("plugin killed", "name", n, "type", "provider")
}
for n, p := range v.SyncedFolders {
v.Logger.Debug("killing plugin", "name", n, "type", "synced_folder")
p.Client.Kill()
v.Logger.Info("plugin killed", "name", n, "type", "synced_folder")
}
}

View File

@ -0,0 +1,291 @@
package plugin
import (
"context"
"encoding/json"
"errors"
go_plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_caps"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common"
)
type GuestCapabilities interface {
vagrant.GuestCapabilities
Meta
}
type GuestCapabilitiesPlugin struct {
go_plugin.NetRPCUnsupportedPlugin
Impl GuestCapabilities
}
type GRPCGuestCapabilitiesServer struct {
GRPCIOServer
Impl GuestCapabilities
}
func (s *GRPCGuestCapabilitiesServer) GuestCapabilities(ctx context.Context, req *vagrant_common.NullRequest) (resp *vagrant_caps.CapabilitiesResponse, err error) {
resp = &vagrant_caps.CapabilitiesResponse{}
r, e := s.Impl.GuestCapabilities()
if e != nil {
resp.Error = e.Error()
return
}
for _, cap := range r {
rcap := &vagrant_caps.Capability{Name: cap.Name, Platform: cap.Platform}
resp.Capabilities = append(resp.Capabilities, rcap)
}
return
}
func (s *GRPCGuestCapabilitiesServer) GuestCapability(ctx context.Context, req *vagrant_caps.GuestCapabilityRequest) (resp *vagrant_caps.GuestCapabilityResponse, err error) {
resp = &vagrant_caps.GuestCapabilityResponse{}
var args interface{}
err = json.Unmarshal([]byte(req.Arguments), args)
if err != nil {
return
}
machine, err := vagrant.LoadMachine(req.Machine, s.Impl)
if err != nil {
return
}
cap := &vagrant.SystemCapability{
Name: req.Capability.Name,
Platform: req.Capability.Platform}
r, err := s.Impl.GuestCapability(cap, args, machine)
if err != nil {
return
}
result, err := json.Marshal(r)
if err != nil {
return
}
resp.Result = string(result)
return
}
type GRPCGuestCapabilitiesClient struct {
client vagrant_caps.GuestCapabilitiesClient
}
func (c *GRPCGuestCapabilitiesClient) GuestCapabilities() (caps []vagrant.SystemCapability, err error) {
resp, err := c.client.GuestCapabilities(context.Background(), &vagrant_common.NullRequest{})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
return
}
caps = make([]vagrant.SystemCapability, len(resp.Capabilities))
for i := 0; i < len(resp.Capabilities); i++ {
cap := vagrant.SystemCapability{
Name: resp.Capabilities[i].Name,
Platform: resp.Capabilities[i].Platform}
caps[i] = cap
}
return
}
func (c *GRPCGuestCapabilitiesClient) GuestCapability(cap *vagrant.SystemCapability, args interface{}, machine *vagrant.Machine) (result interface{}, err error) {
a, err := json.Marshal(args)
if err != nil {
return
}
m, err := vagrant.DumpMachine(machine)
if err != nil {
return
}
resp, err := c.client.GuestCapability(context.Background(), &vagrant_caps.GuestCapabilityRequest{
Capability: &vagrant_caps.Capability{Name: cap.Name, Platform: cap.Platform},
Machine: m,
Arguments: string(a)})
err = json.Unmarshal([]byte(resp.Result), &result)
return
}
type HostCapabilities interface {
vagrant.HostCapabilities
Meta
}
type GRPCHostCapabilitiesServer struct {
GRPCIOServer
Impl HostCapabilities
}
func (s *GRPCHostCapabilitiesServer) HostCapabilities(ctx context.Context, req *vagrant_common.NullRequest) (resp *vagrant_caps.CapabilitiesResponse, err error) {
resp = &vagrant_caps.CapabilitiesResponse{}
r, e := s.Impl.HostCapabilities()
if e != nil {
resp.Error = e.Error()
return
}
for _, cap := range r {
rcap := &vagrant_caps.Capability{Name: cap.Name, Platform: cap.Platform}
resp.Capabilities = append(resp.Capabilities, rcap)
}
return
}
func (s *GRPCHostCapabilitiesServer) HostCapability(ctx context.Context, req *vagrant_caps.HostCapabilityRequest) (resp *vagrant_caps.HostCapabilityResponse, err error) {
resp = &vagrant_caps.HostCapabilityResponse{}
var args interface{}
err = json.Unmarshal([]byte(req.Arguments), args)
if err != nil {
return
}
env, err := vagrant.LoadEnvironment(req.Environment, s.Impl)
if err != nil {
return
}
cap := &vagrant.SystemCapability{
Name: req.Capability.Name,
Platform: req.Capability.Platform}
r, err := s.Impl.HostCapability(cap, args, env)
if err != nil {
return
}
result, err := json.Marshal(r)
if err != nil {
return
}
resp.Result = string(result)
return
}
type GRPCHostCapabilitiesClient struct {
client vagrant_caps.HostCapabilitiesClient
}
func (c *GRPCHostCapabilitiesClient) HostCapabilities() (caps []vagrant.SystemCapability, err error) {
resp, err := c.client.HostCapabilities(context.Background(), &vagrant_common.NullRequest{})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
return
}
caps = make([]vagrant.SystemCapability, len(resp.Capabilities))
for i := 0; i < len(resp.Capabilities); i++ {
cap := vagrant.SystemCapability{
Name: resp.Capabilities[i].Name,
Platform: resp.Capabilities[i].Platform}
caps[i] = cap
}
return
}
func (c *GRPCHostCapabilitiesClient) HostCapability(cap *vagrant.SystemCapability, args interface{}, env *vagrant.Environment) (result interface{}, err error) {
a, err := json.Marshal(args)
if err != nil {
return
}
e, err := vagrant.DumpEnvironment(env)
if err != nil {
return
}
resp, err := c.client.HostCapability(context.Background(), &vagrant_caps.HostCapabilityRequest{
Capability: &vagrant_caps.Capability{
Name: cap.Name,
Platform: cap.Platform},
Environment: e,
Arguments: string(a)})
err = json.Unmarshal([]byte(resp.Result), &result)
return
}
type ProviderCapabilities interface {
vagrant.ProviderCapabilities
Meta
}
type GRPCProviderCapabilitiesServer struct {
GRPCIOServer
Impl ProviderCapabilities
}
func (s *GRPCProviderCapabilitiesServer) ProviderCapabilities(ctx context.Context, req *vagrant_common.NullRequest) (resp *vagrant_caps.ProviderCapabilitiesResponse, err error) {
resp = &vagrant_caps.ProviderCapabilitiesResponse{}
r, e := s.Impl.ProviderCapabilities()
if e != nil {
resp.Error = e.Error()
return
}
for _, cap := range r {
rcap := &vagrant_caps.ProviderCapability{Name: cap.Name, Provider: cap.Provider}
resp.Capabilities = append(resp.Capabilities, rcap)
}
return
}
func (s *GRPCProviderCapabilitiesServer) ProviderCapability(ctx context.Context, req *vagrant_caps.ProviderCapabilityRequest) (resp *vagrant_caps.ProviderCapabilityResponse, err error) {
resp = &vagrant_caps.ProviderCapabilityResponse{}
var args interface{}
err = json.Unmarshal([]byte(req.Arguments), args)
if err != nil {
return
}
m, err := vagrant.LoadMachine(req.Machine, s.Impl)
if err != nil {
return
}
cap := &vagrant.ProviderCapability{
Name: req.Capability.Name,
Provider: req.Capability.Provider}
r, err := s.Impl.ProviderCapability(cap, args, m)
if err != nil {
return
}
result, err := json.Marshal(r)
if err != nil {
return
}
resp.Result = string(result)
return
}
type GRPCProviderCapabilitiesClient struct {
client vagrant_caps.ProviderCapabilitiesClient
}
func (c *GRPCProviderCapabilitiesClient) ProviderCapabilities() (caps []vagrant.ProviderCapability, err error) {
resp, err := c.client.ProviderCapabilities(context.Background(), &vagrant_common.NullRequest{})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
return
}
caps = make([]vagrant.ProviderCapability, len(resp.Capabilities))
for i := 0; i < len(resp.Capabilities); i++ {
cap := vagrant.ProviderCapability{
Name: resp.Capabilities[i].Name,
Provider: resp.Capabilities[i].Provider}
caps[i] = cap
}
return
}
func (c *GRPCProviderCapabilitiesClient) ProviderCapability(cap *vagrant.ProviderCapability, args interface{}, machine *vagrant.Machine) (result interface{}, err error) {
a, err := json.Marshal(args)
if err != nil {
return
}
m, err := vagrant.DumpMachine(machine)
if err != nil {
return
}
resp, err := c.client.ProviderCapability(context.Background(), &vagrant_caps.ProviderCapabilityRequest{
Capability: &vagrant_caps.ProviderCapability{
Name: cap.Name,
Provider: cap.Provider},
Machine: m,
Arguments: string(a)})
err = json.Unmarshal([]byte(resp.Result), &result)
return
}

View File

@ -0,0 +1,179 @@
package plugin
import (
"context"
"encoding/json"
"errors"
go_plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_config"
)
type Config interface {
vagrant.Config
Meta
}
type ConfigPlugin struct {
go_plugin.NetRPCUnsupportedPlugin
Impl Config
}
type GRPCConfigServer struct {
GRPCIOServer
Impl Config
}
func (s *GRPCConfigServer) ConfigAttributes(ctx context.Context, req *vagrant_common.NullRequest) (resp *vagrant_config.AttributesResponse, err error) {
resp = &vagrant_config.AttributesResponse{}
r, e := s.Impl.ConfigAttributes()
if e != nil {
resp.Error = e.Error()
return
}
resp.Attributes = r
return
}
func (s *GRPCConfigServer) ConfigLoad(ctx context.Context, req *vagrant_config.LoadRequest) (resp *vagrant_config.LoadResponse, err error) {
resp = &vagrant_config.LoadResponse{}
var data map[string]interface{}
err = json.Unmarshal([]byte(req.Data), &data)
if err != nil {
resp.Error = err.Error()
return
}
r, err := s.Impl.ConfigLoad(data)
if err != nil {
resp.Error = err.Error()
return
}
mdata, err := json.Marshal(r)
if err != nil {
resp.Error = err.Error()
return
}
resp.Data = string(mdata)
return
}
func (s *GRPCConfigServer) ConfigValidate(ctx context.Context, req *vagrant_config.ValidateRequest) (resp *vagrant_config.ValidateResponse, err error) {
resp = &vagrant_config.ValidateResponse{}
var data map[string]interface{}
err = json.Unmarshal([]byte(req.Data), &data)
if err != nil {
resp.Error = err.Error()
return
}
m, err := vagrant.LoadMachine(req.Machine, s.Impl)
if err != nil {
resp.Error = err.Error()
return
}
r, err := s.Impl.ConfigValidate(data, m)
if err != nil {
resp.Error = err.Error()
return
}
resp.Errors = r
return
}
func (s *GRPCConfigServer) ConfigFinalize(ctx context.Context, req *vagrant_config.FinalizeRequest) (resp *vagrant_config.FinalizeResponse, err error) {
resp = &vagrant_config.FinalizeResponse{}
var data map[string]interface{}
err = json.Unmarshal([]byte(req.Data), &data)
if err != nil {
resp.Error = err.Error()
return
}
r, err := s.Impl.ConfigFinalize(data)
if err != nil {
resp.Error = err.Error()
return
}
mdata, err := json.Marshal(r)
if err != nil {
resp.Error = err.Error()
return
}
resp.Data = string(mdata)
return
}
type GRPCConfigClient struct {
client vagrant_config.ConfigClient
}
func (c *GRPCConfigClient) ConfigAttributes() (attrs []string, err error) {
resp, err := c.client.ConfigAttributes(context.Background(), &vagrant_common.NullRequest{})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
}
attrs = resp.Attributes
return
}
func (c *GRPCConfigClient) ConfigLoad(data map[string]interface{}) (loaddata map[string]interface{}, err error) {
mdata, err := json.Marshal(data)
if err != nil {
return
}
resp, err := c.client.ConfigLoad(context.Background(), &vagrant_config.LoadRequest{
Data: string(mdata)})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
return
}
err = json.Unmarshal([]byte(resp.Data), &loaddata)
return
}
func (c *GRPCConfigClient) ConfigValidate(data map[string]interface{}, m *vagrant.Machine) (errs []string, err error) {
machData, err := vagrant.DumpMachine(m)
if err != nil {
return
}
mdata, err := json.Marshal(data)
if err != nil {
return
}
resp, err := c.client.ConfigValidate(context.Background(), &vagrant_config.ValidateRequest{
Data: string(mdata),
Machine: machData})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
return
}
errs = resp.Errors
return
}
func (c *GRPCConfigClient) ConfigFinalize(data map[string]interface{}) (finaldata map[string]interface{}, err error) {
mdata, err := json.Marshal(data)
if err != nil {
return
}
resp, err := c.client.ConfigFinalize(context.Background(), &vagrant_config.FinalizeRequest{
Data: string(mdata)})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
return
}
err = json.Unmarshal([]byte(resp.Data), &finaldata)
return
}

View File

@ -0,0 +1,79 @@
package plugin
import (
"context"
"errors"
"google.golang.org/grpc"
go_plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_io"
)
type IOPlugin struct {
go_plugin.NetRPCUnsupportedPlugin
Impl vagrant.StreamIO
}
type GRPCIOServer struct {
Impl vagrant.StreamIO
}
func (s *GRPCIOServer) Read(ctx context.Context, req *vagrant_io.ReadRequest) (*vagrant_io.ReadResponse, error) {
r, e := s.Impl.Read(req.Target)
result := &vagrant_io.ReadResponse{Content: r}
if e != nil {
result.Error = e.Error()
}
return result, nil
}
func (s *GRPCIOServer) Write(ctx context.Context, req *vagrant_io.WriteRequest) (*vagrant_io.WriteResponse, error) {
n, e := s.Impl.Write(req.Content, req.Target)
result := &vagrant_io.WriteResponse{Length: int32(n)}
if e != nil {
result.Error = e.Error()
}
return result, nil
}
type GRPCIOClient struct {
client vagrant_io.IOClient
}
func (c *GRPCIOClient) Read(target string) (content string, err error) {
resp, err := c.client.Read(context.Background(), &vagrant_io.ReadRequest{
Target: target})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
}
content = resp.Content
return
}
func (c *GRPCIOClient) Write(content, target string) (length int, err error) {
resp, err := c.client.Write(context.Background(), &vagrant_io.WriteRequest{
Content: content,
Target: target})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
}
length = int(resp.Length)
return
}
func (i *IOPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error {
vagrant_io.RegisterIOServer(s, &GRPCIOServer{Impl: i.Impl})
return nil
}
func (i *IOPlugin) GRPCClient(ctx context.Context, broker *go_plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
return &GRPCIOClient{client: vagrant_io.NewIOClient(c)}, nil
}

View File

@ -0,0 +1,39 @@
package plugin
import (
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
)
type Meta interface {
Init()
vagrant.IOServer
}
type GRPCCoreClient struct{}
func (c *GRPCCoreClient) Init() {}
func (c *GRPCCoreClient) Streams() (s map[string]chan (string)) { return }
type Core struct {
vagrant.IOServer
io vagrant.StreamIO
}
func (c *Core) Init() {
if c.io == nil {
c.io = &vagrant.IOSrv{
map[string]chan (string){
"stdout": make(chan string),
"stderr": make(chan string),
},
}
}
}
func (c *Core) Read(target string) (string, error) {
return c.io.Read(target)
}
func (c *Core) Write(content, target string) (int, error) {
return c.io.Write(content, target)
}

View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
echo -n "Parsing proto files and generating go output... "
for i in *
do
if [ -d "${i}" ]; then
protoc --proto_path=/home/spox/.go/src --proto_path=. --go_out=plugins=grpc:. "${i}"/*.proto;
fi
done
echo "done!"

View File

@ -0,0 +1,859 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: vagrant_caps/capabilities.proto
package vagrant_caps
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import vagrant_common "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Capability struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Platform string `protobuf:"bytes,2,opt,name=platform,proto3" json:"platform,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Capability) Reset() { *m = Capability{} }
func (m *Capability) String() string { return proto.CompactTextString(m) }
func (*Capability) ProtoMessage() {}
func (*Capability) Descriptor() ([]byte, []int) {
return fileDescriptor_591a3013bd09a9cb, []int{0}
}
func (m *Capability) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Capability.Unmarshal(m, b)
}
func (m *Capability) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Capability.Marshal(b, m, deterministic)
}
func (m *Capability) XXX_Merge(src proto.Message) {
xxx_messageInfo_Capability.Merge(m, src)
}
func (m *Capability) XXX_Size() int {
return xxx_messageInfo_Capability.Size(m)
}
func (m *Capability) XXX_DiscardUnknown() {
xxx_messageInfo_Capability.DiscardUnknown(m)
}
var xxx_messageInfo_Capability proto.InternalMessageInfo
func (m *Capability) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Capability) GetPlatform() string {
if m != nil {
return m.Platform
}
return ""
}
type ProviderCapability struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ProviderCapability) Reset() { *m = ProviderCapability{} }
func (m *ProviderCapability) String() string { return proto.CompactTextString(m) }
func (*ProviderCapability) ProtoMessage() {}
func (*ProviderCapability) Descriptor() ([]byte, []int) {
return fileDescriptor_591a3013bd09a9cb, []int{1}
}
func (m *ProviderCapability) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ProviderCapability.Unmarshal(m, b)
}
func (m *ProviderCapability) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ProviderCapability.Marshal(b, m, deterministic)
}
func (m *ProviderCapability) XXX_Merge(src proto.Message) {
xxx_messageInfo_ProviderCapability.Merge(m, src)
}
func (m *ProviderCapability) XXX_Size() int {
return xxx_messageInfo_ProviderCapability.Size(m)
}
func (m *ProviderCapability) XXX_DiscardUnknown() {
xxx_messageInfo_ProviderCapability.DiscardUnknown(m)
}
var xxx_messageInfo_ProviderCapability proto.InternalMessageInfo
func (m *ProviderCapability) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *ProviderCapability) GetProvider() string {
if m != nil {
return m.Provider
}
return ""
}
type ProviderCapabilitiesResponse struct {
Capabilities []*ProviderCapability `protobuf:"bytes,1,rep,name=capabilities,proto3" json:"capabilities,omitempty"`
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ProviderCapabilitiesResponse) Reset() { *m = ProviderCapabilitiesResponse{} }
func (m *ProviderCapabilitiesResponse) String() string { return proto.CompactTextString(m) }
func (*ProviderCapabilitiesResponse) ProtoMessage() {}
func (*ProviderCapabilitiesResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_591a3013bd09a9cb, []int{2}
}
func (m *ProviderCapabilitiesResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ProviderCapabilitiesResponse.Unmarshal(m, b)
}
func (m *ProviderCapabilitiesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ProviderCapabilitiesResponse.Marshal(b, m, deterministic)
}
func (m *ProviderCapabilitiesResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_ProviderCapabilitiesResponse.Merge(m, src)
}
func (m *ProviderCapabilitiesResponse) XXX_Size() int {
return xxx_messageInfo_ProviderCapabilitiesResponse.Size(m)
}
func (m *ProviderCapabilitiesResponse) XXX_DiscardUnknown() {
xxx_messageInfo_ProviderCapabilitiesResponse.DiscardUnknown(m)
}
var xxx_messageInfo_ProviderCapabilitiesResponse proto.InternalMessageInfo
func (m *ProviderCapabilitiesResponse) GetCapabilities() []*ProviderCapability {
if m != nil {
return m.Capabilities
}
return nil
}
func (m *ProviderCapabilitiesResponse) GetError() string {
if m != nil {
return m.Error
}
return ""
}
type ProviderCapabilityRequest struct {
Capability *ProviderCapability `protobuf:"bytes,1,opt,name=capability,proto3" json:"capability,omitempty"`
Machine string `protobuf:"bytes,2,opt,name=machine,proto3" json:"machine,omitempty"`
Arguments string `protobuf:"bytes,3,opt,name=arguments,proto3" json:"arguments,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ProviderCapabilityRequest) Reset() { *m = ProviderCapabilityRequest{} }
func (m *ProviderCapabilityRequest) String() string { return proto.CompactTextString(m) }
func (*ProviderCapabilityRequest) ProtoMessage() {}
func (*ProviderCapabilityRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_591a3013bd09a9cb, []int{3}
}
func (m *ProviderCapabilityRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ProviderCapabilityRequest.Unmarshal(m, b)
}
func (m *ProviderCapabilityRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ProviderCapabilityRequest.Marshal(b, m, deterministic)
}
func (m *ProviderCapabilityRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ProviderCapabilityRequest.Merge(m, src)
}
func (m *ProviderCapabilityRequest) XXX_Size() int {
return xxx_messageInfo_ProviderCapabilityRequest.Size(m)
}
func (m *ProviderCapabilityRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ProviderCapabilityRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ProviderCapabilityRequest proto.InternalMessageInfo
func (m *ProviderCapabilityRequest) GetCapability() *ProviderCapability {
if m != nil {
return m.Capability
}
return nil
}
func (m *ProviderCapabilityRequest) GetMachine() string {
if m != nil {
return m.Machine
}
return ""
}
func (m *ProviderCapabilityRequest) GetArguments() string {
if m != nil {
return m.Arguments
}
return ""
}
type ProviderCapabilityResponse struct {
Result string `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"`
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ProviderCapabilityResponse) Reset() { *m = ProviderCapabilityResponse{} }
func (m *ProviderCapabilityResponse) String() string { return proto.CompactTextString(m) }
func (*ProviderCapabilityResponse) ProtoMessage() {}
func (*ProviderCapabilityResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_591a3013bd09a9cb, []int{4}
}
func (m *ProviderCapabilityResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ProviderCapabilityResponse.Unmarshal(m, b)
}
func (m *ProviderCapabilityResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ProviderCapabilityResponse.Marshal(b, m, deterministic)
}
func (m *ProviderCapabilityResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_ProviderCapabilityResponse.Merge(m, src)
}
func (m *ProviderCapabilityResponse) XXX_Size() int {
return xxx_messageInfo_ProviderCapabilityResponse.Size(m)
}
func (m *ProviderCapabilityResponse) XXX_DiscardUnknown() {
xxx_messageInfo_ProviderCapabilityResponse.DiscardUnknown(m)
}
var xxx_messageInfo_ProviderCapabilityResponse proto.InternalMessageInfo
func (m *ProviderCapabilityResponse) GetResult() string {
if m != nil {
return m.Result
}
return ""
}
func (m *ProviderCapabilityResponse) GetError() string {
if m != nil {
return m.Error
}
return ""
}
type CapabilitiesResponse struct {
Capabilities []*Capability `protobuf:"bytes,1,rep,name=capabilities,proto3" json:"capabilities,omitempty"`
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CapabilitiesResponse) Reset() { *m = CapabilitiesResponse{} }
func (m *CapabilitiesResponse) String() string { return proto.CompactTextString(m) }
func (*CapabilitiesResponse) ProtoMessage() {}
func (*CapabilitiesResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_591a3013bd09a9cb, []int{5}
}
func (m *CapabilitiesResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CapabilitiesResponse.Unmarshal(m, b)
}
func (m *CapabilitiesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CapabilitiesResponse.Marshal(b, m, deterministic)
}
func (m *CapabilitiesResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_CapabilitiesResponse.Merge(m, src)
}
func (m *CapabilitiesResponse) XXX_Size() int {
return xxx_messageInfo_CapabilitiesResponse.Size(m)
}
func (m *CapabilitiesResponse) XXX_DiscardUnknown() {
xxx_messageInfo_CapabilitiesResponse.DiscardUnknown(m)
}
var xxx_messageInfo_CapabilitiesResponse proto.InternalMessageInfo
func (m *CapabilitiesResponse) GetCapabilities() []*Capability {
if m != nil {
return m.Capabilities
}
return nil
}
func (m *CapabilitiesResponse) GetError() string {
if m != nil {
return m.Error
}
return ""
}
type GuestCapabilityRequest struct {
Capability *Capability `protobuf:"bytes,1,opt,name=capability,proto3" json:"capability,omitempty"`
Machine string `protobuf:"bytes,2,opt,name=machine,proto3" json:"machine,omitempty"`
Arguments string `protobuf:"bytes,3,opt,name=arguments,proto3" json:"arguments,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GuestCapabilityRequest) Reset() { *m = GuestCapabilityRequest{} }
func (m *GuestCapabilityRequest) String() string { return proto.CompactTextString(m) }
func (*GuestCapabilityRequest) ProtoMessage() {}
func (*GuestCapabilityRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_591a3013bd09a9cb, []int{6}
}
func (m *GuestCapabilityRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GuestCapabilityRequest.Unmarshal(m, b)
}
func (m *GuestCapabilityRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GuestCapabilityRequest.Marshal(b, m, deterministic)
}
func (m *GuestCapabilityRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_GuestCapabilityRequest.Merge(m, src)
}
func (m *GuestCapabilityRequest) XXX_Size() int {
return xxx_messageInfo_GuestCapabilityRequest.Size(m)
}
func (m *GuestCapabilityRequest) XXX_DiscardUnknown() {
xxx_messageInfo_GuestCapabilityRequest.DiscardUnknown(m)
}
var xxx_messageInfo_GuestCapabilityRequest proto.InternalMessageInfo
func (m *GuestCapabilityRequest) GetCapability() *Capability {
if m != nil {
return m.Capability
}
return nil
}
func (m *GuestCapabilityRequest) GetMachine() string {
if m != nil {
return m.Machine
}
return ""
}
func (m *GuestCapabilityRequest) GetArguments() string {
if m != nil {
return m.Arguments
}
return ""
}
type GuestCapabilityResponse struct {
Result string `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"`
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GuestCapabilityResponse) Reset() { *m = GuestCapabilityResponse{} }
func (m *GuestCapabilityResponse) String() string { return proto.CompactTextString(m) }
func (*GuestCapabilityResponse) ProtoMessage() {}
func (*GuestCapabilityResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_591a3013bd09a9cb, []int{7}
}
func (m *GuestCapabilityResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GuestCapabilityResponse.Unmarshal(m, b)
}
func (m *GuestCapabilityResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GuestCapabilityResponse.Marshal(b, m, deterministic)
}
func (m *GuestCapabilityResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_GuestCapabilityResponse.Merge(m, src)
}
func (m *GuestCapabilityResponse) XXX_Size() int {
return xxx_messageInfo_GuestCapabilityResponse.Size(m)
}
func (m *GuestCapabilityResponse) XXX_DiscardUnknown() {
xxx_messageInfo_GuestCapabilityResponse.DiscardUnknown(m)
}
var xxx_messageInfo_GuestCapabilityResponse proto.InternalMessageInfo
func (m *GuestCapabilityResponse) GetResult() string {
if m != nil {
return m.Result
}
return ""
}
func (m *GuestCapabilityResponse) GetError() string {
if m != nil {
return m.Error
}
return ""
}
type HostCapabilityRequest struct {
Capability *Capability `protobuf:"bytes,1,opt,name=capability,proto3" json:"capability,omitempty"`
Environment string `protobuf:"bytes,2,opt,name=environment,proto3" json:"environment,omitempty"`
Arguments string `protobuf:"bytes,3,opt,name=arguments,proto3" json:"arguments,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *HostCapabilityRequest) Reset() { *m = HostCapabilityRequest{} }
func (m *HostCapabilityRequest) String() string { return proto.CompactTextString(m) }
func (*HostCapabilityRequest) ProtoMessage() {}
func (*HostCapabilityRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_591a3013bd09a9cb, []int{8}
}
func (m *HostCapabilityRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HostCapabilityRequest.Unmarshal(m, b)
}
func (m *HostCapabilityRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HostCapabilityRequest.Marshal(b, m, deterministic)
}
func (m *HostCapabilityRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_HostCapabilityRequest.Merge(m, src)
}
func (m *HostCapabilityRequest) XXX_Size() int {
return xxx_messageInfo_HostCapabilityRequest.Size(m)
}
func (m *HostCapabilityRequest) XXX_DiscardUnknown() {
xxx_messageInfo_HostCapabilityRequest.DiscardUnknown(m)
}
var xxx_messageInfo_HostCapabilityRequest proto.InternalMessageInfo
func (m *HostCapabilityRequest) GetCapability() *Capability {
if m != nil {
return m.Capability
}
return nil
}
func (m *HostCapabilityRequest) GetEnvironment() string {
if m != nil {
return m.Environment
}
return ""
}
func (m *HostCapabilityRequest) GetArguments() string {
if m != nil {
return m.Arguments
}
return ""
}
type HostCapabilityResponse struct {
Result string `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"`
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *HostCapabilityResponse) Reset() { *m = HostCapabilityResponse{} }
func (m *HostCapabilityResponse) String() string { return proto.CompactTextString(m) }
func (*HostCapabilityResponse) ProtoMessage() {}
func (*HostCapabilityResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_591a3013bd09a9cb, []int{9}
}
func (m *HostCapabilityResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HostCapabilityResponse.Unmarshal(m, b)
}
func (m *HostCapabilityResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_HostCapabilityResponse.Marshal(b, m, deterministic)
}
func (m *HostCapabilityResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_HostCapabilityResponse.Merge(m, src)
}
func (m *HostCapabilityResponse) XXX_Size() int {
return xxx_messageInfo_HostCapabilityResponse.Size(m)
}
func (m *HostCapabilityResponse) XXX_DiscardUnknown() {
xxx_messageInfo_HostCapabilityResponse.DiscardUnknown(m)
}
var xxx_messageInfo_HostCapabilityResponse proto.InternalMessageInfo
func (m *HostCapabilityResponse) GetResult() string {
if m != nil {
return m.Result
}
return ""
}
func (m *HostCapabilityResponse) GetError() string {
if m != nil {
return m.Error
}
return ""
}
func init() {
proto.RegisterType((*Capability)(nil), "vagrant.caps.Capability")
proto.RegisterType((*ProviderCapability)(nil), "vagrant.caps.ProviderCapability")
proto.RegisterType((*ProviderCapabilitiesResponse)(nil), "vagrant.caps.ProviderCapabilitiesResponse")
proto.RegisterType((*ProviderCapabilityRequest)(nil), "vagrant.caps.ProviderCapabilityRequest")
proto.RegisterType((*ProviderCapabilityResponse)(nil), "vagrant.caps.ProviderCapabilityResponse")
proto.RegisterType((*CapabilitiesResponse)(nil), "vagrant.caps.CapabilitiesResponse")
proto.RegisterType((*GuestCapabilityRequest)(nil), "vagrant.caps.GuestCapabilityRequest")
proto.RegisterType((*GuestCapabilityResponse)(nil), "vagrant.caps.GuestCapabilityResponse")
proto.RegisterType((*HostCapabilityRequest)(nil), "vagrant.caps.HostCapabilityRequest")
proto.RegisterType((*HostCapabilityResponse)(nil), "vagrant.caps.HostCapabilityResponse")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// GuestCapabilitiesClient is the client API for GuestCapabilities service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type GuestCapabilitiesClient interface {
GuestCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*CapabilitiesResponse, error)
GuestCapability(ctx context.Context, in *GuestCapabilityRequest, opts ...grpc.CallOption) (*GuestCapabilityResponse, error)
}
type guestCapabilitiesClient struct {
cc *grpc.ClientConn
}
func NewGuestCapabilitiesClient(cc *grpc.ClientConn) GuestCapabilitiesClient {
return &guestCapabilitiesClient{cc}
}
func (c *guestCapabilitiesClient) GuestCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*CapabilitiesResponse, error) {
out := new(CapabilitiesResponse)
err := c.cc.Invoke(ctx, "/vagrant.caps.GuestCapabilities/GuestCapabilities", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *guestCapabilitiesClient) GuestCapability(ctx context.Context, in *GuestCapabilityRequest, opts ...grpc.CallOption) (*GuestCapabilityResponse, error) {
out := new(GuestCapabilityResponse)
err := c.cc.Invoke(ctx, "/vagrant.caps.GuestCapabilities/GuestCapability", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// GuestCapabilitiesServer is the server API for GuestCapabilities service.
type GuestCapabilitiesServer interface {
GuestCapabilities(context.Context, *vagrant_common.NullRequest) (*CapabilitiesResponse, error)
GuestCapability(context.Context, *GuestCapabilityRequest) (*GuestCapabilityResponse, error)
}
func RegisterGuestCapabilitiesServer(s *grpc.Server, srv GuestCapabilitiesServer) {
s.RegisterService(&_GuestCapabilities_serviceDesc, srv)
}
func _GuestCapabilities_GuestCapabilities_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_common.NullRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GuestCapabilitiesServer).GuestCapabilities(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.caps.GuestCapabilities/GuestCapabilities",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GuestCapabilitiesServer).GuestCapabilities(ctx, req.(*vagrant_common.NullRequest))
}
return interceptor(ctx, in, info, handler)
}
func _GuestCapabilities_GuestCapability_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GuestCapabilityRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GuestCapabilitiesServer).GuestCapability(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.caps.GuestCapabilities/GuestCapability",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GuestCapabilitiesServer).GuestCapability(ctx, req.(*GuestCapabilityRequest))
}
return interceptor(ctx, in, info, handler)
}
var _GuestCapabilities_serviceDesc = grpc.ServiceDesc{
ServiceName: "vagrant.caps.GuestCapabilities",
HandlerType: (*GuestCapabilitiesServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GuestCapabilities",
Handler: _GuestCapabilities_GuestCapabilities_Handler,
},
{
MethodName: "GuestCapability",
Handler: _GuestCapabilities_GuestCapability_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "vagrant_caps/capabilities.proto",
}
// HostCapabilitiesClient is the client API for HostCapabilities service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type HostCapabilitiesClient interface {
HostCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*CapabilitiesResponse, error)
HostCapability(ctx context.Context, in *HostCapabilityRequest, opts ...grpc.CallOption) (*HostCapabilityResponse, error)
}
type hostCapabilitiesClient struct {
cc *grpc.ClientConn
}
func NewHostCapabilitiesClient(cc *grpc.ClientConn) HostCapabilitiesClient {
return &hostCapabilitiesClient{cc}
}
func (c *hostCapabilitiesClient) HostCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*CapabilitiesResponse, error) {
out := new(CapabilitiesResponse)
err := c.cc.Invoke(ctx, "/vagrant.caps.HostCapabilities/HostCapabilities", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *hostCapabilitiesClient) HostCapability(ctx context.Context, in *HostCapabilityRequest, opts ...grpc.CallOption) (*HostCapabilityResponse, error) {
out := new(HostCapabilityResponse)
err := c.cc.Invoke(ctx, "/vagrant.caps.HostCapabilities/HostCapability", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// HostCapabilitiesServer is the server API for HostCapabilities service.
type HostCapabilitiesServer interface {
HostCapabilities(context.Context, *vagrant_common.NullRequest) (*CapabilitiesResponse, error)
HostCapability(context.Context, *HostCapabilityRequest) (*HostCapabilityResponse, error)
}
func RegisterHostCapabilitiesServer(s *grpc.Server, srv HostCapabilitiesServer) {
s.RegisterService(&_HostCapabilities_serviceDesc, srv)
}
func _HostCapabilities_HostCapabilities_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_common.NullRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HostCapabilitiesServer).HostCapabilities(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.caps.HostCapabilities/HostCapabilities",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HostCapabilitiesServer).HostCapabilities(ctx, req.(*vagrant_common.NullRequest))
}
return interceptor(ctx, in, info, handler)
}
func _HostCapabilities_HostCapability_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(HostCapabilityRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(HostCapabilitiesServer).HostCapability(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.caps.HostCapabilities/HostCapability",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(HostCapabilitiesServer).HostCapability(ctx, req.(*HostCapabilityRequest))
}
return interceptor(ctx, in, info, handler)
}
var _HostCapabilities_serviceDesc = grpc.ServiceDesc{
ServiceName: "vagrant.caps.HostCapabilities",
HandlerType: (*HostCapabilitiesServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "HostCapabilities",
Handler: _HostCapabilities_HostCapabilities_Handler,
},
{
MethodName: "HostCapability",
Handler: _HostCapabilities_HostCapability_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "vagrant_caps/capabilities.proto",
}
// ProviderCapabilitiesClient is the client API for ProviderCapabilities service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type ProviderCapabilitiesClient interface {
ProviderCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*ProviderCapabilitiesResponse, error)
ProviderCapability(ctx context.Context, in *ProviderCapabilityRequest, opts ...grpc.CallOption) (*ProviderCapabilityResponse, error)
}
type providerCapabilitiesClient struct {
cc *grpc.ClientConn
}
func NewProviderCapabilitiesClient(cc *grpc.ClientConn) ProviderCapabilitiesClient {
return &providerCapabilitiesClient{cc}
}
func (c *providerCapabilitiesClient) ProviderCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*ProviderCapabilitiesResponse, error) {
out := new(ProviderCapabilitiesResponse)
err := c.cc.Invoke(ctx, "/vagrant.caps.ProviderCapabilities/ProviderCapabilities", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *providerCapabilitiesClient) ProviderCapability(ctx context.Context, in *ProviderCapabilityRequest, opts ...grpc.CallOption) (*ProviderCapabilityResponse, error) {
out := new(ProviderCapabilityResponse)
err := c.cc.Invoke(ctx, "/vagrant.caps.ProviderCapabilities/ProviderCapability", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ProviderCapabilitiesServer is the server API for ProviderCapabilities service.
type ProviderCapabilitiesServer interface {
ProviderCapabilities(context.Context, *vagrant_common.NullRequest) (*ProviderCapabilitiesResponse, error)
ProviderCapability(context.Context, *ProviderCapabilityRequest) (*ProviderCapabilityResponse, error)
}
func RegisterProviderCapabilitiesServer(s *grpc.Server, srv ProviderCapabilitiesServer) {
s.RegisterService(&_ProviderCapabilities_serviceDesc, srv)
}
func _ProviderCapabilities_ProviderCapabilities_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_common.NullRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProviderCapabilitiesServer).ProviderCapabilities(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.caps.ProviderCapabilities/ProviderCapabilities",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProviderCapabilitiesServer).ProviderCapabilities(ctx, req.(*vagrant_common.NullRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ProviderCapabilities_ProviderCapability_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ProviderCapabilityRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProviderCapabilitiesServer).ProviderCapability(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.caps.ProviderCapabilities/ProviderCapability",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProviderCapabilitiesServer).ProviderCapability(ctx, req.(*ProviderCapabilityRequest))
}
return interceptor(ctx, in, info, handler)
}
var _ProviderCapabilities_serviceDesc = grpc.ServiceDesc{
ServiceName: "vagrant.caps.ProviderCapabilities",
HandlerType: (*ProviderCapabilitiesServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ProviderCapabilities",
Handler: _ProviderCapabilities_ProviderCapabilities_Handler,
},
{
MethodName: "ProviderCapability",
Handler: _ProviderCapabilities_ProviderCapability_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "vagrant_caps/capabilities.proto",
}
func init() { proto.RegisterFile("vagrant_caps/capabilities.proto", fileDescriptor_591a3013bd09a9cb) }
var fileDescriptor_591a3013bd09a9cb = []byte{
// 510 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x95, 0xcf, 0x6e, 0xd3, 0x40,
0x10, 0xc6, 0xb5, 0x14, 0x0a, 0x9d, 0x56, 0xfc, 0x59, 0x85, 0x60, 0x4c, 0x25, 0x22, 0x53, 0x44,
0x84, 0x84, 0x2d, 0x85, 0x0b, 0x87, 0x1e, 0x90, 0xa8, 0x28, 0xe2, 0x80, 0x50, 0xe0, 0x56, 0x89,
0x6a, 0x63, 0x16, 0x7b, 0x91, 0xbd, 0x6b, 0x76, 0xd7, 0x11, 0xe5, 0x11, 0xb8, 0x71, 0xe0, 0x8d,
0xb8, 0xf0, 0x16, 0x3c, 0x0a, 0xb2, 0xbd, 0x71, 0xed, 0x7a, 0x5d, 0x97, 0xd2, 0x53, 0x32, 0x93,
0x99, 0xf9, 0xe6, 0xfb, 0xd9, 0x9a, 0xc0, 0xfd, 0x25, 0x89, 0x24, 0xe1, 0xfa, 0x30, 0x24, 0x99,
0x0a, 0x42, 0x92, 0x91, 0x05, 0x4b, 0x98, 0x66, 0x54, 0xf9, 0x99, 0x14, 0x5a, 0xe0, 0x2d, 0x53,
0xe0, 0x17, 0x05, 0xee, 0x41, 0xc4, 0x74, 0x9c, 0x2f, 0xfc, 0x50, 0xa4, 0x41, 0x4c, 0x54, 0xcc,
0x42, 0x21, 0xb3, 0xc0, 0x94, 0x04, 0xf4, 0xab, 0x0e, 0x22, 0xf1, 0x24, 0x4b, 0xf2, 0x88, 0xf1,
0x3a, 0x6b, 0xc2, 0x72, 0x5c, 0x50, 0xcb, 0x89, 0x34, 0x15, 0x3c, 0xa8, 0x3e, 0x2a, 0x29, 0x6f,
0x17, 0xe0, 0xc5, 0x6a, 0x81, 0x23, 0x8c, 0xe1, 0x32, 0x27, 0x29, 0x75, 0xd0, 0x04, 0x4d, 0x37,
0xe6, 0xe5, 0x77, 0xec, 0xc2, 0xb5, 0x2c, 0x21, 0xfa, 0x93, 0x90, 0xa9, 0x73, 0xa9, 0xcc, 0xd7,
0xb1, 0xb7, 0x07, 0xf8, 0xad, 0x14, 0x4b, 0xf6, 0x91, 0xca, 0x33, 0x4c, 0x31, 0x95, 0xf5, 0x14,
0x13, 0x7b, 0xdf, 0x60, 0xbb, 0x33, 0x85, 0x51, 0x35, 0xa7, 0x2a, 0x13, 0x5c, 0x51, 0xbc, 0x07,
0x5b, 0x4d, 0x48, 0x0e, 0x9a, 0xac, 0x4d, 0x37, 0x67, 0x13, 0xbf, 0x49, 0xc9, 0xef, 0xee, 0x31,
0x6f, 0x75, 0xe1, 0x11, 0x5c, 0xa1, 0x52, 0x8a, 0x95, 0x7c, 0x15, 0x78, 0x3f, 0x11, 0xdc, 0xb5,
0xb4, 0xd2, 0x2f, 0x39, 0x55, 0x1a, 0x3f, 0x07, 0xa8, 0x67, 0x1c, 0x95, 0x7e, 0xce, 0xa2, 0xdb,
0xe8, 0xc1, 0x0e, 0x5c, 0x4d, 0x49, 0x18, 0x33, 0x4e, 0x8d, 0xee, 0x2a, 0xc4, 0xdb, 0xb0, 0x41,
0x64, 0x94, 0xa7, 0x94, 0x6b, 0xe5, 0xac, 0x95, 0xbf, 0x1d, 0x27, 0xbc, 0xd7, 0xe0, 0xda, 0xd6,
0x32, 0x44, 0xc6, 0xb0, 0x2e, 0xa9, 0xca, 0x13, 0x6d, 0x18, 0x9b, 0xa8, 0xc7, 0xe3, 0x67, 0x18,
0x59, 0xb9, 0xee, 0x5a, 0xb9, 0x3a, 0x6d, 0x7f, 0xff, 0xc8, 0xf3, 0x3b, 0x82, 0xf1, 0x7e, 0xc1,
0xae, 0x0b, 0xf3, 0x99, 0x05, 0x66, 0xbf, 0xd8, 0x45, 0x40, 0xdc, 0x87, 0x3b, 0x9d, 0x5d, 0xce,
0x45, 0xf0, 0x07, 0x82, 0xdb, 0xaf, 0xc4, 0xc5, 0x9a, 0x9a, 0xc0, 0x26, 0xe5, 0x4b, 0x26, 0x05,
0x2f, 0x96, 0x35, 0x7a, 0xcd, 0xd4, 0x80, 0xb9, 0x97, 0x30, 0x3e, 0xb9, 0xd2, 0x79, 0xbc, 0xcd,
0x7e, 0x23, 0xb8, 0xd5, 0xa6, 0x54, 0x3c, 0xdd, 0xf7, 0xb6, 0xe4, 0xbd, 0x63, 0x63, 0xd5, 0x0d,
0x79, 0x93, 0x27, 0x89, 0x21, 0xe1, 0x7a, 0x3d, 0xae, 0x9b, 0x6f, 0xdc, 0x07, 0xb8, 0x71, 0xe2,
0x81, 0xe0, 0x9d, 0x76, 0x9b, 0xfd, 0xdd, 0x71, 0x1f, 0x0e, 0x54, 0x55, 0xf3, 0x67, 0xbf, 0x10,
0xdc, 0x6c, 0x41, 0x29, 0xb6, 0x7e, 0x67, 0xc9, 0xfd, 0xb7, 0x93, 0x03, 0xb8, 0xde, 0xa6, 0x8f,
0x1f, 0xb4, 0xbb, 0xac, 0xaf, 0x8b, 0xbb, 0x73, 0x7a, 0x91, 0xb1, 0xf1, 0x07, 0xc1, 0xc8, 0x76,
0x11, 0xf1, 0x61, 0x4f, 0xfe, 0x54, 0x3b, 0x8f, 0x07, 0x0e, 0x56, 0xd3, 0x56, 0x64, 0x3d, 0xe8,
0x8f, 0x06, 0x4f, 0x9e, 0x91, 0x9a, 0x0e, 0x17, 0x56, 0x42, 0x8b, 0xf5, 0xf2, 0xef, 0xe7, 0xe9,
0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7b, 0xfc, 0x96, 0xa9, 0x0c, 0x07, 0x00, 0x00,
}

View File

@ -0,0 +1,72 @@
syntax = "proto3";
package vagrant.caps;
import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common/common.proto";
message Capability {
string name = 1;
string platform = 2;
}
message ProviderCapability {
string name = 1;
string provider = 2;
}
message ProviderCapabilitiesResponse {
repeated ProviderCapability capabilities = 1;
string error = 2;
}
message ProviderCapabilityRequest {
ProviderCapability capability = 1;
string machine = 2;
string arguments = 3;
}
message ProviderCapabilityResponse {
string result = 1;
string error = 2;
}
message CapabilitiesResponse {
repeated Capability capabilities = 1;
string error = 2;
}
message GuestCapabilityRequest {
Capability capability = 1;
string machine = 2;
string arguments = 3;
}
message GuestCapabilityResponse {
string result = 1;
string error = 2;
}
message HostCapabilityRequest {
Capability capability = 1;
string environment = 2;
string arguments = 3;
}
message HostCapabilityResponse {
string result = 1;
string error = 2;
}
service GuestCapabilities {
rpc GuestCapabilities(vagrant.common.NullRequest) returns (CapabilitiesResponse);
rpc GuestCapability(GuestCapabilityRequest) returns (GuestCapabilityResponse);
}
service HostCapabilities {
rpc HostCapabilities(vagrant.common.NullRequest) returns (CapabilitiesResponse);
rpc HostCapability(HostCapabilityRequest) returns (HostCapabilityResponse);
}
service ProviderCapabilities {
rpc ProviderCapabilities(vagrant.common.NullRequest) returns (ProviderCapabilitiesResponse);
rpc ProviderCapability(ProviderCapabilityRequest) returns (ProviderCapabilityResponse);
}

View File

@ -0,0 +1,235 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: vagrant_common/common.proto
package vagrant_common
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type NullRequest struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *NullRequest) Reset() { *m = NullRequest{} }
func (m *NullRequest) String() string { return proto.CompactTextString(m) }
func (*NullRequest) ProtoMessage() {}
func (*NullRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_86eb89499a7c6603, []int{0}
}
func (m *NullRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_NullRequest.Unmarshal(m, b)
}
func (m *NullRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_NullRequest.Marshal(b, m, deterministic)
}
func (m *NullRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_NullRequest.Merge(m, src)
}
func (m *NullRequest) XXX_Size() int {
return xxx_messageInfo_NullRequest.Size(m)
}
func (m *NullRequest) XXX_DiscardUnknown() {
xxx_messageInfo_NullRequest.DiscardUnknown(m)
}
var xxx_messageInfo_NullRequest proto.InternalMessageInfo
type EmptyRequest struct {
Machine string `protobuf:"bytes,1,opt,name=machine,proto3" json:"machine,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *EmptyRequest) Reset() { *m = EmptyRequest{} }
func (m *EmptyRequest) String() string { return proto.CompactTextString(m) }
func (*EmptyRequest) ProtoMessage() {}
func (*EmptyRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_86eb89499a7c6603, []int{1}
}
func (m *EmptyRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EmptyRequest.Unmarshal(m, b)
}
func (m *EmptyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_EmptyRequest.Marshal(b, m, deterministic)
}
func (m *EmptyRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_EmptyRequest.Merge(m, src)
}
func (m *EmptyRequest) XXX_Size() int {
return xxx_messageInfo_EmptyRequest.Size(m)
}
func (m *EmptyRequest) XXX_DiscardUnknown() {
xxx_messageInfo_EmptyRequest.DiscardUnknown(m)
}
var xxx_messageInfo_EmptyRequest proto.InternalMessageInfo
func (m *EmptyRequest) GetMachine() string {
if m != nil {
return m.Machine
}
return ""
}
type EmptyResponse struct {
Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *EmptyResponse) Reset() { *m = EmptyResponse{} }
func (m *EmptyResponse) String() string { return proto.CompactTextString(m) }
func (*EmptyResponse) ProtoMessage() {}
func (*EmptyResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_86eb89499a7c6603, []int{2}
}
func (m *EmptyResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EmptyResponse.Unmarshal(m, b)
}
func (m *EmptyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_EmptyResponse.Marshal(b, m, deterministic)
}
func (m *EmptyResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_EmptyResponse.Merge(m, src)
}
func (m *EmptyResponse) XXX_Size() int {
return xxx_messageInfo_EmptyResponse.Size(m)
}
func (m *EmptyResponse) XXX_DiscardUnknown() {
xxx_messageInfo_EmptyResponse.DiscardUnknown(m)
}
var xxx_messageInfo_EmptyResponse proto.InternalMessageInfo
func (m *EmptyResponse) GetError() string {
if m != nil {
return m.Error
}
return ""
}
type IsResponse struct {
Result bool `protobuf:"varint,1,opt,name=result,proto3" json:"result,omitempty"`
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *IsResponse) Reset() { *m = IsResponse{} }
func (m *IsResponse) String() string { return proto.CompactTextString(m) }
func (*IsResponse) ProtoMessage() {}
func (*IsResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_86eb89499a7c6603, []int{3}
}
func (m *IsResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_IsResponse.Unmarshal(m, b)
}
func (m *IsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_IsResponse.Marshal(b, m, deterministic)
}
func (m *IsResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_IsResponse.Merge(m, src)
}
func (m *IsResponse) XXX_Size() int {
return xxx_messageInfo_IsResponse.Size(m)
}
func (m *IsResponse) XXX_DiscardUnknown() {
xxx_messageInfo_IsResponse.DiscardUnknown(m)
}
var xxx_messageInfo_IsResponse proto.InternalMessageInfo
func (m *IsResponse) GetResult() bool {
if m != nil {
return m.Result
}
return false
}
func (m *IsResponse) GetError() string {
if m != nil {
return m.Error
}
return ""
}
type NameResponse struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *NameResponse) Reset() { *m = NameResponse{} }
func (m *NameResponse) String() string { return proto.CompactTextString(m) }
func (*NameResponse) ProtoMessage() {}
func (*NameResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_86eb89499a7c6603, []int{4}
}
func (m *NameResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_NameResponse.Unmarshal(m, b)
}
func (m *NameResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_NameResponse.Marshal(b, m, deterministic)
}
func (m *NameResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_NameResponse.Merge(m, src)
}
func (m *NameResponse) XXX_Size() int {
return xxx_messageInfo_NameResponse.Size(m)
}
func (m *NameResponse) XXX_DiscardUnknown() {
xxx_messageInfo_NameResponse.DiscardUnknown(m)
}
var xxx_messageInfo_NameResponse proto.InternalMessageInfo
func (m *NameResponse) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func init() {
proto.RegisterType((*NullRequest)(nil), "vagrant.common.NullRequest")
proto.RegisterType((*EmptyRequest)(nil), "vagrant.common.EmptyRequest")
proto.RegisterType((*EmptyResponse)(nil), "vagrant.common.EmptyResponse")
proto.RegisterType((*IsResponse)(nil), "vagrant.common.IsResponse")
proto.RegisterType((*NameResponse)(nil), "vagrant.common.NameResponse")
}
func init() { proto.RegisterFile("vagrant_common/common.proto", fileDescriptor_86eb89499a7c6603) }
var fileDescriptor_86eb89499a7c6603 = []byte{
// 178 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x2e, 0x4b, 0x4c, 0x2f,
0x4a, 0xcc, 0x2b, 0x89, 0x4f, 0xce, 0xcf, 0xcd, 0xcd, 0xcf, 0xd3, 0x87, 0x50, 0x7a, 0x05, 0x45,
0xf9, 0x25, 0xf9, 0x42, 0x7c, 0x50, 0x49, 0x3d, 0x88, 0xa8, 0x12, 0x2f, 0x17, 0xb7, 0x5f, 0x69,
0x4e, 0x4e, 0x50, 0x6a, 0x61, 0x69, 0x6a, 0x71, 0x89, 0x92, 0x06, 0x17, 0x8f, 0x6b, 0x6e, 0x41,
0x49, 0x25, 0x94, 0x2f, 0x24, 0xc1, 0xc5, 0x9e, 0x9b, 0x98, 0x9c, 0x91, 0x99, 0x97, 0x2a, 0xc1,
0xa8, 0xc0, 0xa8, 0xc1, 0x19, 0x04, 0xe3, 0x2a, 0xa9, 0x72, 0xf1, 0x42, 0x55, 0x16, 0x17, 0xe4,
0xe7, 0x15, 0xa7, 0x0a, 0x89, 0x70, 0xb1, 0xa6, 0x16, 0x15, 0xe5, 0x17, 0x41, 0x15, 0x42, 0x38,
0x4a, 0x56, 0x5c, 0x5c, 0x9e, 0xc5, 0x70, 0x35, 0x62, 0x5c, 0x6c, 0x45, 0xa9, 0xc5, 0xa5, 0x39,
0x25, 0x60, 0x45, 0x1c, 0x41, 0x50, 0x1e, 0x42, 0x2f, 0x13, 0xb2, 0x5e, 0x25, 0x2e, 0x1e, 0xbf,
0xc4, 0xdc, 0x54, 0xb8, 0x6e, 0x21, 0x2e, 0x96, 0xbc, 0xc4, 0x5c, 0x98, 0x4b, 0xc0, 0xec, 0x24,
0x36, 0xb0, 0xb7, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x02, 0xed, 0x61, 0x90, 0xf5, 0x00,
0x00, 0x00,
}

View File

@ -0,0 +1,19 @@
syntax = "proto3";
package vagrant.common;
message NullRequest {}
message EmptyRequest {
string machine = 1;
}
message EmptyResponse {
string error = 1;
}
message IsResponse {
bool result = 1;
string error = 2;
}
message NameResponse { string name = 1; }

View File

@ -0,0 +1,541 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: vagrant_config/config.proto
package vagrant_config
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import vagrant_common "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type AttributesResponse struct {
Attributes []string `protobuf:"bytes,1,rep,name=attributes,proto3" json:"attributes,omitempty"`
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *AttributesResponse) Reset() { *m = AttributesResponse{} }
func (m *AttributesResponse) String() string { return proto.CompactTextString(m) }
func (*AttributesResponse) ProtoMessage() {}
func (*AttributesResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_952629f1a9a7438c, []int{0}
}
func (m *AttributesResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_AttributesResponse.Unmarshal(m, b)
}
func (m *AttributesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_AttributesResponse.Marshal(b, m, deterministic)
}
func (m *AttributesResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_AttributesResponse.Merge(m, src)
}
func (m *AttributesResponse) XXX_Size() int {
return xxx_messageInfo_AttributesResponse.Size(m)
}
func (m *AttributesResponse) XXX_DiscardUnknown() {
xxx_messageInfo_AttributesResponse.DiscardUnknown(m)
}
var xxx_messageInfo_AttributesResponse proto.InternalMessageInfo
func (m *AttributesResponse) GetAttributes() []string {
if m != nil {
return m.Attributes
}
return nil
}
func (m *AttributesResponse) GetError() string {
if m != nil {
return m.Error
}
return ""
}
type LoadRequest struct {
Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *LoadRequest) Reset() { *m = LoadRequest{} }
func (m *LoadRequest) String() string { return proto.CompactTextString(m) }
func (*LoadRequest) ProtoMessage() {}
func (*LoadRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_952629f1a9a7438c, []int{1}
}
func (m *LoadRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_LoadRequest.Unmarshal(m, b)
}
func (m *LoadRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_LoadRequest.Marshal(b, m, deterministic)
}
func (m *LoadRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_LoadRequest.Merge(m, src)
}
func (m *LoadRequest) XXX_Size() int {
return xxx_messageInfo_LoadRequest.Size(m)
}
func (m *LoadRequest) XXX_DiscardUnknown() {
xxx_messageInfo_LoadRequest.DiscardUnknown(m)
}
var xxx_messageInfo_LoadRequest proto.InternalMessageInfo
func (m *LoadRequest) GetData() string {
if m != nil {
return m.Data
}
return ""
}
type LoadResponse struct {
Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *LoadResponse) Reset() { *m = LoadResponse{} }
func (m *LoadResponse) String() string { return proto.CompactTextString(m) }
func (*LoadResponse) ProtoMessage() {}
func (*LoadResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_952629f1a9a7438c, []int{2}
}
func (m *LoadResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_LoadResponse.Unmarshal(m, b)
}
func (m *LoadResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_LoadResponse.Marshal(b, m, deterministic)
}
func (m *LoadResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_LoadResponse.Merge(m, src)
}
func (m *LoadResponse) XXX_Size() int {
return xxx_messageInfo_LoadResponse.Size(m)
}
func (m *LoadResponse) XXX_DiscardUnknown() {
xxx_messageInfo_LoadResponse.DiscardUnknown(m)
}
var xxx_messageInfo_LoadResponse proto.InternalMessageInfo
func (m *LoadResponse) GetData() string {
if m != nil {
return m.Data
}
return ""
}
func (m *LoadResponse) GetError() string {
if m != nil {
return m.Error
}
return ""
}
type ValidateRequest struct {
Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
Machine string `protobuf:"bytes,2,opt,name=machine,proto3" json:"machine,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ValidateRequest) Reset() { *m = ValidateRequest{} }
func (m *ValidateRequest) String() string { return proto.CompactTextString(m) }
func (*ValidateRequest) ProtoMessage() {}
func (*ValidateRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_952629f1a9a7438c, []int{3}
}
func (m *ValidateRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ValidateRequest.Unmarshal(m, b)
}
func (m *ValidateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ValidateRequest.Marshal(b, m, deterministic)
}
func (m *ValidateRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ValidateRequest.Merge(m, src)
}
func (m *ValidateRequest) XXX_Size() int {
return xxx_messageInfo_ValidateRequest.Size(m)
}
func (m *ValidateRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ValidateRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ValidateRequest proto.InternalMessageInfo
func (m *ValidateRequest) GetData() string {
if m != nil {
return m.Data
}
return ""
}
func (m *ValidateRequest) GetMachine() string {
if m != nil {
return m.Machine
}
return ""
}
type ValidateResponse struct {
Errors []string `protobuf:"bytes,1,rep,name=errors,proto3" json:"errors,omitempty"`
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ValidateResponse) Reset() { *m = ValidateResponse{} }
func (m *ValidateResponse) String() string { return proto.CompactTextString(m) }
func (*ValidateResponse) ProtoMessage() {}
func (*ValidateResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_952629f1a9a7438c, []int{4}
}
func (m *ValidateResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ValidateResponse.Unmarshal(m, b)
}
func (m *ValidateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ValidateResponse.Marshal(b, m, deterministic)
}
func (m *ValidateResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_ValidateResponse.Merge(m, src)
}
func (m *ValidateResponse) XXX_Size() int {
return xxx_messageInfo_ValidateResponse.Size(m)
}
func (m *ValidateResponse) XXX_DiscardUnknown() {
xxx_messageInfo_ValidateResponse.DiscardUnknown(m)
}
var xxx_messageInfo_ValidateResponse proto.InternalMessageInfo
func (m *ValidateResponse) GetErrors() []string {
if m != nil {
return m.Errors
}
return nil
}
func (m *ValidateResponse) GetError() string {
if m != nil {
return m.Error
}
return ""
}
type FinalizeRequest struct {
Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *FinalizeRequest) Reset() { *m = FinalizeRequest{} }
func (m *FinalizeRequest) String() string { return proto.CompactTextString(m) }
func (*FinalizeRequest) ProtoMessage() {}
func (*FinalizeRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_952629f1a9a7438c, []int{5}
}
func (m *FinalizeRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_FinalizeRequest.Unmarshal(m, b)
}
func (m *FinalizeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_FinalizeRequest.Marshal(b, m, deterministic)
}
func (m *FinalizeRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_FinalizeRequest.Merge(m, src)
}
func (m *FinalizeRequest) XXX_Size() int {
return xxx_messageInfo_FinalizeRequest.Size(m)
}
func (m *FinalizeRequest) XXX_DiscardUnknown() {
xxx_messageInfo_FinalizeRequest.DiscardUnknown(m)
}
var xxx_messageInfo_FinalizeRequest proto.InternalMessageInfo
func (m *FinalizeRequest) GetData() string {
if m != nil {
return m.Data
}
return ""
}
type FinalizeResponse struct {
Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *FinalizeResponse) Reset() { *m = FinalizeResponse{} }
func (m *FinalizeResponse) String() string { return proto.CompactTextString(m) }
func (*FinalizeResponse) ProtoMessage() {}
func (*FinalizeResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_952629f1a9a7438c, []int{6}
}
func (m *FinalizeResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_FinalizeResponse.Unmarshal(m, b)
}
func (m *FinalizeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_FinalizeResponse.Marshal(b, m, deterministic)
}
func (m *FinalizeResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_FinalizeResponse.Merge(m, src)
}
func (m *FinalizeResponse) XXX_Size() int {
return xxx_messageInfo_FinalizeResponse.Size(m)
}
func (m *FinalizeResponse) XXX_DiscardUnknown() {
xxx_messageInfo_FinalizeResponse.DiscardUnknown(m)
}
var xxx_messageInfo_FinalizeResponse proto.InternalMessageInfo
func (m *FinalizeResponse) GetData() string {
if m != nil {
return m.Data
}
return ""
}
func (m *FinalizeResponse) GetError() string {
if m != nil {
return m.Error
}
return ""
}
func init() {
proto.RegisterType((*AttributesResponse)(nil), "vagrant.config.AttributesResponse")
proto.RegisterType((*LoadRequest)(nil), "vagrant.config.LoadRequest")
proto.RegisterType((*LoadResponse)(nil), "vagrant.config.LoadResponse")
proto.RegisterType((*ValidateRequest)(nil), "vagrant.config.ValidateRequest")
proto.RegisterType((*ValidateResponse)(nil), "vagrant.config.ValidateResponse")
proto.RegisterType((*FinalizeRequest)(nil), "vagrant.config.FinalizeRequest")
proto.RegisterType((*FinalizeResponse)(nil), "vagrant.config.FinalizeResponse")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// ConfigClient is the client API for Config service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type ConfigClient interface {
ConfigAttributes(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*AttributesResponse, error)
ConfigLoad(ctx context.Context, in *LoadRequest, opts ...grpc.CallOption) (*LoadResponse, error)
ConfigValidate(ctx context.Context, in *ValidateRequest, opts ...grpc.CallOption) (*ValidateResponse, error)
ConfigFinalize(ctx context.Context, in *FinalizeRequest, opts ...grpc.CallOption) (*FinalizeResponse, error)
}
type configClient struct {
cc *grpc.ClientConn
}
func NewConfigClient(cc *grpc.ClientConn) ConfigClient {
return &configClient{cc}
}
func (c *configClient) ConfigAttributes(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*AttributesResponse, error) {
out := new(AttributesResponse)
err := c.cc.Invoke(ctx, "/vagrant.config.Config/ConfigAttributes", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *configClient) ConfigLoad(ctx context.Context, in *LoadRequest, opts ...grpc.CallOption) (*LoadResponse, error) {
out := new(LoadResponse)
err := c.cc.Invoke(ctx, "/vagrant.config.Config/ConfigLoad", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *configClient) ConfigValidate(ctx context.Context, in *ValidateRequest, opts ...grpc.CallOption) (*ValidateResponse, error) {
out := new(ValidateResponse)
err := c.cc.Invoke(ctx, "/vagrant.config.Config/ConfigValidate", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *configClient) ConfigFinalize(ctx context.Context, in *FinalizeRequest, opts ...grpc.CallOption) (*FinalizeResponse, error) {
out := new(FinalizeResponse)
err := c.cc.Invoke(ctx, "/vagrant.config.Config/ConfigFinalize", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ConfigServer is the server API for Config service.
type ConfigServer interface {
ConfigAttributes(context.Context, *vagrant_common.NullRequest) (*AttributesResponse, error)
ConfigLoad(context.Context, *LoadRequest) (*LoadResponse, error)
ConfigValidate(context.Context, *ValidateRequest) (*ValidateResponse, error)
ConfigFinalize(context.Context, *FinalizeRequest) (*FinalizeResponse, error)
}
func RegisterConfigServer(s *grpc.Server, srv ConfigServer) {
s.RegisterService(&_Config_serviceDesc, srv)
}
func _Config_ConfigAttributes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_common.NullRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ConfigServer).ConfigAttributes(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.config.Config/ConfigAttributes",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ConfigServer).ConfigAttributes(ctx, req.(*vagrant_common.NullRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Config_ConfigLoad_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(LoadRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ConfigServer).ConfigLoad(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.config.Config/ConfigLoad",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ConfigServer).ConfigLoad(ctx, req.(*LoadRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Config_ConfigValidate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ValidateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ConfigServer).ConfigValidate(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.config.Config/ConfigValidate",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ConfigServer).ConfigValidate(ctx, req.(*ValidateRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Config_ConfigFinalize_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(FinalizeRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ConfigServer).ConfigFinalize(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.config.Config/ConfigFinalize",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ConfigServer).ConfigFinalize(ctx, req.(*FinalizeRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Config_serviceDesc = grpc.ServiceDesc{
ServiceName: "vagrant.config.Config",
HandlerType: (*ConfigServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "ConfigAttributes",
Handler: _Config_ConfigAttributes_Handler,
},
{
MethodName: "ConfigLoad",
Handler: _Config_ConfigLoad_Handler,
},
{
MethodName: "ConfigValidate",
Handler: _Config_ConfigValidate_Handler,
},
{
MethodName: "ConfigFinalize",
Handler: _Config_ConfigFinalize_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "vagrant_config/config.proto",
}
func init() { proto.RegisterFile("vagrant_config/config.proto", fileDescriptor_952629f1a9a7438c) }
var fileDescriptor_952629f1a9a7438c = []byte{
// 363 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0xc1, 0x4b, 0xfb, 0x30,
0x14, 0xc7, 0xd9, 0x7e, 0x3f, 0x27, 0x7b, 0xca, 0x36, 0x82, 0x48, 0xe9, 0x44, 0x67, 0x41, 0xd8,
0xc5, 0x06, 0xf4, 0xe2, 0x41, 0x50, 0x11, 0x14, 0x44, 0x3c, 0x74, 0xe0, 0xc5, 0x83, 0x64, 0x5d,
0x6c, 0x03, 0x6d, 0x52, 0xd3, 0x54, 0xc4, 0xbf, 0xd2, 0x3f, 0x49, 0x4c, 0xd2, 0x75, 0xeb, 0xd6,
0x81, 0xa7, 0xe4, 0xbd, 0x7c, 0xf3, 0x79, 0xc9, 0xfb, 0x3e, 0x18, 0x7e, 0x90, 0x48, 0x12, 0xae,
0x5e, 0x43, 0xc1, 0xdf, 0x58, 0x84, 0xcd, 0xe2, 0x67, 0x52, 0x28, 0x81, 0x7a, 0xf6, 0xd0, 0x37,
0x59, 0xf7, 0x25, 0x62, 0x2a, 0x2e, 0xa6, 0x7e, 0x28, 0x52, 0x1c, 0x93, 0x3c, 0x66, 0xa1, 0x90,
0x19, 0xb6, 0x22, 0x4c, 0x3f, 0x15, 0x8e, 0xc4, 0x69, 0x96, 0x14, 0x11, 0xe3, 0xf3, 0xac, 0x0d,
0x35, 0x10, 0x57, 0xc5, 0xd2, 0x54, 0x70, 0x6c, 0x16, 0x53, 0xcc, 0x7b, 0x00, 0x74, 0xa3, 0x94,
0x64, 0xd3, 0x42, 0xd1, 0x3c, 0xa0, 0x79, 0x26, 0x78, 0x4e, 0xd1, 0x21, 0x00, 0x99, 0x67, 0x9d,
0xd6, 0xe8, 0xdf, 0xb8, 0x1b, 0x2c, 0x64, 0xd0, 0x1e, 0x6c, 0x51, 0x29, 0x85, 0x74, 0xda, 0xa3,
0xd6, 0xb8, 0x1b, 0x98, 0xc0, 0x3b, 0x86, 0x9d, 0x47, 0x41, 0x66, 0x01, 0x7d, 0x2f, 0x68, 0xae,
0x10, 0x82, 0xff, 0x33, 0xa2, 0x88, 0xd3, 0xd2, 0x1a, 0xbd, 0xf7, 0x2e, 0x60, 0xd7, 0x48, 0x6c,
0xa1, 0x35, 0x9a, 0x06, 0xf8, 0x15, 0xf4, 0x9f, 0x49, 0xc2, 0x66, 0x44, 0xd1, 0x0d, 0x05, 0x90,
0x03, 0xdb, 0x29, 0x09, 0x63, 0xc6, 0xa9, 0xbd, 0x5e, 0x86, 0xde, 0x35, 0x0c, 0x2a, 0x80, 0x2d,
0xbf, 0x0f, 0x1d, 0x4d, 0x2f, 0xff, 0x68, 0xa3, 0x86, 0x27, 0x9c, 0x40, 0xff, 0x8e, 0x71, 0x92,
0xb0, 0xaf, 0x4d, 0x4f, 0xf0, 0x2e, 0x61, 0x50, 0xc9, 0xfe, 0xfa, 0xcf, 0xb3, 0xef, 0x36, 0x74,
0x6e, 0xb5, 0xf1, 0x68, 0x02, 0x03, 0xb3, 0xab, 0x1c, 0x42, 0x43, 0xbf, 0x9a, 0x0e, 0x6d, 0xe3,
0x53, 0x91, 0x24, 0xf6, 0x35, 0xae, 0xe7, 0x2f, 0x8f, 0x8e, 0xbf, 0xc6, 0xda, 0x7b, 0x00, 0x03,
0xfd, 0xf5, 0x61, 0x09, 0xa7, 0x6f, 0x2c, 0x18, 0xe8, 0x1e, 0xac, 0x3f, 0xb4, 0xa0, 0x09, 0xf4,
0x0c, 0xa8, 0xec, 0x2a, 0x3a, 0xaa, 0xeb, 0x6b, 0x86, 0xb9, 0xa3, 0x66, 0x41, 0x1d, 0x5a, 0x76,
0x70, 0x15, 0x5a, 0xb3, 0x60, 0x15, 0x5a, 0x6f, 0xfe, 0xb4, 0xa3, 0x47, 0xfd, 0xfc, 0x27, 0x00,
0x00, 0xff, 0xff, 0xe0, 0x00, 0xbf, 0x51, 0x76, 0x03, 0x00, 0x00,
}

View File

@ -0,0 +1,44 @@
syntax = "proto3";
package vagrant.config;
import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common/common.proto";
message AttributesResponse {
repeated string attributes = 1;
string error = 2;
}
message LoadRequest {
string data = 1;
}
message LoadResponse {
string data = 1;
string error = 2;
}
message ValidateRequest {
string data = 1;
string machine = 2;
}
message ValidateResponse {
repeated string errors = 1;
string error = 2;
}
message FinalizeRequest {
string data = 1;
}
message FinalizeResponse {
string data = 1;
string error = 2;
}
service Config {
rpc ConfigAttributes(vagrant.common.NullRequest) returns (AttributesResponse);
rpc ConfigLoad(LoadRequest) returns (LoadResponse);
rpc ConfigValidate(ValidateRequest) returns (ValidateResponse);
rpc ConfigFinalize(FinalizeRequest) returns (FinalizeResponse);
}

View File

@ -0,0 +1,688 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: vagrant_folder/synced_folder.proto
package vagrant_folder
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import vagrant_caps "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_caps"
import vagrant_common "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common"
import vagrant_io "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_io"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Request struct {
Machine string `protobuf:"bytes,1,opt,name=machine,proto3" json:"machine,omitempty"`
Folders string `protobuf:"bytes,2,opt,name=folders,proto3" json:"folders,omitempty"`
Options string `protobuf:"bytes,3,opt,name=options,proto3" json:"options,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Request) Reset() { *m = Request{} }
func (m *Request) String() string { return proto.CompactTextString(m) }
func (*Request) ProtoMessage() {}
func (*Request) Descriptor() ([]byte, []int) {
return fileDescriptor_8a01e482b349ecb1, []int{0}
}
func (m *Request) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Request.Unmarshal(m, b)
}
func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Request.Marshal(b, m, deterministic)
}
func (m *Request) XXX_Merge(src proto.Message) {
xxx_messageInfo_Request.Merge(m, src)
}
func (m *Request) XXX_Size() int {
return xxx_messageInfo_Request.Size(m)
}
func (m *Request) XXX_DiscardUnknown() {
xxx_messageInfo_Request.DiscardUnknown(m)
}
var xxx_messageInfo_Request proto.InternalMessageInfo
func (m *Request) GetMachine() string {
if m != nil {
return m.Machine
}
return ""
}
func (m *Request) GetFolders() string {
if m != nil {
return m.Folders
}
return ""
}
func (m *Request) GetOptions() string {
if m != nil {
return m.Options
}
return ""
}
type CleanupRequest struct {
Machine string `protobuf:"bytes,1,opt,name=machine,proto3" json:"machine,omitempty"`
Options string `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CleanupRequest) Reset() { *m = CleanupRequest{} }
func (m *CleanupRequest) String() string { return proto.CompactTextString(m) }
func (*CleanupRequest) ProtoMessage() {}
func (*CleanupRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_8a01e482b349ecb1, []int{1}
}
func (m *CleanupRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_CleanupRequest.Unmarshal(m, b)
}
func (m *CleanupRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_CleanupRequest.Marshal(b, m, deterministic)
}
func (m *CleanupRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_CleanupRequest.Merge(m, src)
}
func (m *CleanupRequest) XXX_Size() int {
return xxx_messageInfo_CleanupRequest.Size(m)
}
func (m *CleanupRequest) XXX_DiscardUnknown() {
xxx_messageInfo_CleanupRequest.DiscardUnknown(m)
}
var xxx_messageInfo_CleanupRequest proto.InternalMessageInfo
func (m *CleanupRequest) GetMachine() string {
if m != nil {
return m.Machine
}
return ""
}
func (m *CleanupRequest) GetOptions() string {
if m != nil {
return m.Options
}
return ""
}
type InfoResponse struct {
Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"`
Priority int64 `protobuf:"varint,2,opt,name=priority,proto3" json:"priority,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *InfoResponse) Reset() { *m = InfoResponse{} }
func (m *InfoResponse) String() string { return proto.CompactTextString(m) }
func (*InfoResponse) ProtoMessage() {}
func (*InfoResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_8a01e482b349ecb1, []int{2}
}
func (m *InfoResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_InfoResponse.Unmarshal(m, b)
}
func (m *InfoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_InfoResponse.Marshal(b, m, deterministic)
}
func (m *InfoResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_InfoResponse.Merge(m, src)
}
func (m *InfoResponse) XXX_Size() int {
return xxx_messageInfo_InfoResponse.Size(m)
}
func (m *InfoResponse) XXX_DiscardUnknown() {
xxx_messageInfo_InfoResponse.DiscardUnknown(m)
}
var xxx_messageInfo_InfoResponse proto.InternalMessageInfo
func (m *InfoResponse) GetDescription() string {
if m != nil {
return m.Description
}
return ""
}
func (m *InfoResponse) GetPriority() int64 {
if m != nil {
return m.Priority
}
return 0
}
func init() {
proto.RegisterType((*Request)(nil), "vagrant.folder.Request")
proto.RegisterType((*CleanupRequest)(nil), "vagrant.folder.CleanupRequest")
proto.RegisterType((*InfoResponse)(nil), "vagrant.folder.InfoResponse")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// SyncedFolderClient is the client API for SyncedFolder service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type SyncedFolderClient interface {
Cleanup(ctx context.Context, in *CleanupRequest, opts ...grpc.CallOption) (*vagrant_common.EmptyResponse, error)
Disable(ctx context.Context, in *Request, opts ...grpc.CallOption) (*vagrant_common.EmptyResponse, error)
Enable(ctx context.Context, in *Request, opts ...grpc.CallOption) (*vagrant_common.EmptyResponse, error)
Info(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*InfoResponse, error)
IsUsable(ctx context.Context, in *vagrant_common.EmptyRequest, opts ...grpc.CallOption) (*vagrant_common.IsResponse, error)
Name(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*vagrant_common.NameResponse, error)
Prepare(ctx context.Context, in *Request, opts ...grpc.CallOption) (*vagrant_common.EmptyResponse, error)
// These are IO helpers for streaming
Read(ctx context.Context, in *vagrant_io.ReadRequest, opts ...grpc.CallOption) (*vagrant_io.ReadResponse, error)
Write(ctx context.Context, in *vagrant_io.WriteRequest, opts ...grpc.CallOption) (*vagrant_io.WriteResponse, error)
// Capabilities
GuestCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*vagrant_caps.CapabilitiesResponse, error)
GuestCapability(ctx context.Context, in *vagrant_caps.GuestCapabilityRequest, opts ...grpc.CallOption) (*vagrant_caps.GuestCapabilityResponse, error)
HostCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*vagrant_caps.CapabilitiesResponse, error)
HostCapability(ctx context.Context, in *vagrant_caps.HostCapabilityRequest, opts ...grpc.CallOption) (*vagrant_caps.HostCapabilityResponse, error)
}
type syncedFolderClient struct {
cc *grpc.ClientConn
}
func NewSyncedFolderClient(cc *grpc.ClientConn) SyncedFolderClient {
return &syncedFolderClient{cc}
}
func (c *syncedFolderClient) Cleanup(ctx context.Context, in *CleanupRequest, opts ...grpc.CallOption) (*vagrant_common.EmptyResponse, error) {
out := new(vagrant_common.EmptyResponse)
err := c.cc.Invoke(ctx, "/vagrant.folder.SyncedFolder/Cleanup", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *syncedFolderClient) Disable(ctx context.Context, in *Request, opts ...grpc.CallOption) (*vagrant_common.EmptyResponse, error) {
out := new(vagrant_common.EmptyResponse)
err := c.cc.Invoke(ctx, "/vagrant.folder.SyncedFolder/Disable", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *syncedFolderClient) Enable(ctx context.Context, in *Request, opts ...grpc.CallOption) (*vagrant_common.EmptyResponse, error) {
out := new(vagrant_common.EmptyResponse)
err := c.cc.Invoke(ctx, "/vagrant.folder.SyncedFolder/Enable", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *syncedFolderClient) Info(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*InfoResponse, error) {
out := new(InfoResponse)
err := c.cc.Invoke(ctx, "/vagrant.folder.SyncedFolder/Info", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *syncedFolderClient) IsUsable(ctx context.Context, in *vagrant_common.EmptyRequest, opts ...grpc.CallOption) (*vagrant_common.IsResponse, error) {
out := new(vagrant_common.IsResponse)
err := c.cc.Invoke(ctx, "/vagrant.folder.SyncedFolder/IsUsable", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *syncedFolderClient) Name(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*vagrant_common.NameResponse, error) {
out := new(vagrant_common.NameResponse)
err := c.cc.Invoke(ctx, "/vagrant.folder.SyncedFolder/Name", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *syncedFolderClient) Prepare(ctx context.Context, in *Request, opts ...grpc.CallOption) (*vagrant_common.EmptyResponse, error) {
out := new(vagrant_common.EmptyResponse)
err := c.cc.Invoke(ctx, "/vagrant.folder.SyncedFolder/Prepare", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *syncedFolderClient) Read(ctx context.Context, in *vagrant_io.ReadRequest, opts ...grpc.CallOption) (*vagrant_io.ReadResponse, error) {
out := new(vagrant_io.ReadResponse)
err := c.cc.Invoke(ctx, "/vagrant.folder.SyncedFolder/Read", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *syncedFolderClient) Write(ctx context.Context, in *vagrant_io.WriteRequest, opts ...grpc.CallOption) (*vagrant_io.WriteResponse, error) {
out := new(vagrant_io.WriteResponse)
err := c.cc.Invoke(ctx, "/vagrant.folder.SyncedFolder/Write", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *syncedFolderClient) GuestCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*vagrant_caps.CapabilitiesResponse, error) {
out := new(vagrant_caps.CapabilitiesResponse)
err := c.cc.Invoke(ctx, "/vagrant.folder.SyncedFolder/GuestCapabilities", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *syncedFolderClient) GuestCapability(ctx context.Context, in *vagrant_caps.GuestCapabilityRequest, opts ...grpc.CallOption) (*vagrant_caps.GuestCapabilityResponse, error) {
out := new(vagrant_caps.GuestCapabilityResponse)
err := c.cc.Invoke(ctx, "/vagrant.folder.SyncedFolder/GuestCapability", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *syncedFolderClient) HostCapabilities(ctx context.Context, in *vagrant_common.NullRequest, opts ...grpc.CallOption) (*vagrant_caps.CapabilitiesResponse, error) {
out := new(vagrant_caps.CapabilitiesResponse)
err := c.cc.Invoke(ctx, "/vagrant.folder.SyncedFolder/HostCapabilities", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *syncedFolderClient) HostCapability(ctx context.Context, in *vagrant_caps.HostCapabilityRequest, opts ...grpc.CallOption) (*vagrant_caps.HostCapabilityResponse, error) {
out := new(vagrant_caps.HostCapabilityResponse)
err := c.cc.Invoke(ctx, "/vagrant.folder.SyncedFolder/HostCapability", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// SyncedFolderServer is the server API for SyncedFolder service.
type SyncedFolderServer interface {
Cleanup(context.Context, *CleanupRequest) (*vagrant_common.EmptyResponse, error)
Disable(context.Context, *Request) (*vagrant_common.EmptyResponse, error)
Enable(context.Context, *Request) (*vagrant_common.EmptyResponse, error)
Info(context.Context, *vagrant_common.NullRequest) (*InfoResponse, error)
IsUsable(context.Context, *vagrant_common.EmptyRequest) (*vagrant_common.IsResponse, error)
Name(context.Context, *vagrant_common.NullRequest) (*vagrant_common.NameResponse, error)
Prepare(context.Context, *Request) (*vagrant_common.EmptyResponse, error)
// These are IO helpers for streaming
Read(context.Context, *vagrant_io.ReadRequest) (*vagrant_io.ReadResponse, error)
Write(context.Context, *vagrant_io.WriteRequest) (*vagrant_io.WriteResponse, error)
// Capabilities
GuestCapabilities(context.Context, *vagrant_common.NullRequest) (*vagrant_caps.CapabilitiesResponse, error)
GuestCapability(context.Context, *vagrant_caps.GuestCapabilityRequest) (*vagrant_caps.GuestCapabilityResponse, error)
HostCapabilities(context.Context, *vagrant_common.NullRequest) (*vagrant_caps.CapabilitiesResponse, error)
HostCapability(context.Context, *vagrant_caps.HostCapabilityRequest) (*vagrant_caps.HostCapabilityResponse, error)
}
func RegisterSyncedFolderServer(s *grpc.Server, srv SyncedFolderServer) {
s.RegisterService(&_SyncedFolder_serviceDesc, srv)
}
func _SyncedFolder_Cleanup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CleanupRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SyncedFolderServer).Cleanup(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.folder.SyncedFolder/Cleanup",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SyncedFolderServer).Cleanup(ctx, req.(*CleanupRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SyncedFolder_Disable_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SyncedFolderServer).Disable(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.folder.SyncedFolder/Disable",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SyncedFolderServer).Disable(ctx, req.(*Request))
}
return interceptor(ctx, in, info, handler)
}
func _SyncedFolder_Enable_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SyncedFolderServer).Enable(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.folder.SyncedFolder/Enable",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SyncedFolderServer).Enable(ctx, req.(*Request))
}
return interceptor(ctx, in, info, handler)
}
func _SyncedFolder_Info_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_common.NullRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SyncedFolderServer).Info(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.folder.SyncedFolder/Info",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SyncedFolderServer).Info(ctx, req.(*vagrant_common.NullRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SyncedFolder_IsUsable_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_common.EmptyRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SyncedFolderServer).IsUsable(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.folder.SyncedFolder/IsUsable",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SyncedFolderServer).IsUsable(ctx, req.(*vagrant_common.EmptyRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SyncedFolder_Name_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_common.NullRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SyncedFolderServer).Name(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.folder.SyncedFolder/Name",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SyncedFolderServer).Name(ctx, req.(*vagrant_common.NullRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SyncedFolder_Prepare_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Request)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SyncedFolderServer).Prepare(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.folder.SyncedFolder/Prepare",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SyncedFolderServer).Prepare(ctx, req.(*Request))
}
return interceptor(ctx, in, info, handler)
}
func _SyncedFolder_Read_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_io.ReadRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SyncedFolderServer).Read(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.folder.SyncedFolder/Read",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SyncedFolderServer).Read(ctx, req.(*vagrant_io.ReadRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SyncedFolder_Write_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_io.WriteRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SyncedFolderServer).Write(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.folder.SyncedFolder/Write",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SyncedFolderServer).Write(ctx, req.(*vagrant_io.WriteRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SyncedFolder_GuestCapabilities_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_common.NullRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SyncedFolderServer).GuestCapabilities(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.folder.SyncedFolder/GuestCapabilities",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SyncedFolderServer).GuestCapabilities(ctx, req.(*vagrant_common.NullRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SyncedFolder_GuestCapability_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_caps.GuestCapabilityRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SyncedFolderServer).GuestCapability(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.folder.SyncedFolder/GuestCapability",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SyncedFolderServer).GuestCapability(ctx, req.(*vagrant_caps.GuestCapabilityRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SyncedFolder_HostCapabilities_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_common.NullRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SyncedFolderServer).HostCapabilities(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.folder.SyncedFolder/HostCapabilities",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SyncedFolderServer).HostCapabilities(ctx, req.(*vagrant_common.NullRequest))
}
return interceptor(ctx, in, info, handler)
}
func _SyncedFolder_HostCapability_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(vagrant_caps.HostCapabilityRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(SyncedFolderServer).HostCapability(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.folder.SyncedFolder/HostCapability",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(SyncedFolderServer).HostCapability(ctx, req.(*vagrant_caps.HostCapabilityRequest))
}
return interceptor(ctx, in, info, handler)
}
var _SyncedFolder_serviceDesc = grpc.ServiceDesc{
ServiceName: "vagrant.folder.SyncedFolder",
HandlerType: (*SyncedFolderServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Cleanup",
Handler: _SyncedFolder_Cleanup_Handler,
},
{
MethodName: "Disable",
Handler: _SyncedFolder_Disable_Handler,
},
{
MethodName: "Enable",
Handler: _SyncedFolder_Enable_Handler,
},
{
MethodName: "Info",
Handler: _SyncedFolder_Info_Handler,
},
{
MethodName: "IsUsable",
Handler: _SyncedFolder_IsUsable_Handler,
},
{
MethodName: "Name",
Handler: _SyncedFolder_Name_Handler,
},
{
MethodName: "Prepare",
Handler: _SyncedFolder_Prepare_Handler,
},
{
MethodName: "Read",
Handler: _SyncedFolder_Read_Handler,
},
{
MethodName: "Write",
Handler: _SyncedFolder_Write_Handler,
},
{
MethodName: "GuestCapabilities",
Handler: _SyncedFolder_GuestCapabilities_Handler,
},
{
MethodName: "GuestCapability",
Handler: _SyncedFolder_GuestCapability_Handler,
},
{
MethodName: "HostCapabilities",
Handler: _SyncedFolder_HostCapabilities_Handler,
},
{
MethodName: "HostCapability",
Handler: _SyncedFolder_HostCapability_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "vagrant_folder/synced_folder.proto",
}
func init() { proto.RegisterFile("vagrant_folder/synced_folder.proto", fileDescriptor_8a01e482b349ecb1) }
var fileDescriptor_8a01e482b349ecb1 = []byte{
// 488 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0x5f, 0x6f, 0xd3, 0x30,
0x14, 0xc5, 0xb5, 0x3f, 0x2c, 0xe3, 0x32, 0x15, 0xf0, 0x0b, 0x21, 0x0c, 0x34, 0x95, 0x21, 0xf1,
0x42, 0x22, 0xc1, 0x13, 0x12, 0x0f, 0x4c, 0xeb, 0x60, 0x95, 0xd0, 0x84, 0x52, 0xd0, 0x1e, 0x26,
0x51, 0xb9, 0xa9, 0xd7, 0x5a, 0x4a, 0x6c, 0x63, 0x3b, 0x88, 0x7c, 0x48, 0xbe, 0x13, 0x4a, 0x6c,
0x87, 0x38, 0x40, 0xa9, 0x58, 0x9f, 0xaa, 0x7b, 0xcf, 0x3d, 0x3f, 0x9f, 0xde, 0x38, 0x81, 0xe1,
0x37, 0xbc, 0x90, 0x98, 0xe9, 0xe9, 0x35, 0xcf, 0xe7, 0x44, 0x26, 0xaa, 0x62, 0x19, 0x99, 0xdb,
0x2a, 0x16, 0x92, 0x6b, 0x8e, 0x06, 0x76, 0x26, 0x36, 0xdd, 0xe8, 0x6a, 0x41, 0xf5, 0xb2, 0x9c,
0xc5, 0x19, 0x2f, 0x92, 0x25, 0x56, 0x4b, 0x9a, 0x71, 0x29, 0x12, 0x3b, 0x94, 0x90, 0xef, 0x3a,
0x59, 0xf0, 0x17, 0x22, 0x2f, 0x17, 0x94, 0xb5, 0x5d, 0x5b, 0x36, 0x40, 0xd7, 0x9c, 0x66, 0xbc,
0x28, 0x38, 0x4b, 0xcc, 0x8f, 0x39, 0x2c, 0x9a, 0x6c, 0x0a, 0x4e, 0x79, 0x42, 0xb9, 0x85, 0x4e,
0x37, 0x96, 0x18, 0x0b, 0x95, 0x64, 0x58, 0xe0, 0x19, 0xcd, 0xa9, 0xa6, 0x44, 0x99, 0x03, 0x86,
0x97, 0x10, 0xa4, 0xe4, 0x6b, 0x49, 0x94, 0x46, 0x21, 0x04, 0x05, 0xce, 0x96, 0x94, 0x91, 0x70,
0xeb, 0x68, 0xeb, 0xf9, 0xed, 0xd4, 0x95, 0xb5, 0x62, 0x36, 0xa8, 0xc2, 0x6d, 0xa3, 0xd8, 0xb2,
0x56, 0xb8, 0xd0, 0x94, 0x33, 0x15, 0xee, 0x18, 0xc5, 0x96, 0xc3, 0x11, 0x0c, 0x4e, 0x73, 0x82,
0x59, 0x29, 0xd6, 0xe2, 0x3b, 0xca, 0xb6, 0x4f, 0xf9, 0x00, 0x07, 0x63, 0x76, 0xcd, 0x53, 0xa2,
0x04, 0x67, 0x8a, 0xa0, 0x23, 0xb8, 0x33, 0x27, 0x2a, 0x93, 0xb4, 0xd1, 0x2d, 0xa7, 0xdb, 0x42,
0x11, 0xec, 0x0b, 0x49, 0xb9, 0xa4, 0xba, 0x6a, 0x60, 0x3b, 0x69, 0x5b, 0xbf, 0xfc, 0x11, 0xc0,
0xc1, 0xa4, 0xb9, 0x27, 0xef, 0x9a, 0xfc, 0xe8, 0x1c, 0x02, 0x1b, 0x12, 0x3d, 0x89, 0xfd, 0xcb,
0x12, 0xfb, 0xe9, 0xa3, 0xc7, 0xad, 0x6e, 0x9f, 0xfa, 0x59, 0x21, 0x74, 0xd5, 0x06, 0x3b, 0x81,
0x60, 0x44, 0x15, 0x9e, 0xe5, 0x04, 0x3d, 0xe8, 0x93, 0xd6, 0x44, 0xbc, 0x85, 0xbd, 0x33, 0x76,
0x23, 0xc2, 0x09, 0xec, 0xd6, 0xdb, 0x42, 0x8f, 0xfa, 0x63, 0x17, 0x65, 0x9e, 0x3b, 0xc6, 0x61,
0x1f, 0xee, 0x2d, 0x78, 0x04, 0xfb, 0x63, 0xf5, 0xd9, 0xfc, 0x91, 0xc3, 0xbf, 0x9c, 0x66, 0x38,
0x51, 0x5f, 0x1d, 0xab, 0x6e, 0x90, 0x0b, 0x5c, 0x90, 0x75, 0x83, 0x38, 0x11, 0x17, 0xa4, 0xbb,
0xd0, 0x8f, 0x92, 0x08, 0x2c, 0xff, 0x7f, 0x1d, 0xaf, 0x61, 0x37, 0x25, 0x78, 0xde, 0xf1, 0x53,
0x1e, 0xd7, 0x1d, 0xe7, 0x0f, 0x7f, 0x17, 0xac, 0xf5, 0x0d, 0xdc, 0xba, 0x94, 0x54, 0x13, 0xe4,
0x8d, 0x34, 0x2d, 0x67, 0x7e, 0xf8, 0x07, 0xc5, 0xba, 0x3f, 0xc1, 0xfd, 0xf7, 0xf5, 0xcc, 0x69,
0xe7, 0x7d, 0x5b, 0xbd, 0x8b, 0xe1, 0x2f, 0x11, 0x0b, 0x15, 0x77, 0x8d, 0x2d, 0xf5, 0x0b, 0xdc,
0xf5, 0xa9, 0x15, 0x3a, 0xf6, 0x6d, 0x3d, 0xd9, 0xc1, 0x9f, 0xfd, 0x63, 0xca, 0xf2, 0x27, 0x70,
0xef, 0x9c, 0x6f, 0x3a, 0xf4, 0x15, 0x0c, 0x3c, 0x68, 0x85, 0x9e, 0xfa, 0x2e, 0x5f, 0x75, 0xe8,
0xe3, 0xd5, 0x43, 0x06, 0x3e, 0xdb, 0x6b, 0xbe, 0x61, 0xaf, 0x7e, 0x06, 0x00, 0x00, 0xff, 0xff,
0x89, 0x36, 0xb1, 0x5c, 0x0c, 0x06, 0x00, 0x00,
}

View File

@ -0,0 +1,40 @@
syntax = "proto3";
package vagrant.folder;
import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common/common.proto";
import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_io/io.proto";
import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_caps/capabilities.proto";
message Request {
string machine = 1;
string folders = 2;
string options = 3;
}
message CleanupRequest {
string machine = 1;
string options = 2;
}
message InfoResponse {
string description = 1;
int64 priority = 2;
}
service SyncedFolder {
rpc Cleanup(CleanupRequest) returns (vagrant.common.EmptyResponse);
rpc Disable(Request) returns (vagrant.common.EmptyResponse);
rpc Enable(Request) returns (vagrant.common.EmptyResponse);
rpc Info(vagrant.common.NullRequest) returns (InfoResponse);
rpc IsUsable(vagrant.common.EmptyRequest) returns (vagrant.common.IsResponse);
rpc Name(vagrant.common.NullRequest) returns (vagrant.common.NameResponse);
rpc Prepare(Request) returns (vagrant.common.EmptyResponse);
// These are IO helpers for streaming
rpc Read(vagrant.io.ReadRequest) returns (vagrant.io.ReadResponse);
rpc Write(vagrant.io.WriteRequest) returns (vagrant.io.WriteResponse);
// Capabilities
rpc GuestCapabilities(vagrant.common.NullRequest) returns (vagrant.caps.CapabilitiesResponse);
rpc GuestCapability(vagrant.caps.GuestCapabilityRequest) returns (vagrant.caps.GuestCapabilityResponse);
rpc HostCapabilities(vagrant.common.NullRequest) returns (vagrant.caps.CapabilitiesResponse);
rpc HostCapability(vagrant.caps.HostCapabilityRequest) returns (vagrant.caps.HostCapabilityResponse);
}

View File

@ -0,0 +1,332 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: vagrant_io/io.proto
package vagrant_io
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type ReadRequest struct {
Target string `protobuf:"bytes,1,opt,name=target,proto3" json:"target,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReadRequest) Reset() { *m = ReadRequest{} }
func (m *ReadRequest) String() string { return proto.CompactTextString(m) }
func (*ReadRequest) ProtoMessage() {}
func (*ReadRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_d46affeac7affd9e, []int{0}
}
func (m *ReadRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReadRequest.Unmarshal(m, b)
}
func (m *ReadRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReadRequest.Marshal(b, m, deterministic)
}
func (m *ReadRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReadRequest.Merge(m, src)
}
func (m *ReadRequest) XXX_Size() int {
return xxx_messageInfo_ReadRequest.Size(m)
}
func (m *ReadRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ReadRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ReadRequest proto.InternalMessageInfo
func (m *ReadRequest) GetTarget() string {
if m != nil {
return m.Target
}
return ""
}
type ReadResponse struct {
Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ReadResponse) Reset() { *m = ReadResponse{} }
func (m *ReadResponse) String() string { return proto.CompactTextString(m) }
func (*ReadResponse) ProtoMessage() {}
func (*ReadResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_d46affeac7affd9e, []int{1}
}
func (m *ReadResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ReadResponse.Unmarshal(m, b)
}
func (m *ReadResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ReadResponse.Marshal(b, m, deterministic)
}
func (m *ReadResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_ReadResponse.Merge(m, src)
}
func (m *ReadResponse) XXX_Size() int {
return xxx_messageInfo_ReadResponse.Size(m)
}
func (m *ReadResponse) XXX_DiscardUnknown() {
xxx_messageInfo_ReadResponse.DiscardUnknown(m)
}
var xxx_messageInfo_ReadResponse proto.InternalMessageInfo
func (m *ReadResponse) GetContent() string {
if m != nil {
return m.Content
}
return ""
}
func (m *ReadResponse) GetError() string {
if m != nil {
return m.Error
}
return ""
}
type WriteRequest struct {
Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"`
Target string `protobuf:"bytes,2,opt,name=target,proto3" json:"target,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *WriteRequest) Reset() { *m = WriteRequest{} }
func (m *WriteRequest) String() string { return proto.CompactTextString(m) }
func (*WriteRequest) ProtoMessage() {}
func (*WriteRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_d46affeac7affd9e, []int{2}
}
func (m *WriteRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_WriteRequest.Unmarshal(m, b)
}
func (m *WriteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_WriteRequest.Marshal(b, m, deterministic)
}
func (m *WriteRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_WriteRequest.Merge(m, src)
}
func (m *WriteRequest) XXX_Size() int {
return xxx_messageInfo_WriteRequest.Size(m)
}
func (m *WriteRequest) XXX_DiscardUnknown() {
xxx_messageInfo_WriteRequest.DiscardUnknown(m)
}
var xxx_messageInfo_WriteRequest proto.InternalMessageInfo
func (m *WriteRequest) GetContent() string {
if m != nil {
return m.Content
}
return ""
}
func (m *WriteRequest) GetTarget() string {
if m != nil {
return m.Target
}
return ""
}
type WriteResponse struct {
Length int32 `protobuf:"varint,1,opt,name=length,proto3" json:"length,omitempty"`
Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *WriteResponse) Reset() { *m = WriteResponse{} }
func (m *WriteResponse) String() string { return proto.CompactTextString(m) }
func (*WriteResponse) ProtoMessage() {}
func (*WriteResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_d46affeac7affd9e, []int{3}
}
func (m *WriteResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_WriteResponse.Unmarshal(m, b)
}
func (m *WriteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_WriteResponse.Marshal(b, m, deterministic)
}
func (m *WriteResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_WriteResponse.Merge(m, src)
}
func (m *WriteResponse) XXX_Size() int {
return xxx_messageInfo_WriteResponse.Size(m)
}
func (m *WriteResponse) XXX_DiscardUnknown() {
xxx_messageInfo_WriteResponse.DiscardUnknown(m)
}
var xxx_messageInfo_WriteResponse proto.InternalMessageInfo
func (m *WriteResponse) GetLength() int32 {
if m != nil {
return m.Length
}
return 0
}
func (m *WriteResponse) GetError() string {
if m != nil {
return m.Error
}
return ""
}
func init() {
proto.RegisterType((*ReadRequest)(nil), "vagrant.io.ReadRequest")
proto.RegisterType((*ReadResponse)(nil), "vagrant.io.ReadResponse")
proto.RegisterType((*WriteRequest)(nil), "vagrant.io.WriteRequest")
proto.RegisterType((*WriteResponse)(nil), "vagrant.io.WriteResponse")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// IOClient is the client API for IO service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type IOClient interface {
Read(ctx context.Context, in *ReadRequest, opts ...grpc.CallOption) (*ReadResponse, error)
Write(ctx context.Context, in *WriteRequest, opts ...grpc.CallOption) (*WriteResponse, error)
}
type iOClient struct {
cc *grpc.ClientConn
}
func NewIOClient(cc *grpc.ClientConn) IOClient {
return &iOClient{cc}
}
func (c *iOClient) Read(ctx context.Context, in *ReadRequest, opts ...grpc.CallOption) (*ReadResponse, error) {
out := new(ReadResponse)
err := c.cc.Invoke(ctx, "/vagrant.io.IO/Read", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *iOClient) Write(ctx context.Context, in *WriteRequest, opts ...grpc.CallOption) (*WriteResponse, error) {
out := new(WriteResponse)
err := c.cc.Invoke(ctx, "/vagrant.io.IO/Write", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// IOServer is the server API for IO service.
type IOServer interface {
Read(context.Context, *ReadRequest) (*ReadResponse, error)
Write(context.Context, *WriteRequest) (*WriteResponse, error)
}
func RegisterIOServer(s *grpc.Server, srv IOServer) {
s.RegisterService(&_IO_serviceDesc, srv)
}
func _IO_Read_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ReadRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(IOServer).Read(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.io.IO/Read",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(IOServer).Read(ctx, req.(*ReadRequest))
}
return interceptor(ctx, in, info, handler)
}
func _IO_Write_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(WriteRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(IOServer).Write(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/vagrant.io.IO/Write",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(IOServer).Write(ctx, req.(*WriteRequest))
}
return interceptor(ctx, in, info, handler)
}
var _IO_serviceDesc = grpc.ServiceDesc{
ServiceName: "vagrant.io.IO",
HandlerType: (*IOServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Read",
Handler: _IO_Read_Handler,
},
{
MethodName: "Write",
Handler: _IO_Write_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "vagrant_io/io.proto",
}
func init() { proto.RegisterFile("vagrant_io/io.proto", fileDescriptor_d46affeac7affd9e) }
var fileDescriptor_d46affeac7affd9e = []byte{
// 219 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2e, 0x4b, 0x4c, 0x2f,
0x4a, 0xcc, 0x2b, 0x89, 0xcf, 0xcc, 0xd7, 0xcf, 0xcc, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17,
0xe2, 0x82, 0x0a, 0xea, 0x65, 0xe6, 0x2b, 0xa9, 0x72, 0x71, 0x07, 0xa5, 0x26, 0xa6, 0x04, 0xa5,
0x16, 0x96, 0xa6, 0x16, 0x97, 0x08, 0x89, 0x71, 0xb1, 0x95, 0x24, 0x16, 0xa5, 0xa7, 0x96, 0x48,
0x30, 0x2a, 0x30, 0x6a, 0x70, 0x06, 0x41, 0x79, 0x4a, 0x76, 0x5c, 0x3c, 0x10, 0x65, 0xc5, 0x05,
0xf9, 0x79, 0xc5, 0xa9, 0x42, 0x12, 0x5c, 0xec, 0xc9, 0xf9, 0x79, 0x25, 0xa9, 0x79, 0x30, 0x85,
0x30, 0xae, 0x90, 0x08, 0x17, 0x6b, 0x6a, 0x51, 0x51, 0x7e, 0x91, 0x04, 0x13, 0x58, 0x1c, 0xc2,
0x51, 0x72, 0xe0, 0xe2, 0x09, 0x2f, 0xca, 0x2c, 0x49, 0x85, 0xd9, 0x83, 0x5b, 0x3f, 0xc2, 0x05,
0x4c, 0x28, 0x2e, 0xb0, 0xe5, 0xe2, 0x85, 0x9a, 0x00, 0x75, 0x82, 0x18, 0x17, 0x5b, 0x4e, 0x6a,
0x5e, 0x7a, 0x49, 0x06, 0xd8, 0x04, 0xd6, 0x20, 0x28, 0x0f, 0xbb, 0x03, 0x8c, 0x6a, 0xb9, 0x98,
0x3c, 0xfd, 0x85, 0x2c, 0xb9, 0x58, 0x40, 0xde, 0x10, 0x12, 0xd7, 0x43, 0x04, 0x81, 0x1e, 0x92,
0xff, 0xa5, 0x24, 0x30, 0x25, 0xa0, 0xd6, 0xd9, 0x70, 0xb1, 0x82, 0xed, 0x17, 0x42, 0x51, 0x82,
0xec, 0x29, 0x29, 0x49, 0x2c, 0x32, 0x10, 0xdd, 0x49, 0x6c, 0xe0, 0x90, 0x37, 0x06, 0x04, 0x00,
0x00, 0xff, 0xff, 0x47, 0x7e, 0x0b, 0xe4, 0x90, 0x01, 0x00, 0x00,
}

View File

@ -0,0 +1,26 @@
syntax = "proto3";
package vagrant.io;
message ReadRequest {
string target = 1;
}
message ReadResponse {
string content = 1;
string error = 2;
}
message WriteRequest {
string content = 1;
string target = 2;
}
message WriteResponse {
int32 length = 1;
string error = 2;
}
service IO {
rpc Read(ReadRequest) returns (ReadResponse);
rpc Write(WriteRequest) returns (WriteResponse);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,74 @@
syntax = "proto3";
package vagrant.provider;
import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_caps/capabilities.proto";
import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common/common.proto";
import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_config/config.proto";
import "github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_io/io.proto";
message ActionRequest {
string name = 1;
string machine = 2;
}
message ActionResponse {
repeated string result = 1;
string error = 2;
}
message InfoResponse {
repeated string capabilities = 1;
string description = 2;
int64 priority = 3;
}
message RunActionRequest {
string name = 1;
string data = 2;
string machine = 3;
}
message RunActionResponse {
string data = 1;
string error = 2;
}
message SshInfoResponse {
string host = 1;
int64 port = 2;
string private_key_path = 3;
string username = 4;
string error = 5;
}
message StateResponse {
string id = 1;
string short_description = 2;
string long_description = 3;
string error = 4;
}
service Provider {
rpc Action(ActionRequest) returns (ActionResponse);
rpc Info(vagrant.common.NullRequest) returns (InfoResponse);
rpc IsInstalled(vagrant.common.EmptyRequest) returns (vagrant.common.IsResponse);
rpc IsUsable(vagrant.common.EmptyRequest) returns (vagrant.common.IsResponse);
rpc MachineIdChanged(vagrant.common.EmptyRequest) returns (vagrant.common.EmptyResponse);
rpc Name(vagrant.common.NullRequest) returns (vagrant.common.NameResponse);
rpc RunAction(RunActionRequest) returns (RunActionResponse);
rpc SshInfo(vagrant.common.EmptyRequest) returns (SshInfoResponse);
rpc State(vagrant.common.EmptyRequest) returns (StateResponse);
// These are IO helpers for streaming
rpc Read(vagrant.io.ReadRequest) returns (vagrant.io.ReadResponse);
rpc Write(vagrant.io.WriteRequest) returns (vagrant.io.WriteResponse);
// These are Config helpers
rpc ConfigAttributes(vagrant.common.NullRequest) returns (vagrant.config.AttributesResponse);
rpc ConfigLoad(vagrant.config.LoadRequest) returns (vagrant.config.LoadResponse);
rpc ConfigValidate(vagrant.config.ValidateRequest) returns (vagrant.config.ValidateResponse);
rpc ConfigFinalize(vagrant.config.FinalizeRequest) returns (vagrant.config.FinalizeResponse);
// Capabilities
rpc GuestCapabilities(vagrant.common.NullRequest) returns (vagrant.caps.CapabilitiesResponse);
rpc GuestCapability(vagrant.caps.GuestCapabilityRequest) returns (vagrant.caps.GuestCapabilityResponse);
rpc HostCapabilities(vagrant.common.NullRequest) returns (vagrant.caps.CapabilitiesResponse);
rpc HostCapability(vagrant.caps.HostCapabilityRequest) returns (vagrant.caps.HostCapabilityResponse);
rpc ProviderCapabilities(vagrant.common.NullRequest) returns (vagrant.caps.ProviderCapabilitiesResponse);
rpc ProviderCapability(vagrant.caps.ProviderCapabilityRequest) returns (vagrant.caps.ProviderCapabilityResponse);
}

View File

@ -0,0 +1,363 @@
package plugin
import (
"context"
"errors"
"google.golang.org/grpc"
go_plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_provider"
)
type Provider interface {
vagrant.Provider
Meta
}
type ProviderPlugin struct {
go_plugin.NetRPCUnsupportedPlugin
Impl Provider
}
type GRPCProviderClient struct {
GRPCCoreClient
GRPCConfigClient
GRPCGuestCapabilitiesClient
GRPCHostCapabilitiesClient
GRPCProviderCapabilitiesClient
GRPCIOClient
client vagrant_provider.ProviderClient
}
func (c *GRPCProviderClient) Action(actionName string, m *vagrant.Machine) (r []string, err error) {
machData, err := vagrant.DumpMachine(m)
if err != nil {
return
}
resp, err := c.client.Action(context.Background(), &vagrant_provider.ActionRequest{
Name: actionName,
Machine: machData})
if err != nil {
return
}
r = resp.Result
if resp.Error != "" {
err = errors.New(resp.Error)
}
return
}
func (c *GRPCProviderClient) Info() *vagrant.ProviderInfo {
resp, err := c.client.Info(context.Background(), &vagrant_common.NullRequest{})
if err != nil {
return &vagrant.ProviderInfo{}
}
return &vagrant.ProviderInfo{
Description: resp.Description,
Priority: resp.Priority}
}
func (c *GRPCProviderClient) IsInstalled(m *vagrant.Machine) (r bool, err error) {
machData, err := vagrant.DumpMachine(m)
if err != nil {
return
}
resp, err := c.client.IsInstalled(context.Background(), &vagrant_common.EmptyRequest{
Machine: machData})
if err != nil {
return
}
r = resp.Result
if resp.Error != "" {
err = errors.New(resp.Error)
}
return
}
func (c *GRPCProviderClient) IsUsable(m *vagrant.Machine) (r bool, err error) {
machData, err := vagrant.DumpMachine(m)
if err != nil {
return
}
resp, err := c.client.IsUsable(context.Background(), &vagrant_common.EmptyRequest{
Machine: machData})
if err != nil {
return
}
r = resp.Result
if resp.Error != "" {
err = errors.New(resp.Error)
}
return
}
func (c *GRPCProviderClient) MachineIdChanged(m *vagrant.Machine) (err error) {
machData, err := vagrant.DumpMachine(m)
if err != nil {
return
}
resp, err := c.client.MachineIdChanged(context.Background(), &vagrant_common.EmptyRequest{
Machine: machData})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
}
return
}
func (c *GRPCProviderClient) RunAction(actName string, runData string, m *vagrant.Machine) (r string, err error) {
machData, err := vagrant.DumpMachine(m)
if err != nil {
return
}
resp, err := c.client.RunAction(context.Background(), &vagrant_provider.RunActionRequest{
Name: actName,
Data: runData,
Machine: machData})
if err != nil {
return
}
r = resp.Data
if resp.Error != "" {
err = errors.New(resp.Error)
}
return
}
func (c *GRPCProviderClient) SshInfo(m *vagrant.Machine) (r *vagrant.SshInfo, err error) {
machData, err := vagrant.DumpMachine(m)
if err != nil {
return
}
resp, err := c.client.SshInfo(context.Background(), &vagrant_common.EmptyRequest{
Machine: machData})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
}
r = &vagrant.SshInfo{
Host: resp.Host,
Port: resp.Port,
PrivateKeyPath: resp.PrivateKeyPath,
Username: resp.Username}
return
}
func (c *GRPCProviderClient) State(m *vagrant.Machine) (r *vagrant.MachineState, err error) {
machData, err := vagrant.DumpMachine(m)
if err != nil {
return
}
resp, err := c.client.State(context.Background(), &vagrant_common.EmptyRequest{
Machine: machData})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
}
r = &vagrant.MachineState{
Id: resp.Id,
ShortDesc: resp.ShortDescription,
LongDesc: resp.LongDescription}
return
}
func (c *GRPCProviderClient) Name() string {
resp, err := c.client.Name(context.Background(), &vagrant_common.NullRequest{})
if err != nil {
return ""
}
return resp.Name
}
func (p *ProviderPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error {
return nil
}
func (p *ProviderPlugin) GRPCClient(ctx context.Context, broker *go_plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
client := vagrant_provider.NewProviderClient(c)
return &GRPCProviderClient{
GRPCConfigClient: GRPCConfigClient{
client: client},
GRPCGuestCapabilitiesClient: GRPCGuestCapabilitiesClient{
client: client},
GRPCHostCapabilitiesClient: GRPCHostCapabilitiesClient{
client: client},
GRPCProviderCapabilitiesClient: GRPCProviderCapabilitiesClient{
client: client},
GRPCIOClient: GRPCIOClient{
client: client},
client: client,
}, nil
}
type GRPCProviderPlugin struct {
ProviderPlugin
Impl Provider
}
func (p *GRPCProviderPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error {
p.Impl.Init()
vagrant_provider.RegisterProviderServer(s, &GRPCProviderServer{
Impl: p.Impl,
GRPCConfigServer: GRPCConfigServer{
Impl: p.Impl},
GRPCGuestCapabilitiesServer: GRPCGuestCapabilitiesServer{
Impl: p.Impl},
GRPCHostCapabilitiesServer: GRPCHostCapabilitiesServer{
Impl: p.Impl},
GRPCProviderCapabilitiesServer: GRPCProviderCapabilitiesServer{
Impl: p.Impl},
GRPCIOServer: GRPCIOServer{
Impl: p.Impl}})
return nil
}
func (p *GRPCProviderPlugin) GRPCClient(context.Context, *go_plugin.GRPCBroker, *grpc.ClientConn) (interface{}, error) {
return nil, nil
}
type GRPCProviderServer struct {
GRPCIOServer
GRPCConfigServer
GRPCGuestCapabilitiesServer
GRPCHostCapabilitiesServer
GRPCProviderCapabilitiesServer
Impl Provider
}
func (s *GRPCProviderServer) Action(ctx context.Context, req *vagrant_provider.ActionRequest) (resp *vagrant_provider.ActionResponse, err error) {
resp = &vagrant_provider.ActionResponse{}
m, e := vagrant.LoadMachine(req.Machine, s.Impl)
if e != nil {
resp.Error = e.Error()
return
}
r, e := s.Impl.Action(req.Name, m)
if e != nil {
resp.Error = e.Error()
return
}
resp.Result = r
return
}
func (s *GRPCProviderServer) RunAction(ctx context.Context, req *vagrant_provider.RunActionRequest) (resp *vagrant_provider.RunActionResponse, err error) {
resp = &vagrant_provider.RunActionResponse{}
m, e := vagrant.LoadMachine(req.Machine, s.Impl)
if e != nil {
resp.Error = e.Error()
return
}
r, e := s.Impl.RunAction(req.Name, req.Data, m)
if e != nil {
resp.Error = e.Error()
return
}
resp.Data = r
return
}
func (s *GRPCProviderServer) Info(ctx context.Context, req *vagrant_common.NullRequest) (*vagrant_provider.InfoResponse, error) {
r := s.Impl.Info()
return &vagrant_provider.InfoResponse{
Description: r.Description,
Priority: r.Priority}, nil
}
func (s *GRPCProviderServer) IsInstalled(ctx context.Context, req *vagrant_common.EmptyRequest) (resp *vagrant_common.IsResponse, err error) {
resp = &vagrant_common.IsResponse{}
m, e := vagrant.LoadMachine(req.Machine, s.Impl)
if e != nil {
resp.Error = e.Error()
return
}
r, e := s.Impl.IsInstalled(m)
if e != nil {
resp.Error = e.Error()
return
}
resp.Result = r
return
}
func (s *GRPCProviderServer) IsUsable(ctx context.Context, req *vagrant_common.EmptyRequest) (resp *vagrant_common.IsResponse, err error) {
resp = &vagrant_common.IsResponse{}
m, e := vagrant.LoadMachine(req.Machine, s.Impl)
if e != nil {
resp.Error = e.Error()
return
}
r, e := s.Impl.IsUsable(m)
if e != nil {
resp.Error = e.Error()
return
}
resp.Result = r
return
}
func (s *GRPCProviderServer) SshInfo(ctx context.Context, req *vagrant_common.EmptyRequest) (resp *vagrant_provider.SshInfoResponse, err error) {
resp = &vagrant_provider.SshInfoResponse{}
m, e := vagrant.LoadMachine(req.Machine, s.Impl)
if e != nil {
resp.Error = e.Error()
return
}
r, e := s.Impl.SshInfo(m)
if e != nil {
resp.Error = e.Error()
return
}
resp = &vagrant_provider.SshInfoResponse{
Host: r.Host,
Port: r.Port,
Username: r.Username,
PrivateKeyPath: r.PrivateKeyPath}
return
}
func (s *GRPCProviderServer) State(ctx context.Context, req *vagrant_common.EmptyRequest) (resp *vagrant_provider.StateResponse, err error) {
resp = &vagrant_provider.StateResponse{}
m, e := vagrant.LoadMachine(req.Machine, s.Impl)
if e != nil {
resp.Error = e.Error()
return
}
r, e := s.Impl.State(m)
if e != nil {
resp.Error = e.Error()
return
}
resp = &vagrant_provider.StateResponse{
Id: r.Id,
ShortDescription: r.ShortDesc,
LongDescription: r.LongDesc}
return
}
func (s *GRPCProviderServer) MachineIdChanged(ctx context.Context, req *vagrant_common.EmptyRequest) (resp *vagrant_common.EmptyResponse, err error) {
resp = &vagrant_common.EmptyResponse{}
m, e := vagrant.LoadMachine(req.Machine, s.Impl)
if e != nil {
resp.Error = e.Error()
return
}
e = s.Impl.MachineIdChanged(m)
if e != nil {
resp.Error = e.Error()
}
return
}
func (s *GRPCProviderServer) Name(ctx context.Context, req *vagrant_common.NullRequest) (*vagrant_common.NameResponse, error) {
return &vagrant_common.NameResponse{Name: s.Impl.Name()}, nil
}

View File

@ -0,0 +1,291 @@
package plugin
import (
"context"
"encoding/json"
"errors"
"google.golang.org/grpc"
go_plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_common"
"github.com/hashicorp/vagrant/ext/go-plugin/vagrant/plugin/proto/vagrant_folder"
)
type SyncedFolder interface {
vagrant.SyncedFolder
Meta
}
type SyncedFolderPlugin struct {
go_plugin.NetRPCUnsupportedPlugin
Impl SyncedFolder
}
type GRPCSyncedFolderClient struct {
GRPCCoreClient
GRPCGuestCapabilitiesClient
GRPCHostCapabilitiesClient
GRPCIOClient
client vagrant_folder.SyncedFolderClient
}
func (c *GRPCSyncedFolderClient) Cleanup(m *vagrant.Machine, o *vagrant.FolderOptions) (err error) {
machine, err := vagrant.DumpMachine(m)
if err != nil {
return
}
opts, err := json.Marshal(o)
if err != nil {
return
}
resp, err := c.client.Cleanup(context.Background(), &vagrant_folder.CleanupRequest{
Machine: machine,
Options: string(opts)})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
}
return
}
func (c *GRPCSyncedFolderClient) Disable(m *vagrant.Machine, f *vagrant.FolderList, o *vagrant.FolderOptions) (err error) {
machine, err := vagrant.DumpMachine(m)
if err != nil {
return
}
folders, err := json.Marshal(f)
if err != nil {
return
}
opts, err := json.Marshal(o)
if err != nil {
return
}
resp, err := c.client.Disable(context.Background(), &vagrant_folder.Request{
Machine: machine,
Folders: string(folders),
Options: string(opts)})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
}
return
}
func (c *GRPCSyncedFolderClient) Enable(m *vagrant.Machine, f *vagrant.FolderList, o *vagrant.FolderOptions) (err error) {
machine, err := vagrant.DumpMachine(m)
if err != nil {
return
}
folders, err := json.Marshal(f)
if err != nil {
return
}
opts, err := json.Marshal(o)
if err != nil {
return
}
resp, err := c.client.Enable(context.Background(), &vagrant_folder.Request{
Machine: machine,
Folders: string(folders),
Options: string(opts)})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
}
return
}
func (c *GRPCSyncedFolderClient) Info() *vagrant.SyncedFolderInfo {
resp, err := c.client.Info(context.Background(), &vagrant_common.NullRequest{})
if err != nil {
return &vagrant.SyncedFolderInfo{}
}
return &vagrant.SyncedFolderInfo{
Description: resp.Description,
Priority: resp.Priority}
}
func (c *GRPCSyncedFolderClient) IsUsable(m *vagrant.Machine) (u bool, err error) {
machine, err := vagrant.DumpMachine(m)
if err != nil {
return
}
resp, err := c.client.IsUsable(context.Background(), &vagrant_common.EmptyRequest{
Machine: machine})
u = resp.Result
if resp.Error != "" {
err = errors.New(resp.Error)
}
return
}
func (c *GRPCSyncedFolderClient) Name() string {
resp, err := c.client.Name(context.Background(), &vagrant_common.NullRequest{})
if err != nil {
return ""
}
return resp.Name
}
func (c *GRPCSyncedFolderClient) Prepare(m *vagrant.Machine, f *vagrant.FolderList, o *vagrant.FolderOptions) (err error) {
machine, err := vagrant.DumpMachine(m)
if err != nil {
return
}
folders, err := json.Marshal(f)
if err != nil {
return
}
opts, err := json.Marshal(o)
if err != nil {
return
}
resp, err := c.client.Prepare(context.Background(), &vagrant_folder.Request{
Machine: machine,
Folders: string(folders),
Options: string(opts)})
if err != nil {
return
}
if resp.Error != "" {
err = errors.New(resp.Error)
}
return
}
type GRPCSyncedFolderServer struct {
GRPCGuestCapabilitiesServer
GRPCHostCapabilitiesServer
GRPCIOServer
Impl SyncedFolder
}
func (s *GRPCSyncedFolderServer) Cleanup(ctx context.Context, req *vagrant_folder.CleanupRequest) (resp *vagrant_common.EmptyResponse, err error) {
resp = &vagrant_common.EmptyResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil)
if err != nil {
return
}
var options vagrant.FolderOptions
err = json.Unmarshal([]byte(req.Options), &options)
if err != nil {
return
}
e := s.Impl.Cleanup(machine, &options)
if e != nil {
resp.Error = e.Error()
}
return
}
func (s *GRPCSyncedFolderServer) Disable(ctx context.Context, req *vagrant_folder.Request) (resp *vagrant_common.EmptyResponse, err error) {
resp = &vagrant_common.EmptyResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil)
if err != nil {
return
}
var folders vagrant.FolderList
err = json.Unmarshal([]byte(req.Folders), &folders)
if err != nil {
return
}
var options vagrant.FolderOptions
err = json.Unmarshal([]byte(req.Options), &options)
if err != nil {
return
}
e := s.Impl.Disable(machine, &folders, &options)
if e != nil {
resp.Error = e.Error()
}
return
}
func (s *GRPCSyncedFolderServer) Enable(ctx context.Context, req *vagrant_folder.Request) (resp *vagrant_common.EmptyResponse, err error) {
resp = &vagrant_common.EmptyResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil)
if err != nil {
return
}
var folders vagrant.FolderList
err = json.Unmarshal([]byte(req.Folders), &folders)
if err != nil {
return
}
var options vagrant.FolderOptions
err = json.Unmarshal([]byte(req.Options), &options)
if err != nil {
return
}
e := s.Impl.Enable(machine, &folders, &options)
if e != nil {
resp.Error = e.Error()
}
return
}
func (s *GRPCSyncedFolderServer) Info(ctx context.Context, req *vagrant_common.NullRequest) (*vagrant_folder.InfoResponse, error) {
r := s.Impl.Info()
return &vagrant_folder.InfoResponse{
Description: r.Description,
Priority: r.Priority}, nil
}
func (s *GRPCSyncedFolderServer) IsUsable(ctx context.Context, req *vagrant_common.EmptyRequest) (resp *vagrant_common.IsResponse, err error) {
resp = &vagrant_common.IsResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil)
if err != nil {
return
}
r, e := s.Impl.IsUsable(machine)
if e != nil {
resp.Error = e.Error()
}
resp.Result = r
return
}
func (s *GRPCSyncedFolderServer) Name(ctx context.Context, req *vagrant_common.NullRequest) (*vagrant_common.NameResponse, error) {
return &vagrant_common.NameResponse{Name: s.Impl.Name()}, nil
}
func (s *GRPCSyncedFolderServer) Prepare(ctx context.Context, req *vagrant_folder.Request) (resp *vagrant_common.EmptyResponse, err error) {
resp = &vagrant_common.EmptyResponse{}
machine, err := vagrant.LoadMachine(req.Machine, nil)
if err != nil {
return
}
var folders vagrant.FolderList
err = json.Unmarshal([]byte(req.Folders), &folders)
if err != nil {
return
}
var options vagrant.FolderOptions
err = json.Unmarshal([]byte(req.Options), &options)
if err != nil {
return
}
e := s.Impl.Prepare(machine, &folders, &options)
if e != nil {
resp.Error = e.Error()
}
return
}
func (f *SyncedFolderPlugin) GRPCServer(broker *go_plugin.GRPCBroker, s *grpc.Server) error {
vagrant_folder.RegisterSyncedFolderServer(s, &GRPCSyncedFolderServer{Impl: f.Impl})
return nil
}
func (f *SyncedFolderPlugin) GRPCClient(ctx context.Context, broker *go_plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
return &GRPCSyncedFolderClient{client: vagrant_folder.NewSyncedFolderClient(c)}, nil
}

View File

@ -0,0 +1,23 @@
package vagrant
type Provider interface {
Info() *ProviderInfo
Action(actionName string, machData *Machine) ([]string, error)
IsInstalled(machData *Machine) (bool, error)
IsUsable(machData *Machine) (bool, error)
MachineIdChanged(machData *Machine) error
Name() string
RunAction(actionName string, data string, machData *Machine) (string, error)
SshInfo(machData *Machine) (*SshInfo, error)
State(machData *Machine) (*MachineState, error)
Config
GuestCapabilities
HostCapabilities
ProviderCapabilities
}
type ProviderInfo struct {
Description string `json:"description"`
Priority int64 `json:"priority"`
}

View File

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

View File

@ -0,0 +1,8 @@
package vagrant
type SshInfo struct {
Host string `json:"host"`
Port int64 `json:"port"`
Username string `json:"username"`
PrivateKeyPath string `json:"private_key_path"`
}

View File

@ -0,0 +1,22 @@
package vagrant
type FolderList map[string]interface{}
type FolderOptions map[string]interface{}
type SyncedFolderInfo struct {
Description string `json:"description"`
Priority int64 `json:"priority"`
}
type SyncedFolder interface {
Cleanup(m *Machine, opts *FolderOptions) error
Disable(m *Machine, f *FolderList, opts *FolderOptions) error
Enable(m *Machine, f *FolderList, opts *FolderOptions) error
Info() *SyncedFolderInfo
IsUsable(m *Machine) (bool, error)
Name() string
Prepare(m *Machine, f *FolderList, opts *FolderOptions) error
GuestCapabilities
HostCapabilities
}

472
ext/go-plugin/vagrant/ui.go Normal file
View File

@ -0,0 +1,472 @@
package vagrant
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"os"
"os/signal"
"runtime"
"strings"
"sync"
"syscall"
"time"
"unicode"
)
type UiColor uint
const (
UiColorRed UiColor = 31
UiColorGreen = 32
UiColorYellow = 33
UiColorBlue = 34
UiColorMagenta = 35
UiColorCyan = 36
)
type UiChannel uint
const (
UiOutput UiChannel = 1
UiError = 2
)
var logger = DefaultLogger().Named("ui")
type Options struct {
Channel UiChannel
NewLine bool
}
var defaultOptions = &Options{
Channel: UiOutput,
NewLine: true,
}
// The Ui interface handles all communication for Vagrant with the outside
// world. This sort of control allows us to strictly control how output
// is formatted and various levels of output.
type Ui interface {
Ask(string) (string, error)
Detail(string)
Info(string)
Error(string)
Machine(string, ...string)
Message(string, *Options)
Output(string)
Say(string)
Success(string)
Warn(string)
}
// The BasicUI is a UI that reads and writes from a standard Go reader
// and writer. It is safe to be called from multiple goroutines. Machine
// readable output is simply logged for this UI.
type BasicUi struct {
Reader io.Reader
Writer io.Writer
ErrorWriter io.Writer
l sync.Mutex
interrupted bool
scanner *bufio.Scanner
}
var _ Ui = new(BasicUi)
func (rw *BasicUi) Ask(query string) (string, error) {
rw.l.Lock()
defer rw.l.Unlock()
if rw.interrupted {
return "", errors.New("interrupted")
}
if rw.scanner == nil {
rw.scanner = bufio.NewScanner(rw.Reader)
}
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
defer signal.Stop(sigCh)
logger.Info("ask", query)
if query != "" {
if _, err := fmt.Fprint(rw.Writer, query+" "); err != nil {
return "", err
}
}
result := make(chan string, 1)
go func() {
var line string
if rw.scanner.Scan() {
line = rw.scanner.Text()
}
if err := rw.scanner.Err(); err != nil {
logger.Error("scan failure", "error", err)
return
}
result <- line
}()
select {
case line := <-result:
return line, nil
case <-sigCh:
// Print a newline so that any further output starts properly
// on a new line.
fmt.Fprintln(rw.Writer)
// Mark that we were interrupted so future Ask calls fail.
rw.interrupted = true
return "", errors.New("interrupted")
}
}
func (rw *BasicUi) Detail(message string) { rw.Say(message) }
func (rw *BasicUi) Info(message string) { rw.Say(message) }
func (rw *BasicUi) Output(message string) { rw.Say(message) }
func (rw *BasicUi) Success(message string) { rw.Say(message) }
func (rw *BasicUi) Warn(message string) { rw.Say(message) }
func (rw *BasicUi) Say(message string) {
rw.Message(message, nil)
}
func (rw *BasicUi) Message(message string, opts *Options) {
rw.l.Lock()
defer rw.l.Unlock()
if opts == nil {
opts = &Options{Channel: UiOutput, NewLine: true}
}
logger.Debug("write message", "content", message, "options", opts)
target := rw.Writer
if opts.Channel == UiError {
if rw.ErrorWriter == nil {
logger.Error("error writer unset using writer")
} else {
target = rw.ErrorWriter
}
}
suffix := ""
if opts.NewLine {
suffix = "\n"
}
_, err := fmt.Fprint(target, message+suffix)
if err != nil {
logger.Error("write failure", "error", err)
}
}
func (rw *BasicUi) Error(message string) {
rw.Message(message, &Options{Channel: UiError, NewLine: true})
}
func (rw *BasicUi) Machine(t string, args ...string) {
logger.Info("machine readable", "category", t, "args", args)
}
// MachineReadableUi is a UI that only outputs machine-readable output
// to the given Writer.
type MachineReadableUi struct {
Writer io.Writer
}
var _ Ui = new(MachineReadableUi)
func (u *MachineReadableUi) Ask(query string) (string, error) {
return "", errors.New("machine-readable UI can't ask")
}
func (u *MachineReadableUi) Detail(message string) {
u.Machine("ui", "detail", message)
}
func (u *MachineReadableUi) Info(message string) {
u.Machine("ui", "info", message)
}
func (u *MachineReadableUi) Output(message string) {
u.Machine("ui", "output", message)
}
func (u *MachineReadableUi) Success(message string) {
u.Machine("ui", "success", message)
}
func (u *MachineReadableUi) Warn(message string) {
u.Machine("ui", "warn", message)
}
func (u *MachineReadableUi) Say(message string) {
u.Machine("ui", "say", message)
}
func (u *MachineReadableUi) Message(message string, opts *Options) {
u.Machine("ui", "message", message)
}
func (u *MachineReadableUi) Error(message string) {
u.Machine("ui", "error", message)
}
// TODO: Do we want to update this to match Vagrant machine style?
func (u *MachineReadableUi) Machine(category string, args ...string) {
now := time.Now().UTC()
// Determine if we have a target, and set it
target := ""
commaIdx := strings.Index(category, ",")
if commaIdx > -1 {
target = category[0:commaIdx]
category = category[commaIdx+1:]
}
// Prepare the args
for i, v := range args {
args[i] = strings.Replace(v, ",", "%!(VAGRANT_COMMA)", -1)
args[i] = strings.Replace(args[i], "\r", "\\r", -1)
args[i] = strings.Replace(args[i], "\n", "\\n", -1)
}
argsString := strings.Join(args, ",")
_, err := fmt.Fprintf(u.Writer, "%d,%s,%s,%s\n", now.Unix(), target, category, argsString)
if err != nil {
if err == syscall.EPIPE || strings.Contains(err.Error(), "broken pipe") {
// Ignore epipe errors because that just means that the file
// is probably closed or going to /dev/null or something.
} else {
panic(err)
}
}
}
type NoopUi struct{}
var _ Ui = new(NoopUi)
func (*NoopUi) Ask(string) (string, error) { return "", errors.New("this is a noop ui") }
func (*NoopUi) Detail(string) { return }
func (*NoopUi) Info(string) { return }
func (*NoopUi) Error(string) { return }
func (*NoopUi) Machine(string, ...string) { return }
func (*NoopUi) Message(string, *Options) { return }
func (*NoopUi) Output(string) { return }
func (*NoopUi) Say(string) { return }
func (*NoopUi) Success(string) { return }
func (*NoopUi) Warn(string) { return }
// ColoredUi is a UI that is colored using terminal colors.
type ColoredUi struct {
Color UiColor
ErrorColor UiColor
SuccessColor UiColor
WarnColor UiColor
Ui Ui
}
var _ Ui = new(ColoredUi)
func (u *ColoredUi) Ask(query string) (string, error) {
return u.Ui.Ask(u.colorize(query, u.Color, true))
}
func (u *ColoredUi) Detail(message string) {
u.Say(message)
}
func (u *ColoredUi) Info(message string) {
u.Say(message)
}
func (u *ColoredUi) Error(message string) {
color := u.ErrorColor
if color == 0 {
color = UiColorRed
}
u.Ui.Error(u.colorize(message, color, true))
}
func (u *ColoredUi) Machine(t string, args ...string) {
// Don't colorize machine-readable output
u.Ui.Machine(t, args...)
}
func (u *ColoredUi) Message(message string, opts *Options) {
u.Ui.Message(u.colorize(message, u.Color, false), opts)
}
func (u *ColoredUi) Output(message string) {
u.Say(message)
}
func (u *ColoredUi) Say(message string) {
u.Ui.Say(u.colorize(message, u.Color, true))
}
func (u *ColoredUi) Success(message string) {
u.Ui.Say(u.colorize(message, u.SuccessColor, true))
}
func (u *ColoredUi) Warn(message string) {
u.Ui.Say(u.colorize(message, u.WarnColor, true))
}
func (u *ColoredUi) colorize(message string, color UiColor, bold bool) string {
if !u.supportsColors() {
return message
}
attr := 0
if bold {
attr = 1
}
return fmt.Sprintf("\033[%d;%dm%s\033[0m", attr, color, message)
}
func (u *ColoredUi) supportsColors() bool {
// Never use colors if we have this environmental variable
if os.Getenv("VAGRANT_NO_COLOR") != "" {
return false
}
// For now, on non-Windows machine, just assume it does
if runtime.GOOS != "windows" {
return true
}
// On Windows, if we appear to be in Cygwin, then it does
cygwin := os.Getenv("CYGWIN") != "" ||
os.Getenv("OSTYPE") == "cygwin" ||
os.Getenv("TERM") == "cygwin"
return cygwin
}
// TargetedUi is a UI that wraps another UI implementation and modifies
// the output to indicate a specific target. Specifically, all Say output
// is prefixed with the target name. Message output is not prefixed but
// is offset by the length of the target so that output is lined up properly
// with Say output. Machine-readable output has the proper target set.
type TargetedUi struct {
Target string
Ui Ui
}
var _ Ui = new(TargetedUi)
func (u *TargetedUi) Ask(query string) (string, error) {
return u.Ui.Ask(u.prefixLines(true, query))
}
func (u *TargetedUi) Detail(message string) {
u.Ui.Detail(u.prefixLines(true, message))
}
func (u *TargetedUi) Info(message string) {
u.Ui.Info(u.prefixLines(true, message))
}
func (u *TargetedUi) Output(message string) {
u.Ui.Output(u.prefixLines(true, message))
}
func (u *TargetedUi) Success(message string) {
u.Ui.Success(u.prefixLines(true, message))
}
func (u *TargetedUi) Warn(message string) {
u.Ui.Warn(u.prefixLines(true, message))
}
func (u *TargetedUi) Say(message string) {
u.Ui.Say(u.prefixLines(true, message))
}
func (u *TargetedUi) Message(message string, opts *Options) {
u.Ui.Message(u.prefixLines(false, message), opts)
}
func (u *TargetedUi) Error(message string) {
u.Ui.Error(u.prefixLines(true, message))
}
func (u *TargetedUi) Machine(t string, args ...string) {
// Prefix in the target, then pass through
u.Ui.Machine(fmt.Sprintf("%s,%s", u.Target, t), args...)
}
func (u *TargetedUi) prefixLines(arrow bool, message string) string {
arrowText := "==>"
if !arrow {
arrowText = strings.Repeat(" ", len(arrowText))
}
var result bytes.Buffer
for _, line := range strings.Split(message, "\n") {
result.WriteString(fmt.Sprintf("%s %s: %s\n", arrowText, u.Target, line))
}
return strings.TrimRightFunc(result.String(), unicode.IsSpace)
}
// TimestampedUi is a UI that wraps another UI implementation and prefixes
// prefixes each message with an RFC3339 timestamp
type TimestampedUi struct {
Ui Ui
}
var _ Ui = new(TimestampedUi)
func (u *TimestampedUi) Ask(query string) (string, error) {
return u.Ui.Ask(query)
}
func (u *TimestampedUi) Detail(message string) {
u.Ui.Detail(u.timestampLine(message))
}
func (u *TimestampedUi) Info(message string) {
u.Ui.Info(u.timestampLine(message))
}
func (u *TimestampedUi) Output(message string) {
u.Ui.Output(u.timestampLine(message))
}
func (u *TimestampedUi) Success(message string) {
u.Ui.Success(u.timestampLine(message))
}
func (u *TimestampedUi) Warn(message string) {
u.Ui.Warn(u.timestampLine(message))
}
func (u *TimestampedUi) Say(message string) {
u.Ui.Say(u.timestampLine(message))
}
func (u *TimestampedUi) Message(message string, opts *Options) {
u.Ui.Message(u.timestampLine(message), opts)
}
func (u *TimestampedUi) Error(message string) {
u.Ui.Error(u.timestampLine(message))
}
func (u *TimestampedUi) Machine(message string, args ...string) {
u.Ui.Machine(message, args...)
}
func (u *TimestampedUi) timestampLine(string string) string {
return fmt.Sprintf("%v: %v", time.Now().Format(time.RFC3339), string)
}

View File

@ -0,0 +1,290 @@
package vagrant
import (
"bytes"
"os"
"strings"
"testing"
)
// This reads the output from the bytes.Buffer in our test object
// and then resets the buffer.
func readWriter(ui *BasicUi) (result string) {
buffer := ui.Writer.(*bytes.Buffer)
result = buffer.String()
buffer.Reset()
return
}
// Reset the input Reader then add some input to it.
func writeReader(ui *BasicUi, input string) {
buffer := ui.Reader.(*bytes.Buffer)
buffer.WriteString(input)
}
func readErrorWriter(ui *BasicUi) (result string) {
buffer := ui.ErrorWriter.(*bytes.Buffer)
result = buffer.String()
buffer.Reset()
return
}
func testUi() *BasicUi {
return &BasicUi{
Reader: new(bytes.Buffer),
Writer: new(bytes.Buffer),
ErrorWriter: new(bytes.Buffer),
}
}
func TestColoredUi(t *testing.T) {
bufferUi := testUi()
ui := &ColoredUi{UiColorBlue, UiColorRed, UiColorGreen,
UiColorYellow, bufferUi}
if !ui.supportsColors() {
t.Skip("skipping for ui without color support")
}
ui.Say("foo")
result := readWriter(bufferUi)
if result != "\033[1;34mfoo\033[0m\n" {
t.Fatalf("invalid output: %s", result)
}
ui.Message("foo", nil)
result = readWriter(bufferUi)
if result != "\033[0;34mfoo\033[0m\n" {
t.Fatalf("invalid output: %s", result)
}
ui.Error("foo")
result = readWriter(bufferUi)
if result != "" {
t.Fatalf("invalid output: %s", result)
}
result = readErrorWriter(bufferUi)
if result != "\033[1;31mfoo\033[0m\n" {
t.Fatalf("invalid output: %s", result)
}
}
func TestColoredUi_noColorEnv(t *testing.T) {
bufferUi := testUi()
ui := &ColoredUi{UiColorBlue, UiColorRed, UiColorGreen,
UiColorYellow, bufferUi}
// Set the env var to get rid of the color
oldenv := os.Getenv("VAGRANT_NO_COLOR")
os.Setenv("VAGRANT_NO_COLOR", "1")
defer os.Setenv("VAGRANT_NO_COLOR", oldenv)
ui.Say("foo")
result := readWriter(bufferUi)
if result != "foo\n" {
t.Fatalf("invalid output: %s", result)
}
ui.Message("foo", nil)
result = readWriter(bufferUi)
if result != "foo\n" {
t.Fatalf("invalid output: %s", result)
}
ui.Error("foo")
result = readErrorWriter(bufferUi)
if result != "foo\n" {
t.Fatalf("invalid output: %s", result)
}
}
func TestTargetedUi(t *testing.T) {
bufferUi := testUi()
targetedUi := &TargetedUi{
Target: "foo",
Ui: bufferUi,
}
var actual, expected string
targetedUi.Say("foo")
actual = readWriter(bufferUi)
expected = "==> foo: foo\n"
if actual != expected {
t.Fatalf("bad: %#v", actual)
}
targetedUi.Message("foo", nil)
actual = readWriter(bufferUi)
expected = " foo: foo\n"
if actual != expected {
t.Fatalf("bad: %#v", actual)
}
targetedUi.Error("bar")
actual = readErrorWriter(bufferUi)
expected = "==> foo: bar\n"
if actual != expected {
t.Fatalf("bad: %#v", actual)
}
targetedUi.Say("foo\nbar")
actual = readWriter(bufferUi)
expected = "==> foo: foo\n==> foo: bar\n"
if actual != expected {
t.Fatalf("bad: %#v", actual)
}
}
func TestColoredUi_ImplUi(t *testing.T) {
var raw interface{}
raw = &ColoredUi{}
if _, ok := raw.(Ui); !ok {
t.Fatalf("ColoredUi must implement Ui")
}
}
func TestTargetedUi_ImplUi(t *testing.T) {
var raw interface{}
raw = &TargetedUi{}
if _, ok := raw.(Ui); !ok {
t.Fatalf("TargetedUi must implement Ui")
}
}
func TestBasicUi_ImplUi(t *testing.T) {
var raw interface{}
raw = &BasicUi{}
if _, ok := raw.(Ui); !ok {
t.Fatalf("BasicUi must implement Ui")
}
}
func TestBasicUi_Error(t *testing.T) {
bufferUi := testUi()
var actual, expected string
bufferUi.Error("foo")
actual = readErrorWriter(bufferUi)
expected = "foo\n"
if actual != expected {
t.Fatalf("bad: %#v", actual)
}
bufferUi.ErrorWriter = nil
bufferUi.Error("5")
actual = readWriter(bufferUi)
expected = "5\n"
if actual != expected {
t.Fatalf("bad: %#v", actual)
}
}
func TestBasicUi_Say(t *testing.T) {
bufferUi := testUi()
var actual, expected string
bufferUi.Say("foo")
actual = readWriter(bufferUi)
expected = "foo\n"
if actual != expected {
t.Fatalf("bad: %#v", actual)
}
bufferUi.Say("5")
actual = readWriter(bufferUi)
expected = "5\n"
if actual != expected {
t.Fatalf("bad: %#v", actual)
}
}
func TestBasicUi_Ask(t *testing.T) {
var actual, expected string
var err error
var testCases = []struct {
Prompt, Input, Answer string
}{
{"[c]ontinue or [a]bort", "c\n", "c"},
{"[c]ontinue or [a]bort", "c", "c"},
// Empty input shouldn't give an error
{"Name", "Joe Bloggs\n", "Joe Bloggs"},
{"Name", "Joe Bloggs", "Joe Bloggs"},
{"Name", "\n", ""},
}
for _, testCase := range testCases {
// Because of the internal bufio we can't easily reset the input, so create a new one each time
bufferUi := testUi()
writeReader(bufferUi, testCase.Input)
actual, err = bufferUi.Ask(testCase.Prompt)
if err != nil {
t.Fatal(err)
}
if actual != testCase.Answer {
t.Fatalf("bad answer: %#v", actual)
}
actual = readWriter(bufferUi)
expected = testCase.Prompt + " "
if actual != expected {
t.Fatalf("bad prompt: %#v", actual)
}
}
}
func TestMachineReadableUi_ImplUi(t *testing.T) {
var raw interface{}
raw = &MachineReadableUi{}
if _, ok := raw.(Ui); !ok {
t.Fatalf("MachineReadableUi must implement Ui")
}
}
func TestMachineReadableUi(t *testing.T) {
var data, expected string
buf := new(bytes.Buffer)
ui := &MachineReadableUi{Writer: buf}
// No target
ui.Machine("foo", "bar", "baz")
data = strings.SplitN(buf.String(), ",", 2)[1]
expected = ",foo,bar,baz\n"
if data != expected {
t.Fatalf("bad: %s", data)
}
// Target
buf.Reset()
ui.Machine("mitchellh,foo", "bar", "baz")
data = strings.SplitN(buf.String(), ",", 2)[1]
expected = "mitchellh,foo,bar,baz\n"
if data != expected {
t.Fatalf("bad: %s", data)
}
// Commas
buf.Reset()
ui.Machine("foo", "foo,bar")
data = strings.SplitN(buf.String(), ",", 2)[1]
expected = ",foo,foo%!(VAGRANT_COMMA)bar\n"
if data != expected {
t.Fatalf("bad: %s", data)
}
// New lines
buf.Reset()
ui.Machine("foo", "foo\n")
data = strings.SplitN(buf.String(), ",", 2)[1]
expected = ",foo,foo\\n\n"
if data != expected {
t.Fatalf("bad: %#v", data)
}
}

View File

@ -1,4 +1,5 @@
require "log4r"
require "log4r/logger"
require "vagrant/util/credential_scrubber"
# Update the default formatter within the log4r library to ensure
# sensitive values are being properly scrubbed from logger data
@ -53,6 +54,8 @@ if ENV["VAGRANT_LOG"] && ENV["VAGRANT_LOG"] != ""
# rest-client to write using the `<<` operator.
# See https://github.com/rest-client/rest-client/issues/34#issuecomment-290858
# for more information
Log4r::PatternFormatter::DirectiveTable["l"] =
'"[" + ' + Log4r::PatternFormatter::DirectiveTable["l"] + ' + "]"'
class VagrantLogger < Log4r::Logger
def << (msg)
debug(msg.strip)
@ -61,13 +64,10 @@ if ENV["VAGRANT_LOG"] && ENV["VAGRANT_LOG"] != ""
logger = VagrantLogger.new("vagrant")
logger.outputters = Log4r::Outputter.stderr
logger.level = level
base_formatter = Log4r::BasicFormatter.new
if ENV["VAGRANT_LOG_TIMESTAMP"]
base_formatter = Log4r::PatternFormatter.new(
pattern: "%d [%5l] %m",
date_pattern: "%F %T"
)
end
base_formatter = Log4r::PatternFormatter.new(
pattern: "%d %-7l %C: %m",
date_pattern: ENV["VAGRANT_LOG_TIMESTAMP"] ? "%FT%T.%L%z" : " "
)
# Vagrant Cloud gem uses RestClient to make HTTP requests, so
# log them if debug is enabled and use Vagrants logger
require 'rest_client'
@ -118,6 +118,7 @@ module Vagrant
autoload :Driver, 'vagrant/driver'
autoload :Environment, 'vagrant/environment'
autoload :Errors, 'vagrant/errors'
autoload :GoPlugin, 'vagrant/go_plugin'
autoload :Guest, 'vagrant/guest'
autoload :Host, 'vagrant/host'
autoload :Machine, 'vagrant/machine'

View File

@ -7,6 +7,10 @@ module Vagrant
def method_missing(name, *args, &block)
DummyConfig.new
end
def to_json(*_)
"null"
end
end
end
end

View File

@ -112,6 +112,14 @@ module Vagrant
@keys = state["keys"] if state.key?("keys")
@missing_key_calls = state["missing_key_calls"] if state.key?("missing_key_calls")
end
def to_json(*args)
Hash[
@keys.find_all { |k,v|
!k.to_s.start_with?("_")
}
].to_json(*args)
end
end
end
end

View File

@ -175,6 +175,15 @@ module Vagrant
# Load any global plugins
Vagrant::Plugin::Manager.instance.load_plugins(plugins)
# Load any available go-plugins
Util::Experimental.guard_with(:go_plugin) do
begin
Vagrant::GoPlugin::Manager.instance.globalize!
rescue LoadError => err
@logger.warn("go plugin support is not available: #{err}")
end
end
plugins = process_configured_plugins
# Call the hooks that does not require configurations to be loaded

23
lib/vagrant/go_plugin.rb Normal file
View File

@ -0,0 +1,23 @@
module Vagrant
module GoPlugin
# @return [String]
INSTALL_DIRECTORY = Vagrant.user_data_path.join("go-plugins").to_s.freeze
autoload :CapabilityPlugin, "vagrant/go_plugin/capability_plugin"
autoload :ConfigPlugin, "vagrant/go_plugin/config_plugin"
autoload :Core, "vagrant/go_plugin/core"
autoload :Interface, "vagrant/go_plugin/interface"
autoload :Manager, "vagrant/go_plugin/manager"
autoload :ProviderPlugin, "vagrant/go_plugin/provider_plugin"
autoload :SyncedFolderPlugin, "vagrant/go_plugin/synced_folder_plugin"
# @return [Interface]
def self.interface
unless @_interface
@_interface = Interface.new
end
@_interface
end
end
end

View File

@ -0,0 +1,179 @@
require "vagrant/go_plugin/core"
module Vagrant
module GoPlugin
# Contains all capability functionality for go-plugin
module CapabilityPlugin
# Wrapper class for go-plugin defined capabilities
class Capability
extend TypedGoPlugin
end
# @return [Interface]
def self.interface
unless @_interface
@_interface = Interface.new
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])
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])
end
end
end
end
end
end

View File

@ -0,0 +1,133 @@
require "vagrant/go_plugin/core"
module Vagrant
module GoPlugin
# Contains all configuration functionality for go-plugin
module ConfigPlugin
# Config plugin class used with go-plugin
class Config < Vagrant.plugin("2", :config)
include TypedGoPlugin
def finalize!
data = local_data
result = ConfigPlugin.interface.finalize(plugin_name, plugin_type, data)
result.each do |key, value|
next if data[key] == value
instance_variable_set("@#{key}", value)
end
self
end
def validate(machine)
ConfigPlugin.interface.validate(plugin_name, plugin_type, local_data, machine)
end
# @return [Hash] currently defined instance variables
def local_data
data = Vagrant::Util::HashWithIndifferentAccess.
new(instance_variables_hash)
data.delete_if { |k,v|
k.start_with?("_")
}
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

@ -0,0 +1,198 @@
require "ffi"
module Vagrant
module GoPlugin
# Base module for generic setup of module/class
module Core
# Loads FFI and core helpers into given module/class
def self.included(const)
const.class_eval do
include Vagrant::Util::Logger
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
if FFI::Platform.windows?
attach_function :free, :_free, [:pointer], :void
else
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
#
# @param [Hash] data Machine data from go-plugin
# @param [Vagrant::Machine] machine
# @return [Vagrant::Machine]
def load_machine(data, machine)
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.
def load_result(*args)
val, ptr = block_given? ? yield : args
FFI::AutoPointer.new(ptr, self.method(:free))
begin
result = JSON.load(val)
if !result.is_a?(Hash)
raise TypeError.new "Expected Hash but received `#{result.class}`"
end
if !result["error"].to_s.empty?
raise ArgumentError.new result["error"].to_s
end
result = result["result"]
if result.is_a?(Hash)
result = Vagrant::Util::HashWithIndifferentAccess.new(result)
end
result
rescue => e
# TODO: Customize to provide formatted output on error
raise
end
end
end
end
end
module DirectGoPlugin
def self.included(klass)
klass.extend(ClassMethods)
klass.include(InstanceMethods)
end
module ClassMethods
# @return [String] plugin name associated to this class
def go_plugin_name
@go_plugin_name
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")
end
@go_plugin_name = n
end
# @return [String]
def name
go_plugin_name.to_s.capitalize.tr("_", "")
end
end
module InstanceMethods
def plugin_name
self.class.go_plugin_name
end
end
end
module TypedGoPlugin
def self.included(klass)
klass.extend(ClassMethods)
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
end
end
end
end

View File

@ -0,0 +1,72 @@
require "log4r"
require "vagrant/go_plugin/core"
module Vagrant
module GoPlugin
# Interface for go-plugin integration
class Interface
include Core
# go plugin functions
typedef :bool, :enable_logger
typedef :bool, :timestamps
typedef :string, :log_level
typedef :string, :plugin_directory
attach_function :_setup, :Setup, [:enable_logger, :timestamps, :log_level], :bool
attach_function :_teardown, :Teardown, [], :void
attach_function :_load_plugins, :LoadPlugins, [:plugin_directory], :bool
def initialize
setup
end
# Load any plugins found at the given directory
#
# @param [String, Pathname] path Directory to load
def load_plugins(path)
logger.debug("loading plugins from path: #{path}")
if !File.directory?(path.to_s)
raise ArgumentError, "Directory expected for plugin loading"
end
_load_plugins(path.to_s)
end
# Register all available plugins
def register_plugins
logger.debug("registering provider plugins")
ProviderPlugin.interface.load!
logger.debug("registering synced folder plugins")
SyncedFolderPlugin.interface.load!
end
# Load the plugins found at the given directory
#
# @param [String] plugin_directory Directory containing go-plugins
def setup
if !@setup
@setup = true
Kernel.at_exit { Vagrant::GoPlugin.interface.teardown }
logger.debug("running go-plugin interface setup")
_setup(!Vagrant.log_level.to_s.empty?,
!!ENV["VAGRANT_LOG_TIMESTAMP"],
Vagrant.log_level.to_s)
else
logger.warn("go-plugin interface already setup")
end
end
# Teardown any plugins that may be currently active
def teardown
logger.debug("starting teardown of go-plugin interface")
_teardown
logger.debug("teardown of go-plugin interface complete")
end
# @return [Boolean] go plugins have been setup
def configured?
!!@setup
end
end
end
end

View File

@ -0,0 +1,88 @@
require "zip"
require "vagrant/plugin/state_file"
module Vagrant
module GoPlugin
class Manager
include Util::Logger
# @return [Manager]
def self.instance(env=nil)
@instance ||= self.new
if env
@instance.envirnoment = env
end
@instance
end
# @return [StateFile] user defined plugins
attr_reader :user_file
# @return [StateFile, nil] project local defined plugins
attr_reader :local_file
def initialize
FileUtils.mkdir_p(INSTALL_DIRECTORY)
FileUtils.mkdir_p(Vagrant.user_data_path.join("tmp").to_s)
@user_file = Plugin::StateFile.new(Vagrant.user_data_path.join("plugins.json"))
end
# Load global plugins
def globalize!
Dir.glob(File.join(INSTALL_DIRECTORY, "*")).each do |entry|
next if !File.directory?(entry)
logger.debug("loading go plugins from directory: #{entry}")
GoPlugin.interface.load_plugins(entry)
end
GoPlugin.interface.register_plugins
end
# Load local plugins
def localize!
raise NotImplementedError
end
# Install a go plugin
#
# @param [String] plugin_name Name of plugin
# @param [String] remote_source Location of plugin for download
# @param [Hash] options Currently unused
def install_plugin(plugin_name, remote_source, options={})
install_dir = File.join(INSTALL_DIRECTORY, plugin_name)
FileUtils.mkdir_p(install_dir)
Dir.mktmpdir("go-plugin", Vagrant.user_data_path.join("tmp").to_s) do |dir|
dest_file = File.join(dir, "plugin.zip")
logger.debug("downloading go plugin #{plugin_name} from #{remote_source}")
Util::Downloader.new(remote_source, dest_file).download!
logger.debug("extracting go plugin #{plugin_name} from #{dest_file}")
Zip::File.open(dest_file) do |zfile|
zfile.each do |entry|
install_path = File.join(install_dir, entry.name)
if File.file?(install_path)
logger.warn("removing existing plugin path for unpacking - #{install_path}")
File.delete(install_path)
end
entry.extract(install_path)
FileUtils.chmod(0755, install_path)
end
end
end
user_file.add_go_plugin(plugin_name, source: remote_source)
end
# Uninstall a go plugin
#
# @param [String] plugin_name Name of plugin
# @param [Hash] options Currently unused
def uninstall_plugin(plugin_name, options={})
plugin_path = File.join(INSTALL_DIRECTORY, plugin_name)
if !File.directory?(plugin_path)
logger.warn("Plugin directory does not exist for #{plugin_name} - #{plugin_path}")
else
logger.debug("deleting go plugin from path #{plugin_path}")
FileUtils.rm_rf(plugin_path)
end
user_file.remove_go_plugin(plugin_name)
end
end
end
end

View File

@ -0,0 +1,341 @@
require "vagrant/go_plugin/core"
module Vagrant
module GoPlugin
module ProviderPlugin
# 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
# @return [String] action name associated to this class
def self.action_name
@action_name
end
# Set the action name for this class
#
# @param [String] n action name
# @return [String]
# @note can only be set once
def self.action_name=(n)
if @action_name
raise ArgumentError.new("Class action name has already been set")
end
@action_name = n.to_s.dup.freeze
end
def initialize(app, env)
@app = app
end
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|
env[k] = v
end
@app.call(env)
end
end
# Helper class used to provide a wrapper around a go-plugin
# provider so that it can be interacted with normally within
# Vagrant
class Provider < Vagrant.plugin("2", :provider)
# @return [Vagrant::Machine]
attr_reader :machine
# @return [String] plugin name associated to this class
def self.go_plugin_name
@go_plugin_name
end
# Set the plugin name for this class
#
# @param [String] n plugin name
# @return [String]
# @note can only be set once
def self.go_plugin_name=(n)
if @go_plugin_name
raise ArgumentError.new("Class plugin name has already been set")
end
@go_plugin_name = n
end
# @return [String]
def self.name
go_plugin_name.to_s.capitalize.tr("_", "")
end
def initialize(machine)
@machine = machine
end
# @return [String] name of the provider plugin for this class
def provider_name
self.class.go_plugin_name
end
# Get callable action by name
#
# @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 = result.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.class_eval do
def self.name
"#{provider_name.capitalize}#{action_name.capitalize}".tr("_", "")
end
end
klass
else
klass_name.split("::").inject(Object) do |memo, const|
if memo.const_defined?(const)
memo.const_get(const)
else
raise NameError.new "Unknown action class `#{klass_name}`"
end
end
end
end
Vagrant::Action::Builder.new.tap do |builder|
klasses.each do |action_class|
builder.use action_class
end
end
end
def capability
end
# Check if provider has requested capability
#
# @param [String] provider_name provider name for request
# @param [String] capability_name name of the capability
# @param [Vagrant::Machine] machine instance of guest
# @return [Boolean]
def has_capability(provider_name, capability_name, machine)
result = load_result { _provider_has_capability(provider_name,
capability_name, dump_machine(machine)) }
result
end
# Check if provider is installed
#
# @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
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
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)) }
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)) }
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
end
end
end
end
end

View File

@ -0,0 +1,170 @@
require "vagrant/go_plugin/core"
module Vagrant
module GoPlugin
# Contains all synced folder functionality for go-plugin
module SyncedFolderPlugin
# Helper class used to provide a wrapper around a go-plugin
# synced folder so that it can be interacted with normally
# within Vagrant
class SyncedFolder < Vagrant.plugin("2", :synced_folder)
include DirectGoPlugin
# 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)
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)
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)
end
# Check if plugin is usable
#
# @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))
}
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.")
end
end
end
end
end
end

View File

@ -24,17 +24,53 @@ module Vagrant
end
upgrade_v0! if !@data["version"]
upgrade_v1! if @data["version"].to_s == "1"
end
@data["version"] ||= "1"
@data["installed"] ||= {}
@data["version"] ||= "2"
@data["ruby"] ||= {"installed" => {}}
@data["go_plugin"] ||= {}
end
# Add a go plugin that is installed to the state file.
#
# @param [String] name The name of the plugin
def add_go_plugin(name, **opts)
@data["go_plugin"][name] = {
"source" => opts[:source]
}
save!
end
# Remove a plugin that is installed from the state file.
#
# @param [String] name The name of the plugin
def remove_go_plugin(name)
@data["go_plugin"].delete(name)
save!
end
# @return [Boolean] go plugin is present in this state file
def has_go_plugin?(name)
@data["go_plugin"].key?(name)
end
# This returns a hash of installed go plugins according to the state
# file. Note that this may _not_ directly match over to actually
# installed plugins.
#
# @return [Hash]
def installed_go_plugins
@data["go_plugin"]
end
# Add a plugin that is installed to the state file.
#
# @param [String] name The name of the plugin
def add_plugin(name, **opts)
@data["installed"][name] = {
@data["ruby"]["installed"][name] = {
"ruby_version" => RUBY_VERSION,
"vagrant_version" => Vagrant::VERSION,
"gem_version" => opts[:version] || "",
@ -51,8 +87,8 @@ module Vagrant
#
# @param [String] url URL of the source.
def add_source(url)
@data["sources"] ||= []
@data["sources"] << url if !@data["sources"].include?(url)
@data["ruby"]["sources"] ||= []
@data["ruby"]["sources"] |= [url]
save!
end
@ -62,21 +98,21 @@ module Vagrant
#
# @return [Hash]
def installed_plugins
@data["installed"]
@data["ruby"]["installed"]
end
# Returns true/false if the plugin is present in this state file.
#
# @return [Boolean]
def has_plugin?(name)
@data["installed"].key?(name)
@data["ruby"]["installed"].key?(name)
end
# Remove a plugin that is installed from the state file.
#
# @param [String] name The name of the plugin.
def remove_plugin(name)
@data["installed"].delete(name)
@data["ruby"]["installed"].delete(name)
save!
end
@ -84,8 +120,8 @@ module Vagrant
#
# @param [String] url URL of the source
def remove_source(url)
@data["sources"] ||= []
@data["sources"].delete(url)
@data["ruby"]["sources"] ||= []
@data["ruby"]["sources"].delete(url)
save!
end
@ -94,7 +130,7 @@ module Vagrant
#
# @return [Array<String>]
def sources
@data["sources"] || []
@data["ruby"]["sources"] || []
end
# This saves the state back into the state file.
@ -128,6 +164,18 @@ module Vagrant
save!
end
# This upgrades the internal data representation from V1 to V2
def upgrade_v1!
@data.delete("version")
new_data = {
"version" => "2",
"ruby" => @data,
"go_plugin" => {}
}
save!
end
end
end
end

View File

@ -9,6 +9,7 @@ module Vagrant
autoload :Env, 'vagrant/util/env'
autoload :HashWithIndifferentAccess, 'vagrant/util/hash_with_indifferent_access'
autoload :GuestInspection, 'vagrant/util/guest_inspection'
autoload :Logger, 'vagrant/util/logger'
autoload :LoggingFormatter, 'vagrant/util/logging_formatter'
autoload :Platform, 'vagrant/util/platform'
autoload :Retryable, 'vagrant/util/retryable'

View File

@ -0,0 +1,18 @@
require "log4r"
module Vagrant
module Util
# Adds a logger method which provides automatically
# namespaced logger instance
module Logger
# @return [Log4r::Logger]
def logger
if !@_logger
@_logger = Log4r::Logger.new(self.class.name.downcase)
end
@_logger
end
end
end
end

View File

@ -74,6 +74,23 @@ module VagrantPlugins
autoload :RepairPluginsLocal, action_root.join("repair_plugins")
autoload :UninstallPlugin, action_root.join("uninstall_plugin")
autoload :UpdateGems, action_root.join("update_gems")
Vagrant::Util::Experimental.guard_with(:go_plugin) do
autoload :UninstallGoPlugin, action_root.join("uninstall_go_plugin")
autoload :InstallGoPlugin, action_root.join("install_go_plugin")
def self.action_go_install
Vagrant::Action::Builder.new.tap do |b|
b.use InstallGoPlugin
end
end
def self.action_go_uninstall
Vagrant::Action::Builder.new.tap do |b|
b.use UninstallGoPlugin
end
end
end
end
end
end

View File

@ -0,0 +1,35 @@
require "log4r"
require "vagrant/go_plugin/manager"
module VagrantPlugins
module CommandPlugin
module Action
class InstallGoPlugin
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant::plugins::plugincommand::installgoplugin")
end
def call(env)
plugin_name = env[:plugin_name]
plugin_source = env[:plugin_source]
manager = Vagrant::GoPlugin::Manager.instance
env[:ui].info(I18n.t("vagrant.commands.plugin.installing",
name: plugin_name))
manager.install_plugin(plugin_name, plugin_source)
# Tell the user
env[:ui].success(I18n.t("vagrant.commands.plugin.installed",
name: plugin_name,
version: plugin_source))
# Continue
@app.call(env)
end
end
end
end
end

View File

@ -0,0 +1,22 @@
module VagrantPlugins
module CommandPlugin
module Action
class UninstallGoPlugin
def initialize(app, env)
@app = app
end
def call(env)
# Remove it!
env[:ui].info(I18n.t("vagrant.commands.plugin.uninstalling",
name: env[:plugin_name]))
manager = Vagrant::GoPlugin::Manager.instance
manager.uninstall_plugin(env[:plugin_name])
@app.call(env)
end
end
end
end
end

View File

@ -0,0 +1,43 @@
require 'optparse'
require_relative "base"
module VagrantPlugins
module CommandPlugin
module Command
class GoInstall < Base
def execute
options = { verbose: false }
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant plugin goinstall <name> <source>"
o.separator ""
o.on("--verbose", "Enable verbose output for plugin installation") do |v|
options[:verbose] = v
end
end
# Parse the options
argv = parse_options(opts)
return if !argv
if argv.length != 2
raise Vagrant::Errors::CLIInvalidUsage, help: opts.help.chomp
end
plugin_name, plugin_source = argv
action(Action.action_go_install,
plugin_name: plugin_name,
plugin_source: plugin_source
)
# Success, exit status 0
0
end
end
end
end
end

View File

@ -0,0 +1,31 @@
require 'optparse'
require_relative "base"
module VagrantPlugins
module CommandPlugin
module Command
class GoUninstall < Base
def execute
options = {}
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant plugin gouninstall <name> [<name2> <name3> ...] [-h]"
end
# Parse the options
argv = parse_options(opts)
return if !argv
raise Vagrant::Errors::CLIInvalidUsage, help: opts.help.chomp if argv.length < 1
# Uninstall the plugins
argv.each do |entry|
action(Action.action_go_uninstall, plugin_name: entry)
end
# Success, exit status 0
0
end
end
end
end
end

View File

@ -48,6 +48,18 @@ module VagrantPlugins
require_relative "uninstall"
Uninstall
end
Vagrant::Util::Experimental.guard_with(:go_plugin) do
@subcommands.register(:goinstall) do
require_relative "go_install"
GoInstall
end
@subcommands.register(:gouninstall) do
require_relative "go_uninstall"
GoUninstall
end
end
end
def execute

View File

@ -13,6 +13,7 @@ Gem::Specification.new do |s|
s.description = "Vagrant is a tool for building and distributing virtualized development environments."
s.required_ruby_version = "~> 2.2", "< 2.7"
s.required_rubygems_version = ">= 1.3.6"
s.rubyforge_project = "vagrant"
@ -49,6 +50,7 @@ Gem::Specification.new do |s|
s.add_development_dependency "rspec-its", "~> 1.2.0"
s.add_development_dependency "webmock", "~> 2.3.1"
s.add_development_dependency "fake_ftp", "~> 0.1.1"
s.add_development_dependency "rake-compiler"
# The following block of code determines the files that should be included
# in the gem. It does this by reading all the files in the directory where

View File

@ -54,3 +54,7 @@ Enabling this feature allows all provisioners to specify `before` and `after`
options. These options allow provisioners to be configured to run before or after
any given "root" provisioner. more information about these options can be found
on the [base provisioner documentation page](/docs/provisioning/basic_usage.html)
### `go_plugin`
Enabling this feature turns on support for [go-plugin](https://github.com/hashicorp/go-plugin) based plugin for Vagrant.