Skip to content

Commit 6d72bee

Browse files
maciaszczykmSebastian Florek
authored andcommitted
Add node resource backend (#860)
1 parent 3eb77b7 commit 6d72bee

File tree

17 files changed

+370
-82
lines changed

17 files changed

+370
-82
lines changed

src/app/backend/handler/apihandler.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/kubernetes/dashboard/resource/deployment"
3131
"github.com/kubernetes/dashboard/resource/job"
3232
. "github.com/kubernetes/dashboard/resource/namespace"
33+
"github.com/kubernetes/dashboard/resource/node"
3334
"github.com/kubernetes/dashboard/resource/petset"
3435
"github.com/kubernetes/dashboard/resource/pod"
3536
"github.com/kubernetes/dashboard/resource/replicaset"
@@ -293,6 +294,15 @@ func CreateHttpApiHandler(client *client.Client, heapsterClient HeapsterClient,
293294
To(apiHandler.handleGetPetSetDetail).
294295
Writes(petset.PetSetDetail{}))
295296

297+
apiV1Ws.Route(
298+
apiV1Ws.GET("/node").
299+
To(apiHandler.handleGetNodeList).
300+
Writes(node.NodeList{}))
301+
apiV1Ws.Route(
302+
apiV1Ws.GET("/node/{name}").
303+
To(apiHandler.handleGetNodeDetail).
304+
Writes(node.NodeDetail{}))
305+
296306
apiV1Ws.Route(
297307
apiV1Ws.DELETE("/{kind}/namespace/{namespace}/name/{name}").
298308
To(apiHandler.handleDeleteResource))
@@ -357,6 +367,28 @@ func (apiHandler *ApiHandler) handleGetServiceDetail(request *restful.Request, r
357367
response.WriteHeaderAndEntity(http.StatusCreated, result)
358368
}
359369

370+
// Handles get node list API call.
371+
func (apiHandler *ApiHandler) handleGetNodeList(request *restful.Request, response *restful.Response) {
372+
result, err := node.GetNodeList(apiHandler.client)
373+
if err != nil {
374+
handleInternalError(response, err)
375+
return
376+
}
377+
378+
response.WriteHeaderAndEntity(http.StatusCreated, result)
379+
}
380+
381+
// Handles get node detail API call.
382+
func (apiHandler *ApiHandler) handleGetNodeDetail(request *restful.Request, response *restful.Response) {
383+
name := request.PathParameter("name")
384+
result, err := node.GetNodeDetail(apiHandler.client, apiHandler.heapsterClient, name)
385+
if err != nil {
386+
handleInternalError(response, err)
387+
return
388+
}
389+
response.WriteHeaderAndEntity(http.StatusCreated, result)
390+
}
391+
360392
// Handles deploy API call.
361393
func (apiHandler *ApiHandler) handleDeploy(request *restful.Request, response *restful.Response) {
362394
appDeploymentSpec := new(AppDeploymentSpec)

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ import (
1818
"bytes"
1919

2020
"k8s.io/kubernetes/pkg/api"
21-
22-
"github.com/kubernetes/dashboard/resource/node"
2321
)
2422

2523
// Endpoint describes an endpoint that is host and a list of available ports for that host.
@@ -85,7 +83,7 @@ func getNodePortEndpoints(pods []api.Pod, service api.Service, nodes []api.Node)
8583
var addresses []api.NodeAddress
8684

8785
for _, pod := range pods {
88-
node := node.GetNodeByName(nodes, pod.Spec.NodeName)
86+
node := GetNodeByName(nodes, pod.Spec.NodeName)
8987
if node == nil {
9088
continue
9189
}
@@ -157,3 +155,14 @@ func getUniqueExternalAddresses(addresses []api.NodeAddress) []api.NodeAddress {
157155

158156
return result
159157
}
158+
159+
// GetNodeByName returns the node with the given name from the list
160+
func GetNodeByName(nodes []api.Node, nodeName string) *api.Node {
161+
for _, node := range nodes {
162+
if node.ObjectMeta.Name == nodeName {
163+
return &node
164+
}
165+
}
166+
167+
return nil
168+
}

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

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,22 +108,14 @@ type NodeListChannel struct {
108108

109109
// GetNodeListChannel returns a pair of channels to a Node list and errors that both must be read
110110
// numReads times.
111-
func GetNodeListChannel(client client.NodesInterface,
112-
nsQuery *NamespaceQuery, numReads int) NodeListChannel {
111+
func GetNodeListChannel(client client.NodesInterface, numReads int) NodeListChannel {
113112
channel := NodeListChannel{
114113
List: make(chan *api.NodeList, numReads),
115114
Error: make(chan error, numReads),
116115
}
117116

118117
go func() {
119118
list, err := client.Nodes().List(listEverything)
120-
var filteredItems []api.Node
121-
for _, item := range list.Items {
122-
if nsQuery.Matches(item.ObjectMeta.Namespace) {
123-
filteredItems = append(filteredItems, item)
124-
}
125-
}
126-
list.Items = filteredItems
127119
for i := 0; i < numReads; i++ {
128120
channel.List <- list
129121
channel.Error <- err

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ const (
9797
ResourceKindDaemonSet = "daemonset"
9898
ResourceKindJob = "job"
9999
ResourceKindPetSet = "petset"
100+
ResourceKindNode = "node"
100101
)
101102

102103
// ClientType represents type of client that is used to perform generic operations on resources.
@@ -131,6 +132,7 @@ var kindToAPIMapping = map[string]struct {
131132
ResourceKindDaemonSet: {"daemonsets", ClientTypeDefault},
132133
ResourceKindPetSet: {"petsets", ClientTypeAppsClient},
133134
ResourceKindJob: {"jobs", ClientTypeBatchClient},
135+
ResourceKindNode: {"nodes", ClientTypeDefault},
134136
}
135137

136138
// IsSelectorMatching returns true when an object with the given

src/app/backend/resource/daemonset/daemonsetlist.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func GetDaemonSetList(client *client.Client, nsQuery *common.NamespaceQuery) (*D
5757
ServiceList: common.GetServiceListChannel(client, nsQuery, 1),
5858
PodList: common.GetPodListChannel(client, nsQuery, 1),
5959
EventList: common.GetEventListChannel(client, nsQuery, 1),
60-
NodeList: common.GetNodeListChannel(client, nsQuery, 1),
60+
NodeList: common.GetNodeListChannel(client, 1),
6161
}
6262

6363
return GetDaemonSetListFromChannels(channels)

src/app/backend/resource/deployment/deploymentlist.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func GetDeploymentList(client client.Interface, nsQuery *common.NamespaceQuery)
5555
ServiceList: common.GetServiceListChannel(client, nsQuery, 1),
5656
PodList: common.GetPodListChannel(client, nsQuery, 1),
5757
EventList: common.GetEventListChannel(client, nsQuery, 1),
58-
NodeList: common.GetNodeListChannel(client, nsQuery, 1),
58+
NodeList: common.GetNodeListChannel(client, 1),
5959
}
6060

6161
return GetDeploymentListFromChannels(channels)

src/app/backend/resource/job/joblist.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func GetJobList(client client.Interface, nsQuery *common.NamespaceQuery) (*JobLi
5252
ServiceList: common.GetServiceListChannel(client, nsQuery, 1),
5353
PodList: common.GetPodListChannel(client, nsQuery, 1),
5454
EventList: common.GetEventListChannel(client, nsQuery, 1),
55-
NodeList: common.GetNodeListChannel(client, nsQuery, 1),
55+
NodeList: common.GetNodeListChannel(client, 1),
5656
}
5757

5858
return GetJobListFromChannels(channels)

src/app/backend/resource/node/nodecommon.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ import (
1818
"k8s.io/kubernetes/pkg/api"
1919
)
2020

21-
// GetNodeByName returns the node with the given name from the list
22-
func GetNodeByName(nodes []api.Node, nodeName string) *api.Node {
23-
for _, node := range nodes {
24-
if node.ObjectMeta.Name == nodeName {
25-
return &node
21+
//getContainerImages returns container image strings from the given node.
22+
func getContainerImages(node api.Node) []string {
23+
var containerImages []string
24+
for _, image := range node.Status.Images {
25+
for _, name := range image.Names {
26+
containerImages = append(containerImages, name)
2627
}
2728
}
28-
29-
return nil
29+
return containerImages
3030
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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 node
16+
17+
import (
18+
"log"
19+
20+
"github.com/kubernetes/dashboard/client"
21+
"github.com/kubernetes/dashboard/resource/common"
22+
"k8s.io/kubernetes/pkg/api"
23+
k8sClient "k8s.io/kubernetes/pkg/client/unversioned"
24+
)
25+
26+
// NodeDetail is a presentation layer view of Kubernetes Node resource. This means it is Node plus
27+
// additional augmented data we can get from other sources.
28+
type NodeDetail struct {
29+
ObjectMeta common.ObjectMeta `json:"objectMeta"`
30+
TypeMeta common.TypeMeta `json:"typeMeta"`
31+
32+
// Container images of the Node.
33+
ContainerImages []string `json:"containerImages"`
34+
35+
// External ID of the node assigned by some machine database (e.g. a cloud provider).
36+
ExternalID string `json:"externalID"`
37+
38+
// PodCIDR represents the pod IP range assigned to the node.
39+
PodCIDR string `json:"podCIDR"`
40+
41+
// ID of the node assigned by the cloud provider.
42+
ProviderID string `json:"providerID"`
43+
44+
// Unschedulable controls node schedulability of new pods. By default node is schedulable.
45+
Unschedulable bool `json:"unschedulable"`
46+
47+
// Set of ids/uuids to uniquely identify the node.
48+
NodeInfo api.NodeSystemInfo `json:"nodeInfo"`
49+
50+
// CPU limit specified (core number).
51+
CPUCapacity int64 `json:"cpuCapacity"`
52+
53+
// Memory limit specified (bytes).
54+
MemoryCapacity int64 `json:"memoryCapacity"`
55+
}
56+
57+
// GetNodeDetail gets node details.
58+
func GetNodeDetail(client k8sClient.Interface, heapsterClient client.HeapsterClient, name string) (
59+
*NodeDetail, error) {
60+
log.Printf("Getting details of %s node", name)
61+
62+
node, err := client.Nodes().Get(name)
63+
if err != nil {
64+
return nil, err
65+
}
66+
67+
nodeDetails := toNodeDetail(*node)
68+
return &nodeDetails, nil
69+
}
70+
71+
func toNodeDetail(node api.Node) NodeDetail {
72+
cpuCapacity, _ := node.Status.Capacity.Cpu().AsInt64()
73+
memoryCapacity, _ := node.Status.Capacity.Memory().AsInt64()
74+
75+
return NodeDetail{
76+
ObjectMeta: common.NewObjectMeta(node.ObjectMeta),
77+
TypeMeta: common.NewTypeMeta(common.ResourceKindNode),
78+
ContainerImages: getContainerImages(node),
79+
ExternalID: node.Spec.ExternalID,
80+
ProviderID: node.Spec.ProviderID,
81+
PodCIDR: node.Spec.PodCIDR,
82+
Unschedulable: node.Spec.Unschedulable,
83+
NodeInfo: node.Status.NodeInfo,
84+
CPUCapacity: cpuCapacity,
85+
MemoryCapacity: memoryCapacity,
86+
}
87+
}
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 node
16+
17+
import (
18+
"log"
19+
20+
"github.com/kubernetes/dashboard/resource/common"
21+
"k8s.io/kubernetes/pkg/api"
22+
client "k8s.io/kubernetes/pkg/client/unversioned"
23+
"k8s.io/kubernetes/pkg/fields"
24+
"k8s.io/kubernetes/pkg/labels"
25+
)
26+
27+
// NodeList contains a list of nodes in the cluster.
28+
type NodeList struct {
29+
// Unordered list of Nodes.
30+
Nodes []Node `json:"nodes"`
31+
}
32+
33+
// Node is a presentation layer view of Kubernetes nodes. This means it is node plus additional
34+
// augumented data we can get from other sources.
35+
type Node struct {
36+
ObjectMeta common.ObjectMeta `json:"objectMeta"`
37+
TypeMeta common.TypeMeta `json:"typeMeta"`
38+
39+
// Container images of the node.
40+
ContainerImages []string `json:"containerImages"`
41+
42+
// External ID of the node assigned by some machine database (e.g. a cloud provider).
43+
ExternalID string `json:"externalID"`
44+
45+
// PodCIDR represents the pod IP range assigned to the node.
46+
PodCIDR string `json:"podCIDR"`
47+
48+
// ID of the node assigned by the cloud provider.
49+
ProviderID string `json:"providerID"`
50+
51+
// Unschedulable controls node schedulability of new pods. By default node is schedulable.
52+
Unschedulable bool `json:"unschedulable"`
53+
}
54+
55+
// GetNodeList returns a list of all Nodes in the cluster.
56+
func GetNodeList(client client.Interface) (*NodeList, error) {
57+
log.Printf("Getting list of all nodes in the cluster")
58+
59+
nodes, err := client.Nodes().List(api.ListOptions{
60+
LabelSelector: labels.Everything(),
61+
FieldSelector: fields.Everything(),
62+
})
63+
64+
if err != nil {
65+
return nil, err
66+
}
67+
68+
return toNodeList(nodes.Items), nil
69+
}
70+
71+
func toNodeList(nodes []api.Node) *NodeList {
72+
nodeList := &NodeList{
73+
Nodes: make([]Node, 0),
74+
}
75+
76+
for _, node := range nodes {
77+
nodeList.Nodes = append(nodeList.Nodes, toNode(node))
78+
}
79+
80+
return nodeList
81+
}
82+
83+
func toNode(node api.Node) Node {
84+
return Node{
85+
ObjectMeta: common.NewObjectMeta(node.ObjectMeta),
86+
TypeMeta: common.NewTypeMeta(common.ResourceKindNode),
87+
ContainerImages: getContainerImages(node),
88+
ExternalID: node.Spec.ExternalID,
89+
ProviderID: node.Spec.ProviderID,
90+
PodCIDR: node.Spec.PodCIDR,
91+
Unschedulable: node.Spec.Unschedulable,
92+
}
93+
}

0 commit comments

Comments
 (0)