github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/internal/testutils/e2e/server.go (about) 1 /* 2 * 3 * Copyright 2020 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 // Package e2e provides utilities for end2end testing of xDS functionality. 20 package e2e 21 22 import ( 23 "context" 24 "fmt" 25 "net" 26 "reflect" 27 "strconv" 28 29 v3clusterpb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/cluster/v3" 30 v3endpointpb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/endpoint/v3" 31 v3listenerpb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/listener/v3" 32 v3routepb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/route/v3" 33 v3discoverygrpc "github.com/hxx258456/ccgo/go-control-plane/envoy/service/discovery/v3" 34 "github.com/hxx258456/ccgo/go-control-plane/pkg/cache/types" 35 v3cache "github.com/hxx258456/ccgo/go-control-plane/pkg/cache/v3" 36 v3resource "github.com/hxx258456/ccgo/go-control-plane/pkg/resource/v3" 37 v3server "github.com/hxx258456/ccgo/go-control-plane/pkg/server/v3" 38 39 grpc "github.com/hxx258456/ccgo/grpc" 40 "github.com/hxx258456/ccgo/grpc/grpclog" 41 ) 42 43 var logger = grpclog.Component("xds-e2e") 44 45 // serverLogger implements the Logger interface defined at 46 // envoyproxy/go-control-plane/pkg/log. This is passed to the Snapshot cache. 47 type serverLogger struct{} 48 49 func (l serverLogger) Debugf(format string, args ...interface{}) { 50 msg := fmt.Sprintf(format, args...) 51 logger.InfoDepth(1, msg) 52 } 53 func (l serverLogger) Infof(format string, args ...interface{}) { 54 msg := fmt.Sprintf(format, args...) 55 logger.InfoDepth(1, msg) 56 } 57 func (l serverLogger) Warnf(format string, args ...interface{}) { 58 msg := fmt.Sprintf(format, args...) 59 logger.WarningDepth(1, msg) 60 } 61 func (l serverLogger) Errorf(format string, args ...interface{}) { 62 msg := fmt.Sprintf(format, args...) 63 logger.ErrorDepth(1, msg) 64 } 65 66 // ManagementServer is a thin wrapper around the xDS control plane 67 // implementation provided by envoyproxy/go-control-plane. 68 type ManagementServer struct { 69 // Address is the host:port on which the management server is listening for 70 // new connections. 71 Address string 72 73 cancel context.CancelFunc // To stop the v3 ADS service. 74 xs v3server.Server // v3 implementation of ADS. 75 gs *grpc.Server // gRPC server which exports the ADS service. 76 cache v3cache.SnapshotCache // Resource snapshot. 77 version int // Version of resource snapshot. 78 } 79 80 // StartManagementServer initializes a management server which implements the 81 // AggregatedDiscoveryService endpoint. The management server is initialized 82 // with no resources. Tests should call the Update() method to change the 83 // resource snapshot held by the management server, as required by the test 84 // logic. When the test is done, it should call the Stop() method to cleanup 85 // resources allocated by the management server. 86 func StartManagementServer() (*ManagementServer, error) { 87 // Create a snapshot cache. 88 cache := v3cache.NewSnapshotCache(true, v3cache.IDHash{}, serverLogger{}) 89 logger.Infof("Created new snapshot cache...") 90 91 lis, err := net.Listen("tcp", "localhost:0") 92 if err != nil { 93 return nil, fmt.Errorf("failed to start xDS management server: %v", err) 94 } 95 96 // Create an xDS management server and register the ADS implementation 97 // provided by it on a gRPC server. Cancelling the context passed to the 98 // server is the only way of stopping it at the end of the test. 99 ctx, cancel := context.WithCancel(context.Background()) 100 xs := v3server.NewServer(ctx, cache, v3server.CallbackFuncs{}) 101 gs := grpc.NewServer() 102 v3discoverygrpc.RegisterAggregatedDiscoveryServiceServer(gs, xs) 103 logger.Infof("Registered Aggregated Discovery Service (ADS)...") 104 105 // Start serving. 106 go gs.Serve(lis) 107 logger.Infof("xDS management server serving at: %v...", lis.Addr().String()) 108 109 return &ManagementServer{ 110 Address: lis.Addr().String(), 111 cancel: cancel, 112 version: 0, 113 gs: gs, 114 xs: xs, 115 cache: cache, 116 }, nil 117 } 118 119 // UpdateOptions wraps parameters to be passed to the Update() method. 120 type UpdateOptions struct { 121 // NodeID is the id of the client to which this update is to be pushed. 122 NodeID string 123 // Endpoints, Clusters, Routes, and Listeners are the updated list of xds 124 // resources for the server. All must be provided with each Update. 125 Endpoints []*v3endpointpb.ClusterLoadAssignment 126 Clusters []*v3clusterpb.Cluster 127 Routes []*v3routepb.RouteConfiguration 128 Listeners []*v3listenerpb.Listener 129 // SkipValidation indicates whether we want to skip validation (by not 130 // calling snapshot.Consistent()). It can be useful for negative tests, 131 // where we send updates that the client will NACK. 132 SkipValidation bool 133 } 134 135 // Update changes the resource snapshot held by the management server, which 136 // updates connected clients as required. 137 func (s *ManagementServer) Update(ctx context.Context, opts UpdateOptions) error { 138 s.version++ 139 140 // Create a snapshot with the passed in resources. 141 resources := map[v3resource.Type][]types.Resource{ 142 v3resource.ListenerType: resourceSlice(opts.Listeners), 143 v3resource.RouteType: resourceSlice(opts.Routes), 144 v3resource.ClusterType: resourceSlice(opts.Clusters), 145 v3resource.EndpointType: resourceSlice(opts.Endpoints), 146 } 147 snapshot, err := v3cache.NewSnapshot(strconv.Itoa(s.version), resources) 148 if err != nil { 149 return fmt.Errorf("failed to create new snapshot cache: %v", err) 150 151 } 152 if !opts.SkipValidation { 153 if err := snapshot.Consistent(); err != nil { 154 return fmt.Errorf("failed to create new resource snapshot: %v", err) 155 } 156 } 157 logger.Infof("Created new resource snapshot...") 158 159 // Update the cache with the new resource snapshot. 160 if err := s.cache.SetSnapshot(ctx, opts.NodeID, snapshot); err != nil { 161 return fmt.Errorf("failed to update resource snapshot in management server: %v", err) 162 } 163 logger.Infof("Updated snapshot cache with resource snapshot...") 164 return nil 165 } 166 167 // Stop stops the management server. 168 func (s *ManagementServer) Stop() { 169 if s.cancel != nil { 170 s.cancel() 171 } 172 s.gs.Stop() 173 } 174 175 // resourceSlice accepts a slice of any type of proto messages and returns a 176 // slice of types.Resource. Will panic if there is an input type mismatch. 177 func resourceSlice(i interface{}) []types.Resource { 178 v := reflect.ValueOf(i) 179 rs := make([]types.Resource, v.Len()) 180 for i := 0; i < v.Len(); i++ { 181 rs[i] = v.Index(i).Interface().(types.Resource) 182 } 183 return rs 184 }