@@ -23,32 +23,34 @@ pub enum Error {
2323/// Merges are only applied to objects that have the same apiVersion, kind, name
2424/// and namespace.
2525///
26+ /// Returns whether the merge matched the base object and was therefore applied.
27+ ///
2628/// In case the merge matches the base object, it will get cloned prior to merging.
2729/// We modeled it this way, as most of the time it won't match, so we don't need to proactively
2830/// clone.
29- pub fn apply_deep_merge < R > ( base : & mut R , merge : & DynamicObject ) -> Result < ( ) , Error >
31+ pub fn apply_deep_merge < R > ( base : & mut R , merge : & DynamicObject ) -> Result < bool , Error >
3032where
3133 R : kube:: Resource < DynamicType = ( ) > + DeepMerge + DeserializeOwned ,
3234{
3335 let Some ( merge_type) = & merge. types else {
34- return Ok ( ( ) ) ;
36+ return Ok ( false ) ;
3537 } ;
3638 if merge_type. api_version != R :: api_version ( & ( ) ) || merge_type. kind != R :: kind ( & ( ) ) {
37- return Ok ( ( ) ) ;
39+ return Ok ( false ) ;
3840 }
3941 let Some ( merge_name) = & merge. metadata . name else {
40- return Ok ( ( ) ) ;
42+ return Ok ( false ) ;
4143 } ;
4244
4345 // The name always needs to match
4446 if & base. name_any ( ) != merge_name {
45- return Ok ( ( ) ) ;
47+ return Ok ( false ) ;
4648 }
4749
4850 // If there is a namespace on the base object, it needs to match as well
4951 // Note that it is not set for cluster-scoped objects.
5052 if base. namespace ( ) != merge. metadata . namespace {
51- return Ok ( ( ) ) ;
53+ return Ok ( false ) ;
5254 }
5355
5456 let deserialized_merge = merge
@@ -61,12 +63,15 @@ where
6163 } ) ?;
6264 base. merge_from ( deserialized_merge) ;
6365
64- Ok ( ( ) )
66+ Ok ( true )
6567}
6668
6769#[ cfg( test) ]
6870mod tests {
69- use std:: { collections:: BTreeMap , vec} ;
71+ use std:: {
72+ collections:: { BTreeMap , HashSet } ,
73+ vec,
74+ } ;
7075
7176 use indoc:: indoc;
7277 use k8s_openapi:: {
@@ -230,6 +235,63 @@ mod tests {
230235 assert_eq ! ( sa, original, "The merge shouldn't have changed anything" ) ;
231236 }
232237
238+ #[ test]
239+ fn service_account_not_merged_as_namespace_missing ( ) {
240+ let mut sa = generate_service_account ( ) ;
241+ let object_overrides: ObjectOverrides = serde_yaml:: from_str ( indoc ! { "
242+ - apiVersion: v1
243+ kind: ServiceAccount
244+ metadata:
245+ name: trino-serviceaccount
246+ # namespace omitted, so it does not match the namespaced base object
247+ labels:
248+ app.kubernetes.io/name: overwritten
249+ foo: bar
250+ " } )
251+ . expect ( "test YAML is valid" ) ;
252+
253+ let original = sa. clone ( ) ;
254+ let matched_indices = object_overrides
255+ . apply_to ( & mut sa)
256+ . expect ( "merging onto test object works" ) ;
257+ assert_eq ! ( sa, original, "The merge shouldn't have changed anything" ) ;
258+ assert_eq ! ( matched_indices, Vec :: <usize >:: new( ) ) ;
259+ }
260+
261+ #[ test]
262+ fn unmatched_overrides_are_reported ( ) {
263+ let mut sa = generate_service_account ( ) ;
264+ let object_overrides: ObjectOverrides = serde_yaml:: from_str ( indoc ! { "
265+ - apiVersion: v1
266+ kind: ServiceAccount
267+ metadata:
268+ name: trino-serviceaccount
269+ namespace: default
270+ labels:
271+ foo: bar
272+ - apiVersion: v1
273+ kind: ServiceAccount
274+ metadata:
275+ name: trino-serviceaccount-typo # name mismatch
276+ namespace: default
277+ " } )
278+ . expect ( "test YAML is valid" ) ;
279+
280+ let matched_indices = object_overrides
281+ . apply_to ( & mut sa)
282+ . expect ( "merging onto test object works" ) ;
283+ assert_eq ! ( matched_indices, vec![ 0 ] ) ;
284+
285+ let unmatched = object_overrides
286+ . unmatched ( & HashSet :: from_iter ( matched_indices) )
287+ . map ( |( index, object_override) | ( index, object_override. metadata . name . clone ( ) ) )
288+ . collect :: < Vec < _ > > ( ) ;
289+ assert_eq ! (
290+ unmatched,
291+ vec![ ( 1 , Some ( "trino-serviceaccount-typo" . to_owned( ) ) ) ]
292+ ) ;
293+ }
294+
233295 #[ test]
234296 fn service_account_not_merged_as_different_api_version ( ) {
235297 let mut sa = generate_service_account ( ) ;
0 commit comments