Skip to content

Commit 29db166

Browse files
wlahtisykesm
authored andcommitted
Instrument chaincode container build
Add metric for chaincode container build duration. FAB-12868 #done Change-Id: Ie28259ef3d6214616f6ef8d4eb5bbcdb13a4c599 Signed-off-by: Will Lahti <wtlahti@us.ibm.com> Signed-off-by: Matthew Sykes <sykesmat@us.ibm.com>
1 parent bd5df09 commit 29db166

File tree

6 files changed

+106
-46
lines changed

6 files changed

+106
-46
lines changed

core/chaincode/chaincode_support_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func initMockPeer(chainIDs ...string) (*ChaincodeSupport, error) {
186186
mockAclProvider,
187187
container.NewVMController(
188188
map[string]container.VMProvider{
189-
dockercontroller.ContainerType: dockercontroller.NewProvider("", ""),
189+
dockercontroller.ContainerType: dockercontroller.NewProvider("", "", &disabled.Provider{}),
190190
inproccontroller.ContainerType: ipRegistry,
191191
},
192192
),

core/chaincode/exectransaction_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ func initPeer(chainIDs ...string) (net.Listener, *ChaincodeSupport, func(), erro
134134
aclmgmt.NewACLProvider(func(string) channelconfig.Resources { return nil }),
135135
container.NewVMController(
136136
map[string]container.VMProvider{
137-
dockercontroller.ContainerType: dockercontroller.NewProvider("", ""),
137+
dockercontroller.ContainerType: dockercontroller.NewProvider("", "", &disabled.Provider{}),
138138
inproccontroller.ContainerType: ipRegistry,
139139
},
140140
),

core/container/dockercontroller/dockercontroller.go

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ import (
1616
"fmt"
1717
"io"
1818
"regexp"
19+
"strconv"
1920
"strings"
2021
"time"
2122

2223
"github.com/fsouza/go-dockerclient"
2324
"github.com/hyperledger/fabric/common/flogging"
25+
"github.com/hyperledger/fabric/common/metrics"
2426
"github.com/hyperledger/fabric/common/util"
2527
"github.com/hyperledger/fabric/core/container"
2628
"github.com/hyperledger/fabric/core/container/ccintf"
@@ -47,6 +49,7 @@ type DockerVM struct {
4749
getClientFnc getClient
4850
PeerID string
4951
NetworkID string
52+
BuildMetrics *BuildMetrics
5053
}
5154

5255
// dockerClient represents a docker client
@@ -80,33 +83,36 @@ type dockerClient interface {
8083
PingWithContext(context.Context) error
8184
}
8285

83-
// Controller implements container.VMProvider
86+
// Provider implements container.VMProvider
8487
type Provider struct {
85-
PeerID string
86-
NetworkID string
88+
PeerID string
89+
NetworkID string
90+
BuildMetrics *BuildMetrics
8791
}
8892

8993
// NewProvider creates a new instance of Provider
90-
func NewProvider(peerID, networkID string) *Provider {
94+
func NewProvider(peerID, networkID string, metricsProvider metrics.Provider) *Provider {
9195
return &Provider{
92-
PeerID: peerID,
93-
NetworkID: networkID,
96+
PeerID: peerID,
97+
NetworkID: networkID,
98+
BuildMetrics: NewBuildMetrics(metricsProvider),
9499
}
95100
}
96101

97102
// NewVM creates a new DockerVM instance
98103
func (p *Provider) NewVM() container.VM {
99-
return NewDockerVM(p.PeerID, p.NetworkID)
104+
return NewDockerVM(p.PeerID, p.NetworkID, p.BuildMetrics)
100105
}
101106

102107
// NewDockerVM returns a new DockerVM instance
103-
func NewDockerVM(peerID, networkID string) *DockerVM {
104-
vm := DockerVM{
105-
PeerID: peerID,
106-
NetworkID: networkID,
108+
func NewDockerVM(peerID, networkID string, buildMetrics *BuildMetrics) *DockerVM {
109+
vm := &DockerVM{
110+
PeerID: peerID,
111+
NetworkID: networkID,
112+
getClientFnc: getDockerClient,
113+
BuildMetrics: buildMetrics,
107114
}
108-
vm.getClientFnc = getDockerClient
109-
return &vm
115+
return vm
110116
}
111117

112118
func getDockerClient() (dockerClient, error) {
@@ -201,7 +207,15 @@ func (vm *DockerVM) deployImage(client dockerClient, ccid ccintf.CCID,
201207
OutputStream: outputbuf,
202208
}
203209

204-
if err := client.BuildImage(opts); err != nil {
210+
startTime := time.Now()
211+
err = client.BuildImage(opts)
212+
213+
vm.BuildMetrics.ChaincodeContainerBuildDuration.With(
214+
"chaincode", ccid.Name+":"+ccid.Version,
215+
"success", strconv.FormatBool(err == nil),
216+
).Observe(time.Since(startTime).Seconds())
217+
218+
if err != nil {
205219
dockerLogger.Errorf("Error building images: %s", err)
206220
dockerLogger.Errorf("Image Output:\n********************\n%s\n********************", outputbuf.String())
207221
return err

core/container/dockercontroller/dockercontroller_test.go

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@ import (
1919
"time"
2020

2121
docker "github.com/fsouza/go-dockerclient"
22+
"github.com/hyperledger/fabric/common/metrics/disabled"
23+
"github.com/hyperledger/fabric/common/metrics/metricsfakes"
2224
"github.com/hyperledger/fabric/common/util"
2325
"github.com/hyperledger/fabric/core/chaincode/platforms"
2426
"github.com/hyperledger/fabric/core/chaincode/platforms/golang"
2527
"github.com/hyperledger/fabric/core/container/ccintf"
2628
coreutil "github.com/hyperledger/fabric/core/testutil"
2729
pb "github.com/hyperledger/fabric/protos/peer"
30+
. "github.com/onsi/gomega"
2831
"github.com/spf13/viper"
2932
"github.com/stretchr/testify/assert"
3033
"github.com/stretchr/testify/require"
@@ -33,7 +36,7 @@ import (
3336
// This test used to be part of an integration style test in core/container, moved to here
3437
func TestIntegrationPath(t *testing.T) {
3538
coreutil.SetupTestConfig()
36-
dc := NewDockerVM("", util.GenerateUUID())
39+
dc := NewDockerVM("", util.GenerateUUID(), NewBuildMetrics(&disabled.Provider{}))
3740
ccid := ccintf.CCID{Name: "simple"}
3841

3942
err := dc.Start(ccid, nil, nil, nil, InMemBuilder{})
@@ -77,8 +80,18 @@ func TestGetDockerHostConfig(t *testing.T) {
7780
}
7881

7982
func Test_Start(t *testing.T) {
80-
dvm := DockerVM{}
81-
ccid := ccintf.CCID{Name: "simple"}
83+
gt := NewGomegaWithT(t)
84+
fakeChaincodeContainerBuildDuration := &metricsfakes.Histogram{}
85+
fakeChaincodeContainerBuildDuration.WithReturns(fakeChaincodeContainerBuildDuration)
86+
dvm := DockerVM{
87+
BuildMetrics: &BuildMetrics{
88+
ChaincodeContainerBuildDuration: fakeChaincodeContainerBuildDuration,
89+
},
90+
}
91+
ccid := ccintf.CCID{
92+
Name: "simple",
93+
Version: "1.0",
94+
}
8295
args := make([]string, 1)
8396
env := make([]string, 1)
8497
files := map[string][]byte{
@@ -90,25 +103,25 @@ func Test_Start(t *testing.T) {
90103
dvm.getClientFnc = getMockClient
91104
getClientErr = true
92105
err := dvm.Start(ccid, args, env, files, nil)
93-
testerr(t, err, false)
106+
gt.Expect(err).To(HaveOccurred())
94107
getClientErr = false
95108

96109
// case 2: dockerClient.CreateContainer returns error
97110
createErr = true
98111
err = dvm.Start(ccid, args, env, files, nil)
99-
testerr(t, err, false)
112+
gt.Expect(err).To(HaveOccurred())
100113
createErr = false
101114

102115
// case 3: dockerClient.UploadToContainer returns error
103116
uploadErr = true
104117
err = dvm.Start(ccid, args, env, files, nil)
105-
testerr(t, err, false)
118+
gt.Expect(err).To(HaveOccurred())
106119
uploadErr = false
107120

108121
// case 4: dockerClient.StartContainer returns docker.noSuchImgErr
109122
noSuchImgErr = true
110123
err = dvm.Start(ccid, args, env, files, nil)
111-
testerr(t, err, false)
124+
gt.Expect(err).To(HaveOccurred())
112125

113126
chaincodePath := "github.com/hyperledger/fabric/examples/chaincode/go/example01/cmd"
114127
spec := &pb.ChaincodeSpec{
@@ -138,34 +151,43 @@ func Test_Start(t *testing.T) {
138151
viper.Set("vm.docker.attachStdout", true)
139152
startErr = true
140153
err = dvm.Start(ccid, args, env, files, bldr)
141-
testerr(t, err, false)
154+
gt.Expect(err).To(HaveOccurred())
155+
156+
gt.Expect(fakeChaincodeContainerBuildDuration.WithCallCount()).To(Equal(1))
157+
labelValues := fakeChaincodeContainerBuildDuration.WithArgsForCall(0)
158+
gt.Expect(labelValues).To(Equal([]string{
159+
"chaincode", "simple:1.0",
160+
"success", "true",
161+
}))
162+
gt.Expect(fakeChaincodeContainerBuildDuration.ObserveArgsForCall(0)).NotTo(BeZero())
163+
gt.Expect(fakeChaincodeContainerBuildDuration.ObserveArgsForCall(0)).To(BeNumerically("<", 1.0))
142164
startErr = false
143165

144166
// Success cases
145167
err = dvm.Start(ccid, args, env, files, bldr)
146-
testerr(t, err, true)
168+
gt.Expect(err).NotTo(HaveOccurred())
147169
noSuchImgErr = false
148170

149171
// dockerClient.StopContainer returns error
150172
stopErr = true
151173
err = dvm.Start(ccid, args, env, files, nil)
152-
testerr(t, err, true)
174+
gt.Expect(err).NotTo(HaveOccurred())
153175
stopErr = false
154176

155177
// dockerClient.KillContainer returns error
156178
killErr = true
157179
err = dvm.Start(ccid, args, env, files, nil)
158-
testerr(t, err, true)
180+
gt.Expect(err).NotTo(HaveOccurred())
159181
killErr = false
160182

161183
// dockerClient.RemoveContainer returns error
162184
removeErr = true
163185
err = dvm.Start(ccid, args, env, files, nil)
164-
testerr(t, err, true)
186+
gt.Expect(err).NotTo(HaveOccurred())
165187
removeErr = false
166188

167189
err = dvm.Start(ccid, args, env, files, nil)
168-
testerr(t, err, true)
190+
gt.Expect(err).NotTo(HaveOccurred())
169191
}
170192

171193
func Test_Stop(t *testing.T) {
@@ -176,12 +198,12 @@ func Test_Stop(t *testing.T) {
176198
getClientErr = true
177199
dvm.getClientFnc = getMockClient
178200
err := dvm.Stop(ccid, 10, true, true)
179-
testerr(t, err, false)
201+
assert.Error(t, err)
180202
getClientErr = false
181203

182204
// Success case
183205
err = dvm.Stop(ccid, 10, true, true)
184-
testerr(t, err, true)
206+
assert.NoError(t, err)
185207
}
186208

187209
func Test_HealthCheck(t *testing.T) {
@@ -308,14 +330,6 @@ func (imb InMemBuilder) Build() (io.Reader, error) {
308330
return inputbuf, nil
309331
}
310332

311-
func testerr(t *testing.T, err error, succ bool) {
312-
if succ {
313-
assert.NoError(t, err, "Expected success but got error")
314-
} else {
315-
assert.Error(t, err, "Expected failure but succeeded")
316-
}
317-
}
318-
319333
func getMockClient() (dockerClient, error) {
320334
if getClientErr {
321335
return nil, errors.New("Failed to get client")
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package dockercontroller
8+
9+
import "github.com/hyperledger/fabric/common/metrics"
10+
11+
var (
12+
chaincodeContainerBuildDuration = metrics.HistogramOpts{
13+
Namespace: "dockercontroller",
14+
Name: "chaincode_container_build_duration",
15+
Help: "The time to build a chaincode container in seconds.",
16+
LabelNames: []string{"chaincode", "success"},
17+
StatsdFormat: "%{#fqname}.%{chaincode}.%{success}",
18+
}
19+
)
20+
21+
type BuildMetrics struct {
22+
ChaincodeContainerBuildDuration metrics.Histogram
23+
}
24+
25+
func NewBuildMetrics(p metrics.Provider) *BuildMetrics {
26+
return &BuildMetrics{
27+
ChaincodeContainerBuildDuration: p.NewHistogram(chaincodeContainerBuildDuration),
28+
}
29+
}

peer/node/start.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -624,13 +624,16 @@ func registerChaincodeSupport(grpcServer *comm.GRPCServer, ccEndpoint string, ca
624624
packageProvider,
625625
lsccInst,
626626
aclProvider,
627-
container.NewVMController(map[string]container.VMProvider{
628-
dockercontroller.ContainerType: dockercontroller.NewProvider(
629-
viper.GetString("peer.id"),
630-
viper.GetString("peer.networkId"),
631-
),
632-
inproccontroller.ContainerType: ipRegistry,
633-
}),
627+
container.NewVMController(
628+
map[string]container.VMProvider{
629+
dockercontroller.ContainerType: dockercontroller.NewProvider(
630+
viper.GetString("peer.id"),
631+
viper.GetString("peer.networkId"),
632+
metricsProvider,
633+
),
634+
inproccontroller.ContainerType: ipRegistry,
635+
},
636+
),
634637
sccp,
635638
pr,
636639
peer.DefaultSupport,

0 commit comments

Comments
 (0)