@@ -24,6 +24,7 @@ import (
2424 kerrors "k8s.io/apimachinery/pkg/api/errors"
2525 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2626 "k8s.io/apimachinery/pkg/runtime"
27+ "k8s.io/apimachinery/pkg/runtime/schema"
2728 "k8s.io/apimachinery/pkg/types"
2829 "sigs.k8s.io/controller-runtime/pkg/client"
2930
@@ -142,14 +143,34 @@ func (a *APIPatchingApplicator) Apply(ctx context.Context, o client.Object, ao .
142143 return errors .Wrap (err , "cannot get object" )
143144 }
144145
146+ if d := desired .(metav1.Object ); d .GetResourceVersion () != "" && d .GetResourceVersion () != o .GetResourceVersion () {
147+ gvr , err := groupResource (a .client , o )
148+ if err != nil {
149+ return err
150+ }
151+ return kerrors .NewConflict (gvr , o .GetName (), errors .New ("resource version does not match" ))
152+ }
153+
145154 for _ , fn := range ao {
146155 if err := fn (ctx , o , desired ); err != nil {
147156 return err
148157 }
149158 }
150159
151160 // TODO(negz): Allow callers to override the kind of patch used.
152- return errors .Wrap (a .client .Patch (ctx , o , & patch {desired }), "cannot patch object" )
161+ return errors .Wrap (a .client .Patch (ctx , desired .(client.Object ), client .MergeFromWithOptions (o , client.MergeFromWithOptimisticLock {})), "cannot patch object" )
162+ }
163+
164+ func groupResource (c client.Client , o runtime.Object ) (schema.GroupResource , error ) {
165+ gvk , err := c .GroupVersionKindFor (o )
166+ if err != nil {
167+ return schema.GroupResource {}, errors .Wrapf (err , "cannot determine group version kind of %T" , o )
168+ }
169+ m , err := c .RESTMapper ().RESTMapping (gvk .GroupKind (), gvk .Version )
170+ if err != nil {
171+ return schema.GroupResource {}, errors .Wrapf (err , "cannot determine group resource of %v" , gvk )
172+ }
173+ return m .Resource .GroupResource (), nil
153174}
154175
155176type patch struct { from runtime.Object }
@@ -165,6 +186,9 @@ type APIUpdatingApplicator struct {
165186
166187// NewAPIUpdatingApplicator returns an Applicator that applies changes to an
167188// object by either creating or updating it in a Kubernetes API server.
189+ //
190+ // Deprecated: Use NewAPIPatchingApplicator instead. The updating applicator
191+ // can lead to data-loss if the Golang types in this process are not up-to-date.
168192func NewAPIUpdatingApplicator (c client.Client ) * APIUpdatingApplicator {
169193 return & APIUpdatingApplicator {client : c }
170194}
0 commit comments