Skip to content

Commit deb08ff

Browse files
committed
feat(replacements): add IgnoreMissingField option
1 parent 01cce4f commit deb08ff

File tree

4 files changed

+120
-5
lines changed

4 files changed

+120
-5
lines changed

api/filters/replacement/replacement.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,20 +185,24 @@ func containsRejectId(rejects []*types.Selector, ids []resid.ResId) bool {
185185
func copyValueToTarget(target *yaml.RNode, value *yaml.RNode, selector *types.TargetSelector) error {
186186
for _, fp := range selector.FieldPaths {
187187
createKind := yaml.Kind(0) // do not create
188+
ignoreMissingField := false
189+
if selector.Options != nil {
190+
ignoreMissingField = selector.Options.IgnoreMissingField
191+
}
188192
if selector.Options != nil && selector.Options.Create {
189193
createKind = value.YNode().Kind
190194
}
191195
targetFieldList, err := target.Pipe(&yaml.PathMatcher{
192196
Path: kyaml_utils.SmarterPathSplitter(fp, "."),
193197
Create: createKind})
194-
if err != nil {
198+
if err != nil && !ignoreMissingField {
195199
return errors.WrapPrefixf(err, fieldRetrievalError(fp, createKind != 0))
196200
}
197201
targetFields, err := targetFieldList.Elements()
198-
if err != nil {
202+
if err != nil && !ignoreMissingField {
199203
return errors.WrapPrefixf(err, fieldRetrievalError(fp, createKind != 0))
200204
}
201-
if len(targetFields) == 0 {
205+
if len(targetFields) == 0 && !ignoreMissingField {
202206
return errors.Errorf(fieldRetrievalError(fp, createKind != 0))
203207
}
204208

api/filters/replacement/replacement_test.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2830,6 +2830,112 @@ spec:
28302830
`,
28312831
expectedErr: "unable to find or create field \"spec.tls.5.hosts.5\" in replacement target: index 5 specified but only 0 elements found",
28322832
},
2833+
"replace target path and ignore missing fields": {
2834+
input: `apiVersion: v1
2835+
kind: ConfigMap
2836+
metadata:
2837+
name: clusterConfig
2838+
data:
2839+
accountId: "123456789101"
2840+
---
2841+
apiVersion: v1
2842+
kind: ServiceAccount
2843+
metadata:
2844+
name: service-account-with-field
2845+
annotations:
2846+
eks.amazonaws.com/role-arn: arn:aws:iam::REPLACEME:role/super-admin
2847+
---
2848+
apiVersion: v1
2849+
kind: ServiceAccount
2850+
metadata:
2851+
name: service-account-without-field
2852+
`,
2853+
replacements: `replacements:
2854+
- source:
2855+
kind: ConfigMap
2856+
name: clusterConfig
2857+
fieldPath: data.accountId
2858+
targets:
2859+
- select:
2860+
kind: ServiceAccount
2861+
fieldPaths:
2862+
- metadata.annotations.[eks.amazonaws.com/role-arn]
2863+
options:
2864+
# not all Service Accounts have irsa annotations
2865+
ignoreMissingField: true
2866+
delimiter: ":"
2867+
index: 4
2868+
`,
2869+
expected: `apiVersion: v1
2870+
kind: ConfigMap
2871+
metadata:
2872+
name: clusterConfig
2873+
data:
2874+
accountId: "123456789101"
2875+
---
2876+
apiVersion: v1
2877+
kind: ServiceAccount
2878+
metadata:
2879+
name: service-account-with-field
2880+
annotations:
2881+
eks.amazonaws.com/role-arn: arn:aws:iam::123456789101:role/super-admin
2882+
---
2883+
apiVersion: v1
2884+
kind: ServiceAccount
2885+
metadata:
2886+
name: service-account-without-field`,
2887+
},
2888+
"no replacement or error with ignore missing fields when there is no matching field": {
2889+
input: `apiVersion: v1
2890+
kind: ConfigMap
2891+
metadata:
2892+
name: clusterConfig
2893+
data:
2894+
accountId: "123456789101"
2895+
---
2896+
apiVersion: v1
2897+
kind: ServiceAccount
2898+
metadata:
2899+
name: service-account-with-field
2900+
---
2901+
apiVersion: v1
2902+
kind: ServiceAccount
2903+
metadata:
2904+
name: service-account-without-field
2905+
`,
2906+
replacements: `replacements:
2907+
- source:
2908+
kind: ConfigMap
2909+
name: clusterConfig
2910+
fieldPath: data.accountId
2911+
targets:
2912+
- select:
2913+
kind: ServiceAccount
2914+
fieldPaths:
2915+
- metadata.annotations.[eks.amazonaws.com/role-arn]
2916+
options:
2917+
# not all Service Accounts have irsa annotations
2918+
ignoreMissingField: true
2919+
delimiter: ":"
2920+
index: 4
2921+
`,
2922+
expected: `apiVersion: v1
2923+
kind: ConfigMap
2924+
metadata:
2925+
name: clusterConfig
2926+
data:
2927+
accountId: "123456789101"
2928+
---
2929+
apiVersion: v1
2930+
kind: ServiceAccount
2931+
metadata:
2932+
name: service-account-with-field
2933+
---
2934+
apiVersion: v1
2935+
kind: ServiceAccount
2936+
metadata:
2937+
name: service-account-without-field`,
2938+
},
28332939
}
28342940

28352941
for tn, tc := range testCases {

api/types/replacement.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,14 @@ type FieldOptions struct {
7777

7878
// If field missing, add it.
7979
Create bool `json:"create,omitempty" yaml:"create,omitempty"`
80+
81+
// If field missing, ignore it.
82+
IgnoreMissingField bool `json:"ignoreMissingField,omitempty" yaml:"ignoreMissingField,omitempty"`
8083
}
8184

8285
func (fo *FieldOptions) String() string {
83-
if fo == nil || (fo.Delimiter == "" && !fo.Create) {
86+
if fo == nil || (fo.Delimiter == "" && !fo.Create && !fo.IgnoreMissingField) {
8487
return ""
8588
}
86-
return fmt.Sprintf("%s(%d), create=%t", fo.Delimiter, fo.Index, fo.Create)
89+
return fmt.Sprintf("%s(%d), create=%t, ignoreMissingField=%t", fo.Delimiter, fo.Index, fo.Create, fo.IgnoreMissingField)
8790
}

site/content/en/docs/Reference/API/Kustomization File/replacements.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ replacements:
6363
delimiter: string
6464
index: int
6565
create: bool
66+
ignoreMissingField: bool
6667
targets:
6768
- select:
6869
group: string
@@ -103,6 +104,7 @@ replacements:
103104
|`delimiter`| | Used to split/join the field
104105
|`index`| | Which position in the split to consider | `0`
105106
|`create`| | If target field is missing, add it | `false`
107+
|`ignoreMissingField`| | If target field is missing, ignore it | `false`
106108

107109
#### Source
108110
The source field is a selector that determines the source of the value by finding a

0 commit comments

Comments
 (0)