From 736671f07876e106ba489ad168dcef2a64e45dc2 Mon Sep 17 00:00:00 2001 From: Marek Siarkowicz Date: Fri, 17 Sep 2021 12:20:59 +0200 Subject: [PATCH] client: Use first endpoint as http2 authority header --- client/v3/client.go | 18 ++++++++++++++--- tests/e2e/ctl_v3_grpc_test.go | 16 +++++++-------- tests/integration/grpc_test.go | 37 ++++++++++++++++++++++++---------- 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/client/v3/client.go b/client/v3/client.go index 530b0399f690..c39f00421578 100644 --- a/client/v3/client.go +++ b/client/v3/client.go @@ -297,9 +297,7 @@ func (c *Client) dial(creds grpccredentials.TransportCredentials, dopts ...grpc. dctx, cancel = context.WithTimeout(c.ctx, c.cfg.DialTimeout) defer cancel() // TODO: Is this right for cases where grpc.WithBlock() is not set on the dial options? } - - initialEndpoints := strings.Join(c.Endpoints(), ";") - target := fmt.Sprintf("%s://%p/#initially=[%s]", resolver.Schema, c, initialEndpoints) + target := fmt.Sprintf("%s://%p/%s", resolver.Schema, c, authority(c.endpoints[0])) conn, err := grpc.DialContext(dctx, target, opts...) if err != nil { return nil, err @@ -307,6 +305,20 @@ func (c *Client) dial(creds grpccredentials.TransportCredentials, dopts ...grpc. return conn, nil } +func authority(endpoint string) string { + spl := strings.SplitN(endpoint, "://", 2) + if len(spl) < 2 { + if strings.HasPrefix(endpoint, "unix:") { + return endpoint[len("unix:"):] + } + if strings.HasPrefix(endpoint, "unixs:") { + return endpoint[len("unixs:"):] + } + return endpoint + } + return spl[1] +} + func (c *Client) credentialsForEndpoint(ep string) grpccredentials.TransportCredentials { r := endpoint.RequiresCredentials(ep) switch r { diff --git a/tests/e2e/ctl_v3_grpc_test.go b/tests/e2e/ctl_v3_grpc_test.go index 0b6dd6f055d4..224fad4f5132 100644 --- a/tests/e2e/ctl_v3_grpc_test.go +++ b/tests/e2e/ctl_v3_grpc_test.go @@ -34,44 +34,44 @@ func TestAuthority(t *testing.T) { clientURLPattern string // Pattern used to validate authority received by server. Fields filled: - // %s - list of endpoints concatenated with ";" + // %d - will be filled with first member grpc port expectAuthorityPattern string }{ { name: "http://domain[:port]", clientURLPattern: "http://localhost:%d", - expectAuthorityPattern: "#initially=[%s]", + expectAuthorityPattern: "localhost:%d", }, { name: "http://address[:port]", clientURLPattern: "http://127.0.0.1:%d", - expectAuthorityPattern: "#initially=[%s]", + expectAuthorityPattern: "127.0.0.1:%d", }, { name: "https://domain[:port] insecure", useTLS: true, useInsecureTLS: true, clientURLPattern: "https://localhost:%d", - expectAuthorityPattern: "#initially=[%s]", + expectAuthorityPattern: "localhost:%d", }, { name: "https://address[:port] insecure", useTLS: true, useInsecureTLS: true, clientURLPattern: "https://127.0.0.1:%d", - expectAuthorityPattern: "#initially=[%s]", + expectAuthorityPattern: "127.0.0.1:%d", }, { name: "https://domain[:port]", useTLS: true, clientURLPattern: "https://localhost:%d", - expectAuthorityPattern: "#initially=[%s]", + expectAuthorityPattern: "localhost:%d", }, { name: "https://address[:port]", useTLS: true, clientURLPattern: "https://127.0.0.1:%d", - expectAuthorityPattern: "#initially=[%s]", + expectAuthorityPattern: "127.0.0.1:%d", }, } for _, tc := range tcs { @@ -102,7 +102,7 @@ func TestAuthority(t *testing.T) { } executeWithTimeout(t, 5*time.Second, func() { - assertAuthority(t, fmt.Sprintf(tc.expectAuthorityPattern, strings.Join(endpoints, ";")), epc) + assertAuthority(t, fmt.Sprintf(tc.expectAuthorityPattern, 20000), epc) }) }) diff --git a/tests/integration/grpc_test.go b/tests/integration/grpc_test.go index 49cbd1df511e..eb71191a3444 100644 --- a/tests/integration/grpc_test.go +++ b/tests/integration/grpc_test.go @@ -37,57 +37,58 @@ func TestAuthority(t *testing.T) { clientURLPattern string // Pattern used to validate authority received by server. Fields filled: - // %s - list of endpoints concatenated with ";" + // %d - will be filled with first member grpc port + // %s - will be filled with first member name expectAuthorityPattern string }{ { name: "unix:path", clientURLPattern: "unix:localhost:%s", - expectAuthorityPattern: "#initially=[%s]", + expectAuthorityPattern: "localhost:%s", }, { name: "unix://absolute_path", clientURLPattern: "unix://localhost:%s", - expectAuthorityPattern: "#initially=[%s]", + expectAuthorityPattern: "localhost:%s", }, // "unixs" is not standard schema supported by etcd { name: "unixs:absolute_path", useTLS: true, clientURLPattern: "unixs:localhost:%s", - expectAuthorityPattern: "#initially=[%s]", + expectAuthorityPattern: "localhost:%s", }, { name: "unixs://absolute_path", useTLS: true, clientURLPattern: "unixs://localhost:%s", - expectAuthorityPattern: "#initially=[%s]", + expectAuthorityPattern: "localhost:%s", }, { name: "http://domain[:port]", useTCP: true, clientURLPattern: "http://localhost:%d", - expectAuthorityPattern: "#initially=[%s]", + expectAuthorityPattern: "localhost:%d", }, { name: "https://domain[:port]", useTLS: true, useTCP: true, clientURLPattern: "https://localhost:%d", - expectAuthorityPattern: "#initially=[%s]", + expectAuthorityPattern: "localhost:%d", }, { name: "http://address[:port]", useTCP: true, clientURLPattern: "http://127.0.0.1:%d", - expectAuthorityPattern: "#initially=[%s]", + expectAuthorityPattern: "127.0.0.1:%d", }, { name: "https://address[:port]", useTCP: true, useTLS: true, clientURLPattern: "https://127.0.0.1:%d", - expectAuthorityPattern: "#initially=[%s]", + expectAuthorityPattern: "127.0.0.1:%d", }, } for _, tc := range tcs { @@ -102,7 +103,6 @@ func TestAuthority(t *testing.T) { cfg, tlsConfig := setupTLS(t, tc.useTLS, cfg) clus := NewClusterV3(t, &cfg) defer clus.Terminate(t) - endpoints := templateEndpoints(t, tc.clientURLPattern, clus) kv := setupClient(t, tc.clientURLPattern, clus, tlsConfig) defer kv.Close() @@ -112,7 +112,7 @@ func TestAuthority(t *testing.T) { t.Fatal(err) } - assertAuthority(t, fmt.Sprintf(tc.expectAuthorityPattern, strings.Join(endpoints, ";")), clus) + assertAuthority(t, templateAuthority(t, tc.expectAuthorityPattern, clus.Members[0]), clus) }) } } @@ -165,6 +165,21 @@ func templateEndpoints(t *testing.T, pattern string, clus *ClusterV3) []string { return endpoints } +func templateAuthority(t *testing.T, pattern string, m *member) string { + t.Helper() + authority := pattern + if strings.Contains(authority, "%d") { + authority = fmt.Sprintf(authority, GrpcPortNumber(m.UniqNumber, m.MemberNumber)) + } + if strings.Contains(authority, "%s") { + authority = fmt.Sprintf(authority, m.Name) + } + if strings.Contains(authority, "%") { + t.Fatalf("Failed to template pattern, %% symbol left %q", authority) + } + return authority +} + func assertAuthority(t *testing.T, expectedAuthority string, clus *ClusterV3) { t.Helper() requestsFound := 0