Example #1
0
File: util.go Project: dcbw/origin
// BuildNumber returns the given build number.
func BuildNumber(build *buildapi.Build) (int64, error) {
	annotations := build.GetAnnotations()
	if stringNumber, ok := annotations[buildapi.BuildNumberAnnotation]; ok {
		return strconv.ParseInt(stringNumber, 10, 64)
	}
	return 0, fmt.Errorf("build %s/%s does not have %s annotation", build.Namespace, build.Name, buildapi.BuildNumberAnnotation)
}
Example #2
0
func convert_v1_BuildStatus_To_api_Build(in *BuildStatus, out *newer.Build, s conversion.Scope) error {
	out.Cancelled = in.Cancelled
	out.CompletionTimestamp = in.CompletionTimestamp
	if err := s.Convert(&in.Config, &out.Config, 0); err != nil {
		return err
	}
	out.Duration = in.Duration
	out.Message = in.Message
	out.StartTimestamp = in.StartTimestamp
	return nil
}
Example #3
0
func setDuration(build *api.Build) {
	if build.StartTimestamp == nil {
		build.Duration = time.Duration(0)
	} else {
		completionTimestamp := build.CompletionTimestamp
		if completionTimestamp == nil {
			dummy := util.Now()
			completionTimestamp = &dummy
		}
		build.Duration = completionTimestamp.Rfc3339Copy().Time.Sub(build.StartTimestamp.Rfc3339Copy().Time)
	}
}
Example #4
0
//setBuildAnnotationAndLabel set annotations and label info of this build
func setBuildAnnotationAndLabel(bcCopy *buildapi.BuildConfig, build *buildapi.Build) {
	if build.Annotations == nil {
		build.Annotations = make(map[string]string)
	}
	//bcCopy.Status.LastVersion has been increased
	build.Annotations[buildapi.BuildNumberAnnotation] = strconv.FormatInt(bcCopy.Status.LastVersion, 10)
	build.Annotations[buildapi.BuildConfigAnnotation] = bcCopy.Name
	if build.Labels == nil {
		build.Labels = make(map[string]string)
	}
	build.Labels[buildapi.BuildConfigLabelDeprecated] = buildapi.LabelValue(bcCopy.Name)
	build.Labels[buildapi.BuildConfigLabel] = buildapi.LabelValue(bcCopy.Name)
	build.Labels[buildapi.BuildRunPolicyLabel] = string(bcCopy.Spec.RunPolicy)
}
Example #5
0
File: util.go Project: dcbw/origin
// BuildRunPolicy returns the scheduling policy for the build based on the
// "queued" label.
func BuildRunPolicy(build *buildapi.Build) buildapi.BuildRunPolicy {
	labels := build.GetLabels()
	if value, found := labels[buildapi.BuildRunPolicyLabel]; found {
		switch value {
		case "Parallel":
			return buildapi.BuildRunPolicyParallel
		case "Serial":
			return buildapi.BuildRunPolicySerial
		case "SerialLatestOnly":
			return buildapi.BuildRunPolicySerialLatestOnly
		}
	}
	glog.V(5).Infof("Build %s/%s does not have start policy label set, using default (Serial)", build.Namespace, build.Name)
	return buildapi.BuildRunPolicySerial
}
Example #6
0
func updateBuildRevision(c client.BuildInterface, build *api.Build, sourceInfo *git.SourceInfo) {
	if build.Spec.Revision != nil {
		return
	}
	build.Spec.Revision = &api.SourceRevision{
		Git: &api.GitSourceRevision{
			Commit:  sourceInfo.CommitID,
			Message: sourceInfo.Message,
			Author: api.SourceControlUser{
				Name:  sourceInfo.AuthorName,
				Email: sourceInfo.AuthorEmail,
			},
			Committer: api.SourceControlUser{
				Name:  sourceInfo.CommitterName,
				Email: sourceInfo.CommitterEmail,
			},
		},
	}

	// Reset ResourceVersion to avoid a conflict with other updates to the build
	build.ResourceVersion = ""

	glog.V(4).Infof("Setting build revision to %#v", build.Spec.Revision.Git)
	_, err := c.UpdateDetails(build)
	if err != nil {
		glog.Warningf("An error occurred saving build revision: %v", err)
	}
}
Example #7
0
// Determine the next status of a build given its current state and the state
// of its associated pod.
// TODO: improve handling of illegal state transitions
func (bc *BuildController) synchronize(build *api.Build) (api.BuildStatus, error) {
	glog.Infof("Syncing build %s", build.ID)

	switch build.Status {
	case api.BuildNew:
		build.PodID = "build-" + string(build.Input.Type) + "-" + build.ID // TODO: better naming
		return api.BuildPending, nil
	case api.BuildPending:
		buildStrategy, ok := bc.buildStrategies[build.Input.Type]
		if !ok {
			return api.BuildError, fmt.Errorf("No build type for %s", build.Input.Type)
		}

		podSpec := buildStrategy.CreateBuildPod(build, bc.dockerRegistry)

		glog.Infof("Attempting to create pod: %#v", podSpec)
		_, err := bc.kubeClient.CreatePod(*podSpec)

		// TODO: strongly typed error checking
		if err != nil {
			if strings.Index(err.Error(), "already exists") != -1 {
				return build.Status, err // no transition, already handled by someone else
			}

			return api.BuildFailed, err
		}

		return api.BuildRunning, nil
	case api.BuildRunning:
		if timedOut := hasTimeoutElapsed(build, bc.timeout); timedOut {
			return api.BuildFailed, fmt.Errorf("Build timed out")
		}

		pod, err := bc.kubeClient.GetPod(build.PodID)
		if err != nil {
			return build.Status, fmt.Errorf("Error retrieving pod for build ID %v: %#v", build.ID, err)
		}

		// pod is still running
		if pod.CurrentState.Status != kubeapi.PodTerminated {
			return build.Status, nil
		}

		var nextStatus = api.BuildComplete

		// check the exit codes of all the containers in the pod
		for _, info := range pod.CurrentState.Info {
			if info.State.ExitCode != 0 {
				nextStatus = api.BuildFailed
			}
		}
		return nextStatus, nil
	case api.BuildComplete, api.BuildFailed, api.BuildError:
		return build.Status, nil
	default:
		return api.BuildError, fmt.Errorf("Invalid build status: %s", build.Status)
	}
}
Example #8
0
// CancelBuild updates a build status to Cancelled, after its associated pod is deleted.
func (bc *BuildPodController) CancelBuild(build *buildapi.Build, pod *kapi.Pod) error {
	if !isBuildCancellable(build) {
		glog.V(4).Infof("Build %s/%s can be cancelled only if it has pending/running status, not %s.", build.Namespace, build.Name, build.Status)
		return nil
	}

	err := bc.PodManager.DeletePod(build.Namespace, pod)
	if err != nil && !errors.IsNotFound(err) {
		return err
	}

	glog.V(4).Infof("Build %s/%s is about to be cancelled", build.Namespace, build.Name)
	build.Status = buildapi.BuildStatusCancelled
	now := util.Now()
	build.CompletionTimestamp = &now
	if err := bc.BuildUpdater.Update(build.Namespace, build); err != nil {
		return err
	}

	glog.V(4).Infof("Build %s/%s was successfully cancelled.", build.Namespace, build.Name)
	return nil
}
Example #9
0
func withStatus(build *buildapi.Build, status buildapi.BuildStatus) *buildapi.Build {
	build.Status = status
	return build
}
Example #10
0
func withCreated(build *buildapi.Build, creationTimestamp util.Time) *buildapi.Build {
	build.CreationTimestamp = creationTimestamp
	return build
}
Example #11
0
// nextBuildPhase updates build with any appropriate changes, or returns an error if
// the change cannot occur. When returning nil, be sure to set build.Status and optionally
// build.Message.
func (bc *BuildController) nextBuildPhase(build *buildapi.Build) error {
	// If a cancelling event was triggered for the build, update build status.
	if build.Status.Cancelled {
		glog.V(4).Infof("Cancelling build %s/%s.", build.Namespace, build.Name)
		build.Status.Phase = buildapi.BuildPhaseCancelled
		build.Status.Reason = ""
		build.Status.Message = ""
		return nil
	}

	// these builds are processed/updated/etc by the jenkins sync plugin
	if build.Spec.Strategy.JenkinsPipelineStrategy != nil {
		glog.V(4).Infof("Ignoring build with jenkins pipeline strategy")
		return nil
	}

	// Set the output Docker image reference.
	ref, err := bc.resolveOutputDockerImageReference(build)
	if err != nil {
		build.Status.Reason = buildapi.StatusReasonInvalidOutputReference
		return err
	}
	build.Status.OutputDockerImageReference = ref

	// Make a copy to avoid mutating the build from this point on.
	copy, err := kapi.Scheme.Copy(build)
	if err != nil {
		return fmt.Errorf("unable to copy build: %v", err)
	}
	buildCopy := copy.(*buildapi.Build)

	// TODO(rhcarvalho)
	// The S2I and Docker builders expect build.Spec.Output.To to contain a
	// resolved reference to a Docker image. Since build.Spec is immutable, we
	// change a copy (that is never persisted) and pass it to
	// bc.BuildStrategy.CreateBuildPod. We should make the builders use
	// build.Status.OutputDockerImageReference, what will make copying the build
	// unnecessary.
	if build.Spec.Output.To != nil && len(build.Spec.Output.To.Name) != 0 {
		buildCopy.Spec.Output.To = &kapi.ObjectReference{
			Kind: "DockerImage",
			Name: ref,
		}
	}

	// Invoke the strategy to get a build pod.
	podSpec, err := bc.BuildStrategy.CreateBuildPod(buildCopy)
	if err != nil {
		build.Status.Reason = buildapi.StatusReasonCannotCreateBuildPodSpec
		if strategy.IsFatal(err) {
			return strategy.FatalError(fmt.Sprintf("failed to create a build pod spec for build %s/%s: %v", build.Namespace, build.Name, err))
		}
		return fmt.Errorf("failed to create a build pod spec for build %s/%s: %v", build.Namespace, build.Name, err)
	}
	glog.V(4).Infof("Pod %s for build %s/%s is about to be created", podSpec.Name, build.Namespace, build.Name)

	if _, err := bc.PodManager.CreatePod(build.Namespace, podSpec); err != nil {
		if errors.IsAlreadyExists(err) {
			bc.Recorder.Eventf(build, kapi.EventTypeWarning, "failedCreate", "Pod already exists: %s/%s", podSpec.Namespace, podSpec.Name)
			glog.V(4).Infof("Build pod already existed: %#v", podSpec)
			return nil
		}
		// Log an event if the pod is not created (most likely due to quota denial).
		bc.Recorder.Eventf(build, kapi.EventTypeWarning, "FailedCreate", "Error creating: %v", err)
		build.Status.Reason = buildapi.StatusReasonCannotCreateBuildPod
		return fmt.Errorf("failed to create build pod: %v", err)
	}
	if build.Annotations == nil {
		build.Annotations = make(map[string]string)
	}
	build.Annotations[buildapi.BuildPodNameAnnotation] = podSpec.Name
	glog.V(4).Infof("Created pod for build: %#v", podSpec)

	// Set the build phase, which will be persisted.
	build.Status.Phase = buildapi.BuildPhasePending
	build.Status.Reason = ""
	build.Status.Message = ""
	return nil
}
Example #12
0
// nextBuildStatus updates build with any appropriate changes, or returns an error if
// the change cannot occur. When returning nil, be sure to set build.Status and optionally
// build.Message.
func (bc *BuildController) nextBuildStatus(build *buildapi.Build) error {
	// If a cancelling event was triggered for the build, update build status.
	if build.Cancelled {
		glog.V(4).Infof("Cancelling Build %s/%s.", build.Namespace, build.Name)
		build.Status = buildapi.BuildStatusCancelled
		return nil
	}

	// lookup the destination from the referenced image repository
	spec := build.Parameters.Output.DockerImageReference
	if ref := build.Parameters.Output.To; ref != nil {
		// TODO: security, ensure that the reference image stream is actually visible
		namespace := ref.Namespace
		if len(namespace) == 0 {
			namespace = build.Namespace
		}

		repo, err := bc.ImageStreamClient.GetImageStream(namespace, ref.Name)
		if err != nil {
			if errors.IsNotFound(err) {
				return fmt.Errorf("the referenced output ImageStream %s/%s does not exist", namespace, ref.Name)
			}
			return fmt.Errorf("the referenced output ImageStream %s/%s could not be found by Build %s/%s: %v", namespace, ref.Name, build.Namespace, build.Name, err)
		}
		if len(repo.Status.DockerImageRepository) == 0 {
			e := fmt.Errorf("the ImageStream %s/%s cannot be used as the output for Build %s/%s because the integrated Docker registry is not configured, or the user forgot to set a valid external registry", namespace, ref.Name, build.Namespace, build.Name)
			bc.Recorder.Eventf(build, "invalidOutput", "Error starting build: %v", e)
			return e
		}
		spec = repo.Status.DockerImageRepository
	}

	// set the expected build parameters, which will be saved if no error occurs
	build.Status = buildapi.BuildStatusPending

	// Make a copy to avoid mutating the build from this point on
	copy, err := kapi.Scheme.Copy(build)
	if err != nil {
		return fmt.Errorf("unable to copy Build: %v", err)
	}
	buildCopy := copy.(*buildapi.Build)

	// override DockerImageReference in the strategy for the copy we send to the build pod
	buildCopy.Parameters.Output.DockerImageReference = spec
	buildCopy.Parameters.Output.To = nil

	// invoke the strategy to get a build pod
	podSpec, err := bc.BuildStrategy.CreateBuildPod(buildCopy)
	if err != nil {
		return fmt.Errorf("the strategy failed to create a build pod for Build %s/%s: %v", build.Namespace, build.Name, err)
	}
	glog.V(4).Infof("Pod %s for Build %s/%s is about to be created", podSpec.Name, build.Namespace, build.Name)

	if _, err := bc.PodManager.CreatePod(build.Namespace, podSpec); err != nil {
		if errors.IsAlreadyExists(err) {
			glog.V(4).Infof("Build pod already existed: %#v", podSpec)
			return nil
		}
		// log an event if the pod is not created (most likely due to quota denial)
		bc.Recorder.Eventf(build, "failedCreate", "Error creating: %v", err)
		return fmt.Errorf("failed to create pod for Build %s/%s: %v", build.Namespace, build.Name, err)
	}

	glog.V(4).Infof("Created pod for Build: %#v", podSpec)
	return nil
}
func updateBuild(t *testing.T, buildInterface client.BuildInterface, build *buildapi.Build) (*buildapi.Build, error) {
	build.Labels = map[string]string{"updated": "true"}
	return buildInterface.Update(build)
}
Example #14
0
func setBuildPodNameAnnotation(build *buildapi.Build, podName string) {
	if build.Annotations == nil {
		build.Annotations = map[string]string{}
	}
	build.Annotations[buildapi.BuildPodNameAnnotation] = podName
}