Merge "Replacement transformer improvement"
This commit is contained in:
@@ -91,3 +91,13 @@ type ErrIndexOutOfBound struct {
|
|||||||
func (e ErrIndexOutOfBound) Error() string {
|
func (e ErrIndexOutOfBound) Error() string {
|
||||||
return fmt.Sprintf("index %v is out of bound", e.Index)
|
return fmt.Sprintf("index %v is out of bound", e.Index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrMapNotFound returned if map specified in fieldRef option was not found in a list
|
||||||
|
type ErrMapNotFound struct {
|
||||||
|
Key, Value, ListKey string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrMapNotFound) Error() string {
|
||||||
|
return fmt.Sprintf("unable to find map key '%s' with the value '%s' in list under '%s' key",
|
||||||
|
e.Key, e.Value, e.ListKey)
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ var (
|
|||||||
substringPatternRegex = regexp.MustCompile(`(\S+)%(\S+)%$`)
|
substringPatternRegex = regexp.MustCompile(`(\S+)%(\S+)%$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
dotReplacer = "$$$$"
|
||||||
|
)
|
||||||
|
|
||||||
// GetGVK returns group, version, kind object used to register version
|
// GetGVK returns group, version, kind object used to register version
|
||||||
// of the plugin
|
// of the plugin
|
||||||
func GetGVK() schema.GroupVersionKind {
|
func GetGVK() schema.GroupVersionKind {
|
||||||
@@ -151,7 +155,23 @@ func substitute(m resmap.ResMap, to *types.ReplTarget, replacement interface{})
|
|||||||
}
|
}
|
||||||
for _, r := range resources {
|
for _, r := range resources {
|
||||||
for _, p := range to.FieldRefs {
|
for _, p := range to.FieldRefs {
|
||||||
|
// TODO (dukov) rework this using k8s.io/client-go/util/jsonpath
|
||||||
|
parts := strings.Split(p, "[")
|
||||||
|
var tmp []string
|
||||||
|
for _, part := range parts {
|
||||||
|
if strings.Contains(part, "]") {
|
||||||
|
filter := strings.Split(part, "]")
|
||||||
|
filter[0] = strings.ReplaceAll(filter[0], ".", dotReplacer)
|
||||||
|
part = strings.Join(filter, "]")
|
||||||
|
}
|
||||||
|
tmp = append(tmp, part)
|
||||||
|
}
|
||||||
|
p = strings.Join(tmp, "[")
|
||||||
|
|
||||||
pathSlice := strings.Split(p, ".")
|
pathSlice := strings.Split(p, ".")
|
||||||
|
for i, part := range pathSlice {
|
||||||
|
pathSlice[i] = strings.ReplaceAll(part, dotReplacer, ".")
|
||||||
|
}
|
||||||
if err := updateField(r.Map(), pathSlice, replacement); err != nil {
|
if err := updateField(r.Map(), pathSlice, replacement); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -246,15 +266,15 @@ func updateMapField(m map[string]interface{}, pathToField []string, replacement
|
|||||||
}
|
}
|
||||||
switch typedV := v.(type) {
|
switch typedV := v.(type) {
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
for _, item := range typedV {
|
for i, item := range typedV {
|
||||||
typedItem, ok := item.(map[string]interface{})
|
typedItem, ok := item.(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrTypeMismatch{Actual: item, Expectation: fmt.Sprintf("is expected to be %T", typedItem)}
|
return ErrTypeMismatch{Actual: item, Expectation: fmt.Sprintf("is expected to be %T", typedItem)}
|
||||||
}
|
}
|
||||||
if actualValue, ok := typedItem[key]; ok {
|
if actualValue, ok := typedItem[key]; ok {
|
||||||
if value == actualValue {
|
if value == actualValue {
|
||||||
// TODO (dukov) should not we do 'item = replacement' here?
|
typedV[i] = replacement
|
||||||
typedItem[key] = value
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,7 +293,7 @@ func updateSliceField(m []interface{}, pathToField []string, replacement interfa
|
|||||||
if len(pathToField) == 0 {
|
if len(pathToField) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_, key, value, isArray := getFirstPathSegment(pathToField[0])
|
path, key, value, isArray := getFirstPathSegment(pathToField[0])
|
||||||
|
|
||||||
if isArray {
|
if isArray {
|
||||||
for _, item := range m {
|
for _, item := range m {
|
||||||
@@ -287,6 +307,7 @@ func updateSliceField(m []interface{}, pathToField []string, replacement interfa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ErrMapNotFound{Key: key, Value: value, ListKey: path}
|
||||||
}
|
}
|
||||||
|
|
||||||
index, err := strconv.Atoi(pathToField[0])
|
index, err := strconv.Atoi(pathToField[0])
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ replacements:
|
|||||||
objref:
|
objref:
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
fieldrefs:
|
fieldrefs:
|
||||||
- spec.template.spec.containers[name=nginx-latest].image
|
- spec.template.spec.containers[name=nginx.latest].image
|
||||||
- source:
|
- source:
|
||||||
value: postgres:latest
|
value: postgres:latest
|
||||||
target:
|
target:
|
||||||
@@ -112,7 +112,7 @@ spec:
|
|||||||
- image: nginx:1.7.9
|
- image: nginx:1.7.9
|
||||||
name: nginx-tagged
|
name: nginx-tagged
|
||||||
- image: nginx:latest
|
- image: nginx:latest
|
||||||
name: nginx-latest
|
name: nginx.latest
|
||||||
- image: foobar:1
|
- image: foobar:1
|
||||||
name: replaced-with-digest
|
name: replaced-with-digest
|
||||||
- image: postgres:1.8.0
|
- image: postgres:1.8.0
|
||||||
@@ -137,7 +137,7 @@ spec:
|
|||||||
- image: nginx:1.7.9
|
- image: nginx:1.7.9
|
||||||
name: nginx-tagged
|
name: nginx-tagged
|
||||||
- image: nginx:newtag
|
- image: nginx:newtag
|
||||||
name: nginx-latest
|
name: nginx.latest
|
||||||
- image: foobar:1
|
- image: foobar:1
|
||||||
name: replaced-with-digest
|
name: replaced-with-digest
|
||||||
- image: postgres:latest
|
- image: postgres:latest
|
||||||
@@ -455,6 +455,65 @@ kind: ReplacementTransformer
|
|||||||
metadata:
|
metadata:
|
||||||
name: notImportantHere
|
name: notImportantHere
|
||||||
replacements:
|
replacements:
|
||||||
|
- source:
|
||||||
|
objref:
|
||||||
|
kind: Pod
|
||||||
|
name: pod
|
||||||
|
fieldref: spec.containers[0]
|
||||||
|
target:
|
||||||
|
objref:
|
||||||
|
kind: Deployment
|
||||||
|
fieldrefs:
|
||||||
|
- spec.template.spec.containers[name=myapp-container]`,
|
||||||
|
in: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: pod
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: repl
|
||||||
|
image: repl
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy2
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: busybox
|
||||||
|
name: myapp-container
|
||||||
|
`,
|
||||||
|
expectedOut: `apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: pod
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: repl
|
||||||
|
name: repl
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy2
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: repl
|
||||||
|
name: repl
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: `
|
||||||
|
apiVersion: airshipit.org/v1alpha1
|
||||||
|
kind: ReplacementTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
replacements:
|
||||||
- source:
|
- source:
|
||||||
objref:
|
objref:
|
||||||
kind: Pod
|
kind: Pod
|
||||||
@@ -782,6 +841,44 @@ spec:
|
|||||||
name: nginx-latest`,
|
name: nginx-latest`,
|
||||||
expectedErr: "pattern 'TAG' is defined in configuration but was not found in target value nginx:latest",
|
expectedErr: "pattern 'TAG' is defined in configuration but was not found in target value nginx:latest",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
cfg: `
|
||||||
|
apiVersion: airshipit.org/v1alpha1
|
||||||
|
kind: ReplacementTransformer
|
||||||
|
metadata:
|
||||||
|
name: notImportantHere
|
||||||
|
replacements:
|
||||||
|
- source:
|
||||||
|
value: 12345678
|
||||||
|
target:
|
||||||
|
objref:
|
||||||
|
kind: KubeadmControlPlane
|
||||||
|
fieldrefs:
|
||||||
|
- spec.kubeadmConfigSpec.files[path=konfigadm].content%{k8s-version}%
|
||||||
|
`,
|
||||||
|
|
||||||
|
in: `
|
||||||
|
kind: KubeadmControlPlane
|
||||||
|
metadata:
|
||||||
|
name: cluster-controlplane
|
||||||
|
spec:
|
||||||
|
infrastructureTemplate:
|
||||||
|
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3
|
||||||
|
kind: Metal3MachineTemplate
|
||||||
|
name: $(cluster-name)
|
||||||
|
kubeadmConfigSpec:
|
||||||
|
files:
|
||||||
|
- content: |
|
||||||
|
kubernetes:
|
||||||
|
version: {k8s-version}
|
||||||
|
container_runtime:
|
||||||
|
type: docker
|
||||||
|
owner: root:root
|
||||||
|
path: konfigadm_bug_
|
||||||
|
permissions: "0640"
|
||||||
|
`,
|
||||||
|
expectedErr: "unable to find map key 'path' with the value 'konfigadm' in list under 'files' key",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
|||||||
Reference in New Issue
Block a user