k3s/vendor/github.com/k3s-io/kine/pkg/endpoint/endpoint.go
Jacob Blain Christen 36230daa86
[migration k3s-io] update kine dependency (#2568)
rancher/kine ➡️ k3s-io/kine

Part of https://github.com/rancher/k3s/issues/2189

Signed-off-by: Jacob Blain Christen <jacob@rancher.com>
2020-11-30 16:45:22 -07:00

163 lines
3.7 KiB
Go

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"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"google.golang.org/grpc"
)
const (
KineSocket = "unix://kine.sock"
SQLiteBackend = "sqlite"
DQLiteBackend = "dqlite"
ETCDBackend = "etcd3"
MySQLBackend = "mysql"
PostgresBackend = "postgres"
)
type Config struct {
GRPCServer *grpc.Server
Listener string
Endpoint string
ConnectionPoolConfig generic.ConnectionPoolConfig
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
}
leaderelect, backend, err := getKineStorageBackend(ctx, driver, dsn, config)
if err != nil {
return ETCDConfig{}, errors.Wrap(err, "building kine")
}
if err := backend.Start(ctx); err != nil {
return ETCDConfig{}, errors.Wrap(err, "starting kine backend")
}
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()
}
func getKineStorageBackend(ctx context.Context, driver, dsn string, cfg Config) (bool, server.Backend, error) {
var (
backend server.Backend
leaderElect = true
err error
)
switch driver {
case SQLiteBackend:
leaderElect = false
backend, err = sqlite.New(ctx, dsn, cfg.ConnectionPoolConfig)
case DQLiteBackend:
backend, err = dqlite.New(ctx, dsn, cfg.ConnectionPoolConfig)
case PostgresBackend:
backend, err = pgsql.New(ctx, dsn, cfg.Config, cfg.ConnectionPoolConfig)
case MySQLBackend:
backend, err = mysql.New(ctx, dsn, cfg.Config, cfg.ConnectionPoolConfig)
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]
}