@@ -9,17 +9,17 @@ import (
99 "strings"
1010 "time"
1111
12+ "github.com/argoproj/argo-cd/v3/common"
1213 "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery"
1314 "github.com/sirupsen/logrus"
1415 "golang.org/x/net/proxy"
1516 "google.golang.org/grpc"
1617 "google.golang.org/grpc/codes"
18+ "google.golang.org/grpc/connectivity"
1719 "google.golang.org/grpc/credentials"
1820 "google.golang.org/grpc/credentials/insecure"
1921 "google.golang.org/grpc/keepalive"
2022 "google.golang.org/grpc/status"
21-
22- "github.com/argoproj/argo-cd/v3/common"
2323)
2424
2525// LoggerRecoveryHandler return a handler for recovering from panics and returning error
@@ -30,72 +30,54 @@ func LoggerRecoveryHandler(log *logrus.Entry) recovery.RecoveryHandlerFunc {
3030 }
3131}
3232
33- // BlockingDial is a helper method to dial the given address, using optional TLS credentials,
33+ // BlockingNewClient is a helper method to dial the given address, using optional TLS credentials,
3434// and blocking until the returned connection is ready. If the given credentials are nil, the
3535// connection will be insecure (plain-text).
3636// Lifted from: https://github.com/fullstorydev/grpcurl/blob/master/grpcurl.go
37- func BlockingDial (ctx context.Context , network , address string , creds credentials.TransportCredentials , opts ... grpc.DialOption ) (* grpc.ClientConn , error ) {
38- // grpc.Dial doesn't provide any information on permanent connection errors (like
39- // TLS handshake failures). So in order to provide good error messages, we need a
40- // custom dialer that can provide that info. That means we manage the TLS handshake.
41- result := make (chan any , 1 )
42- writeResult := func (res any ) {
43- // non-blocking write: we only need the first result
44- select {
45- case result <- res :
46- default :
47- }
37+ func BlockingNewClient (ctx context.Context , network , address string , creds credentials.TransportCredentials , opts ... grpc.DialOption ) (* grpc.ClientConn , error ) {
38+ rawConn , err := proxy .Dial (ctx , network , address )
39+ if err != nil {
40+ return nil , fmt .Errorf ("error dial proxy: %w" , err )
4841 }
49-
50- dialer := func (ctx context.Context , address string ) (net.Conn , error ) {
51- conn , err := proxy .Dial (ctx , network , address )
42+ if creds != nil {
43+ rawConn , _ , err = creds .ClientHandshake (ctx , address , rawConn )
5244 if err != nil {
53- writeResult (err )
54- return nil , fmt .Errorf ("error dial proxy: %w" , err )
45+ return nil , fmt .Errorf ("error creating connection: %w" , err )
5546 }
56- if creds != nil {
57- conn , _ , err = creds .ClientHandshake (ctx , address , conn )
58- if err != nil {
59- writeResult (err )
60- return nil , fmt .Errorf ("error creating connection: %w" , err )
61- }
62- }
63- return conn , nil
6447 }
6548
66- // Even with grpc.FailOnNonTempDialError, this call will usually timeout in
67- // the face of TLS handshake errors. So we can't rely on grpc.WithBlock() to
68- // know when we're done. So we run it in a goroutine and then use result
69- // channel to either get the channel or fail-fast.
70- go func () {
71- opts = append (opts ,
72- //nolint:staticcheck
73- grpc .WithBlock (),
74- //nolint:staticcheck
75- grpc .FailOnNonTempDialError (true ),
76- grpc .WithContextDialer (dialer ),
77- grpc .WithTransportCredentials (insecure .NewCredentials ()), // we are handling TLS, so tell grpc not to
78- grpc .WithKeepaliveParams (keepalive.ClientParameters {Time : common .GetGRPCKeepAliveTime ()}),
79- )
80- //nolint:staticcheck
81- conn , err := grpc .DialContext (ctx , address , opts ... )
82- var res any
83- if err != nil {
84- res = err
85- } else {
86- res = conn
87- }
88- writeResult (res )
89- }()
49+ customDialer := func (_ context.Context , _ string ) (net.Conn , error ) {
50+ return rawConn , nil
51+ }
52+
53+ opts = append (opts ,
54+ grpc .WithContextDialer (customDialer ),
55+ grpc .WithTransportCredentials (insecure .NewCredentials ()), // we are handling TLS, so tell grpc not to
56+ grpc .WithKeepaliveParams (keepalive.ClientParameters {Time : common .GetGRPCKeepAliveTime ()}),
57+ )
9058
91- select {
92- case res := <- result :
93- if conn , ok := res .(* grpc.ClientConn ); ok {
94- return conn , nil
59+ conn , err := grpc .NewClient (address , opts ... )
60+ if err != nil {
61+ return nil , err
62+ }
63+
64+ conn .Connect ()
65+ if err := waitForReady (ctx , conn ); err != nil {
66+ return nil , err
67+ }
68+
69+ return conn , nil
70+ }
71+
72+ func waitForReady (ctx context.Context , conn * grpc.ClientConn ) error {
73+ for {
74+ state := conn .GetState ()
75+ if state == connectivity .Ready {
76+ return nil
77+ }
78+ if ! conn .WaitForStateChange (ctx , state ) {
79+ return ctx .Err () // timeout or canceled
9580 }
96- return nil , res .(error )
97- case <- ctx .Done ():
98- return nil , ctx .Err ()
9981 }
10082}
10183
@@ -119,15 +101,15 @@ func TestTLS(address string, dialTime time.Duration) (*TLSTestResult, error) {
119101 ctx , cancel := context .WithTimeout (context .Background (), dialTime )
120102 defer cancel ()
121103
122- conn , err := BlockingDial (ctx , "tcp" , address , creds )
104+ conn , err := BlockingNewClient (ctx , "tcp" , address , creds )
123105 if err == nil {
124106 _ = conn .Close ()
125107 testResult .TLS = true
126108 creds := credentials .NewTLS (& tls.Config {})
127109 ctx , cancel := context .WithTimeout (context .Background (), dialTime )
128110 defer cancel ()
129111
130- conn , err := BlockingDial (ctx , "tcp" , address , creds )
112+ conn , err := BlockingNewClient (ctx , "tcp" , address , creds )
131113 if err == nil {
132114 _ = conn .Close ()
133115 } else {
@@ -142,7 +124,7 @@ func TestTLS(address string, dialTime time.Duration) (*TLSTestResult, error) {
142124 // refused). Test if server accepts plain-text connections
143125 ctx , cancel = context .WithTimeout (context .Background (), dialTime )
144126 defer cancel ()
145- conn , err = BlockingDial (ctx , "tcp" , address , nil )
127+ conn , err = BlockingNewClient (ctx , "tcp" , address , nil )
146128 if err == nil {
147129 _ = conn .Close ()
148130 testResult .TLS = false
0 commit comments