@@ -32,10 +32,11 @@ impl<S> Outbound<S> {
32
32
. push_switch (
33
33
move |( profile, target) : ( Option < profiles:: Receiver > , T ) | -> Result < _ , Infallible > {
34
34
if let Some ( rx) = profile {
35
- // If the profile provides an endpoint, then the target is single endpoint and
36
- // not a logical/load-balanced service.
35
+ let is_opaque = rx. is_opaque_protocol ( ) ;
36
+
37
+ // If the profile provides an endpoint, then the target is single
38
+ // endpoint and not a logical/load-balanced service.
37
39
if let Some ( ( addr, metadata) ) = rx. endpoint ( ) {
38
- let is_opaque = rx. is_opaque_protocol ( ) ;
39
40
tracing:: debug!( %is_opaque, "Profile describes an endpoint" ) ;
40
41
return Ok ( svc:: Either :: A ( Endpoint :: from_metadata (
41
42
addr,
@@ -46,20 +47,33 @@ impl<S> Outbound<S> {
46
47
) ) ) ;
47
48
}
48
49
49
- // Otherwise, if the profile provides a (named) logical address, then we build a
50
+ // If the profile provides a (named) logical address, then we build a
50
51
// logical stack so we apply routes, traffic splits, and load balancing.
51
52
if let Some ( logical_addr) = rx. logical_addr ( ) {
52
53
tracing:: debug!( "Profile describes a logical service" ) ;
53
54
return Ok ( svc:: Either :: B ( Logical :: new ( logical_addr, rx) ) ) ;
54
55
}
56
+
57
+ // Otherwise, if there was a profile but it didn't include an endpoint or logical
58
+ // address, create a bare endpoint from the original destination address
59
+ // using the profile-provided opaqueness. This applies for targets that
60
+ // aren't known by the destination controller that may target ports
61
+ // included in the cluster-wide default opaque list.
62
+ tracing:: debug!( "Unknown endpoint" ) ;
63
+ return Ok ( svc:: Either :: A ( Endpoint :: forward (
64
+ target. param ( ) ,
65
+ no_tls_reason,
66
+ is_opaque,
67
+ ) ) ) ;
55
68
}
56
69
57
- // If there was no profile or it didn't include any useful metadata , create a bare
58
- // endpoint from the original destination address.
59
- tracing:: debug!( "No profile; forwarding to the original destination " ) ;
70
+ // If there was no profile, create a bare endpoint from the original
71
+ // destination address.
72
+ tracing:: debug!( "No profile" ) ;
60
73
Ok ( svc:: Either :: A ( Endpoint :: forward (
61
74
target. param ( ) ,
62
75
no_tls_reason,
76
+ false ,
63
77
) ) )
64
78
} ,
65
79
logical,
@@ -175,4 +189,37 @@ mod tests {
175
189
let ( server_io, _client_io) = io:: duplex ( 1 ) ;
176
190
svc. oneshot ( server_io) . await . expect ( "service must succeed" ) ;
177
191
}
192
+
193
+ #[ tokio:: test( flavor = "current_thread" ) ]
194
+ async fn profile_neither ( ) {
195
+ let _trace = linkerd_tracing:: test:: trace_init ( ) ;
196
+
197
+ let endpoint_addr = SocketAddr :: new ( [ 192 , 0 , 2 , 20 ] . into ( ) , 2020 ) ;
198
+ let endpoint = {
199
+ let endpoint_addr = endpoint_addr. clone ( ) ;
200
+ move |ep : tcp:: Endpoint | {
201
+ assert_eq ! ( ep. addr. as_ref( ) , & endpoint_addr) ;
202
+ assert ! ( ep. opaque_protocol, "protocol must be marked opaque" ) ;
203
+ svc:: mk ( |_: io:: DuplexStream | future:: ok :: < ( ) , Error > ( ( ) ) )
204
+ }
205
+ } ;
206
+
207
+ let ( rt, _shutdown) = runtime ( ) ;
208
+ let stack = Outbound :: new ( default_config ( ) , rt)
209
+ . with_stack ( endpoint)
210
+ . push_switch_logical ( svc:: Fail :: < _ , WrongStack > :: default ( ) )
211
+ . into_inner ( ) ;
212
+
213
+ let ( _tx, profile) = tokio:: sync:: watch:: channel ( profiles:: Profile {
214
+ endpoint : None ,
215
+ opaque_protocol : true ,
216
+ addr : None ,
217
+ ..Default :: default ( )
218
+ } ) ;
219
+
220
+ let orig_dst = OrigDstAddr ( endpoint_addr) ;
221
+ let svc = stack. new_service ( ( Some ( profile. into ( ) ) , orig_dst) ) ;
222
+ let ( server_io, _client_io) = io:: duplex ( 1 ) ;
223
+ svc. oneshot ( server_io) . await . expect ( "service must succeed" ) ;
224
+ }
178
225
}
0 commit comments