Skip to content

Commit

Permalink
[FAB-16842] prep for for ext CC config
Browse files Browse the repository at this point in the history
Introduce "ChaincodeServerInfo" to build environment. This will
be used by chaincode runtime to decide between chaincode server
and chaincode client models.
Only external builders couls avail this extension. In particular
Docker builders will return nil.

Change-Id: I09ff9fe7d209f25dcc14316228bebf2364285ac9
Signed-off-by: muralisr <srinivasan.muralidharan99@gmail.com>
  • Loading branch information
muralisrini committed Nov 21, 2019
1 parent bbdfa7f commit fead9d9
Show file tree
Hide file tree
Showing 9 changed files with 545 additions and 1 deletion.
1 change: 1 addition & 0 deletions core/chaincode/container_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type CertGenerator interface {
// is removed (or perhaps before), this interface should probably go away entirely.
type ContainerRouter interface {
Build(ccid string) error
ChaincodeServerInfo(ccid string) (*ccintf.ChaincodeServerInfo, error)
Start(ccid string, peerConnection *ccintf.PeerConnection) error
Stop(ccid string) error
Wait(ccid string) (int, error)
Expand Down
78 changes: 78 additions & 0 deletions core/chaincode/mock/container_router.go

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

8 changes: 8 additions & 0 deletions core/container/ccintf/ccintf.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ SPDX-License-Identifier: Apache-2.0
package ccintf

import (
"github.com/hyperledger/fabric/core/comm"

pb "github.com/hyperledger/fabric-protos-go/peer"
)

Expand All @@ -30,3 +32,9 @@ type TLSConfig struct {
ClientKey []byte
RootCert []byte
}

// ChaincodeServerInfo provides chaincode connection information
type ChaincodeServerInfo struct {
Address string
ClientConfig comm.ClientConfig
}
9 changes: 9 additions & 0 deletions core/container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type VM interface {
// 'image' also seemed inappropriate. So, the vague 'Instance' is used here.
type Instance interface {
Start(peerConnection *ccintf.PeerConnection) error
ChaincodeServerInfo() (*ccintf.ChaincodeServerInfo, error)
Stop() error
Wait() (int, error)
}
Expand All @@ -43,6 +44,10 @@ func (UninitializedInstance) Start(peerConnection *ccintf.PeerConnection) error
return errors.Errorf("instance has not yet been built, cannot be started")
}

func (UninitializedInstance) ChaincodeServerInfo() (*ccintf.ChaincodeServerInfo, error) {
return nil, errors.Errorf("instance has not yet been built, cannot get chaincode server info")
}

func (UninitializedInstance) Stop() error {
return errors.Errorf("instance has not yet been built, cannot be stopped")
}
Expand Down Expand Up @@ -122,6 +127,10 @@ func (r *Router) Build(ccid string) error {
return nil
}

func (r *Router) ChaincodeServerInfo(ccid string) (*ccintf.ChaincodeServerInfo, error) {
return r.getInstance(ccid).ChaincodeServerInfo()
}

func (r *Router) Start(ccid string, peerConnection *ccintf.PeerConnection) error {
return r.getInstance(ccid).Start(peerConnection)
}
Expand Down
4 changes: 4 additions & 0 deletions core/container/dockercontroller/dockercontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ func (ci *ContainerInstance) Start(peerConnection *ccintf.PeerConnection) error
return ci.DockerVM.Start(ci.CCID, ci.Type, peerConnection)
}

func (ci *ContainerInstance) ChaincodeServerInfo() (*ccintf.ChaincodeServerInfo, error) {
return nil, nil
}

func (ci *ContainerInstance) Stop() error {
return ci.DockerVM.Stop(ci.CCID)
}
Expand Down
5 changes: 4 additions & 1 deletion core/container/externalbuilder/externalbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func (d *Detector) CachedBuild(ccid string) (*Instance, error) {
PackageID: ccid,
Builder: builder,
BldDir: filepath.Join(durablePath, "bld"),
ReleaseDir: filepath.Join(durablePath, "release"),
TermTimeout: 5 * time.Second,
}, nil
}
Expand Down Expand Up @@ -150,7 +151,8 @@ func (d *Detector) Build(ccid string, md *persistence.ChaincodePackageMetadata,
return nil, errors.WithMessage(err, "could not write build-info.json")
}

err = os.Rename(buildContext.ReleaseDir, filepath.Join(durablePath, "release"))
durableReleaseDir := filepath.Join(durablePath, "release")
err = os.Rename(buildContext.ReleaseDir, durableReleaseDir)
if err != nil {
os.RemoveAll(durablePath)
return nil, errors.WithMessagef(err, "could not move build context release to persistent location '%s'", durablePath)
Expand All @@ -167,6 +169,7 @@ func (d *Detector) Build(ccid string, md *persistence.ChaincodePackageMetadata,
PackageID: ccid,
Builder: builder,
BldDir: durableBldDir,
ReleaseDir: durableReleaseDir,
TermTimeout: 5 * time.Second,
}, nil
}
Expand Down
136 changes: 136 additions & 0 deletions core/container/externalbuilder/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,158 @@ SPDX-License-Identifier: Apache-2.0
package externalbuilder

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"syscall"
"time"

"github.com/hyperledger/fabric/core/comm"
"github.com/hyperledger/fabric/core/container/ccintf"
"github.com/pkg/errors"
)

const (
DialTimeout = 3 * time.Second
CCServerReleaseDir = "chaincode/server"
)

type Instance struct {
PackageID string
BldDir string
ReleaseDir string
Builder *Builder
Session *Session
TermTimeout time.Duration
}

// Duration used for the DialTimeout property
type Duration struct {
time.Duration
}

func (d Duration) MarshalJSON() ([]byte, error) {
return json.Marshal(d.Seconds())
}

func (d *Duration) UnmarshalJSON(b []byte) error {
var v interface{}
if err := json.Unmarshal(b, &v); err != nil {
return err
}

switch value := v.(type) {
case float64:
d.Duration = time.Duration(value)
return nil
case string:
var err error
if d.Duration, err = time.ParseDuration(value); err != nil {
return err
}
return nil
default:
return errors.New("invalid duration")
}
}

// ChaincodeServerUserData holds "connection.json" information
type ChaincodeServerUserData struct {
Address string `json:"address"`
DialTimeout Duration `json:"dial_timeout"`
TlsRequired bool `json:"tls_required"`
ClientAuthRequired bool `json:"client_auth_required"`
KeyPath string `json:"key_path"`
CertPath string `json:"cert_path"`
RootCertPath string `json:"root_cert_path"`
}

func (ccdata *ChaincodeServerUserData) ChaincodeServerInfo(cryptoDir string) (*ccintf.ChaincodeServerInfo, error) {
if ccdata.Address == "" {
return nil, errors.New("chaincode address not provided")
}
connInfo := &ccintf.ChaincodeServerInfo{Address: ccdata.Address}

if ccdata.DialTimeout == (Duration{}) {
connInfo.ClientConfig.Timeout = DialTimeout
} else {
connInfo.ClientConfig.Timeout = ccdata.DialTimeout.Duration
}

// we can expose this if necessary
connInfo.ClientConfig.KaOpts = comm.DefaultKeepaliveOptions

if !ccdata.TlsRequired {
return connInfo, nil
}
if ccdata.ClientAuthRequired && ccdata.KeyPath == "" {
return nil, errors.New("chaincode tls key not provided")
}
if ccdata.ClientAuthRequired && ccdata.CertPath == "" {
return nil, errors.New("chaincode tls cert not provided")
}
if ccdata.RootCertPath == "" {
return nil, errors.New("chaincode tls root cert not provided")
}

connInfo.ClientConfig.SecOpts.UseTLS = true

if ccdata.ClientAuthRequired {
connInfo.ClientConfig.SecOpts.RequireClientCert = true
b, err := ioutil.ReadFile(filepath.Join(cryptoDir, ccdata.CertPath))
if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("error reading cert file %s", ccdata.CertPath))
}
connInfo.ClientConfig.SecOpts.Certificate = b

b, err = ioutil.ReadFile(filepath.Join(cryptoDir, ccdata.KeyPath))
if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("error reading key file %s", ccdata.KeyPath))
}
connInfo.ClientConfig.SecOpts.Key = b
}

b, err := ioutil.ReadFile(filepath.Join(cryptoDir, ccdata.RootCertPath))
if err != nil {
return nil, errors.WithMessage(err, fmt.Sprintf("error reading root cert file %s", ccdata.RootCertPath))
}
connInfo.ClientConfig.SecOpts.ServerRootCAs = [][]byte{b}

return connInfo, nil
}

func (i *Instance) ChaincodeServerReleaseDir() string {
return filepath.Join(i.ReleaseDir, CCServerReleaseDir)
}

func (i *Instance) ChaincodeServerInfo() (*ccintf.ChaincodeServerInfo, error) {
ccinfoPath := filepath.Join(i.ChaincodeServerReleaseDir(), "connection.json")

_, err := os.Stat(ccinfoPath)

if os.IsNotExist(err) {
return nil, nil
}

if err != nil {
return nil, errors.WithMessage(err, "connection information not provided")
}
b, err := ioutil.ReadFile(ccinfoPath)
if err != nil {
return nil, errors.WithMessagef(err, "could not read '%s' for chaincode info", ccinfoPath)
}
ccdata := &ChaincodeServerUserData{}
err = json.Unmarshal(b, &ccdata)
if err != nil {
return nil, errors.WithMessagef(err, "malformed chaincode info at '%s'", ccinfoPath)
}

return ccdata.ChaincodeServerInfo(i.ChaincodeServerReleaseDir())
}

func (i *Instance) Start(peerConnection *ccintf.PeerConnection) error {
sess, err := i.Builder.Run(i.PackageID, i.BldDir, peerConnection)
if err != nil {
Expand Down
Loading

0 comments on commit fead9d9

Please sign in to comment.