open-nomad/nomad/raft_rpc.go

135 lines
3 KiB
Go
Raw Normal View History

2015-06-01 15:49:10 +00:00
package nomad
import (
"context"
2015-06-01 15:49:10 +00:00
"fmt"
"net"
"sync"
"time"
2018-01-12 21:58:44 +00:00
"github.com/hashicorp/nomad/helper/pool"
2016-10-25 23:05:37 +00:00
"github.com/hashicorp/nomad/helper/tlsutil"
2017-02-02 23:49:06 +00:00
"github.com/hashicorp/raft"
2015-06-01 15:49:10 +00:00
)
// RaftLayer implements the raft.StreamLayer interface,
// so that we can use a single RPC layer for Raft and Nomad
type RaftLayer struct {
// Addr is the listener address to return
addr net.Addr
// connCh is used to accept connections
connCh chan net.Conn
// TLS wrapper
2018-01-19 10:12:14 +00:00
tlsWrap tlsutil.Wrapper
tlsWrapLock sync.RWMutex
2015-06-01 15:49:10 +00:00
// Tracks if we are closed
closed bool
closeCh chan struct{}
closeLock sync.Mutex
}
// NewRaftLayer is used to initialize a new RaftLayer which can
// be used as a StreamLayer for Raft. If a tlsConfig is provided,
// then the connection will use TLS.
func NewRaftLayer(addr net.Addr, tlsWrap tlsutil.Wrapper) *RaftLayer {
layer := &RaftLayer{
addr: addr,
connCh: make(chan net.Conn),
tlsWrap: tlsWrap,
closeCh: make(chan struct{}),
}
return layer
}
// Handoff is used to hand off a connection to the
// RaftLayer. This allows it to be Accept()'ed
func (l *RaftLayer) Handoff(ctx context.Context, c net.Conn) error {
2015-06-01 15:49:10 +00:00
select {
case l.connCh <- c:
return nil
case <-l.closeCh:
return fmt.Errorf("Raft RPC layer closed")
case <-ctx.Done():
2017-11-30 15:50:43 +00:00
return nil
2015-06-01 15:49:10 +00:00
}
}
// Accept is used to return connection which are
// dialed to be used with the Raft layer
func (l *RaftLayer) Accept() (net.Conn, error) {
select {
case conn := <-l.connCh:
return conn, nil
case <-l.closeCh:
return nil, fmt.Errorf("Raft RPC layer closed")
}
}
// Close is used to stop listening for Raft connections
func (l *RaftLayer) Close() error {
l.closeLock.Lock()
defer l.closeLock.Unlock()
if !l.closed {
l.closed = true
close(l.closeCh)
}
return nil
}
2018-01-19 10:12:14 +00:00
// getTLSWrapper is used to retrieve the current TLS wrapper
func (l *RaftLayer) getTLSWrapper() tlsutil.Wrapper {
l.tlsWrapLock.RLock()
defer l.tlsWrapLock.RUnlock()
return l.tlsWrap
}
// ReloadTLS swaps the TLS wrapper. This is useful when upgrading or
// downgrading TLS connections.
func (l *RaftLayer) ReloadTLS(tlsWrap tlsutil.Wrapper) {
l.tlsWrapLock.Lock()
defer l.tlsWrapLock.Unlock()
l.tlsWrap = tlsWrap
}
2015-06-01 15:49:10 +00:00
// Addr is used to return the address of the listener
func (l *RaftLayer) Addr() net.Addr {
return l.addr
}
// Dial is used to create a new outgoing connection
2017-02-02 23:49:06 +00:00
func (l *RaftLayer) Dial(address raft.ServerAddress, timeout time.Duration) (net.Conn, error) {
conn, err := net.DialTimeout("tcp", string(address), timeout)
2015-06-01 15:49:10 +00:00
if err != nil {
return nil, err
}
2018-01-19 10:12:14 +00:00
tlsWrapper := l.getTLSWrapper()
2015-06-01 15:49:10 +00:00
// Check for tls mode
2018-01-19 10:12:14 +00:00
if tlsWrapper != nil {
2015-06-01 15:49:10 +00:00
// Switch the connection into TLS mode
2018-01-12 21:58:44 +00:00
if _, err := conn.Write([]byte{byte(pool.RpcTLS)}); err != nil {
2015-06-01 15:49:10 +00:00
conn.Close()
return nil, err
}
// Wrap the connection in a TLS client
2018-01-19 10:12:14 +00:00
conn, err = tlsWrapper(conn)
2015-06-01 15:49:10 +00:00
if err != nil {
return nil, err
}
}
// Write the Raft byte to set the mode
2018-01-12 21:58:44 +00:00
_, err = conn.Write([]byte{byte(pool.RpcRaft)})
2015-06-01 15:49:10 +00:00
if err != nil {
conn.Close()
return nil, err
}
return conn, err
}