Example #1
0
// New creates a new server with the given config. The server will call `cfg.SSHConfig()` to setup
// the server. If an error occurs it will be returned. If the Bind address is empty or invalid
// an error will be returned. If there is an error starting the TCP server, the error will be returned.
func New(cfg *Config) (server SSHServer, err error) {
	if cfg.Context == nil {
		return SSHServer{}, errors.New("Config has no context")
	}

	// Create ssh config for server
	sshConfig := cfg.SSHConfig()
	cfg.sshConfig = sshConfig

	// Validate the ssh bind addr
	if cfg.Bind == "" {
		err = fmt.Errorf("ssh server: Empty SSH bind address")
		return
	}

	// Open SSH socket listener
	sshAddr, e := net.ResolveTCPAddr("tcp", cfg.Bind)
	if e != nil {
		err = fmt.Errorf("ssh server: Invalid tcp address")
		return
	}

	// Create listener
	listener, e := net.ListenTCP("tcp", sshAddr)
	if e != nil {
		err = e
		return
	}
	server.listener = listener
	server.Addr = listener.Addr().(*net.TCPAddr)
	server.config = cfg
	server.reaper = grim.ReaperWithContext(cfg.Context)
	return
}
Example #2
0
func (t *tcpHandler) Execute(c context.Context) {
	select {
	case <-c.Done():
		t.conn.Close()
		return
	default:
	}

	// Create reaper
	g := grim.ReaperWithContext(c)
	defer g.Wait()

	// Convert to SSH connection
	sshConn, channels, requests, err := ssh.NewServerConn(t.conn, t.config)
	if err != nil {
		t.logger.Warn("SSH handshake failed:", "addr", t.conn.RemoteAddr().String(), "error", err)
		t.conn.Close()
		g.Kill()
		return
	}

	// Close connection on exit
	t.logger.Debug("Handshake successful")
	defer sshConn.Close()
	defer sshConn.Wait()

	// Discard all out-of-channel requests
	if t.requestHandler != nil {
		go t.requestHandler.Consume(requests)
	} else {
		go ssh.DiscardRequests(requests)
	}

OUTER:
	for {
		select {
		case <-c.Done():
			break OUTER
		case <-g.Dead():
			break OUTER
		case ch := <-channels:

			// Check if chan was closed
			if ch == nil {
				break OUTER
			}

			// Handle the channel
			g.SpawnFunc(func(ctx context.Context) {
				t.dispatcher.Dispatch(ctx, sshConn, ch)
				return
			})
		}
	}

	g.Kill()
}
Example #3
0
// New creates an implementation of the Yamuxer interface using the given
// context and config.
func New(context context.Context, c *Config) Yamuxer {
	return &yamuxer{
		grim:       grim.ReaperWithContext(context),
		listener:   c.Listener,
		dispatcher: c.Dispatcher,
		deadline:   c.Deadline,
		tlsConfig:  c.TLSConfig,
		logger:     log.NewLogger(c.LogOutput, "yamuxer"),
		logOutput:  c.LogOutput,
	}
}
Example #4
0
func (f *ForwardingHandler) Handle(c context.Context, conn net.Conn) {
	f.logger.Info("Accepted raft connection", "addr", conn.RemoteAddr().String())
	g := grim.ReaperWithContext(c)
	defer g.Wait()

	messages := make(chan namedtuple.Tuple, 1)
	g.SpawnFunc(func(ctx context.Context) {
		defer conn.Close()
		for {
			select {
			case <-ctx.Done():
			case msg, ok := <-messages:
				if !ok {
					return
				}
				if err := f.applier.Apply(msg); err != nil {
					f.logger.Warn("error applying message")
				}
			}
		}
	})
	g.SpawnFunc(func(ctx context.Context) {
		defer close(messages)
		decoder := namedtuple.NewDecoder(namedtuple.DefaultRegistry, conn)
		for {
			tuple, err := decoder.Decode()
			if err != nil {
				return
			}

			if tuple.Is(nodeStatus) {
				messages <- tuple
			}
		}
	})
	return
}
Example #5
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
}