snapshot of https://github.com/grpc/grpc-go.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Stale bot / stale (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / vet-proto (push) Failing after 1s
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Stale bot / stale (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / vet-proto (push) Failing after 1s
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
This commit is contained in:
188
internal/xds/server/rds_handler.go
Normal file
188
internal/xds/server/rds_handler.go
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2021 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 server
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
igrpclog "google.golang.org/grpc/internal/grpclog"
|
||||
"google.golang.org/grpc/internal/xds/xdsclient/xdsresource"
|
||||
)
|
||||
|
||||
// rdsHandler handles any RDS queries that need to be started for a given server
|
||||
// side listeners Filter Chains (i.e. not inline). It persists rdsWatcher
|
||||
// updates for later use and also determines whether all the rdsWatcher updates
|
||||
// needed have been received or not.
|
||||
type rdsHandler struct {
|
||||
xdsC XDSClient
|
||||
xdsNodeID string
|
||||
logger *igrpclog.PrefixLogger
|
||||
|
||||
callback func(string, rdsWatcherUpdate)
|
||||
|
||||
// updates is a map from routeName to rdsWatcher update, including
|
||||
// RouteConfiguration resources and any errors received. If not written in
|
||||
// this map, no RouteConfiguration or error for that route name yet. If
|
||||
// update set in value, use that as valid route configuration, otherwise
|
||||
// treat as an error case and fail at L7 level.
|
||||
updates map[string]rdsWatcherUpdate
|
||||
|
||||
mu sync.Mutex
|
||||
cancels map[string]func()
|
||||
}
|
||||
|
||||
// newRDSHandler creates a new rdsHandler to watch for RouteConfiguration
|
||||
// resources. listenerWrapper updates the list of route names to watch by
|
||||
// calling updateRouteNamesToWatch() upon receipt of new Listener configuration.
|
||||
func newRDSHandler(cb func(string, rdsWatcherUpdate), xdsC XDSClient, logger *igrpclog.PrefixLogger) *rdsHandler {
|
||||
r := &rdsHandler{
|
||||
xdsC: xdsC,
|
||||
logger: logger,
|
||||
callback: cb,
|
||||
updates: make(map[string]rdsWatcherUpdate),
|
||||
cancels: make(map[string]func()),
|
||||
}
|
||||
r.xdsNodeID = xdsC.BootstrapConfig().Node().GetId()
|
||||
return r
|
||||
}
|
||||
|
||||
// updateRouteNamesToWatch handles a list of route names to watch for a given
|
||||
// server side listener (if a filter chain specifies dynamic
|
||||
// RouteConfiguration). This function handles all the logic with respect to any
|
||||
// routes that may have been added or deleted as compared to what was previously
|
||||
// present. Must be called within an xDS Client callback.
|
||||
func (rh *rdsHandler) updateRouteNamesToWatch(routeNamesToWatch map[string]bool) {
|
||||
rh.mu.Lock()
|
||||
defer rh.mu.Unlock()
|
||||
// Add and start watches for any new routes in routeNamesToWatch.
|
||||
for routeName := range routeNamesToWatch {
|
||||
if _, ok := rh.cancels[routeName]; !ok {
|
||||
// The xDS client keeps a reference to the watcher until the cancel
|
||||
// func is invoked. So, we don't need to keep a reference for fear
|
||||
// of it being garbage collected.
|
||||
w := &rdsWatcher{parent: rh, routeName: routeName}
|
||||
cancel := xdsresource.WatchRouteConfig(rh.xdsC, routeName, w)
|
||||
// Set bit on cancel function to eat any RouteConfiguration calls
|
||||
// for this watcher after it has been canceled.
|
||||
rh.cancels[routeName] = func() {
|
||||
w.mu.Lock()
|
||||
w.canceled = true
|
||||
w.mu.Unlock()
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete and cancel watches for any routes from persisted routeNamesToWatch
|
||||
// that are no longer present.
|
||||
for routeName := range rh.cancels {
|
||||
if _, ok := routeNamesToWatch[routeName]; !ok {
|
||||
rh.cancels[routeName]()
|
||||
delete(rh.cancels, routeName)
|
||||
delete(rh.updates, routeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// determines if all dynamic RouteConfiguration needed has received
|
||||
// configuration or update. Must be called from an xDS Client Callback.
|
||||
func (rh *rdsHandler) determineRouteConfigurationReady() bool {
|
||||
// Safe to read cancels because only written to in other parts of xDS Client
|
||||
// Callbacks, which are sync.
|
||||
return len(rh.updates) == len(rh.cancels)
|
||||
}
|
||||
|
||||
// close() is meant to be called by wrapped listener when the wrapped listener
|
||||
// is closed, and it cleans up resources by canceling all the active RDS
|
||||
// watches.
|
||||
func (rh *rdsHandler) close() {
|
||||
rh.mu.Lock()
|
||||
defer rh.mu.Unlock()
|
||||
for _, cancel := range rh.cancels {
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
|
||||
type rdsWatcherUpdate struct {
|
||||
data *xdsresource.RouteConfigUpdate
|
||||
err error
|
||||
}
|
||||
|
||||
// rdsWatcher implements the xdsresource.RouteConfigWatcher interface and is
|
||||
// passed to the WatchRouteConfig API.
|
||||
type rdsWatcher struct {
|
||||
parent *rdsHandler
|
||||
logger *igrpclog.PrefixLogger
|
||||
routeName string
|
||||
|
||||
mu sync.Mutex
|
||||
canceled bool // eats callbacks if true
|
||||
}
|
||||
|
||||
func (rw *rdsWatcher) ResourceChanged(update *xdsresource.RouteConfigUpdate, onDone func()) {
|
||||
defer onDone()
|
||||
rw.mu.Lock()
|
||||
if rw.canceled {
|
||||
rw.mu.Unlock()
|
||||
return
|
||||
}
|
||||
rw.mu.Unlock()
|
||||
if rw.logger.V(2) {
|
||||
rw.logger.Infof("RDS watch for resource %q received update: %#v", rw.routeName, update)
|
||||
}
|
||||
|
||||
routeName := rw.routeName
|
||||
rwu := rdsWatcherUpdate{data: update}
|
||||
rw.parent.updates[routeName] = rwu
|
||||
rw.parent.callback(routeName, rwu)
|
||||
}
|
||||
|
||||
func (rw *rdsWatcher) ResourceError(err error, onDone func()) {
|
||||
defer onDone()
|
||||
rw.mu.Lock()
|
||||
if rw.canceled {
|
||||
rw.mu.Unlock()
|
||||
return
|
||||
}
|
||||
rw.mu.Unlock()
|
||||
if rw.logger.V(2) {
|
||||
rw.logger.Infof("RDS watch for resource %q reported resource error", rw.routeName)
|
||||
}
|
||||
|
||||
routeName := rw.routeName
|
||||
rwu := rdsWatcherUpdate{err: err}
|
||||
rw.parent.updates[routeName] = rwu
|
||||
rw.parent.callback(routeName, rwu)
|
||||
}
|
||||
|
||||
func (rw *rdsWatcher) AmbientError(err error, onDone func()) {
|
||||
defer onDone()
|
||||
rw.mu.Lock()
|
||||
if rw.canceled {
|
||||
rw.mu.Unlock()
|
||||
return
|
||||
}
|
||||
rw.mu.Unlock()
|
||||
if rw.logger.V(2) {
|
||||
rw.logger.Infof("RDS watch for resource %q reported ambient error: %v", rw.routeName, err)
|
||||
}
|
||||
routeName := rw.routeName
|
||||
rwu := rw.parent.updates[routeName]
|
||||
rw.parent.callback(routeName, rwu)
|
||||
}
|
||||
Reference in New Issue
Block a user