Skip to content

Commit 7d0500b

Browse files
author
Jason Yellick
committed
FAB-16599 Add optional release to externalbuilders
Per the design, the external builders are to be given the opportunity to supply a 'release' binary, which will be invoked after the build, and give the chaincode an opportunity to supply assets such as connection information for a remote chaincode, or chaincode db indicates which must be installed into the statedb for the chaincode to function properly. This CR adds rudimentary support for release. Signed-off-by: Jason Yellick <jyellick@us.ibm.com> Change-Id: I743174c825eae7fd62eaca03bb2905ddfa7cdc1b
1 parent 4d7d946 commit 7d0500b

File tree

10 files changed

+123
-34
lines changed

10 files changed

+123
-34
lines changed

core/container/externalbuilders/externalbuilders.go

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ func (d *Detector) Build(ccid string, md *persistence.ChaincodePackageMetadata,
141141
return nil, errors.WithMessage(err, "external builder failed to build")
142142
}
143143

144+
if err := builder.Release(buildContext); err != nil {
145+
return nil, errors.WithMessage(err, "external builder failed to release")
146+
}
147+
144148
durablePath := filepath.Join(d.DurablePath, ccid)
145149

146150
err = os.Mkdir(durablePath, 0700)
@@ -162,9 +166,16 @@ func (d *Detector) Build(ccid string, md *persistence.ChaincodePackageMetadata,
162166
return nil, errors.WithMessage(err, "could not write build-info.json")
163167
}
164168

169+
err = os.Rename(buildContext.ReleaseDir, filepath.Join(durablePath, "release"))
170+
if err != nil {
171+
os.RemoveAll(durablePath)
172+
return nil, errors.WithMessagef(err, "could not move build context release to persistent location '%s'", durablePath)
173+
}
174+
165175
durableBldDir := filepath.Join(durablePath, "bld")
166176
err = os.Rename(buildContext.BldDir, durableBldDir)
167177
if err != nil {
178+
os.RemoveAll(durablePath)
168179
return nil, errors.WithMessagef(err, "could not move build context bld to persistent location '%s'", durablePath)
169180
}
170181

@@ -180,48 +191,52 @@ type BuildContext struct {
180191
Metadata *persistence.ChaincodePackageMetadata
181192
ScratchDir string
182193
SourceDir string
194+
ReleaseDir string
183195
MetadataDir string
184196
BldDir string
185197
}
186198

187199
var pkgIDreg = regexp.MustCompile("[^a-zA-Z0-9]+")
188200

189-
func NewBuildContext(ccid string, md *persistence.ChaincodePackageMetadata, codePackage io.Reader) (*BuildContext, error) {
201+
func NewBuildContext(ccid string, md *persistence.ChaincodePackageMetadata, codePackage io.Reader) (bc *BuildContext, err error) {
190202
scratchDir, err := ioutil.TempDir("", "fabric-"+pkgIDreg.ReplaceAllString(ccid, "-"))
191203
if err != nil {
192204
return nil, errors.WithMessage(err, "could not create temp dir")
193205
}
194206

207+
defer func() {
208+
if err != nil {
209+
os.RemoveAll(scratchDir)
210+
}
211+
}()
212+
195213
sourceDir := filepath.Join(scratchDir, "src")
196-
err = os.Mkdir(sourceDir, 0700)
197-
if err != nil {
198-
os.RemoveAll(scratchDir)
214+
if err = os.Mkdir(sourceDir, 0700); err != nil {
199215
return nil, errors.WithMessage(err, "could not create source dir")
200216
}
201217

202218
metadataDir := filepath.Join(scratchDir, "metadata")
203-
err = os.Mkdir(metadataDir, 0700)
204-
if err != nil {
205-
os.RemoveAll(scratchDir)
219+
if err = os.Mkdir(metadataDir, 0700); err != nil {
206220
return nil, errors.WithMessage(err, "could not create metadata dir")
207221
}
208222

209223
outputDir := filepath.Join(scratchDir, "bld")
210-
err = os.Mkdir(outputDir, 0700)
211-
if err != nil {
212-
os.RemoveAll(scratchDir)
224+
if err = os.Mkdir(outputDir, 0700); err != nil {
213225
return nil, errors.WithMessage(err, "could not create build dir")
214226
}
215227

228+
releaseDir := filepath.Join(scratchDir, "release")
229+
if err = os.Mkdir(releaseDir, 0700); err != nil {
230+
return nil, errors.WithMessage(err, "could not create release dir")
231+
}
232+
216233
err = Untar(codePackage, sourceDir)
217234
if err != nil {
218-
os.RemoveAll(scratchDir)
219235
return nil, errors.WithMessage(err, "could not untar source package")
220236
}
221237

222238
err = writeMetadataFile(ccid, md, metadataDir)
223239
if err != nil {
224-
os.RemoveAll(scratchDir)
225240
return nil, errors.WithMessage(err, "could not write metadata file")
226241
}
227242

@@ -230,6 +245,7 @@ func NewBuildContext(ccid string, md *persistence.ChaincodePackageMetadata, code
230245
SourceDir: sourceDir,
231246
MetadataDir: metadataDir,
232247
BldDir: outputDir,
248+
ReleaseDir: releaseDir,
233249
Metadata: md,
234250
CCID: ccid,
235251
}, nil
@@ -317,6 +333,33 @@ func (b *Builder) Build(buildContext *BuildContext) error {
317333
return nil
318334
}
319335

336+
func (b *Builder) Release(buildContext *BuildContext) error {
337+
release := filepath.Join(b.Location, "bin", "release")
338+
339+
_, err := os.Stat(release)
340+
if os.IsNotExist(err) {
341+
b.Logger.Debugf("Skipping release step for '%s' as no release binary found", buildContext.CCID)
342+
return nil
343+
}
344+
345+
if err != nil {
346+
return errors.WithMessagef(err, "could not stat release binary '%s'", release)
347+
}
348+
349+
cmd := NewCommand(
350+
release,
351+
b.EnvWhitelist,
352+
buildContext.BldDir,
353+
buildContext.ReleaseDir,
354+
)
355+
356+
if err := RunCommand(b.Logger, cmd); err != nil {
357+
return errors.Wrapf(err, "builder '%s' release failed", b.Name)
358+
}
359+
360+
return nil
361+
}
362+
320363
// LaunchConfig is serialized to disk when launching
321364
type LaunchConfig struct {
322365
CCID string `json:"chaincode_id"`

core/container/externalbuilders/externalbuilders_test.go

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ var _ = Describe("Externalbuilders", func() {
6363
_, err = os.Stat(buildContext.SourceDir)
6464
Expect(err).NotTo(HaveOccurred())
6565

66+
Expect(buildContext.ReleaseDir).NotTo(BeEmpty())
67+
_, err = os.Stat(buildContext.SourceDir)
68+
Expect(err).NotTo(HaveOccurred())
69+
70+
Expect(buildContext.BldDir).NotTo(BeEmpty())
71+
_, err = os.Stat(buildContext.SourceDir)
72+
Expect(err).NotTo(HaveOccurred())
73+
6674
_, err = os.Stat(filepath.Join(buildContext.SourceDir, "a/test.file"))
6775
Expect(err).NotTo(HaveOccurred())
6876
})
@@ -104,8 +112,8 @@ var _ = Describe("Externalbuilders", func() {
104112
Name: "bad1",
105113
},
106114
{
107-
Path: "testdata",
108-
Name: "testdata",
115+
Path: "testdata/goodbuilder",
116+
Name: "goodbuilder",
109117
},
110118
{
111119
Path: "bad2",
@@ -127,7 +135,7 @@ var _ = Describe("Externalbuilders", func() {
127135
It("iterates over all detectors and chooses the one that matches", func() {
128136
instance, err := detector.Build("fake-package-id", md, codePackage)
129137
Expect(err).NotTo(HaveOccurred())
130-
Expect(instance.Builder.Name).To(Equal("testdata"))
138+
Expect(instance.Builder.Name).To(Equal("goodbuilder"))
131139
})
132140

133141
Context("when no builder can be found", func() {
@@ -148,6 +156,9 @@ var _ = Describe("Externalbuilders", func() {
148156
_, err = os.Stat(filepath.Join(durablePath, "fake-package-id", "bld"))
149157
Expect(err).NotTo(HaveOccurred())
150158

159+
_, err = os.Stat(filepath.Join(durablePath, "fake-package-id", "release"))
160+
Expect(err).NotTo(HaveOccurred())
161+
151162
_, err = os.Stat(filepath.Join(durablePath, "fake-package-id", "build-info.json"))
152163
Expect(err).NotTo(HaveOccurred())
153164
})
@@ -215,7 +226,7 @@ var _ = Describe("Externalbuilders", func() {
215226

216227
It("returns an error", func() {
217228
_, err := detector.Build("fake-package-id", md, codePackage)
218-
Expect(err).To(MatchError("existing build could not be restored: chaincode 'fake-package-id' was already built with builder 'testdata', but that builder is no longer available"))
229+
Expect(err).To(MatchError("existing build could not be restored: chaincode 'fake-package-id' was already built with builder 'goodbuilder', but that builder is no longer available"))
219230
})
220231
})
221232
})
@@ -229,8 +240,9 @@ var _ = Describe("Externalbuilders", func() {
229240

230241
BeforeEach(func() {
231242
builder = &externalbuilders.Builder{
232-
Location: "testdata",
233-
Name: "testdata",
243+
Location: "testdata/goodbuilder",
244+
Name: "goodbuilder",
245+
Logger: flogging.MustGetLogger("builder.test"),
234246
}
235247

236248
var err error
@@ -250,13 +262,7 @@ var _ = Describe("Externalbuilders", func() {
250262

251263
Context("when the detector exits with a non-zero status", func() {
252264
BeforeEach(func() {
253-
md.Type = "foo"
254-
255-
var err error
256-
codePackage, err = os.Open("testdata/normal_archive.tar.gz")
257-
Expect(err).NotTo(HaveOccurred())
258-
buildContext, err = externalbuilders.NewBuildContext("fake-package-id", md, codePackage)
259-
Expect(err).NotTo(HaveOccurred())
265+
builder.Location = "testdata/failbuilder"
260266
})
261267

262268
It("returns false", func() {
@@ -274,18 +280,43 @@ var _ = Describe("Externalbuilders", func() {
274280

275281
Context("when the builder exits with a non-zero status", func() {
276282
BeforeEach(func() {
277-
md.Path = "bar"
283+
builder.Location = "testdata/failbuilder"
284+
builder.Name = "failbuilder"
285+
})
278286

279-
var err error
280-
codePackage, err = os.Open("testdata/normal_archive.tar.gz")
281-
Expect(err).NotTo(HaveOccurred())
282-
buildContext, err = externalbuilders.NewBuildContext("fake-package-id", md, codePackage)
287+
It("returns an error", func() {
288+
err := builder.Build(buildContext)
289+
Expect(err).To(MatchError("builder 'failbuilder' build failed: exit status 1"))
290+
})
291+
})
292+
})
293+
294+
Describe("Release", func() {
295+
It("releases the package by invoking external builder", func() {
296+
err := builder.Release(buildContext)
297+
Expect(err).NotTo(HaveOccurred())
298+
})
299+
300+
When("the release binary is not in the builder", func() {
301+
BeforeEach(func() {
302+
builder.Location = "bad-builder-location"
303+
})
304+
305+
It("returns no error as release is optional", func() {
306+
err := builder.Release(buildContext)
283307
Expect(err).NotTo(HaveOccurred())
284308
})
309+
})
310+
311+
When("the builder exits with a non-zero status", func() {
312+
BeforeEach(func() {
313+
builder.Location = "testdata/failbuilder"
314+
builder.Name = "failbuilder"
315+
})
285316

286317
It("returns an error", func() {
287-
err := builder.Build(buildContext)
288-
Expect(err).To(MatchError("builder 'testdata' build failed: exit status 1"))
318+
err := builder.Release(buildContext)
319+
Expect(err).To(MatchError("builder 'failbuilder' release failed: exit status 1"))
289320
})
290321
})
291322
})
@@ -325,12 +356,13 @@ var _ = Describe("Externalbuilders", func() {
325356

326357
Context("when the launch exits with a non-zero status", func() {
327358
BeforeEach(func() {
328-
fakeConnection.Address = "different-fake-peer-address"
359+
builder.Location = "testdata/failbuilder"
360+
builder.Name = "failbuilder"
329361
})
330362

331363
It("returns an error", func() {
332364
err := builder.Launch("test-ccid", bldDir, fakeConnection)
333-
Expect(err).To(MatchError("builder 'testdata' launch failed: exit status 1"))
365+
Expect(err).To(MatchError("builder 'failbuilder' launch failed: exit status 1"))
334366
})
335367
})
336368
})
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/bash
2+
exit 1
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/bash
2+
exit 1
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/bash
2+
exit 1
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/bash
2+
exit 1
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/bash
2+
if [ $# -ne 2 ] ; then
3+
exit 2
4+
fi
5+
6+
exit 0

0 commit comments

Comments
 (0)