Merge "Add document filtering in KRM toolbox by GVK"
This commit is contained in:
@@ -66,6 +66,8 @@ The toolbox image has pre-installed `sh` shell,`kubectl` and `calicoctl`.
|
||||
## Input bundle usage
|
||||
|
||||
The KRM function writes to filesystem input bundle specified in `documentEntryPoint` in phase declaration and imports the path to this bundle in `RENDERED_BUNDLE_PATH` environment variable. For example it can be used with `calicoctl` as `calicoctl apply -f $RENDERED_BUNDLE_PATH`
|
||||
Documents can be filtered by group, version and kind. You need to set `RESOURCE_GROUP_FILTER`, `RESOURCE_VERSION_FILTER` and/or`RESOURCE_KIND_FILTER` in executor definition to enable filtering.
|
||||
|
||||
## Important notes
|
||||
The script must write to STDOUT valid yaml or redirect output to STDERR otherwise phase will fail with `mapping values are not allowed in this context`
|
||||
1. The script must write to STDOUT valid yaml or redirect output to STDERR otherwise phase will fail with `mapping values are not allowed in this context`
|
||||
2. All shell scripts must begin with `set -xe`. This allows errors to be passed from the container to the airshipctl itself. Without this flags the container will never fail.
|
||||
|
||||
@@ -28,16 +28,23 @@ import (
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/document/plugin/kyamlutils"
|
||||
"opendev.org/airship/airshipctl/pkg/log"
|
||||
)
|
||||
|
||||
const (
|
||||
// EnvRenderedBundlePath will be passed to the script, it will contain path to the rendered bundle
|
||||
EnvRenderedBundlePath = "RENDERED_BUNDLE_PATH"
|
||||
scriptPath = "script.sh"
|
||||
scriptKey = "script"
|
||||
bundleFile = "bundle.yaml"
|
||||
workdir = "/tmp"
|
||||
// ResourceGroupFilter used for filtering input bundle by document group
|
||||
ResourceGroupFilter = "RESOURCE_GROUP_FILTER"
|
||||
// ResourceVersionFilter used for filtering input bundle by document version
|
||||
ResourceVersionFilter = "RESOURCE_VERSION_FILTER"
|
||||
// ResourceKindFilter used for filtering input bundle by document kind
|
||||
ResourceKindFilter = "RESOURCE_KIND_FILTER"
|
||||
scriptPath = "script.sh"
|
||||
scriptKey = "script"
|
||||
bundleFile = "bundle.yaml"
|
||||
workdir = "/tmp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -137,6 +144,11 @@ func (c *ScriptRunner) writeBundle(path string, items []*kyaml.RNode) error {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
items, err = c.FilterBundle(items)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pipeline := kio.Pipeline{
|
||||
Outputs: []kio.Writer{
|
||||
kio.ByteWriter{
|
||||
@@ -150,3 +162,15 @@ func (c *ScriptRunner) writeBundle(path string, items []*kyaml.RNode) error {
|
||||
|
||||
return pipeline.Execute()
|
||||
}
|
||||
|
||||
// FilterBundle uses for filtering input documents
|
||||
func (c *ScriptRunner) FilterBundle(items []*kyaml.RNode) ([]*kyaml.RNode, error) {
|
||||
group := os.Getenv(ResourceGroupFilter)
|
||||
version := os.Getenv(ResourceVersionFilter)
|
||||
kind := os.Getenv(ResourceKindFilter)
|
||||
log.Printf("Filtering input bundle by Group: %s, Version: %s, Kind: %s",
|
||||
group, version, kind)
|
||||
return kyamlutils.DocumentSelector{}.
|
||||
ByGVK(group, version, kind).
|
||||
Filter(items)
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
@@ -24,6 +25,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/kustomize/kyaml/fn/framework"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
@@ -166,3 +168,132 @@ func TestCmdRunCleanup(t *testing.T) {
|
||||
}()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestFilterBundle(t *testing.T) {
|
||||
rawDocs := `---
|
||||
apiVersion: test/v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: t1
|
||||
---
|
||||
apiVersion: test/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: t2
|
||||
---
|
||||
apiVersion: test/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: t3
|
||||
`
|
||||
docs, err := (&kio.ByteReader{Reader: bytes.NewBufferString(rawDocs)}).Read()
|
||||
require.NoError(t, err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
inputDocs []*yaml.RNode
|
||||
groupFilter string
|
||||
versionFilter string
|
||||
kindFilter string
|
||||
errContains string
|
||||
expectedDocs string
|
||||
}{
|
||||
{
|
||||
name: "Correct documents",
|
||||
inputDocs: docs,
|
||||
groupFilter: "test",
|
||||
versionFilter: "v1",
|
||||
kindFilter: "Pod",
|
||||
errContains: "",
|
||||
expectedDocs: `apiVersion: test/v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: t1
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "Empty kind",
|
||||
inputDocs: docs,
|
||||
groupFilter: "test",
|
||||
versionFilter: "v1beta1",
|
||||
kindFilter: "",
|
||||
errContains: "",
|
||||
expectedDocs: `apiVersion: test/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: t3
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "Empty all filters",
|
||||
inputDocs: docs,
|
||||
groupFilter: "",
|
||||
versionFilter: "",
|
||||
kindFilter: "",
|
||||
errContains: "",
|
||||
expectedDocs: `apiVersion: test/v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: t1
|
||||
---
|
||||
apiVersion: test/v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: t2
|
||||
---
|
||||
apiVersion: test/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: t3
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cMap := &v1.ConfigMap{
|
||||
Data: map[string]string{
|
||||
dataKey: script,
|
||||
},
|
||||
}
|
||||
|
||||
input, err := yaml.Parse(inputString)
|
||||
require.NoError(t, err)
|
||||
|
||||
stderr := bytes.NewBuffer([]byte{})
|
||||
stdout := bytes.NewBuffer([]byte{})
|
||||
|
||||
os.Setenv(ResourceGroupFilter, tc.groupFilter)
|
||||
defer os.Unsetenv(ResourceGroupFilter)
|
||||
os.Setenv(ResourceVersionFilter, tc.versionFilter)
|
||||
defer os.Unsetenv(ResourceVersionFilter)
|
||||
os.Setenv(ResourceKindFilter, tc.kindFilter)
|
||||
defer os.Unsetenv(ResourceKindFilter)
|
||||
|
||||
cmd := &ScriptRunner{
|
||||
ScriptFile: targetFile,
|
||||
WorkDir: dir,
|
||||
DataKey: dataKey,
|
||||
ErrStream: stderr,
|
||||
OutStream: stdout,
|
||||
ResourceList: &framework.ResourceList{Items: []*yaml.RNode{input}},
|
||||
ConfigMap: cMap,
|
||||
RenderedBundleFile: bundlePath,
|
||||
}
|
||||
|
||||
filteredDocs, err := cmd.FilterBundle(tc.inputDocs)
|
||||
if tc.errContains != "" {
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tc.errContains)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
err = kio.ByteWriter{Writer: buf}.Write(filteredDocs)
|
||||
assert.Equal(t, tc.expectedDocs, buf.String())
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user