func TestSaveArtifactsRunError(t *testing.T) { tests := []error{ fmt.Errorf("Run error"), stierr.NewContainerError("", -1, ""), } expected := []error{ tests[0], stierr.NewSaveArtifactsError("", "", tests[1]), } // test with tar extract error or not tarError := []bool{true, false} for i := range tests { for _, te := range tarError { bh := testBuildHandler() fd := bh.docker.(*docker.FakeDocker) th := bh.tar.(*test.FakeTar) fd.RunContainerError = tests[i] if te { th.ExtractTarError = fmt.Errorf("tar error") } err := bh.Save(bh.config) if !te && err != expected[i] { t.Errorf("Unexpected error returned from saveArtifacts: %v", err) } else if te && err != th.ExtractTarError { t.Errorf("Expected tar error. Got %v", err) } } } }
// Save extracts and restores the build artifacts from the previous build to a // current build. func (builder *STI) Save(config *api.Config) (err error) { artifactTmpDir := filepath.Join(config.WorkingDir, "upload", "artifacts") if err = builder.fs.Mkdir(artifactTmpDir); err != nil { return err } image := firstNonEmpty(config.IncrementalFromTag, config.Tag) outReader, outWriter := io.Pipe() defer outReader.Close() defer outWriter.Close() errReader, errWriter := io.Pipe() defer errReader.Close() defer errWriter.Close() glog.V(1).Infof("Saving build artifacts from image %s to path %s", image, artifactTmpDir) extractFunc := func(string) error { return builder.tar.ExtractTarStream(artifactTmpDir, outReader) } user := config.AssembleUser if len(user) == 0 { user, err = builder.docker.GetImageUser(image) if err != nil { return err } glog.V(3).Infof("The assemble user is not set, defaulting to %q user", user) } else { glog.V(3).Infof("Using assemble user %q to extract artifacts", user) } opts := dockerpkg.RunContainerOptions{ Image: image, User: user, ExternalScripts: builder.externalScripts[api.SaveArtifacts], ScriptsURL: config.ScriptsURL, Destination: config.Destination, PullImage: false, Command: api.SaveArtifacts, Stdout: outWriter, Stderr: errWriter, OnStart: extractFunc, NetworkMode: string(config.DockerNetworkMode), CGroupLimits: config.CGroupLimits, CapDrop: config.DropCapabilities, } go dockerpkg.StreamContainerIO(errReader, nil, func(a ...interface{}) { glog.Info(a...) }) err = builder.docker.RunContainer(opts) if e, ok := err.(errors.ContainerError); ok { // even with deferred close above, close errReader now so we avoid data race condition on errOutput; // closing will cause StreamContainerIO to exit, thus releasing the writer in the equation errReader.Close() return errors.NewSaveArtifactsError(image, e.Output, err) } return err }
// Save extracts and restores the build artifacts from the previous build to a // current build. func (b *STI) Save(config *api.Config) (err error) { artifactTmpDir := filepath.Join(config.WorkingDir, "upload", "artifacts") if err = b.fs.Mkdir(artifactTmpDir); err != nil { return err } image := config.IncrementalFromTag if len(image) == 0 { image = config.Tag } outReader, outWriter := io.Pipe() defer outReader.Close() defer outWriter.Close() errReader, errWriter := io.Pipe() defer errReader.Close() defer errWriter.Close() glog.V(1).Infof("Saving build artifacts from image %s to path %s", image, artifactTmpDir) extractFunc := func(string) error { return b.tar.ExtractTarStream(artifactTmpDir, outReader) } user := config.AssembleUser if len(user) == 0 { user, err = b.docker.GetImageUser(image) if err != nil { return err } glog.V(3).Infof("The assemble user is not set, defaulting to %q user", user) } else { glog.V(3).Infof("Using assemble user %q to extract artifacts", user) } opts := dockerpkg.RunContainerOptions{ Image: image, User: user, ExternalScripts: b.externalScripts[api.SaveArtifacts], ScriptsURL: config.ScriptsURL, Destination: config.Destination, PullImage: false, Command: api.SaveArtifacts, Stdout: outWriter, Stderr: errWriter, OnStart: extractFunc, NetworkMode: string(config.DockerNetworkMode), CGroupLimits: config.CGroupLimits, CapDrop: config.DropCapabilities, } go dockerpkg.StreamContainerIO(errReader, nil, glog.Error) err = b.docker.RunContainer(opts) if e, ok := err.(errors.ContainerError); ok { return errors.NewSaveArtifactsError(image, e.Output, err) } return err }
// Save extracts and restores the build artifacts from the previous build to a // current build. func (b *STI) Save(config *api.Config) (err error) { artifactTmpDir := filepath.Join(config.WorkingDir, "upload", "artifacts") if err = b.fs.Mkdir(artifactTmpDir); err != nil { return err } image := config.Tag outReader, outWriter := io.Pipe() errReader, errWriter := io.Pipe() defer errReader.Close() defer errWriter.Close() glog.V(1).Infof("Saving build artifacts from image %s to path %s", image, artifactTmpDir) extractFunc := func() error { defer outReader.Close() return b.tar.ExtractTarStream(artifactTmpDir, outReader) } opts := dockerpkg.RunContainerOptions{ Image: image, ExternalScripts: b.externalScripts[api.SaveArtifacts], ScriptsURL: config.ScriptsURL, Destination: config.Destination, PullImage: false, Command: api.SaveArtifacts, Stdout: outWriter, Stderr: errWriter, OnStart: extractFunc, NetworkMode: string(config.DockerNetworkMode), } go dockerpkg.StreamContainerIO(errReader, nil, glog.Error) err = b.docker.RunContainer(opts) if e, ok := err.(errors.ContainerError); ok { return errors.NewSaveArtifactsError(image, e.Output, err) } return err }
// Save extracts and restores the build artifacts from the previous build to a // current build. func (builder *STI) Save(config *api.Config) (err error) { artifactTmpDir := filepath.Join(config.WorkingDir, "upload", "artifacts") if builder.result == nil { builder.result = &api.Result{} } if err = builder.fs.Mkdir(artifactTmpDir); err != nil { builder.result.BuildInfo.FailureReason = utilstatus.NewFailureReason( utilstatus.ReasonFSOperationFailed, utilstatus.ReasonMessageFSOperationFailed, ) return err } image := firstNonEmpty(config.IncrementalFromTag, config.Tag) outReader, outWriter := io.Pipe() errReader, errWriter := io.Pipe() glog.V(1).Infof("Saving build artifacts from image %s to path %s", image, artifactTmpDir) extractFunc := func(string) error { extractErr := builder.tar.ExtractTarStream(artifactTmpDir, outReader) io.Copy(ioutil.Discard, outReader) // must ensure reader from container is drained return extractErr } user := config.AssembleUser if len(user) == 0 { user, err = builder.docker.GetImageUser(image) if err != nil { builder.result.BuildInfo.FailureReason = utilstatus.NewFailureReason( utilstatus.ReasonGenericS2IBuildFailed, utilstatus.ReasonMessageGenericS2iBuildFailed, ) return err } glog.V(3).Infof("The assemble user is not set, defaulting to %q user", user) } else { glog.V(3).Infof("Using assemble user %q to extract artifacts", user) } opts := dockerpkg.RunContainerOptions{ Image: image, User: user, ExternalScripts: builder.externalScripts[api.SaveArtifacts], ScriptsURL: config.ScriptsURL, Destination: config.Destination, PullImage: false, Command: api.SaveArtifacts, Stdout: outWriter, Stderr: errWriter, OnStart: extractFunc, NetworkMode: string(config.DockerNetworkMode), CGroupLimits: config.CGroupLimits, CapDrop: config.DropCapabilities, } dockerpkg.StreamContainerIO(errReader, nil, func(s string) { glog.Info(s) }) err = builder.docker.RunContainer(opts) if e, ok := err.(s2ierr.ContainerError); ok { err = s2ierr.NewSaveArtifactsError(image, e.Output, err) } builder.result.BuildInfo.FailureReason = utilstatus.NewFailureReason( utilstatus.ReasonGenericS2IBuildFailed, utilstatus.ReasonMessageGenericS2iBuildFailed, ) return err }