mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
* Allow importing kustomize API's without relying on `plugins` Introduce `kustomize_disable_go_plugin_support` go build tag to decouple the kustomize API from the `plugins` package dependency. This is advantageous for applications embedding the kusstomize API without the need for dynamic Go plugins, mitigating an increase in binary size associated with the inclusion of the plugins dependency and the population of ELF sections like `.dynsym` and `.dynstr`. The flag provides applications with the flexibility to exclude the import, catering to scenarios where dynamic Go plugin support is unnecessary. Signed-off-by: Tiago Silva <tiago.silva@goteleport.com> * fix golint by disabling some lint checks * handle code review suggestions --------- Signed-off-by: Tiago Silva <tiago.silva@goteleport.com>
63 lines
2.0 KiB
Go
63 lines
2.0 KiB
Go
// Copyright 2024 The Kubernetes Authors.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//go:build !kustomize_disable_go_plugin_support
|
|
|
|
package loader
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"plugin"
|
|
"reflect"
|
|
|
|
"sigs.k8s.io/kustomize/api/internal/plugins/utils"
|
|
"sigs.k8s.io/kustomize/api/konfig"
|
|
"sigs.k8s.io/kustomize/api/resmap"
|
|
"sigs.k8s.io/kustomize/kyaml/errors"
|
|
"sigs.k8s.io/kustomize/kyaml/resid"
|
|
)
|
|
|
|
// registry is a means to avoid trying to load the same .so file
|
|
// into memory more than once, which results in an error.
|
|
// Each test makes its own loader, and tries to load its own plugins,
|
|
// but the loaded .so files are in shared memory, so one will get
|
|
// "this plugin already loaded" errors if the registry is maintained
|
|
// as a Loader instance variable. So make it a package variable.
|
|
var registry = make(map[string]resmap.Configurable) //nolint:gochecknoglobals
|
|
|
|
func copyPlugin(c resmap.Configurable) resmap.Configurable {
|
|
indirect := reflect.Indirect(reflect.ValueOf(c))
|
|
newIndirect := reflect.New(indirect.Type())
|
|
newIndirect.Elem().Set(reflect.ValueOf(indirect.Interface()))
|
|
newNamed := newIndirect.Interface()
|
|
return newNamed.(resmap.Configurable) //nolint:forcetypeassert
|
|
}
|
|
|
|
func (l *Loader) loadGoPlugin(id resid.ResId, absPath string) (resmap.Configurable, error) {
|
|
regId := relativePluginPath(id)
|
|
if c, ok := registry[regId]; ok {
|
|
return copyPlugin(c), nil
|
|
}
|
|
if !utils.FileExists(absPath) {
|
|
return nil, fmt.Errorf(
|
|
"expected file with Go object code at: %s", absPath)
|
|
}
|
|
log.Printf("Attempting plugin load from %q", absPath)
|
|
p, err := plugin.Open(absPath)
|
|
if err != nil {
|
|
return nil, errors.WrapPrefixf(err, "plugin %s fails to load", absPath)
|
|
}
|
|
symbol, err := p.Lookup(konfig.PluginSymbol)
|
|
if err != nil {
|
|
return nil, errors.WrapPrefixf(
|
|
err, "plugin %s doesn't have symbol %s",
|
|
regId, konfig.PluginSymbol)
|
|
}
|
|
c, ok := symbol.(resmap.Configurable)
|
|
if !ok {
|
|
return nil, fmt.Errorf("plugin %q not configurable", regId)
|
|
}
|
|
registry[regId] = c
|
|
return copyPlugin(c), nil
|
|
}
|