func deploymentRunning(dc *deployapi.DeploymentConfig, rcs []kapi.ReplicationController, pods []kapi.Pod) (bool, error) { if len(rcs) == 0 { return false, nil } rc := rcs[len(rcs)-1] version := deployutil.DeploymentVersionFor(&rc) if version != dc.Status.LatestVersion { //e2e.Logf("deployment %s is not the latest version on DC: %d", rc.Name, version) return false, nil } status := rc.Annotations[deployapi.DeploymentStatusAnnotation] switch deployapi.DeploymentStatus(status) { case deployapi.DeploymentStatusFailed: if deployutil.IsDeploymentCancelled(&rc) { return true, nil } reason := deployutil.DeploymentStatusReasonFor(&rc) if reason == "deployer pod no longer exists" { return true, nil } return false, fmt.Errorf("deployment failed: %v", deployutil.DeploymentStatusReasonFor(&rc)) case deployapi.DeploymentStatusRunning, deployapi.DeploymentStatusComplete: return true, nil default: return false, nil } }
func describeDeploymentStatus(deploy *kapi.ReplicationController, first, test bool) string { timeAt := strings.ToLower(formatRelativeTime(deploy.CreationTimestamp.Time)) status := deployutil.DeploymentStatusFor(deploy) version := deployutil.DeploymentVersionFor(deploy) maybeCancelling := "" if deployutil.IsDeploymentCancelled(deploy) && !deployutil.IsTerminatedDeployment(deploy) { maybeCancelling = " (cancelling)" } switch status { case deployapi.DeploymentStatusFailed: reason := deployutil.DeploymentStatusReasonFor(deploy) if len(reason) > 0 { reason = fmt.Sprintf(": %s", reason) } // TODO: encode fail time in the rc return fmt.Sprintf("deployment #%d failed %s ago%s%s", version, timeAt, reason, describePodSummaryInline(deploy, false)) case deployapi.DeploymentStatusComplete: // TODO: pod status output if test { return fmt.Sprintf("test deployment #%d deployed %s ago", version, timeAt) } return fmt.Sprintf("deployment #%d deployed %s ago%s", version, timeAt, describePodSummaryInline(deploy, first)) case deployapi.DeploymentStatusRunning: format := "deployment #%d running%s for %s%s" if test { format = "test deployment #%d running%s for %s%s" } return fmt.Sprintf(format, version, maybeCancelling, timeAt, describePodSummaryInline(deploy, false)) default: return fmt.Sprintf("deployment #%d %s%s %s ago%s", version, strings.ToLower(string(status)), maybeCancelling, timeAt, describePodSummaryInline(deploy, false)) } }
func describeDeploymentStatus(deploy *kapi.ReplicationController, first bool) string { timeAt := strings.ToLower(formatRelativeTime(deploy.CreationTimestamp.Time)) status := deployutil.DeploymentStatusFor(deploy) version := deployutil.DeploymentVersionFor(deploy) switch status { case deployapi.DeploymentStatusFailed: reason := deployutil.DeploymentStatusReasonFor(deploy) if len(reason) > 0 { reason = fmt.Sprintf(": %s", reason) } // TODO: encode fail time in the rc return fmt.Sprintf("#%d deployment failed %s ago%s%s", version, timeAt, reason, describePodSummaryInline(deploy, false)) case deployapi.DeploymentStatusComplete: // TODO: pod status output return fmt.Sprintf("#%d deployed %s ago%s", version, timeAt, describePodSummaryInline(deploy, first)) case deployapi.DeploymentStatusRunning: return fmt.Sprintf("#%d deployment running for %s%s", version, timeAt, describePodSummaryInline(deploy, false)) default: return fmt.Sprintf("#%d deployment %s %s ago%s", version, strings.ToLower(string(status)), timeAt, describePodSummaryInline(deploy, false)) } }
// TestCmdDeploy_retryOk ensures that a failed deployment can be retried. func TestCmdDeploy_retryOk(t *testing.T) { deletedPods := []string{} config := deploytest.OkDeploymentConfig(1) var updatedDeployment *kapi.ReplicationController existingDeployment := deploymentFor(config, deployapi.DeploymentStatusFailed) existingDeployment.Annotations[deployapi.DeploymentCancelledAnnotation] = deployapi.DeploymentCancelledAnnotationValue existingDeployment.Annotations[deployapi.DeploymentStatusReasonAnnotation] = deployapi.DeploymentCancelledByUser mkpod := func(name string) kapi.Pod { return kapi.Pod{ ObjectMeta: kapi.ObjectMeta{ Name: name, Labels: map[string]string{ deployapi.DeployerPodForDeploymentLabel: existingDeployment.Name, }, }, } } existingDeployerPods := []kapi.Pod{ mkpod("prehook"), mkpod("posthook"), mkpod("deployerpod"), } kubeClient := &ktc.Fake{} kubeClient.AddReactor("get", "replicationcontrollers", func(action ktc.Action) (handled bool, ret runtime.Object, err error) { return true, existingDeployment, nil }) kubeClient.AddReactor("update", "replicationcontrollers", func(action ktc.Action) (handled bool, ret runtime.Object, err error) { updatedDeployment = action.(ktc.UpdateAction).GetObject().(*kapi.ReplicationController) return true, updatedDeployment, nil }) kubeClient.AddReactor("list", "pods", func(action ktc.Action) (handled bool, ret runtime.Object, err error) { return true, &kapi.PodList{Items: existingDeployerPods}, nil }) kubeClient.AddReactor("delete", "pods", func(action ktc.Action) (handled bool, ret runtime.Object, err error) { deletedPods = append(deletedPods, action.(ktc.DeleteAction).GetName()) return true, nil, nil }) o := &DeployOptions{kubeClient: kubeClient} err := o.retry(config, ioutil.Discard) if err != nil { t.Fatalf("unexpected error: %v", err) } if updatedDeployment == nil { t.Fatalf("expected updated config") } if deployutil.IsDeploymentCancelled(updatedDeployment) { t.Fatalf("deployment should not have the cancelled flag set anymore") } if deployutil.DeploymentStatusReasonFor(updatedDeployment) != "" { t.Fatalf("deployment status reason should be empty") } sort.Strings(deletedPods) expectedDeletions := []string{"deployerpod", "posthook", "prehook"} if e, a := expectedDeletions, deletedPods; !reflect.DeepEqual(e, a) { t.Fatalf("Not all deployer pods for the failed deployment were deleted.\nEXPECTED: %v\nACTUAL: %v", e, a) } if e, a := deployapi.DeploymentStatusNew, deployutil.DeploymentStatusFor(updatedDeployment); e != a { t.Fatalf("expected deployment status %s, got %s", e, a) } }
// TestCmdDeploy_retryOk ensures that a failed deployment can be retried. func TestCmdDeploy_retryOk(t *testing.T) { deletedPods := []string{} config := deploytest.OkDeploymentConfig(1) var updatedDeployment *kapi.ReplicationController existingDeployment := deploymentFor(config, deployapi.DeploymentStatusFailed) existingDeployment.Annotations[deployapi.DeploymentCancelledAnnotation] = deployapi.DeploymentCancelledAnnotationValue existingDeployment.Annotations[deployapi.DeploymentStatusReasonAnnotation] = deployapi.DeploymentCancelledByUser existingDeployerPods := []kapi.Pod{ {ObjectMeta: kapi.ObjectMeta{Name: "prehook"}}, {ObjectMeta: kapi.ObjectMeta{Name: "posthook"}}, {ObjectMeta: kapi.ObjectMeta{Name: "deployerpod"}}, } kubeClient := &ktc.Fake{} kubeClient.ReactFn = func(action ktc.Action) (runtime.Object, error) { switch a := action.(type) { case ktc.GetActionImpl: return existingDeployment, nil case ktc.UpdateActionImpl: updatedDeployment = a.GetObject().(*kapi.ReplicationController) return updatedDeployment, nil case ktc.ListActionImpl: return &kapi.PodList{Items: existingDeployerPods}, nil case ktc.DeleteActionImpl: deletedPods = append(deletedPods, a.GetName()) return nil, nil } t.Fatalf("unexpected action: %+v", action) return nil, nil } o := &DeployOptions{kubeClient: kubeClient} err := o.retry(config, ioutil.Discard) if err != nil { t.Fatalf("unexpected error: %v", err) } if updatedDeployment == nil { t.Fatalf("expected updated config") } if deployutil.IsDeploymentCancelled(updatedDeployment) { t.Fatalf("deployment should not have the cancelled flag set anymore") } if deployutil.DeploymentStatusReasonFor(updatedDeployment) != "" { t.Fatalf("deployment status reason should be empty") } sort.Strings(deletedPods) expectedDeletions := []string{"deployerpod", "posthook", "prehook"} if e, a := expectedDeletions, deletedPods; !reflect.DeepEqual(e, a) { t.Fatalf("Not all deployer pods for the failed deployment were deleted.\nEXPECTED: %v\nACTUAL: %v", e, a) } if e, a := deployapi.DeploymentStatusNew, deployutil.DeploymentStatusFor(updatedDeployment); e != a { t.Fatalf("expected deployment status %s, got %s", e, a) } }
// TestCmdDeploy_retryOk ensures that a failed deployment can be retried. func TestCmdDeploy_retryOk(t *testing.T) { deletedPods := []string{} config := deploytest.OkDeploymentConfig(1) existingDeployment := deploymentFor(config, deployapi.DeploymentStatusFailed) existingDeployment.Annotations[deployapi.DeploymentCancelledAnnotation] = deployapi.DeploymentCancelledAnnotationValue existingDeployment.Annotations[deployapi.DeploymentStatusReasonAnnotation] = deployapi.DeploymentCancelledByUser existingDeployerPods := []kapi.Pod{ {ObjectMeta: kapi.ObjectMeta{Name: "prehook"}}, {ObjectMeta: kapi.ObjectMeta{Name: "posthook"}}, {ObjectMeta: kapi.ObjectMeta{Name: "deployerpod"}}, } var updatedDeployment *kapi.ReplicationController commandClient := &deployCommandClientImpl{ GetDeploymentFn: func(namespace, name string) (*kapi.ReplicationController, error) { return existingDeployment, nil }, UpdateDeploymentConfigFn: func(config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) { t.Fatalf("unexpected call to UpdateDeploymentConfig") return nil, nil }, UpdateDeploymentFn: func(deployment *kapi.ReplicationController) (*kapi.ReplicationController, error) { updatedDeployment = deployment return deployment, nil }, ListDeployerPodsForFn: func(namespace, name string) (*kapi.PodList, error) { return &kapi.PodList{Items: existingDeployerPods}, nil }, DeletePodFn: func(pod *kapi.Pod) error { deletedPods = append(deletedPods, pod.Name) return nil }, } c := &retryDeploymentCommand{client: commandClient} err := c.retry(config, ioutil.Discard) if err != nil { t.Fatalf("unexpected error: %v", err) } if updatedDeployment == nil { t.Fatalf("expected updated config") } if deployutil.IsDeploymentCancelled(updatedDeployment) { t.Fatalf("deployment should not have the cancelled flag set anymore") } if deployutil.DeploymentStatusReasonFor(updatedDeployment) != "" { t.Fatalf("deployment status reason should be empty") } sort.Strings(deletedPods) if !reflect.DeepEqual(deletedPods, []string{"deployerpod", "posthook", "prehook"}) { t.Fatalf("Not all deployer pods for the failed deployment were deleted") } if e, a := deployapi.DeploymentStatusNew, deployutil.DeploymentStatusFor(updatedDeployment); e != a { t.Fatalf("expected deployment status %s, got %s", e, a) } }