Пример #1
0
// HandlePod updates the state of the build based on the pod state
func (bc *BuildPodController) HandlePod(pod *kapi.Pod) error {
	obj, exists, err := bc.BuildStore.Get(buildKey(pod))
	if err != nil {
		glog.V(4).Infof("Error getting build for pod %s/%s: %v", pod.Namespace, pod.Name, err)
		return err
	}
	if !exists || obj == nil {
		glog.V(5).Infof("No build found for pod %s/%s", pod.Namespace, pod.Name)
		return nil
	}

	build := obj.(*buildapi.Build)

	nextStatus := build.Status.Phase
	switch pod.Status.Phase {
	case kapi.PodRunning:
		// The pod's still running
		nextStatus = buildapi.BuildPhaseRunning
	case kapi.PodSucceeded:
		// Check the exit codes of all the containers in the pod
		nextStatus = buildapi.BuildPhaseComplete
		if len(pod.Status.ContainerStatuses) == 0 {
			// no containers in the pod means something went badly wrong, so the build
			// should be failed.
			glog.V(2).Infof("Failing build %s/%s because the pod has no containers", build.Namespace, build.Name)
			nextStatus = buildapi.BuildPhaseFailed
		} else {
			for _, info := range pod.Status.ContainerStatuses {
				if info.State.Terminated != nil && info.State.Terminated.ExitCode != 0 {
					nextStatus = buildapi.BuildPhaseFailed
					break
				}
			}
		}
	case kapi.PodFailed:
		nextStatus = buildapi.BuildPhaseFailed
	}

	if build.Status.Phase != nextStatus && !buildutil.IsBuildComplete(build) {
		glog.V(4).Infof("Updating build %s/%s status %s -> %s", build.Namespace, build.Name, build.Status.Phase, nextStatus)
		build.Status.Phase = nextStatus
		build.Status.Reason = ""
		build.Status.Message = ""
		if buildutil.IsBuildComplete(build) {
			now := unversioned.Now()
			build.Status.CompletionTimestamp = &now
		}
		if build.Status.Phase == buildapi.BuildPhaseRunning {
			now := unversioned.Now()
			build.Status.StartTimestamp = &now
		}
		if err := bc.BuildUpdater.Update(build.Namespace, build); err != nil {
			return fmt.Errorf("failed to update build %s/%s: %v", build.Namespace, build.Name, err)
		}
		glog.V(4).Infof("Build %s/%s status was updated %s -> %s", build.Namespace, build.Name, build.Status.Phase, nextStatus)
	}
	return nil
}
Пример #2
0
// HandleBuildPodDeletion sets the status of a build to error if the build pod has been deleted
func (bc *BuildPodDeleteController) HandleBuildPodDeletion(pod *kapi.Pod) error {
	glog.V(4).Infof("Handling deletion of build pod %s/%s", pod.Namespace, pod.Name)
	obj, exists, err := bc.BuildStore.Get(buildKey(pod))
	if err != nil {
		glog.V(4).Infof("Error getting build for pod %s/%s", pod.Namespace, pod.Name)
		return err
	}
	if !exists || obj == nil {
		glog.V(5).Infof("No Build found for deleted pod %s/%s", pod.Namespace, pod.Name)
		return nil
	}
	build := obj.(*buildapi.Build)

	if buildutil.IsBuildComplete(build) {
		glog.V(4).Infof("Pod was deleted but Build %s/%s is already completed, so no need to update it.", build.Namespace, build.Name)
		return nil
	}

	nextStatus := buildapi.BuildPhaseError
	if build.Status.Phase != nextStatus {
		glog.V(4).Infof("Updating build %s/%s status %s -> %s", build.Namespace, build.Name, build.Status.Phase, nextStatus)
		build.Status.Phase = nextStatus
		build.Status.Message = "The Pod for this Build was deleted before the Build completed."
		now := util.Now()
		build.Status.CompletionTimestamp = &now
		if err := bc.BuildUpdater.Update(build.Namespace, build); err != nil {
			return fmt.Errorf("Failed to update Build %s/%s: %v", build.Namespace, build.Name, err)
		}
	}
	return nil
}
Пример #3
0
// HandlePod updates the state of the build based on the pod state
func (bc *BuildPodController) HandlePod(pod *kapi.Pod) error {
	obj, exists, err := bc.BuildStore.Get(buildKey(pod))
	if err != nil {
		glog.V(4).Infof("Error getting Build for pod %s/%s: %v", pod.Namespace, pod.Name, err)
		return err
	}
	if !exists || obj == nil {
		glog.V(5).Infof("No Build found for pod %s/%s", pod.Namespace, pod.Name)
		return nil
	}

	build := obj.(*buildapi.Build)

	// A cancelling event was triggered for the build, delete its pod and update build status.
	if build.Status.Cancelled {
		glog.V(4).Infof("Cancelling Build %s/%s.", build.Namespace, build.Name)

		if err := bc.CancelBuild(build, pod); err != nil {
			return fmt.Errorf("failed to cancel Build %s/%s: %v, will retry", build.Namespace, build.Name, err)
		}
		return nil
	}

	nextStatus := build.Status.Phase

	switch pod.Status.Phase {
	case kapi.PodRunning:
		// The pod's still running
		nextStatus = buildapi.BuildPhaseRunning
	case kapi.PodSucceeded, kapi.PodFailed:
		// Check the exit codes of all the containers in the pod
		nextStatus = buildapi.BuildPhaseComplete
		for _, info := range pod.Status.ContainerStatuses {
			if info.State.Terminated != nil && info.State.Terminated.ExitCode != 0 {
				nextStatus = buildapi.BuildPhaseFailed
				break
			}
		}
	}

	if build.Status.Phase != nextStatus {
		glog.V(4).Infof("Updating Build %s/%s status %s -> %s", build.Namespace, build.Name, build.Status.Phase, nextStatus)
		build.Status.Phase = nextStatus
		if buildutil.IsBuildComplete(build) {
			now := util.Now()
			build.Status.CompletionTimestamp = &now
		}
		if build.Status.Phase == buildapi.BuildPhaseRunning {
			now := util.Now()
			build.Status.StartTimestamp = &now
		}
		if err := bc.BuildUpdater.Update(build.Namespace, build); err != nil {
			return fmt.Errorf("failed to update Build %s/%s: %v", build.Namespace, build.Name, err)
		}
		glog.V(4).Infof("Build %s/%s status was updated %s -> %s", build.Namespace, build.Name, build.Status.Phase, nextStatus)
	}
	return nil
}
Пример #4
0
// HandleBuild deletes pods for cancelled builds and takes new builds and puts
// them in the pending state after creating a corresponding pod
func (bc *BuildController) HandleBuild(build *buildapi.Build) error {
	// 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
	}
	glog.V(4).Infof("Handling build %s/%s (%s)", build.Namespace, build.Name, build.Status.Phase)

	runPolicy := policy.ForBuild(build, bc.RunPolicies)
	if runPolicy == nil {
		return fmt.Errorf("unable to determine build scheduler for %s/%s", build.Namespace, build.Name)
	}

	if buildutil.IsBuildComplete(build) {
		if err := runPolicy.OnComplete(build); err != nil {
			return err
		}
		return nil
	}

	// A cancelling event was triggered for the build, delete its pod and update build status.
	if build.Status.Cancelled && build.Status.Phase != buildapi.BuildPhaseCancelled {
		glog.V(5).Infof("Marking build %s/%s as cancelled", build.Namespace, build.Name)
		if err := bc.CancelBuild(build); err != nil {
			build.Status.Reason = buildapi.StatusReasonCancelBuildFailed
			build.Status.Message = buildapi.StatusMessageCancelBuildFailed
			if err = bc.BuildUpdater.Update(build.Namespace, build); err != nil {
				utilruntime.HandleError(fmt.Errorf("Failed to update build %s/%s: %v", build.Namespace, build.Name, err))
			}
			return fmt.Errorf("Failed to cancel build %s/%s: %v, will retry", build.Namespace, build.Name, err)
		}
	}

	// Handle only new builds from this point
	if build.Status.Phase != buildapi.BuildPhaseNew {
		return nil
	}

	// The runPolicy decides whether to execute this build or not.
	if run, err := runPolicy.IsRunnable(build); err != nil || !run {
		return err
	}

	if err := bc.nextBuildPhase(build); err != nil {
		return err
	}

	if err := bc.BuildUpdater.Update(build.Namespace, build); err != nil {
		// This is not a retryable error because the build has been created.  The worst case
		// outcome of not updating the buildconfig is that we might rerun a build for the
		// same "new" imageid change in the future, which is better than guaranteeing we
		// run the build 2+ times by retrying it here.
		glog.V(2).Infof("Failed to record changes to build %s/%s: %v", build.Namespace, build.Name, err)
	}
	return nil
}
Пример #5
0
func ValidateBuildUpdate(build *buildapi.Build, older *buildapi.Build) fielderrors.ValidationErrorList {
	allErrs := fielderrors.ValidationErrorList{}
	allErrs = append(allErrs, validation.ValidateObjectMetaUpdate(&build.ObjectMeta, &older.ObjectMeta).Prefix("metadata")...)

	allErrs = append(allErrs, ValidateBuild(build)...)

	if buildutil.IsBuildComplete(older) && older.Status.Phase != build.Status.Phase {
		allErrs = append(allErrs, fielderrors.NewFieldInvalid("status.Phase", build.Status.Phase, "phase cannot be updated from a terminal state"))
	}
	if !kapi.Semantic.DeepEqual(build.Spec, older.Spec) {
		allErrs = append(allErrs, fielderrors.NewFieldInvalid("spec", "content of spec is not printed out, please refer to the \"details\"", "spec is immutable"))
	}

	return allErrs
}
Пример #6
0
// List lists all Pods associated with a Build.
func (lw *buildPodDeleteLW) List(options kapi.ListOptions) (runtime.Object, error) {
	glog.V(5).Info("Checking for deleted build pods")
	buildList, err := lw.Client.Builds(kapi.NamespaceAll).List(options)
	if err != nil {
		glog.V(4).Infof("Failed to find any builds due to error %v", err)
		return nil, err
	}
	for _, build := range buildList.Items {
		glog.V(5).Infof("Found build %s/%s", build.Namespace, build.Name)
		if buildutil.IsBuildComplete(&build) {
			glog.V(5).Infof("Ignoring build %s/%s because it is complete", build.Namespace, build.Name)
			continue
		}
		if build.Spec.Strategy.JenkinsPipelineStrategy != nil {
			glog.V(5).Infof("Ignoring build %s/%s because it is a pipeline build", build.Namespace, build.Name)
			continue
		}
		pod, err := lw.KubeClient.Pods(build.Namespace).Get(buildapi.GetBuildPodName(&build))
		if err != nil {
			if !kerrors.IsNotFound(err) {
				glog.V(4).Infof("Error getting pod for build %s/%s: %v", build.Namespace, build.Name, err)
				return nil, err
			} else {
				pod = nil
			}
		} else {
			if buildName := buildapi.GetBuildName(pod); buildName != build.Name {
				pod = nil
			}
		}
		if pod == nil {
			deletedPod := &kapi.Pod{
				ObjectMeta: kapi.ObjectMeta{
					Name:      buildapi.GetBuildPodName(&build),
					Namespace: build.Namespace,
				},
			}
			glog.V(4).Infof("No build pod found for build %s/%s, sending delete event for build pod", build.Namespace, build.Name)
			err := lw.store.Delete(deletedPod)
			if err != nil {
				glog.V(4).Infof("Error queuing delete event: %v", err)
			}
		} else {
			glog.V(5).Infof("Found build pod %s/%s for build %s", pod.Namespace, pod.Name, build.Name)
		}
	}
	return &kapi.PodList{}, nil
}
Пример #7
0
// HandleBuildPodDeletion sets the status of a build to error if the build pod has been deleted
func (bc *BuildPodDeleteController) HandleBuildPodDeletion(pod *kapi.Pod) error {
	glog.V(4).Infof("Handling deletion of build pod %s/%s", pod.Namespace, pod.Name)
	obj, exists, err := bc.BuildStore.Get(buildKey(pod))
	if err != nil {
		glog.V(4).Infof("Error getting build for pod %s/%s", pod.Namespace, pod.Name)
		return err
	}
	if !exists || obj == nil {
		glog.V(5).Infof("No build found for deleted pod %s/%s", pod.Namespace, pod.Name)
		return nil
	}
	build := obj.(*buildapi.Build)

	if build.Spec.Strategy.JenkinsPipelineStrategy != nil {
		glog.V(4).Infof("Build %s/%s is a pipeline build, ignoring", build.Namespace, build.Name)
		return nil
	}
	// If build was cancelled, we'll leave HandleBuild to update the build
	if build.Status.Cancelled {
		glog.V(4).Infof("Cancelation for build %s/%s was already triggered, ignoring", build.Namespace, build.Name)
		return nil
	}

	if buildutil.IsBuildComplete(build) {
		glog.V(4).Infof("Pod was deleted but build %s/%s is already completed, so no need to update it.", build.Namespace, build.Name)
		return nil
	}

	nextStatus := buildapi.BuildPhaseError
	if build.Status.Phase != nextStatus {
		glog.V(4).Infof("Updating build %s/%s status %s -> %s", build.Namespace, build.Name, build.Status.Phase, nextStatus)
		build.Status.Phase = nextStatus
		build.Status.Reason = buildapi.StatusReasonBuildPodDeleted
		build.Status.Message = buildapi.StatusMessageBuildPodDeleted
		now := unversioned.Now()
		build.Status.CompletionTimestamp = &now
		if err := bc.BuildUpdater.Update(build.Namespace, build); err != nil {
			return fmt.Errorf("Failed to update build %s/%s: %v", build.Namespace, build.Name, err)
		}
	}
	return nil
}
Пример #8
0
// cancelPreviousBuilds cancels all queued builds that have the build sequence number
// lower than the given build. It retries the cancellation in case of conflict.
func (s *SerialLatestOnlyPolicy) cancelPreviousBuilds(build *buildapi.Build) []error {
	bcName := buildutil.ConfigNameForBuild(build)
	if len(bcName) == 0 {
		return []error{}
	}
	currentBuildNumber, err := buildutil.BuildNumber(build)
	if err != nil {
		return []error{NewNoBuildNumberAnnotationError(build)}
	}
	builds, err := buildutil.BuildConfigBuilds(s.BuildLister, build.Namespace, bcName, func(b buildapi.Build) bool {
		// Do not cancel the complete builds, builds that were already cancelled, or
		// running builds.
		if buildutil.IsBuildComplete(&b) || b.Status.Phase == buildapi.BuildPhaseRunning {
			return false
		}

		// Prevent race-condition when there is a newer build than this and we don't
		// want to cancel it. The HandleBuild() function that runs for that build
		// will cancel this build.
		buildNumber, _ := buildutil.BuildNumber(&b)
		return buildNumber < currentBuildNumber
	})
	if err != nil {
		return []error{err}
	}
	var result = []error{}
	for _, b := range builds.Items {
		err := wait.Poll(500*time.Millisecond, 5*time.Second, func() (bool, error) {
			b.Status.Cancelled = true
			err := s.BuildUpdater.Update(b.Namespace, &b)
			if err != nil && errors.IsConflict(err) {
				glog.V(5).Infof("Error cancelling build %s/%s: %v (will retry)", b.Namespace, b.Name, err)
				return false, nil
			}
			return true, err
		})
		if err != nil {
			result = append(result, err)
		}
	}
	return result
}
Пример #9
0
func ValidateBuildUpdate(build *buildapi.Build, older *buildapi.Build) field.ErrorList {
	allErrs := field.ErrorList{}
	allErrs = append(allErrs, validation.ValidateObjectMetaUpdate(&build.ObjectMeta, &older.ObjectMeta, field.NewPath("metadata"))...)

	allErrs = append(allErrs, ValidateBuild(build)...)

	if buildutil.IsBuildComplete(older) && older.Status.Phase != build.Status.Phase {
		allErrs = append(allErrs, field.Invalid(field.NewPath("status", "phase"), build.Status.Phase, "phase cannot be updated from a terminal state"))
	}
	if !kapi.Semantic.DeepEqual(build.Spec, older.Spec) {
		diff, err := diffBuildSpec(build.Spec, older.Spec)
		if err != nil {
			glog.V(2).Infof("Error calculating build spec patch: %v", err)
			diff = "[unknown]"
		}
		detail := fmt.Sprintf("spec is immutable, diff: %s", diff)
		allErrs = append(allErrs, field.Invalid(field.NewPath("spec"), "content of spec is not printed out, please refer to the details", detail))
	}

	return allErrs
}
Пример #10
0
// List lists all Pods associated with a Build.
func (lw *buildPodDeleteLW) List() (runtime.Object, error) {
	glog.V(5).Info("Checking for deleted build pods")
	buildList, err := lw.Client.Builds(kapi.NamespaceAll).List(labels.Everything(), fields.Everything())
	if err != nil {
		glog.V(4).Infof("Failed to find any builds due to error %v", err)
		return nil, err
	}
	for _, build := range buildList.Items {
		glog.V(5).Infof("Found build %s/%s", build.Namespace, build.Name)
		if buildutil.IsBuildComplete(&build) {
			glog.V(5).Infof("Ignoring build %s/%s because it is complete", build.Namespace, build.Name)
			continue
		}
		pod, err := lw.KubeClient.Pods(build.Namespace).Get(buildutil.GetBuildPodName(&build))
		if err != nil && !kerrors.IsNotFound(err) {
			glog.V(4).Infof("Error getting pod for build %s/%s: %v", build.Namespace, build.Name, err)
			return nil, err
		}
		if (err != nil && kerrors.IsNotFound(err)) || pod.Labels[buildapi.BuildLabel] != build.Name {
			pod = nil
		}
		if pod == nil {
			deletedPod := &kapi.Pod{
				ObjectMeta: kapi.ObjectMeta{
					Name:      buildutil.GetBuildPodName(&build),
					Namespace: build.Namespace,
				},
			}
			glog.V(4).Infof("No build pod found for build %s/%s, sending delete event for build pod", build.Namespace, build.Name)
			err := lw.store.Delete(deletedPod)
			if err != nil {
				glog.V(4).Infof("Error queuing delete event: %v", err)
			}
		} else {
			glog.V(5).Infof("Found build pod %s/%s for build %s", pod.Namespace, pod.Name, build.Name)
		}
	}
	return &kapi.PodList{}, nil
}
Пример #11
0
// ictMarker inspects the image change triggers for the provided deploymentconfig and returns
// a marker in case of the following two scenarios:
//
// 1. The image stream pointed by the dc trigger doen not exist.
// 2. The image stream tag pointed by the dc trigger does not exist and there is no build in
// 	  flight that could push to the tag.
func ictMarker(g osgraph.Graph, f osgraph.Namer, dcNode *deploygraph.DeploymentConfigNode) *osgraph.Marker {
	for _, uncastIstNode := range g.PredecessorNodesByEdgeKind(dcNode, deployedges.TriggersDeploymentEdgeKind) {
		if istNode := uncastIstNode.(*imagegraph.ImageStreamTagNode); !istNode.Found() {
			// The image stream for the tag of interest does not exist.
			if isNode, exists := doesImageStreamExist(g, uncastIstNode); !exists {
				return &osgraph.Marker{
					Node:         dcNode,
					RelatedNodes: []graph.Node{uncastIstNode, isNode},

					Severity: osgraph.ErrorSeverity,
					Key:      MissingImageStreamErr,
					Message: fmt.Sprintf("The image trigger for %s will have no effect because %s does not exist.",
						f.ResourceName(dcNode), f.ResourceName(isNode)),
					// TODO: Suggest `oc create imagestream` once we have that.
				}
			}

			for _, bcNode := range buildedges.BuildConfigsForTag(g, istNode) {
				// Avoid warning for the dc image trigger in case there is a build in flight.
				if latestBuild := buildedges.GetLatestBuild(g, bcNode); latestBuild != nil && !buildutil.IsBuildComplete(latestBuild.Build) {
					return nil
				}
			}

			// The image stream tag of interest does not exist.
			return &osgraph.Marker{
				Node:         dcNode,
				RelatedNodes: []graph.Node{uncastIstNode},

				Severity: osgraph.WarningSeverity,
				Key:      MissingImageStreamTagWarning,
				Message: fmt.Sprintf("The image trigger for %s will have no effect until %s is imported or created by a build.",
					f.ResourceName(dcNode), f.ResourceName(istNode)),
			}
		}
	}
	return nil
}
Пример #12
0
				LabelSelector: buildutil.BuildConfigSelector(bcName),
			})
			defer buildWatch.Stop()

			// Start first build
			stdout, _, err := exutil.StartBuild(oc, bcName, "-o=name")
			o.Expect(err).NotTo(o.HaveOccurred())
			o.Expect(strings.TrimSpace(stdout)).ShouldNot(o.HaveLen(0))
			// extract build name from "build/buildName" resource id
			startedBuilds = append(startedBuilds, strings.TrimSpace(strings.Split(stdout, "/")[1]))

			// Wait for it to become running
			for {
				event := <-buildWatch.ResultChan()
				build := event.Object.(*buildapi.Build)
				o.Expect(buildutil.IsBuildComplete(build)).Should(o.BeFalse())
				if build.Name == startedBuilds[0] && build.Status.Phase == buildapi.BuildPhaseRunning {
					break
				}
			}

			for i := 0; i < 2; i++ {
				stdout, _, err = exutil.StartBuild(oc, bcName, "-o=name")
				o.Expect(err).NotTo(o.HaveOccurred())
				o.Expect(strings.TrimSpace(stdout)).ShouldNot(o.HaveLen(0))
				startedBuilds = append(startedBuilds, strings.TrimSpace(strings.Split(stdout, "/")[1]))
			}

			o.Expect(err).NotTo(o.HaveOccurred())

			for {
Пример #13
0
// HandlePod updates the state of the build based on the pod state
func (bc *BuildPodController) HandlePod(pod *kapi.Pod) error {
	obj, exists, err := bc.BuildStore.Get(buildKey(pod))
	if err != nil {
		glog.V(4).Infof("Error getting build for pod %s/%s: %v", pod.Namespace, pod.Name, err)
		return err
	}
	if !exists || obj == nil {
		glog.V(5).Infof("No build found for pod %s/%s", pod.Namespace, pod.Name)
		return nil
	}

	build := obj.(*buildapi.Build)

	nextStatus := build.Status.Phase
	currentReason := build.Status.Reason

	switch pod.Status.Phase {
	case kapi.PodRunning:
		// The pod's still running
		build.Status.Reason = ""
		nextStatus = buildapi.BuildPhaseRunning
	case kapi.PodPending:
		build.Status.Reason = ""
		nextStatus = buildapi.BuildPhasePending
		if secret := build.Spec.Output.PushSecret; secret != nil && currentReason != buildapi.StatusReasonMissingPushSecret {
			if _, err := bc.SecretClient.Secrets(build.Namespace).Get(secret.Name); err != nil && errors.IsNotFound(err) {
				build.Status.Reason = buildapi.StatusReasonMissingPushSecret
				glog.V(4).Infof("Setting reason for pending build to %q due to missing secret %s/%s", build.Status.Reason, build.Namespace, secret.Name)
			}
		}
	case kapi.PodSucceeded:
		// Check the exit codes of all the containers in the pod
		nextStatus = buildapi.BuildPhaseComplete
		build.Status.Reason = ""
		if len(pod.Status.ContainerStatuses) == 0 {
			// no containers in the pod means something went badly wrong, so the build
			// should be failed.
			glog.V(2).Infof("Failing build %s/%s because the pod has no containers", build.Namespace, build.Name)
			nextStatus = buildapi.BuildPhaseFailed
		} else {
			for _, info := range pod.Status.ContainerStatuses {
				if info.State.Terminated != nil && info.State.Terminated.ExitCode != 0 {
					nextStatus = buildapi.BuildPhaseFailed
					break
				}
			}
		}
	case kapi.PodFailed:
		build.Status.Reason = ""
		nextStatus = buildapi.BuildPhaseFailed
	}

	// Update the build object when it progress to a next state or the reason for
	// the current state changed.
	if build.Status.Phase != nextStatus && !buildutil.IsBuildComplete(build) {
		reason := ""
		if len(build.Status.Reason) > 0 {
			reason = " (" + string(build.Status.Reason) + ")"
		}
		glog.V(4).Infof("Updating build %s/%s status %s -> %s%s", build.Namespace, build.Name, build.Status.Phase, nextStatus, reason)
		build.Status.Phase = nextStatus
		build.Status.Message = ""
		if buildutil.IsBuildComplete(build) {
			now := unversioned.Now()
			build.Status.CompletionTimestamp = &now
		}
		if build.Status.Phase == buildapi.BuildPhaseRunning {
			now := unversioned.Now()
			build.Status.StartTimestamp = &now
		}
		if err := bc.BuildUpdater.Update(build.Namespace, build); err != nil {
			return fmt.Errorf("failed to update build %s/%s: %v", build.Namespace, build.Name, err)
		}
		glog.V(4).Infof("Build %s/%s status was updated %s -> %s", build.Namespace, build.Name, build.Status.Phase, nextStatus)
	}
	return nil
}
Пример #14
0
// RunCancelBuild implements all the necessary functionality for CancelBuild.
func (o *CancelBuildOptions) RunCancelBuild() error {
	var builds []*buildapi.Build

	for _, name := range o.BuildNames {
		build, err := o.BuildClient.Get(name)
		if err != nil {
			o.ReportError(fmt.Errorf("build %s/%s not found", o.Namespace, name))
			continue
		}

		stateMatch := false
		for _, state := range o.States {
			if strings.ToLower(string(build.Status.Phase)) == state {
				stateMatch = true
				break
			}
		}
		if stateMatch && !buildutil.IsBuildComplete(build) {
			builds = append(builds, build)
		}
	}

	if o.DumpLogs {
		for _, b := range builds {
			// Do not attempt to get logs from build that was not scheduled.
			if b.Status.Phase == buildapi.BuildPhaseNew {
				continue
			}
			opts := buildapi.BuildLogOptions{NoWait: true}
			response, err := o.Client.BuildLogs(o.Namespace).Get(b.Name, opts).Do().Raw()
			if err != nil {
				o.ReportError(fmt.Errorf("unable to fetch logs for %s/%s: %v", b.Namespace, b.Name, err))
				continue
			}
			fmt.Fprintf(o.Out, "==== Build %s/%s logs ====\n", b.Namespace, b.Name)
			fmt.Fprint(o.Out, string(response))
		}
	}

	var wg sync.WaitGroup
	for _, b := range builds {
		wg.Add(1)
		go func(build *buildapi.Build) {
			defer wg.Done()
			err := wait.Poll(500*time.Millisecond, 30*time.Second, func() (bool, error) {
				build.Status.Cancelled = true
				_, err := o.BuildClient.Update(build)
				switch {
				case err == nil:
					return true, nil
				case kapierrors.IsConflict(err):
					build, err = o.BuildClient.Get(build.Name)
					return false, err
				}
				return true, err
			})
			if err != nil {
				o.ReportError(fmt.Errorf("build %s/%s failed to update: %v", build.Namespace, build.Name, err))
				return
			}

			// Make sure the build phase is really cancelled.
			err = wait.Poll(500*time.Millisecond, 30*time.Second, func() (bool, error) {
				updatedBuild, err := o.BuildClient.Get(build.Name)
				if err != nil {
					return true, err
				}
				return updatedBuild.Status.Phase == buildapi.BuildPhaseCancelled, nil
			})
			if err != nil {
				o.ReportError(fmt.Errorf("build %s/%s failed to cancel: %v", build.Namespace, build.Name, err))
				return
			}

			resource, name, _ := cmdutil.ResolveResource(buildapi.Resource("builds"), build.Name, o.Mapper)
			kcmdutil.PrintSuccess(o.Mapper, false, o.Out, resource.Resource, name, "cancelled")
		}(b)
	}
	wg.Wait()

	if o.Restart {
		for _, b := range builds {
			request := &buildapi.BuildRequest{ObjectMeta: kapi.ObjectMeta{Name: b.Name}}
			build, err := o.BuildClient.Clone(request)
			if err != nil {
				o.ReportError(fmt.Errorf("build %s/%s failed to restart: %v", b.Namespace, b.Name, err))
				continue
			}
			resource, name, _ := cmdutil.ResolveResource(buildapi.Resource("builds"), build.Name, o.Mapper)
			kcmdutil.PrintSuccess(o.Mapper, false, o.Out, resource.Resource, name, fmt.Sprintf("restarted build %q", b.Name))
		}
	}

	if o.HasError {
		return errors.New("failure during the build cancellation")
	}

	return nil
}