Skip to content

Commit 8d05f34

Browse files
committed
pkg/resource: make patching applicator consistent and deprecate update applicator
Signed-off-by: Dr. Stefan Schimanski <[email protected]>
1 parent 78b1e5b commit 8d05f34

File tree

2 files changed

+27
-2
lines changed

2 files changed

+27
-2
lines changed

pkg/resource/api.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

155176
type 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.
168192
func NewAPIUpdatingApplicator(c client.Client) *APIUpdatingApplicator {
169193
return &APIUpdatingApplicator{client: c}
170194
}

pkg/resource/resource.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,8 @@ func IsConditionTrue(c xpv1.Condition) bool {
231231
return c.Status == corev1.ConditionTrue
232232
}
233233

234-
// An Applicator applies changes to an object.
234+
// An Applicator applies changes to an object. The passed object is expected to
235+
// be complete, i.e. not partial.
235236
type Applicator interface {
236237
Apply(context.Context, client.Object, ...ApplyOption) error
237238
}

0 commit comments

Comments
 (0)