@@ -341,6 +341,83 @@ func (f ForceApplyObject) preprocess(parser Parser) (Operation, error) {
341341 return f , nil
342342}
343343
344+ // ExtractApply is a type of operation. It simulates extracting an object
345+ // the state based on the manager you have applied with, merging the
346+ // apply object with that extracted object and reapplying that.
347+ type ExtractApply struct {
348+ Manager string
349+ APIVersion fieldpath.APIVersion
350+ Object typed.YAMLObject
351+ }
352+
353+ var _ Operation = & ExtractApply {}
354+
355+ func (e ExtractApply ) run (state * State ) error {
356+ p , err := e .preprocess (state .Parser )
357+ if err != nil {
358+ return err
359+ }
360+ return p .run (state )
361+ }
362+
363+ func (e ExtractApply ) preprocess (parser Parser ) (Operation , error ) {
364+
365+ tv , err := parser .Type (string (e .APIVersion )).FromYAML (FixTabsOrDie (e .Object ))
366+ if err != nil {
367+ return nil , err
368+ }
369+ return ExtractApplyObject {
370+ Manager : e .Manager ,
371+ APIVersion : e .APIVersion ,
372+ Object : tv ,
373+ }, nil
374+ }
375+
376+ type ExtractApplyObject struct {
377+ Manager string
378+ APIVersion fieldpath.APIVersion
379+ Object * typed.TypedValue
380+ }
381+
382+ var _ Operation = & ExtractApplyObject {}
383+
384+ func (e ExtractApplyObject ) run (state * State ) error {
385+ if state .Live == nil {
386+ return state .ApplyObject (e .Object , e .APIVersion , e .Manager , true )
387+ }
388+ // Get object from state and convert it to current APIVersion
389+ current , err := state .Updater .Converter .Convert (state .Live , e .APIVersion )
390+ if err != nil {
391+ return err
392+ }
393+ // Get set based on the manager you've applied with
394+ set := fieldpath .NewSet ()
395+ mgr := state .Managers [e .Manager ]
396+ if mgr != nil {
397+ // we cannot extract a set that is for a different version
398+ if mgr .APIVersion () != e .APIVersion {
399+ return fmt .Errorf ("existing managed fieldpath set APIVersion (%s) differs from desired (%s), unable to extract" , mgr .APIVersion (), e .APIVersion )
400+ }
401+ // trying to extract the fieldSet directly will return everything
402+ // under the first path in the set, so we must filter out all
403+ // the non-leaf nodes from the fieldSet
404+ set = mgr .Set ().Leaves ()
405+ }
406+ // ExtractFields from the state object based on the set
407+ extracted := current .ExtractItems (set )
408+ // Merge ApplyObject on top of the extracted object
409+ obj , err := extracted .Merge (e .Object )
410+ if err != nil {
411+ return err
412+ }
413+ // Reapply that to the state
414+ return state .ApplyObject (obj , e .APIVersion , e .Manager , true )
415+ }
416+
417+ func (e ExtractApplyObject ) preprocess (parser Parser ) (Operation , error ) {
418+ return e , nil
419+ }
420+
344421// Update is a type of operation. It is a controller type of
345422// update. Errors are passed along.
346423type Update struct {
0 commit comments