Skip to content

Commit 5f1e09c

Browse files
Sebastien CoavouxSebastien Coavoux
authored andcommitted
Add: new routes for daemonsets
1 parent d7b0cec commit 5f1e09c

File tree

8 files changed

+596
-8
lines changed

8 files changed

+596
-8
lines changed

src/app/backend/handler/apihandler.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
. "github.com/kubernetes/dashboard/client"
2626
"github.com/kubernetes/dashboard/resource/common"
2727
. "github.com/kubernetes/dashboard/resource/container"
28+
"github.com/kubernetes/dashboard/resource/daemonset"
2829
"github.com/kubernetes/dashboard/resource/deployment"
2930
. "github.com/kubernetes/dashboard/resource/namespace"
3031
"github.com/kubernetes/dashboard/resource/pod"
@@ -203,6 +204,23 @@ func CreateHttpApiHandler(client *client.Client, heapsterClient HeapsterClient,
203204
To(apiHandler.handleGetDeployments).
204205
Writes(deployment.DeploymentList{}))
205206
wsContainer.Add(deploymentsWs)
207+
daemonSetWs := new(restful.WebService)
208+
daemonSetWs.Filter(wsLogger)
209+
daemonSetWs.Path("/api/v1/daemonsets").
210+
Consumes(restful.MIME_JSON).
211+
Produces(restful.MIME_JSON)
212+
daemonSetWs.Route(
213+
daemonSetWs.GET("").
214+
To(apiHandler.handleGetDaemonSetList).
215+
Writes(daemonset.DaemonSetList{}))
216+
daemonSetWs.Route(
217+
daemonSetWs.GET("/{namespace}/{daemonSet}").
218+
To(apiHandler.handleGetDaemonSetDetail).
219+
Writes(daemonset.DaemonSetDetail{}))
220+
daemonSetWs.Route(
221+
daemonSetWs.DELETE("/{namespace}/{daemonSet}").
222+
To(apiHandler.handleDeleteDaemonSet))
223+
wsContainer.Add(daemonSetWs)
206224

207225
namespacesWs := new(restful.WebService)
208226
namespacesWs.Filter(wsLogger)
@@ -660,3 +678,53 @@ func handleInternalError(response *restful.Response, err error) {
660678
response.AddHeader("Content-Type", "text/plain")
661679
response.WriteErrorString(http.StatusInternalServerError, err.Error()+"\n")
662680
}
681+
682+
// Handles get Daemon Set list API call.
683+
func (apiHandler *ApiHandler) handleGetDaemonSetList(
684+
request *restful.Request, response *restful.Response) {
685+
686+
namespace := request.PathParameter("namespace")
687+
result, err := daemonset.GetDaemonSetList(apiHandler.client, namespace)
688+
if err != nil {
689+
handleInternalError(response, err)
690+
return
691+
}
692+
693+
response.WriteHeaderAndEntity(http.StatusCreated, result)
694+
}
695+
696+
// Handles get Daemon Set detail API call.
697+
func (apiHandler *ApiHandler) handleGetDaemonSetDetail(
698+
request *restful.Request, response *restful.Response) {
699+
700+
namespace := request.PathParameter("namespace")
701+
daemonSet := request.PathParameter("daemonSet")
702+
result, err := daemonset.GetDaemonSetDetail(apiHandler.client, apiHandler.heapsterClient, namespace, daemonSet)
703+
if err != nil {
704+
handleInternalError(response, err)
705+
return
706+
}
707+
708+
response.WriteHeaderAndEntity(http.StatusCreated, result)
709+
}
710+
711+
// Handles delete Daemon Set API call.
712+
func (apiHandler *ApiHandler) handleDeleteDaemonSet(
713+
request *restful.Request, response *restful.Response) {
714+
715+
namespace := request.PathParameter("namespace")
716+
daemonSet := request.PathParameter("daemonSet")
717+
deleteServices, err := strconv.ParseBool(request.QueryParameter("deleteServices"))
718+
if err != nil {
719+
handleInternalError(response, err)
720+
return
721+
}
722+
723+
if err := daemonset.DeleteDaemonSet(apiHandler.client, namespace,
724+
daemonSet, deleteServices); err != nil {
725+
handleInternalError(response, err)
726+
return
727+
}
728+
729+
response.WriteHeader(http.StatusOK)
730+
}

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package common
1616

1717
import (
1818
"k8s.io/kubernetes/pkg/api"
19+
"k8s.io/kubernetes/pkg/api/unversioned"
1920
)
2021

2122
func FilterNamespacedPodsBySelector(pods []api.Pod, namespace string,
@@ -24,7 +25,7 @@ func FilterNamespacedPodsBySelector(pods []api.Pod, namespace string,
2425
var matchingPods []api.Pod
2526
for _, pod := range pods {
2627
if pod.ObjectMeta.Namespace == namespace &&
27-
IsLabelSelectorMatching(resourceSelector, pod.Labels) {
28+
IsSelectorMatching(resourceSelector, pod.Labels) {
2829
matchingPods = append(matchingPods, pod)
2930
}
3031
}
@@ -37,7 +38,18 @@ func FilterPodsBySelector(pods []api.Pod, resourceSelector map[string]string) []
3738

3839
var matchingPods []api.Pod
3940
for _, pod := range pods {
40-
if IsLabelSelectorMatching(resourceSelector, pod.Labels) {
41+
if IsSelectorMatching(resourceSelector, pod.Labels) {
42+
matchingPods = append(matchingPods, pod)
43+
}
44+
}
45+
return matchingPods
46+
}
47+
48+
func FilterPodsByLabelSelector(pods []api.Pod, labelSelector *unversioned.LabelSelector) []api.Pod {
49+
50+
var matchingPods []api.Pod
51+
for _, pod := range pods {
52+
if IsLabelSelectorMatching(pod.Labels, labelSelector) {
4153
matchingPods = append(matchingPods, pod)
4254
}
4355
}

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ type ResourceChannels struct {
4343
// List and error channels to Deployments.
4444
DeploymentList DeploymentListChannel
4545

46+
// List and error channels to Daemon Sets.
47+
DaemonSetList DaemonSetListChannel
48+
4649
// List and error channels to Services.
4750
ServiceList ServiceListChannel
4851

@@ -280,3 +283,28 @@ func GetReplicaSetListChannel(client client.ReplicaSetsNamespacer, numReads int)
280283

281284
return channel
282285
}
286+
287+
// List and error channels to Nodes.
288+
type DaemonSetListChannel struct {
289+
List chan *extensions.DaemonSetList
290+
Error chan error
291+
}
292+
293+
// Returns a pair of channels to a DaemonSet list and errors that both must be read
294+
// numReads times.
295+
func GetDaemonSetListChannel(client client.DaemonSetsNamespacer, numReads int) DaemonSetListChannel {
296+
channel := DaemonSetListChannel{
297+
List: make(chan *extensions.DaemonSetList, numReads),
298+
Error: make(chan error, numReads),
299+
}
300+
301+
go func() {
302+
rcs, err := client.DaemonSets(api.NamespaceAll).List(listEverything)
303+
for i := 0; i < numReads; i++ {
304+
channel.List <- rcs
305+
channel.Error <- err
306+
}
307+
}()
308+
309+
return channel
310+
}

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ const (
9494
ResourceKindPod = "pod"
9595
ResourceKindEvent = "event"
9696
ResourceKindReplicationController = "replicationcontroller"
97+
ResourceKindDaemonSet = "daemonset"
9798
)
9899

99100
// Mapping from resource kind to K8s apiserver API path. This is mostly pluralization, because
@@ -106,24 +107,40 @@ var kindToAPIPathMapping = map[string]string{
106107
ResourceKindReplicationController: "replicationcontrollers",
107108
ResourceKindDeployment: "deployments",
108109
ResourceKindReplicaSet: "replicasets",
110+
ResourceKindDaemonSet: "daemonsets",
109111
}
110112

111-
// IsLabelSelectorMatching returns true when an object with the given
113+
// IsSelectorMatching returns true when an object with the given
112114
// selector targets the same Resources (or subset) that
113115
// the tested object with the given selector.
114-
func IsLabelSelectorMatching(labelSelector map[string]string,
116+
func IsSelectorMatching(labelSelector map[string]string,
115117
testedObjectLabels map[string]string) bool {
116118

117-
// If there are no label selectors, then assume it targets different Resource.
119+
// If service has no selectors, then assume it targets different Resource.
118120
if len(labelSelector) == 0 {
119121
return false
120122
}
121-
122123
for label, value := range labelSelector {
123124
if rsValue, ok := testedObjectLabels[label]; !ok || rsValue != value {
124125
return false
125126
}
126127
}
128+
return true
129+
}
127130

131+
// Returns true when a resrouce (Service / Pod) with the given selector targets
132+
// the same Pod (or itself) that a Daemon Set with the given selector.
133+
func IsLabelSelectorMatching(selector map[string]string,
134+
labelSelector *unversioned.LabelSelector) bool {
135+
136+
// If the resrouce has no selectors, then assume it targets different Pods.
137+
if len(selector) == 0 {
138+
return false
139+
}
140+
for label, value := range selector {
141+
if rsValue, ok := labelSelector.MatchLabels[label]; !ok || rsValue != value {
142+
return false
143+
}
144+
}
128145
return true
129146
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
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 daemonset
16+
17+
import (
18+
"github.com/kubernetes/dashboard/resource/common"
19+
// "github.com/kubernetes/dashboard/resource/event"
20+
"k8s.io/kubernetes/pkg/api"
21+
"k8s.io/kubernetes/pkg/api/unversioned"
22+
"k8s.io/kubernetes/pkg/apis/extensions"
23+
client "k8s.io/kubernetes/pkg/client/unversioned"
24+
"k8s.io/kubernetes/pkg/fields"
25+
"k8s.io/kubernetes/pkg/labels"
26+
)
27+
28+
type DaemonSetWithPods struct {
29+
DaemonSet *extensions.DaemonSet
30+
Pods *api.PodList
31+
}
32+
33+
// Returns structure containing DaemonSet and Pods for the given daemon set.
34+
func getRawDaemonSetWithPods(client client.Interface, namespace, name string) (
35+
*DaemonSetWithPods, error) {
36+
daemonSet, err := client.Extensions().DaemonSets(namespace).Get(name)
37+
if err != nil {
38+
return nil, err
39+
}
40+
41+
labelSelector, err := unversioned.LabelSelectorAsSelector(daemonSet.Spec.Selector)
42+
if err != nil {
43+
return nil, err
44+
}
45+
46+
pods, err := client.Pods(namespace).List(
47+
api.ListOptions{
48+
LabelSelector: labelSelector,
49+
FieldSelector: fields.Everything(),
50+
})
51+
52+
if err != nil {
53+
return nil, err
54+
}
55+
56+
daemonSetAndPods := &DaemonSetWithPods{
57+
DaemonSet: daemonSet,
58+
Pods: pods,
59+
}
60+
return daemonSetAndPods, nil
61+
}
62+
63+
// Retrieves Pod list that belongs to a Daemon Set.
64+
func getRawDaemonSetPods(client client.Interface, namespace, name string) (*api.PodList, error) {
65+
daemonSetAndPods, err := getRawDaemonSetWithPods(client, namespace, name)
66+
if err != nil {
67+
return nil, err
68+
}
69+
return daemonSetAndPods.Pods, nil
70+
}
71+
72+
// Returns aggregate information about daemon set pods.
73+
func getDaemonSetPodInfo(daemonSet *extensions.DaemonSet, pods []api.Pod) common.PodInfo {
74+
result := common.PodInfo{}
75+
for _, pod := range pods {
76+
switch pod.Status.Phase {
77+
case api.PodRunning:
78+
result.Running++
79+
case api.PodPending:
80+
result.Pending++
81+
case api.PodFailed:
82+
result.Failed++
83+
}
84+
}
85+
86+
return result
87+
}
88+
89+
// Based on given selector returns list of services that are candidates for deletion.
90+
// Services are matched by daemon sets' label selector. They are deleted if given
91+
// label selector is targeting only 1 daemon set.
92+
func getServicesForDSDeletion(client client.Interface, labelSelector labels.Selector,
93+
namespace string) ([]api.Service, error) {
94+
95+
daemonSet, err := client.Extensions().DaemonSets(namespace).List(api.ListOptions{
96+
LabelSelector: labelSelector,
97+
FieldSelector: fields.Everything(),
98+
})
99+
if err != nil {
100+
return nil, err
101+
}
102+
103+
// if label selector is targeting only 1 daemon set
104+
// then we can delete services targeted by this label selector,
105+
// otherwise we can not delete any services so just return empty list
106+
if len(daemonSet.Items) != 1 {
107+
return []api.Service{}, nil
108+
}
109+
110+
services, err := client.Services(namespace).List(api.ListOptions{
111+
LabelSelector: labelSelector,
112+
FieldSelector: fields.Everything(),
113+
})
114+
if err != nil {
115+
return nil, err
116+
}
117+
118+
return services.Items, nil
119+
}

0 commit comments

Comments
 (0)