Skip to content

Commit 980b4b2

Browse files
committed
[FAB-3118] pull ccenv image at runtime
The current code requires the CORE_CHAINCODE_BUILDER image to be pre-pulled down from dockerhub or chaincode building will fail. This patch adds the docker-client intelligence to check whether the image is present. If it finds that it is not present, it will try to pull the image from dockerhub. Change-Id: I95b6bcd0f1b1beb2edee7f0b542f90f5fb9eabc7 Signed-off-by: Greg Haskins <[email protected]>
1 parent ed41640 commit 980b4b2

File tree

4 files changed

+73
-3
lines changed

4 files changed

+73
-3
lines changed

core/chaincode/platforms/util/utils.go

+15
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,21 @@ func DockerBuild(opts DockerBuildOptions) error {
155155
}
156156
}
157157

158+
logger.Debugf("Attempting build with image %s", opts.Image)
159+
160+
//-----------------------------------------------------------------------------------
161+
// Ensure the image exists locally, or pull it from a registry if it doesn't
162+
//-----------------------------------------------------------------------------------
163+
_, err = client.InspectImage(opts.Image)
164+
if err != nil {
165+
logger.Debugf("Image %s does not exist locally, attempt pull", opts.Image)
166+
167+
err = client.PullImage(docker.PullImageOptions{Repository: opts.Image}, docker.AuthConfiguration{})
168+
if err != nil {
169+
return fmt.Errorf("Failed to pull %s: %s", opts.Image, err)
170+
}
171+
}
172+
158173
//-----------------------------------------------------------------------------------
159174
// Create an ephemeral container, armed with our Env/Cmd
160175
//-----------------------------------------------------------------------------------

core/chaincode/platforms/util/utils_test.go

+55
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,16 @@ import (
2323
"testing"
2424
"time"
2525

26+
"archive/tar"
27+
"fmt"
28+
"io"
29+
"os"
30+
"strings"
31+
2632
"github.com/hyperledger/fabric/common/util"
33+
"github.com/hyperledger/fabric/core/config"
34+
cutil "github.com/hyperledger/fabric/core/container/util"
35+
"github.com/spf13/viper"
2736
)
2837

2938
// TestHashContentChange changes a random byte in a content and checks for hash change
@@ -187,3 +196,49 @@ func TestHashSameDir(t *testing.T) {
187196
t.Error("Hash should be same across multiple downloads")
188197
}
189198
}
199+
200+
func TestDockerPull(t *testing.T) {
201+
codepackage, output := io.Pipe()
202+
go func() {
203+
tw := tar.NewWriter(output)
204+
205+
tw.Close()
206+
output.Close()
207+
}()
208+
209+
binpackage := bytes.NewBuffer(nil)
210+
211+
// Perform a nop operation within a fixed target. We choose 1.0.0-alpha2 because we know it's
212+
// published and available. Ideally we could choose something that we know is both multi-arch
213+
// and ok to delete prior to executing DockerBuild. This would ensure that we exercise the
214+
// image pull logic. However, no suitable target exists that meets all the criteria. Therefore
215+
// we settle on using a known released image. We don't know if the image is already
216+
// downloaded per se, and we don't want to explicitly delete this particular image first since
217+
// it could be in use legitimately elsewhere. Instead, we just know that this should always
218+
// work and call that "close enough".
219+
//
220+
// Future considerations: publish a known dummy image that is multi-arch and free to randomly
221+
// delete, and use that here instead.
222+
err := DockerBuild(DockerBuildOptions{
223+
Image: cutil.ParseDockerfileTemplate("hyperledger/fabric-ccenv:$(ARCH)-1.0.0-alpha2"),
224+
Cmd: "/bin/true",
225+
InputStream: codepackage,
226+
OutputStream: binpackage,
227+
})
228+
if err != nil {
229+
t.Errorf("Error during build: %s", err)
230+
}
231+
}
232+
233+
func TestMain(m *testing.M) {
234+
viper.SetConfigName("core")
235+
viper.SetEnvPrefix("CORE")
236+
config.AddDevConfigPath(nil)
237+
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
238+
viper.AutomaticEnv()
239+
if err := viper.ReadInConfig(); err != nil {
240+
fmt.Printf("could not read config %s\n", err)
241+
os.Exit(-1)
242+
}
243+
os.Exit(m.Run())
244+
}

core/container/util/dockerutil.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func getArch() string {
5656
}
5757
}
5858

59-
func parseDockerfileTemplate(template string) string {
59+
func ParseDockerfileTemplate(template string) string {
6060
r := strings.NewReplacer(
6161
"$(ARCH)", getArch(),
6262
"$(PROJECT_VERSION)", metadata.Version,
@@ -68,5 +68,5 @@ func parseDockerfileTemplate(template string) string {
6868
}
6969

7070
func GetDockerfileFromConfig(path string) string {
71-
return parseDockerfileTemplate(viper.GetString(path))
71+
return ParseDockerfileTemplate(viper.GetString(path))
7272
}

core/container/util/dockerutil_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import (
2626

2727
func TestUtil_DockerfileTemplateParser(t *testing.T) {
2828
expected := "FROM foo:" + getArch() + "-" + metadata.Version
29-
actual := parseDockerfileTemplate("FROM foo:$(ARCH)-$(PROJECT_VERSION)")
29+
actual := ParseDockerfileTemplate("FROM foo:$(ARCH)-$(PROJECT_VERSION)")
3030
assert.Equal(t, expected, actual, "Error parsing Dockerfile Template. Expected \"%s\", got \"%s\"",
3131
expected, actual)
3232
}

0 commit comments

Comments
 (0)