Skip to content

Commit

Permalink
Merge pull request #959 from Liujingfang1/execplugins
Browse files Browse the repository at this point in the history
add goplugin for exec generators and transformers
  • Loading branch information
k8s-ci-robot authored Apr 9, 2019
2 parents ee68a9c + e5d730e commit 177297c
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 10 deletions.
5 changes: 5 additions & 0 deletions bin/pre-commit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ cd "$base_dir" || {

rc=0

function buildPlugins {
go build -buildmode plugin -tags=plugin -o ./pkg/plugins/builtin/executable.so ./pkg/plugins/builtin/executable.go
}

function runTest {
local name=$1
local result="SUCCESS"
Expand All @@ -36,6 +40,7 @@ function testExamples {
mdrip --mode test --label test README.md ./examples
}

runTest buildPlugins
runTest testGoLangCILint
runTest testGoTest
runTest testExamples
Expand Down
72 changes: 72 additions & 0 deletions pkg/plugins/builtin/executable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// +build plugin

package main

import (
"bytes"
"os"
"os/exec"
"path/filepath"

"github.com/ghodss/yaml"
"sigs.k8s.io/kustomize/pkg/ifc"
"sigs.k8s.io/kustomize/pkg/pgmconfig"
"sigs.k8s.io/kustomize/pkg/resmap"
)

type plugin struct {
name string
input string
rf *resmap.Factory
}

var KustomizePlugin plugin

func (p *plugin) Config(
ldr ifc.Loader, rf *resmap.Factory, k ifc.Kunstructured) error {
dir := filepath.Join(pgmconfig.ConfigRoot(), "plugins")
id := k.GetGvk()
p.name = filepath.Join(dir, id.Group, id.Version, id.Kind)
content, err := yaml.Marshal(k)
if err != nil {
return err
}
p.input = string(content)
p.rf = rf
return nil
}

func (p *plugin) Generate() (resmap.ResMap, error) {
return p.run(nil)
}

func (p *plugin) Transformer(rm resmap.ResMap) error {
result, err := p.run(rm)
if err != nil {
return err
}
for id := range rm {
delete(rm, id)
}
for id, r := range result {
rm[id] = r
}
return nil
}

func (p *plugin) run(rm resmap.ResMap) (resmap.ResMap, error) {
cmd := exec.Command(p.name, p.input)
cmd.Env = os.Environ()
if rm != nil {
content, err := rm.EncodeAsYaml()
if err != nil {
return nil, err
}
cmd.Stdin = bytes.NewReader(content)
}
output, err := cmd.Output()
if err != nil {
return nil, err
}
return p.rf.NewResMapFromBytes(output)
}
5 changes: 2 additions & 3 deletions pkg/plugins/generators.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,13 @@ func (l generatorLoader) Load(
}
var result []transformers.Generator
for id, res := range rm {
fileName := pluginFileName(l.pc, id)
c, err := loadAndConfigurePlugin(fileName, l.ldr, l.rf, res)
c, err := loadAndConfigurePlugin(l.pc.DirectoryPath, id, l.ldr, l.rf, res)
if err != nil {
return nil, err
}
g, ok := c.(transformers.Generator)
if !ok {
return nil, fmt.Errorf("plugin %s not a generator", fileName)
return nil, fmt.Errorf("plugin %s not a generator", id.String())
}
result = append(result, g)
}
Expand Down
37 changes: 30 additions & 7 deletions pkg/plugins/transformers.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ package plugins

import (
"fmt"
"os"
"path/filepath"
"plugin"
"runtime"

"github.com/pkg/errors"
kplugin "sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
Expand Down Expand Up @@ -57,29 +59,50 @@ func (l transformerLoader) Load(
}
var result []transformers.Transformer
for id, res := range rm {
fileName := pluginFileName(l.pc, id)
c, err := loadAndConfigurePlugin(fileName, l.ldr, l.rf, res)
c, err := loadAndConfigurePlugin(l.pc.DirectoryPath, id, l.ldr, l.rf, res)
if err != nil {
return nil, err
}
t, ok := c.(transformers.Transformer)
if !ok {
return nil, fmt.Errorf("plugin %s not a transformer", fileName)
return nil, fmt.Errorf("plugin %s not a transformer", id.String())
}
result = append(result, t)
}
return result, nil
}

func pluginFileName(pc *types.PluginConfig, id resid.ResId) string {
func goPluginFileName(dir string, id resid.ResId) string {
return execPluginFileName(dir, id) + ".so"
}

func execPluginFileName(dir string, id resid.ResId) string {
return filepath.Join(
pc.DirectoryPath,
id.Gvk().Group, id.Gvk().Version, id.Gvk().Kind+".so")
dir,
id.Gvk().Group, id.Gvk().Version, id.Gvk().Kind)
}

// isExecAvailable checks if an executable is available
func isExecAvailable(name string) bool {
f, err := os.Stat(name)
if os.IsNotExist(err) {
return false
}
return f.Mode()&0111 != 0000
}

func loadAndConfigurePlugin(
fileName string, ldr ifc.Loader,
dir string, id resid.ResId,
ldr ifc.Loader,
rf *resmap.Factory, res *resource.Resource) (Configurable, error) {
var fileName string
exec := execPluginFileName(dir, id)
if isExecAvailable(exec) {
_, f, _, _ := runtime.Caller(1)
fileName = filepath.Join(filepath.Dir(f), "builtin", "executable.so")
} else {
fileName = goPluginFileName(dir, id)
}
goPlugin, err := plugin.Open(fileName)
if err != nil {
return nil, errors.Wrapf(err, "plugin %s fails to load", fileName)
Expand Down
34 changes: 34 additions & 0 deletions pkg/target/generatorplugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,37 @@ metadata:
type: Opaque
`)
}

func TestConfigMapGenerator(t *testing.T) {
tc := NewTestEnvController(t).Set()
defer tc.Reset()

tc.BuildExecPlugin(
"someteam.example.com", "v1", "ConfigMapGenerator")

th := NewKustTestHarnessWithPluginConfig(
t, "/app", plugin.ActivePluginConfig())
th.writeK("/app", `
generators:
- configmapGenerator.yaml
`)
th.writeF("/app/configmapGenerator.yaml", `
apiVersion: someteam.example.com/v1
kind: ConfigMapGenerator
metadata:
name: some-random-name
`)
m, err := th.makeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.assertActualEqualsExpected(m, `
apiVersion: v1
data:
password: secret
username: admin
kind: ConfigMap
metadata:
name: example-configmap-test
`)
}
23 changes: 23 additions & 0 deletions pkg/target/testenvcontroller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package target_test
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"sigs.k8s.io/kustomize/k8sdeps/kv/plugin"
"testing"
Expand Down Expand Up @@ -57,6 +58,28 @@ func (x *TestEnvController) BuildGoPlugin(g, v, k string) {
}
}

func (x *TestEnvController) BuildExecPlugin(name ...string) {
obj := filepath.Join(
append([]string{x.workDir, pgmconfig.ProgramName, plugin.PluginRoot}, name...)...)

srcRoot, err := plugins.DefaultSrcRoot()
if err != nil {
x.t.Error(err)
}

src := filepath.Join(
append([]string{srcRoot}, name...)...)

if err := os.MkdirAll(filepath.Dir(obj), 0755); err != nil {
x.t.Errorf("error making directory: %s", filepath.Dir(obj))
}
cmd := exec.Command("cp", src, obj)
cmd.Env = os.Environ()
if err := cmd.Run(); err != nil {
x.t.Errorf("error copying %s: %v", src, err)
}
}

func (x *TestEnvController) makeCompiler() *plugins.Compiler {
// The plugin loader wants to find object code under
// $XDG_CONFIG_HOME/kustomize/plugins
Expand Down
11 changes: 11 additions & 0 deletions plugins/someteam.example.com/v1/ConfigMapGenerator
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

echo "
kind: ConfigMap
apiVersion: v1
metadata:
name: example-configmap-test
data:
username: admin
password: secret
"

0 comments on commit 177297c

Please sign in to comment.