func (p *pluginControl) Start() error {
	p.Started = true
	controlLogger.WithFields(log.Fields{
		"_block": "start",
	}).Info("control started")
	if p.Config.AutoDiscoverPath != "" {
		controlLogger.WithFields(log.Fields{
			"_block": "start",
		}).Info("auto discover path is enabled")
		paths := filepath.SplitList(p.Config.AutoDiscoverPath)
		p.SetAutodiscoverPaths(paths)
		for _, pa := range paths {
			fullPath, err := filepath.Abs(pa)
			if err != nil {
				controlLogger.WithFields(log.Fields{
					"_block":           "start",
					"autodiscoverpath": pa,
				}).Fatal(err)
			}
			controlLogger.WithFields(log.Fields{
				"_block": "start",
			}).Info("autoloading plugins from: ", fullPath)
			files, err := ioutil.ReadDir(fullPath)
			if err != nil {
				controlLogger.WithFields(log.Fields{
					"_block":           "start",
					"autodiscoverpath": pa,
				}).Fatal(err)
			}
			for _, file := range files {
				fileName := file.Name()
				statCheck := file
				if file.Mode()&os.ModeSymlink != 0 {
					realPath, err := filepath.EvalSymlinks(filepath.Join(fullPath, fileName))
					if err != nil {
						controlLogger.WithFields(log.Fields{
							"_block":           "start",
							"autodiscoverpath": pa,
							"error":            err,
							"plugin":           fileName,
						}).Error("Cannot follow symlink")
						continue
					}
					statCheck, err = os.Stat(realPath)
					if err != nil {
						controlLogger.WithFields(log.Fields{
							"_block":           "start",
							"autodiscoverpath": pa,
							"error":            err,
							"plugin":           fileName,
							"target-path":      realPath,
						}).Error("Target of symlink inacessible")
						continue
					}
				}
				if statCheck.IsDir() {
					controlLogger.WithFields(log.Fields{
						"_block":           "start",
						"autodiscoverpath": pa,
					}).Warning("Ignoring subdirectory: ", fileName)
					continue
				}
				fname := strings.ToLower(fileName)
				if strings.HasSuffix(fname, ".json") || strings.HasSuffix(fname, ".yaml") || strings.HasSuffix(fname, ".yml") {
					controlLogger.WithFields(log.Fields{
						"_block":           "start",
						"autodiscoverpath": pa,
					}).Warning("Ignoring JSON/Yaml file: ", fileName)
					continue
				}
				if strings.HasSuffix(fileName, ".aci") || !(strings.HasSuffix(fileName, ".asc")) {
					if (statCheck.Mode() & 0111) == 0 {
						controlLogger.WithFields(log.Fields{
							"_block":           "start",
							"autodiscoverpath": pa,
							"plugin":           fileName,
						}).Warn("Auto-loading of plugin '", fileName, "' skipped (plugin not executable)")
						continue
					}
					rp, err := core.NewRequestedPlugin(path.Join(fullPath, fileName), p.GetTempDir(), nil)
					if err != nil {
						controlLogger.WithFields(log.Fields{
							"_block":           "start",
							"autodiscoverpath": pa,
							"plugin":           fileName,
						}).Error(err)
					}
					signatureFile := fileName + ".asc"
					if _, err := os.Stat(path.Join(fullPath, signatureFile)); err == nil {
						err = rp.ReadSignatureFile(path.Join(fullPath, signatureFile))
						if err != nil {
							controlLogger.WithFields(log.Fields{
								"_block":           "start",
								"autodiscoverpath": pa,
								"plugin":           fileName + ".asc",
							}).Error(err)
						}
					}
					pl, err := p.Load(rp)
					if err != nil {
						controlLogger.WithFields(log.Fields{
							"_block":           "start",
							"autodiscoverpath": fullPath,
							"plugin":           fileName,
						}).Error(err)
					} else {
						controlLogger.WithFields(log.Fields{
							"_block":           "start",
							"autodiscoverpath": fullPath,
							"plugin-file-name": fileName,
							"plugin-name":      pl.Name(),
							"plugin-version":   pl.Version(),
							"plugin-type":      pl.TypeName(),
						}).Info("Loading plugin")
					}
				}
			}
		}
	} else {
		controlLogger.WithFields(log.Fields{
			"_block": "start",
		}).Info("auto discover path is disabled")
	}
	lis, err := net.Listen("tcp", fmt.Sprintf("%v:%v", p.Config.ListenAddr, p.Config.ListenPort))
	if err != nil {
		controlLogger.WithField("error", err.Error()).Error("Failed to start control grpc listener")
		return err
	}
	opts := []grpc.ServerOption{}
	p.closingChan = make(chan bool, 1)
	p.grpcServer = grpc.NewServer(opts...)
	rpc.RegisterMetricManagerServer(p.grpcServer, &ControlGRPCServer{p})
	p.wg.Add(1)
	go func() {
		defer p.wg.Done()
		err := p.grpcServer.Serve(lis)
		if err != nil {
			select {
			case <-p.closingChan:
			default:
				controlLogger.Fatal(err)
			}
		}
	}()
	return nil
}
Begin handling load, unload, and inventory
package control
import (
	"crypto/sha256"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"
	log "github.com/sirupsen/logrus"
	"google.golang.org/grpc"
	"github.com/intelsdi-x/gomit"
	"github.com/intelsdi-x/snap/control/plugin"
	"github.com/intelsdi-x/snap/control/plugin/client"
	"github.com/intelsdi-x/snap/control/strategy"
	"github.com/intelsdi-x/snap/core"
	"github.com/intelsdi-x/snap/core/cdata"
	"github.com/intelsdi-x/snap/core/control_event"
	"github.com/intelsdi-x/snap/core/ctypes"
	"github.com/intelsdi-x/snap/core/serror"
	"github.com/intelsdi-x/snap/grpc/controlproxy/rpc"
	"github.com/intelsdi-x/snap/pkg/aci"
	"github.com/intelsdi-x/snap/pkg/psigning"
)
const (
	PluginTrustDisabled int = iota
	PluginTrustEnabled
	PluginTrustWarn
)
var (
	controlLogger = log.WithFields(log.Fields{
		"_module": "control",
	})
	ErrLoadedPluginNotFound = errors.New("Loaded plugin not found")
	ErrControllerNotStarted = errors.New("Must start Controller before use")
)
type pluginControl struct {
	Started bool
	Config  *Config
	autodiscoverPaths []string
	eventManager      *gomit.EventController
	pluginManager  managesPlugins
	metricCatalog  catalogsMetrics
	pluginRunner   runsPlugins
	signingManager managesSigning
	pluginTrust  int
	keyringFiles []string
	grpcServer  *grpc.Server
	closingChan chan bool
	wg          sync.WaitGroup
	subscriptionGroups ManagesSubscriptionGroups
	grpcSecurity       client.GRPCSecurity
}
type subscribedPlugin struct {
	typeName string
	name     string
	version  int
	config   *cdata.ConfigDataNode
}
func (s subscribedPlugin) TypeName() string              { return s.typeName }
func (s subscribedPlugin) Name() string                  { return s.name }
func (s subscribedPlugin) Version() int                  { return s.version }
func (s subscribedPlugin) Config() *cdata.ConfigDataNode { return s.config }
type runsPlugins interface {
	Start() error
	Stop() []error
	AvailablePlugins() *availablePlugins
	AddDelegates(...gomit.Delegator)
	SetEmitter(gomit.Emitter)
	SetMetricCatalog(catalogsMetrics)
	SetPluginManager(managesPlugins)
	Monitor() *monitor
	runPlugin(string, *pluginDetails) error
	SetPluginLoadTimeout(int)
}
type managesPlugins interface {
	teardown()
	get(string) (*loadedPlugin, error)
	all() map[string]*loadedPlugin
	LoadPlugin(*pluginDetails, gomit.Emitter) (*loadedPlugin, serror.SnapError)
	UnloadPlugin(core.Plugin) (*loadedPlugin, serror.SnapError)
	SetMetricCatalog(catalogsMetrics)
	GenerateArgs(logLevel int) plugin.Arg
	SetPluginConfig(*pluginConfig)
	GetPluginConfig() *pluginConfig
	SetPluginTags(map[string]map[string]string)
	AddStandardAndWorkflowTags(core.Metric, map[string]map[string]string) core.Metric
	SetPluginLoadTimeout(int)
}
type catalogsMetrics interface {
	GetMetric(core.Namespace, int) (*metricType, error)
	GetMetrics(core.Namespace, int) ([]*metricType, error)
	Add(*metricType)
	AddLoadedMetricType(*loadedPlugin, core.Metric) error
	RmUnloadedPluginMetrics(lp *loadedPlugin)
	GetVersions(core.Namespace) ([]*metricType, error)
	Fetch(core.Namespace) ([]*metricType, error)
	Keys() []string
	Subscribe([]string, int) error
	Unsubscribe([]string, int) error
	GetPlugin(core.Namespace, int) (core.CatalogedPlugin, error)
	GetPlugins(core.Namespace) ([]core.CatalogedPlugin, error)
}
type managesSigning interface {
	ValidateSignature([]string, string, []byte) error
}
type PluginControlOpt func(*pluginControl)
func MaxRunningPlugins(m int) PluginControlOpt {
	return func(c *pluginControl) {
		strategy.MaximumRunningPlugins = m
	}
}
func CacheExpiration(t time.Duration) PluginControlOpt {
	return func(c *pluginControl) {
		strategy.GlobalCacheExpiration = t
	}
}
func OptSetConfig(cfg *Config) PluginControlOpt {
	return func(c *pluginControl) {
		c.Config = cfg
		c.pluginManager.SetPluginConfig(cfg.Plugins)
		c.pluginManager.SetPluginLoadTimeout(c.Config.PluginLoadTimeout)
		c.pluginRunner.SetPluginLoadTimeout(c.Config.PluginLoadTimeout)
	}
}
func OptSetTags(tags map[string]map[string]string) PluginControlOpt {
	return func(c *pluginControl) {
		c.pluginManager.SetPluginTags(tags)
	}
}
func MaxPluginRestarts(cfg *Config) PluginControlOpt {
	return func(*pluginControl) {
		MaxPluginRestartCount = cfg.MaxPluginRestarts
	}
}
func New(cfg *Config) *pluginControl {
	opts := []PluginControlOpt{
		MaxRunningPlugins(cfg.MaxRunningPlugins),
		CacheExpiration(cfg.CacheExpiration.Duration),
		OptSetConfig(cfg),
		OptSetTags(cfg.Tags),
		MaxPluginRestarts(cfg),
	}
	c := &pluginControl{}
	c.Config = cfg
	c.eventManager = gomit.NewEventController()
	controlLogger.WithFields(log.Fields{
		"_block": "new",
	}).Debug("pevent controller created")
	c.metricCatalog = newMetricCatalog()
	controlLogger.WithFields(log.Fields{
		"_block": "new",
	}).Debug("metric catalog created")
	managerOpts := []pluginManagerOpt{
		OptSetPprof(cfg.Pprof),
		OptSetTempDirPath(cfg.TempDirPath),
	}
	runnerOpts := []pluginRunnerOpt{}
	if cfg.IsTLSEnabled() {
		if cfg.CACertPaths != "" {
			certPaths := filepath.SplitList(cfg.CACertPaths)
			c.grpcSecurity = client.SecurityTLSExtended(cfg.TLSCertPath, cfg.TLSKeyPath, client.SecureClient, certPaths)
		} else {
			c.grpcSecurity = client.SecurityTLSEnabled(cfg.TLSCertPath, cfg.TLSKeyPath, client.SecureClient)
		}
		managerOpts = append(managerOpts, OptEnableManagerTLS(c.grpcSecurity))
		runnerOpts = append(runnerOpts, OptEnableRunnerTLS(c.grpcSecurity))
	}
	c.pluginManager = newPluginManager(managerOpts...)
	controlLogger.WithFields(log.Fields{
		"_block": "new",
	}).Debug("plugin manager created")
	c.pluginManager.SetMetricCatalog(c.metricCatalog)
	c.signingManager = &psigning.SigningManager{}
	controlLogger.WithFields(log.Fields{
		"_block": "new",
	}).Debug("signing manager created")
	c.pluginRunner = newRunner(runnerOpts...)
	controlLogger.WithFields(log.Fields{
		"_block": "new",
	}).Debug("runner created")
	c.pluginRunner.AddDelegates(c.eventManager)
	c.pluginRunner.SetEmitter(c.eventManager)
	c.pluginRunner.SetMetricCatalog(c.metricCatalog)
	c.pluginRunner.SetPluginManager(c.pluginManager)
	c.eventManager.RegisterHandler(c.Name(), c)
	c.subscriptionGroups = newSubscriptionGroups(c)
	err := c.pluginRunner.Start()
	if err != nil {
		panic(err)
	}
	for _, opt := range opts {
		opt(c)
	}
	return c
}
func (p *pluginControl) HandleGomitEvent(e gomit.Event) {
	switch v := e.Body.(type) {
	case *control_event.LoadPluginEvent:
		serrs := p.subscriptionGroups.Process()
		if serrs != nil {
			for _, err := range serrs {
				controlLogger.WithFields(log.Fields{
					"_block": "LoadPluginEvent",
				}).Error(err)
			}
		}
	case *control_event.UnloadPluginEvent:
		serrs := p.subscriptionGroups.Process()
		if serrs != nil {
			for _, err := range serrs {
				controlLogger.WithFields(log.Fields{
					"_block": "UnloadPluginEvent",
				}).Error(err)
			}
		}
	default:
		runnerLog.WithFields(log.Fields{
			"_block": "handle-events",
			"event":  v.Namespace(),
		}).Info("Nothing to do for this event")
	}
}
func (p *pluginControl) Name() string {
	return "control"
}
func (p *pluginControl) RegisterEventHandler(name string, h gomit.Handler) error {
	return p.eventManager.RegisterHandler(name, h)
}