Plugins work now oughghgghughgghg
This commit is contained in:
parent
c2ccaff8ab
commit
f112a2e564
@ -129,29 +129,31 @@ func main () {
|
|||||||
Config: config,
|
Config: config,
|
||||||
}
|
}
|
||||||
environment.Providers = providers.All()
|
environment.Providers = providers.All()
|
||||||
err := environment.Init(context.Background())
|
|
||||||
if err != nil { log.Fatal(err) }
|
|
||||||
|
|
||||||
// load plugins
|
// load plugins
|
||||||
for _, pat := range pluginPath {
|
var err error
|
||||||
entries, err := os.ReadDir(pat)
|
var plugins []step.Provider
|
||||||
if err != nil { continue }
|
if flagUnsafePlugins.Value == "true" {
|
||||||
for _, entry := range entries {
|
plugins, err = step.LoadAllProviderPluginsUnsafe(pluginPath...)
|
||||||
pluginPath := filepath.Join(pat, entry.Name())
|
} else {
|
||||||
ext := filepath.Ext(pluginPath)
|
plugins, err = step.LoadAllProviderPlugins(pluginPath...)
|
||||||
if ext != ".so" { continue }
|
}
|
||||||
if flagUnsafePlugins.Value == "true" {
|
if err != nil {
|
||||||
_, err = environment.LoadProviderPluginUnsafe(pluginPath)
|
if errs, ok := err.(step.Errors); ok {
|
||||||
} else {
|
for _, err := range errs.Unwrap() {
|
||||||
_, err = environment.LoadProviderPlugin(pluginPath)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Println("!!!", err)
|
log.Println("!!!", err)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.Println("!!!", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
environment.Providers = append(environment.Providers, plugins...)
|
||||||
logProviders(environment.Providers)
|
logProviders(environment.Providers)
|
||||||
|
|
||||||
|
// initialize the environment
|
||||||
|
err = environment.Init(context.Background())
|
||||||
|
if err != nil { log.Fatal(err) }
|
||||||
|
|
||||||
// set up the HTTP handler
|
// set up the HTTP handler
|
||||||
handler := stephttp.Handler {
|
handler := stephttp.Handler {
|
||||||
Environment: &environment,
|
Environment: &environment,
|
||||||
|
@ -5,9 +5,7 @@ import "io"
|
|||||||
import "fmt"
|
import "fmt"
|
||||||
import "time"
|
import "time"
|
||||||
import "io/fs"
|
import "io/fs"
|
||||||
import "plugin"
|
|
||||||
import "errors"
|
import "errors"
|
||||||
import "syscall"
|
|
||||||
import "context"
|
import "context"
|
||||||
import "path/filepath"
|
import "path/filepath"
|
||||||
import "html/template"
|
import "html/template"
|
||||||
@ -105,55 +103,6 @@ func (this *Environment) Unload (name string) {
|
|||||||
delete(documents, name)
|
delete(documents, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadProviderPlugin loads a plugin given its file path. The file must:
|
|
||||||
//
|
|
||||||
// - Be a shared library
|
|
||||||
// - Be built with go -buildmode=plugin
|
|
||||||
// - Be built with the same version of Go
|
|
||||||
// - Be built with the same version of STEP
|
|
||||||
// - Be owned by root
|
|
||||||
//
|
|
||||||
// Plugins cannot be unloaded from the current program once they are loaded.
|
|
||||||
// Sorgy :( its Go's fault.
|
|
||||||
func (this *Environment) LoadProviderPlugin (name string) (Provider, error) {
|
|
||||||
return this.loadProviderPlugin(name, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadProviderPluginUnsafe is like LoadProviderPlugin, but does not check to
|
|
||||||
// see that the file is owned by root, thereby making it easier to run a random
|
|
||||||
// plugin you just compiled. This should not be used otherwise.
|
|
||||||
func (this *Environment) LoadProviderPluginUnsafe (name string) (Provider, error) {
|
|
||||||
return this.loadProviderPlugin(name, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *Environment) loadProviderPlugin (name string, checkRoot bool) (Provider, error) {
|
|
||||||
plugin, err := this.loadPlugin(name, checkRoot)
|
|
||||||
if err != nil { return nil, err }
|
|
||||||
providerSymbol, err := plugin.Lookup("NewProvider")
|
|
||||||
if err != nil { return nil, err }
|
|
||||||
providerFactory, ok := providerSymbol.(func () Provider)
|
|
||||||
if !ok { return nil, ErrPluginBadSymbol }
|
|
||||||
provider := providerFactory()
|
|
||||||
this.Providers = append(this.Providers, provider)
|
|
||||||
return provider, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *Environment) loadPlugin (name string, checkRoot bool) (*plugin.Plugin, error) {
|
|
||||||
name = filepath.Clean(name)
|
|
||||||
if checkRoot {
|
|
||||||
info, err := os.Stat(name)
|
|
||||||
if err != nil { return nil, err }
|
|
||||||
if info, ok := info.Sys().(*syscall.Stat_t); ok {
|
|
||||||
if info.Uid != 0 {
|
|
||||||
return nil, ErrPluginNotOwnedByRoot
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, ErrInsufficientSystem
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return plugin.Open(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this *Environment) parse (name string, modTime time.Time, input io.Reader) (*Document, error) {
|
func (this *Environment) parse (name string, modTime time.Time, input io.Reader) (*Document, error) {
|
||||||
documents, done := this.documents.Borrow()
|
documents, done := this.documents.Borrow()
|
||||||
defer done()
|
defer done()
|
||||||
|
6
error.go
6
error.go
@ -8,6 +8,7 @@ type Error string; const (
|
|||||||
ErrTypeMismatch Error = "type mismatch"
|
ErrTypeMismatch Error = "type mismatch"
|
||||||
ErrPluginBadSymbol Error = "plugin has an incorrect symbol"
|
ErrPluginBadSymbol Error = "plugin has an incorrect symbol"
|
||||||
ErrPluginNotOwnedByRoot Error = "plugin is not owned by the root user"
|
ErrPluginNotOwnedByRoot Error = "plugin is not owned by the root user"
|
||||||
|
ErrPathNotAbsolute Error = "path is not absolute"
|
||||||
ErrInsufficientSystem Error = "the system cannot perform this action"
|
ErrInsufficientSystem Error = "the system cannot perform this action"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,3 +16,8 @@ type Error string; const (
|
|||||||
func (err Error) Error () string {
|
func (err Error) Error () string {
|
||||||
return string(err)
|
return string(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Errors is any error that unwraps to a list of sub-errors.
|
||||||
|
type Errors interface {
|
||||||
|
Unwrap () []error
|
||||||
|
}
|
||||||
|
98
plugin.go
Normal file
98
plugin.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package step
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
import "errors"
|
||||||
|
import "plugin"
|
||||||
|
import "syscall"
|
||||||
|
import "path/filepath"
|
||||||
|
|
||||||
|
// LoadAllProviderPlugins loads all plugins according to the given search path.
|
||||||
|
//
|
||||||
|
// If a non-nil error is returned, the error should be treated as a list of
|
||||||
|
// warning messages and the return value should be used normally.
|
||||||
|
func LoadAllProviderPlugins (pluginPath ...string) ([]Provider, error) {
|
||||||
|
return loadAllProviderPlugins(pluginPath, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadAllProviderPluginsUnsafe is like LoadAllProviderPlugins, but does not
|
||||||
|
// check to see that the files are owned by root, thereby making it easier to
|
||||||
|
// run a random plugin you just compiled. This should not be used otherwise.
|
||||||
|
//
|
||||||
|
// If a non-nil error is returned, the error should be treated as a list of
|
||||||
|
// warning messages and the return value should be used normally.
|
||||||
|
func LoadAllProviderPluginsUnsafe (pluginPath ...string) ([]Provider, error) {
|
||||||
|
return loadAllProviderPlugins(pluginPath, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadAllProviderPlugins (pluginPath []string, checkRoot bool) ([]Provider, error) {
|
||||||
|
providers := []Provider { }
|
||||||
|
errs := []error { }
|
||||||
|
for _, pat := range pluginPath {
|
||||||
|
entries, err := os.ReadDir(pat)
|
||||||
|
if err != nil { continue }
|
||||||
|
for _, entry := range entries {
|
||||||
|
pluginPath := filepath.Join(pat, entry.Name())
|
||||||
|
ext := filepath.Ext(pluginPath)
|
||||||
|
if ext != ".so" { continue }
|
||||||
|
provider, err := loadProviderPlugin(pluginPath, checkRoot)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
providers = append(providers, provider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return providers, errors.Join(errs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadProviderPlugin loads a plugin given its file path. The file must:
|
||||||
|
//
|
||||||
|
// - Be a shared library
|
||||||
|
// - Be addressed with an absolute path
|
||||||
|
// - Be built with go -buildmode=plugin
|
||||||
|
// - Be built with the same version of Go
|
||||||
|
// - Be built with the same version of STEP
|
||||||
|
// - Be owned by root
|
||||||
|
//
|
||||||
|
// Plugins cannot be unloaded from the current program once they are loaded.
|
||||||
|
// Sorgy :( its Go's fault.
|
||||||
|
func LoadProviderPlugin (name string) (Provider, error) {
|
||||||
|
return loadProviderPlugin(name, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadProviderPluginUnsafe is like LoadProviderPlugin, but does not check to
|
||||||
|
// see that the file is owned by root, thereby making it easier to run a random
|
||||||
|
// plugin you just compiled. This should not be used otherwise.
|
||||||
|
func LoadProviderPluginUnsafe (name string) (Provider, error) {
|
||||||
|
return loadProviderPlugin(name, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadProviderPlugin (name string, checkRoot bool) (Provider, error) {
|
||||||
|
plugin, err := loadPlugin(name, checkRoot)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
providerSymbol, err := plugin.Lookup("NewProvider")
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
providerFactory, ok := providerSymbol.(func () Provider)
|
||||||
|
if !ok { return nil, ErrPluginBadSymbol }
|
||||||
|
provider := providerFactory()
|
||||||
|
return provider, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadPlugin (name string, checkRoot bool) (*plugin.Plugin, error) {
|
||||||
|
name = filepath.Clean(name)
|
||||||
|
if !filepath.IsAbs(name) {
|
||||||
|
return nil, ErrPathNotAbsolute
|
||||||
|
}
|
||||||
|
if checkRoot {
|
||||||
|
info, err := os.Stat(name)
|
||||||
|
if err != nil { return nil, err }
|
||||||
|
if info, ok := info.Sys().(*syscall.Stat_t); ok {
|
||||||
|
if info.Uid != 0 {
|
||||||
|
return nil, ErrPluginNotOwnedByRoot
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, ErrInsufficientSystem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return plugin.Open(name)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user