gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/xds/csds/csds.go (about) 1 /* 2 * 3 * Copyright 2021 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 csds implements features to dump the status (xDS responses) the 20 // xds_client is using. 21 // 22 // Notice: This package is EXPERIMENTAL and may be changed or removed in a later 23 // release. 24 package csds 25 26 import ( 27 "context" 28 "io" 29 30 v3adminpb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/admin/v3" 31 v2corepb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/api/v2/core" 32 v3corepb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/config/core/v3" 33 v3statusgrpc "gitee.com/ks-custle/core-gm/go-control-plane/envoy/service/status/v3" 34 v3statuspb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/service/status/v3" 35 "gitee.com/ks-custle/core-gm/grpc/codes" 36 "gitee.com/ks-custle/core-gm/grpc/grpclog" 37 "gitee.com/ks-custle/core-gm/grpc/status" 38 "gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient" 39 "gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/xdsresource" 40 "github.com/golang/protobuf/proto" 41 "google.golang.org/protobuf/types/known/timestamppb" 42 43 _ "gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/controller/version/v2" // Register v2 xds_client. 44 _ "gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/controller/version/v3" // Register v3 xds_client. 45 ) 46 47 var ( 48 logger = grpclog.Component("xds") 49 newXDSClient = func() xdsclient.XDSClient { 50 c, err := xdsclient.New() 51 if err != nil { 52 logger.Warningf("failed to create xds client: %v", err) 53 return nil 54 } 55 return c 56 } 57 ) 58 59 const ( 60 listenerTypeURL = "envoy.config.listener.v3.Listener" 61 routeConfigTypeURL = "envoy.config.route.v3.RouteConfiguration" 62 clusterTypeURL = "envoy.config.cluster.v3.Cluster" 63 endpointsTypeURL = "envoy.config.endpoint.v3.ClusterLoadAssignment" 64 ) 65 66 // ClientStatusDiscoveryServer implementations interface ClientStatusDiscoveryServiceServer. 67 type ClientStatusDiscoveryServer struct { 68 // xdsClient will always be the same in practice. But we keep a copy in each 69 // server instance for testing. 70 xdsClient xdsclient.XDSClient 71 } 72 73 // NewClientStatusDiscoveryServer returns an implementation of the CSDS server that can be 74 // registered on a gRPC server. 75 func NewClientStatusDiscoveryServer() (*ClientStatusDiscoveryServer, error) { 76 return &ClientStatusDiscoveryServer{xdsClient: newXDSClient()}, nil 77 } 78 79 // StreamClientStatus implementations interface ClientStatusDiscoveryServiceServer. 80 func (s *ClientStatusDiscoveryServer) StreamClientStatus(stream v3statusgrpc.ClientStatusDiscoveryService_StreamClientStatusServer) error { 81 for { 82 req, err := stream.Recv() 83 if err == io.EOF { 84 return nil 85 } 86 if err != nil { 87 return err 88 } 89 resp, err := s.buildClientStatusRespForReq(req) 90 if err != nil { 91 return err 92 } 93 if err := stream.Send(resp); err != nil { 94 return err 95 } 96 } 97 } 98 99 // FetchClientStatus implementations interface ClientStatusDiscoveryServiceServer. 100 func (s *ClientStatusDiscoveryServer) FetchClientStatus(_ context.Context, req *v3statuspb.ClientStatusRequest) (*v3statuspb.ClientStatusResponse, error) { 101 return s.buildClientStatusRespForReq(req) 102 } 103 104 // buildClientStatusRespForReq fetches the status from the client, and returns 105 // the response to be sent back to xdsclient. 106 // 107 // If it returns an error, the error is a status error. 108 func (s *ClientStatusDiscoveryServer) buildClientStatusRespForReq(req *v3statuspb.ClientStatusRequest) (*v3statuspb.ClientStatusResponse, error) { 109 if s.xdsClient == nil { 110 return &v3statuspb.ClientStatusResponse{}, nil 111 } 112 // Field NodeMatchers is unsupported, by design 113 // https://github.com/grpc/proposal/blob/master/A40-csds-support.md#detail-node-matching. 114 if len(req.NodeMatchers) != 0 { 115 return nil, status.Errorf(codes.InvalidArgument, "node_matchers are not supported, request contains node_matchers: %v", req.NodeMatchers) 116 } 117 118 lds := dumpToGenericXdsConfig(listenerTypeURL, s.xdsClient.DumpLDS) 119 rds := dumpToGenericXdsConfig(routeConfigTypeURL, s.xdsClient.DumpRDS) 120 cds := dumpToGenericXdsConfig(clusterTypeURL, s.xdsClient.DumpCDS) 121 eds := dumpToGenericXdsConfig(endpointsTypeURL, s.xdsClient.DumpEDS) 122 configs := make([]*v3statuspb.ClientConfig_GenericXdsConfig, 0, len(lds)+len(rds)+len(cds)+len(eds)) 123 configs = append(configs, lds...) 124 configs = append(configs, rds...) 125 configs = append(configs, cds...) 126 configs = append(configs, eds...) 127 128 ret := &v3statuspb.ClientStatusResponse{ 129 Config: []*v3statuspb.ClientConfig{ 130 { 131 Node: nodeProtoToV3(s.xdsClient.BootstrapConfig().XDSServer.NodeProto), 132 GenericXdsConfigs: configs, 133 }, 134 }, 135 } 136 return ret, nil 137 } 138 139 // Close cleans up the resources. 140 func (s *ClientStatusDiscoveryServer) Close() { 141 if s.xdsClient != nil { 142 s.xdsClient.Close() 143 } 144 } 145 146 // nodeProtoToV3 converts the given proto into a v3.Node. n is from bootstrap 147 // config, it can be either v2.Node or v3.Node. 148 // 149 // If n is already a v3.Node, return it. 150 // If n is v2.Node, marshal and unmarshal it to v3. 151 // Otherwise, return nil. 152 // 153 // The default case (not v2 or v3) is nil, instead of error, because the 154 // resources in the response are more important than the node. The worst case is 155 // that the user will receive no Node info, but will still get resources. 156 func nodeProtoToV3(n proto.Message) *v3corepb.Node { 157 var node *v3corepb.Node 158 switch nn := n.(type) { 159 case *v3corepb.Node: 160 node = nn 161 case *v2corepb.Node: 162 v2, err := proto.Marshal(nn) 163 if err != nil { 164 logger.Warningf("Failed to marshal node (%v): %v", n, err) 165 break 166 } 167 node = new(v3corepb.Node) 168 if err := proto.Unmarshal(v2, node); err != nil { 169 logger.Warningf("Failed to unmarshal node (%v): %v", v2, err) 170 } 171 default: 172 logger.Warningf("node from bootstrap is %#v, only v2.Node and v3.Node are supported", nn) 173 } 174 return node 175 } 176 177 func dumpToGenericXdsConfig(typeURL string, dumpF func() map[string]xdsresource.UpdateWithMD) []*v3statuspb.ClientConfig_GenericXdsConfig { 178 dump := dumpF() 179 ret := make([]*v3statuspb.ClientConfig_GenericXdsConfig, 0, len(dump)) 180 for name, d := range dump { 181 config := &v3statuspb.ClientConfig_GenericXdsConfig{ 182 TypeUrl: typeURL, 183 Name: name, 184 VersionInfo: d.MD.Version, 185 XdsConfig: d.Raw, 186 LastUpdated: timestamppb.New(d.MD.Timestamp), 187 ClientStatus: serviceStatusToProto(d.MD.Status), 188 } 189 if errState := d.MD.ErrState; errState != nil { 190 config.ErrorState = &v3adminpb.UpdateFailureState{ 191 LastUpdateAttempt: timestamppb.New(errState.Timestamp), 192 Details: errState.Err.Error(), 193 VersionInfo: errState.Version, 194 } 195 } 196 ret = append(ret, config) 197 } 198 return ret 199 } 200 201 func serviceStatusToProto(serviceStatus xdsresource.ServiceStatus) v3adminpb.ClientResourceStatus { 202 switch serviceStatus { 203 case xdsresource.ServiceStatusUnknown: 204 return v3adminpb.ClientResourceStatus_UNKNOWN 205 case xdsresource.ServiceStatusRequested: 206 return v3adminpb.ClientResourceStatus_REQUESTED 207 case xdsresource.ServiceStatusNotExist: 208 return v3adminpb.ClientResourceStatus_DOES_NOT_EXIST 209 case xdsresource.ServiceStatusACKed: 210 return v3adminpb.ClientResourceStatus_ACKED 211 case xdsresource.ServiceStatusNACKed: 212 return v3adminpb.ClientResourceStatus_NACKED 213 default: 214 return v3adminpb.ClientResourceStatus_UNKNOWN 215 } 216 }