func (s *k8sSyncer) mutateFn() controllerutil.MutateFn {
	return func() error {
		s.previousOwnee = s.ownee.DeepCopyObject()
		err := s.userMutateFn()
		if err != nil {
			return err
		}
		if s.owner != nil {
			owneeMeta, ok := s.ownee.(metav1.Object)
			if !ok {
				return errors.Errorf("%s is not a metav1.Object", s.owneeType())
			}
			ownerMeta, ok := s.owner.(metav1.Object)
			if !ok {
				return errors.Errorf("%s is not a metav1.Object", s.ownerType())
			}
			if ownerMeta.GetDeletionTimestamp().IsZero() {
				err := controllerutil.SetControllerReference(ownerMeta, owneeMeta, s.Scheme)
				if err != nil {
					return err
				}
			} else if ctime := owneeMeta.GetCreationTimestamp(); ctime.IsZero() {
				return ErrOwnerDeleted
			}
		}
		return nil
	}
}
mutateFn wraps user-defined mutateFn by setting owner reference if it has.
package syncer
import (
	"context"
	"fmt"
	"github.com/megaease/easemesh/mesh-operator/pkg/base"
	"github.com/go-logr/logr"
	"github.com/go-test/deep"
	"github.com/pkg/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)
const (
	eventNormal  = "Normal"
	eventWarning = "Warning"
)
var (
	ErrOwnerDeleted = errors.New("Owner has been deleted")
	ErrIgnored = errors.New("ignored error")
)
type k8sSyncer struct {
	*base.Runtime
	log logr.Logger
	owner         client.Object
	ownee         client.Object
	previousOwnee runtime.Object
	userMutateFn  controllerutil.MutateFn
}
var _ Syncer = &k8sSyncer{}
func (s *k8sSyncer) Object() client.Object {
	return s.ownee
}
func (s *k8sSyncer) ObjectOwner() client.Object {
	return s.owner
}
func (s *k8sSyncer) owneeType() string {
	return fmt.Sprintf("%T", s.ownee)
}
func (s *k8sSyncer) ownerType() string {
	return fmt.Sprintf("%T", s.owner)
}
func (s *k8sSyncer) Sync(ctx context.Context) (SyncResult, error) {
	result := SyncResult{}
	id, err := idOfObject(s.ownee)
	if err != nil {
		return result, err
	}
	result.Operation, err = controllerutil.CreateOrUpdate(ctx, s.Client, s.ownee, s.mutateFn())
	diff := deep.Equal(stripSecrets(s.previousOwnee), stripSecrets(s.ownee))
	if err == ErrOwnerDeleted {
		s.log.Info(string(result.Operation), "id", id, "ownerKind", s.ownerType(), "message", err)
		err = nil
	} else if err == ErrIgnored {
		s.log.V(1).Info("syncer skipped", "id", id, "owneeKind", s.owneeType())
		err = nil
	} else if err != nil {
		result.SetEventData(eventWarning, basicEventReason(s.Name, err),
			fmt.Sprintf("%s %s failed syncing: %s", s.owneeType(), id, err))
		s.log.V(1).Error(err, string(result.Operation), "id", id, "owneeKind", s.owneeType(), "diff", diff)
	} else {
		result.SetEventData(eventNormal, basicEventReason(s.Name, err),
			fmt.Sprintf("%s %s %s successfully", s.owneeType(), id, result.Operation))
		s.log.V(1).Info(string(result.Operation), "id", id, "owneeKind", s.owneeType(), "diff", diff)
	}
	return result, err
}