Skip to content

Commit e1e4efc

Browse files
committed
[FAB-678] Add BuildSpecFactory to container controller
We currently take an io.Reader as a parameter to Controller.Start(). This is relatively inconsequential since the docker tarball is precomputed. However, in the near future, we will be splitting this up so that cds.CodePackage is only a src container. The formulation into a docker container will happen JIT in response to a peer trying to start the container. Once this happens, we want to avoid the overhead of computing the build specification unless it is actually needed. Therefore, we use a callback that the docker-controller may use to indicate when the build-spec is needed. Part of FAB-678 Change-Id: I259c9c0b600866c2b78c4319039ca8214d2a9620 Signed-off-by: Greg Haskins <[email protected]>
1 parent b978f0d commit e1e4efc

File tree

5 files changed

+65
-27
lines changed

5 files changed

+65
-27
lines changed

core/chaincode/chaincode_support.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"github.com/hyperledger/fabric/core/chaincode/shim"
3636
"github.com/hyperledger/fabric/core/common/ccprovider"
3737
"github.com/hyperledger/fabric/core/container"
38+
"github.com/hyperledger/fabric/core/container/api"
3839
"github.com/hyperledger/fabric/core/container/ccintf"
3940
"github.com/hyperledger/fabric/core/ledger"
4041
pb "github.com/hyperledger/fabric/protos/peer"
@@ -355,7 +356,7 @@ func (chaincodeSupport *ChaincodeSupport) getArgsAndEnv(cccid *ccprovider.CCCont
355356
}
356357

357358
// launchAndWaitForRegister will launch container if not already running. Use the targz to create the image if not found
358-
func (chaincodeSupport *ChaincodeSupport) launchAndWaitForRegister(ctxt context.Context, cccid *ccprovider.CCContext, cds *pb.ChaincodeDeploymentSpec, cLang pb.ChaincodeSpec_Type, targz io.Reader) error {
359+
func (chaincodeSupport *ChaincodeSupport) launchAndWaitForRegister(ctxt context.Context, cccid *ccprovider.CCContext, cds *pb.ChaincodeDeploymentSpec, cLang pb.ChaincodeSpec_Type, builder api.BuildSpecFactory) error {
359360
canName := cccid.GetCanonicalName()
360361
if canName == "" {
361362
return fmt.Errorf("chaincode name not set")
@@ -384,7 +385,7 @@ func (chaincodeSupport *ChaincodeSupport) launchAndWaitForRegister(ctxt context.
384385

385386
vmtype, _ := chaincodeSupport.getVMType(cds)
386387

387-
sir := container.StartImageReq{CCID: ccintf.CCID{ChaincodeSpec: cds.ChaincodeSpec, NetworkID: chaincodeSupport.peerNetworkID, PeerID: chaincodeSupport.peerID, ChainID: cccid.ChainID, Version: cccid.Version}, Reader: targz, Args: args, Env: env}
388+
sir := container.StartImageReq{CCID: ccintf.CCID{ChaincodeSpec: cds.ChaincodeSpec, NetworkID: chaincodeSupport.peerNetworkID, PeerID: chaincodeSupport.peerID, ChainID: cccid.ChainID, Version: cccid.Version}, Builder: builder, Args: args, Env: env}
388389

389390
ipcCtxt := context.WithValue(ctxt, ccintf.GetCCHandlerKey(), chaincodeSupport)
390391

@@ -538,8 +539,9 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, cccid
538539

539540
//launch container if it is a System container or not in dev mode
540541
if (!chaincodeSupport.userRunsCC || cds.ExecEnv == pb.ChaincodeDeploymentSpec_SYSTEM) && (chrte == nil || chrte.handler == nil) {
541-
var targz io.Reader = bytes.NewBuffer(cds.CodePackage)
542-
err = chaincodeSupport.launchAndWaitForRegister(context, cccid, cds, cLang, targz)
542+
543+
builder := func() (io.Reader, error) { return bytes.NewBuffer(cds.CodePackage), nil }
544+
err = chaincodeSupport.launchAndWaitForRegister(context, cccid, cds, cLang, builder)
543545
if err != nil {
544546
chaincodeLogger.Errorf("launchAndWaitForRegister failed %s", err)
545547
return cID, cMsg, err

core/container/api/core.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package api
18+
19+
import (
20+
"io"
21+
22+
"golang.org/x/net/context"
23+
24+
"github.com/hyperledger/fabric/core/container/ccintf"
25+
)
26+
27+
type BuildSpecFactory func() (io.Reader, error)
28+
29+
//abstract virtual image for supporting arbitrary virual machines
30+
type VM interface {
31+
Deploy(ctxt context.Context, ccid ccintf.CCID, args []string, env []string, reader io.Reader) error
32+
Start(ctxt context.Context, ccid ccintf.CCID, args []string, env []string, builder BuildSpecFactory) error
33+
Stop(ctxt context.Context, ccid ccintf.CCID, timeout uint, dontkill bool, dontremove bool) error
34+
Destroy(ctxt context.Context, ccid ccintf.CCID, force bool, noprune bool) error
35+
GetVMName(ccID ccintf.CCID) (string, error)
36+
}

core/container/controller.go

+12-20
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,12 @@ import (
2323

2424
"golang.org/x/net/context"
2525

26+
"github.com/hyperledger/fabric/core/container/api"
2627
"github.com/hyperledger/fabric/core/container/ccintf"
2728
"github.com/hyperledger/fabric/core/container/dockercontroller"
2829
"github.com/hyperledger/fabric/core/container/inproccontroller"
2930
)
3031

31-
//abstract virtual image for supporting arbitrary virual machines
32-
type vm interface {
33-
Deploy(ctxt context.Context, ccid ccintf.CCID, args []string, env []string, reader io.Reader) error
34-
Start(ctxt context.Context, ccid ccintf.CCID, args []string, env []string, reader io.Reader) error
35-
Stop(ctxt context.Context, ccid ccintf.CCID, timeout uint, dontkill bool, dontremove bool) error
36-
Destroy(ctxt context.Context, ccid ccintf.CCID, force bool, noprune bool) error
37-
GetVMName(ccID ccintf.CCID) (string, error)
38-
}
39-
4032
type refCountedLock struct {
4133
refCount int
4234
lock *sync.RWMutex
@@ -67,9 +59,9 @@ func init() {
6759
vmcontroller.containerLocks = make(map[string]*refCountedLock)
6860
}
6961

70-
func (vmc *VMController) newVM(typ string) vm {
62+
func (vmc *VMController) newVM(typ string) api.VM {
7163
var (
72-
v vm
64+
v api.VM
7365
)
7466

7567
switch typ {
@@ -123,7 +115,7 @@ func (vmc *VMController) unlockContainer(id string) {
123115
//note that we'd stop on the first method on the stack that does not
124116
//take context
125117
type VMCReqIntf interface {
126-
do(ctxt context.Context, v vm) VMCResp
118+
do(ctxt context.Context, v api.VM) VMCResp
127119
getCCID() ccintf.CCID
128120
}
129121

@@ -142,7 +134,7 @@ type CreateImageReq struct {
142134
Env []string
143135
}
144136

145-
func (bp CreateImageReq) do(ctxt context.Context, v vm) VMCResp {
137+
func (bp CreateImageReq) do(ctxt context.Context, v api.VM) VMCResp {
146138
var resp VMCResp
147139

148140
if err := v.Deploy(ctxt, bp.CCID, bp.Args, bp.Env, bp.Reader); err != nil {
@@ -161,15 +153,15 @@ func (bp CreateImageReq) getCCID() ccintf.CCID {
161153
//StartImageReq - properties for starting a container.
162154
type StartImageReq struct {
163155
ccintf.CCID
164-
Reader io.Reader
165-
Args []string
166-
Env []string
156+
Builder api.BuildSpecFactory
157+
Args []string
158+
Env []string
167159
}
168160

169-
func (si StartImageReq) do(ctxt context.Context, v vm) VMCResp {
161+
func (si StartImageReq) do(ctxt context.Context, v api.VM) VMCResp {
170162
var resp VMCResp
171163

172-
if err := v.Start(ctxt, si.CCID, si.Args, si.Env, si.Reader); err != nil {
164+
if err := v.Start(ctxt, si.CCID, si.Args, si.Env, si.Builder); err != nil {
173165
resp = VMCResp{Err: err}
174166
} else {
175167
resp = VMCResp{}
@@ -192,7 +184,7 @@ type StopImageReq struct {
192184
Dontremove bool
193185
}
194186

195-
func (si StopImageReq) do(ctxt context.Context, v vm) VMCResp {
187+
func (si StopImageReq) do(ctxt context.Context, v api.VM) VMCResp {
196188
var resp VMCResp
197189

198190
if err := v.Stop(ctxt, si.CCID, si.Timeout, si.Dontkill, si.Dontremove); err != nil {
@@ -216,7 +208,7 @@ type DestroyImageReq struct {
216208
NoPrune bool
217209
}
218210

219-
func (di DestroyImageReq) do(ctxt context.Context, v vm) VMCResp {
211+
func (di DestroyImageReq) do(ctxt context.Context, v api.VM) VMCResp {
220212
var resp VMCResp
221213

222214
if err := v.Destroy(ctxt, di.CCID, di.Force, di.NoPrune); err != nil {

core/container/dockercontroller/dockercontroller.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"bufio"
2727

2828
"github.com/fsouza/go-dockerclient"
29+
container "github.com/hyperledger/fabric/core/container/api"
2930
"github.com/hyperledger/fabric/core/container/ccintf"
3031
cutil "github.com/hyperledger/fabric/core/container/util"
3132
"github.com/op/go-logging"
@@ -154,7 +155,7 @@ func (vm *DockerVM) Deploy(ctxt context.Context, ccid ccintf.CCID, args []string
154155
}
155156

156157
//Start starts a container using a previously created docker image
157-
func (vm *DockerVM) Start(ctxt context.Context, ccid ccintf.CCID, args []string, env []string, reader io.Reader) error {
158+
func (vm *DockerVM) Start(ctxt context.Context, ccid ccintf.CCID, args []string, env []string, builder container.BuildSpecFactory) error {
158159
imageID, _ := vm.GetVMName(ccid)
159160
client, err := cutil.NewDockerClient()
160161
if err != nil {
@@ -174,8 +175,14 @@ func (vm *DockerVM) Start(ctxt context.Context, ccid ccintf.CCID, args []string,
174175
if err != nil {
175176
//if image not found try to create image and retry
176177
if err == docker.ErrNoSuchImage {
177-
if reader != nil {
178+
if builder != nil {
178179
dockerLogger.Debugf("start-could not find image ...attempt to recreate image %s", err)
180+
181+
reader, err := builder()
182+
if err != nil {
183+
dockerLogger.Errorf("Error creating image builder: %s", err)
184+
}
185+
179186
if err = vm.deployImage(client, ccid, args, env, reader); err != nil {
180187
return err
181188
}

core/container/inproccontroller/inproccontroller.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"io"
2222

2323
"github.com/hyperledger/fabric/core/chaincode/shim"
24+
container "github.com/hyperledger/fabric/core/container/api"
2425
"github.com/hyperledger/fabric/core/container/ccintf"
2526
pb "github.com/hyperledger/fabric/protos/peer"
2627
"github.com/op/go-logging"
@@ -153,7 +154,7 @@ func (ipc *inprocContainer) launchInProc(ctxt context.Context, id string, args [
153154
}
154155

155156
//Start starts a previously registered system codechain
156-
func (vm *InprocVM) Start(ctxt context.Context, ccid ccintf.CCID, args []string, env []string, reader io.Reader) error {
157+
func (vm *InprocVM) Start(ctxt context.Context, ccid ccintf.CCID, args []string, env []string, builder container.BuildSpecFactory) error {
157158
path := ccid.ChaincodeSpec.ChaincodeID.Path
158159

159160
ipctemplate := typeRegistry[path]

0 commit comments

Comments
 (0)