// 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) } }