Skip to content

Commit fdacd23

Browse files
aeon: add connection from the etcd/tcs config
@@@@Tarantool_box document Title: add connection from the etcd/tcs config Added ability to connect to gRpc server used a configuration etcd/tcs tt aeon connect URI INSTANCE_NAME Closes #1052
1 parent 956c5cd commit fdacd23

File tree

11 files changed

+599
-8
lines changed

11 files changed

+599
-8
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1212
- `tt pack `: added TCM file packaging.
1313
- `tt aeon connect`: add connection from the cluster config.
1414
- `tt aeon connect`: add connection from the `app:insance_name`.
15+
- `tt aeon connect`: add connection from the etcd/tcs config.
1516

1617
### Changed
1718

cli/aeon/client.go

-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ func getTlsConfig(args cmd.Ssl) (*tls.Config, error) {
6464
}
6565
}
6666
// Else if RootCAs is nil, TLS uses the host's root CA set.
67-
6867
cert, err := getCertificate(args)
6968
if err != nil {
7069
return nil, fmt.Errorf("failed get certificate: %w", err)

cli/aeon/cmd/common.go

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
8+
"github.com/tarantool/go-tarantool/v2"
9+
libcluster "github.com/tarantool/tt/lib/cluster"
10+
"github.com/tarantool/tt/lib/connect"
11+
clientv3 "go.etcd.io/etcd/client/v3"
12+
)
13+
14+
// connectEtcd establishes a connection to etcd.
15+
func connectEtcd(uriOpts UriOpts, connOpts connectOpts) (*clientv3.Client, error) {
16+
etcdOpts := MakeEtcdOptsFromUriOpts(uriOpts)
17+
if etcdOpts.Username == "" && etcdOpts.Password == "" {
18+
etcdOpts.Username = connOpts.Username
19+
etcdOpts.Password = connOpts.Password
20+
if etcdOpts.Username == "" {
21+
etcdOpts.Username = os.Getenv(connect.EtcdUsernameEnv)
22+
}
23+
if etcdOpts.Password == "" {
24+
etcdOpts.Password = os.Getenv(connect.EtcdPasswordEnv)
25+
}
26+
}
27+
28+
etcdcli, err := libcluster.ConnectEtcd(etcdOpts)
29+
if err != nil {
30+
return nil, fmt.Errorf("failed to connect to etcd: %w", err)
31+
}
32+
return etcdcli, nil
33+
}
34+
35+
// connectTarantool establishes a connection to Tarantool.
36+
func connectTarantool(uriOpts UriOpts, connOpts connectOpts) (tarantool.Connector, error) {
37+
if uriOpts.Username == "" && uriOpts.Password == "" {
38+
uriOpts.Username = connOpts.Username
39+
uriOpts.Password = connOpts.Password
40+
if uriOpts.Username == "" {
41+
uriOpts.Username = os.Getenv(connect.TarantoolUsernameEnv)
42+
}
43+
if uriOpts.Password == "" {
44+
uriOpts.Password = os.Getenv(connect.TarantoolPasswordEnv)
45+
}
46+
}
47+
48+
dialer, connectorOpts := MakeConnectOptsFromUriOpts(uriOpts)
49+
50+
ctx := context.Background()
51+
if connectorOpts.Timeout > 0 {
52+
var cancel context.CancelFunc
53+
ctx, cancel = context.WithTimeout(ctx, connectorOpts.Timeout)
54+
defer cancel()
55+
}
56+
conn, err := tarantool.Connect(ctx, dialer, connectorOpts)
57+
if err != nil {
58+
return nil, fmt.Errorf("failed to connect to tarantool: %w", err)
59+
}
60+
return conn, nil
61+
}
62+
63+
// doOnStorage determines a storage based on the opts.
64+
func doOnStorage(connOpts connectOpts, opts UriOpts,
65+
tarantoolFunc func(tarantool.Connector) error, etcdFunc func(*clientv3.Client) error) error {
66+
etcdcli, errEtcd := connectEtcd(opts, connOpts)
67+
if errEtcd == nil {
68+
return etcdFunc(etcdcli)
69+
}
70+
71+
conn, errTarantool := connectTarantool(opts, connOpts)
72+
if errTarantool == nil {
73+
return tarantoolFunc(conn)
74+
}
75+
76+
return fmt.Errorf("failed to establish a connection to tarantool or etcd: %w, %w",
77+
errTarantool, errEtcd)
78+
}
79+
80+
// createPublisherAndCollector creates a new data publisher and collector based on UriOpts.
81+
func createPublisherAndCollector(
82+
publishers libcluster.DataPublisherFactory,
83+
collectors libcluster.CollectorFactory,
84+
connOpts connectOpts,
85+
opts UriOpts) (libcluster.DataPublisher, libcluster.Collector, func(), error) {
86+
prefix, key, timeout := opts.Prefix, opts.Key, opts.Timeout
87+
88+
var (
89+
publisher libcluster.DataPublisher
90+
collector libcluster.Collector
91+
err error
92+
closeFunc func()
93+
)
94+
95+
tarantoolFunc := func(conn tarantool.Connector) error {
96+
if collectors != nil {
97+
collector, err = collectors.NewTarantool(conn, prefix, key, timeout)
98+
if err != nil {
99+
conn.Close()
100+
return fmt.Errorf("failed to create tarantool config storage collector: %w", err)
101+
}
102+
}
103+
closeFunc = func() { conn.Close() }
104+
return nil
105+
}
106+
107+
etcdFunc := func(client *clientv3.Client) error {
108+
if publishers != nil {
109+
publisher, err = publishers.NewEtcd(client, prefix, key, timeout)
110+
if err != nil {
111+
client.Close()
112+
return fmt.Errorf("failed to create etcd publisher: %w", err)
113+
}
114+
}
115+
if collectors != nil {
116+
collector, err = collectors.NewEtcd(client, prefix, key, timeout)
117+
if err != nil {
118+
client.Close()
119+
return fmt.Errorf("failed to create etcd collector: %w", err)
120+
}
121+
}
122+
closeFunc = func() { client.Close() }
123+
return nil
124+
}
125+
126+
if err := doOnStorage(connOpts, opts, tarantoolFunc, etcdFunc); err != nil {
127+
return nil, nil, nil, err
128+
}
129+
130+
return publisher, collector, closeFunc, nil
131+
}

cli/aeon/cmd/connect.go

+10
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ type Ssl struct {
1212

1313
// ConnectCtx keeps context information for aeon connection.
1414
type ConnectCtx struct {
15+
// Username defines a username for connection.
16+
Username string
17+
// Password defines a password for connection.
18+
Password string
1519
// Ssl group of paths to ssl key files.
1620
Ssl Ssl
1721
// Transport is a connection mode.
@@ -41,3 +45,9 @@ type AdvertiseParams struct {
4145
// CaFile path to the trusted certificate authorities (CA) file (optional).
4246
CaFile string `mapstructure:"ssl_ca_file"`
4347
}
48+
49+
// connectOpts is additional connect options specified by a user.
50+
type connectOpts struct {
51+
Username string
52+
Password string
53+
}

cli/aeon/cmd/connection.go

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package cmd
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"net/url"
7+
8+
"github.com/mitchellh/mapstructure"
9+
"github.com/tarantool/tt/cli/util"
10+
libcluster "github.com/tarantool/tt/lib/cluster"
11+
libconnect "github.com/tarantool/tt/lib/connect"
12+
)
13+
14+
func ShowUri(connectCtx *ConnectCtx, uri *url.URL,
15+
instanceName string, collectors libcluster.CollectorFactory) error {
16+
uriOpts, err := ParseUriOpts(uri)
17+
if err != nil {
18+
return fmt.Errorf("invalid URL %q: %w", uri, err)
19+
}
20+
21+
connOpts := connectOpts{
22+
Username: connectCtx.Username,
23+
Password: connectCtx.Password,
24+
}
25+
_, collector, cancel, err := createPublisherAndCollector(
26+
nil,
27+
collectors,
28+
connOpts, uriOpts)
29+
if err != nil {
30+
return err
31+
}
32+
defer cancel()
33+
34+
config, err := collector.Collect()
35+
if err != nil {
36+
return fmt.Errorf("failed to collect a configuration: %w", err)
37+
}
38+
39+
clusterConfig, err := libcluster.MakeClusterConfig(config)
40+
if err != nil {
41+
return err
42+
}
43+
44+
result := libcluster.Instantiate(clusterConfig, instanceName)
45+
46+
dataSsl := []string{"roles_cfg", "aeon.grpc", "advertise"}
47+
data, err := result.Get(dataSsl)
48+
if err != nil {
49+
return err
50+
}
51+
52+
var advertise Advertise
53+
err = mapstructure.Decode(data, &advertise)
54+
if err != nil {
55+
return err
56+
}
57+
58+
if advertise.Uri == "" {
59+
return errors.New("invalid connection url")
60+
}
61+
62+
cleanedURL, err := util.RemoveScheme(advertise.Uri)
63+
if err != nil {
64+
return err
65+
}
66+
67+
connectCtx.Network, connectCtx.Address = libconnect.ParseBaseURI(cleanedURL)
68+
69+
if (advertise.Params.Transport != "ssl") && (advertise.Params.Transport != "plain") {
70+
return errors.New("transport must be ssl or plain")
71+
}
72+
73+
if advertise.Params.Transport == "ssl" {
74+
connectCtx.Transport = TransportSsl
75+
76+
connectCtx.Ssl = Ssl{
77+
KeyFile: advertise.Params.KeyFile,
78+
CertFile: advertise.Params.CertFile,
79+
CaFile: advertise.Params.CaFile,
80+
}
81+
}
82+
83+
return nil
84+
}

0 commit comments

Comments
 (0)