-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathindex.js
executable file
·240 lines (209 loc) · 7.09 KB
/
index.js
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
#!/usr/bin/env node
// dependencies
var cli = require('cli'),
request = require('request'),
utils = require('./utils'),
widgets = require('./widgets'),
blessed = require('blessed'),
contrib = require('blessed-contrib'),
screen = blessed.screen(),
_ = require('lodash');
// enable status
cli.enable('status');
// initialize variables
var containers = '',
host = process.env.DOCKER_HOST || 'unix:///var/run/docker.sock',
isUnixSocket = (host.indexOf('unix') > -1);
// add the trailing `:` if it's a unix socket
if (isUnixSocket) {
host += ":";
}
// backwards compatibility for unix format
if (isUnixSocket && host.substring(0, 8) == "unix:///") {
host = host.replace("unix://", "http://unix:")
}
// parse command line arguments
var parse = function (func){
if (cli.args.length) {
return func(cli.args);
}
utils.GetAllContainers(host, function (err, containers){
if (err) {
return cli.error(err);
}
return func(containers);
});
};
var fetchContainerDetails = function (containerID, detailBox) {
request({
json: true,
method: 'GET',
uri: host + '/containers/' + containerID + '/json'
}, function(err, resp, body) {
detailBox.setLabel("Container details: " + containerID.substr(0, 8) + " (use j/k to scroll)")
if (err) {
return detailBox.setText("Error fetching container info: " + err)
}
if (resp.statusCode != 200) {
return detailBox.setText("Error fetch container info (" + resp.statusCode + "), error: " + body)
}
detailBox.setText(JSON.stringify(body, undefined, 2))
screen.render()
})
}
// Get the containers
parse(function (containers) {
if (containers.length <= 0){
return cli.error("No containers.")
}
var borderColor = "cyan"
var labelStyle = {
fg: "white",
bold: true
}
// Create upper nested grid
var upperGrid = new contrib.grid({rows: 1, cols: 2})
upperGrid.set(0, 0, contrib.table, {
columnSpacing: [14, 32, 10],
label: "Running containers (use arrows/enter to select)",
parent: screen, // workaround a blessed bug
style: {
label: labelStyle
}
})
upperGrid.set(0, 1, blessed.box, {
fg: "default",
label: "Container details",
scrollable: true,
style: {
label: labelStyle
}
})
var bottomGrid = new contrib.grid({rows: 1, cols: 2})
bottomGrid.set(0, 0, contrib.line, {
label: "CPU %",
maxY: 100,
showNthLabel: 10,
style: {
baseline: "white",
label: labelStyle,
line: "yellow",
text: "white"
}
})
var gaugesGrid = new contrib.grid({rows: 1, cols: 2})
gaugesGrid.set(0, 0, contrib.gauge, {
label: "CPU %",
style: {
label: labelStyle
}
})
gaugesGrid.set(0, 1, contrib.gauge, {
label: "MEM %",
style: {
label: labelStyle
}
})
var bottomRightGrid = new contrib.grid({rows: 2, cols: 1})
bottomRightGrid.set(0, 0, gaugesGrid)
bottomRightGrid.set(1, 0, blessed.box, {
label: "Network",
padding: {
left: 1
},
style: {
label: labelStyle
}
})
bottomGrid.set(0, 1, bottomRightGrid)
// Create global grid layout
var globalGrid = new contrib.grid({rows: 2, cols: 1})
globalGrid.set(0, 0, upperGrid)
globalGrid.set(1, 0, bottomGrid)
globalGrid.applyLayout(screen);
// Name widgets
var cpuLine = bottomGrid.get(0, 0)
var cpuGauge = gaugesGrid.get(0, 0)
var memGauge = gaugesGrid.get(0, 1)
var networkBox = bottomRightGrid.get(1, 0)
cpuLine.border.style.fg = borderColor
cpuGauge.border.style.fg = borderColor
memGauge.border.style.fg = borderColor
networkBox.border.style.fg = borderColor
cpuLine.canvasSize.width -= 12 // workaround to avoid overflowing the X labels
// Create container detail view
var containerDetailBox = upperGrid.get(0, 1)
containerDetailBox.border.style.fg = borderColor
// Create container list
var containersTable = upperGrid.get(0, 0)
// debounce call to containers endpoint because many events can happen at
// "once"
var updateContainers = _.debounce(function(){
utils.GetAllContainers(host, function (err, containers){
if(err) throw err;
containersTable.setData({
headers: ["ID", "Names", "Image"],
data: containers.map(function (el) {
return [el.Id.substr(0, 8), el.Names.join(", "), el.Image]
})
})
// If we don't render, you have to take action in the terminal for the
// screen to re-render the current containers.
screen.render()
})
}, 200)
// listen to events api to update "Running Containers" list
request({
json: true,
method: 'GET',
uri: host + '/events'
})
.on('data', function(data){
// we don't care about data, just that something happened
updateContainers();
})
containersTable.setData({
headers: ["ID", "Names", "Image"],
data: containers.map(function (el) {
return [el.Id.substr(0, 8), el.Names.join(", "), el.Image]
})
})
var elements = [
new widgets.CPUPercentageLine(cpuLine),
new widgets.CPUGauge(cpuGauge),
new widgets.MEMGauge(memGauge),
new widgets.NetworkIO(networkBox)
]
containersTable.rows.on("select", function (item) {
// Get container data, update detail view
var containerData = containers[containersTable.rows.getItemIndex(item)]
fetchContainerDetails(containerData.Id, containerDetailBox)
// Clear graphs and start collecting container stats
elements.map(function(e){
if(typeof e.clear == 'function' || false){
e.clear()
}
})
utils.GetStats(host, containerData.Id, function (statItem) {
elements.map(function (el) { el.update(statItem) })
screen.render()
})
})
containersTable.border.style.fg = borderColor // override blessed-contrib border color (cyan)
containersTable.rows.style.item.fg = "default" // override blessed-contrib item color (green)
containersTable.style.fg = "cyan" // override blessed-contrib headers color (fg)
containersTable.style.bold = true // override blessed-contrib headers style
containersTable.focus()
// Key bindings
screen.key('j', function (ch, key) {
containerDetailBox.setScrollPerc(containerDetailBox.getScrollPerc() + 10)
});
screen.key('k', function (ch, key) {
containerDetailBox.setScrollPerc(containerDetailBox.getScrollPerc() - 10)
});
screen.key(['escape', 'q', 'C-c'], function (ch, key) {
return process.exit(0)
});
// Render screen
screen.render();
});