@@ -15,7 +15,7 @@ use snafu::{OptionExt, ResultExt, Snafu};
1515use stackable_operator:: { commons:: listener:: Listener , kvp:: Labels } ;
1616use tokio:: sync:: RwLock ;
1717use tracing:: { Span , info, instrument} ;
18- use tracing_indicatif:: span_ext:: IndicatifSpanExt as _;
18+ use tracing_indicatif:: { indicatif_println , span_ext:: IndicatifSpanExt as _} ;
1919
2020#[ cfg( doc) ]
2121use crate :: utils:: k8s:: ListParamsExt ;
@@ -114,6 +114,7 @@ impl Client {
114114
115115 // TODO (Techassi): Impl IntoIterator for Labels
116116 let labels: BTreeMap < String , String > = labels. into ( ) ;
117+ let mut failed_manifests = Vec :: new ( ) ;
117118
118119 for manifest in serde_yaml:: Deserializer :: from_str ( manifests) {
119120 let mut object = DynamicObject :: deserialize ( manifest) . context ( DeserializeYamlSnafu ) ?;
@@ -144,13 +145,54 @@ impl Client {
144145 }
145146 } ;
146147
147- api. patch (
148- & object. name_any ( ) ,
149- & PatchParams :: apply ( "stackablectl" ) ,
150- & Patch :: Apply ( object) ,
151- )
152- . await
153- . context ( KubeClientPatchSnafu ) ?;
148+ if let Some ( existing_object) = api
149+ . get_opt ( & object. name_any ( ) )
150+ . await
151+ . context ( KubeClientFetchSnafu ) ?
152+ {
153+ object. metadata . resource_version = existing_object. resource_version ( ) ;
154+
155+ match api
156+ . patch (
157+ & object. name_any ( ) ,
158+ & PatchParams :: apply ( "stackablectl" ) ,
159+ & Patch :: Merge ( object. clone ( ) ) ,
160+ )
161+ . await
162+ {
163+ Ok ( result) => result,
164+ Err ( e) => {
165+ // If re-applying a Job fails due to immutability, print out the failed manifests instead of erroring out,
166+ // so the user can decide if the existing Job needs a deletion and recreation
167+ if resource. kind == * "Job" && e. to_string ( ) . contains ( "field is immutable" ) {
168+ failed_manifests. push ( format ! (
169+ "{kind} {object_name}" ,
170+ kind = resource. kind,
171+ object_name = object. name_any( ) . clone( )
172+ ) ) ;
173+ object
174+ } else {
175+ indicatif_println ! (
176+ "{object_name} {object:?}" ,
177+ object_name = & object. name_any( )
178+ ) ;
179+ return Err ( e) . context ( KubeClientPatchSnafu ) ;
180+ }
181+ }
182+ } ;
183+ } else {
184+ api. patch (
185+ & object. name_any ( ) ,
186+ & PatchParams :: apply ( "stackablectl" ) ,
187+ & Patch :: Apply ( object. clone ( ) ) ,
188+ )
189+ . await
190+ . context ( KubeClientPatchSnafu ) ?;
191+ }
192+ }
193+
194+ if !failed_manifests. is_empty ( ) {
195+ indicatif_println ! ( "Failed manifests due to immutability: {failed_manifests:?}" ) ;
154196 }
155197
156198 Ok ( ( ) )
0 commit comments