Adding decoding and encoding feature to Replacement Transformer

This PS adds decoding features to ReplacementTransformer to decode
the source objectRef when source is of `kind: Secret` and has `data`
field. It also encodes the value in the target fieldRefs before
replacement if the target is `kind: Secret` and has `data` fields.
Throws an error if the target fieldRefs have both `data` and `stringData`
for replacement.

Change-Id: I1d918058409b3511faa9a99512d25574027bda86
This commit is contained in:
Sirisha Gopigiri 2020-10-12 19:01:07 +05:30 committed by SirishaGopigiri
parent 19360953b0
commit d82e04ea5e
3 changed files with 283 additions and 12 deletions

View File

@ -67,6 +67,15 @@ func (e ErrPatternSubstring) Error() string {
return e.Msg
}
// ErrBase64Decoding returned incorrect base64 encoded string received for `kind: Secret`
type ErrBase64Decoding struct {
Msg string
}
func (e ErrBase64Decoding) Error() string {
return e.Msg
}
// ErrIndexOutOfBound returned if JSON path points to a wrong index of a list
type ErrIndexOutOfBound struct {
Index int

View File

@ -15,9 +15,11 @@
package replacement
import (
"encoding/base64"
"fmt"
"io"
"regexp"
"strings"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/kustomize/api/types"
@ -34,6 +36,11 @@ var (
substringPatternRegex = regexp.MustCompile(`(.+)%(\S+)%$`)
)
const (
secret = "Secret"
secretData = "data"
)
var _ plugtypes.Plugin = &plugin{}
type plugin struct {
@ -105,7 +112,17 @@ func getValue(items []*yaml.RNode, source *types.ReplSource) (*yaml.RNode, error
if source.FieldRef != "" {
path = source.FieldRef
}
return sources[0].Pipe(kyamlutils.JSONPathFilter{Path: path})
sourceNode, err := sources[0].Pipe(kyamlutils.JSONPathFilter{Path: path})
if err != nil {
return nil, err
}
// Decoding value if source is `kind: Secret` and
// has fieldRef `data`
if source.ObjRef.Gvk.Kind == secret && strings.Split(source.FieldRef, ".")[0] == secretData {
return decodeValue(sourceNode)
}
return sourceNode, nil
}
func mutateField(rnSource *yaml.RNode) func([]*yaml.RNode) error {
@ -131,18 +148,24 @@ func replace(items []*yaml.RNode, target *types.ReplTarget, value *yaml.RNode) e
}
for _, tgt := range targets {
for _, fieldRef := range target.FieldRefs {
val := value
// Encoding value before replacement if target is `kind: Secret`
// and has fieldRef `data`
if target.ObjRef.Gvk.Kind == secret && strings.Split(fieldRef, ".")[0] == secretData {
val = encodeValue(val)
}
// fieldref can contain substring pattern for regexp - we need to get it
groups := substringPatternRegex.FindStringSubmatch(fieldRef)
// if there is no substring pattern
if len(groups) != 3 {
filter := kyamlutils.JSONPathFilter{Path: fieldRef, Mutator: mutateField(value), Create: true}
filter := kyamlutils.JSONPathFilter{Path: fieldRef, Mutator: mutateField(val), Create: true}
if _, err := tgt.Pipe(filter); err != nil {
return err
}
continue
}
if err := substituteSubstring(tgt, groups[1], groups[2], value); err != nil {
if err := substituteSubstring(tgt, groups[1], groups[2], val); err != nil {
return err
}
}
@ -180,3 +203,32 @@ func substituteSubstring(tgt *yaml.RNode, fieldRef, substringPattern string, val
}
return nil
}
func decodeValue(source *yaml.RNode) (*yaml.RNode, error) {
//decoding replacement source if source reference has data field
decodeValue, err := decodeString(yaml.GetValue(source))
if err != nil {
return nil, ErrBase64Decoding{Msg: fmt.Sprintf("Error while decoding base64"+
" encoded string: %s", yaml.GetValue(source))}
}
node := yaml.NewScalarRNode(decodeValue)
return node, nil
}
func encodeValue(value *yaml.RNode) *yaml.RNode {
encodeValue := encodeString(yaml.GetValue(value))
node := yaml.NewScalarRNode(encodeValue)
return node
}
func decodeString(value interface{}) (string, error) {
decodedValue, err := base64.StdEncoding.DecodeString(value.(string))
if err != nil {
return "", err
}
return string(decodedValue), nil
}
func encodeString(value string) string {
return base64.StdEncoding.EncodeToString([]byte(value))
}

View File

@ -644,6 +644,188 @@ kind: ReplacementTransformer
metadata:
name: Test_Case_10
replacements:
- source:
objref:
kind: Secret
name: secret
fieldref: data.imagename
target:
objref:
kind: Deployment
fieldrefs:
- spec.template.spec.containers[name=myapp-container].image`,
in: `
apiVersion: v1
kind: Secret
metadata:
name: secret
data:
imagename: c2VjcmV0ZGVjb2Rpbmc=
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy2
spec:
template:
spec:
containers:
- image: busybox:TAG
name: myapp-container
`,
expectedOut: `apiVersion: v1
kind: Secret
metadata:
name: secret
data:
imagename: c2VjcmV0ZGVjb2Rpbmc=
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy2
spec:
template:
spec:
containers:
- image: secretdecoding
name: myapp-container
`,
},
{
cfg: `
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_11
replacements:
- source:
objref:
kind: Secret
name: secret1
fieldref: stringData.username
target:
objref:
kind: Secret
name: secret2
fieldrefs:
- data.username`,
in: `
apiVersion: v1
kind: Secret
metadata:
name: secret1
stringData:
username: secretencoding
---
apiVersion: v1
kind: Secret
metadata:
name: secret2
`,
expectedOut: `apiVersion: v1
kind: Secret
metadata:
name: secret1
stringData:
username: secretencoding
---
apiVersion: v1
kind: Secret
metadata:
name: secret2
data:
username: c2VjcmV0ZW5jb2Rpbmc=
`,
},
{
cfg: `
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_12
replacements:
- source:
value: testing
target:
objref:
kind: Secret
name: secret1
fieldrefs:
- data.username
- stringData.username`,
in: `
apiVersion: v1
kind: Secret
metadata:
name: secret1
`,
expectedOut: `apiVersion: v1
kind: Secret
metadata:
name: secret1
data:
username: dGVzdGluZw==
stringData:
username: testing
`,
},
{
cfg: `
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_13
replacements:
- source:
objref:
kind: Secret
name: secret1
fieldref: data.username
target:
objref:
kind: Secret
name: secret2
fieldrefs:
- data.password
- stringData.password`,
in: `
apiVersion: v1
kind: Secret
metadata:
name: secret1
data:
username: dGVzdGluZw==
---
apiVersion: v1
kind: Secret
metadata:
name: secret2
`,
expectedOut: `apiVersion: v1
kind: Secret
metadata:
name: secret1
data:
username: dGVzdGluZw==
---
apiVersion: v1
kind: Secret
metadata:
name: secret2
data:
password: dGVzdGluZw==
stringData:
password: testing
`,
},
{
cfg: `
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_14
replacements:
- source:
objref:
kind: Pod
@ -677,7 +859,7 @@ spec:
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_11
name: Test_Case_15
replacements:
- source:
objref:
@ -701,7 +883,7 @@ metadata:
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_12
name: Test_Case_16
replacements:
- source:
objref:
@ -728,7 +910,7 @@ spec:
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_13
name: Test_Case_17
replacements:
- source:
objref:
@ -768,7 +950,7 @@ spec:
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_14
name: Test_Case_18
replacements:
- source:
objref:
@ -808,7 +990,7 @@ spec:
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_15
name: Test_Case_19
replacements:
- source:
objref:
@ -848,7 +1030,7 @@ spec:
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_16
name: Test_Case_20
replacements:
- source:
objref:
@ -887,7 +1069,7 @@ spec:
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_17
name: Test_Case_21
replacements:
- source:
objref:
@ -927,7 +1109,7 @@ spec:
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_18
name: Test_Case_22
replacements:
- source:
objref:
@ -967,7 +1149,7 @@ spec:
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_19
name: Test_Case_23
replacements:
- source:
value: "12345678"
@ -1015,6 +1197,34 @@ spec:
permissions: "0640"
`,
},
{
cfg: `
apiVersion: airshipit.org/v1alpha1
kind: ReplacementTransformer
metadata:
name: Test_Case_24
replacements:
- source:
objref:
kind: Secret
name: secret1
fieldref: data.username
target:
objref:
kind: Secret
name: secret1
fieldrefs:
- data.password`,
in: `
apiVersion: v1
kind: Secret
metadata:
name: secret1
data:
username: abc
`,
expectedErr: "Error while decoding base64 encoded string: abc",
},
}
func TestExec(t *testing.T) {