blob: 1c4fa4f192d0da1167939342aaa043956154d4c7 [file] [log] [blame]
Mateusz Zalega18a67b02022-08-02 13:37:50 +02001package core
2
3import (
4 "context"
5 "crypto/ed25519"
6 "crypto/tls"
7 "crypto/x509"
8 "fmt"
9 "io"
10 "net"
11
12 "golang.org/x/net/proxy"
13 "google.golang.org/grpc"
14
15 "source.monogon.dev/metropolis/node"
16 "source.monogon.dev/metropolis/node/core/rpc"
17 "source.monogon.dev/metropolis/node/core/rpc/resolver"
18 "source.monogon.dev/metropolis/proto/api"
19)
20
21type ResolverLogger func(format string, args ...interface{})
22
Serge Bazanski925ec3d2024-02-05 14:38:20 +010023func DialOpts(ctx context.Context, c *ConnectOptions) ([]grpc.DialOption, error) {
24 var opts []grpc.DialOption
25 if c.ProxyServer != "" {
26 socksDialer, err := proxy.SOCKS5("tcp", c.ProxyServer, nil, proxy.Direct)
Mateusz Zalega18a67b02022-08-02 13:37:50 +020027 if err != nil {
28 return nil, fmt.Errorf("failed to build a SOCKS dialer: %v", err)
29 }
30 grpcd := func(_ context.Context, addr string) (net.Conn, error) {
31 return socksDialer.Dial("tcp", addr)
32 }
Serge Bazanski925ec3d2024-02-05 14:38:20 +010033 opts = append(opts, grpc.WithContextDialer(grpcd))
Mateusz Zalega18a67b02022-08-02 13:37:50 +020034 }
35
36 var resolverOpts []resolver.ResolverOption
Serge Bazanski925ec3d2024-02-05 14:38:20 +010037 if c.ResolverLogger != nil {
38 resolverOpts = append(resolverOpts, resolver.WithLogger(c.ResolverLogger))
Mateusz Zalega18a67b02022-08-02 13:37:50 +020039 }
Serge Bazanski925ec3d2024-02-05 14:38:20 +010040
Mateusz Zalega18a67b02022-08-02 13:37:50 +020041 r := resolver.New(ctx, resolverOpts...)
42
Serge Bazanski925ec3d2024-02-05 14:38:20 +010043 if len(c.Endpoints) == 0 {
44 return nil, fmt.Errorf("no cluster endpoints specified")
45 }
46 for _, eps := range c.Endpoints {
Mateusz Zalega18a67b02022-08-02 13:37:50 +020047 ep := resolver.NodeByHostPort(eps, uint16(node.CuratorServicePort))
48 r.AddEndpoint(ep)
49 }
Serge Bazanski925ec3d2024-02-05 14:38:20 +010050 opts = append(opts, grpc.WithResolvers(r))
Mateusz Zalega18a67b02022-08-02 13:37:50 +020051
Serge Bazanski925ec3d2024-02-05 14:38:20 +010052 return opts, nil
Mateusz Zalega18a67b02022-08-02 13:37:50 +020053}
54
Serge Bazanskib91938f2023-03-29 14:31:22 +020055func DialNode(ctx context.Context, opkey ed25519.PrivateKey, ocert, ca *x509.Certificate, proxyAddr, nodeId, nodeAddr string) (*grpc.ClientConn, error) {
56 var dialOpts []grpc.DialOption
57
58 if opkey == nil {
59 return nil, fmt.Errorf("an owner's private key must be provided")
60 }
61 if proxyAddr != "" {
62 socksDialer, err := proxy.SOCKS5("tcp", proxyAddr, nil, proxy.Direct)
63 if err != nil {
64 return nil, fmt.Errorf("failed to build a SOCKS dialer: %v", err)
65 }
66 grpcd := func(_ context.Context, addr string) (net.Conn, error) {
67 return socksDialer.Dial("tcp", addr)
68 }
69 dialOpts = append(dialOpts, grpc.WithContextDialer(grpcd))
70 }
71 tlsc := tls.Certificate{
72 Certificate: [][]byte{ocert.Raw},
73 PrivateKey: opkey,
74 }
75 creds := rpc.NewAuthenticatedCredentials(tlsc, rpc.WantRemoteCluster(ca), rpc.WantRemoteNode(nodeId))
76 dialOpts = append(dialOpts, grpc.WithTransportCredentials(creds))
77
78 endpoint := net.JoinHostPort(nodeAddr, node.NodeManagement.PortString())
79 return grpc.Dial(endpoint, dialOpts...)
80}
81
Mateusz Zalega18a67b02022-08-02 13:37:50 +020082// GetNodes retrieves node records, filtered by the supplied node filter
83// expression fexp.
84func GetNodes(ctx context.Context, mgmt api.ManagementClient, fexp string) ([]*api.Node, error) {
85 resN, err := mgmt.GetNodes(ctx, &api.GetNodesRequest{
86 Filter: fexp,
87 })
88 if err != nil {
89 return nil, err
90 }
91
92 var nodes []*api.Node
93 for {
94 node, err := resN.Recv()
95 if err == io.EOF {
96 break
97 }
98 if err != nil {
99 return nil, err
100 }
101 nodes = append(nodes, node)
102 }
103 return nodes, nil
104}