Repository: kubernetes/dashboard (go)

Issue:
A "Terminating" pod is shown incorrectly in the dashboard as "Waiting: ContainerCreating" 
##### Environment
<!-- Describe your setup. Versions of Node.js, Go etc. are needed only from developers. -->

```
Installation method: kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.4/aio/deploy/recommended.yaml
Kubernetes version: v1.19.0
Dashboard version: 2.0.4
Operating system: CentOS Linux release 7.8.2003 (Core)
Node.js version ('node --version' output): ??
Go version ('go version' output): ??
```

##### Steps to reproduce
I have a deployment that runs 3 pods.

Starting the pod takes a few seconds.

In my test I used this as the basis: https://github.com/nielsbasjes/yauaa/blob/master/webapp/yauaa-k8s-example.yaml

I see the effect when I simply do a restart of the deployment with
`kubectl -n yauaa rollout restart deployment yauaa`

##### Observed result
Looking at the pod status the same moment via command line and in the UI:
`kubectl -n yauaa get pods -owide`
Note: I sorted the results to match the ordering in the screenshot.

```
NAME                     READY   STATUS        RESTARTS   AGE     IP               NODE         NOMINATED NODE   READINESS GATES
yauaa-565956f64f-6dmd9   0/1     Running       0          7s      172.30.100.170   node11.xxx   <none>           <none>
yauaa-565956f64f-ftdxr   1/1     Running       0          26s     172.30.3.67      node10.xxx   <none>           <none>
yauaa-565956f64f-4x6r7   1/1     Running       0          46s     172.30.228.216   node12.xxx   <none>           <none>
yauaa-58fc466c4-vdpmr    1/1     Running       0          2m21s   172.30.100.171   node11.xxx   <none>           <none>
yauaa-58fc466c4-thqcj    0/1     Terminating   0          2m38s   <none>           node10.xxx   <none>           <none>
```

Kubernetes Dashboard 2.0.4
![image](https://user-images.githubusercontent.com/240096/96698571-91a8b000-138d-11eb-996c-d69e792653c3.png)


<!-- Describe observed result as precisely as possible. -->
Looking at pod yauaa-58fc466c4-thqcj

The commandline shows it as `Terminating` which is correct.
The dashboard shows it as `Waiting: ContainerCreating` which is incorrect.

##### Expected result
The dashboard shows pod yauaa-58fc466c4-thqcj also as `Terminating`.

##### Comments
No comments.


Pull request:
Sync pod status logic with kubectl and simplify API
- Moved logic that determines the status of a pod to the backend
- Used current kubectl logic to determine the status of the pod
- Simplified status of the pod to a single string instead of using a more complicated structure and adding an additional layer of logic in the frontend
- Updated frontend logic that determines icon display based on pod status

The logic that figures out the icon to use basically checks if the returned status is a known one and only then the specific icon will be used. For unchecked statuses, it will most often be a question mark icon meaning that we simply do not have a specific icon for it or it is not recognized by us.

I have checked the output with `kubectl` and it was the same at all times.

Other resources might still require additional work as they work on much simpler statuses. The pod itself has a wider range of possible statuses.

![Zrzut ekranu z 2020-10-22 14-36-29](https://user-images.githubusercontent.com/2285385/96873073-bf1c5900-1474-11eb-9611-85759ef377d7.png)

![Zrzut ekranu z 2020-10-22 14-37-49](https://user-images.githubusercontent.com/2285385/96873083-c17eb300-1474-11eb-8ae8-2a8e82ecb8a6.png)

Fixes #5656



Patch:
diff --git a/src/app/backend/resource/pod/common.go b/src/app/backend/resource/pod/common.go
index e247a547f..fdd981888 100644
--- a/src/app/backend/resource/pod/common.go
+++ b/src/app/backend/resource/pod/common.go
@@ -15,12 +15,15 @@
 package pod
 
 import (
+	"fmt"
+
+	v1 "k8s.io/api/core/v1"
+
 	"github.com/kubernetes/dashboard/src/app/backend/api"
 	metricapi "github.com/kubernetes/dashboard/src/app/backend/integration/metric/api"
 	"github.com/kubernetes/dashboard/src/app/backend/resource/common"
 	"github.com/kubernetes/dashboard/src/app/backend/resource/dataselect"
 	"github.com/kubernetes/dashboard/src/app/backend/resource/event"
-	v1 "k8s.io/api/core/v1"
 )
 
 // getRestartCount return the restart count of given pod (total number of its containers restarts).
@@ -32,18 +35,98 @@ func getRestartCount(pod v1.Pod) int32 {
 	return restartCount
 }
 
-// getPodStatus returns a PodStatus object containing a summary of the pod's status.
-func getPodStatus(pod v1.Pod, warnings []common.Event) PodStatus {
-	var states []v1.ContainerState
-	for _, containerStatus := range pod.Status.ContainerStatuses {
-		states = append(states, containerStatus.State)
+// getPodStatus returns status string calculated based on the same logic as kubectl
+// Base code: https://github.com/kubernetes/kubernetes/blob/master/pkg/printers/internalversion/printers.go#L734
+func getPodStatus(pod v1.Pod) string {
+	restarts := 0
+	readyContainers := 0
+
+	reason := string(pod.Status.Phase)
+	if pod.Status.Reason != "" {
+		reason = pod.Status.Reason
 	}
 
-	return PodStatus{
-		Status:          string(getPodStatusPhase(pod, warnings)),
-		PodPhase:        pod.Status.Phase,
-		ContainerStates: states,
+	initializing := false
+	for i := range pod.Status.InitContainerStatuses {
+		container := pod.Status.InitContainerStatuses[i]
+		restarts += int(container.RestartCount)
+		switch {
+		case container.State.Terminated != nil && container.State.Terminated.ExitCode == 0:
+			continue
+		case container.State.Terminated != nil:
+			// initialization is failed
+			if len(container.State.Terminated.Reason) == 0 {
+				if container.State.Terminated.Signal != 0 {
+					reason = fmt.Sprintf("Init: Signal %d", container.State.Terminated.Signal)
+				} else {
+					reason = fmt.Sprintf("Init: ExitCode %d", container.State.Terminated.ExitCode)
+				}
+			} else {
+				reason = "Init:" + container.State.Terminated.Reason
+			}
+			initializing = true
+		case container.State.Waiting != nil && len(container.State.Waiting.Reason) > 0 && container.State.Waiting.Reason != "PodInitializing":
+			reason = fmt.Sprintf("Init: %s", container.State.Waiting.Reason)
+			initializing = true
+		default:
+			reason = fmt.Sprintf("Init: %d/%d", i, len(pod.Spec.InitContainers))
+			initializing = true
+		}
+		break
+	}
+	if !initializing {
+		restarts = 0
+		hasRunning := false
+		for i := len(pod.Status.ContainerStatuses) - 1; i >= 0; i-- {
+			container := pod.Status.ContainerStatuses[i]
+
+			restarts += int(container.RestartCount)
+			if container.State.Waiting != nil && container.State.Waiting.Reason != "" {
+				reason = container.State.Waiting.Reason
+			} else if container.State.Terminated != nil && container.State.Terminated.Reason != "" {
+				reason = container.State.Terminated.Reason
+			} else if container.State.Terminated != nil && container.State.Terminated.Reason == "" {
+				if container.State.Terminated.Signal != 0 {
+					reason = fmt.Sprintf("Signal: %d", container.State.Terminated.Signal)
+				} else {
+					reason = fmt.Sprintf("ExitCode: %d", container.State.Terminated.ExitCode)
+				}
+			} else if container.Ready && container.State.Running != nil {
+				hasRunning = true
+				readyContainers++
+			}
+		}
+
+		// change pod status back to "Running" if there is at least one container still reporting as "Running" status
+		if reason == "Completed" && hasRunning {
+			if hasPodReadyCondition(pod.Status.Conditions) {
+				reason = string(v1.PodRunning)
+			} else {
+				reason = "NotReady"
+			}
+		}
+	}
+
+	if pod.DeletionTimestamp != nil && pod.Status.Reason == "NodeLost" {
+		reason = string(v1.PodUnknown)
+	} else if pod.DeletionTimestamp != nil {
+		reason = "Terminating"
+	}
+
+	if len(reason) == 0 {
+		reason = string(v1.PodUnknown)
+	}
+
+	return reason
+}
+
+func hasPodReadyCondition(conditions []v1.PodCondition) bool {
+	for _, condition := range conditions {
+		if condition.Type == v1.PodReady && condition.Status == v1.ConditionTrue {
+			return true
+		}
 	}
+	return false
 }
 
 // getPodStatusPhase returns one of four pod status phases (Pending, Running, Succeeded, Failed, Unknown, Terminating)
diff --git a/src/app/backend/resource/pod/detail.go b/src/app/backend/resource/pod/detail.go
index ffc33ac67..374c1b7ab 100644
--- a/src/app/backend/resource/pod/detail.go
+++ b/src/app/backend/resource/pod/detail.go
@@ -24,6 +24,12 @@ import (
 
 	"k8s.io/apimachinery/pkg/runtime/schema"
 
+	v1 "k8s.io/api/core/v1"
+	res "k8s.io/apimachinery/pkg/api/resource"
+	metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/client-go/kubernetes"
+
 	"github.com/kubernetes/dashboard/src/app/backend/api"
 	errorHandler "github.com/kubernetes/dashboard/src/app/backend/errors"
 	metricapi "github.com/kubernetes/dashboard/src/app/backend/integration/metric/api"
@@ -31,18 +37,13 @@ import (
 	"github.com/kubernetes/dashboard/src/app/backend/resource/controller"
 	"github.com/kubernetes/dashboard/src/app/backend/resource/dataselect"
 	"github.com/kubernetes/dashboard/src/app/backend/resource/persistentvolumeclaim"
-	v1 "k8s.io/api/core/v1"
-	res "k8s.io/apimachinery/pkg/api/resource"
-	metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
-	"k8s.io/client-go/kubernetes"
 )
 
 // PodDetail is a presentation layer view of Kubernetes Pod resource.
 type PodDetail struct {
 	ObjectMeta                api.ObjectMeta                                  `json:"objectMeta"`
 	TypeMeta                  api.TypeMeta                                    `json:"typeMeta"`
-	PodPhase                  v1.PodPhase                                     `json:"podPhase"`
+	PodPhase                  string                                          `json:"podPhase"`
 	PodIP                     string                                          `json:"podIP"`
 	NodeName                  string                                          `json:"nodeName"`
 	RestartCount              int32                                           `json:"restartCount"`
@@ -213,7 +214,7 @@ func toPodDetail(pod *v1.Pod, metrics []metricapi.Metric, configMaps *v1.ConfigM
 	return PodDetail{
 		ObjectMeta:                api.NewObjectMeta(pod.ObjectMeta),
 		TypeMeta:                  api.NewTypeMeta(api.ResourceKindPod),
-		PodPhase:                  pod.Status.Phase,
+		PodPhase:                  getPodStatus(*pod),
 		PodIP:                     pod.Status.PodIP,
 		RestartCount:              getRestartCount(*pod),
 		QOSClass:                  string(pod.Status.QOSClass),
diff --git a/src/app/backend/resource/pod/list.go b/src/app/backend/resource/pod/list.go
index 63c7911e0..782981d6d 100644
--- a/src/app/backend/resource/pod/list.go
+++ b/src/app/backend/resource/pod/list.go
@@ -55,10 +55,10 @@ type Pod struct {
 	ObjectMeta api.ObjectMeta `json:"objectMeta"`
 	TypeMeta   api.TypeMeta   `json:"typeMeta"`
 
-	// More info on pod status
-	PodStatus PodStatus `json:"podStatus"`
+	// Status determined based on the same logic as kubectl.
+	Status string `json:"status"`
 
-	// Count of containers restarts.
+	// RestartCount of containers restarts.
 	RestartCount int32 `json:"restartCount"`
 
 	// Pod metrics.
@@ -67,7 +67,7 @@ type Pod struct {
 	// Pod warning events
 	Warnings []common.Event `json:"warnings"`
 
-	// Name of the Node this Pod runs on.
+	// NodeName of the Node this Pod runs on.
 	NodeName string `json:"nodeName"`
 }
 
@@ -154,7 +154,7 @@ func toPod(pod *v1.Pod, metrics *MetricsByPod, warnings []common.Event) Pod {
 		ObjectMeta:   api.NewObjectMeta(pod.ObjectMeta),
 		TypeMeta:     api.NewTypeMeta(api.ResourceKindPod),
 		Warnings:     warnings,
-		PodStatus:    getPodStatus(*pod, warnings),
+		Status:       getPodStatus(*pod),
 		RestartCount: getRestartCount(*pod),
 		NodeName:     pod.Spec.NodeName,
 	}
diff --git a/src/app/frontend/_theming.scss b/src/app/frontend/_theming.scss
index 2713d7a81..ed6d864ab 100644
--- a/src/app/frontend/_theming.scss
+++ b/src/app/frontend/_theming.scss
@@ -108,6 +108,10 @@
     background-color: lighten(map-get($colors, indicator-error), 33%);
   }
 
+  .kd-help {
+    color: $muted;
+  }
+
   .kd-muted {
     color: $muted;
   }
diff --git a/src/app/frontend/common/components/namespace/component.ts b/src/app/frontend/common/components/namespace/component.ts
index 8ab07b5f0..b0c17b1cd 100644
--- a/src/app/frontend/common/components/namespace/component.ts
+++ b/src/app/frontend/common/components/namespace/component.ts
@@ -150,9 +150,9 @@ export class NamespaceSelectorComponent implements OnInit, OnDestroy {
 
   private loadNamespaces_(): void {
     this.namespaceUpdate_
-      .pipe(takeUntil(this.unsubscribe_))
       .pipe(startWith({}))
       .pipe(switchMap(() => this.namespace_.get(this.endpoint_.list())))
+      .pipe(takeUntil(this.unsubscribe_))
       .subscribe(
         namespaceList => {
           this.namespaces = namespaceList.namespaces.map(n => n.objectMeta.name);
diff --git a/src/app/frontend/common/components/resourcelist/pod/component.ts b/src/app/frontend/common/components/resourcelist/pod/component.ts
index dbad0b837..3da5932f2 100644
--- a/src/app/frontend/common/components/resourcelist/pod/component.ts
+++ b/src/app/frontend/common/components/resourcelist/pod/component.ts
@@ -16,7 +16,6 @@ import {HttpParams} from '@angular/common/http';
 import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from '@angular/core';
 import {Event, Metric, Pod, PodList} from '@api/backendapi';
 import {Observable} from 'rxjs';
-
 import {ResourceListWithStatuses} from '../../../resources/list';
 import {NotificationsService} from '../../../services/global/notifications';
 import {EndpointManager, Resource} from '../../../services/resource/endpoint';
@@ -24,6 +23,19 @@ import {NamespacedResourceService} from '../../../services/resource/resource';
 import {MenuComponent} from '../../list/column/menu/component';
 import {ListGroupIdentifier, ListIdentifier} from '../groupids';
 
+enum Status {
+  Pending = 'Pending',
+  ContainerCreating = 'ContainerCreating',
+  Running = 'Running',
+  Succeeded = 'Succeeded',
+  Completed = 'Completed',
+  Failed = 'Failed',
+  Unknown = 'Unknown',
+  NotReady = 'NotReady',
+  Terminating = 'Terminating',
+  Error = 'Error',
+}
+
 @Component({
   selector: 'kd-pod-list',
   templateUrl: './template.html',
@@ -65,23 +77,21 @@ export class PodListComponent extends ResourceListWithStatuses<PodList, Pod> {
   }
 
   isInErrorState(resource: Pod): boolean {
-    return resource.podStatus.status === 'Failed';
+    return (
+      [Status.Failed, Status.Error].some(s => resource.status === s) ||
+      (resource.warnings.length > 0 &&
+        ![Status.Pending, Status.NotReady, Status.Terminating, Status.Unknown, Status.ContainerCreating].some(
+          s => resource.status === s
+        ))
+    );
   }
 
   isInPendingState(resource: Pod): boolean {
-    return resource.podStatus.status === 'Pending';
+    return [Status.Pending, Status.ContainerCreating].some(s => resource.status === s);
   }
 
   isInSuccessState(resource: Pod): boolean {
-    return resource.podStatus.status === 'Succeeded' || resource.podStatus.status === 'Running';
-  }
-
-  protected getDisplayColumns(): string[] {
-    return ['statusicon', 'name', 'labels', 'node', 'status', 'restarts', 'cpu', 'mem', 'created'];
-  }
-
-  private shouldShowNamespaceColumn_(): boolean {
-    return this.namespaceService_.areMultipleNamespacesSelected();
+    return [Status.Succeeded, Status.Running, Status.Completed].some(s => resource.status === s);
   }
 
   hasErrors(pod: Pod): boolean {
@@ -93,43 +103,14 @@ export class PodListComponent extends ResourceListWithStatuses<PodList, Pod> {
   }
 
   getDisplayStatus(pod: Pod): string {
-    // See kubectl printers.go for logic in kubectl:
-    // https://github.com/kubernetes/kubernetes/blob/39857f486511bd8db81868185674e8b674b1aeb9/pkg/printers/internalversion/printers.go
-    let msgState = 'running';
-    let reason = undefined;
-
-    // Init container statuses are currently not taken into account.
-    // However, init containers with errors will still show as failed because of warnings.
-    if (pod.podStatus.containerStates) {
-      // Container states array may be null when no containers have started yet.
-      for (let i = pod.podStatus.containerStates.length - 1; i >= 0; i--) {
-        const state = pod.podStatus.containerStates[i];
-        if (state.waiting) {
-          msgState = 'waiting';
-          reason = state.waiting.reason;
-        }
-        if (state.terminated) {
-          msgState = 'terminated';
-          reason = state.terminated.reason;
-          if (!reason) {
-            if (state.terminated.signal) {
-              reason = `Signal:${state.terminated.signal}`;
-            } else {
-              reason = `ExitCode:${state.terminated.exitCode}`;
-            }
-          }
-        }
-      }
-    }
-
-    if (msgState === 'waiting') {
-      return `Waiting: ${reason}`;
-    }
-
-    if (msgState === 'terminated') {
-      return `Terminated: ${reason}`;
-    }
-
-    return pod.podStatus.podPhase;
+    return pod.status;
+  }
+
+  protected getDisplayColumns(): string[] {
+    return ['statusicon', 'name', 'labels', 'node', 'status', 'restarts', 'cpu', 'mem', 'created'];
+  }
+
+  private shouldShowNamespaceColumn_(): boolean {
+    return this.namespaceService_.areMultipleNamespacesSelected();
   }
 }
diff --git a/src/app/frontend/common/resources/list.ts b/src/app/frontend/common/resources/list.ts
index 91e80ddce..618dbe23c 100644
--- a/src/app/frontend/common/resources/list.ts
+++ b/src/app/frontend/common/resources/list.ts
@@ -366,7 +366,7 @@ export abstract class ResourceListWithStatuses<T extends ResourceList, R extends
   private lastHash_: number;
   private readonly unknownStatus: StatusIcon = {
     iconName: 'help',
-    iconClass: {'': true},
+    iconClass: {'kd-help': true},
   };
 
   protected icon = IconName;
diff --git a/src/app/frontend/resource/discovery/service/detail/component.spec.ts b/src/app/frontend/resource/discovery/service/detail/component.spec.ts
index 3735160ef..19034c518 100644
--- a/src/app/frontend/resource/discovery/service/detail/component.spec.ts
+++ b/src/app/frontend/resource/discovery/service/detail/component.spec.ts
@@ -14,7 +14,7 @@
 
 import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
 import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
-import {waitForAsync, TestBed} from '@angular/core/testing';
+import {TestBed, waitForAsync} from '@angular/core/testing';
 import {MatCardModule} from '@angular/material/card';
 import {MatChipsModule} from '@angular/material/chips';
 import {MatDialogModule} from '@angular/material/dialog';
@@ -74,11 +74,7 @@ class MaxiTestComponent {
     podList: {
       pods: [
         {
-          podStatus: {
-            podPhase: 'phase1',
-            status: 'Ready',
-            containerStates: [{waiting: {reason: 'Still starting'}}],
-          },
+          status: 'Running',
           restartCount: 1,
           metrics: {
             cpuUsage: 10,
diff --git a/src/app/frontend/typings/backendapi.ts b/src/app/frontend/typings/backendapi.ts
index ebf4cc3d3..0b7dcc867 100644
--- a/src/app/frontend/typings/backendapi.ts
+++ b/src/app/frontend/typings/backendapi.ts
@@ -347,7 +347,7 @@ export interface PersistentVolumeClaim extends Resource {
 }
 
 export interface Pod extends Resource {
-  podStatus: PodStatus;
+  status: string;
   podIP?: string;
   restartCount: number;
   qosClass?: string;


Test patch:
diff --git a/src/app/backend/resource/pod/common_test.go b/src/app/backend/resource/pod/common_test.go
index c5af25c0c..6f5f8c679 100644
--- a/src/app/backend/resource/pod/common_test.go
+++ b/src/app/backend/resource/pod/common_test.go
@@ -40,10 +40,7 @@ func TestToPodPodStatusFailed(t *testing.T) {
 
 	expected := Pod{
 		TypeMeta: api.TypeMeta{Kind: api.ResourceKindPod},
-		PodStatus: PodStatus{
-			Status:   string(v1.PodFailed),
-			PodPhase: v1.PodFailed,
-		},
+		Status:   string(v1.PodFailed),
 		Warnings: []common.Event{},
 	}
 
@@ -70,10 +67,7 @@ func TestToPodPodStatusSucceeded(t *testing.T) {
 
 	expected := Pod{
 		TypeMeta: api.TypeMeta{Kind: api.ResourceKindPod},
-		PodStatus: PodStatus{
-			Status:   string(v1.PodSucceeded),
-			PodPhase: v1.PodSucceeded,
-		},
+		Status:   string(v1.PodSucceeded),
 		Warnings: []common.Event{},
 	}
 
@@ -104,10 +98,7 @@ func TestToPodPodStatusRunning(t *testing.T) {
 
 	expected := Pod{
 		TypeMeta: api.TypeMeta{Kind: api.ResourceKindPod},
-		PodStatus: PodStatus{
-			Status:   string(v1.PodRunning),
-			PodPhase: v1.PodRunning,
-		},
+		Status:   string(v1.PodRunning),
 		Warnings: []common.Event{},
 	}
 
@@ -134,10 +125,7 @@ func TestToPodPodStatusPending(t *testing.T) {
 
 	expected := Pod{
 		TypeMeta: api.TypeMeta{Kind: api.ResourceKindPod},
-		PodStatus: PodStatus{
-			Status:   string(v1.PodPending),
-			PodPhase: v1.PodPending,
-		},
+		Status:   string(v1.PodPending),
 		Warnings: []common.Event{},
 	}
 
@@ -157,14 +145,14 @@ func TestToPodContainerStates(t *testing.T) {
 				{
 					State: v1.ContainerState{
 						Terminated: &v1.ContainerStateTerminated{
-							Reason: "Terminated Test Reason",
+							Reason: "Terminated",
 						},
 					},
 				},
 				{
 					State: v1.ContainerState{
 						Waiting: &v1.ContainerStateWaiting{
-							Reason: "Waiting Test Reason",
+							Reason: "Waiting",
 						},
 					},
 				},
@@ -174,22 +162,7 @@ func TestToPodContainerStates(t *testing.T) {
 
 	expected := Pod{
 		TypeMeta: api.TypeMeta{Kind: api.ResourceKindPod},
-		PodStatus: PodStatus{
-			PodPhase: v1.PodRunning,
-			Status:   string(v1.PodPending),
-			ContainerStates: []v1.ContainerState{
-				{
-					Terminated: &v1.ContainerStateTerminated{
-						Reason: "Terminated Test Reason",
-					},
-				},
-				{
-					Waiting: &v1.ContainerStateWaiting{
-						Reason: "Waiting Test Reason",
-					},
-				},
-			},
-		},
+		Status:   "Terminated",
 		Warnings: []common.Event{},
 	}
 
@@ -211,9 +184,7 @@ func TestToPod(t *testing.T) {
 			pod: &v1.Pod{}, metrics: &MetricsByPod{},
 			expected: Pod{
 				TypeMeta: api.TypeMeta{Kind: api.ResourceKindPod},
-				PodStatus: PodStatus{
-					Status: string(v1.PodPending),
-				},
+				Status:   string(v1.PodUnknown),
 				Warnings: []common.Event{},
 			},
 		}, {
@@ -228,9 +199,7 @@ func TestToPod(t *testing.T) {
 					Name:      "test-pod",
 					Namespace: "test-namespace",
 				},
-				PodStatus: PodStatus{
-					Status: string(v1.PodPending),
-				},
+				Status:   string(v1.PodUnknown),
 				Warnings: []common.Event{},
 			},
 		},
diff --git a/src/app/backend/resource/pod/detail_test.go b/src/app/backend/resource/pod/detail_test.go
index 3c4b1ecd1..5408b8ec7 100644
--- a/src/app/backend/resource/pod/detail_test.go
+++ b/src/app/backend/resource/pod/detail_test.go
@@ -43,6 +43,7 @@ func TestGetPodDetail(t *testing.T) {
 				}}}},
 			expected: &PodDetail{
 				TypeMeta: api.TypeMeta{Kind: api.ResourceKindPod},
+				PodPhase: string(v1.PodUnknown),
 				ObjectMeta: api.ObjectMeta{
 					Name:      "test-pod",
 					Namespace: "test-namespace",
diff --git a/src/app/backend/resource/pod/list_test.go b/src/app/backend/resource/pod/list_test.go
index 35439fa97..f66e8dc55 100644
--- a/src/app/backend/resource/pod/list_test.go
+++ b/src/app/backend/resource/pod/list_test.go
@@ -102,9 +102,9 @@ func TestGetPodListFromChannels(t *testing.T) {
 						Labels:            map[string]string{"key": "value"},
 						CreationTimestamp: metav1.Unix(111, 222),
 					},
-					TypeMeta:  api.TypeMeta{Kind: api.ResourceKindPod},
-					PodStatus: pod.PodStatus{Status: string(v1.PodPending)},
-					Warnings:  []common.Event{},
+					TypeMeta: api.TypeMeta{Kind: api.ResourceKindPod},
+					Status:   string(v1.PodUnknown),
+					Warnings: []common.Event{},
 				}},
 				Errors: []error{},
 			},
diff --git a/src/app/backend/resource/service/pods_test.go b/src/app/backend/resource/service/pods_test.go
index 9146f395e..096093e5a 100644
--- a/src/app/backend/resource/service/pods_test.go
+++ b/src/app/backend/resource/service/pods_test.go
@@ -57,9 +57,9 @@ func TestGetServicePods(t *testing.T) {
 							Name:      "pod-1",
 							UID:       "test-uid",
 							Namespace: "ns-1"},
-						TypeMeta:  api.TypeMeta{Kind: api.ResourceKindPod},
-						PodStatus: pod.PodStatus{Status: string(v1.PodPending)},
-						Warnings:  []common.Event{},
+						TypeMeta: api.TypeMeta{Kind: api.ResourceKindPod},
+						Status:   string(v1.PodUnknown),
+						Warnings: []common.Event{},
 					},
 				},
 				Errors: []error{},