func (p *Plugin) initializeCRDs() error {
	nodeConfigInformer := p.sharedFactory.Nodeconfig().V1().NodeConfigs().Informer()
	p.nodeConfigController = &controller.CrdController{
		Deps: controller.Deps{
			Log:       p.Log.NewLogger("nodeConfigController"),
			APIClient: p.apiclientset,
			Informer:  nodeConfigInformer,
			EventHandler: &kvdbreflector.KvdbReflector{
				Deps: kvdbreflector.Deps{
					Log:          p.Log.NewLogger("nodeConfigHandler"),
					ServiceLabel: p.ServiceLabel,
					Publish:      p.Etcd.RawAccess(),
					Informer:     nodeConfigInformer,
					Handler: &nodeconfig.Handler{
						CrdClient: p.crdClient,
					},
				},
			},
		},
		Spec: controller.CrdSpec{
			TypeName: reflect.TypeOf(nodeconfigv1.NodeConfig{}).Name(),
			Group:    nodeconfigv1.CRDGroup,
			Version:  nodeconfigv1.CRDGroupVersion,
			Plural:   nodeconfigv1.CRDContivNodeConfigPlural,
		},
	}
	customNetworkInformer := p.sharedFactory.Contivpp().V1().CustomNetworks().Informer()
	p.customNetworkController = &controller.CrdController{
		Deps: controller.Deps{
			Log:       p.Log.NewLogger("customNetworkController"),
			APIClient: p.apiclientset,
			Informer:  customNetworkInformer,
			EventHandler: &kvdbreflector.KvdbReflector{
				Deps: kvdbreflector.Deps{
					Log:          p.Log.NewLogger("customNetworkHandler"),
					ServiceLabel: p.ServiceLabel,
					Publish:      p.Etcd.RawAccess(),
					Informer:     customNetworkInformer,
					Handler: &customnetwork.Handler{
						CrdClient: p.crdClient,
					},
				},
			},
		},
		Spec: controller.CrdSpec{
			TypeName:   reflect.TypeOf(v1.CustomNetwork{}).Name(),
			Group:      contivppio.GroupName,
			Version:    "v1",
			Plural:     "customnetworks",
			Validation: customnetwork.Validation(),
		},
	}
	externalInterfaceInformer := p.sharedFactory.Contivpp().V1().ExternalInterfaces().Informer()
	p.externalInterfaceController = &controller.CrdController{
		Deps: controller.Deps{
			Log:       p.Log.NewLogger("externalInterfaceController"),
			APIClient: p.apiclientset,
			Informer:  externalInterfaceInformer,
			EventHandler: &kvdbreflector.KvdbReflector{
				Deps: kvdbreflector.Deps{
					Log:          p.Log.NewLogger("externalInterfaceHandler"),
					ServiceLabel: p.ServiceLabel,
					Publish:      p.Etcd.RawAccess(),
					Informer:     externalInterfaceInformer,
					Handler: &externalinterface.Handler{
						CrdClient: p.crdClient,
					},
				},
			},
		},
		Spec: controller.CrdSpec{
			TypeName:   reflect.TypeOf(v1.ExternalInterface{}).Name(),
			Group:      contivppio.GroupName,
			Version:    "v1",
			Plural:     "externalinterfaces",
			Validation: externalinterface.Validation(),
		},
	}
	serviceFunctionChainInformer := p.sharedFactory.Contivpp().V1().ServiceFunctionChains().Informer()
	p.serviceFunctionChainController = &controller.CrdController{
		Deps: controller.Deps{
			Log:       p.Log.NewLogger("serviceFunctionChainController"),
			APIClient: p.apiclientset,
			Informer:  serviceFunctionChainInformer,
			EventHandler: &kvdbreflector.KvdbReflector{
				Deps: kvdbreflector.Deps{
					Log:          p.Log.NewLogger("serviceFunctionChainHandler"),
					ServiceLabel: p.ServiceLabel,
					Publish:      p.Etcd.RawAccess(),
					Informer:     serviceFunctionChainInformer,
					Handler: &servicefunctionchain.Handler{
						CrdClient: p.crdClient,
					},
				},
			},
		},
		Spec: controller.CrdSpec{
			TypeName:   reflect.TypeOf(v1.ServiceFunctionChain{}).Name(),
			Group:      contivppio.GroupName,
			Version:    "v1",
			Plural:     "servicefunctionchains",
			Validation: servicefunctionchain.Validation(),
		},
	}
	customConfigInformer := p.sharedFactory.Contivpp().V1().CustomConfigurations().Informer()
	customConfigLog := p.Log.NewLogger("customConfigHandler")
	p.customConfigController = &controller.CrdController{
		Deps: controller.Deps{
			Log:       p.Log.NewLogger("customConfigController"),
			APIClient: p.apiclientset,
			Informer:  customConfigInformer,
			EventHandler: &kvdbreflector.KvdbReflector{
				Deps: kvdbreflector.Deps{
					Log:          customConfigLog,
					ServiceLabel: p.ServiceLabel,
					Publish:      p.Etcd.RawAccess(),
					Informer:     customConfigInformer,
					Handler: &customconfiguration.Handler{
						Log:       customConfigLog,
						CrdClient: p.crdClient,
					},
				},
			},
		},
		Spec: controller.CrdSpec{
			TypeName:   reflect.TypeOf(v1.CustomConfiguration{}).Name(),
			Group:      contivppio.GroupName,
			Version:    "v1",
			Plural:     "customconfigurations",
			Validation: customconfiguration.Validation(),
		},
	}
	p.nodeConfigController.Init()
	p.customNetworkController.Init()
	p.externalInterfaceController.Init()
	p.serviceFunctionChainController.Init()
	p.customConfigController.Init()
	if p.verbose {
		p.customNetworkController.Log.SetLevel(logging.DebugLevel)
		p.nodeConfigController.Log.SetLevel(logging.DebugLevel)
		p.externalInterfaceController.Log.SetLevel(logging.DebugLevel)
		p.serviceFunctionChainController.Log.SetLevel(logging.DebugLevel)
		p.customConfigController.Log.SetLevel(logging.DebugLevel)
		customConfigLog.SetLevel(logging.DebugLevel)
	}
	return nil
}
initializeCRDs initializes and starts controllers for all CRDs except for Telemetry (which is initialized
by initializeTelemetry()).
Must be run *after* (first) connection with etcd has been established.
package crd
import (
	"context"
	"fmt"
	"os"
	"reflect"
	"strconv"
	"sync"
	"time"
	crdClientSet "github.com/contiv/vpp/plugins/crd/pkg/client/clientset/versioned"
	nodemodel "github.com/contiv/vpp/plugins/ksr/model/node"
	podmodel "github.com/contiv/vpp/plugins/ksr/model/pod"
	vppnodemodel "github.com/contiv/vpp/plugins/nodesync/vppnode"
	"github.com/namsral/flag"
	"k8s.io/client-go/tools/clientcmd"
	"github.com/contiv/vpp/plugins/crd/utils"
	"go.ligato.io/cn-infra/v2/config"
	"go.ligato.io/cn-infra/v2/datasync"
	"go.ligato.io/cn-infra/v2/datasync/resync"
	"go.ligato.io/cn-infra/v2/db/keyval/etcd"
	"go.ligato.io/cn-infra/v2/infra"
	"go.ligato.io/cn-infra/v2/logging"
	"go.ligato.io/cn-infra/v2/rpc/rest"
	"go.ligato.io/cn-infra/v2/servicelabel"
	"go.ligato.io/cn-infra/v2/utils/safeclose"
	"github.com/contiv/vpp/plugins/crd/api"
	"github.com/contiv/vpp/plugins/crd/cache"
	"github.com/contiv/vpp/plugins/crd/controller"
	"github.com/contiv/vpp/plugins/crd/handler/customconfiguration"
	"github.com/contiv/vpp/plugins/crd/handler/customnetwork"
	"github.com/contiv/vpp/plugins/crd/handler/externalinterface"
	"github.com/contiv/vpp/plugins/crd/handler/kvdbreflector"
	"github.com/contiv/vpp/plugins/crd/handler/nodeconfig"
	"github.com/contiv/vpp/plugins/crd/handler/servicefunctionchain"
	"github.com/contiv/vpp/plugins/crd/handler/telemetry"
	"github.com/contiv/vpp/plugins/crd/validator"
	"github.com/contiv/vpp/plugins/crd/pkg/apis/contivppio"
	v1 "github.com/contiv/vpp/plugins/crd/pkg/apis/contivppio/v1"
	nodeconfigv1 "github.com/contiv/vpp/plugins/crd/pkg/apis/nodeconfig/v1"
	telemetryv1 "github.com/contiv/vpp/plugins/crd/pkg/apis/telemetry/v1"
	factory "github.com/contiv/vpp/plugins/crd/pkg/client/informers/externalversions"
	apiextcs "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
)
const (
	k8sResyncInterval = 10 * time.Minute
)
type Plugin struct {
	Deps
	resyncChan chan datasync.ResyncEvent
	changeChan chan datasync.ChangeEvent
	watchConfigReg datasync.WatchRegistration
	resyncLock sync.Mutex
	ctx        context.Context
	cancel     context.CancelFunc
	wg         sync.WaitGroup
	resyncCounter  uint
	pendingResync  datasync.ResyncEvent
	pendingChanges []datasync.ChangeEvent
	telemetryController            *controller.CrdController
	nodeConfigController           *controller.CrdController
	customNetworkController        *controller.CrdController
	externalInterfaceController    *controller.CrdController
	serviceFunctionChainController *controller.CrdController
	customConfigController         *controller.CrdController
	cache                          *cache.ContivTelemetryCache
	processor                      api.ContivTelemetryProcessor
	verbose                        bool
	crdClient     *crdClientSet.Clientset
	apiclientset  *apiextcs.Clientset
	sharedFactory factory.SharedInformerFactory
}
type Deps struct {
	infra.PluginDeps
	ServiceLabel servicelabel.ReaderAPI
	KubeConfig config.PluginConfig
	Resync resync.Subscriber
	HTTP rest.HTTPHandlers
	Watcher datasync.KeyValProtoWatcher
	Etcd    *etcd.Plugin  
}
const electionPrefix = "/contiv-crd/election"
func (p *Plugin) Init() error {
	var err error
	p.Log.SetLevel(logging.DebugLevel)
	p.verbose = flag.Lookup("verbose").Value.String() == "true"
	netctlRESTdisabled := os.Getenv("DISABLE_NETCTL_REST")
	if netctlRESTdisabled == "" {
		p.HTTP.RegisterHTTPHandler("/netctl", utils.HandleNetctlCommand, "POST")
	}
	p.resyncChan = make(chan datasync.ResyncEvent)
	p.changeChan = make(chan datasync.ChangeEvent)
	p.ctx, p.cancel = context.WithCancel(context.Background())
	kubeconfig := p.KubeConfig.GetConfigName()
	p.Log.WithField("kubeconfig", kubeconfig).Info("Loading kubernetes client config")
	k8sClientConfig, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
	if err != nil {
		return fmt.Errorf("failed to build kubernetes client config: %s", err)
	}
	p.crdClient, err = crdClientSet.NewForConfig(k8sClientConfig)
	if err != nil {
		return fmt.Errorf("failed to build crd Client: %s", err)
	}
	p.apiclientset, err = apiextcs.NewForConfig(k8sClientConfig)
	if err != nil {
		return fmt.Errorf("failed to build api Client: %s", err)
	}
	p.sharedFactory = factory.NewSharedInformerFactory(p.crdClient, k8sResyncInterval)
	err = p.initializeTelemetry()
	if err != nil {
		return err
	}
	go p.watchEvents()
	err = p.subscribeWatcher()
	if err != nil {
		return err
	}
	p.Etcd.OnConnect(p.onEtcdConnect)
	return nil
}