Beispiel #1
0
// run is responsible for preparing environment for actual build.
// It accepts factoryFunc and an ordered array of SCMAuths.
func run(builderFactory factoryFunc, scmAuths []scmauth.SCMAuth) {
	client, endpoint, err := dockerutil.NewHelper().GetClient()
	if err != nil {
		glog.Fatalf("Error obtaining docker client: %v", err)
	}
	buildStr := os.Getenv("BUILD")
	build := api.Build{}
	if err := latest.Codec.DecodeInto([]byte(buildStr), &build); err != nil {
		glog.Fatalf("Unable to parse build: %v", err)
	}
	var (
		authcfg     docker.AuthConfiguration
		authPresent bool
	)
	output := build.Spec.Output.To != nil && len(build.Spec.Output.To.Name) != 0
	if output {
		authcfg, authPresent = dockercfg.NewHelper().GetDockerAuth(
			build.Spec.Output.To.Name,
			dockercfg.PullAuthType,
		)
	}
	if build.Spec.Source.SourceSecret != nil {
		if err := setupSourceSecret(build.Spec.Source.SourceSecret.Name, scmAuths); err != nil {
			glog.Fatalf("Cannot setup secret file for accessing private repository: %v", err)
		}
	}
	b := builderFactory(client, endpoint, authcfg, authPresent, &build)
	if err = b.Build(); err != nil {
		glog.Fatalf("Build error: %v", err)
	}
	if !output {
		glog.Warning("Build does not have an Output defined, no output image was pushed to a registry.")
	}

}
Beispiel #2
0
// Build executes a Docker build
func (d *DockerBuilder) Build() error {
	var push bool

	buildDir, err := ioutil.TempDir("", "docker-build")
	if err != nil {
		return err
	}
	sourceInfo, err := fetchSource(d.dockerClient, buildDir, d.build, d.urlTimeout, os.Stdin, d.gitClient)
	if err != nil {
		return err
	}
	if sourceInfo != nil {
		updateBuildRevision(d.client, d.build, sourceInfo)
	}
	if err := d.addBuildParameters(buildDir); err != nil {
		return err
	}

	glog.V(4).Infof("Starting Docker build from build config %s ...", d.build.Name)
	// if there is no output target, set one up so the docker build logic
	// (which requires a tag) will still work, but we won't push it at the end.
	if d.build.Spec.Output.To == nil || len(d.build.Spec.Output.To.Name) == 0 {
		d.build.Status.OutputDockerImageReference = d.build.Name
	} else {
		push = true
	}

	if err := d.dockerBuild(buildDir, d.build.Spec.Source.Secrets); err != nil {
		return err
	}

	defer removeImage(d.dockerClient, d.build.Status.OutputDockerImageReference)

	if push {
		// Get the Docker push authentication
		pushAuthConfig, authPresent := dockercfg.NewHelper().GetDockerAuth(
			d.build.Status.OutputDockerImageReference,
			dockercfg.PushAuthType,
		)
		if authPresent {
			glog.V(4).Infof("Authenticating Docker push with user %q", pushAuthConfig.Username)
		}
		glog.Infof("Pushing image %s ...", d.build.Status.OutputDockerImageReference)
		if err := pushImage(d.dockerClient, d.build.Status.OutputDockerImageReference, pushAuthConfig); err != nil {
			return fmt.Errorf("Failed to push image: %v", err)
		}
		glog.Infof("Push successful")
	}
	return nil
}
Beispiel #3
0
// Build executes a Docker build
func (d *DockerBuilder) Build() error {
	buildDir, err := ioutil.TempDir("", "docker-build")
	if err != nil {
		return err
	}
	if err = d.fetchSource(buildDir); err != nil {
		return err
	}
	if err = d.addBuildParameters(buildDir); err != nil {
		return err
	}
	glog.V(4).Infof("Starting Docker build from %s/%s BuildConfig ...", d.build.Namespace, d.build.Name)
	var push bool

	// if there is no output target, set one up so the docker build logic
	// will still work, but we won't push it at the end.
	if d.build.Spec.Output.To == nil || len(d.build.Spec.Output.To.Name) == 0 {
		d.build.Spec.Output.To = &kapi.ObjectReference{
			Kind: "DockerImage",
			Name: noOutputDefaultTag,
		}
		push = false
	} else {
		push = true
	}

	if err = d.dockerBuild(buildDir); err != nil {
		return err
	}

	defer removeImage(d.dockerClient, d.build.Spec.Output.To.Name)

	if push {
		// Get the Docker push authentication
		pushAuthConfig, authPresent := dockercfg.NewHelper().GetDockerAuth(
			d.build.Spec.Output.To.Name,
			dockercfg.PushAuthType,
		)
		if authPresent {
			glog.V(3).Infof("Using Docker authentication provided")
			d.auth = pushAuthConfig
		}
		glog.Infof("Pushing %s image ...", d.build.Spec.Output.To.Name)
		if err := pushImage(d.dockerClient, d.build.Spec.Output.To.Name, d.auth); err != nil {
			return fmt.Errorf("Failed to push image: %v", err)
		}
		glog.Infof("Successfully pushed %s", d.build.Spec.Output.To.Name)
	}
	return nil
}
Beispiel #4
0
// Build executes a Docker build
func (d *DockerBuilder) Build() error {
	buildDir, err := ioutil.TempDir("", "docker-build")
	if err != nil {
		return err
	}
	if err := fetchSource(buildDir, d.build, d.urlTimeout, os.Stdin, d.git); err != nil {
		return err
	}
	if err := d.addBuildParameters(buildDir); err != nil {
		return err
	}
	glog.V(4).Infof("Starting Docker build from build config %s ...", d.build.Name)
	var push bool

	// if there is no output target, set one up so the docker build logic
	// will still work, but we won't push it at the end.
	if d.build.Spec.Output.To == nil || len(d.build.Spec.Output.To.Name) == 0 {
		d.build.Spec.Output.To = &kapi.ObjectReference{
			Kind: "DockerImage",
			Name: noOutputDefaultTag,
		}
		push = false
	} else {
		push = true
	}

	if err := d.dockerBuild(buildDir); err != nil {
		return err
	}

	defer removeImage(d.dockerClient, d.build.Spec.Output.To.Name)

	if push {
		// Get the Docker push authentication
		pushAuthConfig, authPresent := dockercfg.NewHelper().GetDockerAuth(
			d.build.Spec.Output.To.Name,
			dockercfg.PushAuthType,
		)
		if authPresent {
			glog.V(4).Infof("Authenticating Docker push with user %q", pushAuthConfig.Username)
		}
		glog.Infof("Pushing image %s ...", d.build.Spec.Output.To.Name)
		if err := pushImage(d.dockerClient, d.build.Spec.Output.To.Name, pushAuthConfig); err != nil {
			return fmt.Errorf("Failed to push image: %v", err)
		}
		glog.Infof("Push successful")
	}
	return nil
}
Beispiel #5
0
// Build executes a Docker build
func (d *DockerBuilder) Build() error {
	buildDir, err := ioutil.TempDir("", "docker-build")
	if err != nil {
		return err
	}
	if err = d.fetchSource(buildDir); err != nil {
		return err
	}
	if err = d.addBuildParameters(buildDir); err != nil {
		return err
	}
	glog.V(4).Infof("Starting Docker build from %s/%s BuildConfig ...", d.build.Namespace, d.build.Name)
	if err = d.dockerBuild(buildDir); err != nil {
		return err
	}
	tag := d.build.Parameters.Output.DockerImageReference
	defer removeImage(d.dockerClient, tag)

	dockerImageRef := d.build.Parameters.Output.DockerImageReference
	if len(dockerImageRef) != 0 {
		// Get the Docker push authentication
		pushAuthConfig, authPresent := dockercfg.NewHelper().GetDockerAuth(
			dockerImageRef,
			dockercfg.PushAuthType,
		)
		if authPresent {
			glog.V(3).Infof("Using Docker authentication provided")
			d.auth = pushAuthConfig
		}
		glog.Infof("Pushing %s image ...", dockerImageRef)
		if err := pushImage(d.dockerClient, tag, d.auth); err != nil {
			return fmt.Errorf("Failed to push image: %v", err)
		}
		glog.Infof("Successfully pushed %s", dockerImageRef)
	}
	return nil
}
Beispiel #6
0
func extractSourceFromImage(dockerClient DockerClient, image, buildDir string, paths []api.ImageSourcePath) error {
	glog.V(4).Infof("Extracting image source from %s", image)

	// Pre-pull image if a secret is specified
	pullSecret := os.Getenv(dockercfg.PullSourceAuthType)
	if len(pullSecret) > 0 {
		dockerAuth, present := dockercfg.NewHelper().GetDockerAuth(image, dockercfg.PullSourceAuthType)
		if present {
			dockerClient.PullImage(docker.PullImageOptions{Repository: image}, dockerAuth)
		}
	}

	// Create container to copy from
	container, err := dockerClient.CreateContainer(docker.CreateContainerOptions{
		Config: &docker.Config{
			Image: image,
		},
	})
	if err != nil {
		return fmt.Errorf("error creating source image container: %v", err)
	}
	defer dockerClient.RemoveContainer(docker.RemoveContainerOptions{ID: container.ID})

	tarHelper := tar.New()
	tarHelper.SetExclusionPattern(nil)

	for _, path := range paths {
		glog.V(4).Infof("Extracting path %s from container %s to %s", path.SourcePath, container.ID, path.DestinationDir)
		err := copyImageSource(dockerClient, container.ID, path.SourcePath, filepath.Join(buildDir, path.DestinationDir), tarHelper)
		if err != nil {
			return fmt.Errorf("error copying source path %s to %s: %v", path.SourcePath, path.DestinationDir, err)
		}
	}

	return nil
}
Beispiel #7
0
// Build executes a Docker build
func (d *DockerBuilder) Build() error {
	if d.build.Spec.Source.Git == nil && d.build.Spec.Source.Binary == nil &&
		d.build.Spec.Source.Dockerfile == nil && d.build.Spec.Source.Images == nil {
		return fmt.Errorf("must provide a value for at least one of source, binary, images, or dockerfile")
	}
	var push bool
	pushTag := d.build.Status.OutputDockerImageReference

	buildDir, err := ioutil.TempDir("", "docker-build")
	if err != nil {
		return err
	}
	sourceInfo, err := fetchSource(d.dockerClient, buildDir, d.build, initialURLCheckTimeout, os.Stdin, d.gitClient)
	if err != nil {
		d.build.Status.Reason = api.StatusReasonFetchSourceFailed
		d.build.Status.Message = api.StatusMessageFetchSourceFailed
		if updateErr := retryBuildStatusUpdate(d.build, d.client, nil); updateErr != nil {
			utilruntime.HandleError(fmt.Errorf("error: An error occured while updating the build status: %v", updateErr))
		}
		return err
	}

	if sourceInfo != nil {
		glog.V(4).Infof("Setting build revision with details %#v", sourceInfo)
		revision := updateBuildRevision(d.build, sourceInfo)
		if updateErr := retryBuildStatusUpdate(d.build, d.client, revision); updateErr != nil {
			utilruntime.HandleError(fmt.Errorf("error: An error occured while updating the build status: %v", updateErr))
		}
	}
	if err = d.addBuildParameters(buildDir, sourceInfo); err != nil {
		return err
	}

	glog.V(4).Infof("Starting Docker build from build config %s ...", d.build.Name)
	// if there is no output target, set one up so the docker build logic
	// (which requires a tag) will still work, but we won't push it at the end.
	if d.build.Spec.Output.To == nil || len(d.build.Spec.Output.To.Name) == 0 {
		d.build.Status.OutputDockerImageReference = d.build.Name
	} else {
		push = true
	}

	buildTag := randomBuildTag(d.build.Namespace, d.build.Name)
	dockerfilePath := d.getDockerfilePath(buildDir)
	imageNames := getDockerfileFrom(dockerfilePath)
	if len(imageNames) == 0 {
		return fmt.Errorf("no FROM image in Dockerfile")
	}
	for _, imageName := range imageNames {
		if imageName == "scratch" {
			glog.V(4).Infof("\nSkipping image \"scratch\"")
			continue
		}
		imageExists := true
		_, err = d.dockerClient.InspectImage(imageName)
		if err != nil {
			if err != docker.ErrNoSuchImage {
				return err
			}
			imageExists = false
		}
		// if forcePull or the image not exists on the node we should pull the image first
		if d.build.Spec.Strategy.DockerStrategy.ForcePull || !imageExists {
			pullAuthConfig, _ := dockercfg.NewHelper().GetDockerAuth(
				imageName,
				dockercfg.PullAuthType,
			)
			glog.V(0).Infof("\nPulling image %s ...", imageName)
			if err = pullImage(d.dockerClient, imageName, pullAuthConfig); err != nil {
				d.build.Status.Reason = api.StatusReasonPullBuilderImageFailed
				d.build.Status.Message = api.StatusMessagePullBuilderImageFailed
				if updateErr := retryBuildStatusUpdate(d.build, d.client, nil); updateErr != nil {
					utilruntime.HandleError(fmt.Errorf("error: An error occured while updating the build status: %v", updateErr))
				}
				return fmt.Errorf("failed to pull image: %v", err)
			}
		}
	}

	if err = d.dockerBuild(buildDir, buildTag, d.build.Spec.Source.Secrets); err != nil {
		d.build.Status.Reason = api.StatusReasonDockerBuildFailed
		d.build.Status.Message = api.StatusMessageDockerBuildFailed
		if updateErr := retryBuildStatusUpdate(d.build, d.client, nil); updateErr != nil {
			utilruntime.HandleError(fmt.Errorf("error: An error occured while updating the build status: %v", updateErr))
		}
		return err
	}

	cname := containerName("docker", d.build.Name, d.build.Namespace, "post-commit")
	if err := execPostCommitHook(d.dockerClient, d.build.Spec.PostCommit, buildTag, cname); err != nil {
		d.build.Status.Reason = api.StatusReasonPostCommitHookFailed
		d.build.Status.Message = api.StatusMessagePostCommitHookFailed
		if updateErr := retryBuildStatusUpdate(d.build, d.client, nil); updateErr != nil {
			utilruntime.HandleError(fmt.Errorf("error: An error occured while updating the build status: %v", updateErr))
		}
		return err
	}

	if push {
		if err := tagImage(d.dockerClient, buildTag, pushTag); err != nil {
			return err
		}
	}

	if err := removeImage(d.dockerClient, buildTag); err != nil {
		glog.V(0).Infof("warning: Failed to remove temporary build tag %v: %v", buildTag, err)
	}

	if push {
		// Get the Docker push authentication
		pushAuthConfig, authPresent := dockercfg.NewHelper().GetDockerAuth(
			pushTag,
			dockercfg.PushAuthType,
		)
		if authPresent {
			glog.V(4).Infof("Authenticating Docker push with user %q", pushAuthConfig.Username)
		}
		glog.V(0).Infof("\nPushing image %s ...", pushTag)
		if err := pushImage(d.dockerClient, pushTag, pushAuthConfig); err != nil {
			d.build.Status.Reason = api.StatusReasonPushImageToRegistryFailed
			d.build.Status.Message = api.StatusMessagePushImageToRegistryFailed
			if updateErr := retryBuildStatusUpdate(d.build, d.client, nil); updateErr != nil {
				utilruntime.HandleError(fmt.Errorf("error: An error occured while updating the build status: %v", updateErr))
			}
			return reportPushFailure(err, authPresent, pushAuthConfig)
		}
		glog.V(0).Infof("Push successful")
	}
	return nil
}
Beispiel #8
0
func extractSourceFromImage(dockerClient DockerClient, image, buildDir string, imageSecretIndex int, paths []api.ImageSourcePath, forcePull bool) error {
	glog.V(4).Infof("Extracting image source from %s", image)

	dockerAuth := docker.AuthConfiguration{}
	if imageSecretIndex != -1 {
		pullSecret := os.Getenv(fmt.Sprintf("%s%d", dockercfg.PullSourceAuthType, imageSecretIndex))
		if len(pullSecret) > 0 {
			authPresent := false
			dockerAuth, authPresent = dockercfg.NewHelper().GetDockerAuth(image, fmt.Sprintf("%s%d", dockercfg.PullSourceAuthType, imageSecretIndex))
			if authPresent {
				glog.V(5).Infof("Registry server Address: %s", dockerAuth.ServerAddress)
				glog.V(5).Infof("Registry server User Name: %s", dockerAuth.Username)
				glog.V(5).Infof("Registry server Email: %s", dockerAuth.Email)
				passwordPresent := "<<empty>>"
				if len(dockerAuth.Password) > 0 {
					passwordPresent = "<<non-empty>>"
				}
				glog.V(5).Infof("Registry server Password: %s", passwordPresent)
			}
		}
	}

	exists := true
	if !forcePull {
		_, err := dockerClient.InspectImage(image)
		if err != nil && err == docker.ErrNoSuchImage {
			exists = false
		} else if err != nil {
			return err
		}
	}

	if !exists || forcePull {
		glog.V(0).Infof("Pulling image %q ...", image)
		if err := dockerClient.PullImage(docker.PullImageOptions{Repository: image}, dockerAuth); err != nil {
			return fmt.Errorf("error pulling image %v: %v", image, err)
		}
	}

	containerConfig := &docker.Config{Image: image}
	if inspect, err := dockerClient.InspectImage(image); err != nil {
		return err
	} else {
		// In case the Docker image does not specify the entrypoint
		if len(inspect.Config.Entrypoint) == 0 && len(inspect.Config.Cmd) == 0 {
			containerConfig.Entrypoint = []string{"/fake-entrypoint"}
		}
	}

	// Create container to copy from
	container, err := dockerClient.CreateContainer(docker.CreateContainerOptions{Config: containerConfig})
	if err != nil {
		return fmt.Errorf("error creating source image container: %v", err)
	}
	defer dockerClient.RemoveContainer(docker.RemoveContainerOptions{ID: container.ID})

	tarHelper := tar.New()
	tarHelper.SetExclusionPattern(nil)

	for _, path := range paths {
		glog.V(4).Infof("Extracting path %s from container %s to %s", path.SourcePath, container.ID, path.DestinationDir)
		err := copyImageSource(dockerClient, container.ID, path.SourcePath, filepath.Join(buildDir, path.DestinationDir), tarHelper)
		if err != nil {
			return fmt.Errorf("error copying source path %s to %s: %v", path.SourcePath, path.DestinationDir, err)
		}
	}

	return nil
}
Beispiel #9
0
// executes STI build based on configured builder, S2I builder factory and S2I config validator
func (s *STIBuilder) Build() error {

	var push bool

	// if there is no output target, set one up so the docker build logic
	// (which requires a tag) will still work, but we won't push it at the end.
	if s.build.Spec.Output.To == nil || len(s.build.Spec.Output.To.Name) == 0 {
		s.build.Spec.Output.To = &kapi.ObjectReference{
			Kind: "DockerImage",
			Name: noOutputDefaultTag,
		}
		push = false
	} else {
		push = true
	}
	tag := s.build.Spec.Output.To.Name

	config := &stiapi.Config{
		BuilderImage:   s.build.Spec.Strategy.SourceStrategy.From.Name,
		DockerConfig:   &stiapi.DockerConfig{Endpoint: s.dockerSocket},
		Source:         s.build.Spec.Source.Git.URI,
		ContextDir:     s.build.Spec.Source.ContextDir,
		DockerCfgPath:  os.Getenv(dockercfg.PullAuthType),
		Tag:            tag,
		ScriptsURL:     s.build.Spec.Strategy.SourceStrategy.Scripts,
		Environment:    buildEnvVars(s.build),
		LabelNamespace: api.DefaultDockerLabelNamespace,
		Incremental:    s.build.Spec.Strategy.SourceStrategy.Incremental,
		ForcePull:      s.build.Spec.Strategy.SourceStrategy.ForcePull,
	}
	if s.build.Spec.Revision != nil && s.build.Spec.Revision.Git != nil &&
		s.build.Spec.Revision.Git.Commit != "" {
		config.Ref = s.build.Spec.Revision.Git.Commit
	} else if s.build.Spec.Source.Git.Ref != "" {
		config.Ref = s.build.Spec.Source.Git.Ref
	}

	allowedUIDs := os.Getenv("ALLOWED_UIDS")
	glog.V(2).Infof("The value of ALLOWED_UIDS is [%s]", allowedUIDs)
	if len(allowedUIDs) > 0 {
		err := config.AllowedUIDs.Set(allowedUIDs)
		if err != nil {
			return err
		}
	}

	if errs := s.configValidator.ValidateConfig(config); len(errs) != 0 {
		var buffer bytes.Buffer
		for _, ve := range errs {
			buffer.WriteString(ve.Error())
			buffer.WriteString(", ")
		}
		return errors.New(buffer.String())
	}

	// If DockerCfgPath is provided in api.Config, then attempt to read the the
	// dockercfg file and get the authentication for pulling the builder image.
	config.PullAuthentication, _ = dockercfg.NewHelper().GetDockerAuth(config.BuilderImage, dockercfg.PullAuthType)
	config.IncrementalAuthentication, _ = dockercfg.NewHelper().GetDockerAuth(tag, dockercfg.PushAuthType)

	glog.V(2).Infof("Creating a new S2I builder with build config: %#v\n", describe.DescribeConfig(config))
	builder, err := s.builderFactory.GetStrategy(config)
	if err != nil {
		return err
	}

	glog.V(4).Infof("Starting S2I build from %s/%s BuildConfig ...", s.build.Namespace, s.build.Name)

	// Set the HTTP and HTTPS proxies to be used by the S2I build.
	originalProxies := setHTTPProxy(s.build.Spec.Source.Git.HTTPProxy, s.build.Spec.Source.Git.HTTPSProxy)

	if _, err = builder.Build(config); err != nil {
		return err
	}

	// Reset proxies back to their original value.
	resetHTTPProxy(originalProxies)

	if push {
		// Get the Docker push authentication
		pushAuthConfig, authPresent := dockercfg.NewHelper().GetDockerAuth(
			tag,
			dockercfg.PushAuthType,
		)
		if authPresent {
			glog.Infof("Using provided push secret for pushing %s image", tag)
		} else {
			glog.Infof("No push secret provided")
		}
		glog.Infof("Pushing %s image ...", tag)
		if err := pushImage(s.dockerClient, tag, pushAuthConfig); err != nil {
			// write extended error message to assist in problem resolution
			msg := fmt.Sprintf("Failed to push image. Response from registry is: %v", err)
			if authPresent {
				glog.Infof("Registry server Address: %s", pushAuthConfig.ServerAddress)
				glog.Infof("Registry server User Name: %s", pushAuthConfig.Username)
				glog.Infof("Registry server Email: %s", pushAuthConfig.Email)
				passwordPresent := "<<empty>>"
				if len(pushAuthConfig.Password) > 0 {
					passwordPresent = "<<non-empty>>"
				}
				glog.Infof("Registry server address: %s", passwordPresent)
			}
			return errors.New(msg)
		}
		glog.Infof("Successfully pushed %s", tag)
		glog.Flush()
	}
	return nil
}
Beispiel #10
0
// Build executes STI build based on configured builder, S2I builder factory and S2I config validator
func (s *STIBuilder) Build() error {
	var push bool

	contextDir := filepath.Clean(s.build.Spec.Source.ContextDir)
	if contextDir == "." || contextDir == "/" {
		contextDir = ""
	}
	buildDir, err := ioutil.TempDir("", "s2i-build")
	if err != nil {
		return err
	}
	srcDir := filepath.Join(buildDir, s2iapi.Source)
	if err := os.MkdirAll(srcDir, os.ModePerm); err != nil {
		return err
	}
	tmpDir := filepath.Join(buildDir, "tmp")
	if err := os.MkdirAll(tmpDir, os.ModePerm); err != nil {
		return err
	}

	download := &downloader{
		s:       s,
		in:      os.Stdin,
		timeout: urlCheckTimeout,

		dir:        srcDir,
		contextDir: contextDir,
		tmpDir:     tmpDir,
	}

	// if there is no output target, set one up so the docker build logic
	// (which requires a tag) will still work, but we won't push it at the end.
	if s.build.Spec.Output.To == nil || len(s.build.Spec.Output.To.Name) == 0 {
		s.build.Spec.Output.To = &kapi.ObjectReference{
			Kind: "DockerImage",
			Name: noOutputDefaultTag,
		}
		push = false
	} else {
		push = true
	}

	tag := s.build.Spec.Output.To.Name
	git := s.build.Spec.Source.Git

	var ref string
	if s.build.Spec.Revision != nil && s.build.Spec.Revision.Git != nil &&
		len(s.build.Spec.Revision.Git.Commit) != 0 {
		ref = s.build.Spec.Revision.Git.Commit
	} else if git != nil && len(git.Ref) != 0 {
		ref = git.Ref
	}

	sourceURI := &url.URL{
		Scheme:   "file",
		Path:     srcDir,
		Fragment: ref,
	}

	config := &s2iapi.Config{
		WorkingDir:     buildDir,
		DockerConfig:   &s2iapi.DockerConfig{Endpoint: s.dockerSocket},
		DockerCfgPath:  os.Getenv(dockercfg.PullAuthType),
		LabelNamespace: api.DefaultDockerLabelNamespace,

		ScriptsURL: s.build.Spec.Strategy.SourceStrategy.Scripts,

		BuilderImage: s.build.Spec.Strategy.SourceStrategy.From.Name,
		Incremental:  s.build.Spec.Strategy.SourceStrategy.Incremental,
		ForcePull:    s.build.Spec.Strategy.SourceStrategy.ForcePull,

		Environment:       buildEnvVars(s.build),
		DockerNetworkMode: getDockerNetworkMode(),

		Source:     sourceURI.String(),
		Tag:        tag,
		ContextDir: s.build.Spec.Source.ContextDir,
	}

	allowedUIDs := os.Getenv("ALLOWED_UIDS")
	glog.V(2).Infof("The value of ALLOWED_UIDS is [%s]", allowedUIDs)
	if len(allowedUIDs) > 0 {
		err := config.AllowedUIDs.Set(allowedUIDs)
		if err != nil {
			return err
		}
	}

	if errs := s.validator.ValidateConfig(config); len(errs) != 0 {
		var buffer bytes.Buffer
		for _, ve := range errs {
			buffer.WriteString(ve.Error())
			buffer.WriteString(", ")
		}
		return errors.New(buffer.String())
	}

	// If DockerCfgPath is provided in api.Config, then attempt to read the the
	// dockercfg file and get the authentication for pulling the builder image.
	config.PullAuthentication, _ = dockercfg.NewHelper().GetDockerAuth(config.BuilderImage, dockercfg.PullAuthType)
	config.IncrementalAuthentication, _ = dockercfg.NewHelper().GetDockerAuth(tag, dockercfg.PushAuthType)

	glog.V(2).Infof("Creating a new S2I builder with build config: %#v\n", describe.DescribeConfig(config))
	builder, err := s.builder.Builder(config, s2ibuild.Overrides{Downloader: download})
	if err != nil {
		return err
	}

	glog.V(4).Infof("Starting S2I build from %s/%s BuildConfig ...", s.build.Namespace, s.build.Name)

	// Set the HTTP and HTTPS proxies to be used by the S2I build.
	var originalProxies map[string]string
	if git != nil {
		originalProxies = setHTTPProxy(git.HTTPProxy, git.HTTPSProxy)
	}

	if _, err = builder.Build(config); err != nil {
		return err
	}

	// Reset proxies back to their original value.
	resetHTTPProxy(originalProxies)

	if push {
		// Get the Docker push authentication
		pushAuthConfig, authPresent := dockercfg.NewHelper().GetDockerAuth(
			tag,
			dockercfg.PushAuthType,
		)
		if authPresent {
			glog.Infof("Using provided push secret for pushing %s image", tag)
		} else {
			glog.Infof("No push secret provided")
		}
		glog.Infof("Pushing %s image ...", tag)
		if err := pushImage(s.dockerClient, tag, pushAuthConfig); err != nil {
			// write extended error message to assist in problem resolution
			msg := fmt.Sprintf("Failed to push image. Response from registry is: %v", err)
			if authPresent {
				glog.Infof("Registry server Address: %s", pushAuthConfig.ServerAddress)
				glog.Infof("Registry server User Name: %s", pushAuthConfig.Username)
				glog.Infof("Registry server Email: %s", pushAuthConfig.Email)
				passwordPresent := "<<empty>>"
				if len(pushAuthConfig.Password) > 0 {
					passwordPresent = "<<non-empty>>"
				}
				glog.Infof("Registry server Password: %s", passwordPresent)
			}
			return errors.New(msg)
		}
		glog.Infof("Successfully pushed %s", tag)
		glog.Flush()
	}
	return nil
}
Beispiel #11
0
// Build executes STI build based on configured builder, S2I builder factory
// and S2I config validator
func (s *S2IBuilder) Build() error {
	if s.build.Spec.Strategy.SourceStrategy == nil {
		return errors.New("the source to image builder must be used with the source strategy")
	}

	contextDir := filepath.Clean(s.build.Spec.Source.ContextDir)
	if contextDir == "." || contextDir == "/" {
		contextDir = ""
	}
	buildDir, err := ioutil.TempDir("", "s2i-build")
	if err != nil {
		return err
	}
	srcDir := filepath.Join(buildDir, s2iapi.Source)
	if err = os.MkdirAll(srcDir, os.ModePerm); err != nil {
		return err
	}
	tmpDir := filepath.Join(buildDir, "tmp")
	if err = os.MkdirAll(tmpDir, os.ModePerm); err != nil {
		return err
	}

	download := &downloader{
		s:       s,
		in:      os.Stdin,
		timeout: initialURLCheckTimeout,

		dir:        srcDir,
		contextDir: contextDir,
		tmpDir:     tmpDir,
	}

	var push bool
	// if there is no output target, set one up so the docker build logic
	// (which requires a tag) will still work, but we won't push it at the end.
	if s.build.Spec.Output.To == nil || len(s.build.Spec.Output.To.Name) == 0 {
		s.build.Status.OutputDockerImageReference = s.build.Name
	} else {
		push = true
	}
	pushTag := s.build.Status.OutputDockerImageReference
	git := s.build.Spec.Source.Git

	var ref string
	if s.build.Spec.Revision != nil && s.build.Spec.Revision.Git != nil &&
		len(s.build.Spec.Revision.Git.Commit) != 0 {
		ref = s.build.Spec.Revision.Git.Commit
	} else if git != nil && len(git.Ref) != 0 {
		ref = git.Ref
	}

	sourceURI := &url.URL{
		Scheme:   "file",
		Path:     srcDir,
		Fragment: ref,
	}

	injections := s2iapi.VolumeList{}
	for _, s := range s.build.Spec.Source.Secrets {
		glog.V(3).Infof("Injecting secret %q into a build into %q", s.Secret.Name, filepath.Clean(s.DestinationDir))
		secretSourcePath := filepath.Join(strategy.SecretBuildSourceBaseMountPath, s.Secret.Name)
		injections = append(injections, s2iapi.VolumeSpec{
			Source:      secretSourcePath,
			Destination: s.DestinationDir,
		})
	}

	buildTag := randomBuildTag(s.build.Namespace, s.build.Name)
	scriptDownloadProxyConfig, err := scriptProxyConfig(s.build)
	if err != nil {
		return err
	}
	if scriptDownloadProxyConfig != nil {
		glog.V(0).Infof("Using HTTP proxy %v and HTTPS proxy %v for script download",
			scriptDownloadProxyConfig.HTTPProxy,
			scriptDownloadProxyConfig.HTTPSProxy)
	}

	var incremental bool
	if s.build.Spec.Strategy.SourceStrategy.Incremental != nil {
		incremental = *s.build.Spec.Strategy.SourceStrategy.Incremental
	}
	config := &s2iapi.Config{
		WorkingDir:     buildDir,
		DockerConfig:   &s2iapi.DockerConfig{Endpoint: s.dockerSocket},
		DockerCfgPath:  os.Getenv(dockercfg.PullAuthType),
		LabelNamespace: api.DefaultDockerLabelNamespace,

		ScriptsURL: s.build.Spec.Strategy.SourceStrategy.Scripts,

		BuilderImage:       s.build.Spec.Strategy.SourceStrategy.From.Name,
		Incremental:        incremental,
		IncrementalFromTag: pushTag,

		Environment:       buildEnvVars(s.build),
		Labels:            buildLabels(s.build),
		DockerNetworkMode: getDockerNetworkMode(),

		Source:                    sourceURI.String(),
		Tag:                       buildTag,
		ContextDir:                s.build.Spec.Source.ContextDir,
		CGroupLimits:              s.cgLimits,
		Injections:                injections,
		ScriptDownloadProxyConfig: scriptDownloadProxyConfig,
		BlockOnBuild:              true,
	}

	if s.build.Spec.Strategy.SourceStrategy.ForcePull {
		glog.V(4).Infof("With force pull true, setting policies to %s", s2iapi.PullAlways)
		config.BuilderPullPolicy = s2iapi.PullAlways
		config.RuntimeImagePullPolicy = s2iapi.PullAlways
	} else {
		glog.V(4).Infof("With force pull false, setting policies to %s", s2iapi.PullIfNotPresent)
		config.BuilderPullPolicy = s2iapi.PullIfNotPresent
		config.RuntimeImagePullPolicy = s2iapi.PullIfNotPresent
	}
	config.PreviousImagePullPolicy = s2iapi.PullAlways

	allowedUIDs := os.Getenv(api.AllowedUIDs)
	glog.V(4).Infof("The value of %s is [%s]", api.AllowedUIDs, allowedUIDs)
	if len(allowedUIDs) > 0 {
		err = config.AllowedUIDs.Set(allowedUIDs)
		if err != nil {
			return err
		}
	}
	dropCaps := os.Getenv(api.DropCapabilities)
	glog.V(4).Infof("The value of %s is [%s]", api.DropCapabilities, dropCaps)
	if len(dropCaps) > 0 {
		config.DropCapabilities = strings.Split(dropCaps, ",")
	}

	if s.build.Spec.Strategy.SourceStrategy.RuntimeImage != nil {
		runtimeImageName := s.build.Spec.Strategy.SourceStrategy.RuntimeImage.Name
		config.RuntimeImage = runtimeImageName
		t, _ := dockercfg.NewHelper().GetDockerAuth(runtimeImageName, dockercfg.PullAuthType)
		config.RuntimeAuthentication = s2iapi.AuthConfig{Username: t.Username, Password: t.Password, Email: t.Email, ServerAddress: t.ServerAddress}
		config.RuntimeArtifacts = copyToVolumeList(s.build.Spec.Strategy.SourceStrategy.RuntimeArtifacts)
	}
	// If DockerCfgPath is provided in api.Config, then attempt to read the
	// dockercfg file and get the authentication for pulling the builder image.
	t, _ := dockercfg.NewHelper().GetDockerAuth(config.BuilderImage, dockercfg.PullAuthType)
	config.PullAuthentication = s2iapi.AuthConfig{Username: t.Username, Password: t.Password, Email: t.Email, ServerAddress: t.ServerAddress}
	t, _ = dockercfg.NewHelper().GetDockerAuth(pushTag, dockercfg.PushAuthType)
	config.IncrementalAuthentication = s2iapi.AuthConfig{Username: t.Username, Password: t.Password, Email: t.Email, ServerAddress: t.ServerAddress}

	if errs := s.validator.ValidateConfig(config); len(errs) != 0 {
		var buffer bytes.Buffer
		for _, ve := range errs {
			buffer.WriteString(ve.Error())
			buffer.WriteString(", ")
		}
		return errors.New(buffer.String())
	}

	glog.V(4).Infof("Creating a new S2I builder with build config: %#v\n", describe.Config(config))
	builder, buildInfo, err := s.builder.Builder(config, s2ibuild.Overrides{Downloader: download})
	if err != nil {
		s.build.Status.Reason, s.build.Status.Message = convertS2IFailureType(buildInfo.FailureReason.Reason, buildInfo.FailureReason.Message)
		if updateErr := retryBuildStatusUpdate(s.build, s.client, nil); updateErr != nil {
			utilruntime.HandleError(fmt.Errorf("error: An error occured while updating the build status: %v", updateErr))
		}
		return err
	}

	glog.V(4).Infof("Starting S2I build from %s/%s BuildConfig ...", s.build.Namespace, s.build.Name)
	result, err := builder.Build(config)
	if err != nil {
		s.build.Status.Reason, s.build.Status.Message = convertS2IFailureType(result.BuildInfo.FailureReason.Reason, result.BuildInfo.FailureReason.Message)

		if updateErr := retryBuildStatusUpdate(s.build, s.client, nil); updateErr != nil {
			utilruntime.HandleError(fmt.Errorf("error: An error occured while updating the build status: %v", updateErr))
		}
		return err
	}

	cName := containerName("s2i", s.build.Name, s.build.Namespace, "post-commit")
	if err = execPostCommitHook(s.dockerClient, s.build.Spec.PostCommit, buildTag, cName); err != nil {
		s.build.Status.Reason = api.StatusReasonPostCommitHookFailed
		s.build.Status.Message = api.StatusMessagePostCommitHookFailed
		if updateErr := retryBuildStatusUpdate(s.build, s.client, nil); updateErr != nil {
			utilruntime.HandleError(fmt.Errorf("error: An error occured while updating the build status: %v", updateErr))
		}
		return err
	}

	if push {
		if err = tagImage(s.dockerClient, buildTag, pushTag); err != nil {
			return err
		}
	}

	if err = removeImage(s.dockerClient, buildTag); err != nil {
		glog.V(0).Infof("warning: Failed to remove temporary build tag %v: %v", buildTag, err)
	}

	if push {
		// Get the Docker push authentication
		pushAuthConfig, authPresent := dockercfg.NewHelper().GetDockerAuth(
			pushTag,
			dockercfg.PushAuthType,
		)
		if authPresent {
			glog.V(3).Infof("Using provided push secret for pushing %s image", pushTag)
		} else {
			glog.V(3).Infof("No push secret provided")
		}
		glog.V(0).Infof("\nPushing image %s ...", pushTag)
		if err = pushImage(s.dockerClient, pushTag, pushAuthConfig); err != nil {
			s.build.Status.Reason = api.StatusReasonPushImageToRegistryFailed
			s.build.Status.Message = api.StatusMessagePushImageToRegistryFailed
			if updateErr := retryBuildStatusUpdate(s.build, s.client, nil); updateErr != nil {
				utilruntime.HandleError(fmt.Errorf("error: An error occured while updating the build status: %v", updateErr))
			}
			return reportPushFailure(err, authPresent, pushAuthConfig)
		}
		glog.V(0).Infof("Push successful")
	}
	return nil
}
Beispiel #12
0
// Build executes STI build based on configured builder, S2I builder factory and S2I config validator
func (s *S2IBuilder) Build() error {
	var push bool

	contextDir := filepath.Clean(s.build.Spec.Source.ContextDir)
	if contextDir == "." || contextDir == "/" {
		contextDir = ""
	}
	buildDir, err := ioutil.TempDir("", "s2i-build")
	if err != nil {
		return err
	}
	srcDir := filepath.Join(buildDir, s2iapi.Source)
	if err := os.MkdirAll(srcDir, os.ModePerm); err != nil {
		return err
	}
	tmpDir := filepath.Join(buildDir, "tmp")
	if err := os.MkdirAll(tmpDir, os.ModePerm); err != nil {
		return err
	}

	download := &downloader{
		s:       s,
		in:      os.Stdin,
		timeout: urlCheckTimeout,

		dir:        srcDir,
		contextDir: contextDir,
		tmpDir:     tmpDir,
	}
	// if there is no output target, set one up so the docker build logic
	// (which requires a tag) will still work, but we won't push it at the end.
	if s.build.Spec.Output.To == nil || len(s.build.Spec.Output.To.Name) == 0 {
		s.build.Status.OutputDockerImageReference = s.build.Name
	} else {
		push = true
	}
	pushTag := s.build.Status.OutputDockerImageReference
	git := s.build.Spec.Source.Git

	var ref string
	if s.build.Spec.Revision != nil && s.build.Spec.Revision.Git != nil &&
		len(s.build.Spec.Revision.Git.Commit) != 0 {
		ref = s.build.Spec.Revision.Git.Commit
	} else if git != nil && len(git.Ref) != 0 {
		ref = git.Ref
	}

	sourceURI := &url.URL{
		Scheme:   "file",
		Path:     srcDir,
		Fragment: ref,
	}

	injections := s2iapi.InjectionList{}
	for _, s := range s.build.Spec.Source.Secrets {
		glog.V(3).Infof("Injecting secret %q into a build into %q", s.Secret.Name, filepath.Clean(s.DestinationDir))
		secretSourcePath := filepath.Join(strategy.SecretBuildSourceBaseMountPath, s.Secret.Name)
		injections = append(injections, s2iapi.InjectPath{
			SourcePath:     secretSourcePath,
			DestinationDir: s.DestinationDir,
		})
	}

	buildTag := randomBuildTag(s.build.Namespace, s.build.Name)

	config := &s2iapi.Config{
		WorkingDir:     buildDir,
		DockerConfig:   &s2iapi.DockerConfig{Endpoint: s.dockerSocket},
		DockerCfgPath:  os.Getenv(dockercfg.PullAuthType),
		LabelNamespace: api.DefaultDockerLabelNamespace,

		ScriptsURL: s.build.Spec.Strategy.SourceStrategy.Scripts,

		BuilderImage: s.build.Spec.Strategy.SourceStrategy.From.Name,
		Incremental:  s.build.Spec.Strategy.SourceStrategy.Incremental,

		Environment:       buildEnvVars(s.build),
		DockerNetworkMode: getDockerNetworkMode(),

		Source:       sourceURI.String(),
		Tag:          buildTag,
		ContextDir:   s.build.Spec.Source.ContextDir,
		CGroupLimits: s.cgLimits,
		Injections:   injections,
	}

	if s.build.Spec.Strategy.SourceStrategy.ForcePull {
		glog.V(4).Infof("With force pull true, setting policies to %s", s2iapi.PullAlways)
		config.PreviousImagePullPolicy = s2iapi.PullAlways
		config.BuilderPullPolicy = s2iapi.PullAlways
	} else {
		glog.V(4).Infof("With force pull false, setting policies to %s", s2iapi.PullIfNotPresent)
		config.PreviousImagePullPolicy = s2iapi.PullIfNotPresent
		config.BuilderPullPolicy = s2iapi.PullIfNotPresent
	}

	allowedUIDs := os.Getenv("ALLOWED_UIDS")
	glog.V(2).Infof("The value of ALLOWED_UIDS is [%s]", allowedUIDs)
	if len(allowedUIDs) > 0 {
		err := config.AllowedUIDs.Set(allowedUIDs)
		if err != nil {
			return err
		}
	}

	if errs := s.validator.ValidateConfig(config); len(errs) != 0 {
		var buffer bytes.Buffer
		for _, ve := range errs {
			buffer.WriteString(ve.Error())
			buffer.WriteString(", ")
		}
		return errors.New(buffer.String())
	}

	// If DockerCfgPath is provided in api.Config, then attempt to read the the
	// dockercfg file and get the authentication for pulling the builder image.
	config.PullAuthentication, _ = dockercfg.NewHelper().GetDockerAuth(config.BuilderImage, dockercfg.PullAuthType)
	config.IncrementalAuthentication, _ = dockercfg.NewHelper().GetDockerAuth(pushTag, dockercfg.PushAuthType)

	glog.V(2).Infof("Creating a new S2I builder with build config: %#v\n", describe.DescribeConfig(config))
	builder, err := s.builder.Builder(config, s2ibuild.Overrides{Downloader: download})
	if err != nil {
		return err
	}

	glog.V(4).Infof("Starting S2I build from %s/%s BuildConfig ...", s.build.Namespace, s.build.Name)

	if _, err = builder.Build(config); err != nil {
		return err
	}

	cname := containerName("s2i", s.build.Name, s.build.Namespace, "post-commit")
	if err := execPostCommitHook(s.dockerClient, s.build.Spec.PostCommit, buildTag, cname); err != nil {
		return err
	}

	if push {
		if err := tagImage(s.dockerClient, buildTag, pushTag); err != nil {
			return err
		}
	}

	if err := removeImage(s.dockerClient, buildTag); err != nil {
		glog.Warningf("Failed to remove temporary build tag %v: %v", buildTag, err)
	}

	if push {
		// Get the Docker push authentication
		pushAuthConfig, authPresent := dockercfg.NewHelper().GetDockerAuth(
			pushTag,
			dockercfg.PushAuthType,
		)
		if authPresent {
			glog.Infof("Using provided push secret for pushing %s image", pushTag)
		} else {
			glog.Infof("No push secret provided")
		}
		glog.Infof("Pushing %s image ...", pushTag)
		if err := pushImage(s.dockerClient, pushTag, pushAuthConfig); err != nil {
			// write extended error message to assist in problem resolution
			msg := fmt.Sprintf("Failed to push image. Response from registry is: %v", err)
			if authPresent {
				glog.Infof("Registry server Address: %s", pushAuthConfig.ServerAddress)
				glog.Infof("Registry server User Name: %s", pushAuthConfig.Username)
				glog.Infof("Registry server Email: %s", pushAuthConfig.Email)
				passwordPresent := "<<empty>>"
				if len(pushAuthConfig.Password) > 0 {
					passwordPresent = "<<non-empty>>"
				}
				glog.Infof("Registry server Password: %s", passwordPresent)
			}
			return errors.New(msg)
		}
		glog.Infof("Successfully pushed %s", pushTag)
		glog.Flush()
	}
	return nil
}
Beispiel #13
0
// Build executes the STI build
func (s *STIBuilder) Build() error {
	tag := s.build.Parameters.Output.DockerImageReference
	config := &stiapi.Config{
		BuilderImage:  s.build.Parameters.Strategy.SourceStrategy.From.Name,
		DockerConfig:  &stiapi.DockerConfig{Endpoint: s.dockerSocket},
		Source:        s.build.Parameters.Source.Git.URI,
		ContextDir:    s.build.Parameters.Source.ContextDir,
		DockerCfgPath: os.Getenv(dockercfg.PullAuthType),
		Tag:           tag,
		ScriptsURL:    s.build.Parameters.Strategy.SourceStrategy.Scripts,
		Environment:   getBuildEnvVars(s.build),
		Incremental:   s.build.Parameters.Strategy.SourceStrategy.Incremental,
	}

	if s.build.Parameters.Revision != nil && s.build.Parameters.Revision.Git != nil &&
		s.build.Parameters.Revision.Git.Commit != "" {
		config.Ref = s.build.Parameters.Revision.Git.Commit
	} else if s.build.Parameters.Source.Git.Ref != "" {
		config.Ref = s.build.Parameters.Source.Git.Ref
	}

	if errs := validation.ValidateConfig(config); len(errs) != 0 {
		var buffer bytes.Buffer
		for _, ve := range errs {
			buffer.WriteString(ve.Error())
			buffer.WriteString(", ")
		}
		return errors.New(buffer.String())
	}

	// If DockerCfgPath is provided in api.Config, then attempt to read the the
	// dockercfg file and get the authentication for pulling the builder image.
	if r, err := os.Open(config.DockerCfgPath); err == nil {
		config.PullAuthentication = stidocker.GetImageRegistryAuth(r, config.BuilderImage)
		glog.Infof("Using provided pull secret for pulling %s image", config.BuilderImage)
	}
	glog.V(2).Infof("Creating a new S2I builder with build config: %#v\n", describe.DescribeConfig(config))
	builder, err := sti.GetStrategy(config)
	if err != nil {
		return err
	}
	defer removeImage(s.dockerClient, tag)
	glog.V(4).Infof("Starting S2I build from %s/%s BuildConfig ...", s.build.Namespace, s.build.Name)
	if _, err = builder.Build(config); err != nil {
		return err
	}
	dockerImageRef := s.build.Parameters.Output.DockerImageReference
	if len(dockerImageRef) != 0 {
		// Get the Docker push authentication
		pushAuthConfig, authPresent := dockercfg.NewHelper().GetDockerAuth(
			dockerImageRef,
			dockercfg.PushAuthType,
		)
		if authPresent {
			glog.Infof("Using provided push secret for pushing %s image", dockerImageRef)
			s.auth = pushAuthConfig
		}
		glog.Infof("Pushing %s image ...", dockerImageRef)
		if err := pushImage(s.dockerClient, tag, s.auth); err != nil {
			return fmt.Errorf("Failed to push image: %v", err)
		}
		glog.Infof("Successfully pushed %s", dockerImageRef)
		glog.Flush()
	}
	return nil
}
Beispiel #14
0
// Build executes the STI build
func (s *STIBuilder) Build() error {
	var push bool

	// if there is no output target, set one up so the docker build logic
	// will still work, but we won't push it at the end.
	if s.build.Spec.Output.To == nil || len(s.build.Spec.Output.To.Name) == 0 {
		s.build.Spec.Output.To = &kapi.ObjectReference{
			Kind: "DockerImage",
			Name: noOutputDefaultTag,
		}
		push = false
	} else {
		push = true
	}
	tag := s.build.Spec.Output.To.Name

	config := &stiapi.Config{
		BuilderImage:  s.build.Spec.Strategy.SourceStrategy.From.Name,
		DockerConfig:  &stiapi.DockerConfig{Endpoint: s.dockerSocket},
		Source:        s.build.Spec.Source.Git.URI,
		ContextDir:    s.build.Spec.Source.ContextDir,
		DockerCfgPath: os.Getenv(dockercfg.PullAuthType),
		Tag:           tag,
		ScriptsURL:    s.build.Spec.Strategy.SourceStrategy.Scripts,
		Environment:   getBuildEnvVars(s.build),
		Incremental:   s.build.Spec.Strategy.SourceStrategy.Incremental,
		ForcePull:     s.build.Spec.Strategy.SourceStrategy.ForcePull,
	}
	if s.build.Spec.Revision != nil && s.build.Spec.Revision.Git != nil &&
		s.build.Spec.Revision.Git.Commit != "" {
		config.Ref = s.build.Spec.Revision.Git.Commit
	} else if s.build.Spec.Source.Git.Ref != "" {
		config.Ref = s.build.Spec.Source.Git.Ref
	}

	if errs := validation.ValidateConfig(config); len(errs) != 0 {
		var buffer bytes.Buffer
		for _, ve := range errs {
			buffer.WriteString(ve.Error())
			buffer.WriteString(", ")
		}
		return errors.New(buffer.String())
	}

	// If DockerCfgPath is provided in api.Config, then attempt to read the the
	// dockercfg file and get the authentication for pulling the builder image.
	if r, err := os.Open(config.DockerCfgPath); err == nil {
		config.PullAuthentication = stidocker.GetImageRegistryAuth(r, config.BuilderImage)
		glog.Infof("Using provided pull secret for pulling %s image", config.BuilderImage)
	}
	glog.V(2).Infof("Creating a new S2I builder with build config: %#v\n", describe.DescribeConfig(config))
	builder, err := sti.GetStrategy(config)
	if err != nil {
		return err
	}

	glog.V(4).Infof("Starting S2I build from %s/%s BuildConfig ...", s.build.Namespace, s.build.Name)

	origProxy := make(map[string]string)
	var setHttp, setHttps bool
	// set the http proxy to be used by the git clone performed by S2I
	if len(s.build.Spec.Source.Git.HTTPSProxy) != 0 {
		glog.V(2).Infof("Setting https proxy variables for Git to %s", s.build.Spec.Source.Git.HTTPSProxy)
		origProxy["HTTPS_PROXY"] = os.Getenv("HTTPS_PROXY")
		origProxy["https_proxy"] = os.Getenv("https_proxy")
		os.Setenv("HTTPS_PROXY", s.build.Spec.Source.Git.HTTPSProxy)
		os.Setenv("https_proxy", s.build.Spec.Source.Git.HTTPSProxy)
		setHttps = true
	}
	if len(s.build.Spec.Source.Git.HTTPProxy) != 0 {
		glog.V(2).Infof("Setting http proxy variables for Git to %s", s.build.Spec.Source.Git.HTTPSProxy)
		origProxy["HTTP_PROXY"] = os.Getenv("HTTP_PROXY")
		origProxy["http_proxy"] = os.Getenv("http_proxy")
		os.Setenv("HTTP_PROXY", s.build.Spec.Source.Git.HTTPProxy)
		os.Setenv("http_proxy", s.build.Spec.Source.Git.HTTPProxy)
		setHttp = true
	}

	if _, err = builder.Build(config); err != nil {
		return err
	}

	// reset http proxy env variables to original value
	if setHttps {
		glog.V(4).Infof("Resetting HTTPS_PROXY variable for Git to %s", origProxy["HTTPS_PROXY"])
		os.Setenv("HTTPS_PROXY", origProxy["HTTPS_PROXY"])
		glog.V(4).Infof("Resetting https_proxy variable for Git to %s", origProxy["https_proxy"])
		os.Setenv("https_proxy", origProxy["https_proxy"])
	}
	if setHttp {
		glog.V(4).Infof("Resetting HTTP_PROXY variable for Git to %s", origProxy["HTTP_PROXY"])
		os.Setenv("HTTP_PROXY", origProxy["HTTP_PROXY"])
		glog.V(4).Infof("Resetting http_proxy variable for Git to %s", origProxy["http_proxy"])
		os.Setenv("http_proxy", origProxy["http_proxy"])
	}

	if push {
		// Get the Docker push authentication
		pushAuthConfig, authPresent := dockercfg.NewHelper().GetDockerAuth(
			tag,
			dockercfg.PushAuthType,
		)
		if authPresent {
			glog.Infof("Using provided push secret for pushing %s image", tag)
			s.auth = pushAuthConfig
		}
		glog.Infof("Pushing %s image ...", tag)
		if err := pushImage(s.dockerClient, tag, s.auth); err != nil {
			return fmt.Errorf("Failed to push image: %v", err)
		}
		glog.Infof("Successfully pushed %s", tag)
		glog.Flush()
	}
	return nil
}
Beispiel #15
0
// Build executes a Docker build
func (d *DockerBuilder) Build() error {
	var push bool
	pushTag := d.build.Status.OutputDockerImageReference

	buildDir, err := ioutil.TempDir("", "docker-build")
	if err != nil {
		return err
	}
	sourceInfo, err := fetchSource(d.dockerClient, buildDir, d.build, d.urlTimeout, os.Stdin, d.gitClient)
	if err != nil {
		return err
	}
	if sourceInfo != nil {
		updateBuildRevision(d.client, d.build, sourceInfo)
	}
	if err := d.addBuildParameters(buildDir); err != nil {
		return err
	}

	glog.V(4).Infof("Starting Docker build from build config %s ...", d.build.Name)
	// if there is no output target, set one up so the docker build logic
	// (which requires a tag) will still work, but we won't push it at the end.
	if d.build.Spec.Output.To == nil || len(d.build.Spec.Output.To.Name) == 0 {
		d.build.Status.OutputDockerImageReference = d.build.Name
	} else {
		push = true
	}

	buildTag := randomBuildTag(d.build.Namespace, d.build.Name)

	if err := d.dockerBuild(buildDir, buildTag, d.build.Spec.Source.Secrets); err != nil {
		return err
	}

	cname := containerName("docker", d.build.Name, d.build.Namespace, "post-commit")
	if err := execPostCommitHook(d.dockerClient, d.build.Spec.PostCommit, buildTag, cname); err != nil {
		return err
	}

	if push {
		if err := tagImage(d.dockerClient, buildTag, pushTag); err != nil {
			return err
		}

	}

	if err := removeImage(d.dockerClient, buildTag); err != nil {
		glog.Warningf("Failed to remove temporary build tag %v: %v", buildTag, err)
	}

	defer glog.Flush()
	if push {
		// Get the Docker push authentication
		pushAuthConfig, authPresent := dockercfg.NewHelper().GetDockerAuth(
			pushTag,
			dockercfg.PushAuthType,
		)
		if authPresent {
			glog.V(4).Infof("Authenticating Docker push with user %q", pushAuthConfig.Username)
		}

		if sourceInfo != nil {
			repo, _ := parsers.ParseRepositoryTag(pushTag)
			pushTag2 := repo + ":" + strings.Replace(sourceInfo.Ref, "/", "-", -1) + "-" + sourceInfo.CommitID[:8]
			if err := tagImage(d.dockerClient, pushTag, pushTag2); err != nil {
				return err
			}
			glog.Infof("Pushing image %s ...", pushTag2)
			if err := pushImage(d.dockerClient, pushTag2, pushAuthConfig); err != nil {
				return fmt.Errorf("Failed to push image: %v", err)
			}
			if err := removeImage(d.dockerClient, pushTag2); err != nil {
				glog.Warningf("Failed to remove build tag %v: %v", pushTag2, err)
			}
		}

		glog.Infof("Pushing image %s ...", pushTag)
		if err := pushImage(d.dockerClient, pushTag, pushAuthConfig); err != nil {
			return fmt.Errorf("Failed to push image: %v", err)
		}

		glog.Infof("Push successful")
	}
	return nil
}
Beispiel #16
0
// Build executes a Docker build
func (d *DockerBuilder) Build() error {
	if d.build.Spec.Source.Git == nil && d.build.Spec.Source.Binary == nil && d.build.Spec.Source.Dockerfile == nil && d.build.Spec.Source.Images == nil {
		return fmt.Errorf("must provide a value for at least one of source, binary, images, or dockerfile")
	}
	var push bool
	pushTag := d.build.Status.OutputDockerImageReference

	buildDir, err := ioutil.TempDir("", "docker-build")
	if err != nil {
		return err
	}
	sourceInfo, err := fetchSource(d.dockerClient, buildDir, d.build, d.urlTimeout, os.Stdin, d.gitClient)
	if err != nil {
		return err
	}
	if sourceInfo != nil {
		updateBuildRevision(d.client, d.build, sourceInfo)
	}
	if err := d.addBuildParameters(buildDir); err != nil {
		return err
	}

	glog.V(4).Infof("Starting Docker build from build config %s ...", d.build.Name)
	// if there is no output target, set one up so the docker build logic
	// (which requires a tag) will still work, but we won't push it at the end.
	if d.build.Spec.Output.To == nil || len(d.build.Spec.Output.To.Name) == 0 {
		d.build.Status.OutputDockerImageReference = d.build.Name
	} else {
		push = true
	}

	buildTag := randomBuildTag(d.build.Namespace, d.build.Name)

	if err := d.dockerBuild(buildDir, buildTag, d.build.Spec.Source.Secrets); err != nil {
		return err
	}

	cname := containerName("docker", d.build.Name, d.build.Namespace, "post-commit")
	if err := execPostCommitHook(d.dockerClient, d.build.Spec.PostCommit, buildTag, cname); err != nil {
		return err
	}

	if push {
		if err := tagImage(d.dockerClient, buildTag, pushTag); err != nil {
			return err
		}
	}

	if err := removeImage(d.dockerClient, buildTag); err != nil {
		glog.V(0).Infof("warning: Failed to remove temporary build tag %v: %v", buildTag, err)
	}

	if push {
		// Get the Docker push authentication
		pushAuthConfig, authPresent := dockercfg.NewHelper().GetDockerAuth(
			pushTag,
			dockercfg.PushAuthType,
		)
		if authPresent {
			glog.V(4).Infof("Authenticating Docker push with user %q", pushAuthConfig.Username)
		}
		glog.V(1).Infof("Pushing image %s ...", pushTag)
		if err := pushImage(d.dockerClient, pushTag, pushAuthConfig); err != nil {
			return fmt.Errorf("Failed to push image: %v", err)
		}
		glog.V(1).Infof("Push successful")
	}
	return nil
}