Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Commit 89112b8

Browse files
committed
[FAB-8330] grpcs fallback to grpc when failed
For Orderer, Peer, Events when protocol is not mentioned in the URL, - GRPCS will be tried first - If connection fails, it will fall back to GRPC when 'allow-insecure=true' Change-Id: I1421fa4f60702a7ea1980ad4dfe600d08d752c43 Signed-off-by: Sudesh Shetty <sudesh.shetty@securekey.com>
1 parent 614551a commit 89112b8

File tree

24 files changed

+460
-174
lines changed

24 files changed

+460
-174
lines changed

api/apifabclient/event.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616

1717
// EventHub ...
1818
type EventHub interface {
19-
SetPeerAddr(peerURL string, certificate *x509.Certificate, serverHostOverride string)
19+
SetPeerAddr(peerURL string, certificate *x509.Certificate, serverHostOverride string, allowInsecure bool)
2020
IsConnected() bool
2121
Connect() error
2222
Disconnect() error

pkg/config/comm/comm.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@ import (
1919
// TLSConfig returns the appropriate config for TLS including the root CAs,
2020
// certs for mutual TLS, and server host override. Works with certs loaded either from a path or embedded pem.
2121
func TLSConfig(cert *x509.Certificate, serverName string, config apiconfig.Config) (*tls.Config, error) {
22-
certPool, _ := config.TLSCACertPool()
22+
certPool, err := config.TLSCACertPool()
23+
if err != nil {
24+
return nil, err
25+
}
2326

2427
if cert == nil && (certPool == nil || len(certPool.Subjects()) == 0) {
25-
return nil, errors.New("certificate is required")
28+
//Return empty tls config if there is no cert provided or if certpool unavailable
29+
return &tls.Config{}, nil
2630
}
2731

2832
tlsCaCertPool, err := config.TLSCACertPool(cert)

pkg/config/comm/comm_test.go

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package comm
88

99
import (
1010
"bytes"
11-
"crypto/x509"
1211
"encoding/hex"
1312
"testing"
1413

@@ -22,29 +21,6 @@ import (
2221
"github.com/hyperledger/fabric-sdk-go/api/apiconfig/mocks"
2322
)
2423

25-
func TestTLSConfigEmptyCertPoolAndCertificate(t *testing.T) {
26-
mockCtrl := gomock.NewController(t)
27-
defer mockCtrl.Finish()
28-
config := mock_apiconfig.NewMockConfig(mockCtrl)
29-
30-
// nil cert pool
31-
config.EXPECT().TLSCACertPool().Return(nil, nil)
32-
33-
_, err := TLSConfig(nil, "", config)
34-
if err == nil {
35-
t.Fatal("Expected failure with nil cert pool")
36-
}
37-
38-
// empty cert pool
39-
certPool := x509.NewCertPool()
40-
config.EXPECT().TLSCACertPool().Return(certPool, nil)
41-
42-
_, err = TLSConfig(nil, "", config)
43-
if err == nil {
44-
t.Fatal("Expected failure with empty cert pool")
45-
}
46-
}
47-
4824
func TestTLSConfigErrorAddingCertificate(t *testing.T) {
4925
mockCtrl := gomock.NewController(t)
5026
defer mockCtrl.Finish()

pkg/config/testdata/config_test_pem.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ orderers:
239239
grpcOptions:
240240
ssl-target-name-override: orderer.example.com
241241
grpc-max-send-message-length: 15
242+
allow-insecure: false
242243

243244
tlsCACerts:
244245
# pem supersedes path
@@ -276,6 +277,7 @@ peers:
276277
grpcOptions:
277278
ssl-target-name-override: peer0.org1.example.com
278279
grpc.http2.keepalive_time: 15
280+
allow-insecure: false
279281

280282
tlsCACerts:
281283
pem: |
@@ -303,6 +305,7 @@ peers:
303305
eventUrl: grpcs://peer0.org2.example.com:7053
304306
grpcOptions:
305307
ssl-target-name-override: peer0.org2.example.com
308+
allow-insecure: false
306309
tlsCACerts:
307310
pem:
308311
path:

pkg/config/testdata/template/config.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ orderers:
209209
#fail-fast is action to take when an RPC is attempted on broken connections or unreachable servers
210210
# fail-fast: true
211211

212+
# When no protocol provided in url, grpcs connection will be tried first, if failed it falls back to grpc when this option set to true
213+
# allow-insecure: true
214+
212215
# tlsCACerts:
213216
# Certificate location absolute path
214217
# path: ${GOPATH}/src/github.com/hyperledger/fabric-sdk-go/test/fixtures/channel/crypto-config/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem
@@ -228,6 +231,8 @@ peers:
228231
# grpcOptions:
229232
# ssl-target-name-override: peer0.org1.example.com
230233
# grpc.http2.keepalive_time: 15
234+
# When no protocol provided in url, grpcs connection will be tried first, if failed it falls back to grpc when this option set to true
235+
# allow-insecure: true
231236

232237
# tlsCACerts:
233238
# Certificate location absolute path

pkg/config/urlutil/urlutils.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ package urlutil
99
import (
1010
"strings"
1111

12+
"regexp"
13+
1214
"github.com/hyperledger/fabric-sdk-go/pkg/logging"
1315
)
1416

@@ -33,8 +35,22 @@ func ToAddress(url string) string {
3335
if strings.HasPrefix(url, "grpcs://") {
3436
return strings.TrimPrefix(url, "grpcs://")
3537
}
36-
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
37-
logger.Warnf("URL '%s' has no prefix. Please enter a prefix as it will be mandatory in a future release", url)
38-
}
3938
return url
4039
}
40+
41+
//AttemptSecured is a utility function which verifies URL and returns if secured connections needs to established
42+
func AttemptSecured(url string) bool {
43+
ok, err := regexp.MatchString(".*(?i)s://", url)
44+
if ok && err == nil {
45+
return true
46+
} else if !strings.Contains(url, "://") {
47+
return true
48+
} else {
49+
return false
50+
}
51+
}
52+
53+
//HasProtocol is a utility function which verifies if protocol is provided in URL
54+
func HasProtocol(url string) bool {
55+
return strings.Contains(url, "://")
56+
}

pkg/fabric-client/channel/channel.go

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ package channel
99
import (
1010
"crypto/x509"
1111
"encoding/pem"
12-
"regexp"
1312
"strings"
1413

1514
"github.com/pkg/errors"
@@ -91,7 +90,7 @@ func New(ctx fab.Context, cfg fab.ChannelCfg) (*Channel, error) {
9190

9291
var o *orderer.Orderer
9392
if oCfg == nil {
94-
o, err = orderer.New(ctx.Config(), orderer.WithURL(resolveOrdererURL(name)), orderer.WithServerName(resolveOrdererAddress(name)))
93+
o, err = orderer.New(ctx.Config(), orderer.WithURL(name), orderer.WithServerName(resolveOrdererAddress(name)))
9594
} else {
9695
o, err = orderer.New(ctx.Config(), orderer.FromOrdererConfig(oCfg))
9796
}
@@ -319,14 +318,6 @@ func resolveOrdererAddress(ordererAddress string) string {
319318
return ordererAddress
320319
}
321320

322-
// resolveOrdererURL resolves order URL to prefix protocol if not present
323-
func resolveOrdererURL(ordererURL string) string {
324-
if ok, err := regexp.MatchString(".*://", ordererURL); ok && err == nil {
325-
return ordererURL
326-
}
327-
return "grpcs://" + ordererURL
328-
}
329-
330321
// QueryInfo queries for various useful information on the state of the channel
331322
// (height, known peers).
332323
// This query will be made to the primary peer.

pkg/fabric-client/events/consumer/consumer.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,15 @@ type eventsClient struct {
5353
processEventsCompleted chan struct{}
5454
kap keepalive.ClientParameters
5555
failFast bool
56+
secured bool
57+
allowInsecure bool
5658
}
5759

5860
//NewEventsClient Returns a new grpc.ClientConn to the configured local PEER.
5961
func NewEventsClient(provider fab.ProviderContext, identity fab.IdentityContext, peerAddress string, certificate *x509.Certificate,
6062
serverhostoverride string, regTimeout time.Duration, adapter consumer.EventAdapter,
61-
kap keepalive.ClientParameters, failFast bool) (fab.EventsClient, error) {
63+
kap keepalive.ClientParameters, failFast bool, allowInsecure bool) (fab.EventsClient, error) {
64+
6265
var err error
6366
if regTimeout < 100*time.Millisecond {
6467
regTimeout = 100 * time.Millisecond
@@ -80,14 +83,17 @@ func NewEventsClient(provider fab.ProviderContext, identity fab.IdentityContext,
8083
tlsCertHash: ccomm.TLSCertHash(provider.Config()),
8184
kap: kap,
8285
failFast: failFast,
86+
secured: urlutil.AttemptSecured(peerAddress),
87+
allowInsecure: allowInsecure,
8388
}, err
8489
}
8590

8691
//newEventsClientConnectionWithAddress Returns a new grpc.ClientConn to the configured local PEER.
8792
func newEventsClientConnectionWithAddress(peerAddress string, cert *x509.Certificate, serverHostOverride string,
88-
config apiconfig.Config, kap keepalive.ClientParameters, failFast bool) (*grpc.ClientConn, error) {
93+
config apiconfig.Config, kap keepalive.ClientParameters, failFast bool, secured bool) (*grpc.ClientConn, error) {
8994
var opts []grpc.DialOption
90-
if urlutil.IsTLSEnabled(peerAddress) {
95+
opts = append(opts, grpc.WithTimeout(config.TimeoutOrDefault(apiconfig.EventHub)))
96+
if secured {
9197
tlsConfig, err := comm.TLSConfig(cert, serverHostOverride, config)
9298
if err != nil {
9399
return nil, err
@@ -301,8 +307,13 @@ func (ec *eventsClient) processEvents() error {
301307

302308
//Start establishes connection with Event hub and registers interested events with it
303309
func (ec *eventsClient) Start() error {
310+
return ec.establishConnectionAndRegister(ec.secured)
311+
}
312+
313+
func (ec *eventsClient) establishConnectionAndRegister(secured bool) error {
304314
conn, err := newEventsClientConnectionWithAddress(ec.peerAddress, ec.TLSCertificate, ec.TLSServerHostOverride,
305-
ec.provider.Config(), ec.kap, ec.failFast)
315+
ec.provider.Config(), ec.kap, ec.failFast, secured)
316+
306317
if err != nil {
307318
return errors.WithMessage(err, "events connection failed")
308319
}
@@ -320,6 +331,12 @@ func (ec *eventsClient) Start() error {
320331
serverClient := ehpb.NewEventsClient(conn)
321332
ec.stream, err = serverClient.Chat(context.Background())
322333
if err != nil {
334+
logger.Error("events connection failed, cause: ", err)
335+
if secured && ec.allowInsecure {
336+
//If secured mode failed and allow insecure is enabled then retry in insecure mode
337+
logger.Debug("Secured establishConnectionAndRegister failed, attempting insecured")
338+
return ec.establishConnectionAndRegister(false)
339+
}
323340
return errors.Wrap(err, "events connection failed")
324341
}
325342

pkg/fabric-client/events/eventhub.go

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,23 +60,24 @@ type EventHub struct {
6060
// Factory that creates EventsClient
6161
eventsClientFactory eventClientFactory
6262
// FabricClient
63-
provider fab.ProviderContext
64-
identity fab.IdentityContext
65-
kap keepalive.ClientParameters
66-
failFast bool
63+
provider fab.ProviderContext
64+
identity fab.IdentityContext
65+
kap keepalive.ClientParameters
66+
failFast bool
67+
allowInsecure bool
6768
}
6869

6970
// eventClientFactory creates an EventsClient instance
7071
type eventClientFactory interface {
71-
newEventsClient(provider fab.ProviderContext, identity fab.IdentityContext, peerAddress string, certificate *x509.Certificate, serverHostOverride string, regTimeout time.Duration, adapter cnsmr.EventAdapter, kap keepalive.ClientParameters, failFast bool) (fab.EventsClient, error)
72+
newEventsClient(provider fab.ProviderContext, identity fab.IdentityContext, peerAddress string, certificate *x509.Certificate, serverHostOverride string, regTimeout time.Duration, adapter cnsmr.EventAdapter, kap keepalive.ClientParameters, failFast bool, allowInsecure bool) (fab.EventsClient, error)
7273
}
7374

7475
// consumerClientFactory is the default implementation oif the eventClientFactory
7576
type consumerClientFactory struct{}
7677

7778
func (ccf *consumerClientFactory) newEventsClient(provider fab.ProviderContext, identity fab.IdentityContext, peerAddress string, certificate *x509.Certificate, serverHostOverride string,
78-
regTimeout time.Duration, adapter cnsmr.EventAdapter, kap keepalive.ClientParameters, failFast bool) (fab.EventsClient, error) {
79-
return consumer.NewEventsClient(provider, identity, peerAddress, certificate, serverHostOverride, regTimeout, adapter, kap, failFast)
79+
regTimeout time.Duration, adapter cnsmr.EventAdapter, kap keepalive.ClientParameters, failFast bool, allowInsecure bool) (fab.EventsClient, error) {
80+
return consumer.NewEventsClient(provider, identity, peerAddress, certificate, serverHostOverride, regTimeout, adapter, kap, failFast, allowInsecure)
8081
}
8182

8283
// Context holds the providers and services needed to create an EventHub.
@@ -126,6 +127,8 @@ func FromConfig(ctx Context, peerCfg *apiconfig.PeerConfig) (*EventHub, error) {
126127
eventHub.peerTLSServerHostOverride = serverHostOverride
127128
eventHub.kap = getKeepAliveOptions(peerCfg)
128129
eventHub.failFast = getFailFast(peerCfg)
130+
eventHub.allowInsecure = isInsecureConnectionAllowed(peerCfg)
131+
129132
return eventHub, nil
130133
}
131134

@@ -278,10 +281,12 @@ func (eventHub *EventHub) removeChaincodeInterest(ChaincodeID string, EventName
278281
// peeraddr peer url
279282
// peerTLSCertificate peer tls certificate
280283
// peerTLSServerHostOverride tls serverhostoverride
281-
func (eventHub *EventHub) SetPeerAddr(peerURL string, peerTLSCertificate *x509.Certificate, peerTLSServerHostOverride string) {
284+
// inSecure option enables grpc retry when grpcs fails (only when no protocol provided in peerURL)
285+
func (eventHub *EventHub) SetPeerAddr(peerURL string, peerTLSCertificate *x509.Certificate, peerTLSServerHostOverride string, allowInsecure bool) {
282286
eventHub.peerAddr = peerURL
283287
eventHub.peerTLSCertificate = peerTLSCertificate
284288
eventHub.peerTLSServerHostOverride = peerTLSServerHostOverride
289+
eventHub.allowInsecure = allowInsecure && !urlutil.HasProtocol(peerURL)
285290
}
286291

287292
// IsConnected gets connected state of eventhub
@@ -312,7 +317,7 @@ func (eventHub *EventHub) Connect() error {
312317
if eventHub.grpcClient == nil {
313318
eventsClient, _ := eventHub.eventsClientFactory.newEventsClient(eventHub.provider, eventHub.identity,
314319
eventHub.peerAddr, eventHub.peerTLSCertificate, eventHub.peerTLSServerHostOverride,
315-
eventHub.provider.Config().TimeoutOrDefault(apiconfig.EventReg), eventHub, eventHub.kap, eventHub.failFast)
320+
eventHub.provider.Config().TimeoutOrDefault(apiconfig.EventReg), eventHub, eventHub.kap, eventHub.failFast, eventHub.allowInsecure)
316321
eventHub.grpcClient = eventsClient
317322
}
318323

@@ -602,3 +607,13 @@ func (eventHub *EventHub) notifyChaincodeRegistrants(channelID string, ccEvent *
602607
}
603608
}
604609
}
610+
611+
func isInsecureConnectionAllowed(peerCfg *apiconfig.PeerConfig) bool {
612+
//allowInsecure used only when protocol is missing from URL
613+
allowInsecure := !urlutil.HasProtocol(peerCfg.URL)
614+
boolVal, ok := peerCfg.GRPCOptions["allow-insecure"].(bool)
615+
if ok {
616+
return allowInsecure && boolVal
617+
}
618+
return false
619+
}

pkg/fabric-client/events/eventmocks.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ type mockEventClientFactory struct {
4545
}
4646

4747
func (mecf *mockEventClientFactory) newEventsClient(provider fab.ProviderContext, identity fab.IdentityContext, peerAddress string, certificate *x509.Certificate, serverHostOverride string, regTimeout time.Duration,
48-
adapter fcConsumer.EventAdapter, kap keepalive.ClientParameters, failFast bool) (fab.EventsClient, error) {
48+
adapter fcConsumer.EventAdapter, kap keepalive.ClientParameters, failFast bool, allowInsecure bool) (fab.EventsClient, error) {
4949
mec := &mockEventClient{
5050
PeerAddress: peerAddress,
5151
RegTimeout: regTimeout,
@@ -121,7 +121,7 @@ func createMockedEventHub() (*EventHub, *mockEventClientFactory, error) {
121121
var clientFactory mockEventClientFactory
122122
eventHub.eventsClientFactory = &clientFactory
123123

124-
eventHub.SetPeerAddr("mock://mock", nil, "")
124+
eventHub.SetPeerAddr("mock://mock", nil, "", true)
125125

126126
err = eventHub.Connect()
127127
if err != nil {

0 commit comments

Comments
 (0)