Skip to content

Commit ac2203b

Browse files
Sebastian FlorekSebastian Florek
authored andcommitted
Add replica set detail page and refactor backend (#730)
1 parent 64f698b commit ac2203b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1254
-303
lines changed

src/app/backend/handler/apihandler.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ import (
2323
restful "github.com/emicklei/go-restful"
2424
// TODO(maciaszczykm): Avoid using dot-imports.
2525
. "github.com/kubernetes/dashboard/client"
26+
"github.com/kubernetes/dashboard/resource/common"
2627
. "github.com/kubernetes/dashboard/resource/container"
2728
"github.com/kubernetes/dashboard/resource/deployment"
28-
. "github.com/kubernetes/dashboard/resource/event"
2929
. "github.com/kubernetes/dashboard/resource/namespace"
3030
"github.com/kubernetes/dashboard/resource/pod"
3131
"github.com/kubernetes/dashboard/resource/replicaset"
@@ -174,6 +174,10 @@ func CreateHttpApiHandler(client *client.Client, heapsterClient HeapsterClient,
174174
replicaSetsWs.GET("").
175175
To(apiHandler.handleGetReplicaSets).
176176
Writes(replicaset.ReplicaSetList{}))
177+
replicaSetsWs.Route(
178+
replicaSetsWs.GET("/{namespace}/{replicaSet}").
179+
To(apiHandler.handleGetReplicaSetDetail).
180+
Writes(replicaset.ReplicaSetDetail{}))
177181
wsContainer.Add(replicaSetsWs)
178182

179183
podsWs := new(restful.WebService)
@@ -235,7 +239,7 @@ func CreateHttpApiHandler(client *client.Client, heapsterClient HeapsterClient,
235239
eventsWs.Route(
236240
eventsWs.GET("/{namespace}/{replicationController}").
237241
To(apiHandler.handleEvents).
238-
Writes(Events{}))
242+
Writes(common.EventList{}))
239243
wsContainer.Add(eventsWs)
240244

241245
secretsWs := new(restful.WebService)
@@ -422,6 +426,22 @@ func (apiHandler *ApiHandler) handleGetReplicaSets(
422426
response.WriteHeaderAndEntity(http.StatusCreated, result)
423427
}
424428

429+
func (apiHandler *ApiHandler) handleGetReplicaSetDetail(
430+
request *restful.Request, response *restful.Response) {
431+
432+
namespace := request.PathParameter("namespace")
433+
replicaSet := request.PathParameter("replicaSet")
434+
result, err := replicaset.GetReplicaSetDetail(apiHandler.client, apiHandler.heapsterClient,
435+
namespace, replicaSet)
436+
437+
if err != nil {
438+
handleInternalError(response, err)
439+
return
440+
}
441+
442+
response.WriteHeaderAndEntity(http.StatusCreated, result)
443+
}
444+
425445
// Handles get Deployment list API call.
426446
func (apiHandler *ApiHandler) handleGetDeployments(
427447
request *restful.Request, response *restful.Response) {
@@ -599,7 +619,7 @@ func (apiHandler *ApiHandler) handleLogs(request *restful.Request, response *res
599619
func (apiHandler *ApiHandler) handleEvents(request *restful.Request, response *restful.Response) {
600620
namespace := request.PathParameter("namespace")
601621
replicationController := request.PathParameter("replicationController")
602-
result, err := GetEvents(apiHandler.client, namespace, replicationController)
622+
result, err := GetReplicationControllerEvents(apiHandler.client, namespace, replicationController)
603623
if err != nil {
604624
handleInternalError(response, err)
605625
return

src/app/backend/resource/common/podinfo.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ import (
1818
"k8s.io/kubernetes/pkg/api"
1919
"k8s.io/kubernetes/pkg/api/unversioned"
2020
"k8s.io/kubernetes/pkg/labels"
21-
22-
"github.com/kubernetes/dashboard/resource/event"
2321
)
2422

2523
// PodInfo represents aggregate information about controller's pods.
@@ -40,15 +38,15 @@ type PodInfo struct {
4038
Failed int `json:"failed"`
4139

4240
// Unique warning messages related to pods in this resource.
43-
Warnings []event.Event `json:"warnings"`
41+
Warnings []Event `json:"warnings"`
4442
}
4543

4644
// GetPodInfo returns aggregate information about a group of pods.
4745
func GetPodInfo(current int, desired int, pods []api.Pod) PodInfo {
4846
result := PodInfo{
4947
Current: current,
5048
Desired: desired,
51-
Warnings: make([]event.Event, 0),
49+
Warnings: make([]Event, 0),
5250
}
5351

5452
for _, pod := range pods {
@@ -95,7 +93,6 @@ func GetMatchingPods(labelSelector *unversioned.LabelSelector, namespace string,
9593
selector.Matches(labels.Set(pod.ObjectMeta.Labels)) {
9694
matchingPods = append(matchingPods, pod)
9795
}
98-
return matchingPods
9996
}
10097

10198
return matchingPods

src/app/backend/resource/common/resourcechannels.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,26 @@ func GetEventListChannel(client client.EventNamespacer, numReads int) EventListC
138138
return channel
139139
}
140140

141+
func GetNamespacedEventListChannel(client client.EventNamespacer, numReads int,
142+
namespace string, options api.ListOptions) EventListChannel {
143+
144+
channel := EventListChannel{
145+
List: make(chan *api.EventList, numReads),
146+
Error: make(chan error, numReads),
147+
}
148+
149+
go func() {
150+
events, err := client.Events(namespace).List(options)
151+
152+
for i := 0; i < numReads; i++ {
153+
channel.List <- events
154+
channel.Error <- err
155+
}
156+
}()
157+
158+
return channel
159+
}
160+
141161
// List and error channels to Nodes.
142162
type PodListChannel struct {
143163
List chan *api.PodList
@@ -164,6 +184,26 @@ func GetPodListChannel(client client.PodsNamespacer, numReads int) PodListChanne
164184
return channel
165185
}
166186

187+
func GetNamespacedPodListChannel(client client.PodsNamespacer, numReads int,
188+
namespace string, options api.ListOptions) PodListChannel {
189+
190+
channel := PodListChannel{
191+
List: make(chan *api.PodList, numReads),
192+
Error: make(chan error, numReads),
193+
}
194+
195+
go func() {
196+
pods, err := client.Pods(namespace).List(options)
197+
198+
for i := 0; i < numReads; i++ {
199+
channel.List <- pods
200+
channel.Error <- err
201+
}
202+
}()
203+
204+
return channel
205+
}
206+
167207
// List and error channels to Nodes.
168208
type ReplicationControllerListChannel struct {
169209
List chan *api.ReplicationControllerList

src/app/backend/resource/common/types.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,49 @@ type ServicePort struct {
104104
Protocol api.Protocol `json:"protocol"`
105105
}
106106

107+
// Events response structure.
108+
type EventList struct {
109+
// Namespace.
110+
Namespace string `json:"namespace"`
111+
112+
// List of events from given namespace.
113+
Events []Event `json:"events"`
114+
}
115+
116+
// Event is a single event representation.
117+
type Event struct {
118+
// A human-readable description of the status of related object.
119+
Message string `json:"message"`
120+
121+
// Component from which the event is generated.
122+
SourceComponent string `json:"sourceComponent"`
123+
124+
// Host name on which the event is generated.
125+
SourceHost string `json:"sourceHost"`
126+
127+
// Reference to a piece of an object, which triggered an event. For example
128+
// "spec.containers{name}" refers to container within pod with given name, if no container
129+
// name is specified, for example "spec.containers[2]", then it refers to container with
130+
// index 2 in this pod.
131+
SubObject string `json:"object"`
132+
133+
// The number of times this event has occurred.
134+
Count int `json:"count"`
135+
136+
// The time at which the event was first recorded.
137+
FirstSeen unversioned.Time `json:"firstSeen"`
138+
139+
// The time at which the most recent occurrence of this event was recorded.
140+
LastSeen unversioned.Time `json:"lastSeen"`
141+
142+
// Short, machine understandable string that gives the reason
143+
// for this event being generated.
144+
Reason string `json:"reason"`
145+
146+
// Event type (at the moment only normal and warning are supported).
147+
Type string `json:"type"`
148+
}
149+
107150
// Returns internal endpoint name for the given service properties, e.g.,
108151
// "my-service.namespace 80/TCP" or "my-service 53/TCP,53/UDP".
109152
func GetInternalEndpoint(serviceName, namespace string, ports []api.ServicePort) Endpoint {

src/app/backend/resource/event/event.go

Lines changed: 4 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -17,54 +17,11 @@ package event
1717
import (
1818
"strings"
1919

20+
"github.com/kubernetes/dashboard/resource/common"
2021
"k8s.io/kubernetes/pkg/api"
21-
"k8s.io/kubernetes/pkg/api/unversioned"
2222
"k8s.io/kubernetes/pkg/types"
2323
)
2424

25-
// Events response structure.
26-
type Events struct {
27-
// Namespace.
28-
Namespace string `json:"namespace"`
29-
30-
// List of events from given namespace.
31-
Events []Event `json:"events"`
32-
}
33-
34-
// Event is a single event representation.
35-
type Event struct {
36-
// A human-readable description of the status of related object.
37-
Message string `json:"message"`
38-
39-
// Component from which the event is generated.
40-
SourceComponent string `json:"sourceComponent"`
41-
42-
// Host name on which the event is generated.
43-
SourceHost string `json:"sourceHost"`
44-
45-
// Reference to a piece of an object, which triggered an event. For example
46-
// "spec.containers{name}" refers to container within pod with given name, if no container
47-
// name is specified, for example "spec.containers[2]", then it refers to container with
48-
// index 2 in this pod.
49-
SubObject string `json:"object"`
50-
51-
// The number of times this event has occurred.
52-
Count int `json:"count"`
53-
54-
// The time at which the event was first recorded.
55-
FirstSeen unversioned.Time `json:"firstSeen"`
56-
57-
// The time at which the most recent occurrence of this event was recorded.
58-
LastSeen unversioned.Time `json:"lastSeen"`
59-
60-
// Short, machine understandable string that gives the reason
61-
// for this event being generated.
62-
Reason string `json:"reason"`
63-
64-
// Event type (at the moment only normal and warning are supported).
65-
Type string `json:"type"`
66-
}
67-
6825
// FailedReasonPartials is an array of partial strings to correctly filter warning events.
6926
// Have to be lower case for correct case insensitive comparison.
7027
// Based on k8s official events reason file:
@@ -76,8 +33,8 @@ var FailedReasonPartials = []string{"failed", "err", "exceeded", "invalid", "unh
7633

7734
// GetPodsEventWarnings returns warning pod events by filtering out events targeting only given pods
7835
// TODO(floreks) : Import and use Set instead of custom function to get rid of duplicates
79-
func GetPodsEventWarnings(events []api.Event, pods []api.Pod) []Event {
80-
result := make([]Event, 0)
36+
func GetPodsEventWarnings(events []api.Event, pods []api.Pod) []common.Event {
37+
result := make([]common.Event, 0)
8138

8239
// Filter out only warning events
8340
events = getWarningEvents(events)
@@ -95,7 +52,7 @@ func GetPodsEventWarnings(events []api.Event, pods []api.Pod) []Event {
9552
events = removeDuplicates(events)
9653

9754
for _, event := range events {
98-
result = append(result, Event{
55+
result = append(result, common.Event{
9956
Message: event.Message,
10057
Reason: event.Reason,
10158
Type: event.Type,
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright 2015 Google Inc. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package event
16+
17+
import (
18+
"github.com/kubernetes/dashboard/resource/common"
19+
"k8s.io/kubernetes/pkg/api"
20+
client "k8s.io/kubernetes/pkg/client/unversioned"
21+
"k8s.io/kubernetes/pkg/fields"
22+
"k8s.io/kubernetes/pkg/labels"
23+
)
24+
25+
// GetEvents gets events associated to resource with given name.
26+
func GetEvents(client client.EventNamespacer, namespace, resourceName string) ([]api.Event, error) {
27+
28+
fieldSelector, err := fields.ParseSelector("involvedObject.name=" + resourceName)
29+
30+
if err != nil {
31+
return nil, err
32+
}
33+
34+
channels := &common.ResourceChannels{
35+
EventList: common.GetNamespacedEventListChannel(client, 1, namespace,
36+
api.ListOptions{
37+
LabelSelector: labels.Everything(),
38+
FieldSelector: fieldSelector,
39+
}),
40+
}
41+
42+
eventList := <-channels.EventList.List
43+
if err := <-channels.EventList.Error; err != nil {
44+
return nil, err
45+
}
46+
47+
return eventList.Items, nil
48+
}
49+
50+
// GetPodsEvents gets pods events associated to resource targeted by given resource selector.
51+
func GetPodsEvents(client client.Interface, namespace string, resourceSelector map[string]string) (
52+
[]api.Event, error) {
53+
54+
channels := &common.ResourceChannels{
55+
PodList: common.GetNamespacedPodListChannel(client, 1, namespace, api.ListOptions{
56+
LabelSelector: labels.SelectorFromSet(resourceSelector),
57+
FieldSelector: fields.Everything(),
58+
}),
59+
EventList: common.GetEventListChannel(client, 1),
60+
}
61+
62+
podList := <-channels.PodList.List
63+
if err := <-channels.PodList.Error; err != nil {
64+
return nil, err
65+
}
66+
67+
eventList := <-channels.EventList.List
68+
if err := <-channels.EventList.Error; err != nil {
69+
return nil, err
70+
}
71+
72+
events := FilterEventsByPodsUID(eventList.Items, podList.Items)
73+
74+
return events, nil
75+
}
76+
77+
// AppendEvents appends events from source slice to target events representation.
78+
func AppendEvents(source []api.Event, target common.EventList) common.EventList {
79+
for _, event := range source {
80+
target.Events = append(target.Events, common.Event{
81+
Message: event.Message,
82+
SourceComponent: event.Source.Component,
83+
SourceHost: event.Source.Host,
84+
SubObject: event.InvolvedObject.FieldPath,
85+
Count: event.Count,
86+
FirstSeen: event.FirstTimestamp,
87+
LastSeen: event.LastTimestamp,
88+
Reason: event.Reason,
89+
Type: event.Type,
90+
})
91+
}
92+
return target
93+
}

0 commit comments

Comments
 (0)