Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 39534
1
###
2
Some code specific to running a project in the KuCalc environment.
3
###
4
5
fs = require('fs')
6
async = require('async')
7
8
misc = require('smc-util/misc')
9
misc_node = require('smc-util-node/misc_node')
10
11
# This gets **changed** to true in local_hub.coffee, if a certain
12
# command line flag is passed in.
13
exports.IN_KUCALC = false
14
15
exports.init = (client) ->
16
# update project status every 30s
17
# TODO: could switch to faster when it's changing and slower when it isn't.
18
f = -> update_project_status(client)
19
f()
20
setInterval(f, 30000)
21
22
update_project_status = (client, cb) ->
23
dbg = client.dbg("update_status")
24
dbg()
25
status = undefined
26
async.series([
27
(cb) ->
28
compute_status (err, s) ->
29
status = s
30
cb(err)
31
(cb) ->
32
client.query
33
query :
34
projects : {project_id:client.client_id(), status: status}
35
cb : cb
36
], (err) ->
37
cb?(err)
38
)
39
40
exports.compute_status = compute_status = (cb) ->
41
status = {memory:{rss:0}, disk_MB:0}
42
async.parallel([
43
(cb) ->
44
compute_status_disk(status, cb)
45
(cb) ->
46
#compute_status_memory(status, cb)
47
cgroup_memstats(status, cb)
48
(cb) ->
49
compute_status_tmp(status, cb)
50
], (err) ->
51
cb(err, status)
52
)
53
54
compute_status_disk = (status, cb) ->
55
disk_usage "$HOME", (err, x) ->
56
status.disk_MB = x
57
cb(err)
58
59
# NOTE: we use tmpfs for /tmp, so RAM usage is the **sum** of /tmp and what
60
# processes use.
61
compute_status_tmp = (status, cb) ->
62
disk_usage "/tmp", (err, x) ->
63
status.memory.rss += 1000*x
64
cb(err)
65
66
compute_status_memory = (status, cb) ->
67
misc_node.execute_code
68
command : "smem -nu | tail -1 | awk '{print $6}'"
69
bash : true
70
cb : (err, out) ->
71
if err
72
cb(err)
73
else
74
status.memory.rss += parseInt(out.stdout)
75
cb()
76
77
# this grabs the memory stats directly from the sysfs cgroup files
78
# the actual usage is the sum of the rss values plus cache, but we leave cache aside
79
cgroup_memstats = (status, cb) ->
80
fs.readFile '/sys/fs/cgroup/memory/memory.stat', 'utf8', (err, data) ->
81
if err
82
cb(err)
83
return
84
stats = {}
85
for line in data.split('\n')
86
[key, value] = line.split(' ')
87
try
88
stats[key] = parseInt(value)
89
90
kib = 1024 # convert to kibibyte
91
status.memory.rss += (stats.total_rss ? 0 + stats.total_rss_huge ? 0) / kib
92
status.memory.cache = (stats.cache ? 0) / kib
93
status.memory.limit = (stats.hierarchical_memory_limit ? 0) / kib
94
cb()
95
96
97
disk_usage = (path, cb) ->
98
misc_node.execute_code
99
command : "df -BM #{path} | tail -1 | awk '{gsub(\"M\",\"\");print $3}'"
100
bash : true
101
cb : (err, out) ->
102
if err
103
cb(err)
104
else
105
cb(undefined, parseInt(out.stdout))
106
107
108
# Every 60s, check if we can reach google's internal network -- in kucalc on GCE, this must be blocked.
109
# If we recieve some information, exit with status code 99.
110
exports.init_gce_firewall_test = (logger, interval_ms=60*1000) ->
111
return # temporarily disabled
112
if not exports.IN_KUCALC
113
logger?.warn("not running firewall test -- not in kucalc")
114
return
115
URI = 'http://metadata.google.internal/computeMetadata/v1/'
116
test_firewall = ->
117
logger?.log("test_firewall")
118
request = require('request')
119
request(
120
timeout : 3000
121
headers :
122
'Metadata-Flavor' : 'Google'
123
uri: URI
124
method: 'GET'
125
, (err, res, body) ->
126
if err?.code == 'ETIMEDOUT'
127
logger?.log('test_firewall: timeout -> no action')
128
else
129
logger?.warn('test_firewall', res)
130
logger?.warn('test_firewall', body)
131
if res? or body?
132
logger?.warn('test_firewall: request went through and got a response -> exiting with code 99')
133
process.exit(99)
134
else
135
logger?.warn('test_firewall: request went through with no response -> no action')
136
)
137
test_firewall()
138
setInterval(test_firewall, interval_ms)
139
return
140
141
# called inside raw_server
142
exports.init_health_metrics = (raw_server, project_id) ->
143
return if not exports.IN_KUCALC
144
# uniquely identifies this instance of the local hub
145
session_id = misc.uuid()
146
# record when this instance started
147
start_ts = (new Date()).getTime()
148
149
# Setup health and metrics (no url base prefix needed)
150
raw_server.use '/health', (req, res) ->
151
res.setHeader("Content-Type", "text/plain")
152
res.setHeader('Cache-Control', 'private, no-cache, must-revalidate')
153
res.send('OK')
154
155
# prometheus text format -- https://prometheus.io/docs/instrumenting/exposition_formats/#text-format-details
156
raw_server.use '/metrics', (req, res) ->
157
res.setHeader("Content-Type", "text/plain; version=0.0.4")
158
res.setHeader('Cache-Control', 'private, no-cache, must-revalidate')
159
{get_bugs_total} = require('./local_hub')
160
labels = "project_id=\"#{project_id}\",session_id=\"#{session_id}\""
161
res.send("""
162
# HELP kucalc_project_bugs_total The total number of caught bugs.
163
# TYPE kucalc_project_bugs_total counter
164
kucalc_project_bugs_total{#{labels}} #{get_bugs_total()}
165
# HELP kucalc_project_start_time when the project/session started
166
# TYPE kucalc_project_start_time counter
167
kucalc_project_start_time{#{labels}} #{start_ts}
168
""")
169
170