mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-07 11:13:48 +00:00
Sidecar: Update printPod to show restartable init container information
This commit is contained in:
parent
ea1eb7f8f7
commit
0a98707912
@ -815,9 +815,11 @@ func printPodList(podList *api.PodList, options printers.GenerateOptions) ([]met
|
|||||||
|
|
||||||
func printPod(pod *api.Pod, options printers.GenerateOptions) ([]metav1.TableRow, error) {
|
func printPod(pod *api.Pod, options printers.GenerateOptions) ([]metav1.TableRow, error) {
|
||||||
restarts := 0
|
restarts := 0
|
||||||
|
restartableInitContainerRestarts := 0
|
||||||
totalContainers := len(pod.Spec.Containers)
|
totalContainers := len(pod.Spec.Containers)
|
||||||
readyContainers := 0
|
readyContainers := 0
|
||||||
lastRestartDate := metav1.NewTime(time.Time{})
|
lastRestartDate := metav1.NewTime(time.Time{})
|
||||||
|
lastRestartableInitContainerRestartDate := metav1.NewTime(time.Time{})
|
||||||
|
|
||||||
reason := string(pod.Status.Phase)
|
reason := string(pod.Status.Phase)
|
||||||
if pod.Status.Reason != "" {
|
if pod.Status.Reason != "" {
|
||||||
@ -842,6 +844,14 @@ func printPod(pod *api.Pod, options printers.GenerateOptions) ([]metav1.TableRow
|
|||||||
row.Conditions = podFailedConditions
|
row.Conditions = podFailedConditions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initContainers := make(map[string]*api.Container)
|
||||||
|
for i := range pod.Spec.InitContainers {
|
||||||
|
initContainers[pod.Spec.InitContainers[i].Name] = &pod.Spec.InitContainers[i]
|
||||||
|
if isRestartableInitContainer(&pod.Spec.InitContainers[i]) {
|
||||||
|
totalContainers++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
initializing := false
|
initializing := false
|
||||||
for i := range pod.Status.InitContainerStatuses {
|
for i := range pod.Status.InitContainerStatuses {
|
||||||
container := pod.Status.InitContainerStatuses[i]
|
container := pod.Status.InitContainerStatuses[i]
|
||||||
@ -852,9 +862,24 @@ func printPod(pod *api.Pod, options printers.GenerateOptions) ([]metav1.TableRow
|
|||||||
lastRestartDate = terminatedDate
|
lastRestartDate = terminatedDate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if isRestartableInitContainer(initContainers[container.Name]) {
|
||||||
|
restartableInitContainerRestarts += int(container.RestartCount)
|
||||||
|
if container.LastTerminationState.Terminated != nil {
|
||||||
|
terminatedDate := container.LastTerminationState.Terminated.FinishedAt
|
||||||
|
if lastRestartableInitContainerRestartDate.Before(&terminatedDate) {
|
||||||
|
lastRestartableInitContainerRestartDate = terminatedDate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
switch {
|
switch {
|
||||||
case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0:
|
case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0:
|
||||||
continue
|
continue
|
||||||
|
case isRestartableInitContainer(initContainers[container.Name]) &&
|
||||||
|
container.Started != nil && *container.Started:
|
||||||
|
if container.Ready {
|
||||||
|
readyContainers++
|
||||||
|
}
|
||||||
|
continue
|
||||||
case container.State.Terminated != nil:
|
case container.State.Terminated != nil:
|
||||||
// initialization is failed
|
// initialization is failed
|
||||||
if len(container.State.Terminated.Reason) == 0 {
|
if len(container.State.Terminated.Reason) == 0 {
|
||||||
@ -876,8 +901,10 @@ func printPod(pod *api.Pod, options printers.GenerateOptions) ([]metav1.TableRow
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if !initializing {
|
|
||||||
restarts = 0
|
if !initializing || isPodInitializedConditionTrue(&pod.Status) {
|
||||||
|
restarts = restartableInitContainerRestarts
|
||||||
|
lastRestartDate = lastRestartableInitContainerRestartDate
|
||||||
hasRunning := false
|
hasRunning := false
|
||||||
for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- {
|
for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- {
|
||||||
container := pod.Status.ContainerStatuses[i]
|
container := pod.Status.ContainerStatuses[i]
|
||||||
@ -922,7 +949,7 @@ func printPod(pod *api.Pod, options printers.GenerateOptions) ([]metav1.TableRow
|
|||||||
}
|
}
|
||||||
|
|
||||||
restartsStr := strconv.Itoa(restarts)
|
restartsStr := strconv.Itoa(restarts)
|
||||||
if !lastRestartDate.IsZero() {
|
if restarts != 0 && !lastRestartDate.IsZero() {
|
||||||
restartsStr = fmt.Sprintf("%d (%s ago)", restarts, translateTimestampSince(lastRestartDate))
|
restartsStr = fmt.Sprintf("%d (%s ago)", restarts, translateTimestampSince(lastRestartDate))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2996,3 +3023,22 @@ func (list SortableResourceNames) Swap(i, j int) {
|
|||||||
func (list SortableResourceNames) Less(i, j int) bool {
|
func (list SortableResourceNames) Less(i, j int) bool {
|
||||||
return list[i] < list[j]
|
return list[i] < list[j]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isRestartableInitContainer(initContainer *api.Container) bool {
|
||||||
|
if initContainer.RestartPolicy == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return *initContainer.RestartPolicy == api.ContainerRestartPolicyAlways
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPodInitializedConditionTrue(status *api.PodStatus) bool {
|
||||||
|
for _, condition := range status.Conditions {
|
||||||
|
if condition.Type != api.PodInitialized {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return condition.Status == api.ConditionTrue
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -50,6 +50,8 @@ import (
|
|||||||
utilpointer "k8s.io/utils/pointer"
|
utilpointer "k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var containerRestartPolicyAlways = api.ContainerRestartPolicyAlways
|
||||||
|
|
||||||
func TestFormatResourceName(t *testing.T) {
|
func TestFormatResourceName(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
kind schema.GroupKind
|
kind schema.GroupKind
|
||||||
@ -1536,6 +1538,200 @@ func TestPrintPod(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrintPodWithRestartableInitContainer(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
pod api.Pod
|
||||||
|
expect []metav1.TableRow
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// Test pod has 2 restartable init containers, the first one running but not started.
|
||||||
|
api.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "test1"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
InitContainers: []api.Container{
|
||||||
|
{Name: "restartable-init-1", RestartPolicy: &containerRestartPolicyAlways},
|
||||||
|
{Name: "restartable-init-2", RestartPolicy: &containerRestartPolicyAlways},
|
||||||
|
}, Containers: make([]api.Container, 1)},
|
||||||
|
Status: api.PodStatus{
|
||||||
|
Phase: "Pending",
|
||||||
|
InitContainerStatuses: []api.ContainerStatus{
|
||||||
|
{
|
||||||
|
Name: "restartable-init-1",
|
||||||
|
Ready: false,
|
||||||
|
RestartCount: 3,
|
||||||
|
State: api.ContainerState{Running: &api.ContainerStateRunning{}},
|
||||||
|
Started: utilpointer.Bool(false),
|
||||||
|
LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "restartable-init-2",
|
||||||
|
Ready: false,
|
||||||
|
State: api.ContainerState{Waiting: &api.ContainerStateWaiting{}},
|
||||||
|
Started: utilpointer.Bool(false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ContainerStatuses: []api.ContainerStatus{
|
||||||
|
{
|
||||||
|
Ready: false,
|
||||||
|
RestartCount: 0,
|
||||||
|
State: api.ContainerState{Waiting: &api.ContainerStateWaiting{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Conditions: []api.PodCondition{
|
||||||
|
{Type: api.PodInitialized, Status: api.ConditionFalse},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]metav1.TableRow{{Cells: []interface{}{"test1", "0/3", "Init:0/2", "3 (10s ago)", "<unknown>"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Test pod has 2 restartable init containers, the first one started and the second one running but not started.
|
||||||
|
api.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "test1"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
InitContainers: []api.Container{
|
||||||
|
{Name: "restartable-init-1", RestartPolicy: &containerRestartPolicyAlways},
|
||||||
|
{Name: "restartable-init-2", RestartPolicy: &containerRestartPolicyAlways},
|
||||||
|
}, Containers: make([]api.Container, 1)},
|
||||||
|
Status: api.PodStatus{
|
||||||
|
Phase: "Pending",
|
||||||
|
InitContainerStatuses: []api.ContainerStatus{
|
||||||
|
{
|
||||||
|
Name: "restartable-init-1",
|
||||||
|
Ready: false,
|
||||||
|
RestartCount: 3,
|
||||||
|
State: api.ContainerState{Running: &api.ContainerStateRunning{}},
|
||||||
|
Started: utilpointer.Bool(true),
|
||||||
|
LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "restartable-init-2",
|
||||||
|
Ready: false,
|
||||||
|
State: api.ContainerState{Running: &api.ContainerStateRunning{}},
|
||||||
|
Started: utilpointer.Bool(false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ContainerStatuses: []api.ContainerStatus{
|
||||||
|
{
|
||||||
|
Ready: false,
|
||||||
|
RestartCount: 0,
|
||||||
|
State: api.ContainerState{Waiting: &api.ContainerStateWaiting{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Conditions: []api.PodCondition{
|
||||||
|
{Type: api.PodInitialized, Status: api.ConditionFalse},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]metav1.TableRow{{Cells: []interface{}{"test1", "0/3", "Init:1/2", "3 (10s ago)", "<unknown>"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Test pod has 2 restartable init containers started and 1 container running
|
||||||
|
api.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "test2"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
InitContainers: []api.Container{
|
||||||
|
{Name: "restartable-init-1", RestartPolicy: &containerRestartPolicyAlways},
|
||||||
|
{Name: "restartable-init-2", RestartPolicy: &containerRestartPolicyAlways},
|
||||||
|
}, Containers: make([]api.Container, 1)},
|
||||||
|
Status: api.PodStatus{
|
||||||
|
Phase: "Running",
|
||||||
|
InitContainerStatuses: []api.ContainerStatus{
|
||||||
|
{
|
||||||
|
Name: "restartable-init-1",
|
||||||
|
Ready: false,
|
||||||
|
RestartCount: 3,
|
||||||
|
State: api.ContainerState{Running: &api.ContainerStateRunning{}},
|
||||||
|
Started: utilpointer.Bool(true),
|
||||||
|
LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "restartable-init-2",
|
||||||
|
Ready: false,
|
||||||
|
State: api.ContainerState{Running: &api.ContainerStateRunning{}},
|
||||||
|
Started: utilpointer.Bool(true),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ContainerStatuses: []api.ContainerStatus{
|
||||||
|
{
|
||||||
|
Ready: true,
|
||||||
|
RestartCount: 4,
|
||||||
|
State: api.ContainerState{Running: &api.ContainerStateRunning{}},
|
||||||
|
LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-20 * time.Second))}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Conditions: []api.PodCondition{
|
||||||
|
{Type: api.PodInitialized, Status: api.ConditionTrue},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]metav1.TableRow{{Cells: []interface{}{"test2", "1/3", "Running", "7 (10s ago)", "<unknown>"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Test pod has 2 restartable init containers completed with non-zero and 1 container completed
|
||||||
|
api.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "test3"},
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
InitContainers: []api.Container{
|
||||||
|
{Name: "restartable-init-1", RestartPolicy: &containerRestartPolicyAlways},
|
||||||
|
{Name: "restartable-init-2", RestartPolicy: &containerRestartPolicyAlways},
|
||||||
|
}, Containers: make([]api.Container, 1)},
|
||||||
|
Status: api.PodStatus{
|
||||||
|
Phase: "Succeeded",
|
||||||
|
InitContainerStatuses: []api.ContainerStatus{
|
||||||
|
{
|
||||||
|
Name: "restartable-init-1",
|
||||||
|
Ready: false,
|
||||||
|
RestartCount: 3,
|
||||||
|
State: api.ContainerState{Terminated: &api.ContainerStateTerminated{Reason: "Error", ExitCode: 137}},
|
||||||
|
Started: utilpointer.Bool(false),
|
||||||
|
LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-10 * time.Second))}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "restartable-init-2",
|
||||||
|
Ready: false,
|
||||||
|
State: api.ContainerState{Terminated: &api.ContainerStateTerminated{Reason: "Error", ExitCode: 137}},
|
||||||
|
Started: utilpointer.Bool(false),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ContainerStatuses: []api.ContainerStatus{
|
||||||
|
{
|
||||||
|
Ready: false,
|
||||||
|
RestartCount: 4,
|
||||||
|
State: api.ContainerState{Terminated: &api.ContainerStateTerminated{Reason: "Completed", ExitCode: 0}},
|
||||||
|
LastTerminationState: api.ContainerState{Terminated: &api.ContainerStateTerminated{FinishedAt: metav1.NewTime(time.Now().Add(-20 * time.Second))}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Conditions: []api.PodCondition{
|
||||||
|
{Type: api.PodInitialized, Status: api.ConditionTrue},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]metav1.TableRow{
|
||||||
|
{
|
||||||
|
Cells: []interface{}{"test3", "0/3", "Completed", "7 (10s ago)", "<unknown>"},
|
||||||
|
Conditions: []metav1.TableRowCondition{
|
||||||
|
{Type: metav1.RowCompleted, Status: metav1.ConditionTrue, Reason: "Succeeded", Message: "The pod has completed successfully."},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
rows, err := printPod(&test.pod, printers.GenerateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for i := range rows {
|
||||||
|
rows[i].Object.Object = nil
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(test.expect, rows) {
|
||||||
|
t.Errorf("%d mismatch: %s", i, cmp.Diff(test.expect, rows))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPrintPodwide(t *testing.T) {
|
func TestPrintPodwide(t *testing.T) {
|
||||||
condition1 := "condition1"
|
condition1 := "condition1"
|
||||||
condition2 := "condition2"
|
condition2 := "condition2"
|
||||||
|
Loading…
Reference in New Issue
Block a user