@@ -295,6 +295,9 @@ enum BrokerRewriteHandle {
295
295
/// For _default_ ssh tunnels, we store an error if _creation_
296
296
/// of the tunnel failed, so that `tunnel_status` can return it.
297
297
FailedDefaultSshTunnel ( String ) ,
298
+ /// We store an error if DNS resolution fails when resolving
299
+ /// a new broker host.
300
+ FailedDNSResolution ( String ) ,
298
301
}
299
302
300
303
/// Tunneling clients
@@ -309,6 +312,24 @@ pub enum TunnelConfig {
309
312
None ,
310
313
}
311
314
315
+ /// Status of all active ssh tunnels and direct broker connections for a `TunnelingClientContext`.
316
+ #[ derive( Clone ) ]
317
+ pub struct TunnelingClientStatus {
318
+ /// Status of all active ssh tunnels.
319
+ pub ssh_status : SshTunnelStatus ,
320
+ /// Status of direct broker connections.
321
+ pub broker_status : BrokerStatus ,
322
+ }
323
+
324
+ /// Status of direct broker connections for a `TunnelingClientContext`.
325
+ #[ derive( Clone ) ]
326
+ pub enum BrokerStatus {
327
+ /// The broker connections are nominal.
328
+ Nominal ,
329
+ /// At least one broker connection has failed.
330
+ Failed ( String ) ,
331
+ }
332
+
312
333
/// A client context that supports rewriting broker addresses.
313
334
#[ derive( Clone ) ]
314
335
pub struct TunnelingClientContext < C > {
@@ -391,19 +412,22 @@ impl<C> TunnelingClientContext<C> {
391
412
& self . inner
392
413
}
393
414
394
- /// Returns a _consolidated_ `SshTunnelStatus` that communicates the status
395
- /// of all active ssh tunnels `self` knows about.
396
- pub fn tunnel_status ( & self ) -> SshTunnelStatus {
397
- self . rewrites
398
- . lock ( )
399
- . expect ( "poisoned" )
415
+ /// Returns a `TunnelingClientStatus` that contains a _consolidated_ `SshTunnelStatus` to
416
+ /// communicates the status of all active ssh tunnels `self` knows about, and a `BrokerStatus`
417
+ /// that contains a _consolidated_ status of all direct broker connections.
418
+ pub fn tunnel_status ( & self ) -> TunnelingClientStatus {
419
+ let rewrites = self . rewrites . lock ( ) . expect ( "poisoned" ) ;
420
+
421
+ let ssh_status = rewrites
400
422
. values ( )
401
423
. map ( |handle| match handle {
402
424
BrokerRewriteHandle :: SshTunnel ( s) => s. check_status ( ) ,
403
425
BrokerRewriteHandle :: FailedDefaultSshTunnel ( e) => {
404
426
SshTunnelStatus :: Errored ( e. clone ( ) )
405
427
}
406
- BrokerRewriteHandle :: Simple ( _) => SshTunnelStatus :: Running ,
428
+ BrokerRewriteHandle :: Simple ( _) | BrokerRewriteHandle :: FailedDNSResolution ( _) => {
429
+ SshTunnelStatus :: Running
430
+ }
407
431
} )
408
432
. fold ( SshTunnelStatus :: Running , |acc, status| {
409
433
match ( acc, status) {
@@ -418,7 +442,27 @@ impl<C> TunnelingClientContext<C> {
418
442
SshTunnelStatus :: Running
419
443
}
420
444
}
445
+ } ) ;
446
+
447
+ let broker_status = rewrites
448
+ . values ( )
449
+ . map ( |handle| match handle {
450
+ BrokerRewriteHandle :: FailedDNSResolution ( e) => BrokerStatus :: Failed ( e. clone ( ) ) ,
451
+ _ => BrokerStatus :: Nominal ,
421
452
} )
453
+ . fold ( BrokerStatus :: Nominal , |acc, status| match ( acc, status) {
454
+ ( BrokerStatus :: Nominal , BrokerStatus :: Failed ( e) )
455
+ | ( BrokerStatus :: Failed ( e) , BrokerStatus :: Nominal ) => BrokerStatus :: Failed ( e) ,
456
+ ( BrokerStatus :: Failed ( err) , BrokerStatus :: Failed ( e) ) => {
457
+ BrokerStatus :: Failed ( format ! ( "{}, {}" , err, e) )
458
+ }
459
+ ( BrokerStatus :: Nominal , BrokerStatus :: Nominal ) => BrokerStatus :: Nominal ,
460
+ } ) ;
461
+
462
+ TunnelingClientStatus {
463
+ ssh_status,
464
+ broker_status,
465
+ }
422
466
}
423
467
}
424
468
@@ -441,7 +485,8 @@ where
441
485
port : Some ( addr. port ( ) ) ,
442
486
}
443
487
}
444
- BrokerRewriteHandle :: FailedDefaultSshTunnel ( _) => {
488
+ BrokerRewriteHandle :: FailedDefaultSshTunnel ( _)
489
+ | BrokerRewriteHandle :: FailedDNSResolution ( _) => {
445
490
unreachable ! ( )
446
491
}
447
492
} ;
@@ -463,16 +508,30 @@ where
463
508
let rewrite = self . rewrites . lock ( ) . expect ( "poisoned" ) . get ( & addr) . cloned ( ) ;
464
509
465
510
match rewrite {
466
- None | Some ( BrokerRewriteHandle :: FailedDefaultSshTunnel ( _) ) => {
511
+ None
512
+ | Some ( BrokerRewriteHandle :: FailedDefaultSshTunnel ( _) )
513
+ | Some ( BrokerRewriteHandle :: FailedDNSResolution ( _) ) => {
467
514
match & self . default_tunnel {
468
515
TunnelConfig :: Ssh ( default_tunnel) => {
469
516
// Multiple users could all run `connect` at the same time; only one ssh
470
517
// tunnel will ever be connected, and only one will be inserted into the
471
518
// map.
472
519
let ssh_tunnel = self . runtime . block_on ( async {
520
+ // Ensure the default tunnel host is resolved to an external address.
521
+ let resolved_tunnel_addr = resolve_external_address (
522
+ & default_tunnel. host ,
523
+ self . enforce_external_addresses ,
524
+ )
525
+ . await ?;
526
+ let tunnel_config = SshTunnelConfig {
527
+ host : resolved_tunnel_addr. to_string ( ) ,
528
+ port : default_tunnel. port ,
529
+ user : default_tunnel. user . clone ( ) ,
530
+ key_pair : default_tunnel. key_pair . clone ( ) ,
531
+ } ;
473
532
self . ssh_tunnel_manager
474
533
. connect (
475
- default_tunnel . clone ( ) ,
534
+ tunnel_config ,
476
535
& addr. host ,
477
536
addr. port . parse ( ) . unwrap ( ) ,
478
537
self . ssh_timeout_config ,
@@ -487,6 +546,7 @@ where
487
546
if matches ! (
488
547
o. get( ) ,
489
548
BrokerRewriteHandle :: FailedDefaultSshTunnel ( _)
549
+ | BrokerRewriteHandle :: FailedDNSResolution ( _)
490
550
) =>
491
551
{
492
552
o. insert ( BrokerRewriteHandle :: SshTunnel (
@@ -533,19 +593,42 @@ where
533
593
TunnelConfig :: None => {
534
594
// If no rewrite is specified, we still should check that this potentially
535
595
// new broker address is a global address.
536
- let rewrite = self . runtime . block_on ( async {
537
- let resolved = resolve_external_address (
596
+ self . runtime . block_on ( async {
597
+ match resolve_external_address (
538
598
& addr. host ,
539
599
self . enforce_external_addresses ,
540
600
)
541
601
. await
542
- . unwrap ( ) ;
543
- BrokerRewriteHandle :: Simple ( BrokerRewrite {
544
- host : resolved. to_string ( ) ,
545
- port : addr. port . parse ( ) . ok ( ) ,
546
- } )
547
- } ) ;
548
- return_rewrite ( & rewrite)
602
+ {
603
+ Ok ( resolved) => {
604
+ let rewrite = BrokerRewriteHandle :: Simple ( BrokerRewrite {
605
+ host : resolved. to_string ( ) ,
606
+ port : addr. port . parse ( ) . ok ( ) ,
607
+ } ) ;
608
+ return_rewrite ( & rewrite)
609
+ }
610
+ Err ( e) => {
611
+ warn ! (
612
+ "failed to resolve external address for {:?}: {}" ,
613
+ addr,
614
+ e. display_with_causes( )
615
+ ) ;
616
+ // Write an error if no one else has already written one.
617
+ let mut rewrites = self . rewrites . lock ( ) . expect ( "poisoned" ) ;
618
+ rewrites. entry ( addr. clone ( ) ) . or_insert_with ( || {
619
+ BrokerRewriteHandle :: FailedDNSResolution (
620
+ e. to_string_with_causes ( ) ,
621
+ )
622
+ } ) ;
623
+ // We have to give rdkafka an address, as this callback can't fail.
624
+ BrokerAddr {
625
+ host : "failed-dns-resolution.dev.materialize.com"
626
+ . to_string ( ) ,
627
+ port : 1337 . to_string ( ) ,
628
+ }
629
+ }
630
+ }
631
+ } )
549
632
}
550
633
}
551
634
}
0 commit comments