Skip to content

Commit 30f5943

Browse files
authored
Add api to get cluster nodes' resources (#260)
1 parent 412ac0a commit 30f5943

13 files changed

+1172
-0
lines changed

models/cluster_resources.go

Lines changed: 97 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

models/node_info.go

Lines changed: 97 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

models/node_taints.go

Lines changed: 66 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

restapi/admin_nodes.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// This file is part of MinIO Console Server
2+
// Copyright (c) 2020 MinIO, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package restapi
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"log"
23+
"strings"
24+
25+
"github.com/minio/console/cluster"
26+
27+
"github.com/go-openapi/runtime/middleware"
28+
"github.com/go-openapi/swag"
29+
"github.com/minio/console/models"
30+
"github.com/minio/console/restapi/operations"
31+
"github.com/minio/console/restapi/operations/admin_api"
32+
corev1 "k8s.io/api/core/v1"
33+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34+
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
35+
)
36+
37+
func registerNodesHandlers(api *operations.ConsoleAPI) {
38+
api.AdminAPIGetClusterResourcesHandler = admin_api.GetClusterResourcesHandlerFunc(func(params admin_api.GetClusterResourcesParams, session *models.Principal) middleware.Responder {
39+
resp, err := getClusterResourcesResponse(session)
40+
if err != nil {
41+
return admin_api.NewGetClusterResourcesDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
42+
}
43+
return admin_api.NewGetClusterResourcesOK().WithPayload(resp)
44+
})
45+
}
46+
47+
// getClusterResources get cluster nodes and collects taints, available and allocatable resources of the node
48+
func getClusterResources(ctx context.Context, clientset v1.CoreV1Interface) (*models.ClusterResources, error) {
49+
// get all nodes from cluster
50+
nodes, err := clientset.Nodes().List(ctx, metav1.ListOptions{})
51+
if err != nil {
52+
return nil, err
53+
}
54+
// construct ClusterResources response
55+
res := &models.ClusterResources{}
56+
57+
for _, n := range nodes.Items {
58+
// Get Total Resources
59+
totalResources := make(map[string]int64)
60+
for resource, quantity := range n.Status.Capacity {
61+
totalResources[string(resource)] = quantity.Value()
62+
}
63+
64+
// Get Allocatable Resources
65+
allocatableResources := make(map[string]int64)
66+
for resource, quantity := range n.Status.Allocatable {
67+
allocatableResources[string(resource)] = quantity.Value()
68+
}
69+
70+
// Get Node taints and split them by effect
71+
taints := &models.NodeTaints{}
72+
for _, t := range n.Spec.Taints {
73+
var taint string
74+
// when value is not defined the taint string is created without `=`
75+
if strings.TrimSpace(t.Value) != "" {
76+
taint = fmt.Sprintf("%s=%s:%s", t.Key, t.Value, t.Effect)
77+
} else {
78+
taint = fmt.Sprintf("%s:%s", t.Key, t.Effect)
79+
}
80+
switch t.Effect {
81+
case corev1.TaintEffectNoSchedule:
82+
taints.NoSchedule = append(taints.NoSchedule, taint)
83+
case corev1.TaintEffectNoExecute:
84+
taints.NoExecute = append(taints.NoExecute, taint)
85+
case corev1.TaintEffectPreferNoSchedule:
86+
taints.PreferNoSchedule = append(taints.PreferNoSchedule, taint)
87+
default:
88+
continue
89+
}
90+
}
91+
92+
// create node object an add it to the nodes list
93+
nodeInfo := &models.NodeInfo{
94+
Name: n.Name,
95+
Taints: taints,
96+
AllocatableResources: allocatableResources,
97+
TotalResources: totalResources,
98+
}
99+
res.Nodes = append(res.Nodes, nodeInfo)
100+
}
101+
return res, nil
102+
}
103+
104+
func getClusterResourcesResponse(session *models.Principal) (*models.ClusterResources, error) {
105+
ctx := context.Background()
106+
client, err := cluster.K8sClient(session.SessionToken)
107+
if err != nil {
108+
log.Println("error getting k8sClient:", err)
109+
return nil, err
110+
}
111+
112+
clusterResources, err := getClusterResources(ctx, client.CoreV1())
113+
if err != nil {
114+
log.Println("error getting cluster's resources:", err)
115+
return nil, err
116+
117+
}
118+
return clusterResources, nil
119+
}

0 commit comments

Comments
 (0)