@@ -19,6 +19,11 @@ import * as fs from 'fs';
1919import { EXPERIMENTAL_FEDERATION } from './environment' ;
2020import { Struct } from './generated/google/protobuf/Struct' ;
2121import { 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 ;
2227
2328/* eslint-disable @typescript-eslint/no-explicit-any */
2429
@@ -51,12 +56,20 @@ export interface Authority {
5156 xdsServers ?: XdsServerConfig [ ] ;
5257}
5358
59+ export type PluginConfig = FileWatcherCertificateProviderConfig ;
60+
61+ export interface CertificateProviderConfig {
62+ pluginName : string ;
63+ config : PluginConfig ;
64+ }
65+
5466export interface BootstrapInfo {
5567 xdsServers : XdsServerConfig [ ] ;
5668 node : Node ;
5769 authorities : { [ authorityName : string ] : Authority } ;
5870 clientDefaultListenerResourceNameTemplate : string ;
5971 serverListenerResourceNameTemplate : string | null ;
72+ certificateProviders : { [ instanceName : string ] : CertificateProviderConfig } ;
6073}
6174
6275const KNOWN_SERVER_FEATURES = [ 'ignore_resource_deletion' ] ;
@@ -306,6 +319,71 @@ function validateAuthoritiesMap(obj: any): {[authorityName: string]: Authority}
306319 return result ;
307320}
308321
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+
309387export function validateBootstrapConfig ( obj : any ) : BootstrapInfo {
310388 const xdsServers = obj . xds_servers . map ( validateXdsServerConfig ) ;
311389 const node = validateNode ( obj . node ) ;
@@ -325,15 +403,17 @@ export function validateBootstrapConfig(obj: any): BootstrapInfo {
325403 node : node ,
326404 authorities : validateAuthoritiesMap ( obj . authorities ) ,
327405 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 )
329408 } ;
330409 } else {
331410 return {
332411 xdsServers : xdsServers ,
333412 node : node ,
334413 authorities : { } ,
335414 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 )
337417 } ;
338418 }
339419}
0 commit comments