Skip to content

Commit

Permalink
Fix nil pointer dereference on job details page (kubernetes#2302)
Browse files Browse the repository at this point in the history
* Fix `nil pointer dereference` on job details page

* Make tests compile

* Fix test

* Fix test

* Fix tests

* Fix tests
  • Loading branch information
maciaszczykm authored Aug 25, 2017
1 parent a596f5f commit 2ac2816
Show file tree
Hide file tree
Showing 28 changed files with 103 additions and 76 deletions.
4 changes: 2 additions & 2 deletions src/app/backend/resource/common/podinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type PodInfo struct {
Current int32 `json:"current"`

// Number of pods that are desired.
Desired int32 `json:"desired"`
Desired *int32 `json:"desired,omitempty"`

// Number of pods that are currently running.
Running int32 `json:"running"`
Expand All @@ -41,7 +41,7 @@ type PodInfo struct {
}

// GetPodInfo returns aggregate information about a group of pods.
func GetPodInfo(current int32, desired int32, pods []api.Pod) PodInfo {
func GetPodInfo(current int32, desired *int32, pods []api.Pod) PodInfo {
result := PodInfo{
Current: current,
Desired: desired,
Expand Down
15 changes: 10 additions & 5 deletions src/app/backend/resource/common/podinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,20 @@ import (
api "k8s.io/client-go/pkg/api/v1"
)

func getReplicasPointer(replicas int32) *int32 {
return &replicas
}

func TestGetPodInfo(t *testing.T) {
cases := []struct {
current, desired int32
pods []api.Pod
expected PodInfo
current int32
desired *int32
pods []api.Pod
expected PodInfo
}{
{
5,
4,
getReplicasPointer(4),
[]api.Pod{
{
Status: api.PodStatus{
Expand All @@ -39,7 +44,7 @@ func TestGetPodInfo(t *testing.T) {
},
PodInfo{
Current: 5,
Desired: 4,
Desired: getReplicasPointer(4),
Running: 1,
Pending: 0,
Failed: 0,
Expand Down
14 changes: 5 additions & 9 deletions src/app/backend/resource/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,7 @@ type JobController batch.Job
// Get is an implementation of Get method from ResourceController interface.
func (self JobController) Get(allPods []v1.Pod, allEvents []v1.Event) ResourceOwner {
matchingPods := common.FilterPodsForJob(batch.Job(self), allPods)
var completions int32
if self.Spec.Completions != nil {
completions = *self.Spec.Completions
}
podInfo := common.GetPodInfo(self.Status.Active, completions, matchingPods)
podInfo := common.GetPodInfo(self.Status.Active, self.Spec.Completions, matchingPods)
podInfo.Warnings = event.GetPodsEventWarnings(allEvents, matchingPods)

return ResourceOwner{
Expand Down Expand Up @@ -142,7 +138,7 @@ type ReplicaSetController extensions.ReplicaSet
// Get is an implementation of Get method from ResourceController interface.
func (self ReplicaSetController) Get(allPods []v1.Pod, allEvents []v1.Event) ResourceOwner {
matchingPods := common.FilterPodsByControllerRef(&self, allPods)
podInfo := common.GetPodInfo(self.Status.Replicas, *self.Spec.Replicas, matchingPods)
podInfo := common.GetPodInfo(self.Status.Replicas, self.Spec.Replicas, matchingPods)
podInfo.Warnings = event.GetPodsEventWarnings(allEvents, matchingPods)

return ResourceOwner{
Expand Down Expand Up @@ -175,7 +171,7 @@ type ReplicationControllerController v1.ReplicationController
func (self ReplicationControllerController) Get(allPods []v1.Pod,
allEvents []v1.Event) ResourceOwner {
matchingPods := common.FilterPodsByControllerRef(&self, allPods)
podInfo := common.GetPodInfo(self.Status.Replicas, *self.Spec.Replicas, matchingPods)
podInfo := common.GetPodInfo(self.Status.Replicas, self.Spec.Replicas, matchingPods)
podInfo.Warnings = event.GetPodsEventWarnings(allEvents, matchingPods)

return ResourceOwner{
Expand Down Expand Up @@ -208,7 +204,7 @@ type DaemonSetController extensions.DaemonSet
func (self DaemonSetController) Get(allPods []v1.Pod, allEvents []v1.Event) ResourceOwner {
matchingPods := common.FilterPodsByControllerRef(&self, allPods)
podInfo := common.GetPodInfo(self.Status.CurrentNumberScheduled,
self.Status.DesiredNumberScheduled, matchingPods)
&self.Status.DesiredNumberScheduled, matchingPods)
podInfo.Warnings = event.GetPodsEventWarnings(allEvents, matchingPods)

return ResourceOwner{
Expand Down Expand Up @@ -240,7 +236,7 @@ type StatefulSetController apps.StatefulSet
// Get is an implementation of Get method from ResourceController interface.
func (self StatefulSetController) Get(allPods []v1.Pod, allEvents []v1.Event) ResourceOwner {
matchingPods := common.FilterPodsByControllerRef(&self, allPods)
podInfo := common.GetPodInfo(self.Status.Replicas, *self.Spec.Replicas, matchingPods)
podInfo := common.GetPodInfo(self.Status.Replicas, self.Spec.Replicas, matchingPods)
podInfo.Warnings = event.GetPodsEventWarnings(allEvents, matchingPods)

return ResourceOwner{
Expand Down
2 changes: 1 addition & 1 deletion src/app/backend/resource/daemonset/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func toDaemonSetList(daemonSets []extensions.DaemonSet, pods []v1.Pod, events []
for _, daemonSet := range daemonSets {
matchingPods := common.FilterPodsByControllerRef(&daemonSet, pods)
podInfo := common.GetPodInfo(daemonSet.Status.CurrentNumberScheduled,
daemonSet.Status.DesiredNumberScheduled, matchingPods)
&daemonSet.Status.DesiredNumberScheduled, matchingPods)
podInfo.Warnings = event.GetPodsEventWarnings(events, matchingPods)

daemonSetList.DaemonSets = append(daemonSetList.DaemonSets, DaemonSet{
Expand Down
19 changes: 16 additions & 3 deletions src/app/backend/resource/daemonset/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
func TestToDaemonSetList(t *testing.T) {
events := []v1.Event{}
controller := true
var desired int32 = 1
validPodMeta := metaV1.ObjectMeta{
Namespace: "namespace-1",
OwnerReferences: []metaV1.OwnerReference{
Expand Down Expand Up @@ -60,9 +61,13 @@ func TestToDaemonSetList(t *testing.T) {
nodes []v1.Node
expected *DaemonSetList
}{
{nil, nil, nil, nil, &DaemonSetList{
DaemonSets: []DaemonSet{},
CumulativeMetrics: make([]metricapi.Metric, 0)},
{nil,
nil,
nil,
nil,
&DaemonSetList{
DaemonSets: []DaemonSet{},
CumulativeMetrics: make([]metricapi.Metric, 0)},
}, {
[]extensions.DaemonSet{
{
Expand All @@ -79,6 +84,9 @@ func TestToDaemonSetList(t *testing.T) {
Spec: v1.PodSpec{Containers: []v1.Container{{Image: "my-container-image-1"}}},
},
},
Status: extensions.DaemonSetStatus{
DesiredNumberScheduled: desired,
},
},
{
ObjectMeta: metaV1.ObjectMeta{
Expand All @@ -93,6 +101,9 @@ func TestToDaemonSetList(t *testing.T) {
Spec: v1.PodSpec{Containers: []v1.Container{{Image: "my-container-image-2"}}},
},
},
Status: extensions.DaemonSetStatus{
DesiredNumberScheduled: desired,
},
},
},
[]v1.Service{
Expand Down Expand Up @@ -178,6 +189,7 @@ func TestToDaemonSetList(t *testing.T) {
TypeMeta: api.TypeMeta{Kind: api.ResourceKindDaemonSet},
ContainerImages: []string{"my-container-image-1"},
Pods: common.PodInfo{
Desired: &desired,
Failed: 2,
Pending: 1,
Running: 1,
Expand All @@ -192,6 +204,7 @@ func TestToDaemonSetList(t *testing.T) {
TypeMeta: api.TypeMeta{Kind: api.ResourceKindDaemonSet},
ContainerImages: []string{"my-container-image-2"},
Pods: common.PodInfo{
Desired: &desired,
Warnings: []common.Event{},
},
},
Expand Down
2 changes: 1 addition & 1 deletion src/app/backend/resource/daemonset/pods.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,6 @@ func getDaemonSetPodInfo(client k8sClient.Interface, daemonSet *extensions.Daemo
}

podInfo := common.GetPodInfo(daemonSet.Status.CurrentNumberScheduled,
daemonSet.Status.DesiredNumberScheduled, pods)
&daemonSet.Status.DesiredNumberScheduled, pods)
return &podInfo, nil
}
3 changes: 1 addition & 2 deletions src/app/backend/resource/deployment/detail.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ func GetDeploymentDetail(client client.Interface, metricClient metricapi.MetricC
return nil, err
}

// TODO fix not to use kubernetes utils
selector, err := metaV1.LabelSelectorAsSelector(deployment.Spec.Selector)
if err != nil {
return nil, err
Expand Down Expand Up @@ -172,7 +171,7 @@ func GetDeploymentDetail(client client.Interface, metricClient metricapi.MetricC
var newReplicaSet replicaset.ReplicaSet
if newRs != nil {
matchingPods := common.FilterPodsByControllerRef(newRs, rawPods.Items)
newRsPodInfo := common.GetPodInfo(newRs.Status.Replicas, *newRs.Spec.Replicas, matchingPods)
newRsPodInfo := common.GetPodInfo(newRs.Status.Replicas, newRs.Spec.Replicas, matchingPods)
events, err := event.GetPodsEvents(client, namespace, matchingPods)
nonCriticalErrors, criticalError = errors.AppendError(err, nonCriticalErrors)
if criticalError != nil {
Expand Down
28 changes: 16 additions & 12 deletions src/app/backend/resource/deployment/detail_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,8 @@ import (
extensions "k8s.io/client-go/pkg/apis/extensions/v1beta1"
)

func createDeployment(name, namespace, podTemplateName string, podLabel,
func createDeployment(name, namespace, podTemplateName string, replicas int32, podLabel,
labelSelector map[string]string) *extensions.Deployment {
replicas := int32(4)
maxSurge := intstr.FromInt(1)
maxUnavailable := intstr.FromString("25%")

Expand All @@ -43,8 +42,9 @@ func createDeployment(name, namespace, podTemplateName string, podLabel,
Name: name, Namespace: namespace, Labels: labelSelector,
},
Spec: extensions.DeploymentSpec{
Selector: &metaV1.LabelSelector{MatchLabels: labelSelector},
Replicas: &replicas, MinReadySeconds: 5,
Selector: &metaV1.LabelSelector{MatchLabels: labelSelector},
Replicas: &replicas,
MinReadySeconds: 5,
Strategy: extensions.DeploymentStrategy{
Type: extensions.RollingUpdateDeploymentStrategyType,
RollingUpdate: &extensions.RollingUpdateDeployment{
Expand All @@ -56,14 +56,13 @@ func createDeployment(name, namespace, podTemplateName string, podLabel,
ObjectMeta: metaV1.ObjectMeta{Name: podTemplateName, Labels: podLabel}},
},
Status: extensions.DeploymentStatus{
Replicas: 4, UpdatedReplicas: 2, AvailableReplicas: 3, UnavailableReplicas: 1,
Replicas: replicas, UpdatedReplicas: 2, AvailableReplicas: 3, UnavailableReplicas: 1,
},
}
}

func createReplicaSet(name, namespace string, labelSelector map[string]string,
func createReplicaSet(name, namespace string, replicas int32, labelSelector map[string]string,
podTemplateSpec v1.PodTemplateSpec) extensions.ReplicaSet {
replicas := int32(0)
return extensions.ReplicaSet{
ObjectMeta: metaV1.ObjectMeta{
Name: name, Namespace: namespace, Labels: labelSelector,
Expand All @@ -78,18 +77,20 @@ func createReplicaSet(name, namespace string, labelSelector map[string]string,
func TestGetDeploymentDetail(t *testing.T) {
podList := &v1.PodList{}
eventList := &v1.EventList{}
var replicas int32 = 4

deployment := createDeployment("dp-1", "ns-1", "pod-1", map[string]string{"track": "beta"},
map[string]string{"foo": "bar"})
deployment := createDeployment("dp-1", "ns-1", "pod-1", replicas,
map[string]string{"track": "beta"}, map[string]string{"foo": "bar"})

podTemplateSpec := GetNewReplicaSetTemplate(deployment)

newReplicaSet := createReplicaSet("rs-1", "ns-1", map[string]string{"foo": "bar"}, podTemplateSpec)
newReplicaSet := createReplicaSet("rs-1", "ns-1", replicas, map[string]string{"foo": "bar"},
podTemplateSpec)

replicaSetList := &extensions.ReplicaSetList{
Items: []extensions.ReplicaSet{
newReplicaSet,
createReplicaSet("rs-2", "ns-1", map[string]string{"foo": "bar"},
createReplicaSet("rs-2", "ns-1", replicas, map[string]string{"foo": "bar"},
podTemplateSpec),
},
}
Expand Down Expand Up @@ -140,7 +141,10 @@ func TestGetDeploymentDetail(t *testing.T) {
NewReplicaSet: replicaset.ReplicaSet{
ObjectMeta: api.NewObjectMeta(newReplicaSet.ObjectMeta),
TypeMeta: api.NewTypeMeta(api.ResourceKindReplicaSet),
Pods: common.PodInfo{Warnings: []common.Event{}},
Pods: common.PodInfo{
Warnings: []common.Event{},
Desired: &replicas,
},
},
EventList: common.EventList{
Events: []common.Event{},
Expand Down
2 changes: 1 addition & 1 deletion src/app/backend/resource/deployment/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func toDeploymentList(deployments []extensions.Deployment, pods []v1.Pod, events

for _, deployment := range deployments {
matchingPods := common.FilterDeploymentPodsByOwnerReference(deployment, rs, pods)
podInfo := common.GetPodInfo(deployment.Status.Replicas, *deployment.Spec.Replicas, matchingPods)
podInfo := common.GetPodInfo(deployment.Status.Replicas, deployment.Spec.Replicas, matchingPods)
podInfo.Warnings = event.GetPodsEventWarnings(events, matchingPods)

deploymentList.Deployments = append(deploymentList.Deployments,
Expand Down
2 changes: 1 addition & 1 deletion src/app/backend/resource/deployment/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func TestGetDeploymentListFromChannels(t *testing.T) {
TypeMeta: api.TypeMeta{Kind: api.ResourceKindDeployment},
Pods: common.PodInfo{
Current: 7,
Desired: 21,
Desired: getReplicasPointer(21),
Failed: 0,
Warnings: []common.Event{},
},
Expand Down
10 changes: 6 additions & 4 deletions src/app/backend/resource/job/detail_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ import (
batch "k8s.io/client-go/pkg/apis/batch/v1"
)

func createJob(name, namespace string, labelSelector map[string]string) *batch.Job {
var jobCompletions int32
func createJob(name, namespace string, jobCompletions int32, labelSelector map[string]string) *batch.Job {
var parallelism int32

return &batch.Job{
Expand Down Expand Up @@ -57,12 +56,15 @@ func TestGetJobDetail(t *testing.T) {
{
"ns-1", "job-1",
[]string{"get", "get", "list", "list", "list", "list"},
createJob("job-1", "ns-1", map[string]string{"app": "test"}),
createJob("job-1", "ns-1", jobCompletions, map[string]string{"app": "test"}),
&JobDetail{
ObjectMeta: api.ObjectMeta{Name: "job-1", Namespace: "ns-1",
Labels: map[string]string{"app": "test"}},
TypeMeta: api.TypeMeta{Kind: api.ResourceKindJob},
PodInfo: common.PodInfo{Warnings: []common.Event{}},
PodInfo: common.PodInfo{
Warnings: []common.Event{},
Desired: &jobCompletions,
},
PodList: pod.PodList{
Pods: []pod.Pod{},
CumulativeMetrics: make([]metricapi.Metric, 0),
Expand Down
3 changes: 2 additions & 1 deletion src/app/backend/resource/job/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
)

func TestGetJobEvents(t *testing.T) {
var jobCompletions int32
cases := []struct {
namespace, name string
eventList *v1.EventList
Expand All @@ -46,7 +47,7 @@ func TestGetJobEvents(t *testing.T) {
&v1.PodList{Items: []v1.Pod{{ObjectMeta: metaV1.ObjectMeta{
Name: "pod-1", Namespace: "ns-1",
}}}},
createJob("job-1", "ns-1", map[string]string{"app": "test"}),
createJob("job-1", "ns-1", jobCompletions, map[string]string{"app": "test"}),
[]string{"list"},
&common.EventList{
ListMeta: api.ListMeta{TotalItems: 1},
Expand Down
6 changes: 1 addition & 5 deletions src/app/backend/resource/job/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,8 @@ func toJobList(jobs []batch.Job, pods []v1.Pod, events []v1.Event, nonCriticalEr
jobList.ListMeta = api.ListMeta{TotalItems: filteredTotal}

for _, job := range jobs {
var completions int32
matchingPods := common.FilterPodsForJob(job, pods)
if job.Spec.Completions != nil {
completions = *job.Spec.Completions
}
podInfo := common.GetPodInfo(job.Status.Active, completions, matchingPods)
podInfo := common.GetPodInfo(job.Status.Active, job.Spec.Completions, matchingPods)
podInfo.Warnings = event.GetPodsEventWarnings(events, matchingPods)
jobList.Jobs = append(jobList.Jobs, toJob(&job, &podInfo))
}
Expand Down
11 changes: 6 additions & 5 deletions src/app/backend/resource/job/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
)

func TestGetJobListFromChannels(t *testing.T) {
var jobCompletions int32 = 21
var completions int32 = 21
controller := true
cases := []struct {
k8sRs batch.JobList
Expand Down Expand Up @@ -91,7 +91,7 @@ func TestGetJobListFromChannels(t *testing.T) {
},
Spec: batch.JobSpec{
Selector: &metaV1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
Completions: &jobCompletions,
Completions: &completions,
},
Status: batch.JobStatus{
Active: 7,
Expand All @@ -106,7 +106,8 @@ func TestGetJobListFromChannels(t *testing.T) {
CreationTimestamp: metaV1.Unix(111, 222),
},
Spec: batch.JobSpec{
Selector: &metaV1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
Selector: &metaV1.LabelSelector{MatchLabels: map[string]string{"foo": "bar"}},
Completions: &completions,
},
Status: batch.JobStatus{
Active: 7,
Expand Down Expand Up @@ -158,7 +159,7 @@ func TestGetJobListFromChannels(t *testing.T) {
TypeMeta: api.TypeMeta{Kind: api.ResourceKindJob},
Pods: common.PodInfo{
Current: 7,
Desired: 21,
Desired: &completions,
Failed: 2,
Warnings: []common.Event{},
},
Expand All @@ -172,7 +173,7 @@ func TestGetJobListFromChannels(t *testing.T) {
TypeMeta: api.TypeMeta{Kind: api.ResourceKindJob},
Pods: common.PodInfo{
Current: 7,
Desired: 0,
Desired: &completions,
Failed: 2,
Warnings: []common.Event{},
},
Expand Down
Loading

0 comments on commit 2ac2816

Please sign in to comment.