// Build handles the `docker build` equivalent execution, returning the // success/failure details. func (builder *Layered) Build(config *api.Config) (*api.Result, error) { buildResult := &api.Result{} if config.HasOnBuild && config.BlockOnBuild { buildResult.BuildInfo.FailureReason = utilstatus.NewFailureReason( utilstatus.ReasonOnBuildForbidden, utilstatus.ReasonMessageOnBuildForbidden, ) return buildResult, errors.New("builder image uses ONBUILD instructions but ONBUILD is not allowed") } if config.BuilderImage == "" { buildResult.BuildInfo.FailureReason = utilstatus.NewFailureReason( utilstatus.ReasonGenericS2IBuildFailed, utilstatus.ReasonMessageGenericS2iBuildFailed, ) return buildResult, errors.New("builder image name cannot be empty") } if err := builder.CreateDockerfile(config); err != nil { buildResult.BuildInfo.FailureReason = utilstatus.NewFailureReason( utilstatus.ReasonDockerfileCreateFailed, utilstatus.ReasonMessageDockerfileCreateFailed, ) return buildResult, err } glog.V(2).Info("Creating application source code image") tarStream := builder.tar.CreateTarStreamReader(filepath.Join(config.WorkingDir, "upload"), false) defer tarStream.Close() newBuilderImage := fmt.Sprintf("s2i-layered-temp-image-%d", time.Now().UnixNano()) outReader, outWriter := io.Pipe() opts := docker.BuildImageOptions{ Name: newBuilderImage, Stdin: tarStream, Stdout: outWriter, CGroupLimits: config.CGroupLimits, } docker.StreamContainerIO(outReader, nil, func(s string) { glog.V(2).Info(s) }) glog.V(2).Infof("Building new image %s with scripts and sources already inside", newBuilderImage) if err := builder.docker.BuildImage(opts); err != nil { buildResult.BuildInfo.FailureReason = utilstatus.NewFailureReason( utilstatus.ReasonDockerImageBuildFailed, utilstatus.ReasonMessageDockerImageBuildFailed, ) return buildResult, err } // upon successful build we need to modify current config builder.config.LayeredBuild = true // new image name builder.config.BuilderImage = newBuilderImage // see CreateDockerfile, conditional copy, location of scripts scriptsIncluded := checkValidDirWithContents(path.Join(config.WorkingDir, api.UploadScripts)) glog.V(2).Infof("Scripts dir has contents %v", scriptsIncluded) if scriptsIncluded { builder.config.ScriptsURL = "image://" + path.Join(getDestination(config), "scripts") } else { var err error builder.config.ScriptsURL, err = builder.docker.GetScriptsURL(newBuilderImage) if err != nil { buildResult.BuildInfo.FailureReason = utilstatus.NewFailureReason( utilstatus.ReasonGenericS2IBuildFailed, utilstatus.ReasonMessageGenericS2iBuildFailed, ) return buildResult, err } } glog.V(2).Infof("Building %s using sti-enabled image", builder.config.Tag) if err := builder.scripts.Execute(api.Assemble, config.AssembleUser, builder.config); err != nil { buildResult.BuildInfo.FailureReason = utilstatus.NewFailureReason( utilstatus.ReasonAssembleFailed, utilstatus.ReasonMessageAssembleFailed, ) switch e := err.(type) { case s2ierr.ContainerError: return buildResult, s2ierr.NewAssembleError(builder.config.Tag, e.Output, e) default: return buildResult, err } } buildResult.Success = true return buildResult, nil }
func (b *Layered) Build(config *api.Config) (*api.Result, error) { if err := b.CreateDockerfile(config); err != nil { return nil, err } glog.V(2).Info("Creating application source code image") tarStream, err := b.SourceTar(config) if err != nil { return nil, err } defer tarStream.Close() newBuilderImage := fmt.Sprintf("%s-%d", b.config.BuilderImage, time.Now().UnixNano()) outReader, outWriter := io.Pipe() defer outReader.Close() defer outWriter.Close() opts := docker.BuildImageOptions{ Name: newBuilderImage, Stdin: tarStream, Stdout: outWriter, } // goroutine to stream container's output go func(reader io.Reader) { scanner := bufio.NewReader(reader) for { text, err := scanner.ReadString('\n') if err != nil { // we're ignoring ErrClosedPipe, as this is information // the docker container ended streaming logs if glog.V(2) && err != io.ErrClosedPipe { glog.Errorf("Error reading docker stdout, %v", err) } break } glog.V(2).Info(text) } }(outReader) glog.V(2).Infof("Building new image %s with scripts and sources already inside", newBuilderImage) if err = b.docker.BuildImage(opts); err != nil { return nil, err } // upon successful build we need to modify current config b.config.LayeredBuild = true // new image name b.config.BuilderImage = newBuilderImage // the scripts are inside the image b.config.ScriptsURL = "image://" + filepath.Join(getDestination(config), "scripts") glog.V(2).Infof("Building %s using sti-enabled image", b.config.Tag) if err := b.scripts.Execute(api.Assemble, b.config); err != nil { switch e := err.(type) { case errors.ContainerError: return nil, errors.NewAssembleError(b.config.Tag, e.Output, e) default: return nil, err } } return &api.Result{ Success: true, }, nil }
// Build handles the `docker build` equivalent execution, returning the // success/failure details. func (builder *Layered) Build(config *api.Config) (*api.Result, error) { if config.HasOnBuild && config.BlockOnBuild { return nil, fmt.Errorf("builder image uses ONBUILD instructions but ONBUILD is not allowed") } if err := builder.CreateDockerfile(config); err != nil { return nil, err } glog.V(2).Info("Creating application source code image") tarStream, err := builder.SourceTar(config) if err != nil { return nil, err } defer tarStream.Close() namedReference, err := reference.ParseNamed(builder.config.BuilderImage) if err != nil { return nil, err } newBuilderImage := fmt.Sprintf("%s:s2i-layered-%d", namedReference.Name(), time.Now().UnixNano()) outReader, outWriter := io.Pipe() defer outReader.Close() defer outWriter.Close() opts := docker.BuildImageOptions{ Name: newBuilderImage, Stdin: tarStream, Stdout: outWriter, CGroupLimits: config.CGroupLimits, } // goroutine to stream container's output go func(reader io.Reader) { scanner := bufio.NewReader(reader) for { text, err := scanner.ReadString('\n') if err != nil { // we're ignoring ErrClosedPipe, as this is information // the docker container ended streaming logs if glog.Is(2) && err != io.ErrClosedPipe && err != io.EOF { glog.Errorf("Error reading docker stdout, %v", err) } break } glog.V(2).Info(text) } }(outReader) glog.V(2).Infof("Building new image %s with scripts and sources already inside", newBuilderImage) if err = builder.docker.BuildImage(opts); err != nil { return nil, err } // upon successful build we need to modify current config builder.config.LayeredBuild = true // new image name builder.config.BuilderImage = newBuilderImage // see CreateDockerfile, conditional copy, location of scripts scriptsIncluded := checkValidDirWithContents(path.Join(config.WorkingDir, api.UploadScripts)) glog.V(2).Infof("Scripts dir has contents %v", scriptsIncluded) if scriptsIncluded { builder.config.ScriptsURL = "image://" + path.Join(getDestination(config), "scripts") } else { builder.config.ScriptsURL, err = builder.docker.GetScriptsURL(newBuilderImage) if err != nil { return nil, err } } glog.V(2).Infof("Building %s using sti-enabled image", builder.config.Tag) if err := builder.scripts.Execute(api.Assemble, config.AssembleUser, builder.config); err != nil { switch e := err.(type) { case errors.ContainerError: return nil, errors.NewAssembleError(builder.config.Tag, e.Output, e) default: return nil, err } } return &api.Result{ Success: true, }, nil }
//Build handles the `docker build` equivalent execution, returning the success/failure details func (b *Layered) Build(config *api.Config) (*api.Result, error) { if err := b.CreateDockerfile(config); err != nil { return nil, err } glog.V(2).Info("Creating application source code image") tarStream, err := b.SourceTar(config) if err != nil { return nil, err } defer tarStream.Close() dockerImageReference, err := docker.ParseDockerImageReference(b.config.BuilderImage) if err != nil { return nil, err } // if we fall down this path via oc new-app, the builder image will be a docker image ref ending // with a @<hex image id> instead of a tag; simply appending the time stamp to the end of a // hex image id ref is not kosher with the docker API; so we remove the ID piece, and then // construct the new image name var newBuilderImage string if len(dockerImageReference.ID) == 0 { newBuilderImage = fmt.Sprintf("%s-%d", b.config.BuilderImage, time.Now().UnixNano()) } else { if len(dockerImageReference.Registry) > 0 { newBuilderImage = fmt.Sprintf("%s/", dockerImageReference.Registry) } if len(dockerImageReference.Namespace) > 0 { newBuilderImage = fmt.Sprintf("%s%s/", newBuilderImage, dockerImageReference.Namespace) } newBuilderImage = fmt.Sprintf("%s%s:s2i-layered-%d", newBuilderImage, dockerImageReference.Name, time.Now().UnixNano()) } outReader, outWriter := io.Pipe() defer outReader.Close() defer outWriter.Close() opts := docker.BuildImageOptions{ Name: newBuilderImage, Stdin: tarStream, Stdout: outWriter, CGroupLimits: config.CGroupLimits, } // goroutine to stream container's output go func(reader io.Reader) { scanner := bufio.NewReader(reader) for { text, err := scanner.ReadString('\n') if err != nil { // we're ignoring ErrClosedPipe, as this is information // the docker container ended streaming logs if glog.V(2) && err != io.ErrClosedPipe { glog.Errorf("Error reading docker stdout, %v", err) } break } glog.V(2).Info(text) } }(outReader) glog.V(2).Infof("Building new image %s with scripts and sources already inside", newBuilderImage) if err = b.docker.BuildImage(opts); err != nil { return nil, err } // upon successful build we need to modify current config b.config.LayeredBuild = true // new image name b.config.BuilderImage = newBuilderImage // see CreateDockerfile, conditional copy, location of scripts scriptsIncluded := checkValidDirWithContents(path.Join(config.WorkingDir, api.UploadScripts)) glog.V(2).Infof("Scripts dir has contents %v", scriptsIncluded) if scriptsIncluded { b.config.ScriptsURL = "image://" + path.Join(getDestination(config), "scripts") } else { b.config.ScriptsURL, err = b.docker.GetScriptsURL(newBuilderImage) if err != nil { return nil, err } } glog.V(2).Infof("Building %s using sti-enabled image", b.config.Tag) if err := b.scripts.Execute(api.Assemble, config.AssembleUser, b.config); err != nil { switch e := err.(type) { case errors.ContainerError: return nil, errors.NewAssembleError(b.config.Tag, e.Output, e) default: return nil, err } } return &api.Result{ Success: true, }, nil }