k3s/vendor/github.com/k3s-io/kine/pkg/endpoint/endpoint.go

163 lines
3.7 KiB
Go
Raw Normal View History

2019-08-22 05:12:46 +00:00
package endpoint
import (
"context"
"fmt"
"net"
"os"
"strings"
"github.com/k3s-io/kine/pkg/drivers/dqlite"
"github.com/k3s-io/kine/pkg/drivers/generic"
"github.com/k3s-io/kine/pkg/drivers/mysql"
"github.com/k3s-io/kine/pkg/drivers/pgsql"
"github.com/k3s-io/kine/pkg/drivers/sqlite"
"github.com/k3s-io/kine/pkg/server"
"github.com/k3s-io/kine/pkg/tls"
2019-12-12 01:27:03 +00:00
"github.com/pkg/errors"
2019-08-22 05:12:46 +00:00
"github.com/sirupsen/logrus"
"google.golang.org/grpc"
)
const (
KineSocket = "unix://kine.sock"
SQLiteBackend = "sqlite"
2019-11-08 21:45:10 +00:00
DQLiteBackend = "dqlite"
2019-08-22 05:12:46 +00:00
ETCDBackend = "etcd3"
MySQLBackend = "mysql"
PostgresBackend = "postgres"
)
type Config struct {
GRPCServer *grpc.Server
Listener string
Endpoint string
ConnectionPoolConfig generic.ConnectionPoolConfig
2019-08-22 05:12:46 +00:00
tls.Config
}
type ETCDConfig struct {
Endpoints []string
TLSConfig tls.Config
LeaderElect bool
}
func Listen(ctx context.Context, config Config) (ETCDConfig, error) {
driver, dsn := ParseStorageEndpoint(config.Endpoint)
if driver == ETCDBackend {
return ETCDConfig{
Endpoints: strings.Split(config.Endpoint, ","),
TLSConfig: config.Config,
LeaderElect: true,
}, nil
}
2019-11-08 21:45:10 +00:00
leaderelect, backend, err := getKineStorageBackend(ctx, driver, dsn, config)
2019-08-22 05:12:46 +00:00
if err != nil {
2019-12-12 01:27:03 +00:00
return ETCDConfig{}, errors.Wrap(err, "building kine")
2019-08-22 05:12:46 +00:00
}
if err := backend.Start(ctx); err != nil {
2019-12-12 01:27:03 +00:00
return ETCDConfig{}, errors.Wrap(err, "starting kine backend")
2019-08-22 05:12:46 +00:00
}
listen := config.Listener
if listen == "" {
listen = KineSocket
}
b := server.New(backend)
grpcServer := grpcServer(config)
b.Register(grpcServer)
listener, err := createListener(listen)
if err != nil {
return ETCDConfig{}, err
}
go func() {
if err := grpcServer.Serve(listener); err != nil {
logrus.Errorf("Kine server shutdown: %v", err)
}
<-ctx.Done()
grpcServer.Stop()
listener.Close()
}()
return ETCDConfig{
LeaderElect: leaderelect,
Endpoints: []string{listen},
TLSConfig: tls.Config{},
}, nil
}
func createListener(listen string) (ret net.Listener, rerr error) {
network, address := networkAndAddress(listen)
if network == "unix" {
if err := os.Remove(address); err != nil && !os.IsNotExist(err) {
logrus.Warnf("failed to remove socket %s: %v", address, err)
}
defer func() {
if err := os.Chmod(address, 0600); err != nil {
rerr = err
}
}()
}
logrus.Infof("Kine listening on %s://%s", network, address)
return net.Listen(network, address)
}
func grpcServer(config Config) *grpc.Server {
if config.GRPCServer != nil {
return config.GRPCServer
}
return grpc.NewServer()
}
2019-11-08 21:45:10 +00:00
func getKineStorageBackend(ctx context.Context, driver, dsn string, cfg Config) (bool, server.Backend, error) {
2019-08-22 05:12:46 +00:00
var (
backend server.Backend
leaderElect = true
err error
)
switch driver {
case SQLiteBackend:
leaderElect = false
backend, err = sqlite.New(ctx, dsn, cfg.ConnectionPoolConfig)
2019-11-08 21:45:10 +00:00
case DQLiteBackend:
backend, err = dqlite.New(ctx, dsn, cfg.ConnectionPoolConfig)
2019-08-22 05:12:46 +00:00
case PostgresBackend:
backend, err = pgsql.New(ctx, dsn, cfg.Config, cfg.ConnectionPoolConfig)
2019-08-22 05:12:46 +00:00
case MySQLBackend:
backend, err = mysql.New(ctx, dsn, cfg.Config, cfg.ConnectionPoolConfig)
2019-08-22 05:12:46 +00:00
default:
return false, nil, fmt.Errorf("storage backend is not defined")
}
return leaderElect, backend, err
}
func ParseStorageEndpoint(storageEndpoint string) (string, string) {
network, address := networkAndAddress(storageEndpoint)
switch network {
case "":
return SQLiteBackend, ""
case "http":
fallthrough
case "https":
return ETCDBackend, address
}
return network, address
}
func networkAndAddress(str string) (string, string) {
parts := strings.SplitN(str, "://", 2)
if len(parts) > 1 {
return parts[0], parts[1]
}
return "", parts[0]
}