diff --git a/core/chaincode/chaincode_support.go b/core/chaincode/chaincode_support.go index a10b889c0e5..95f525e9376 100644 --- a/core/chaincode/chaincode_support.go +++ b/core/chaincode/chaincode_support.go @@ -8,18 +8,14 @@ package chaincode import ( "fmt" - "strconv" - "strings" "time" "github.com/golang/protobuf/proto" - "github.com/hyperledger/fabric/common/flogging" "github.com/hyperledger/fabric/core/chaincode/accesscontrol" "github.com/hyperledger/fabric/core/common/ccprovider" "github.com/hyperledger/fabric/core/container" "github.com/hyperledger/fabric/core/container/ccintf" pb "github.com/hyperledger/fabric/protos/peer" - logging "github.com/op/go-logging" "github.com/pkg/errors" "github.com/spf13/viper" "golang.org/x/net/context" @@ -70,6 +66,7 @@ func (cs *ChaincodeSupport) preLaunchSetup(chaincode string, notify chan bool) { // NewChaincodeSupport creates a new ChaincodeSupport instance func NewChaincodeSupport( + config *Config, peerAddress string, userrunsCC bool, ccstartuptimeout time.Duration, @@ -77,92 +74,41 @@ func NewChaincodeSupport( certGenerator CertGenerator, ) *ChaincodeSupport { ccprovider.SetChaincodesPath(ccprovider.GetCCsPath()) - pnid := viper.GetString("peer.networkId") - pid := viper.GetString("peer.id") - theChaincodeSupport := &ChaincodeSupport{ - caCert: caCert, - peerNetworkID: pnid, - peerID: pid, + cs := &ChaincodeSupport{ + caCert: caCert, + peerNetworkID: config.PeerNetworkID, + peerID: config.PeerID, + userRunsCC: userrunsCC, + ccStartupTimeout: ccstartuptimeout, + keepalive: config.Keepalive, + executetimeout: config.ExecuteTimeout, runningChaincodes: &runningChaincodes{ chaincodeMap: make(map[string]*chaincodeRTEnv), launchStarted: make(map[string]bool), }, } - theChaincodeSupport.userRunsCC = userrunsCC - theChaincodeSupport.ccStartupTimeout = ccstartuptimeout - theChaincodeSupport.peerTLS = viper.GetBool("peer.tls.enabled") - - kadef := 0 - if ka := viper.GetString("chaincode.keepalive"); ka == "" { - theChaincodeSupport.keepalive = time.Duration(kadef) * time.Second - } else { - t, terr := strconv.Atoi(ka) - if terr != nil { - chaincodeLogger.Errorf("Invalid keepalive value %s (%s) defaulting to %d", ka, terr, kadef) - t = kadef - } else if t <= 0 { - chaincodeLogger.Debugf("Turn off keepalive(value %s)", ka) - t = kadef - } - theChaincodeSupport.keepalive = time.Duration(t) * time.Second - } - - //default chaincode execute timeout is 30 secs - execto := time.Duration(30) * time.Second - if eto := viper.GetDuration("chaincode.executetimeout"); eto <= time.Duration(1)*time.Second { - chaincodeLogger.Errorf("Invalid execute timeout value %s (should be at least 1s); defaulting to %s", eto, execto) - } else { - chaincodeLogger.Debugf("Setting execute timeout value to %s", eto) - execto = eto - } - - theChaincodeSupport.executetimeout = execto - - viper.SetEnvPrefix("CORE") - viper.AutomaticEnv() - replacer := strings.NewReplacer(".", "_") - viper.SetEnvKeyReplacer(replacer) - - theChaincodeSupport.chaincodeLogLevel = getLogLevelFromViper("level") - theChaincodeSupport.shimLogLevel = getLogLevelFromViper("shim") - theChaincodeSupport.logFormat = viper.GetString("chaincode.logging.format") - // Keep TestQueries working - if !theChaincodeSupport.peerTLS { + if !config.TLSEnabled { certGenerator = nil } - theChaincodeSupport.ContainerRuntime = &ContainerRuntime{ + cs.ContainerRuntime = &ContainerRuntime{ CertGenerator: certGenerator, Processor: ProcessFunc(container.VMCProcess), CACert: caCert, PeerAddress: peerAddress, - PeerID: pid, - PeerNetworkID: pnid, + PeerID: config.PeerID, + PeerNetworkID: config.PeerNetworkID, CommonEnv: []string{ - "CORE_CHAINCODE_LOGGING_LEVEL=" + theChaincodeSupport.chaincodeLogLevel, - "CORE_CHAINCODE_LOGGING_SHIM=" + theChaincodeSupport.shimLogLevel, - "CORE_CHAINCODE_LOGGING_FORMAT=" + theChaincodeSupport.logFormat, + "CORE_CHAINCODE_LOGGING_LEVEL=" + config.LogLevel, + "CORE_CHAINCODE_LOGGING_SHIM=" + config.ShimLogLevel, + "CORE_CHAINCODE_LOGGING_FORMAT=" + config.LogFormat, }, } - return theChaincodeSupport -} - -// getLogLevelFromViper gets the chaincode container log levels from viper -func getLogLevelFromViper(module string) string { - levelString := viper.GetString("chaincode.logging." + module) - _, err := logging.LogLevel(levelString) - - if err == nil { - chaincodeLogger.Debugf("CORE_CHAINCODE_%s set to level %s", strings.ToUpper(module), levelString) - } else { - chaincodeLogger.Warningf("CORE_CHAINCODE_%s has invalid log level %s. defaulting to %s", strings.ToUpper(module), levelString, flogging.DefaultLevel()) - levelString = flogging.DefaultLevel() - } - return levelString + return cs } // ChaincodeSupport responsible for providing interfacing with chaincodes from the Peer. @@ -174,12 +120,8 @@ type ChaincodeSupport struct { peerNetworkID string peerID string keepalive time.Duration - chaincodeLogLevel string - shimLogLevel string - logFormat string executetimeout time.Duration userRunsCC bool - peerTLS bool ContainerRuntime Runtime } diff --git a/core/chaincode/chaincode_support_test.go b/core/chaincode/chaincode_support_test.go index 82e8f784f3d..4145ad58c86 100644 --- a/core/chaincode/chaincode_support_test.go +++ b/core/chaincode/chaincode_support_test.go @@ -172,7 +172,7 @@ func initMockPeer(chainIDs ...string) error { ccStartupTimeout := time.Duration(10) * time.Second ca, _ := accesscontrol.NewCA() certGenerator := accesscontrol.NewAuthenticator(ca) - theChaincodeSupport = NewChaincodeSupport("0.0.0.0:7052", false, ccStartupTimeout, ca.CertBytes(), certGenerator) + theChaincodeSupport = NewChaincodeSupport(GlobalConfig(), "0.0.0.0:7052", false, ccStartupTimeout, ca.CertBytes(), certGenerator) SideEffectInitialize(theChaincodeSupport) theChaincodeSupport.executetimeout = time.Duration(1) * time.Second @@ -893,12 +893,9 @@ func TestLaunchAndWaitSuccess(t *testing.T) { } newCCSupport := &ChaincodeSupport{ - peerTLS: false, - chaincodeLogLevel: "debug", - shimLogLevel: "info", - ccStartupTimeout: time.Duration(10) * time.Second, - peerNetworkID: "networkID", - peerID: "peerID", + ccStartupTimeout: time.Duration(10) * time.Second, + peerNetworkID: "networkID", + peerID: "peerID", runningChaincodes: &runningChaincodes{ chaincodeMap: make(map[string]*chaincodeRTEnv), launchStarted: make(map[string]bool), @@ -928,12 +925,9 @@ func TestLaunchAndWaitTimeout(t *testing.T) { } newCCSupport := &ChaincodeSupport{ - peerTLS: false, - chaincodeLogLevel: "debug", - shimLogLevel: "info", - ccStartupTimeout: 500 * time.Millisecond, - peerNetworkID: "networkID", - peerID: "peerID", + ccStartupTimeout: 500 * time.Millisecond, + peerNetworkID: "networkID", + peerID: "peerID", runningChaincodes: &runningChaincodes{ chaincodeMap: make(map[string]*chaincodeRTEnv), launchStarted: make(map[string]bool), @@ -962,12 +956,9 @@ func TestLaunchAndWaitNotificationError(t *testing.T) { } newCCSupport := &ChaincodeSupport{ - peerTLS: false, - chaincodeLogLevel: "debug", - shimLogLevel: "info", - ccStartupTimeout: 10 * time.Second, - peerNetworkID: "networkID", - peerID: "peerID", + ccStartupTimeout: 10 * time.Second, + peerNetworkID: "networkID", + peerID: "peerID", runningChaincodes: &runningChaincodes{ chaincodeMap: make(map[string]*chaincodeRTEnv), launchStarted: make(map[string]bool), @@ -995,12 +986,9 @@ func TestLaunchAndWaitLaunchError(t *testing.T) { } newCCSupport := &ChaincodeSupport{ - peerTLS: false, - chaincodeLogLevel: "debug", - shimLogLevel: "info", - ccStartupTimeout: time.Duration(10) * time.Second, - peerNetworkID: "networkID", - peerID: "peerID", + ccStartupTimeout: time.Duration(10) * time.Second, + peerNetworkID: "networkID", + peerID: "peerID", runningChaincodes: &runningChaincodes{ chaincodeMap: make(map[string]*chaincodeRTEnv), launchStarted: make(map[string]bool), diff --git a/core/chaincode/config.go b/core/chaincode/config.go new file mode 100644 index 00000000000..635a5059eae --- /dev/null +++ b/core/chaincode/config.go @@ -0,0 +1,86 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package chaincode + +import ( + "strconv" + "strings" + "time" + + "github.com/hyperledger/fabric/common/flogging" + logging "github.com/op/go-logging" + "github.com/spf13/viper" +) + +const ( + defaultExecutionTimeout = 30 * time.Second + minimumStartupTimeout = 5 * time.Second +) + +type Config struct { + PeerNetworkID string + PeerID string + TLSEnabled bool + Keepalive time.Duration + ExecuteTimeout time.Duration + StartupTimeout time.Duration + LogFormat string + LogLevel string + ShimLogLevel string +} + +func GlobalConfig() *Config { + c := &Config{} + c.load() + return c +} + +func (c *Config) load() { + viper.SetEnvPrefix("CORE") + viper.AutomaticEnv() + replacer := strings.NewReplacer(".", "_") + viper.SetEnvKeyReplacer(replacer) + + c.PeerNetworkID = viper.GetString("peer.networkId") + c.PeerID = viper.GetString("peer.id") + c.TLSEnabled = viper.GetBool("peer.tls.enabled") + + c.Keepalive = toSeconds(viper.GetString("chaincode.keepalive"), 0) + c.ExecuteTimeout = viper.GetDuration("chaincode.executetimeout") + if c.ExecuteTimeout < time.Second { + c.ExecuteTimeout = defaultExecutionTimeout + } + c.StartupTimeout = viper.GetDuration("chaincode.startuptimeout") + if c.StartupTimeout < minimumStartupTimeout { + c.StartupTimeout = 5 * time.Second + } + + c.LogFormat = viper.GetString("chaincode.logging.format") + c.LogLevel = getLogLevelFromViper("chaincode.logging.level") + c.ShimLogLevel = getLogLevelFromViper("chaincode.logging.shim") +} + +func toSeconds(s string, def int) time.Duration { + seconds, err := strconv.Atoi(s) + if err != nil { + return time.Duration(def) * time.Second + } + + return time.Duration(seconds) * time.Second +} + +// getLogLevelFromViper gets the chaincode container log levels from viper +func getLogLevelFromViper(key string) string { + levelString := viper.GetString(key) + _, err := logging.LogLevel(levelString) + if err != nil { + chaincodeLogger.Warningf("%s has invalid log level %s. defaulting to %s", key, levelString, flogging.DefaultLevel()) + levelString = flogging.DefaultLevel() + } + + return levelString +} diff --git a/core/chaincode/config_test.go b/core/chaincode/config_test.go new file mode 100644 index 00000000000..6906cb0abd9 --- /dev/null +++ b/core/chaincode/config_test.go @@ -0,0 +1,107 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package chaincode_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/hyperledger/fabric/core/chaincode" + "github.com/spf13/viper" +) + +func TestGlobalConfig(t *testing.T) { + cleanup := capture() + defer cleanup() + + viper.Set("peer.networkId", "test-peer-network-id") + viper.Set("peer.id", "test-peer-id") + viper.Set("peer.tls.enabled", "true") + viper.Set("chaincode.keepalive", "50") + viper.Set("chaincode.executetimeout", "20h") + viper.Set("chaincode.startuptimeout", "30h") + viper.Set("chaincode.logging.format", "test-chaincode-logging-format") + viper.Set("chaincode.logging.level", "WARNING") + viper.Set("chaincode.logging.shim", "WARNING") + + config := chaincode.GlobalConfig() + assert.Equal(t, "test-peer-network-id", config.PeerNetworkID) + assert.Equal(t, "test-peer-id", config.PeerID) + assert.Equal(t, true, config.TLSEnabled) + assert.Equal(t, 50*time.Second, config.Keepalive) + assert.Equal(t, 20*time.Hour, config.ExecuteTimeout) + assert.Equal(t, 30*time.Hour, config.StartupTimeout) + assert.Equal(t, "test-chaincode-logging-format", config.LogFormat) + assert.Equal(t, "WARNING", config.LogLevel) + assert.Equal(t, "WARNING", config.ShimLogLevel) +} + +func TestGlobalConfigInvalidKeepalive(t *testing.T) { + cleanup := capture() + defer cleanup() + + viper.Set("chaincode.keepalive", "abc") + + config := chaincode.GlobalConfig() + assert.Equal(t, time.Duration(0), config.Keepalive) +} + +func TestGlobalConfigExecuteTimeoutTooLow(t *testing.T) { + cleanup := capture() + defer cleanup() + + viper.Set("chaincode.executetimeout", "15") + + config := chaincode.GlobalConfig() + assert.Equal(t, 30*time.Second, config.ExecuteTimeout) +} + +func TestGlobalConfigStartupTimeoutTooLow(t *testing.T) { + cleanup := capture() + defer cleanup() + + viper.Set("chaincode.startuptimeout", "15") + + config := chaincode.GlobalConfig() + assert.Equal(t, 5*time.Second, config.StartupTimeout) +} + +func TestGlobalConfigInvalidLogLevel(t *testing.T) { + cleanup := capture() + defer cleanup() + + viper.Set("chaincode.logging.level", "foo") + viper.Set("chaincode.logging.shim", "bar") + + config := chaincode.GlobalConfig() + assert.Equal(t, "INFO", config.LogLevel) + assert.Equal(t, "INFO", config.ShimLogLevel) +} + +func capture() (restore func()) { + viper.SetEnvPrefix("CORE") + viper.AutomaticEnv() + config := map[string]string{ + "peer.networkId": viper.GetString("peer.networkId"), + "peer.id": viper.GetString("peer.id"), + "peer.tls.enabled": viper.GetString("peer.tls.enabled"), + "chaincode.keepalive": viper.GetString("chaincode.keepalive"), + "chaincode.executetimeout": viper.GetString("chaincode.executetimeout"), + "chaincode.startuptimeout": viper.GetString("chaincode.startuptimeout"), + "chaincode.logging.format": viper.GetString("chaincode.logging.format"), + "chaincode.logging.level": viper.GetString("chaincode.logging.level"), + "chaincode.logging.shim": viper.GetString("chaincode.logging.shim"), + } + + return func() { + for k, val := range config { + viper.Set(k, val) + } + } +} diff --git a/core/chaincode/exectransaction_test.go b/core/chaincode/exectransaction_test.go index 38a6865839b..23c751585ac 100644 --- a/core/chaincode/exectransaction_test.go +++ b/core/chaincode/exectransaction_test.go @@ -105,7 +105,7 @@ func initPeer(chainIDs ...string) (net.Listener, error) { ccStartupTimeout := time.Duration(3) * time.Minute ca, _ := accesscontrol.NewCA() certGenerator := accesscontrol.NewAuthenticator(ca) - theChaincodeSupport = NewChaincodeSupport(peerAddress, false, ccStartupTimeout, ca.CertBytes(), certGenerator) + theChaincodeSupport = NewChaincodeSupport(GlobalConfig(), peerAddress, false, ccStartupTimeout, ca.CertBytes(), certGenerator) SideEffectInitialize(theChaincodeSupport) pb.RegisterChaincodeSupportServer(grpcServer, theChaincodeSupport) diff --git a/core/chaincode/systemchaincode_test.go b/core/chaincode/systemchaincode_test.go index cfc1eb4752b..f000d131e35 100644 --- a/core/chaincode/systemchaincode_test.go +++ b/core/chaincode/systemchaincode_test.go @@ -121,7 +121,7 @@ func initSysCCTests() (*oldSysCCInfo, net.Listener, error) { ccStartupTimeout := time.Duration(5000) * time.Millisecond ca, _ := accesscontrol.NewCA() certGenerator := accesscontrol.NewAuthenticator(ca) - pb.RegisterChaincodeSupportServer(grpcServer, NewChaincodeSupport(peerAddress, false, ccStartupTimeout, ca.CertBytes(), certGenerator)) + pb.RegisterChaincodeSupportServer(grpcServer, NewChaincodeSupport(GlobalConfig(), peerAddress, false, ccStartupTimeout, ca.CertBytes(), certGenerator)) go grpcServer.Serve(lis) diff --git a/core/scc/cscc/configure_test.go b/core/scc/cscc/configure_test.go index a36c967c4f4..5083a0b4ab3 100644 --- a/core/scc/cscc/configure_test.go +++ b/core/scc/cscc/configure_test.go @@ -3,6 +3,7 @@ Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ + package cscc import ( @@ -195,7 +196,7 @@ func TestConfigerInvokeJoinChainCorrectParams(t *testing.T) { ccStartupTimeout := time.Duration(30000) * time.Millisecond ca, _ := accesscontrol.NewCA() certGenerator := accesscontrol.NewAuthenticator(ca) - chaincode.NewChaincodeSupport(peerEndpoint, false, ccStartupTimeout, ca.CertBytes(), certGenerator) + chaincode.NewChaincodeSupport(chaincode.GlobalConfig(), peerEndpoint, false, ccStartupTimeout, ca.CertBytes(), certGenerator) // Init the policy checker policyManagerGetter := &policymocks.MockChannelPolicyManagerGetter{ diff --git a/peer/node/start.go b/peer/node/start.go index 4986dc8c882..6d6a75f6827 100644 --- a/peer/node/start.go +++ b/peer/node/start.go @@ -584,7 +584,14 @@ func registerChaincodeSupport(grpcServer *comm.GRPCServer, ccEndpoint string, ca } authenticator := accesscontrol.NewAuthenticator(ca) - chaincodeSupport := chaincode.NewChaincodeSupport(ccEndpoint, userRunsCC, ccStartupTimeout, ca.CertBytes(), authenticator) + chaincodeSupport := chaincode.NewChaincodeSupport( + chaincode.GlobalConfig(), + ccEndpoint, + userRunsCC, + ccStartupTimeout, + ca.CertBytes(), + authenticator, + ) chaincode.SideEffectInitialize(chaincodeSupport) ccSrv := pb.ChaincodeSupportServer(chaincodeSupport)