Add REST PrepareForUpdate() hook

As per discussion with @snmarterclayton.  I implemented this for most
types in the "obvious" way.  I am not sure how to implement
this for a couple types, though.
This commit is contained in:
Tim Hockin 2015-03-25 17:03:30 -07:00
parent b2687c1a84
commit 0f36c68244
9 changed files with 76 additions and 1 deletions

View File

@ -66,6 +66,14 @@ func (svcStrategy) PrepareForCreate(obj runtime.Object) {
service.Status = api.ServiceStatus{} service.Status = api.ServiceStatus{}
} }
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
func (svcStrategy) PrepareForUpdate(obj, old runtime.Object) {
// TODO: once service has a status sub-resource we can enable this.
//newService := obj.(*api.Service)
//oldService := old.(*api.Service)
//newService.Status = oldService.Status
}
// Validate validates a new service. // Validate validates a new service.
func (svcStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList { func (svcStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList {
service := obj.(*api.Service) service := obj.(*api.Service)

View File

@ -33,6 +33,10 @@ type RESTUpdateStrategy interface {
NamespaceScoped() bool NamespaceScoped() bool
// AllowCreateOnUpdate returns true if the object can be created by a PUT. // AllowCreateOnUpdate returns true if the object can be created by a PUT.
AllowCreateOnUpdate() bool AllowCreateOnUpdate() bool
// PrepareForUpdate is invoked on update before validation to normalize
// the object. For example: remove fields that are not to be persisted,
// sort order-insensitive list fields, etc.
PrepareForUpdate(obj, old runtime.Object)
// ValidateUpdate is invoked after default fields in the object have been filled in before // ValidateUpdate is invoked after default fields in the object have been filled in before
// the object is persisted. // the object is persisted.
ValidateUpdate(obj, old runtime.Object) fielderrors.ValidationErrorList ValidateUpdate(obj, old runtime.Object) fielderrors.ValidationErrorList
@ -53,6 +57,7 @@ func BeforeUpdate(strategy RESTUpdateStrategy, ctx api.Context, obj, old runtime
} else { } else {
objectMeta.Namespace = api.NamespaceNone objectMeta.Namespace = api.NamespaceNone
} }
strategy.PrepareForUpdate(obj, old)
if errs := strategy.ValidateUpdate(obj, old); len(errs) > 0 { if errs := strategy.ValidateUpdate(obj, old); len(errs) > 0 {
return errors.NewInvalid(kind, objectMeta.Name, errs) return errors.NewInvalid(kind, objectMeta.Name, errs)
} }

View File

@ -48,6 +48,14 @@ func (rcStrategy) PrepareForCreate(obj runtime.Object) {
controller.Status = api.ReplicationControllerStatus{} controller.Status = api.ReplicationControllerStatus{}
} }
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
func (rcStrategy) PrepareForUpdate(obj, old runtime.Object) {
// TODO: once RC has a status sub-resource we can enable this.
//newController := obj.(*api.ReplicationController)
//oldController := old.(*api.ReplicationController)
//newController.Status = oldController.Status
}
// Validate validates a new replication controller. // Validate validates a new replication controller.
func (rcStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList { func (rcStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList {
controller := obj.(*api.ReplicationController) controller := obj.(*api.ReplicationController)

View File

@ -48,6 +48,12 @@ func (endpointsStrategy) PrepareForCreate(obj runtime.Object) {
_ = obj.(*api.Endpoints) _ = obj.(*api.Endpoints)
} }
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
func (endpointsStrategy) PrepareForUpdate(obj, old runtime.Object) {
_ = obj.(*api.Endpoints)
_ = old.(*api.Endpoints)
}
// Validate validates a new endpoints. // Validate validates a new endpoints.
func (endpointsStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList { func (endpointsStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList {
return validation.ValidateEndpoints(obj.(*api.Endpoints)) return validation.ValidateEndpoints(obj.(*api.Endpoints))

View File

@ -43,7 +43,8 @@ type testRESTStrategy struct {
func (t *testRESTStrategy) NamespaceScoped() bool { return t.namespaceScoped } func (t *testRESTStrategy) NamespaceScoped() bool { return t.namespaceScoped }
func (t *testRESTStrategy) AllowCreateOnUpdate() bool { return t.allowCreateOnUpdate } func (t *testRESTStrategy) AllowCreateOnUpdate() bool { return t.allowCreateOnUpdate }
func (t *testRESTStrategy) PrepareForCreate(obj runtime.Object) {} func (t *testRESTStrategy) PrepareForCreate(obj runtime.Object) {}
func (t *testRESTStrategy) PrepareForUpdate(obj, old runtime.Object) {}
func (t *testRESTStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList { func (t *testRESTStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList {
return nil return nil
} }

View File

@ -59,6 +59,13 @@ func (nodeStrategy) PrepareForCreate(obj runtime.Object) {
// Nodes allow *all* fields, including status, to be set. // Nodes allow *all* fields, including status, to be set.
} }
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
func (nodeStrategy) PrepareForUpdate(obj, old runtime.Object) {
_ = obj.(*api.Node)
_ = old.(*api.Node)
// Nodes allow *all* fields, including status, to be set.
}
// Validate validates a new node. // Validate validates a new node.
func (nodeStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList { func (nodeStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList {
node := obj.(*api.Node) node := obj.(*api.Node)

View File

@ -68,6 +68,14 @@ func (namespaceStrategy) PrepareForCreate(obj runtime.Object) {
} }
} }
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
func (namespaceStrategy) PrepareForUpdate(obj, old runtime.Object) {
newNamespace := obj.(*api.Namespace)
oldNamespace := old.(*api.Namespace)
newNamespace.Spec.Finalizers = oldNamespace.Spec.Finalizers
newNamespace.Status = oldNamespace.Status
}
// Validate validates a new namespace. // Validate validates a new namespace.
func (namespaceStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList { func (namespaceStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList {
namespace := obj.(*api.Namespace) namespace := obj.(*api.Namespace)
@ -90,6 +98,12 @@ type namespaceStatusStrategy struct {
var StatusStrategy = namespaceStatusStrategy{Strategy} var StatusStrategy = namespaceStatusStrategy{Strategy}
func (namespaceStatusStrategy) PrepareForUpdate(obj, old runtime.Object) {
newNamespace := obj.(*api.Namespace)
oldNamespace := old.(*api.Namespace)
newNamespace.Spec = oldNamespace.Spec
}
func (namespaceStatusStrategy) ValidateUpdate(obj, old runtime.Object) fielderrors.ValidationErrorList { func (namespaceStatusStrategy) ValidateUpdate(obj, old runtime.Object) fielderrors.ValidationErrorList {
return validation.ValidateNamespaceStatusUpdate(obj.(*api.Namespace), old.(*api.Namespace)) return validation.ValidateNamespaceStatusUpdate(obj.(*api.Namespace), old.(*api.Namespace))
} }

View File

@ -59,6 +59,13 @@ func (podStrategy) PrepareForCreate(obj runtime.Object) {
} }
} }
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
func (podStrategy) PrepareForUpdate(obj, old runtime.Object) {
newPod := obj.(*api.Pod)
oldPod := old.(*api.Pod)
newPod.Status = oldPod.Status
}
// Validate validates a new pod. // Validate validates a new pod.
func (podStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList { func (podStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList {
pod := obj.(*api.Pod) pod := obj.(*api.Pod)
@ -86,6 +93,12 @@ type podStatusStrategy struct {
var StatusStrategy = podStatusStrategy{Strategy} var StatusStrategy = podStatusStrategy{Strategy}
func (podStatusStrategy) PrepareForUpdate(obj, old runtime.Object) {
newPod := obj.(*api.Pod)
oldPod := old.(*api.Pod)
newPod.Spec = oldPod.Spec
}
func (podStatusStrategy) ValidateUpdate(obj, old runtime.Object) fielderrors.ValidationErrorList { func (podStatusStrategy) ValidateUpdate(obj, old runtime.Object) fielderrors.ValidationErrorList {
// TODO: merge valid fields after update // TODO: merge valid fields after update
return validation.ValidatePodStatusUpdate(obj.(*api.Pod), old.(*api.Pod)) return validation.ValidatePodStatusUpdate(obj.(*api.Pod), old.(*api.Pod))

View File

@ -49,6 +49,13 @@ func (resourcequotaStrategy) PrepareForCreate(obj runtime.Object) {
resourcequota.Status = api.ResourceQuotaStatus{} resourcequota.Status = api.ResourceQuotaStatus{}
} }
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
func (resourcequotaStrategy) PrepareForUpdate(obj, old runtime.Object) {
newResourcequota := obj.(*api.ResourceQuota)
oldResourcequota := old.(*api.ResourceQuota)
newResourcequota.Status = oldResourcequota.Status
}
// Validate validates a new resourcequota. // Validate validates a new resourcequota.
func (resourcequotaStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList { func (resourcequotaStrategy) Validate(obj runtime.Object) fielderrors.ValidationErrorList {
resourcequota := obj.(*api.ResourceQuota) resourcequota := obj.(*api.ResourceQuota)
@ -71,6 +78,12 @@ type resourcequotaStatusStrategy struct {
var StatusStrategy = resourcequotaStatusStrategy{Strategy} var StatusStrategy = resourcequotaStatusStrategy{Strategy}
func (resourcequotaStatusStrategy) PrepareForUpdate(obj, old runtime.Object) {
newResourcequota := obj.(*api.ResourceQuota)
oldResourcequota := old.(*api.ResourceQuota)
newResourcequota.Spec = oldResourcequota.Spec
}
func (resourcequotaStatusStrategy) ValidateUpdate(obj, old runtime.Object) fielderrors.ValidationErrorList { func (resourcequotaStatusStrategy) ValidateUpdate(obj, old runtime.Object) fielderrors.ValidationErrorList {
return validation.ValidateResourceQuotaStatusUpdate(obj.(*api.ResourceQuota), old.(*api.ResourceQuota)) return validation.ValidateResourceQuotaStatusUpdate(obj.(*api.ResourceQuota), old.(*api.ResourceQuota))
} }