From fb1679e6acc6882bf25599890d1b23664a8d6548 Mon Sep 17 00:00:00 2001 From: Michal Fojtik Date: Thu, 14 Sep 2017 14:33:35 +0200 Subject: [PATCH] apps: record cause of rollout and deployer pods timestamps back to rc --- pkg/apps/apis/apps/types.go | 11 ++++++++ .../deployer/deployer_controller.go | 27 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/pkg/apps/apis/apps/types.go b/pkg/apps/apis/apps/types.go index 1f96ec3beb78..58338278ce2e 100644 --- a/pkg/apps/apis/apps/types.go +++ b/pkg/apps/apis/apps/types.go @@ -37,6 +37,17 @@ const ( // annotation value is the name of the deployer Pod which will act upon the ReplicationController // to implement the deployment behavior. DeploymentPodAnnotation = "openshift.io/deployer-pod.name" + // DeployerPodCreatedAtAnnotation is an annotation on a deployment that + // records the time in RFC3339 format of when the deployer pod for this particular + // deployment was created. + DeployerPodCreatedAtAnnotation = "openshift.io/deployer-pod.created-at" + // DeployerPodStartedAtAnnotation is an annotation on a deployment that + // records the time in RFC3339 format of when the deployer pod for this particular + // deployment was started. + DeployerPodStartedAtAnnotation = "openshift.io/deployer-pod.started-at" + // DeployerPodCompletedAtAnnotation is an annotation on deployment that records + // the time in RFC3339 format of when the deployer pod finished. + DeployerPodCompletedAtAnnotation = "openshift.io/deployer-pod.completed-at" // DeploymentIgnorePodAnnotation is an annotation on a deployment config that will bypass creating // a deployment pod with the deployment. The caller is responsible for setting the deployment // status and running the deployment process. diff --git a/pkg/apps/controller/deployer/deployer_controller.go b/pkg/apps/controller/deployer/deployer_controller.go index 40769d756d13..349def5be22b 100755 --- a/pkg/apps/controller/deployer/deployer_controller.go +++ b/pkg/apps/controller/deployer/deployer_controller.go @@ -149,6 +149,10 @@ func (c *DeploymentController) handle(deployment *v1.ReplicationController, will return actionableError(fmt.Sprintf("couldn't create deployer pod for %q: %v", deployutil.LabelForDeploymentV1(deployment), err)) } updatedAnnotations[deployapi.DeploymentPodAnnotation] = deploymentPod.Name + updatedAnnotations[deployapi.DeployerPodCreatedAtAnnotation] = deploymentPod.CreationTimestamp.String() + if deploymentPod.Status.StartTime != nil { + updatedAnnotations[deployapi.DeployerPodStartedAtAnnotation] = deploymentPod.Status.StartTime.String() + } nextStatus = deployapi.DeploymentStatusPending glog.V(4).Infof("Created deployer pod %q for %q", deploymentPod.Name, deployutil.LabelForDeploymentV1(deployment)) @@ -176,6 +180,10 @@ func (c *DeploymentController) handle(deployment *v1.ReplicationController, will } else { // Update to pending or to the appropriate status relative to the existing validated deployer pod. updatedAnnotations[deployapi.DeploymentPodAnnotation] = deployer.Name + updatedAnnotations[deployapi.DeployerPodCreatedAtAnnotation] = deployer.CreationTimestamp.String() + if deployer.Status.StartTime != nil { + updatedAnnotations[deployapi.DeployerPodStartedAtAnnotation] = deployer.Status.StartTime.String() + } nextStatus = nextStatusComp(nextStatus, deployapi.DeploymentStatusPending) } } @@ -293,16 +301,35 @@ func (c *DeploymentController) nextStatus(pod *v1.Pod, deployment *v1.Replicatio } // Sync the internal replica annotation with the target so that we can // distinguish deployer updates from other scaling events. + completedTimestamp := getPodTerminatedTimestamp(pod) + if completedTimestamp != nil { + updatedAnnotations[deployapi.DeployerPodCompletedAtAnnotation] = completedTimestamp.String() + } updatedAnnotations[deployapi.DeploymentReplicasAnnotation] = updatedAnnotations[deployapi.DesiredReplicasAnnotation] delete(updatedAnnotations, deployapi.DesiredReplicasAnnotation) return deployapi.DeploymentStatusComplete case v1.PodFailed: + completedTimestamp := getPodTerminatedTimestamp(pod) + if completedTimestamp != nil { + updatedAnnotations[deployapi.DeployerPodCompletedAtAnnotation] = completedTimestamp.String() + } return deployapi.DeploymentStatusFailed } return deployapi.DeploymentStatusNew } +// getPodTerminatedTimestamp gets the first terminated container in a pod and +// return its termination timestamp. +func getPodTerminatedTimestamp(pod *v1.Pod) *metav1.Time { + for _, c := range pod.Status.ContainerStatuses { + if t := c.State.Terminated; t != nil { + return &t.FinishedAt + } + } + return nil +} + func nextStatusComp(fromDeployer, fromPath deployapi.DeploymentStatus) deployapi.DeploymentStatus { if deployutil.CanTransitionPhase(fromPath, fromDeployer) { return fromDeployer