Do no require exec/go plugin home to use fn plugins

This commit is contained in:
Katrina Verey
2021-03-22 15:51:29 -07:00
parent 710db98dbf
commit e77c284924
11 changed files with 80 additions and 83 deletions

View File

@@ -45,10 +45,12 @@ s/$BAR/bar baz/g
}) })
pluginConfig.RemoveBuildAnnotations() pluginConfig.RemoveBuildAnnotations()
p := NewExecPlugin( loader := pLdr.NewLoader(konfig.DisabledPluginConfig(), rf)
pLdr.AbsolutePluginPath( pluginPath, err := loader.AbsolutePluginPath(pluginConfig.OrgId())
konfig.DisabledPluginConfig(), if err != nil {
pluginConfig.OrgId())) t.Fatalf("unexpected err: %v", err)
}
p := NewExecPlugin(pluginPath)
// Not checking to see if the plugin is executable, // Not checking to see if the plugin is executable,
// because this test does not run it. // because this test does not run it.
// This tests only covers sending configuration // This tests only covers sending configuration

View File

@@ -13,6 +13,7 @@ import (
"strings" "strings"
"github.com/pkg/errors" "github.com/pkg/errors"
"sigs.k8s.io/kustomize/api/filesys"
"sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers" "sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
"sigs.k8s.io/kustomize/api/internal/plugins/execplugin" "sigs.k8s.io/kustomize/api/internal/plugins/execplugin"
@@ -29,6 +30,10 @@ import (
type Loader struct { type Loader struct {
pc *types.PluginConfig pc *types.PluginConfig
rf *resmap.Factory rf *resmap.Factory
// absolutePluginHome caches the location of a valid plugin root directory.
// It should only be set once the directory's existence has been confirmed.
absolutePluginHome string
} }
func NewLoader( func NewLoader(
@@ -95,13 +100,47 @@ func relativePluginPath(id resid.ResId) string {
strings.ToLower(id.Kind)) strings.ToLower(id.Kind))
} }
func AbsolutePluginPath(pc *types.PluginConfig, id resid.ResId) string { func (l *Loader) AbsolutePluginPath(id resid.ResId) (string, error) {
return filepath.Join( pluginHome, err := l.absPluginHome()
pc.AbsPluginHome, relativePluginPath(id), id.Kind) if err != nil {
return "", err
}
return filepath.Join(pluginHome, relativePluginPath(id), id.Kind), nil
} }
func (l *Loader) absolutePluginPath(id resid.ResId) string { // absPluginHome is the home of kustomize Exec and Go plugins.
return AbsolutePluginPath(l.pc, id) // Kustomize plugin configuration files are k8s-style objects
// containing the fields 'apiVersion' and 'kind', e.g.
// apiVersion: apps/v1
// kind: Deployment
// kustomize reads plugin configuration data from a file path
// specified in the 'generators:' or 'transformers:' field of a
// kustomization file. For Exec and Go plugins, kustomize
// uses this data to both locate the plugin and configure it.
// Each Exec or Go plugin (its code, its tests, its supporting data
// files, etc.) must be housed in its own directory at
// ${absPluginHome}/${pluginApiVersion}/LOWERCASE(${pluginKind})
// where
// - ${absPluginHome} is an absolute path, defined below.
// - ${pluginApiVersion} is taken from the plugin config file.
// - ${pluginKind} is taken from the plugin config file.
func (l *Loader) absPluginHome() (string, error) {
// External plugins are disabled--return the dummy plugin root.
if l.pc.PluginRestrictions != types.PluginRestrictionsNone {
return konfig.NoPluginHomeSentinal, nil
}
// We've already determined plugin home--use the cached value.
if l.absolutePluginHome != "" {
return l.absolutePluginHome, nil
}
// Check default locations for a valid plugin root, and cache it if found.
dir, err := konfig.DefaultAbsPluginHome(filesys.MakeFsOnDisk())
if err != nil {
return "", err
}
l.absolutePluginHome = dir
return l.absolutePluginHome, nil
} }
func isBuiltinPlugin(res *resource.Resource) bool { func isBuiltinPlugin(res *resource.Resource) bool {
@@ -176,10 +215,13 @@ func (l *Loader) loadPlugin(res *resource.Resource) (resmap.Configurable, error)
} }
func (l *Loader) loadExecOrGoPlugin(resId resid.ResId) (resmap.Configurable, error) { func (l *Loader) loadExecOrGoPlugin(resId resid.ResId) (resmap.Configurable, error) {
absPluginPath, err := l.AbsolutePluginPath(resId)
if err != nil {
return nil, err
}
// First try to load the plugin as an executable. // First try to load the plugin as an executable.
p := execplugin.NewExecPlugin(l.absolutePluginPath(resId)) p := execplugin.NewExecPlugin(absPluginPath)
err := p.ErrIfNotExecutable() if err = p.ErrIfNotExecutable(); err == nil {
if err == nil {
return p, nil return p, nil
} }
if !os.IsNotExist(err) { if !os.IsNotExist(err) {
@@ -193,7 +235,7 @@ func (l *Loader) loadExecOrGoPlugin(resId resid.ResId) (resmap.Configurable, err
return nil, err return nil, err
} }
// Failing the above, try loading it as a Go plugin. // Failing the above, try loading it as a Go plugin.
c, err := l.loadGoPlugin(resId) c, err := l.loadGoPlugin(resId, absPluginPath+".so")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -208,12 +250,11 @@ func (l *Loader) loadExecOrGoPlugin(resId resid.ResId) (resmap.Configurable, err
// as a Loader instance variable. So make it a package variable. // as a Loader instance variable. So make it a package variable.
var registry = make(map[string]resmap.Configurable) var registry = make(map[string]resmap.Configurable)
func (l *Loader) loadGoPlugin(id resid.ResId) (resmap.Configurable, error) { func (l *Loader) loadGoPlugin(id resid.ResId, absPath string) (resmap.Configurable, error) {
regId := relativePluginPath(id) regId := relativePluginPath(id)
if c, ok := registry[regId]; ok { if c, ok := registry[regId]; ok {
return copyPlugin(c), nil return copyPlugin(c), nil
} }
absPath := l.absolutePluginPath(id) + ".so"
if !utils.FileExists(absPath) { if !utils.FileExists(absPath) {
return nil, fmt.Errorf( return nil, fmt.Errorf(
"expected file with Go object code at: %s", absPath) "expected file with Go object code at: %s", absPath)

View File

@@ -66,10 +66,7 @@ func TestLoader(t *testing.T) {
for _, behavior := range []types.BuiltinPluginLoadingOptions{ for _, behavior := range []types.BuiltinPluginLoadingOptions{
/* types.BploUseStaticallyLinked, /* types.BploUseStaticallyLinked,
types.BploLoadFromFileSys */} { types.BploLoadFromFileSys */} {
c, err := konfig.EnabledPluginConfig(behavior) c := konfig.EnabledPluginConfig(behavior)
if err != nil {
t.Fatal(err)
}
pLdr := NewLoader(c, rmF) pLdr := NewLoader(c, rmF)
if pLdr == nil { if pLdr == nil {
t.Fatal("expect non-nil loader") t.Fatal("expect non-nil loader")

View File

@@ -34,7 +34,7 @@ func GoBin() string {
// has her ${g}/${v}/$lower(${k})/${k}.go files. // has her ${g}/${v}/$lower(${k})/${k}.go files.
func DeterminePluginSrcRoot(fSys filesys.FileSystem) (string, error) { func DeterminePluginSrcRoot(fSys filesys.FileSystem) (string, error) {
return konfig.FirstDirThatExistsElseError( return konfig.FirstDirThatExistsElseError(
"source directory", fSys, []konfig.NotedFunc{ "plugin src root", fSys, []konfig.NotedFunc{
{ {
Note: "relative to unit test", Note: "relative to unit test",
F: func() string { F: func() string {

View File

@@ -41,28 +41,20 @@ const (
NoPluginHomeSentinal = "/No/non-builtin/plugins!" NoPluginHomeSentinal = "/No/non-builtin/plugins!"
) )
func EnabledPluginConfig(b types.BuiltinPluginLoadingOptions) (*types.PluginConfig, error) { func EnabledPluginConfig(b types.BuiltinPluginLoadingOptions) *types.PluginConfig {
dir, err := DefaultAbsPluginHome(filesys.MakeFsOnDisk()) return MakePluginConfig(types.PluginRestrictionsNone, b)
if err != nil {
return nil, err
}
return MakePluginConfig(types.PluginRestrictionsNone, b, dir), nil
} }
func DisabledPluginConfig() *types.PluginConfig { func DisabledPluginConfig() *types.PluginConfig {
return MakePluginConfig( return MakePluginConfig(
types.PluginRestrictionsBuiltinsOnly, types.PluginRestrictionsBuiltinsOnly,
types.BploUseStaticallyLinked, types.BploUseStaticallyLinked)
NoPluginHomeSentinal)
} }
func MakePluginConfig( func MakePluginConfig(pr types.PluginRestrictions,
pr types.PluginRestrictions, b types.BuiltinPluginLoadingOptions) *types.PluginConfig {
b types.BuiltinPluginLoadingOptions,
home string) *types.PluginConfig {
return &types.PluginConfig{ return &types.PluginConfig{
PluginRestrictions: pr, PluginRestrictions: pr,
AbsPluginHome: home,
BpLoadingOptions: b, BpLoadingOptions: b,
} }
} }
@@ -77,7 +69,7 @@ type NotedFunc struct {
// the home of kustomize plugins. // the home of kustomize plugins.
func DefaultAbsPluginHome(fSys filesys.FileSystem) (string, error) { func DefaultAbsPluginHome(fSys filesys.FileSystem) (string, error) {
return FirstDirThatExistsElseError( return FirstDirThatExistsElseError(
"plugin home directory", fSys, []NotedFunc{ "plugin root", fSys, []NotedFunc{
{ {
Note: "homed in $" + KustomizePluginHomeEnv, Note: "homed in $" + KustomizePluginHomeEnv,
F: func() string { F: func() string {

View File

@@ -8,8 +8,8 @@ import (
) )
func TestFnExecGenerator(t *testing.T) { func TestFnExecGenerator(t *testing.T) {
th := kusttest_test.MakeEnhancedHarness(t) // Function plugins should not need the env setup done by MakeEnhancedHarness
defer th.Reset() th := kusttest_test.MakeHarness(t)
th.WriteK(".", ` th.WriteK(".", `
resources: resources:
@@ -92,8 +92,8 @@ func skipIfNoDocker(t *testing.T) {
func TestFnContainerGenerator(t *testing.T) { func TestFnContainerGenerator(t *testing.T) {
skipIfNoDocker(t) skipIfNoDocker(t)
th := kusttest_test.MakeEnhancedHarness(t) // Function plugins should not need the env setup done by MakeEnhancedHarness
defer th.Reset() th := kusttest_test.MakeHarness(t)
th.WriteK(".", ` th.WriteK(".", `
resources: resources:
@@ -308,8 +308,8 @@ spec:
func TestFnContainerTransformer(t *testing.T) { func TestFnContainerTransformer(t *testing.T) {
skipIfNoDocker(t) skipIfNoDocker(t)
th := kusttest_test.MakeEnhancedHarness(t) // Function plugins should not need the env setup done by MakeEnhancedHarness
defer th.Reset() th := kusttest_test.MakeHarness(t)
th.WriteK(".", ` th.WriteK(".", `
resources: resources:
@@ -408,8 +408,8 @@ spec:
func TestFnContainerTransformerWithConfig(t *testing.T) { func TestFnContainerTransformerWithConfig(t *testing.T) {
skipIfNoDocker(t) skipIfNoDocker(t)
th := kusttest_test.MakeEnhancedHarness(t) // Function plugins should not need the env setup done by MakeEnhancedHarness
defer th.Reset() th := kusttest_test.MakeHarness(t)
th.WriteK(".", ` th.WriteK(".", `
resources: resources:
@@ -468,8 +468,8 @@ metadata:
func TestFnContainerEnvVars(t *testing.T) { func TestFnContainerEnvVars(t *testing.T) {
skipIfNoDocker(t) skipIfNoDocker(t)
th := kusttest_test.MakeEnhancedHarness(t) // Function plugins should not need the env setup done by MakeEnhancedHarness
defer th.Reset() th := kusttest_test.MakeHarness(t)
th.WriteK(".", ` th.WriteK(".", `
generators: generators:

View File

@@ -5,7 +5,6 @@ package kusttest_test
import ( import (
"path/filepath" "path/filepath"
"strings"
"testing" "testing"
"sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/filesys"
@@ -77,15 +76,7 @@ func (th Harness) MakeOptionsPluginsDisabled() krusty.Options {
// Enables use of non-builtin plugins. // Enables use of non-builtin plugins.
func (th Harness) MakeOptionsPluginsEnabled() krusty.Options { func (th Harness) MakeOptionsPluginsEnabled() krusty.Options {
pc, err := konfig.EnabledPluginConfig(types.BploLoadFromFileSys) pc := konfig.EnabledPluginConfig(types.BploLoadFromFileSys)
if err != nil {
if strings.Contains(err.Error(), "unable to find plugin root") {
th.t.Log(
"Tests that want to run with plugins enabled must be " +
"bookended by calls to MakeEnhancedHarness(), Reset().")
}
th.t.Fatal(err)
}
o := *krusty.MakeDefaultOptions() o := *krusty.MakeDefaultOptions()
o.PluginConfig = pc o.PluginConfig = pc
return o return o

View File

@@ -40,11 +40,8 @@ type HarnessEnhanced struct {
func MakeEnhancedHarness(t *testing.T) *HarnessEnhanced { func MakeEnhancedHarness(t *testing.T) *HarnessEnhanced {
pte := newPluginTestEnv(t).set() pte := newPluginTestEnv(t).set()
pc, err := konfig.EnabledPluginConfig(types.BploLoadFromFileSys) pc := konfig.EnabledPluginConfig(types.BploLoadFromFileSys)
pc.FnpLoadingOptions.EnableStar = true pc.FnpLoadingOptions.EnableStar = true
if err != nil {
t.Fatal(err)
}
p := provider.NewDefaultDepProvider() p := provider.NewDefaultDepProvider()
resourceFactory := p.GetResourceFactory() resourceFactory := p.GetResourceFactory()
resmapFactory := resmap.NewFactory(resourceFactory) resmapFactory := resmap.NewFactory(resourceFactory)

View File

@@ -23,7 +23,7 @@ func (e *errUnableToFind) Error() string {
m = append(m, "('"+p.Value+"'; "+p.Key+")") m = append(m, "('"+p.Value+"'; "+p.Key+")")
} }
return fmt.Sprintf( return fmt.Sprintf(
"unable to find plugin root - tried: %s", strings.Join(m, ", ")) "unable to find %s - tried: %s", e.what, strings.Join(m, ", "))
} }
func NewErrUnableToFind(w string, a []Pair) *errUnableToFind { func NewErrUnableToFind(w string, a []Pair) *errUnableToFind {

View File

@@ -5,25 +5,6 @@ package types
// PluginConfig holds plugin configuration. // PluginConfig holds plugin configuration.
type PluginConfig struct { type PluginConfig struct {
// AbsPluginHome is the home of kustomize plugins.
// Kustomize plugin configuration files are k8s-style objects
// containing the fields 'apiVersion' and 'kind', e.g.
// apiVersion: apps/v1
// kind: Deployment
// kustomize reads plugin configuration data from a file path
// specified in the 'generators:' or 'transformers:' field of a
// kustomization file. kustomize must then use this data to both
// locate the plugin and configure it.
// Every kustomize plugin (its code, its tests, its supporting data
// files, etc.) must be housed in its own directory at
// ${AbsPluginHome}/${pluginApiVersion}/LOWERCASE(${pluginKind})
// where
// - ${AbsPluginHome} is an absolute path, defined below.
// - ${pluginApiVersion} is taken from the plugin config file.
// - ${pluginKind} is taken from the plugin config file.
// The value of AbsPluginHome can be any absolute path.
AbsPluginHome string
// PluginRestrictions distinguishes plugin restrictions. // PluginRestrictions distinguishes plugin restrictions.
PluginRestrictions PluginRestrictions PluginRestrictions PluginRestrictions

View File

@@ -6,7 +6,6 @@ package build
import ( import (
"fmt" "fmt"
"io" "io"
"log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"sigs.k8s.io/kustomize/api/filesys" "sigs.k8s.io/kustomize/api/filesys"
@@ -130,10 +129,7 @@ func HonorKustomizeFlags(kOpts *krusty.Options) *krusty.Options {
kOpts.DoLegacyResourceSort = getFlagReorderOutput() == legacy kOpts.DoLegacyResourceSort = getFlagReorderOutput() == legacy
kOpts.LoadRestrictions = getFlagLoadRestrictorValue() kOpts.LoadRestrictions = getFlagLoadRestrictorValue()
if theFlags.enable.plugins { if theFlags.enable.plugins {
c, err := konfig.EnabledPluginConfig(types.BploUseStaticallyLinked) c := konfig.EnabledPluginConfig(types.BploUseStaticallyLinked)
if err != nil {
log.Fatal(err)
}
c.FnpLoadingOptions = theFlags.fnOptions c.FnpLoadingOptions = theFlags.fnOptions
kOpts.PluginConfig = c kOpts.PluginConfig = c
} }