15
15
*
16
16
*/
17
17
18
- import { Node } from "./generated/envoy/config/core/v3/Node" ;
19
18
import { ClientConfig , _envoy_service_status_v3_ClientConfig_GenericXdsConfig as GenericXdsConfig } from "./generated/envoy/service/status/v3/ClientConfig" ;
20
19
import { ClientStatusDiscoveryServiceHandlers } from "./generated/envoy/service/status/v3/ClientStatusDiscoveryService" ;
21
20
import { ClientStatusRequest__Output } from "./generated/envoy/service/status/v3/ClientStatusRequest" ;
22
21
import { ClientStatusResponse } from "./generated/envoy/service/status/v3/ClientStatusResponse" ;
23
22
import { Timestamp } from "./generated/google/protobuf/Timestamp" ;
24
- import { AdsTypeUrl , CDS_TYPE_URL , EDS_TYPE_URL , LDS_TYPE_URL , RDS_TYPE_URL } from "./resources" ;
25
- import { HandleResponseResult } from "./xds-stream-state/xds-stream-state" ;
23
+ import { xdsResourceNameToString } from "./resources" ;
26
24
import { sendUnaryData , ServerDuplexStream , ServerUnaryCall , status , experimental , loadPackageDefinition , logVerbosity } from '@grpc/grpc-js' ;
27
25
import { loadSync } from "@grpc/proto-loader" ;
28
26
import { ProtoGrpcType as CsdsProtoGrpcType } from "./generated/csds" ;
29
27
30
28
import registerAdminService = experimental . registerAdminService ;
29
+ import { XdsClient } from "./xds-client" ;
31
30
32
31
const TRACER_NAME = 'csds' ;
33
32
@@ -47,115 +46,47 @@ function dateToProtoTimestamp(date?: Date | null): Timestamp | null {
47
46
}
48
47
}
49
48
50
- let clientNode : Node | null = null ;
49
+ const registeredClients : XdsClient [ ] = [ ] ;
51
50
52
- const configStatus = {
53
- [ EDS_TYPE_URL ] : new Map < string , GenericXdsConfig > ( ) ,
54
- [ CDS_TYPE_URL ] : new Map < string , GenericXdsConfig > ( ) ,
55
- [ RDS_TYPE_URL ] : new Map < string , GenericXdsConfig > ( ) ,
56
- [ LDS_TYPE_URL ] : new Map < string , GenericXdsConfig > ( )
57
- } ;
58
-
59
- /**
60
- * This function only accepts a v3 Node message, because we are only supporting
61
- * v3 CSDS and it only handles v3 Nodes. If the client is actually using v2 xDS
62
- * APIs, it should just provide the equivalent v3 Node message.
63
- * @param node The Node message for the client that is requesting resources
64
- */
65
- export function setCsdsClientNode ( node : Node ) {
66
- clientNode = node ;
51
+ export function registerXdsClientWithCsds ( client : XdsClient ) {
52
+ registeredClients . push ( client ) ;
67
53
}
68
54
69
- /**
70
- * Update the config status maps from the list of names of requested resources
71
- * for a specific type URL. These lists are the source of truth for determining
72
- * what resources will be listed in the CSDS response. Any resource that is not
73
- * in this list will never actually be applied anywhere.
74
- * @param typeUrl The resource type URL
75
- * @param names The list of resource names that are being requested
76
- */
77
- export function updateCsdsRequestedNameList ( typeUrl : AdsTypeUrl , names : string [ ] ) {
78
- trace ( 'Update type URL ' + typeUrl + ' with names [' + names + ']' ) ;
79
- const currentTime = dateToProtoTimestamp ( new Date ( ) ) ;
80
- const configMap = configStatus [ typeUrl ] ;
81
- for ( const name of names ) {
82
- if ( ! configMap . has ( name ) ) {
83
- configMap . set ( name , {
84
- type_url : typeUrl ,
85
- name : name ,
86
- last_updated : currentTime ,
87
- client_status : 'REQUESTED'
88
- } ) ;
89
- }
90
- }
91
- for ( const name of configMap . keys ( ) ) {
92
- if ( ! names . includes ( name ) ) {
93
- configMap . delete ( name ) ;
94
- }
95
- }
96
- }
97
-
98
- /**
99
- * Update the config status maps from the result of parsing a single ADS
100
- * response. All resources that validated are considered "ACKED", and all
101
- * resources that failed validation are considered "NACKED".
102
- * @param typeUrl The type URL of resources in this response
103
- * @param versionInfo The version info field from this response
104
- * @param updates The lists of resources that passed and failed validation
105
- */
106
- export function updateCsdsResourceResponse ( typeUrl : AdsTypeUrl , versionInfo : string , updates : HandleResponseResult ) {
107
- const currentTime = dateToProtoTimestamp ( new Date ( ) ) ;
108
- const configMap = configStatus [ typeUrl ] ;
109
- for ( const { name, raw} of updates . accepted ) {
110
- const mapEntry = configMap . get ( name ) ;
111
- if ( mapEntry ) {
112
- trace ( 'Updated ' + typeUrl + ' resource ' + name + ' to state ACKED' ) ;
113
- mapEntry . client_status = 'ACKED' ;
114
- mapEntry . version_info = versionInfo ;
115
- mapEntry . xds_config = raw ;
116
- mapEntry . error_state = null ;
117
- mapEntry . last_updated = currentTime ;
55
+ function getCurrentConfigList ( ) : ClientConfig [ ] {
56
+ const result : ClientConfig [ ] = [ ] ;
57
+ for ( const client of registeredClients ) {
58
+ if ( ! client . adsNode ) {
59
+ continue ;
118
60
}
119
- }
120
- for ( const { name, error, raw} of updates . rejected ) {
121
- const mapEntry = configMap . get ( name ) ;
122
- if ( mapEntry ) {
123
- trace ( 'Updated ' + typeUrl + ' resource ' + name + ' to state NACKED' ) ;
124
- mapEntry . client_status = 'NACKED' ;
125
- mapEntry . error_state = {
126
- failed_configuration : raw ,
127
- last_update_attempt : currentTime ,
128
- details : error ,
129
- version_info : versionInfo
130
- } ;
131
- }
132
- }
133
- for ( const name of updates . missing ) {
134
- const mapEntry = configMap . get ( name ) ;
135
- if ( mapEntry ) {
136
- trace ( 'Updated ' + typeUrl + ' resource ' + name + ' to state DOES_NOT_EXIST' ) ;
137
- mapEntry . client_status = 'DOES_NOT_EXIST' ;
138
- mapEntry . version_info = versionInfo ;
139
- mapEntry . xds_config = null ;
140
- mapEntry . error_state = null ;
141
- mapEntry . last_updated = currentTime ;
142
- }
143
- }
144
- }
145
-
146
- function getCurrentConfig ( ) : ClientConfig {
147
- const genericConfigList : GenericXdsConfig [ ] = [ ] ;
148
- for ( const configMap of Object . values ( configStatus ) ) {
149
- for ( const configValue of configMap . values ( ) ) {
150
- genericConfigList . push ( configValue ) ;
61
+ const genericConfigList : GenericXdsConfig [ ] = [ ] ;
62
+ for ( const [ authority , authorityState ] of client . authorityStateMap ) {
63
+ for ( const [ type , typeMap ] of authorityState . resourceMap ) {
64
+ for ( const [ key , resourceState ] of typeMap ) {
65
+ const typeUrl = type . getTypeUrl ( ) ;
66
+ const meta = resourceState . meta ;
67
+ genericConfigList . push ( {
68
+ name : xdsResourceNameToString ( { authority, key} , typeUrl ) ,
69
+ type_url : typeUrl ,
70
+ client_status : meta . clientStatus ,
71
+ version_info : meta . version ,
72
+ xds_config : meta . clientStatus === 'ACKED' ? meta . rawResource : undefined ,
73
+ last_updated : meta . updateTime ? dateToProtoTimestamp ( meta . updateTime ) : undefined ,
74
+ error_state : meta . clientStatus === 'NACKED' ? {
75
+ details : meta . failedDetails ,
76
+ failed_configuration : meta . rawResource ,
77
+ last_update_attempt : meta . failedUpdateTime ? dateToProtoTimestamp ( meta . failedUpdateTime ) : undefined ,
78
+ version_info : meta . failedVersion
79
+ } : undefined
80
+ } ) ;
81
+ }
82
+ }
151
83
}
84
+ result . push ( {
85
+ node : client . adsNode ,
86
+ generic_xds_configs : genericConfigList
87
+ } ) ;
152
88
}
153
- const config = {
154
- node : clientNode ,
155
- generic_xds_configs : genericConfigList
156
- } ;
157
- trace ( 'Sending current config ' + JSON . stringify ( config , undefined , 2 ) ) ;
158
- return config ;
89
+ return result ;
159
90
}
160
91
161
92
const csdsImplementation : ClientStatusDiscoveryServiceHandlers = {
@@ -169,7 +100,7 @@ const csdsImplementation: ClientStatusDiscoveryServiceHandlers = {
169
100
return ;
170
101
}
171
102
callback ( null , {
172
- config : [ getCurrentConfig ( ) ]
103
+ config : getCurrentConfigList ( )
173
104
} ) ;
174
105
} ,
175
106
StreamClientStatus ( call : ServerDuplexStream < ClientStatusRequest__Output , ClientStatusResponse > ) {
@@ -182,7 +113,7 @@ const csdsImplementation: ClientStatusDiscoveryServiceHandlers = {
182
113
return ;
183
114
}
184
115
call . write ( {
185
- config : [ getCurrentConfig ( ) ]
116
+ config : getCurrentConfigList ( )
186
117
} ) ;
187
118
} ) ;
188
119
call . on ( 'end' , ( ) => {
@@ -211,4 +142,4 @@ const csdsServiceDefinition = csdsGrpcObject.envoy.service.status.v3.ClientStatu
211
142
212
143
export function setup ( ) {
213
144
registerAdminService ( ( ) => csdsServiceDefinition , ( ) => csdsImplementation ) ;
214
- }
145
+ }
0 commit comments