Example #1
0
func New(c *Config) (cer Cerebrum, err error) {

	// Create logger
	if c.LogOutput == nil {
		c.LogOutput = log.NewConcurrentWriter(os.Stderr)
	}
	logger := log.NewLogger(c.LogOutput, "kappa")

	// Create data directory
	if err = os.MkdirAll(c.DataPath, 0755); err != nil {
		logger.Warn("Could not create data directory", "err", err)
		return
	}

	// Setup reconciler
	serfEventCh := make(chan serf.Event, 256)
	reconcilerCh := make(chan serf.Member, 32)

	ctx, cancel := context.WithCancel(context.Background())
	cereb := &cerebrum{
		config:      c,
		logger:      logger,
		dialer:      NewDialer(NewPool(c.LogOutput, 5*time.Minute, c.TLSConfig)),
		serfEventCh: serfEventCh,
		reconcileCh: reconcilerCh,
		grim:        grim.ReaperWithContext(ctx),
		context:     ctx,
		cancel:      cancel,
	}

	// Create serf server
	err = cereb.setupRaft()
	if err != nil {
		err = logger.Error("Failed to start serf: %v", err)
		return nil, err
	}

	isLeader := func() bool { return cereb.raft.State() == raft.Leader }
	reconciler := &Reconciler{reconcilerCh, isLeader}
	cereb.serfer = serfer.NewSerfer(serfEventCh, serfer.SerfEventHandler{
		Logger:              log.NewLogger(c.LogOutput, CerebrumEventPrefix),
		ServicePrefix:       CerebrumEventPrefix,
		ReconcileOnJoin:     true,
		ReconcileOnLeave:    true,
		ReconcileOnFail:     true,
		ReconcileOnUpdate:   true,
		ReconcileOnReap:     true,
		NodeJoined:          c.NodeJoined,
		NodeUpdated:         c.NodeUpdated,
		NodeLeft:            c.NodeLeft,
		NodeFailed:          c.NodeFailed,
		NodeReaped:          c.NodeReaped,
		UserEvent:           c.UserEvent,
		UnknownEventHandler: c.UnknownEventHandler,
		Reconciler:          reconciler,
		IsLeader:            isLeader,
		IsLeaderEvent: func(name string) bool {
			return name == CerebrumLeaderEvent
		},
		LeaderElectionHandler: cereb,
	})

	// Create serf server
	cereb.serf, err = cereb.setupSerf()
	if err != nil {
		err = logger.Error("Failed to start serf: %v", err)
		return nil, err
	}

	cer = cereb
	return cer, nil
}
Example #2
0
func NewServer(c *DatabaseConfig) (server *Server, err error) {

	// Create logger
	if c.LogOutput == nil {
		c.LogOutput = log.NewConcurrentWriter(os.Stdout)
	}
	logger := log.NewLogger(c.LogOutput, "kappa")

	// Create data directory
	if err = os.MkdirAll(c.DataPath, 0755); err != nil {
		logger.Warn("Could not create data directory", "err", err)
		// logger.Warn("Could not create data directory", "err", err.Error())
		return
	}

	// Connect to database
	cwd, err := os.Getwd()
	if err != nil {
		logger.Error("Could not get working directory", "error", err.Error())
		return
	}

	file := path.Join(cwd, c.DataPath, "meta.db")
	logger.Info("Connecting to database", "file", file)
	system, err := datamodel.NewSystem(file)
	if err != nil {
		logger.Error("Could not connect to database", "error", err.Error())
		return
	}

	// Get SSH Key file
	sshKeyFile := c.SSHPrivateKeyFile
	logger.Info("Reading private key", "file", sshKeyFile)

	privateKey, err := auth.ReadPrivateKey(logger, sshKeyFile)
	if err != nil {
		return
	}

	// Get admin certificate
	adminCertFile := c.AdminCertificateFile
	logger.Info("Reading admin public key", "file", adminCertFile)

	// Read admin certificate
	cert, err := ioutil.ReadFile(adminCertFile)
	if err != nil {
		logger.Error("admin certificate could not be read", "filename", c.AdminCertificateFile)
		return
	}

	// Add admin cert to key ring
	userStore, err := system.Users()
	if err != nil {
		logger.Error("could not get user store", "error", err.Error())
		return
	}

	// Create admin account
	admin, err := userStore.Create("admin")
	if err != nil {
		logger.Error("error creating admin account", "error", err.Error())
		return
	}

	// Add admin certificate
	keyRing := admin.KeyRing()
	fingerprint, err := keyRing.AddPublicKey(cert)
	if err != nil {
		logger.Error("admin certificate could not be added", "error", err.Error())
		return
	}
	logger.Info("Added admin certificate", "fingerprint", fingerprint)

	// Read root cert
	rootPem, err := ioutil.ReadFile(c.CACertificateFile)
	if err != nil {
		logger.Error("root certificate could not be read", "filename", c.CACertificateFile)
		return
	}

	// Create certificate pool
	roots := x509.NewCertPool()
	if ok := roots.AppendCertsFromPEM(rootPem); !ok {
		logger.Error("failed to parse root certificate")
		return
	}

	// Setup SSH Server
	sshLogger := log.NewLogger(c.LogOutput, "ssh")
	pubKeyCallback, err := PublicKeyCallback(system)
	if err != nil {
		logger.Error("failed to create PublicKeyCallback", err)
		return
	}

	// Setup server config
	config := sshh.Config{
		Deadline:          c.SSHConnectionDeadline,
		Logger:            sshLogger,
		Bind:              c.SSHBindAddress,
		PrivateKey:        privateKey,
		PublicKeyCallback: pubKeyCallback,
		AuthLogCallback: func(meta ssh.ConnMetadata, method string, err error) {
			if err == nil {
				sshLogger.Info("login success", "user", meta.User())
			} else if err != nil && method == "publickey" {
				sshLogger.Info("login failure", "user", meta.User(), "err", err.Error())
			}
		},
		Handlers: map[string]sshh.SSHHandler{
			"kappa-client": &EchoHandler{},
		},
	}

	// Create SSH server
	sshServer, err := sshh.NewSSHServer(&config)
	if err != nil {
		logger.Error("SSH Server could not be configured", "error", err.Error())
		return
	}

	// Setup Serf handlers
	mgr := NewNodeList()
	reconcilerCh := make(chan serf.Member, 32)
	serfEventCh := make(chan serf.Event, 256)
	userEventCh := make(chan serf.UserEvent, 256)
	serfer := serfer.NewSerfer(serfEventCh, serfer.SerfEventHandler{
		Logger:            log.NewLogger(c.LogOutput, "serf"),
		ServicePrefix:     "kappa",
		ReconcileOnJoin:   true,
		ReconcileOnLeave:  true,
		ReconcileOnFail:   true,
		ReconcileOnUpdate: true,
		ReconcileOnReap:   true,
		NodeJoined: &SerfNodeJoinHandler{
			mgr, log.NewLogger(c.LogOutput, "serf:node-join")},
		NodeUpdated: &SerfNodeUpdateHandler{
			mgr, log.NewLogger(c.LogOutput, "serf:node-update")},
		NodeLeft: &SerfNodeLeaveHandler{
			mgr, log.NewLogger(c.LogOutput, "serf:node-left")},
		NodeFailed: &SerfNodeLeaveHandler{
			mgr, log.NewLogger(c.LogOutput, "serf:node-fail")},
		NodeReaped: &SerfNodeLeaveHandler{
			mgr, log.NewLogger(c.LogOutput, "serf:node-reap")},
		UserEvent: &SerfUserEventHandler{
			log.NewLogger(c.LogOutput, "serf:user-events"), userEventCh},
		UnknownEventHandler: &SerfUserEventHandler{
			log.NewLogger(c.LogOutput, "serf:unknown-event"), userEventCh},
		Reconciler: &SerfReconciler{reconcilerCh},
		IsLeader: func() bool {

			// TODO: Replace with Raft IsLeader check
			return true
		},
	})

	// Create database server
	s := &Server{
		config:       c,
		logger:       logger,
		sshServer:    &sshServer,
		serfer:       serfer,
		localKappas:  make(map[string]*NodeDetails),
		serfEventCh:  serfEventCh,
		kappaEventCh: userEventCh,
		reconcileCh:  reconcilerCh,
	}

	// Create serf server
	s.serf, err = s.setupSerf()
	if err != nil {
		err = logger.Error("Failed to start serf: %v", err)
		return
	}

	return s, nil
}