Skip to content

Commit

Permalink
Allow only one endpoint
Browse files Browse the repository at this point in the history
To support multiple endpoints use a DNS record that returns multiple IP addresses
  • Loading branch information
robertvolkmann committed Feb 26, 2024
1 parent 1c665e5 commit adbeea8
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 191 deletions.
62 changes: 37 additions & 25 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ import (
"crypto/x509"
"fmt"
"math/rand"
"net"
"os"
"regexp"
"strconv"
"strings"
"time"

grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
Expand All @@ -28,6 +31,7 @@ import (
)

var (
hostRegex *regexp.Regexp
//nolint
prng = rand.New(rand.NewSource(time.Now().UnixNano()))
)
Expand All @@ -44,16 +48,9 @@ const (
defaultUserAgent = "duros-go"
)

// client for the duros grpc endpoint
type client struct {
eps EPs
conn *grpc.ClientConn
log *zap.SugaredLogger
}

// DialConfig is the configuration to create a duros-api connection
type DialConfig struct {
Endpoints EPs
Endpoint string
Scheme GRPCScheme
Token string
Credentials *Credentials
Expand Down Expand Up @@ -82,6 +79,10 @@ type ByteCredentials struct {
CA []byte
}

func init() {
hostRegex = regexp.MustCompile(`^([a-zA-Z0-9.\[\]:%-]+)$`)
}

// Dial creates a LightOS cluster client. it is a blocking call and will only
// return once the connection to [at least one of the] `targets` has been
// actually established - subject to `ctx` limitations. if `ctx` specified
Expand All @@ -100,9 +101,9 @@ func Dial(ctx context.Context, config DialConfig) (durosv2.DurosAPIClient, error
return nil, status.Errorf(codes.InvalidArgument,
"if you provide credentials, provide either file or byte credentials but not both")
}
if !config.Endpoints.isValid() {
if err := isValid(config.Endpoint); err != nil {
return nil, status.Errorf(codes.InvalidArgument,
"invalid target endpoints specified: [%s]", config.Endpoints)
"invalid target endpoints specified: %v", err)
}
id := fmt.Sprintf("%07s", strconv.FormatUint(uint64(prng.Uint32()), 36))
if config.Log == nil {
Expand All @@ -117,15 +118,10 @@ func Dial(ctx context.Context, config DialConfig) (durosv2.DurosAPIClient, error

log.Infow("connecting...",
"client", ua,
"targets", config.Endpoints,
"target", config.Endpoint,
"client-id", id,
)

res := &client{
eps: config.Endpoints.clone(),
log: log,
}

zapOpts := []grpc_zap.Option{
grpc_zap.WithLevels(grpcToZapLevel),
}
Expand Down Expand Up @@ -201,21 +197,15 @@ func Dial(ctx context.Context, config DialConfig) (durosv2.DurosAPIClient, error
return nil, fmt.Errorf("unsupported scheme:%v", config.Scheme)
}

var err error
res.conn, err = grpc.DialContext(
ctx,
config.Endpoints.String(),
opts...,
)
conn, err := grpc.DialContext(ctx, config.Endpoint, opts...)
if err != nil {
log.Errorw("failed to connect", "endpoints", config.Endpoints.String(), "error", err.Error())
log.Errorw("failed to connect", "endpoints", config.Endpoint, "error", err.Error())
return nil, err
}

log.Infof("connected")

c := durosv2.NewDurosAPIClient(res.conn)
return c, nil
return durosv2.NewDurosAPIClient(conn), nil
}

type tokenAuth struct {
Expand Down Expand Up @@ -318,3 +308,25 @@ func (c ByteCredentials) getTransportCredentials() (credentials.TransportCredent
})
return creds, nil
}

func isValid(endpoint string) error {
host, port, err := net.SplitHostPort(endpoint)
if err != nil {
//nolint dunno howto convert this to errors.As
if addrErr, ok := err.(*net.AddrError); ok {
return fmt.Errorf("%s", addrErr.Err)
}
// shouldn't happen, but...
return err
}
if strings.TrimSpace(host) == "" {
return fmt.Errorf("invalid empty host")
}
if !hostRegex.MatchString(host) {
return fmt.Errorf("invalid host %q", host)
}
if _, err = strconv.ParseUint(port, 10, 16); err != nil {
return fmt.Errorf("invalid port number %q", port)
}
return nil
}
8 changes: 4 additions & 4 deletions cmd/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"fmt"

"github.com/google/uuid"
duros "github.com/metal-stack/duros-go"
"github.com/metal-stack/duros-go"
v2 "github.com/metal-stack/duros-go/api/duros/v2"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -37,7 +37,7 @@ htcrucZWyL4=

func main() {
var (
endpoints string
endpoint string
token string
scheme string
caFile string
Expand All @@ -47,7 +47,7 @@ func main() {
)
flag.StringVar(&token, "token", "", "The token to authenticate against the lightbits api.")
flag.StringVar(&scheme, "scheme", "grpcs", "The scheme to connect to the lightbits api, can be grpc|grpcs")
flag.StringVar(&endpoints, "endpoints", "localhost:443", "The endpoints, in the form host:port,host:port of the lightbits api.")
flag.StringVar(&endpoint, "endpoint", "localhost:443", "The endpoint, in the form host:port of the lightbits api.")
flag.StringVar(&caFile, "ca-file", "", "the filename of the ca for certificate based authentication")
flag.StringVar(&certFile, "cert-file", "", "the filename of the ca certificate for certificate based authentication")
flag.StringVar(&keyFile, "key-file", "", "the filename of the key for certificate based authentication")
Expand All @@ -71,7 +71,7 @@ func main() {

ctx := context.Background()
dialConfig := duros.DialConfig{
Endpoints: duros.MustParseCSV(endpoints),
Endpoint: endpoint,
Scheme: grpcScheme,
Token: token,
Log: zlog.Sugar(),
Expand Down
162 changes: 0 additions & 162 deletions endpoint.go

This file was deleted.

0 comments on commit adbeea8

Please sign in to comment.