Skip to content

Commit e569989

Browse files
committed
add host capability
1 parent ef0b5ad commit e569989

File tree

14 files changed

+1434
-5
lines changed

14 files changed

+1434
-5
lines changed

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "host/vendor/github.com/cloudfoundry/gosigar"]
2+
path = host/vendor/github.com/cloudfoundry/gosigar
3+
url = https://github.com/cloudfoundry/gosigar

host/metrics.go

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package host
2+
3+
import (
4+
"time"
5+
6+
"github.com/cloudfoundry/gosigar"
7+
)
8+
9+
type Metrics struct {
10+
SampleRate int
11+
Sigar sigar.Sigar
12+
Cpu sigar.Cpu
13+
closer func()
14+
}
15+
16+
func (self *Metrics) Start() {
17+
self.Sigar = &sigar.ConcreteSigar{}
18+
cpus, stop := self.Sigar.CollectCpuStats(time.Duration(self.SampleRate) * time.Millisecond)
19+
self.closer = func() {
20+
stop <- struct{}{}
21+
}
22+
for {
23+
if cpu, open := <-cpus; !open {
24+
return
25+
} else {
26+
self.Cpu = cpu
27+
}
28+
}
29+
}

host/mgmt.go

+259
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
package host
2+
3+
import (
4+
"syscall"
5+
6+
"github.com/c2stack/c2g/node"
7+
"github.com/c2stack/c2g/nodes"
8+
"github.com/c2stack/c2g/val"
9+
"github.com/cloudfoundry/gosigar"
10+
)
11+
12+
func Manage() node.Node {
13+
return &nodes.Basic{
14+
OnChild: func(r node.ChildRequest) (node.Node, error) {
15+
switch r.Meta.GetIdent() {
16+
case "cpu":
17+
return CpusNode()
18+
case "fs":
19+
return FilesystemsNode()
20+
case "ram":
21+
return MemoryNode()
22+
case "swap":
23+
return SwapNode()
24+
case "proc":
25+
return ProcsNode()
26+
}
27+
return nil, nil
28+
},
29+
}
30+
}
31+
32+
func ProcsNode() (node.Node, error) {
33+
procs := sigar.ProcList{}
34+
if err := procs.Get(); err != nil {
35+
return nil, err
36+
}
37+
return &nodes.Basic{
38+
OnNext: func(r node.ListRequest) (node.Node, []val.Value, error) {
39+
key := r.Key
40+
var n node.Node
41+
if key != nil {
42+
for _, pid := range procs.List {
43+
if key[0].Value().(int) == pid {
44+
n = ProcNode(pid)
45+
break
46+
}
47+
}
48+
} else {
49+
row := int(r.Row)
50+
if row < len(procs.List) {
51+
pid := procs.List[row]
52+
n = ProcNode(pid)
53+
var err error
54+
key, err = node.NewValues(r.Meta.KeyMeta(), pid)
55+
if err != nil {
56+
return nil, nil, err
57+
}
58+
}
59+
}
60+
if n != nil {
61+
return n, key, nil
62+
}
63+
return nil, nil, nil
64+
},
65+
}, nil
66+
67+
}
68+
69+
func ignoreUnavail(err error) error {
70+
// some percentage of the process return no information on Mac, could be permission
71+
// related.
72+
if err == syscall.ENOMEM {
73+
return nil
74+
}
75+
return err
76+
}
77+
78+
func ProcNode(pid int) node.Node {
79+
return &nodes.Basic{
80+
OnChild: func(r node.ChildRequest) (node.Node, error) {
81+
switch r.Meta.GetIdent() {
82+
case "state":
83+
state := &sigar.ProcState{}
84+
if err := ignoreUnavail(state.Get(pid)); err != nil {
85+
return nil, err
86+
}
87+
return ProcStateNode(*state), nil
88+
case "mem":
89+
mem := sigar.ProcMem{}
90+
if err := ignoreUnavail(mem.Get(pid)); err != nil {
91+
return nil, err
92+
}
93+
return nodes.ReflectChild(&mem), nil
94+
case "time":
95+
time := sigar.ProcTime{}
96+
if err := ignoreUnavail(time.Get(pid)); err != nil {
97+
return nil, err
98+
}
99+
return nodes.ReflectChild(&time), nil
100+
}
101+
return nil, nil
102+
},
103+
OnField: func(r node.FieldRequest, hnd *node.ValueHandle) (err error) {
104+
switch r.Meta.GetIdent() {
105+
case "pid":
106+
hnd.Val = val.Int32(pid)
107+
}
108+
return nil
109+
},
110+
}
111+
}
112+
113+
func ProcStateNode(state sigar.ProcState) node.Node {
114+
return &nodes.Extend{
115+
Base: nodes.ReflectChild(&state),
116+
OnField: func(p node.Node, r node.FieldRequest, hnd *node.ValueHandle) (err error) {
117+
switch r.Meta.GetIdent() {
118+
case "state":
119+
e := r.Meta.GetDataType().EnumerationRef
120+
switch state.State {
121+
case sigar.RunStateSleep:
122+
hnd.Val, _ = e.ById(0)
123+
case sigar.RunStateRun:
124+
hnd.Val, _ = e.ById(1)
125+
case sigar.RunStateStop:
126+
hnd.Val, _ = e.ById(2)
127+
case sigar.RunStateZombie:
128+
hnd.Val, _ = e.ById(3)
129+
case sigar.RunStateIdle:
130+
hnd.Val, _ = e.ById(4)
131+
case sigar.RunStateUnknown:
132+
hnd.Val, _ = e.ById(5)
133+
}
134+
return nil
135+
}
136+
return p.Field(r, hnd)
137+
},
138+
}
139+
}
140+
141+
func SwapNode() (node.Node, error) {
142+
swap := sigar.Swap{}
143+
if err := swap.Get(); err != nil {
144+
return nil, err
145+
}
146+
return nodes.ReflectChild(&swap), nil
147+
}
148+
149+
func MemoryNode() (node.Node, error) {
150+
mem := sigar.Mem{}
151+
if err := mem.Get(); err != nil {
152+
return nil, err
153+
}
154+
return nodes.ReflectChild(&mem), nil
155+
}
156+
157+
func FilesystemsNode() (node.Node, error) {
158+
fs := &sigar.FileSystemList{}
159+
if err := fs.Get(); err != nil {
160+
return nil, err
161+
}
162+
return &nodes.Basic{
163+
OnNext: func(r node.ListRequest) (node.Node, []val.Value, error) {
164+
key := r.Key
165+
var n node.Node
166+
if key != nil {
167+
for _, fs := range fs.List {
168+
if key[0].String() == fs.DirName {
169+
n = FileSystemNode(fs)
170+
break
171+
}
172+
}
173+
} else {
174+
row := int(r.Row)
175+
if row < len(fs.List) {
176+
n = FileSystemNode(fs.List[row])
177+
key, _ = node.NewValues(r.Meta.KeyMeta(), fs.List[row].DirName)
178+
}
179+
}
180+
if n != nil {
181+
return n, key, nil
182+
}
183+
return nil, nil, nil
184+
},
185+
}, nil
186+
}
187+
188+
func FileSystemNode(fss sigar.FileSystem) node.Node {
189+
return &nodes.Extend{
190+
Base: nodes.ReflectChild(&fss),
191+
OnChild: func(p node.Node, r node.ChildRequest) (node.Node, error) {
192+
switch r.Meta.GetIdent() {
193+
case "usage":
194+
return FileSystemUsageNode(fss.DirName)
195+
}
196+
return p.Child(r)
197+
},
198+
OnField: func(p node.Node, r node.FieldRequest, hnd *node.ValueHandle) (err error) {
199+
switch r.Meta.GetIdent() {
200+
case "flags":
201+
hnd.Val = val.Int32(int(fss.Flags))
202+
default:
203+
err = p.Field(r, hnd)
204+
}
205+
return
206+
},
207+
}
208+
}
209+
210+
func FileSystemUsageNode(dirName string) (node.Node, error) {
211+
var usage sigar.FileSystemUsage
212+
if err := usage.Get(dirName); err != nil {
213+
return nil, err
214+
}
215+
return nodes.ReflectChild(&usage), nil
216+
}
217+
218+
func CpusNode() (node.Node, error) {
219+
cpus := &sigar.CpuList{}
220+
if err := cpus.Get(); err != nil {
221+
return nil, err
222+
}
223+
return &nodes.Basic{
224+
OnNext: func(r node.ListRequest) (node.Node, []val.Value, error) {
225+
key := r.Key
226+
var n node.Node
227+
if key != nil {
228+
if key[0].Value().(int) < len(cpus.List) {
229+
n = CpuNode(key[0].Value().(int), cpus.List[key[0].Value().(int)])
230+
}
231+
} else {
232+
id := int(r.Row)
233+
if id < len(cpus.List) {
234+
n = CpuNode(id, cpus.List[id])
235+
key, _ = node.NewValues(r.Meta.KeyMeta(), id)
236+
}
237+
}
238+
if n != nil {
239+
return n, key, nil
240+
}
241+
return nil, nil, nil
242+
},
243+
}, nil
244+
}
245+
246+
func CpuNode(id int, cpu sigar.Cpu) node.Node {
247+
return &nodes.Extend{
248+
Base: nodes.ReflectChild(&cpu),
249+
OnField: func(p node.Node, r node.FieldRequest, hnd *node.ValueHandle) (err error) {
250+
switch r.Meta.GetIdent() {
251+
case "id":
252+
hnd.Val = val.Int32(id)
253+
default:
254+
err = p.Field(r, hnd)
255+
}
256+
return
257+
},
258+
}
259+
}

host/mgmt_test.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package host
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/c2stack/c2g/c2"
8+
9+
"github.com/c2stack/c2g/meta"
10+
"github.com/c2stack/c2g/nodes"
11+
12+
"github.com/c2stack/c2g/meta/yang"
13+
"github.com/c2stack/c2g/node"
14+
)
15+
16+
func TestHostNode(t *testing.T) {
17+
c2.DebugLog(true)
18+
model := yang.RequireModule(&meta.FileStreamSource{Root: "../yang"}, "host")
19+
b := node.NewBrowser(model, Manage())
20+
metrics := &Metrics{SampleRate: 100}
21+
go metrics.Start()
22+
<-time.After(100 * time.Millisecond)
23+
defer metrics.closer()
24+
25+
s, err := nodes.WriteJSON(b.Root())
26+
if err != nil {
27+
t.Fatal(err)
28+
}
29+
t.Log(s)
30+
}
Submodule gosigar added at f4030c1

metrics/node.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
func InfluxNode(influx *InfluxSink) node.Node {
1010
o := influx.Options()
1111
return &nodes.Extend{
12-
Base: nodes.Reflect(&o),
12+
Base: nodes.ReflectChild(&o),
1313
OnChild: func(p node.Node, r node.ChildRequest) (node.Node, error) {
1414
switch r.Meta.GetIdent() {
1515
case "relay":
@@ -66,7 +66,7 @@ func relayListNode(mgr Manager, relayIndex *node.Index) node.Node {
6666

6767
func relayNode(relay *Relay) node.Node {
6868
return &nodes.Extend{
69-
Base: nodes.Reflect(relay),
69+
Base: nodes.ReflectChild(relay),
7070
OnChild: func(p node.Node, r node.ChildRequest) (node.Node, error) {
7171
switch r.Meta.GetIdent() {
7272
case "source":
@@ -216,7 +216,7 @@ func fieldNode(field string, fields map[string]interface{}) node.Node {
216216
func relaySourceNode(relay *Relay) node.Node {
217217
src := relay.Source()
218218
return &nodes.Extend{
219-
Base: nodes.Reflect(&src),
219+
Base: nodes.ReflectChild(&src),
220220
OnEndEdit: func(p node.Node, r node.NodeRequest) error {
221221
if err := p.EndEdit(r); err != nil {
222222
return err

metrics/relay_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package metrics
22

33
import "testing"
44
import "github.com/c2stack/c2g/device"
5-
import "github.com/c2stack/c2g/examples/car"
5+
import "github.com/c2stack/examples/car"
66
import "github.com/c2stack/c2g/meta"
77
import "github.com/c2stack/c2g/c2"
88

99
func Test_RelayNotify(t *testing.T) {
10-
d := device.New(&meta.FileStreamSource{Root: "../../c2g/examples/car"})
10+
d := device.New(&meta.FileStreamSource{Root: "../../examples/car"})
1111
c := car.New()
1212
c.Speed = 1
1313
d.Add("car", car.Manage(c))

0 commit comments

Comments
 (0)