@@ -19,6 +19,11 @@ import * as fs from 'fs';
19
19
import { EXPERIMENTAL_FEDERATION } from './environment' ;
20
20
import { Struct } from './generated/google/protobuf/Struct' ;
21
21
import { Value } from './generated/google/protobuf/Value' ;
22
+ import { experimental } from '@grpc/grpc-js' ;
23
+
24
+ import parseDuration = experimental . parseDuration ;
25
+ import durationToMs = experimental . durationToMs ;
26
+ import FileWatcherCertificateProviderConfig = experimental . FileWatcherCertificateProviderConfig ;
22
27
23
28
/* eslint-disable @typescript-eslint/no-explicit-any */
24
29
@@ -51,12 +56,20 @@ export interface Authority {
51
56
xdsServers ?: XdsServerConfig [ ] ;
52
57
}
53
58
59
+ export type PluginConfig = FileWatcherCertificateProviderConfig ;
60
+
61
+ export interface CertificateProviderConfig {
62
+ pluginName : string ;
63
+ config : PluginConfig ;
64
+ }
65
+
54
66
export interface BootstrapInfo {
55
67
xdsServers : XdsServerConfig [ ] ;
56
68
node : Node ;
57
69
authorities : { [ authorityName : string ] : Authority } ;
58
70
clientDefaultListenerResourceNameTemplate : string ;
59
71
serverListenerResourceNameTemplate : string | null ;
72
+ certificateProviders : { [ instanceName : string ] : CertificateProviderConfig } ;
60
73
}
61
74
62
75
const KNOWN_SERVER_FEATURES = [ 'ignore_resource_deletion' ] ;
@@ -306,6 +319,71 @@ function validateAuthoritiesMap(obj: any): {[authorityName: string]: Authority}
306
319
return result ;
307
320
}
308
321
322
+ function validateFileWatcherPluginConfig ( obj : any , instanceName : string ) : FileWatcherCertificateProviderConfig {
323
+ if ( 'certificate_file' in obj && typeof obj . certificate_file !== 'string' ) {
324
+ throw new Error ( `certificate_providers[${ instanceName } ].config.certificate_file: expected string, got ${ typeof obj . certificate_file } ` ) ;
325
+ }
326
+ if ( 'private_key_file' in obj && typeof obj . private_key_file !== 'string' ) {
327
+ throw new Error ( `certificate_providers[${ instanceName } ].config.private_key_file: expected string, got ${ typeof obj . private_key_file } ` ) ;
328
+ }
329
+ if ( 'ca_certificate_file' in obj && typeof obj . ca_certificate_file !== 'string' ) {
330
+ throw new Error ( `certificate_providers[${ instanceName } ].config.ca_certificate_file: expected string, got ${ typeof obj . ca_certificate_file } ` ) ;
331
+ }
332
+ if ( typeof obj . refresh_interval !== 'string' ) {
333
+ throw new Error ( `certificate_providers[${ instanceName } ].config.refresh_interval: expected string, got ${ typeof obj . refresh_interval } ` ) ;
334
+ }
335
+ if ( ( 'private_key_file' in obj ) !== ( 'certificate_file' in obj ) ) {
336
+ throw new Error ( `certificate_providers[${ instanceName } ].config: private_key_file and certificate_file must be provided or omitted together` ) ;
337
+ }
338
+ if ( ! ( 'private_key_file' in obj ) && ! ( 'ca_certificate_file' in obj ) ) {
339
+ throw new Error ( `certificate_providers[${ instanceName } ].config: either private_key_file and certificate_file or ca_certificate_file must be set` ) ;
340
+ }
341
+ const refreshDuration = parseDuration ( obj . refresh_interval ) ;
342
+ if ( ! refreshDuration ) {
343
+ throw new Error ( `certificate_providers[${ instanceName } ].config.refresh_interval: failed to parse duration from value ${ obj . refresh_interval } ` ) ;
344
+ }
345
+ return {
346
+ certificateFile : obj . certificate_file ,
347
+ privateKeyFile : obj . private_key_file ,
348
+ caCertificateFile : obj . caCertificateFile ,
349
+ refreshIntervalMs : durationToMs ( refreshDuration )
350
+ } ;
351
+ }
352
+
353
+ const pluginConfigValidators : { [ typeName : string ] : ( obj : any , instanceName : string ) => PluginConfig } = {
354
+ 'file_watcher' : validateFileWatcherPluginConfig
355
+ } ;
356
+
357
+ function validateCertificateProvider ( obj : any , instanceName : string ) : CertificateProviderConfig {
358
+ if ( ! ( 'plugin_name' in obj ) || typeof obj . plugin_name !== 'string' ) {
359
+ throw new Error ( `certificate_providers[${ instanceName } ].plugin_name: expected string, got ${ typeof obj . plugin_name } ` ) ;
360
+ }
361
+ if ( ! ( obj . plugin_name in pluginConfigValidators ) ) {
362
+ throw new Error ( `certificate_providers[${ instanceName } ]: unknown plugin_name ${ obj . plugin_name } ` ) ;
363
+ }
364
+ if ( ! obj . config ) {
365
+ throw new Error ( `certificate_providers[${ instanceName } ].config: expected object, got ${ typeof obj . config } ` ) ;
366
+ }
367
+ if ( ! ( obj . plugin_name in pluginConfigValidators ) ) {
368
+ throw new Error ( `certificate_providers[${ instanceName } ].config: unknown plugin_name ${ obj . plugin_name } ` ) ;
369
+ }
370
+ return {
371
+ pluginName : obj . plugin_name ,
372
+ config : pluginConfigValidators [ obj . plugin_name ] ! ( obj . config , instanceName )
373
+ } ;
374
+ }
375
+
376
+ function validateCertificateProvidersMap ( obj : any ) : { [ instanceName : string ] : CertificateProviderConfig } {
377
+ if ( ! obj ) {
378
+ return { } ;
379
+ }
380
+ const result : { [ instanceName : string ] : CertificateProviderConfig } = { } ;
381
+ for ( const [ name , provider ] of Object . entries ( obj ) ) {
382
+ result [ name ] = validateCertificateProvider ( provider , name ) ;
383
+ }
384
+ return result ;
385
+ }
386
+
309
387
export function validateBootstrapConfig ( obj : any ) : BootstrapInfo {
310
388
const xdsServers = obj . xds_servers . map ( validateXdsServerConfig ) ;
311
389
const node = validateNode ( obj . node ) ;
@@ -325,15 +403,17 @@ export function validateBootstrapConfig(obj: any): BootstrapInfo {
325
403
node : node ,
326
404
authorities : validateAuthoritiesMap ( obj . authorities ) ,
327
405
clientDefaultListenerResourceNameTemplate : obj . client_default_listener_resource_name_template ?? '%s' ,
328
- serverListenerResourceNameTemplate : obj . server_listener_resource_name_template ?? null
406
+ serverListenerResourceNameTemplate : obj . server_listener_resource_name_template ?? null ,
407
+ certificateProviders : validateCertificateProvidersMap ( obj . certificate_providers )
329
408
} ;
330
409
} else {
331
410
return {
332
411
xdsServers : xdsServers ,
333
412
node : node ,
334
413
authorities : { } ,
335
414
clientDefaultListenerResourceNameTemplate : '%s' ,
336
- serverListenerResourceNameTemplate : obj . server_listener_resource_name_template ?? null
415
+ serverListenerResourceNameTemplate : obj . server_listener_resource_name_template ?? null ,
416
+ certificateProviders : validateCertificateProvidersMap ( obj . certificate_providers )
337
417
} ;
338
418
}
339
419
}
0 commit comments