This repository has been archived by the owner on Nov 22, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
279 lines (227 loc) · 8.61 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
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
'use strict';
let request = require('request-promise');
let async = require('async');
let http = require('http');
let sequence = require('sequence');
let prometheus = require('prom-client');
let Gauge = prometheus.Gauge;
let express = require('express');
let app = express();
/*
* ACP vars
*/
var acp_nodes;
var acp_root_url = process.env.ACP_TARGET_ROOT_URL;
var acp_auth_url = 'https://' + acp_root_url + '/authentication/api/v1/sessions/soc/';
var session_token;
var server;
var server_listen_port = process.env.EXPORTER_LISTEN_PORT;
var node_roles_state_keys = ['Online', 'Offline', 'Removed', 'Down', 'Reserved', 'Maintenance', 'ReservedDown'];
/*
* METRIC DEFINITIONS
*/
var node_state_gauge;
var node_cpu_allocation_gauge;
var node_memory_allocation_gauge;
var node_memory_total_gauge;
var application_workload_count_total_guage;
var application_workload_memory_allocation_total_gauge;
function createMetrics(callback) {
prometheus.register.clear();
// gauge metric for node state (indexOf node_roles_state_keys)
node_state_gauge = new prometheus.Gauge({
name: 'apprenda_node_current_state',
help: 'The current state of the node as an index of ' + node_roles_state_keys.toString(),
labelNames: ['node', 'role'] });
// gauge metric for node cpu allocation
node_cpu_allocation_gauge = new prometheus.Gauge({
name: 'apprenda_node_current_cpu_allocation',
help: 'The current allocation of CPU capacity consumed by guest application workloads (in Mhz)',
labelNames: ['node'] });
// gauge metric for node memory allocation
node_memory_allocation_gauge = new prometheus.Gauge({
name: 'apprenda_node_current_memory_allocation',
help: 'The current allocation of memory capacity consumed by guest application workloads (in MB)',
labelNames: ['node'] });
// gauge metric for node cpu allocation
node_memory_total_gauge = new prometheus.Gauge({
name: 'apprenda_node_total_usable_memory',
help: 'The total amount of memory that can be allocated to guest application workloads (in MB)',
labelNames: ['node'] });
// guage metric for developer workload count
application_workload_count_total_guage = new prometheus.Gauge({
name: 'apprenda_developer_workload_count_total',
help: 'The total number of workloads currently running for a developer/application combination.',
labelNames: ['developerTeamAlias', 'applicationAlias']
});
// gauge metric for developer allocation
application_workload_memory_allocation_total_gauge = new prometheus.Gauge({
name: 'apprenda_developer_workload_memory_allocation_total',
help: 'The amount of memory allocated via resource policy for a developer/application combination (in MB)',
labelNames: ['developerTeamAlias', 'applicationAlias']
});
callback();
}
// handle requests to /metrics from prometheus
app.get('/metrics', (req, res) => {
createMetrics(function() {
getSession(function(){
getNodeData(function(){
getWorkloadData(function(){
res.end(prometheus.register.metrics());
endSession()
});
});
});
});
});
// deletes session via API
function endSession()
{
console.log("Killing session");
var options = {
url: acp_auth_url + session_token,
method: 'DELETE',
rejectUnauthorized: false // in case target uses self-signed SSL cert (dev)
}
request(options, function(err, res, body){
if(err) {
console.log(err);
} else {
console.log("Session closed");
}
});
}
// create session via API
function getSession(callback)
{
console.log("Target: " + acp_root_url);
console.log("Authenticating");
var options = {
url: acp_auth_url,
body: {
username: process.env.ACP_USER,
password: process.env.ACP_SECRET
},
method: 'POST',
json: true,
rejectUnauthorized: false // in case target uses self-signed SSL cert (dev)
}
request(options)
.then(function(parsedBody){
session_token = parsedBody.apprendaSessionToken;
console.log("Session token stored");
callback();
})
.catch(function(err){
console.log(err);
callback();
});
}
/*
* Call nodes endpoint on ACP API and get node data, insert into metrics
*/
function getNodeData(callback)
{
console.log("Getting node metadata");
var options = {
url: 'https://' + acp_root_url + '/soc/api/v1/nodes',
rejectUnauthorized: false,
headers:
{
"ApprendaSessionToken": session_token
}
}
request.get(options)
.then(function(parsedBody){
var items = JSON.parse(parsedBody).items;
for(var n=0;n<items.length;n++) {
var node = items[n];
// node role metrics
for(var i=0;i<node.nodeRoles.length;i++){
var role = node.nodeRoles[i];
// windows and linux nodes
if((role.nodeRole == "Windows") || (role.nodeRole == "Linux"))
{
// role state
node_state_gauge.set({node: node.name, role: role.nodeRole},
node_roles_state_keys.indexOf(role.roleState.state)
);
// memory allocation
node_memory_allocation_gauge.set({node: node.name},
role.allocatedMemory
);
// memory total
node_memory_total_gauge.set({node: node.name},
role.totalMemory
);
// cpu allocation
node_cpu_allocation_gauge.set({node: node.name},
role.allocatedCpu
);
}
// kubernetes clusters
if(role.nodeRole == "KubernetesLinux")
{
// memory allocation
node_memory_allocation_gauge.set({node: node.name},
role.allocatedMemory
);
// memory total
node_memory_total_gauge.set({node: node.name},
role.totalMemory
);
}
}
}
callback();
})
.catch(function(err){
callback();
});
}
function getWorkloadData(callback)
{
console.log("Getting workload metadata");
/* here we want endTimes that don't yet exist so we get CURRENTLY running workloads */
var options = {
url: 'https://' + acp_root_url + '/soc/api/v1/resourceallocation?startTime=2017-01-01',
rejectUnauthorized: false,
headers:
{
"ApprendaSessionToken": session_token
}
}
/* Because the Apprenda API for resource allocation doesn't yet support querying for only
currently running workloads, we pull back all results and filter them here. A future version
will optimize for this query. */
request.get(options)
.then(function(parsedBody){
var allocations = JSON.parse(parsedBody).resourceAllocations;
for(var n=0;n<allocations.length;n++) {
var workload = allocations[n];
if(workload.undeployTime == null)
{
/* increment gauges */
application_workload_count_total_guage.inc({
developerTeamAlias: workload.developerAlias,
applicationAlias: workload.applicationAlias
});
if(workload.policy != null) {
if(workload.policy.memoryLimitInMegabytes != null) {
application_workload_memory_allocation_total_gauge.inc({
developerTeamAlias: workload.developerAlias,
applicationAlias: workload.applicationAlias},
workload.policy.memoryLimitInMegabytes
);
}
}
}
}
callback();
})
}
// listen for requests
app.listen(server_listen_port || 3000, () => {
console.log("Listening");
});