-
Notifications
You must be signed in to change notification settings - Fork 1
/
container.go
141 lines (95 loc) · 2.93 KB
/
container.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package container
import (
"io"
"sync"
"github.com/mcc-github/blockchain/common/flogging"
"github.com/mcc-github/blockchain/core/chaincode/persistence"
"github.com/mcc-github/blockchain/core/container/ccintf"
"github.com/pkg/errors"
)
var vmLogger = flogging.MustGetLogger("container")
type VM interface {
Build(ccid string, metadata *persistence.ChaincodePackageMetadata, codePackageStream io.Reader) (Instance, error)
}
type Instance interface {
Start(peerConnection *ccintf.PeerConnection) error
Stop() error
Wait() (int, error)
}
type UninitializedInstance struct{}
func (UninitializedInstance) Start(peerConnection *ccintf.PeerConnection) error {
return errors.Errorf("instance has not yet been built, cannot be started")
}
func (UninitializedInstance) Stop() error {
return errors.Errorf("instance has not yet been built, cannot be stopped")
}
func (UninitializedInstance) Wait() (int, error) {
return 0, errors.Errorf("instance has not yet been built, cannot wait")
}
type PackageProvider interface {
GetChaincodePackage(packageID string) (*persistence.ChaincodePackageMetadata, io.ReadCloser, error)
}
type Router struct {
ExternalVM VM
DockerVM VM
containers map[string]Instance
PackageProvider PackageProvider
mutex sync.Mutex
}
func (r *Router) getInstance(ccid string) Instance {
r.mutex.Lock()
defer r.mutex.Unlock()
if r.containers == nil {
r.containers = map[string]Instance{}
}
vm, ok := r.containers[ccid]
if !ok {
return UninitializedInstance{}
}
return vm
}
func (r *Router) Build(ccid string) error {
packageID := ccid
var instance Instance
var externalErr error
if r.ExternalVM != nil {
metadata, codeStream, err := r.PackageProvider.GetChaincodePackage(packageID)
if err != nil {
return errors.WithMessage(err, "get chaincode package for external build failed")
}
instance, externalErr = r.ExternalVM.Build(ccid, metadata, codeStream)
codeStream.Close()
}
var dockerErr error
if r.ExternalVM == nil || externalErr != nil {
metadata, codeStream, err := r.PackageProvider.GetChaincodePackage(ccid)
if err != nil {
return errors.WithMessage(err, "get chaincode package for docker build failed")
}
instance, dockerErr = r.DockerVM.Build(ccid, metadata, codeStream)
codeStream.Close()
}
if dockerErr != nil {
return errors.WithMessagef(dockerErr, "failed external (%s) and docker build", externalErr)
}
r.mutex.Lock()
defer r.mutex.Unlock()
if r.containers == nil {
r.containers = map[string]Instance{}
}
r.containers[ccid] = instance
return nil
}
func (r *Router) Start(ccid string, peerConnection *ccintf.PeerConnection) error {
return r.getInstance(ccid).Start(peerConnection)
}
func (r *Router) Stop(ccid string) error {
return r.getInstance(ccid).Stop()
}
func (r *Router) Wait(ccid string) (int, error) {
return r.getInstance(ccid).Wait()
}