-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathnode.go
More file actions
437 lines (359 loc) · 12.1 KB
/
node.go
File metadata and controls
437 lines (359 loc) · 12.1 KB
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
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
// Package client provides a simple RMB interface to work with the node.
//
// # Requirements
//
// 1. A msgbusd instance must be running on the node. this client uses RMB (message bus)
// to send messages to nodes, and get the repspons.
// 2. A valid ed25519 key pair. this key is used to sign deployments and MUST be the same
// key used to configure the local twin on substrate.
//
// # Simple deployment
//
// create an instance from the default rmb client.
// ```
// cl, err := rmb.Default()
//
// if err != nil {
// panic(err)
// }
//
// ```
// then create an instance of the node client
// ```
// node := client.NewNodeClient(NodeTwinID, cl)
// ```
// define your deployment object
// ```
//
// dl := gridtypes.Deployment{
// Version: Version,
// TwinID: Twin, //LocalTwin,
// // this contract id must match the one on substrate
// Workloads: []gridtypes.Workload{
// network(), // network workload definition
// zmount(), // zmount workload definition
// publicip(), // public ip definition
// zmachine(), // zmachine definition
// },
// SignatureRequirement: gridtypes.SignatureRequirement{
// WeightRequired: 1,
// Requests: []gridtypes.SignatureRequest{
// {
// TwinID: Twin,
// Weight: 1,
// },
// },
// },
// }
//
// ```
// compute hash
// ```
// hash, err := dl.ChallengeHash()
//
// if err != nil {
// panic("failed to create hash")
// }
//
// fmt.Printf("Hash: %x\n", hash)
// ```
// create the contract and ge the contract id
// then
// “
// dl.ContractID = 11 // from substrate
// ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
// defer cancel()
// err = node.DeploymentDeploy(ctx, dl)
//
// if err != nil {
// panic(err)
// }
//
// ```
package client
import (
"context"
"net"
"github.com/threefoldtech/tfgrid-sdk-go/rmb-sdk-go"
"github.com/threefoldtech/zos/pkg"
"github.com/threefoldtech/zos/pkg/capacity/dmi"
"github.com/threefoldtech/zos/pkg/diagnostics"
"github.com/threefoldtech/zos/pkg/gridtypes"
)
// NodeClient struct
type NodeClient struct {
nodeTwin uint32
bus rmb.Client
}
type Version struct {
ZOS string `json:"zos"`
ZInit string `json:"zinit"`
}
type Interface struct {
IPs []string `json:"ips"`
Mac string `json:"mac"`
}
type ExitDevice struct {
// IsSingle is set to true if br-pub
// is connected to zos bridge
IsSingle bool `json:"is_single"`
// IsDual is set to true if br-pub is
// connected to a physical nic
IsDual bool `json:"is_dual"`
// AsDualInterface is set to the physical
// interface name if IsDual is true
AsDualInterface string `json:"dual_interface"`
}
type args map[string]interface{}
// NewNodeClient creates a new node RMB client. This client then can be used to
// communicate with the node over RMB.
func NewNodeClient(nodeTwin uint32, bus rmb.Client) *NodeClient {
return &NodeClient{nodeTwin, bus}
}
// DeploymentDeploy sends the deployment to the node for processing.
func (n *NodeClient) DeploymentDeploy(ctx context.Context, dl gridtypes.Deployment) error {
const cmd = "zos.deployment.deploy"
return n.bus.Call(ctx, n.nodeTwin, cmd, dl, nil)
}
// DeploymentUpdate update the given deployment. deployment must be a valid update for
// a deployment that has been already created via DeploymentDeploy
func (n *NodeClient) DeploymentUpdate(ctx context.Context, dl gridtypes.Deployment) error {
const cmd = "zos.deployment.update"
return n.bus.Call(ctx, n.nodeTwin, cmd, dl, nil)
}
// DeploymentGet gets a deployment via contract ID
func (n *NodeClient) DeploymentGet(ctx context.Context, contractID uint64) (dl gridtypes.Deployment, err error) {
const cmd = "zos.deployment.get"
in := args{
"contract_id": contractID,
}
if err = n.bus.Call(ctx, n.nodeTwin, cmd, in, &dl); err != nil {
return dl, err
}
return dl, nil
}
// DeploymentList gets all deployments for a twin
func (n *NodeClient) DeploymentList(ctx context.Context) (dls []gridtypes.Deployment, err error) {
const cmd = "zos.deployment.list"
err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &dls)
return
}
// DeploymentGet gets a deployment via contract ID
func (n *NodeClient) DeploymentChanges(ctx context.Context, contractID uint64) (changes []gridtypes.Workload, err error) {
const cmd = "zos.deployment.changes"
in := args{
"contract_id": contractID,
}
if err = n.bus.Call(ctx, n.nodeTwin, cmd, in, &changes); err != nil {
return changes, err
}
return changes, nil
}
// DeploymentDelete deletes a deployment, the node will make sure to decomission all deployments
// and set all workloads to deleted. A call to Get after delete is valid
func (n *NodeClient) DeploymentDelete(ctx context.Context, contractID uint64) error {
const cmd = "zos.deployment.delete"
in := args{
"contract_id": contractID,
}
return n.bus.Call(ctx, n.nodeTwin, cmd, in, nil)
}
// Counters (statistics) of the node
type Counters struct {
// Total system capacity
Total gridtypes.Capacity `json:"total"`
// Used capacity this include user + system resources
Used gridtypes.Capacity `json:"used"`
// System resource reserved by zos
System gridtypes.Capacity `json:"system"`
// Users statistics by zos
Users UsersCounters `json:"users"`
}
// UsersCounters the expected counters for deployments and workloads
type UsersCounters struct {
// Total deployments count
Deployments int `json:"deployments"`
// Total workloads count
Workloads int `json:"workloads"`
}
// GPU information
type GPU struct {
ID string `json:"id"`
Vendor string `json:"vendor"`
Device string `json:"device"`
Contract uint64 `json:"contract"`
}
// Counters returns some node statistics. Including total and available cpu, memory, storage, etc...
func (n *NodeClient) Counters(ctx context.Context) (counters Counters, err error) {
const cmd = "zos.statistics.get"
err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &counters)
return
}
// Pools returns statistics of separate pools
func (n *NodeClient) Pools(ctx context.Context) (pools []pkg.PoolMetrics, err error) {
const cmd = "zos.storage.pools"
err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &pools)
return
}
func (n *NodeClient) GPUs(ctx context.Context) (gpus []GPU, err error) {
const cmd = "zos.gpu.list"
err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &gpus)
return
}
// NetworkListWGPorts return a list of all "taken" ports on the node. A new deployment
// should be careful to use a free port for its network setup.
func (n *NodeClient) NetworkListWGPorts(ctx context.Context) ([]uint16, error) {
const cmd = "zos.network.list_wg_ports"
var result []uint16
if err := n.bus.Call(ctx, n.nodeTwin, cmd, nil, &result); err != nil {
return nil, err
}
return result, nil
}
func (n *NodeClient) HasPublicIPv6(ctx context.Context) (bool, error) {
const cmd = "zos.network.has_ipv6"
var result bool
if err := n.bus.Call(ctx, n.nodeTwin, cmd, nil, &result); err != nil {
return false, err
}
return result, nil
}
func (n *NodeClient) NetworkListInterfaces(ctx context.Context) (result map[string][]net.IP, err error) {
const cmd = "zos.network.interfaces"
err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &result)
return
}
// AdminRebootNode stops all the running services and reboots the node
func (n *NodeClient) AdminRebootNode(ctx context.Context) error {
const cmd = "zos.admin.reboot"
return n.bus.Call(ctx, n.nodeTwin, cmd, nil, nil)
}
// AdminRestartService restarts a zinit service
func (n *NodeClient) AdminRestartService(ctx context.Context, service string) error {
const cmd = "zos.admin.restart"
return n.bus.Call(ctx, n.nodeTwin, cmd, service, nil)
}
// AdminRestartAll restarts all zinit services
func (n *NodeClient) AdminRestartAll(ctx context.Context) error {
const cmd = "zos.admin.restart_all"
return n.bus.Call(ctx, n.nodeTwin, cmd, nil, nil)
}
// AdminShowLogs returns l lines of zinit logs
func (n *NodeClient) AdminShowLogs(ctx context.Context, l int) (logs []byte, err error) {
const cmd = "zos.admin.show_logs"
err = n.bus.Call(ctx, n.nodeTwin, cmd, l, &logs)
return
}
// AdminShowResolve return the content of /etc/resolv.conf
func (n *NodeClient) AdminShowResolve(ctx context.Context) (res []byte, err error) {
const cmd = "zos.admin.show_resolve"
err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &res)
return
}
// AdminShowOpenConnections return information about all open connections in the node
func (n *NodeClient) AdminShowOpenConnections(ctx context.Context) (res []byte, err error) {
const cmd = "zos.admin.show_open_connections"
err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &res)
return
}
// AdminStopWorkload stops a workload
func (n *NodeClient) AdminStopWorkload(ctx context.Context, twinID uint32, wlID uint64) error {
const cmd = "zos.admin.stop_workload"
args := struct {
TwinID uint32 `json:"twin_id"`
WorkloadID uint64 `json:"workload_id"`
}{
TwinID: twinID,
WorkloadID: wlID,
}
return n.bus.Call(ctx, n.nodeTwin, cmd, args, nil)
}
// AdminResumeWorkload stops a workload
func (n *NodeClient) AdminResumeWorkload(ctx context.Context, twinID uint32, wlID uint64) error {
const cmd = "zos.admin.resume_workload"
args := struct {
TwinID uint32 `json:"twin_id"`
WorkloadID uint64 `json:"workload_id"`
}{
TwinID: twinID,
WorkloadID: wlID,
}
return n.bus.Call(ctx, n.nodeTwin, cmd, args, nil)
}
// NetworkListAllInterfaces return all physical devices on a node
func (n *NodeClient) NetworkListAllInterfaces(ctx context.Context) (result map[string]Interface, err error) {
const cmd = "zos.admin.interfaces"
err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &result)
return
}
// NetworkSetPublicExitDevice select which physical interface to use as an exit device
// setting `iface` to `zos` will then make node run in a single nic setup.
func (n *NodeClient) NetworkSetPublicExitDevice(ctx context.Context, iface string) error {
const cmd = "zos.admin.set_public_nic"
return n.bus.Call(ctx, n.nodeTwin, cmd, iface, nil)
}
// NetworkGetPublicExitDevice gets the current dual nic setup of the node.
func (n *NodeClient) NetworkGetPublicExitDevice(ctx context.Context) (exit ExitDevice, err error) {
const cmd = "zos.admin.get_public_nic"
err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &exit)
return
}
// NetworkListPublicIPs list taken public IPs on the node
func (n *NodeClient) NetworkListPublicIPs(ctx context.Context) ([]string, error) {
const cmd = "zos.network.list_public_ips"
var result []string
if err := n.bus.Call(ctx, n.nodeTwin, cmd, nil, &result); err != nil {
return nil, err
}
return result, nil
}
// NetworkListPrivateIPs list private ips reserved for a network
func (n *NodeClient) NetworkListPrivateIPs(ctx context.Context, networkName string) ([]string, error) {
const cmd = "zos.network.list_private_ips"
var result []string
in := args{
"network_name": networkName,
}
if err := n.bus.Call(ctx, n.nodeTwin, cmd, in, &result); err != nil {
return nil, err
}
return result, nil
}
// NetworkGetPublicConfig returns the current public node network configuration. A node with a
// public config can be used as an access node for wireguard.
func (n *NodeClient) NetworkGetPublicConfig(ctx context.Context) (cfg pkg.PublicConfig, err error) {
const cmd = "zos.network.public_config_get"
err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &cfg)
return
}
func (n *NodeClient) SystemGetNodeFeatures(ctx context.Context) (feat []pkg.NodeFeature, err error) {
const cmd = "zos.system.node_features_get"
err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &feat)
return
}
func (n *NodeClient) SystemVersion(ctx context.Context) (ver Version, err error) {
const cmd = "zos.system.version"
if err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &ver); err != nil {
return
}
return
}
func (n *NodeClient) SystemDMI(ctx context.Context) (result dmi.DMI, err error) {
const cmd = "zos.system.dmi"
if err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &result); err != nil {
return
}
return
}
func (n *NodeClient) SystemHypervisor(ctx context.Context) (result string, err error) {
const cmd = "zos.system.hypervisor"
if err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &result); err != nil {
return
}
return
}
func (n *NodeClient) SystemDiagnostics(ctx context.Context) (result diagnostics.Diagnostics, err error) {
const cmd = "zos.system.diagnostics"
err = n.bus.Call(ctx, n.nodeTwin, cmd, nil, &result)
return
}