@@ -22,6 +22,33 @@ var (
|
|||||||
_ grafanarest.Storage = (*dualWriter)(nil)
|
_ grafanarest.Storage = (*dualWriter)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func objectInfo(obj runtime.Object) map[string]interface{} {
|
||||||
|
if obj == nil {
|
||||||
|
return map[string]interface{}{"object": "nil"}
|
||||||
|
}
|
||||||
|
|
||||||
|
acc, err := meta.Accessor(obj)
|
||||||
|
if err != nil {
|
||||||
|
return map[string]interface{}{"object": fmt.Sprintf("%T", obj), "error": err.Error()}
|
||||||
|
}
|
||||||
|
|
||||||
|
info := map[string]interface{}{
|
||||||
|
"name": acc.GetName(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if ns := acc.GetNamespace(); ns != "" {
|
||||||
|
info["namespace"] = ns
|
||||||
|
}
|
||||||
|
if uid := acc.GetUID(); uid != "" {
|
||||||
|
info["uid"] = string(uid)
|
||||||
|
}
|
||||||
|
if rv := acc.GetResourceVersion(); rv != "" {
|
||||||
|
info["resourceVersion"] = rv
|
||||||
|
}
|
||||||
|
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
// Let's give the background queries a bit more time to complete
|
// Let's give the background queries a bit more time to complete
|
||||||
// as we also run them as part of load tests that might need longer
|
// as we also run them as part of load tests that might need longer
|
||||||
// to complete. Those run in the background and won't impact the
|
// to complete. Those run in the background and won't impact the
|
||||||
@@ -45,7 +72,7 @@ func (d *dualWriter) Get(ctx context.Context, name string, options *metav1.GetOp
|
|||||||
// If legacy is still our main store, lets first read from it.
|
// If legacy is still our main store, lets first read from it.
|
||||||
legacyGet, err := d.legacy.Get(ctx, name, options)
|
legacyGet, err := d.legacy.Get(ctx, name, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("failed to get object from legacy storage", "err", err)
|
log.Error("failed to GET object from legacy storage", "err", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Once we have successfully read from legacy, we can check if we want to fail on a unified read.
|
// Once we have successfully read from legacy, we can check if we want to fail on a unified read.
|
||||||
@@ -62,7 +89,7 @@ func (d *dualWriter) Get(ctx context.Context, name string, options *metav1.GetOp
|
|||||||
// If it's not okay to fail, we have to check it in the foreground.
|
// If it's not okay to fail, we have to check it in the foreground.
|
||||||
_, unifiedErr := d.unified.Get(ctx, name, options)
|
_, unifiedErr := d.unified.Get(ctx, name, options)
|
||||||
if unifiedErr != nil && !apierrors.IsNotFound(unifiedErr) {
|
if unifiedErr != nil && !apierrors.IsNotFound(unifiedErr) {
|
||||||
log.Error("failed to get object from unified storage", "err", unifiedErr)
|
log.Error("failed to GET object from unified storage", "err", unifiedErr)
|
||||||
return nil, unifiedErr
|
return nil, unifiedErr
|
||||||
}
|
}
|
||||||
return legacyGet, nil
|
return legacyGet, nil
|
||||||
@@ -212,7 +239,7 @@ func (d *dualWriter) Create(ctx context.Context, in runtime.Object, createValida
|
|||||||
// will try to cleanup the object in legacy.
|
// will try to cleanup the object in legacy.
|
||||||
createdFromLegacy, err := d.legacy.Create(ctx, in, createValidation, options)
|
createdFromLegacy, err := d.legacy.Create(ctx, in, createValidation, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.With("object", in).Error("failed to CREATE object in legacy storage", "err", err)
|
log.With("objectInfo", objectInfo(in)).Error("failed to CREATE object in legacy storage", "err", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,7 +266,7 @@ func (d *dualWriter) Create(ctx context.Context, in runtime.Object, createValida
|
|||||||
if d.readUnified {
|
if d.readUnified {
|
||||||
storageObj, errObjectSt := d.unified.Create(ctx, createdCopy, createValidation, options)
|
storageObj, errObjectSt := d.unified.Create(ctx, createdCopy, createValidation, options)
|
||||||
if errObjectSt != nil {
|
if errObjectSt != nil {
|
||||||
log.With("object", createdCopy).Error("failed to CREATE object in unified storage", "err", errObjectSt)
|
log.With("objectInfo", objectInfo(createdCopy)).Error("failed to CREATE object in unified storage", "err", errObjectSt)
|
||||||
// If we cannot create in unified storage, attempt to clean up legacy.
|
// If we cannot create in unified storage, attempt to clean up legacy.
|
||||||
go func(ctxBg context.Context, cancel context.CancelFunc) {
|
go func(ctxBg context.Context, cancel context.CancelFunc) {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -255,13 +282,13 @@ func (d *dualWriter) Create(ctx context.Context, in runtime.Object, createValida
|
|||||||
go func(ctxBg context.Context, cancel context.CancelFunc) {
|
go func(ctxBg context.Context, cancel context.CancelFunc) {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if _, err := d.unified.Create(ctxBg, createdCopy, createValidation, options); err != nil {
|
if _, err := d.unified.Create(ctxBg, createdCopy, createValidation, options); err != nil {
|
||||||
log.With("object", createdCopy).Error("failed to CREATE object in unified storage", "err", err)
|
log.With("objectInfo", objectInfo(createdCopy)).Error("failed to CREATE object in unified storage", "err", err)
|
||||||
}
|
}
|
||||||
}(context.WithTimeout(context.WithoutCancel(ctx), backgroundReqTimeout))
|
}(context.WithTimeout(context.WithoutCancel(ctx), backgroundReqTimeout))
|
||||||
} else {
|
} else {
|
||||||
// Otherwise let's create it in the foreground and return any error.
|
// Otherwise let's create it in the foreground and return any error.
|
||||||
if _, err := d.unified.Create(ctx, createdCopy, createValidation, options); err != nil {
|
if _, err := d.unified.Create(ctx, createdCopy, createValidation, options); err != nil {
|
||||||
log.With("object", createdCopy).Error("failed to CREATE object in unified storage", "err", err)
|
log.With("objectInfo", objectInfo(createdCopy)).Error("failed to CREATE object in unified storage", "err", err)
|
||||||
if d.errorIsOK {
|
if d.errorIsOK {
|
||||||
return createdFromLegacy, nil
|
return createdFromLegacy, nil
|
||||||
}
|
}
|
||||||
@@ -330,7 +357,7 @@ func (d *dualWriter) Delete(ctx context.Context, name string, deleteValidation r
|
|||||||
|
|
||||||
// Update overrides the behavior of the generic DualWriter and writes first to Storage and then to LegacyStorage.
|
// Update overrides the behavior of the generic DualWriter and writes first to Storage and then to LegacyStorage.
|
||||||
func (d *dualWriter) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
|
func (d *dualWriter) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) {
|
||||||
log := logging.FromContext(ctx).With("method", "Update", "name", name, "objInfo", objInfo)
|
log := logging.FromContext(ctx).With("method", "Update", "name", name)
|
||||||
|
|
||||||
// update in legacy first, and then unistore. Will return a failure if either fails.
|
// update in legacy first, and then unistore. Will return a failure if either fails.
|
||||||
//
|
//
|
||||||
@@ -378,14 +405,14 @@ func (d *dualWriter) Update(ctx context.Context, name string, objInfo rest.Updat
|
|||||||
go func(ctxBg context.Context, cancel context.CancelFunc) {
|
go func(ctxBg context.Context, cancel context.CancelFunc) {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if _, _, err := d.unified.Update(ctxBg, name, unifiedInfo, createValidation, updateValidation, unifiedForceCreate, options); err != nil {
|
if _, _, err := d.unified.Update(ctxBg, name, unifiedInfo, createValidation, updateValidation, unifiedForceCreate, options); err != nil {
|
||||||
log.Error("failed background UPDATE to unified storage", "err", err)
|
log.With("objectInfo", objectInfo(objFromLegacy)).Error("failed background UPDATE to unified storage", "err", err)
|
||||||
}
|
}
|
||||||
}(context.WithTimeout(context.WithoutCancel(ctx), backgroundReqTimeout))
|
}(context.WithTimeout(context.WithoutCancel(ctx), backgroundReqTimeout))
|
||||||
return objFromLegacy, createdLegacy, nil
|
return objFromLegacy, createdLegacy, nil
|
||||||
}
|
}
|
||||||
// If we want to check unified errors just run it in foreground.
|
// If we want to check unified errors just run it in foreground.
|
||||||
if _, _, err := d.unified.Update(ctx, name, unifiedInfo, createValidation, updateValidation, unifiedForceCreate, options); err != nil {
|
if _, _, err := d.unified.Update(ctx, name, unifiedInfo, createValidation, updateValidation, unifiedForceCreate, options); err != nil {
|
||||||
log.Error("failed to UPDATE in unified storage", "err", err)
|
log.With("objectInfo", objectInfo(objFromLegacy)).Error("failed to UPDATE in unified storage", "err", err)
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
return objFromLegacy, createdLegacy, nil
|
return objFromLegacy, createdLegacy, nil
|
||||||
@@ -415,14 +442,14 @@ func (d *dualWriter) DeleteCollection(ctx context.Context, deleteValidation rest
|
|||||||
go func(ctxBg context.Context, cancel context.CancelFunc) {
|
go func(ctxBg context.Context, cancel context.CancelFunc) {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if _, err := d.unified.DeleteCollection(ctxBg, deleteValidation, options, listOptions); err != nil {
|
if _, err := d.unified.DeleteCollection(ctxBg, deleteValidation, options, listOptions); err != nil {
|
||||||
log.With("object", deletedLegacy).Error("failed background DELETE collection to unified storage", "err", err)
|
log.With("objectInfo", objectInfo(deletedLegacy)).Error("failed background DELETE collection to unified storage", "err", err)
|
||||||
}
|
}
|
||||||
}(context.WithTimeout(context.WithoutCancel(ctx), backgroundReqTimeout))
|
}(context.WithTimeout(context.WithoutCancel(ctx), backgroundReqTimeout))
|
||||||
return deletedLegacy, nil
|
return deletedLegacy, nil
|
||||||
}
|
}
|
||||||
// Otherwise we have to check the error and run it in the foreground.
|
// Otherwise we have to check the error and run it in the foreground.
|
||||||
if _, err := d.unified.DeleteCollection(ctx, deleteValidation, options, listOptions); err != nil {
|
if _, err := d.unified.DeleteCollection(ctx, deleteValidation, options, listOptions); err != nil {
|
||||||
log.With("object", deletedLegacy).Error("failed to DELETE collection successfully from Storage", "err", err)
|
log.With("objectInfo", objectInfo(deletedLegacy)).Error("failed to DELETE collection successfully from Storage", "err", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return deletedLegacy, nil
|
return deletedLegacy, nil
|
||||||
|
|||||||
Reference in New Issue
Block a user