Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
526a92a
add Equal and String helpers for clients.ServerIdentifier
purnesh42H Mar 19, 2025
c916c48
Add String() and Equal() to grpctransport
purnesh42H Mar 19, 2025
b506c66
copy clientimpl, clientimpl_watcher and authority files
purnesh42H Mar 19, 2025
7ccb50b
modify copied clientimpl and related files for resource watching
purnesh42H Mar 19, 2025
88c1f90
modify ServerIdentifierExtension to use pointer receiver
purnesh42H Mar 19, 2025
306f330
copy lds_watcher_test and helpers
purnesh42H Mar 19, 2025
e927ad1
modify copied lds_watcher_test and helpers for e2e resource watcher t…
purnesh42H Mar 19, 2025
cc8cf9d
dfawley review1: modify String() and Equal()
purnesh42H Mar 20, 2025
77a11cb
add ServerIdentiferMap and serverConfigMap for transort channel re-use
purnesh42H Mar 21, 2025
249481c
serverConfigMap unit tests
purnesh42H Mar 22, 2025
c81e438
xdsclient validations
purnesh42H Mar 23, 2025
54f56bf
copy authority tests
purnesh42H Mar 23, 2025
2fcec9c
modify authorty tests
purnesh42H Mar 23, 2025
a55ff04
test to validate xdsclient ServerIdentifier.Extensions without Equal …
purnesh42H Mar 25, 2025
38e3d95
dfawley review 2: consider ServerIdentifier to be a map key
purnesh42H Mar 28, 2025
42a1223
remove clientImpl
purnesh42H Mar 31, 2025
6b9b12b
Remove ServerConfigString() and ServerIdentifierString()
purnesh42H Mar 31, 2025
5bbac97
restrict ServerConfigExtensions to be added as value in grpctransport
purnesh42H Mar 31, 2025
82a874a
copy dump_test.go for DumpResourcesTesting
purnesh42H Mar 31, 2025
1ad13b4
modify dump_test.go
purnesh42H Mar 31, 2025
1b7917f
dfawley review 2: small changes
purnesh42H Apr 2, 2025
c2545ce
copy misc_watchers_test including channel creation failure test case
purnesh42H Apr 2, 2025
76bff92
modify misc_watchers_test.go including channel creation failure test …
purnesh42H Apr 2, 2025
2e45e62
ref counted grpc transport
purnesh42H Apr 3, 2025
967db9c
delete config_test.go
purnesh42H Apr 3, 2025
d74aac0
easwars review 1
purnesh42H Apr 3, 2025
05da820
dfawley review 4
purnesh42H Apr 4, 2025
323ffed
A88 changes
purnesh42H Apr 4, 2025
ebe35a6
delete test hooks and remove err from transport close
purnesh42H Apr 14, 2025
81711cb
move cleanup part under single lock
purnesh42H Apr 15, 2025
3dda0b1
dfawley nits
purnesh42H Apr 16, 2025
6a422d7
easwars review 2 for xdsclient impl
purnesh42H Apr 18, 2025
d22c5b7
easwars review 3
purnesh42H Apr 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions xds/internal/clients/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ type ServerIdentifier struct {
//
// For example, a custom TransportBuilder might use this field to
// configure a specific security credentials.
//
// Extensions may be any type that is comparable, as they are used as map
// keys internally. If Extensions are not able to be used as a map key,
// the client may panic.
//
// See: https://go.dev/ref/spec#Comparison_operators
//
// Any equivalent extensions in all ServerIdentifiers present in a single
// client's configuration should have the same value. Not following this
// restriction may result in excess resource usage.
Extensions any
}

Expand Down
39 changes: 39 additions & 0 deletions xds/internal/clients/grpctransport/examples_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
*
* Copyright 2025 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package grpctransport_test

import (
"fmt"

"google.golang.org/grpc/xds/internal/clients"
"google.golang.org/grpc/xds/internal/clients/grpctransport"
)

// ExampleServerIdentifierExtension demonstrates how to create
// clients.ServerIdentifier with grpctransport.ServerIdentifierExtension as
// its extensions.
//
// This example is creating clients.ServerIdentifier to connect to server at
// localhost:5678 using the credentials named "local". Note that "local" must
// exist as an entry in the provided credentials to grpctransport.Builder.
func ExampleServerIdentifierExtension() {
// Note the Extensions field is set by value and not by pointer.
fmt.Printf("%+v", clients.ServerIdentifier{ServerURI: "localhost:5678", Extensions: grpctransport.ServerIdentifierExtension{Credentials: "local"}})
// Output: {ServerURI:localhost:5678 Extensions:{Credentials:local}}
}
104 changes: 89 additions & 15 deletions xds/internal/clients/grpctransport/grpc_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,55 @@ package grpctransport
import (
"context"
"fmt"
"sync"
"time"

"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/keepalive"
"google.golang.org/grpc/xds/internal/clients"
)

var (
logger = grpclog.Component("grpctransport")
)

// ServerIdentifierExtension holds settings for connecting to a gRPC server,
// such as an xDS management or an LRS server.
//
// It must be set by value (not pointer) in the
// clients.ServerIdentifier.Extensions field (See Example).
Comment thread
dfawley marked this conversation as resolved.
type ServerIdentifierExtension struct {
// Credentials will be used for all gRPC transports. If it is unset,
// transport creation will fail.
Credentials credentials.Bundle
// Credentials is name of the credentials to use for this transport to the
// server. It must be present in the map passed to NewBuilder.
Credentials string
}

// Builder creates gRPC-based Transports. It must be paired with ServerIdentifiers
// that contain an Extension field of type ServerIdentifierExtension.
type Builder struct{}
type Builder struct {
// credentials is a map of credentials names to credentials.Bundle which
// can be used to connect to the server.
credentials map[string]credentials.Bundle

mu sync.Mutex
// connections is a map of clients.ServerIdentifiers in use by the Builder
// to connect to different servers.
connections map[clients.ServerIdentifier]*grpc.ClientConn
refs map[clients.ServerIdentifier]int
}

// NewBuilder provides a builder for creating gRPC-based Transports using
// the credentials from provided map of credentials names to
// credentials.Bundle.
func NewBuilder(credentials map[string]credentials.Bundle) *Builder {
return &Builder{
credentials: credentials,
connections: make(map[clients.ServerIdentifier]*grpc.ClientConn),
refs: make(map[clients.ServerIdentifier]int),
}
}

// Build returns a gRPC-based clients.Transport.
//
Expand All @@ -57,14 +87,24 @@ func (b *Builder) Build(si clients.ServerIdentifier) (clients.Transport, error)
if !ok {
return nil, fmt.Errorf("grpctransport: Extensions field is %T, but must be %T in ServerIdentifier", si.Extensions, ServerIdentifierExtension{})
}
if sce.Credentials == nil {
return nil, fmt.Errorf("grptransport: Credentials field is not set in ServerIdentifierExtension")

creds, ok := b.credentials[sce.Credentials]
if !ok {
return nil, fmt.Errorf("grpctransport: unknown credentials type %q specified in extensions", sce.Credentials)
}

// TODO: Incorporate reference count map for existing transports and
// deduplicate transports based on the provided ServerIdentifier so that
// transport channel to same server can be shared between xDS and LRS
// client.
b.mu.Lock()
defer b.mu.Unlock()

if cc, ok := b.connections[si]; ok {
if logger.V(2) {
logger.Info("Reusing existing connection to the server for ServerIdentifier: %v", si)
Comment thread
easwars marked this conversation as resolved.
}
b.refs[si]++
tr := &grpcTransport{cc: cc}
tr.cleanup = b.cleanupFunc(si, tr)
return tr, nil
}

// Create a new gRPC client/channel for the server with the provided
// credentials, server URI, and a byte codec to send and receive messages.
Expand All @@ -74,16 +114,50 @@ func (b *Builder) Build(si clients.ServerIdentifier) (clients.Transport, error)
Time: 5 * time.Minute,
Timeout: 20 * time.Second,
})
cc, err := grpc.NewClient(si.ServerURI, kpCfg, grpc.WithCredentialsBundle(sce.Credentials), grpc.WithDefaultCallOptions(grpc.ForceCodec(&byteCodec{})))
cc, err := grpc.NewClient(si.ServerURI, kpCfg, grpc.WithCredentialsBundle(creds), grpc.WithDefaultCallOptions(grpc.ForceCodec(&byteCodec{})))
if err != nil {
return nil, fmt.Errorf("grpctransport: failed to create transport to server %q: %v", si.ServerURI, err)
return nil, fmt.Errorf("grpctransport: failed to create connection to server %q: %v", si.ServerURI, err)
}
tr := &grpcTransport{cc: cc}
// Register a cleanup function that decrements the refs to the gRPC
// transport each time Close() is called to close it and remove from
// transports and connections map if last reference is being released.
tr.cleanup = b.cleanupFunc(si, tr)

// Add the newly created connection to the maps to re-use the transport
// channel and track references.
b.connections[si] = cc
b.refs[si] = 1

if logger.V(2) {
logger.Info("Created a new transport to the server for ServerIdentifier: %v", si)
}
return tr, nil
}

return &grpcTransport{cc: cc}, nil
func (b *Builder) cleanupFunc(si clients.ServerIdentifier, tr *grpcTransport) func() {
return sync.OnceFunc(func() {
b.mu.Lock()
defer b.mu.Unlock()

b.refs[si]--
if b.refs[si] != 0 {
return
}

tr.cc.Close()
tr.cc = nil
delete(b.connections, si)
delete(b.refs, si)
})
}

type grpcTransport struct {
cc *grpc.ClientConn

// cleanup is the function to be invoked for releasing the references to
// the gRPC transport each time Close() is called.
cleanup func()
}

// NewStream creates a new gRPC stream to the server for the specified method.
Expand All @@ -96,8 +170,8 @@ func (g *grpcTransport) NewStream(ctx context.Context, method string) (clients.S
}

// Close closes the gRPC channel to the server.
func (g *grpcTransport) Close() error {
return g.cc.Close()
func (g *grpcTransport) Close() {
g.cleanup()
}

type stream struct {
Expand Down
Loading