Skip to content

Commit

Permalink
Merge "[FAB-16890] move build out of container runtime"
Browse files Browse the repository at this point in the history
  • Loading branch information
denyeart authored and Gerrit Code Review committed Nov 21, 2019
2 parents 78471de + a9572d6 commit 75e51fb
Show file tree
Hide file tree
Showing 9 changed files with 264 additions and 77 deletions.
3 changes: 2 additions & 1 deletion core/chaincode/chaincode_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ const (

// Runtime is used to manage chaincode runtime instances.
type Runtime interface {
Start(ccid string) error
Build(ccid string) (*ccintf.ChaincodeServerInfo, error)
Start(ccid string, ccinfo *ccintf.PeerConnection) error
Stop(ccid string) error
Wait(ccid string) (int, error)
}
Expand Down
17 changes: 9 additions & 8 deletions core/chaincode/chaincode_support_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (
"github.com/hyperledger/fabric/core/common/ccprovider"
"github.com/hyperledger/fabric/core/config"
"github.com/hyperledger/fabric/core/container"
"github.com/hyperledger/fabric/core/container/ccintf"
"github.com/hyperledger/fabric/core/container/dockercontroller"
"github.com/hyperledger/fabric/core/ledger"
ledgermock "github.com/hyperledger/fabric/core/ledger/mock"
Expand Down Expand Up @@ -231,14 +232,9 @@ func initMockPeer(channelIDs ...string) (*peer.Peer, *ChaincodeSupport, func(),
}

containerRuntime := &ContainerRuntime{
CACert: ca.CertBytes(),
CertGenerator: certGenerator,
BuildRegistry: buildRegistry,
ContainerRouter: containerRouter,
}
if !globalConfig.TLSEnabled {
containerRuntime.CertGenerator = nil
}
userRunsCC := true
metricsProviders := &disabled.Provider{}
chaincodeHandlerRegistry := NewHandlerRegistry(userRunsCC)
Expand All @@ -247,6 +243,11 @@ func initMockPeer(channelIDs ...string) (*peer.Peer, *ChaincodeSupport, func(),
Runtime: containerRuntime,
Registry: chaincodeHandlerRegistry,
StartupTimeout: globalConfig.StartupTimeout,
CACert: ca.CertBytes(),
CertGenerator: certGenerator,
}
if !globalConfig.TLSEnabled {
chaincodeLauncher.CertGenerator = nil
}
chaincodeSupport := &ChaincodeSupport{
ACLProvider: mockAclProvider,
Expand Down Expand Up @@ -903,7 +904,7 @@ func getHistory(t *testing.T, chainID, ccname string, ccSide *mockpeer.MockCCCom
func TestStartAndWaitSuccess(t *testing.T) {
handlerRegistry := NewHandlerRegistry(false)
fakeRuntime := &mock.Runtime{}
fakeRuntime.StartStub = func(_ string) error {
fakeRuntime.StartStub = func(_ string, _ *ccintf.PeerConnection) error {
handlerRegistry.Ready("testcc:0")
return nil
}
Expand All @@ -925,7 +926,7 @@ func TestStartAndWaitSuccess(t *testing.T) {
//test timeout error
func TestStartAndWaitTimeout(t *testing.T) {
fakeRuntime := &mock.Runtime{}
fakeRuntime.StartStub = func(_ string) error {
fakeRuntime.StartStub = func(_ string, _ *ccintf.PeerConnection) error {
time.Sleep(time.Second)
return nil
}
Expand All @@ -947,7 +948,7 @@ func TestStartAndWaitTimeout(t *testing.T) {
//test container return error
func TestStartAndWaitLaunchError(t *testing.T) {
fakeRuntime := &mock.Runtime{}
fakeRuntime.StartStub = func(_ string) error {
fakeRuntime.StartStub = func(_ string, _ *ccintf.PeerConnection) error {
return errors.New("Bad lunch; upset stomach")
}

Expand Down
45 changes: 10 additions & 35 deletions core/chaincode/container_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,11 @@ SPDX-License-Identifier: Apache-2.0
package chaincode

import (
"github.com/hyperledger/fabric/core/chaincode/accesscontrol"
"github.com/hyperledger/fabric/core/container"
"github.com/hyperledger/fabric/core/container/ccintf"
"github.com/pkg/errors"
)

// CertGenerator generates client certificates for chaincode.
type CertGenerator interface {
// Generate returns a certificate and private key and associates
// the hash of the certificates with the given chaincode name
Generate(ccName string) (*accesscontrol.CertAndPrivKeyPair, error)
}

// ContainerRouter is a poor abstraction used for building, and running chaincode processes.
// This management probably does not belong in this package, chaincode process lifecycle should
// be driven by what chaincodes are defined, what chaincodes are instantiated, and not driven by
Expand All @@ -35,29 +27,13 @@ type ContainerRouter interface {

// ContainerRuntime is responsible for managing containerized chaincode.
type ContainerRuntime struct {
CertGenerator CertGenerator
ContainerRouter ContainerRouter
CACert []byte
PeerAddress string
BuildRegistry *container.BuildRegistry
}

// Start launches chaincode in a runtime environment.
func (c *ContainerRuntime) Start(ccid string) error {
var tlsConfig *ccintf.TLSConfig
if c.CertGenerator != nil {
certKeyPair, err := c.CertGenerator.Generate(string(ccid))
if err != nil {
return errors.WithMessagef(err, "failed to generate TLS certificates for %s", ccid)
}

tlsConfig = &ccintf.TLSConfig{
ClientCert: certKeyPair.Cert,
ClientKey: certKeyPair.Key,
RootCert: c.CACert,
}
}

// Build builds the chaincode if necessary and returns ChaincodeServerInfo if
// the chaincode is a server
func (c *ContainerRuntime) Build(ccid string) (*ccintf.ChaincodeServerInfo, error) {
buildStatus, ok := c.BuildRegistry.BuildStatus(ccid)
if !ok {
err := c.ContainerRouter.Build(ccid)
Expand All @@ -66,18 +42,17 @@ func (c *ContainerRuntime) Start(ccid string) error {
<-buildStatus.Done()

if err := buildStatus.Err(); err != nil {
return errors.WithMessage(err, "error building image")
return nil, errors.WithMessage(err, "error building image")
}

return c.ContainerRouter.ChaincodeServerInfo(ccid)
}

// Start launches chaincode in a runtime environment.
func (c *ContainerRuntime) Start(ccid string, ccinfo *ccintf.PeerConnection) error {
chaincodeLogger.Debugf("start container: %s", ccid)

if err := c.ContainerRouter.Start(
ccid,
&ccintf.PeerConnection{
Address: c.PeerAddress,
TLSConfig: tlsConfig,
},
); err != nil {
if err := c.ContainerRouter.Start(ccid, ccinfo); err != nil {
return errors.WithMessage(err, "error starting container")
}

Expand Down
31 changes: 20 additions & 11 deletions core/chaincode/container_runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,39 @@ import (
"github.com/hyperledger/fabric/core/chaincode"
"github.com/hyperledger/fabric/core/chaincode/mock"
"github.com/hyperledger/fabric/core/container"
"github.com/hyperledger/fabric/core/container/ccintf"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)

func TestContainerRuntimeStart(t *testing.T) {
func TestContainerRuntimeBuild(t *testing.T) {
fakeRouter := &mock.ContainerRouter{}
fakeRouter.ChaincodeServerInfoReturns(&ccintf.ChaincodeServerInfo{Address: "ccaddress:12345"}, nil)

cr := &chaincode.ContainerRuntime{
ContainerRouter: fakeRouter,
PeerAddress: "peer-address",
BuildRegistry: &container.BuildRegistry{},
}

err := cr.Start("chaincode-name:chaincode-version")
ccinfo, err := cr.Build("chaincode-name:chaincode-version")
assert.NoError(t, err)
assert.Equal(t, &ccintf.ChaincodeServerInfo{Address: "ccaddress:12345"}, ccinfo)

assert.Equal(t, 1, fakeRouter.BuildCallCount())
packageID := fakeRouter.BuildArgsForCall(0)
assert.Equal(t, "chaincode-name:chaincode-version", packageID)
}

func TestContainerRuntimeStart(t *testing.T) {
fakeRouter := &mock.ContainerRouter{}

cr := &chaincode.ContainerRuntime{
ContainerRouter: fakeRouter,
BuildRegistry: &container.BuildRegistry{},
}

err := cr.Start("chaincode-name:chaincode-version", &ccintf.PeerConnection{Address: "peer-address"})
assert.NoError(t, err)

assert.Equal(t, 1, fakeRouter.StartCallCount())
ccid, peerConnection := fakeRouter.StartArgsForCall(0)
Expand All @@ -41,35 +55,30 @@ func TestContainerRuntimeStart(t *testing.T) {

// Try starting a second time, to ensure build is not invoked again
// as the BuildRegistry already holds it
err = cr.Start("chaincode-name:chaincode-version")
err = cr.Start("chaincode-name:chaincode-version", &ccintf.PeerConnection{Address: "fake-address"})
assert.NoError(t, err)
assert.Equal(t, 1, fakeRouter.BuildCallCount())
assert.Equal(t, 2, fakeRouter.StartCallCount())
}

func TestContainerRuntimeStartErrors(t *testing.T) {
tests := []struct {
chaincodeType string
buildErr error
startErr error
errValue string
}{
{pb.ChaincodeSpec_GOLANG.String(), nil, errors.New("process-failed"), "error starting container: process-failed"},
{pb.ChaincodeSpec_GOLANG.String(), errors.New("build-failed"), nil, "error building image: build-failed"},
{pb.ChaincodeSpec_GOLANG.String(), errors.New("build-failed"), nil, "error building image: build-failed"},
{pb.ChaincodeSpec_GOLANG.String(), errors.New("process-failed"), "error starting container: process-failed"},
}

for _, tc := range tests {
fakeRouter := &mock.ContainerRouter{}
fakeRouter.BuildReturns(tc.buildErr)
fakeRouter.StartReturns(tc.startErr)

cr := &chaincode.ContainerRuntime{
ContainerRouter: fakeRouter,
BuildRegistry: &container.BuildRegistry{},
}

err := cr.Start("ccid")
err := cr.Start("ccid", &ccintf.PeerConnection{Address: "fake-address"})
assert.EqualError(t, err, tc.errValue)
}
}
Expand Down
4 changes: 2 additions & 2 deletions core/chaincode/exectransaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,7 @@ func initPeer(channelIDs ...string) (*cm.Lifecycle, net.Listener, *ChaincodeSupp
}
containerRuntime := &ContainerRuntime{
BuildRegistry: buildRegistry,
CACert: ca.CertBytes(),
ContainerRouter: containerRouter,
PeerAddress: peerAddress,
}
userRunsCC := false
metricsProviders := &disabled.Provider{}
Expand All @@ -187,6 +185,8 @@ func initPeer(channelIDs ...string) (*cm.Lifecycle, net.Listener, *ChaincodeSupp
Registry: chaincodeHandlerRegistry,
Runtime: containerRuntime,
StartupTimeout: globalConfig.StartupTimeout,
CACert: ca.CertBytes(),
PeerAddress: peerAddress,
}
chaincodeSupport := &ChaincodeSupport{
ACLProvider: aclmgmt.NewACLProvider(
Expand Down
98 changes: 90 additions & 8 deletions core/chaincode/mock/runtime.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 75e51fb

Please sign in to comment.