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:
parent
19360953b0
commit
d82e04ea5e
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user