forked from goodrain/rainbond
-
Notifications
You must be signed in to change notification settings - Fork 0
/
node.go
355 lines (311 loc) · 11.5 KB
/
node.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
// RAINBOND, Application Management Platform
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. For any non-GPL usage of Rainbond,
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
// must be obtained first.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package client
import (
"strings"
"time"
"k8s.io/client-go/pkg/api/v1"
"github.com/Sirupsen/logrus"
client "github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/mvcc/mvccpb"
conf "github.com/goodrain/rainbond/cmd/node/option"
store "github.com/goodrain/rainbond/node/core/store"
"github.com/pquerna/ffjson/ffjson"
)
//APIHostNode api host node
type APIHostNode struct {
ID string `json:"uuid" validate:"uuid"`
HostName string `json:"host_name" validate:"host_name"`
InternalIP string `json:"internal_ip" validate:"internal_ip|ip"`
ExternalIP string `json:"external_ip" validate:"external_ip|ip"`
RootPass string `json:"root_pass,omitempty"`
Role []string `json:"role" validate:"role|required"`
Labels map[string]string `json:"labels"`
}
//Clone Clone
func (a APIHostNode) Clone() *HostNode {
hn := &HostNode{
ID: a.ID,
HostName: a.HostName,
InternalIP: a.InternalIP,
ExternalIP: a.ExternalIP,
RootPass: a.RootPass,
Role: a.Role,
Labels: a.Labels,
NodeStatus: &NodeStatus{},
}
return hn
}
//HostNode rainbond node entity
type HostNode struct {
ID string `json:"uuid"`
HostName string `json:"host_name"`
CreateTime time.Time `json:"create_time"`
InternalIP string `json:"internal_ip"`
ExternalIP string `json:"external_ip"`
RootPass string `json:"root_pass,omitempty"`
KeyPath string `json:"key_path,omitempty"` //管理节点key文件路径
AvailableMemory int64 `json:"available_memory"`
AvailableCPU int64 `json:"available_cpu"`
Mode string `json:"mode"`
Role HostRule `json:"role"` //节点属性 compute manage storage
Status string `json:"status"` //节点状态 create,init,running,stop,delete
Labels map[string]string `json:"labels"` //节点标签 内置标签+用户自定义标签
Unschedulable bool `json:"unschedulable"` //不可调度
NodeStatus *NodeStatus `json:"node_status,omitempty"`
ClusterNode
}
//NodeStatus node status
type NodeStatus struct {
Status string `json:"status"` //installed running offline unknown
Conditions []NodeCondition `json:"conditions,omitempty"`
NodeInfo NodeSystemInfo `json:"nodeInfo,omitempty" protobuf:"bytes,7,opt,name=nodeInfo"`
}
//UpdateK8sNodeStatus update rainbond node status by k8s node
func (n *HostNode) UpdateK8sNodeStatus(k8sNode v1.Node) {
status := k8sNode.Status
n.UpdataK8sCondition(status.Conditions)
n.NodeStatus.NodeInfo = NodeSystemInfo{
MachineID: status.NodeInfo.MachineID,
SystemUUID: status.NodeInfo.SystemUUID,
BootID: status.NodeInfo.BootID,
KernelVersion: status.NodeInfo.KernelVersion,
OSImage: status.NodeInfo.OSImage,
OperatingSystem: status.NodeInfo.OperatingSystem,
ContainerRuntimeVersion: status.NodeInfo.ContainerRuntimeVersion,
Architecture: status.NodeInfo.Architecture,
}
n.Unschedulable = k8sNode.Spec.Unschedulable
if n.Unschedulable {
n.Status = "unschedulable"
} else {
n.Status = "running"
}
}
// NodeSystemInfo is a set of ids/uuids to uniquely identify the node.
type NodeSystemInfo struct {
// MachineID reported by the node. For unique machine identification
// in the cluster this field is preferred. Learn more from man(5)
// machine-id: http://man7.org/linux/man-pages/man5/machine-id.5.html
MachineID string `json:"machineID"`
// SystemUUID reported by the node. For unique machine identification
// MachineID is preferred. This field is specific to Red Hat hosts
// https://access.redhat.com/documentation/en-US/Red_Hat_Subscription_Management/1/html/RHSM/getting-system-uuid.html
SystemUUID string `json:"systemUUID"`
// Boot ID reported by the node.
BootID string `json:"bootID" protobuf:"bytes,3,opt,name=bootID"`
// Kernel Version reported by the node from 'uname -r' (e.g. 3.16.0-0.bpo.4-amd64).
KernelVersion string `json:"kernelVersion" `
// OS Image reported by the node from /etc/os-release (e.g. Debian GNU/Linux 7 (wheezy)).
OSImage string `json:"osImage"`
// ContainerRuntime Version reported by the node through runtime remote API (e.g. docker://1.5.0).
ContainerRuntimeVersion string `json:"containerRuntimeVersion"`
// The Operating System reported by the node
OperatingSystem string `json:"operatingSystem"`
// The Architecture reported by the node
Architecture string `json:"architecture"`
MemorySize uint64 `json:"memorySize"`
}
//Decode decode node info
func (n *HostNode) Decode(data []byte) error {
if err := ffjson.Unmarshal(data, n); err != nil {
logrus.Error("decode node info error:", err.Error())
return err
}
return nil
}
type NodeList []*HostNode
func (list NodeList) Len() int {
return len(list)
}
func (list NodeList) Less(i, j int) bool {
if list[i].InternalIP < list[j].InternalIP {
return true
} else {
return false
}
}
func (list NodeList) Swap(i, j int) {
var temp = list[i]
list[i] = list[j]
list[j] = temp
}
//GetNodeFromKV 从etcd解析node信息
func GetNodeFromKV(kv *mvccpb.KeyValue) *HostNode {
var node HostNode
if err := ffjson.Unmarshal(kv.Value, &node); err != nil {
logrus.Error("parse node info error:", err.Error())
return nil
}
return &node
}
//UpdataK8sCondition 更新k8s节点的状态到rainbond节点
func (n *HostNode) UpdataK8sCondition(conditions []v1.NodeCondition) {
for _, con := range conditions {
rbcon := NodeCondition{
Type: NodeConditionType(con.Type),
Status: ConditionStatus(con.Status),
LastHeartbeatTime: con.LastHeartbeatTime.Time,
LastTransitionTime: con.LastTransitionTime.Time,
Reason: con.Reason,
Message: con.Message,
}
n.UpdataCondition(rbcon)
}
}
//DeleteCondition DeleteCondition
func (n *HostNode) DeleteCondition(types ...NodeConditionType) {
if n.NodeStatus == nil {
return
}
for _, t := range types {
for i, c := range n.NodeStatus.Conditions {
if c.Type.Compare(t) {
n.NodeStatus.Conditions = append(n.NodeStatus.Conditions[:i], n.NodeStatus.Conditions[i+1:]...)
break
}
}
}
}
//UpdataCondition 更新状态
func (n *HostNode) UpdataCondition(conditions ...NodeCondition) {
if n.NodeStatus == nil {
n.NodeStatus = &NodeStatus{}
}
for _, newcon := range conditions {
var update bool
if n.NodeStatus.Conditions != nil {
for i, con := range n.NodeStatus.Conditions {
if con.Type.Compare(newcon.Type) {
n.NodeStatus.Conditions[i] = newcon
update = true
break
}
}
}
if !update {
n.NodeStatus.Conditions = append(n.NodeStatus.Conditions, newcon)
}
}
}
//HostRule 节点角色
type HostRule []string
//ComputeNode 计算节点
var ComputeNode = "compute"
//ManageNode 管理节点
var ManageNode = "manage"
//StorageNode 存储节点
var StorageNode = "storage"
//LBNode 边缘负载均衡节点
var LBNode = "lb"
//HasRule 是否具有什么角色
func (h HostRule) HasRule(rule string) bool {
for _, v := range h {
if v == rule {
return true
}
}
return false
}
func (h HostRule) String() string {
return strings.Join(h, ",")
}
//NodeConditionType NodeConditionType
type NodeConditionType string
// These are valid conditions of node.
const (
// NodeReady means this node is working
NodeReady NodeConditionType = "Ready"
// InstallNotReady means the installation task was not completed in this node.
InstallNotReady NodeConditionType = "InstallNotReady"
// NodeInit means node already install rainbond node and regist
NodeInit NodeConditionType = "NodeInit"
OutOfDisk NodeConditionType = "OutOfDisk"
MemoryPressure NodeConditionType = "MemoryPressure"
DiskPressure NodeConditionType = "DiskPressure"
)
//Compare 比较
func (nt NodeConditionType) Compare(ent NodeConditionType) bool {
return string(nt) == string(ent)
}
//ConditionStatus ConditionStatus
type ConditionStatus string
// These are valid condition statuses. "ConditionTrue" means a resource is in the condition.
// "ConditionFalse" means a resource is not in the condition. "ConditionUnknown" means kubernetes
// can't decide if a resource is in the condition or not. In the future, we could add other
// intermediate conditions, e.g. ConditionDegraded.
const (
ConditionTrue ConditionStatus = "True"
ConditionFalse ConditionStatus = "False"
ConditionUnknown ConditionStatus = "Unknown"
)
// NodeCondition contains condition information for a node.
type NodeCondition struct {
// Type of node condition.
Type NodeConditionType `json:"type" `
// Status of the condition, one of True, False, Unknown.
Status ConditionStatus `json:"status" `
// Last time we got an update on a given condition.
// +optional
LastHeartbeatTime time.Time `json:"lastHeartbeatTime,omitempty" `
// Last time the condition transit from one status to another.
// +optional
LastTransitionTime time.Time `json:"lastTransitionTime,omitempty" `
// (brief) reason for the condition's last transition.
// +optional
Reason string `json:"reason,omitempty"`
// Human readable message indicating details about last transition.
// +optional
Message string `json:"message,omitempty"`
}
// ClusterNode 集群节点实体
type ClusterNode struct {
PID string `json:"pid"` // 进程 pid
Version string `json:"version"`
UpTime time.Time `json:"up"` // 启动时间
DownTime time.Time `json:"down"` // 上次关闭时间
Alived bool `json:"alived"` // 是否可用
Connected bool `json:"connected"` // 当 Alived 为 true 时有效,表示心跳是否正常
}
//String string
func (h *HostNode) String() string {
res, _ := ffjson.Marshal(h)
return string(res)
}
//Put 节点上线更新
func (h *HostNode) Put(opts ...client.OpOption) (*client.PutResponse, error) {
return store.DefalutClient.Put(conf.Config.OnlineNodePath+"/"+h.ID, h.PID, opts...)
}
//Update 更新节点信息,由节点启动时调用
func (h *HostNode) Update() (*client.PutResponse, error) {
return store.DefalutClient.Put(conf.Config.NodePath+"/"+h.ID, h.String())
}
//DeleteNode 删除节点
func (h *HostNode) DeleteNode() (*client.DeleteResponse, error) {
return store.DefalutClient.Delete(conf.Config.NodePath + "/" + h.ID)
}
//Del 删除
func (h *HostNode) Del() (*client.DeleteResponse, error) {
return store.DefalutClient.Delete(conf.Config.OnlineNodePath + h.ID)
}
//GetNodes 获取节点
func GetNodes() (nodes []*HostNode, err error) {
return nil, nil
}
// Down 节点下线
func (h *HostNode) Down() {
h.Alived, h.DownTime = false, time.Now()
h.Update()
}