mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 15:25:57 +00:00
Adding more fields to PodCondition
This commit is contained in:
parent
0f8cc8926f
commit
6523ec142b
@ -13137,6 +13137,18 @@
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "Status is the status of the condition. Can be True, False, Unknown. More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#pod-conditions"
|
||||
},
|
||||
"lastProbeTime": {
|
||||
"type": "string"
|
||||
},
|
||||
"lastTransitionTime": {
|
||||
"type": "string"
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1344,6 +1344,14 @@ func deepCopy_api_PodAttachOptions(in PodAttachOptions, out *PodAttachOptions, c
|
||||
func deepCopy_api_PodCondition(in PodCondition, out *PodCondition, c *conversion.Cloner) error {
|
||||
out.Type = in.Type
|
||||
out.Status = in.Status
|
||||
if err := deepCopy_unversioned_Time(in.LastProbeTime, &out.LastProbeTime, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deepCopy_unversioned_Time(in.LastTransitionTime, &out.LastTransitionTime, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Reason = in.Reason
|
||||
out.Message = in.Message
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -68,10 +68,22 @@ func GetExistingContainerStatus(statuses []ContainerStatus, name string) Contain
|
||||
|
||||
// IsPodReady retruns true if a pod is ready; false otherwise.
|
||||
func IsPodReady(pod *Pod) bool {
|
||||
for _, c := range pod.Status.Conditions {
|
||||
if c.Type == PodReady && c.Status == ConditionTrue {
|
||||
return true
|
||||
return IsPodReadyConditionTrue(pod.Status)
|
||||
}
|
||||
|
||||
// IsPodReady retruns true if a pod is ready; false otherwise.
|
||||
func IsPodReadyConditionTrue(status PodStatus) bool {
|
||||
condition := GetPodReadyCondition(status)
|
||||
return condition != nil && condition.Status == ConditionTrue
|
||||
}
|
||||
|
||||
// Extracts the pod ready condition from the given status and returns that.
|
||||
// Returns nil if the condition is not present.
|
||||
func GetPodReadyCondition(status PodStatus) *PodCondition {
|
||||
for _, c := range status.Conditions {
|
||||
if c.Type == PodReady {
|
||||
return &c
|
||||
}
|
||||
}
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
|
@ -883,10 +883,13 @@ const (
|
||||
PodReady PodConditionType = "Ready"
|
||||
)
|
||||
|
||||
// TODO: add LastTransitionTime, Reason, Message to match NodeCondition api.
|
||||
type PodCondition struct {
|
||||
Type PodConditionType `json:"type"`
|
||||
Status ConditionStatus `json:"status"`
|
||||
Type PodConditionType `json:"type"`
|
||||
Status ConditionStatus `json:"status"`
|
||||
LastProbeTime unversioned.Time `json:"lastProbeTime,omitempty"`
|
||||
LastTransitionTime unversioned.Time `json:"lastTransitionTime,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// RestartPolicy describes how the container should be restarted.
|
||||
|
@ -1550,6 +1550,14 @@ func convert_api_PodCondition_To_v1_PodCondition(in *api.PodCondition, out *PodC
|
||||
}
|
||||
out.Type = PodConditionType(in.Type)
|
||||
out.Status = ConditionStatus(in.Status)
|
||||
if err := s.Convert(&in.LastProbeTime, &out.LastProbeTime, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.LastTransitionTime, &out.LastTransitionTime, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Reason = in.Reason
|
||||
out.Message = in.Message
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -3912,6 +3920,14 @@ func convert_v1_PodCondition_To_api_PodCondition(in *PodCondition, out *api.PodC
|
||||
}
|
||||
out.Type = api.PodConditionType(in.Type)
|
||||
out.Status = api.ConditionStatus(in.Status)
|
||||
if err := s.Convert(&in.LastProbeTime, &out.LastProbeTime, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Convert(&in.LastTransitionTime, &out.LastTransitionTime, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Reason = in.Reason
|
||||
out.Message = in.Message
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1364,6 +1364,14 @@ func deepCopy_v1_PodAttachOptions(in PodAttachOptions, out *PodAttachOptions, c
|
||||
func deepCopy_v1_PodCondition(in PodCondition, out *PodCondition, c *conversion.Cloner) error {
|
||||
out.Type = in.Type
|
||||
out.Status = in.Status
|
||||
if err := deepCopy_unversioned_Time(in.LastProbeTime, &out.LastProbeTime, c); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deepCopy_unversioned_Time(in.LastTransitionTime, &out.LastTransitionTime, c); err != nil {
|
||||
return err
|
||||
}
|
||||
out.Reason = in.Reason
|
||||
out.Message = in.Message
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1102,7 +1102,6 @@ const (
|
||||
)
|
||||
|
||||
// PodCondition contains details for the current condition of this pod.
|
||||
// TODO: add LastTransitionTime, Reason, Message to match NodeCondition api.
|
||||
type PodCondition struct {
|
||||
// Type is the type of the condition.
|
||||
// Currently only Ready.
|
||||
@ -1112,6 +1111,14 @@ type PodCondition struct {
|
||||
// Can be True, False, Unknown.
|
||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/pod-states.md#pod-conditions
|
||||
Status ConditionStatus `json:"status"`
|
||||
// Last time we probed the condition.
|
||||
LastProbeTime unversioned.Time `json:"lastProbeTime,omitempty"`
|
||||
// Last time the condition transitioned from one status to another.
|
||||
LastTransitionTime unversioned.Time `json:"lastTransitionTime,omitempty"`
|
||||
// Unique, one-word, CamelCase reason for the condition's last transition.
|
||||
Reason string `json:"reason,omitempty"`
|
||||
// Human-readable message indicating details about last transition.
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// RestartPolicy describes how the container should be restarted.
|
||||
|
@ -2126,29 +2126,65 @@ func GetPhase(spec *api.PodSpec, info []api.ContainerStatus) api.PodPhase {
|
||||
}
|
||||
}
|
||||
|
||||
// getPodReadyCondition returns ready condition if all containers in a pod are ready, else it returns an notReady condition.
|
||||
func getPodReadyCondition(spec *api.PodSpec, statuses []api.ContainerStatus) []api.PodCondition {
|
||||
ready := []api.PodCondition{{
|
||||
Type: api.PodReady,
|
||||
Status: api.ConditionTrue,
|
||||
}}
|
||||
notReady := []api.PodCondition{{
|
||||
Type: api.PodReady,
|
||||
Status: api.ConditionFalse,
|
||||
}}
|
||||
if statuses == nil {
|
||||
return notReady
|
||||
func readyPodCondition(isPodReady bool, reason, message string, existingStatus *api.PodStatus) []api.PodCondition {
|
||||
currentTime := unversioned.Now()
|
||||
condition := api.PodCondition{
|
||||
Type: api.PodReady,
|
||||
}
|
||||
for _, container := range spec.Containers {
|
||||
if containerStatus, ok := api.GetContainerStatus(statuses, container.Name); ok {
|
||||
if !containerStatus.Ready {
|
||||
return notReady
|
||||
}
|
||||
if isPodReady {
|
||||
condition.Status = api.ConditionTrue
|
||||
} else {
|
||||
condition.Status = api.ConditionFalse
|
||||
}
|
||||
condition.LastProbeTime = currentTime
|
||||
condition.Reason = reason
|
||||
condition.Message = message
|
||||
if existingStatus != nil {
|
||||
if api.IsPodReadyConditionTrue(*existingStatus) != isPodReady {
|
||||
// condition has transitioned, update transition time.
|
||||
condition.LastTransitionTime = currentTime
|
||||
} else {
|
||||
return notReady
|
||||
// retain the existing transition time.
|
||||
existingCondition := api.GetPodReadyCondition(*existingStatus)
|
||||
if existingCondition != nil {
|
||||
condition.LastTransitionTime = existingCondition.LastTransitionTime
|
||||
}
|
||||
}
|
||||
}
|
||||
return ready
|
||||
return []api.PodCondition{condition}
|
||||
}
|
||||
|
||||
// getPodReadyCondition returns ready condition if all containers in a pod are ready, else it returns an unready condition.
|
||||
func getPodReadyCondition(spec *api.PodSpec, containerStatuses []api.ContainerStatus, existingStatus *api.PodStatus) []api.PodCondition {
|
||||
// Find if all containers are ready or not.
|
||||
if containerStatuses == nil {
|
||||
return readyPodCondition(false, "UnknownContainerStatuses", "", existingStatus)
|
||||
}
|
||||
unknownContainers := []string{}
|
||||
unreadyContainers := []string{}
|
||||
for _, container := range spec.Containers {
|
||||
if containerStatus, ok := api.GetContainerStatus(containerStatuses, container.Name); ok {
|
||||
if !containerStatus.Ready {
|
||||
unreadyContainers = append(unreadyContainers, container.Name)
|
||||
}
|
||||
} else {
|
||||
unknownContainers = append(unknownContainers, container.Name)
|
||||
}
|
||||
}
|
||||
unreadyMessages := []string{}
|
||||
if len(unknownContainers) > 0 {
|
||||
unreadyMessages = append(unreadyMessages, fmt.Sprintf("containers with unknown status: %s", unknownContainers))
|
||||
}
|
||||
if len(unreadyContainers) > 0 {
|
||||
unreadyMessages = append(unreadyMessages, fmt.Sprintf("containers with unready status: %s", unreadyContainers))
|
||||
}
|
||||
unreadyMessage := strings.Join(unreadyMessages, ", ")
|
||||
if unreadyMessage != "" {
|
||||
// return unready status.
|
||||
return readyPodCondition(false, fmt.Sprint("ContainersNotReady"), unreadyMessage, existingStatus)
|
||||
}
|
||||
// return ready status.
|
||||
return readyPodCondition(true, "", "", existingStatus)
|
||||
}
|
||||
|
||||
// By passing the pod directly, this method avoids pod lookup, which requires
|
||||
@ -2162,8 +2198,8 @@ func (kl *Kubelet) generatePodStatus(pod *api.Pod) (api.PodStatus, error) {
|
||||
|
||||
podFullName := kubecontainer.GetPodFullName(pod)
|
||||
glog.V(3).Infof("Generating status for %q", podFullName)
|
||||
|
||||
if existingStatus, ok := kl.statusManager.GetPodStatus(pod.UID); ok {
|
||||
existingStatus, hasExistingStatus := kl.statusManager.GetPodStatus(pod.UID)
|
||||
if hasExistingStatus {
|
||||
// This is a hacky fix to ensure container restart counts increment
|
||||
// monotonically. Normally, we should not modify given pod. In this
|
||||
// case, we check if there are cached status for this pod, and update
|
||||
@ -2215,8 +2251,11 @@ func (kl *Kubelet) generatePodStatus(pod *api.Pod) (api.PodStatus, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
podStatus.Conditions = append(podStatus.Conditions, getPodReadyCondition(spec, podStatus.ContainerStatuses)...)
|
||||
if hasExistingStatus {
|
||||
podStatus.Conditions = append(podStatus.Conditions, getPodReadyCondition(spec, podStatus.ContainerStatuses, &existingStatus)...)
|
||||
} else {
|
||||
podStatus.Conditions = append(podStatus.Conditions, getPodReadyCondition(spec, podStatus.ContainerStatuses, nil)...)
|
||||
}
|
||||
|
||||
if !kl.standaloneMode {
|
||||
hostIP, err := kl.nodeManager.GetHostIP()
|
||||
|
@ -1732,30 +1732,47 @@ func getNotReadyStatus(cName string) api.ContainerStatus {
|
||||
Ready: false,
|
||||
}
|
||||
}
|
||||
func getReadyCondition(status api.ConditionStatus, transitionTime unversioned.Time, reason, message string) []api.PodCondition {
|
||||
return []api.PodCondition{{
|
||||
Type: api.PodReady,
|
||||
Status: status,
|
||||
LastTransitionTime: transitionTime,
|
||||
Reason: reason,
|
||||
Message: message,
|
||||
}}
|
||||
}
|
||||
|
||||
func TestGetPodReadyCondition(t *testing.T) {
|
||||
ready := []api.PodCondition{{
|
||||
Type: api.PodReady,
|
||||
Status: api.ConditionTrue,
|
||||
}}
|
||||
notReady := []api.PodCondition{{
|
||||
Type: api.PodReady,
|
||||
Status: api.ConditionFalse,
|
||||
}}
|
||||
transitionTime := unversioned.Now()
|
||||
tests := []struct {
|
||||
spec *api.PodSpec
|
||||
info []api.ContainerStatus
|
||||
expected []api.PodCondition
|
||||
spec *api.PodSpec
|
||||
containerStatuses []api.ContainerStatus
|
||||
existingStatus *api.PodStatus
|
||||
expected []api.PodCondition
|
||||
clearTimestamp bool
|
||||
}{
|
||||
{
|
||||
spec: nil,
|
||||
info: nil,
|
||||
expected: notReady,
|
||||
spec: nil,
|
||||
containerStatuses: nil,
|
||||
existingStatus: nil,
|
||||
expected: getReadyCondition(api.ConditionFalse, transitionTime, "UnknownContainerStatuses", ""),
|
||||
clearTimestamp: true,
|
||||
},
|
||||
{
|
||||
spec: &api.PodSpec{},
|
||||
info: []api.ContainerStatus{},
|
||||
expected: ready,
|
||||
spec: nil,
|
||||
containerStatuses: nil,
|
||||
existingStatus: &api.PodStatus{
|
||||
Conditions: getReadyCondition(api.ConditionFalse, transitionTime, "", ""),
|
||||
},
|
||||
expected: getReadyCondition(api.ConditionFalse, transitionTime, "UnknownContainerStatuses", ""),
|
||||
clearTimestamp: false,
|
||||
},
|
||||
{
|
||||
spec: &api.PodSpec{},
|
||||
containerStatuses: []api.ContainerStatus{},
|
||||
existingStatus: nil,
|
||||
expected: getReadyCondition(api.ConditionTrue, transitionTime, "", ""),
|
||||
clearTimestamp: true,
|
||||
},
|
||||
{
|
||||
spec: &api.PodSpec{
|
||||
@ -1763,8 +1780,10 @@ func TestGetPodReadyCondition(t *testing.T) {
|
||||
{Name: "1234"},
|
||||
},
|
||||
},
|
||||
info: []api.ContainerStatus{},
|
||||
expected: notReady,
|
||||
containerStatuses: []api.ContainerStatus{},
|
||||
existingStatus: nil,
|
||||
expected: getReadyCondition(api.ConditionFalse, transitionTime, "ContainersNotReady", "containers with unknown status: [1234]"),
|
||||
clearTimestamp: true,
|
||||
},
|
||||
{
|
||||
spec: &api.PodSpec{
|
||||
@ -1772,10 +1791,12 @@ func TestGetPodReadyCondition(t *testing.T) {
|
||||
{Name: "1234"},
|
||||
},
|
||||
},
|
||||
info: []api.ContainerStatus{
|
||||
containerStatuses: []api.ContainerStatus{
|
||||
getReadyStatus("1234"),
|
||||
},
|
||||
expected: ready,
|
||||
existingStatus: nil,
|
||||
expected: getReadyCondition(api.ConditionTrue, transitionTime, "", ""),
|
||||
clearTimestamp: true,
|
||||
},
|
||||
{
|
||||
spec: &api.PodSpec{
|
||||
@ -1784,11 +1805,13 @@ func TestGetPodReadyCondition(t *testing.T) {
|
||||
{Name: "5678"},
|
||||
},
|
||||
},
|
||||
info: []api.ContainerStatus{
|
||||
containerStatuses: []api.ContainerStatus{
|
||||
getReadyStatus("1234"),
|
||||
getReadyStatus("5678"),
|
||||
},
|
||||
expected: ready,
|
||||
existingStatus: nil,
|
||||
expected: getReadyCondition(api.ConditionTrue, transitionTime, "", ""),
|
||||
clearTimestamp: true,
|
||||
},
|
||||
{
|
||||
spec: &api.PodSpec{
|
||||
@ -1797,10 +1820,12 @@ func TestGetPodReadyCondition(t *testing.T) {
|
||||
{Name: "5678"},
|
||||
},
|
||||
},
|
||||
info: []api.ContainerStatus{
|
||||
containerStatuses: []api.ContainerStatus{
|
||||
getReadyStatus("1234"),
|
||||
},
|
||||
expected: notReady,
|
||||
existingStatus: nil,
|
||||
expected: getReadyCondition(api.ConditionFalse, transitionTime, "ContainersNotReady", "containers with unknown status: [5678]"),
|
||||
clearTimestamp: true,
|
||||
},
|
||||
{
|
||||
spec: &api.PodSpec{
|
||||
@ -1809,16 +1834,22 @@ func TestGetPodReadyCondition(t *testing.T) {
|
||||
{Name: "5678"},
|
||||
},
|
||||
},
|
||||
info: []api.ContainerStatus{
|
||||
containerStatuses: []api.ContainerStatus{
|
||||
getReadyStatus("1234"),
|
||||
getNotReadyStatus("5678"),
|
||||
},
|
||||
expected: notReady,
|
||||
expected: getReadyCondition(api.ConditionFalse, transitionTime, "ContainersNotReady", "containers with unready status: [5678]"),
|
||||
clearTimestamp: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
condition := getPodReadyCondition(test.spec, test.info)
|
||||
condition := getPodReadyCondition(test.spec, test.containerStatuses, test.existingStatus)
|
||||
if test.clearTimestamp {
|
||||
condition[0].LastTransitionTime = transitionTime
|
||||
test.expected[0].LastTransitionTime = transitionTime
|
||||
}
|
||||
condition[0].LastProbeTime = unversioned.Time{}
|
||||
if !reflect.DeepEqual(condition, test.expected) {
|
||||
t.Errorf("On test case %v, expected:\n%+v\ngot\n%+v\n", i, test.expected, condition)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user