softwareaccounting 1.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sams/__init__.py +19 -0
- sams/aggregator/SoftwareAccounting.py +421 -0
- sams/aggregator/SoftwareAccountingPW.py +37 -0
- sams/aggregator/__init__.py +0 -0
- sams/backend/SoftwareAccounting.py +266 -0
- sams/backend/SoftwareAccountingPW.py +465 -0
- sams/backend/__init__.py +1 -0
- sams/base.py +320 -0
- sams/core.py +267 -0
- sams/listener/Prometheus.py +133 -0
- sams/listener/__init__.py +0 -0
- sams/loader/File.py +111 -0
- sams/loader/FileSlurmInfoFallback.py +118 -0
- sams/loader/__init__.py +0 -0
- sams/output/Carbon.py +137 -0
- sams/output/Collectd.py +132 -0
- sams/output/File.py +91 -0
- sams/output/Http.py +105 -0
- sams/output/Prometheus.py +165 -0
- sams/output/__init__.py +0 -0
- sams/pidfinder/Slurm.py +90 -0
- sams/pidfinder/__init__.py +0 -0
- sams/sampler/Core.py +61 -0
- sams/sampler/FSStats.py +103 -0
- sams/sampler/IOStats.py +159 -0
- sams/sampler/NvidiaSMI.py +225 -0
- sams/sampler/Pressure.py +129 -0
- sams/sampler/SlurmCGroup.py +161 -0
- sams/sampler/SlurmCGroup2.py +62 -0
- sams/sampler/SlurmInfo.py +134 -0
- sams/sampler/Software.py +289 -0
- sams/sampler/ZFSStats.py +136 -0
- sams/sampler/__init__.py +0 -0
- sams/software/Regexp.py +137 -0
- sams/software/__init__.py +0 -0
- sams/xmlwriter/File.py +149 -0
- sams/xmlwriter/__init__.py +1 -0
- softwareaccounting-1.9.data/scripts/sams-aggregator.py +148 -0
- softwareaccounting-1.9.data/scripts/sams-collector.py +279 -0
- softwareaccounting-1.9.data/scripts/sams-post-receiver.py +146 -0
- softwareaccounting-1.9.data/scripts/sams-software-extractor.py +132 -0
- softwareaccounting-1.9.data/scripts/sams-software-updater.py +206 -0
- softwareaccounting-1.9.data/scripts/sgas-sa-registrant +632 -0
- softwareaccounting-1.9.dist-info/METADATA +21 -0
- softwareaccounting-1.9.dist-info/RECORD +48 -0
- softwareaccounting-1.9.dist-info/WHEEL +5 -0
- softwareaccounting-1.9.dist-info/licenses/LICENSE +339 -0
- softwareaccounting-1.9.dist-info/top_level.txt +1 -0
sams/__init__.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SAMS Software accounting
|
|
3
|
+
Copyright (C) 2018-2021 Swedish National Infrastructure for Computing (SNIC)
|
|
4
|
+
|
|
5
|
+
This program is free software; you can redistribute it and/or
|
|
6
|
+
modify it under the terms of the GNU General Public License
|
|
7
|
+
as published by the Free Software Foundation; either version 2
|
|
8
|
+
of the License, or (at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU General Public License
|
|
16
|
+
along with this program; If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
__version__ = "1.9"
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Software accounting storage "backend" for updating the list of softwares
|
|
3
|
+
|
|
4
|
+
SAMS Software accounting
|
|
5
|
+
Copyright (C) 2018-2021 Swedish National Infrastructure for Computing (SNIC)
|
|
6
|
+
|
|
7
|
+
This program is free software; you can redistribute it and/or
|
|
8
|
+
modify it under the terms of the GNU General Public License
|
|
9
|
+
as published by the Free Software Foundation; either version 2
|
|
10
|
+
of the License, or (at your option) any later version.
|
|
11
|
+
|
|
12
|
+
This program is distributed in the hope that it will be useful,
|
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
GNU General Public License for more details.
|
|
16
|
+
|
|
17
|
+
You should have received a copy of the GNU General Public License
|
|
18
|
+
along with this program; If not, see <http://www.gnu.org/licenses/>.
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
Config options:
|
|
22
|
+
|
|
23
|
+
sams.backend.SoftwareAccounting:
|
|
24
|
+
# Number of jobs in
|
|
25
|
+
jobid_hash_size: 0 # All in one.
|
|
26
|
+
|
|
27
|
+
# sqlite file name(s)
|
|
28
|
+
file_pattern: 'sa-%(jobid_hash)d.db'
|
|
29
|
+
|
|
30
|
+
# Path to sqlite db files
|
|
31
|
+
db_path: /data/softwareaccounting/CLUSTER/db
|
|
32
|
+
|
|
33
|
+
# cluster (used for calculating SGAS recordid)
|
|
34
|
+
cluster: CLUSTER
|
|
35
|
+
|
|
36
|
+
# sqlite temp_store pragma (DEFAULT, FILE or MEMORY)
|
|
37
|
+
# DEFAULT is normally FILE but is dependent on compile time
|
|
38
|
+
# options of the sqlite library.
|
|
39
|
+
sqlite_temp_store: DEFAULT
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
import logging
|
|
43
|
+
import os
|
|
44
|
+
import sqlite3
|
|
45
|
+
|
|
46
|
+
import sams.base
|
|
47
|
+
|
|
48
|
+
logger = logging.getLogger(__name__)
|
|
49
|
+
|
|
50
|
+
""" Create tables unless exists """
|
|
51
|
+
TABLES = [
|
|
52
|
+
"""
|
|
53
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
54
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
55
|
+
project TEXT NOT NULL
|
|
56
|
+
);
|
|
57
|
+
""",
|
|
58
|
+
"""
|
|
59
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
60
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
61
|
+
user TEXT NOT NULL
|
|
62
|
+
);
|
|
63
|
+
""",
|
|
64
|
+
"""
|
|
65
|
+
CREATE TABLE IF NOT EXISTS jobs (
|
|
66
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
67
|
+
jobid TEXT NOT NULL,
|
|
68
|
+
recordid TEXT,
|
|
69
|
+
user INTEGER,
|
|
70
|
+
project INTEGER,
|
|
71
|
+
ncpus INTEGER,
|
|
72
|
+
start_time INTEGER,
|
|
73
|
+
end_time INTEGER,
|
|
74
|
+
user_time REAL,
|
|
75
|
+
system_time REAL
|
|
76
|
+
);
|
|
77
|
+
""",
|
|
78
|
+
"""
|
|
79
|
+
CREATE TABLE IF NOT EXISTS software (
|
|
80
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
81
|
+
path TEXT NOT NULL,
|
|
82
|
+
software TEXT,
|
|
83
|
+
version TEXT,
|
|
84
|
+
versionstr TEXT,
|
|
85
|
+
user_provided BOOLEAN,
|
|
86
|
+
ignore BOOLEAN,
|
|
87
|
+
last_updated INTEGER
|
|
88
|
+
);
|
|
89
|
+
""",
|
|
90
|
+
"""
|
|
91
|
+
CREATE INDEX IF NOT EXISTS software_path_idx on software(path);
|
|
92
|
+
""",
|
|
93
|
+
"""
|
|
94
|
+
CREATE TABLE IF NOT EXISTS node (
|
|
95
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
96
|
+
node TEXT NOT NULL
|
|
97
|
+
);
|
|
98
|
+
""",
|
|
99
|
+
"""
|
|
100
|
+
CREATE INDEX IF NOT EXISTS node_node_idx on node(node);
|
|
101
|
+
""",
|
|
102
|
+
"""
|
|
103
|
+
CREATE TABLE IF NOT EXISTS command (
|
|
104
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
105
|
+
jobid INTEGER NOT NULL,
|
|
106
|
+
node INTEGER,
|
|
107
|
+
software INTEGER,
|
|
108
|
+
start_time INTEGER,
|
|
109
|
+
end_time INTEGER,
|
|
110
|
+
user REAL,
|
|
111
|
+
sys REAL,
|
|
112
|
+
updated INTEGER,
|
|
113
|
+
FOREIGN KEY(node) REFERENCES node(node),
|
|
114
|
+
FOREIGN KEY(software) REFERENCES software(software)
|
|
115
|
+
);
|
|
116
|
+
""",
|
|
117
|
+
"""
|
|
118
|
+
CREATE TABLE IF NOT EXISTS last_sent (
|
|
119
|
+
timestamp INTEGER
|
|
120
|
+
);
|
|
121
|
+
""",
|
|
122
|
+
"""
|
|
123
|
+
INSERT INTO last_sent(timestamp) SELECT 0 WHERE NOT EXISTS(SELECT 1 FROM last_sent);
|
|
124
|
+
""",
|
|
125
|
+
"""
|
|
126
|
+
CREATE INDEX IF NOT EXISTS command_jobid_node_software_idx on command(jobid,node,software);
|
|
127
|
+
""",
|
|
128
|
+
"""
|
|
129
|
+
CREATE INDEX IF NOT EXISTS command_updated_idx on command(updated);
|
|
130
|
+
""",
|
|
131
|
+
"""
|
|
132
|
+
CREATE INDEX IF NOT EXISTS software_last_updated_idx on software(last_updated);
|
|
133
|
+
""",
|
|
134
|
+
"""
|
|
135
|
+
CREATE INDEX IF NOT EXISTS jobs_jobid_idx on jobs(jobid);
|
|
136
|
+
""",
|
|
137
|
+
"""
|
|
138
|
+
CREATE INDEX IF NOT EXISTS jobs_start_time_idx on jobs(start_time);
|
|
139
|
+
""",
|
|
140
|
+
"""
|
|
141
|
+
CREATE INDEX IF NOT EXISTS jobs_end_time_idx on jobs(end_time);
|
|
142
|
+
""",
|
|
143
|
+
"""
|
|
144
|
+
CREATE INDEX IF NOT EXISTS jobs_user_time_idx on jobs(user_time);
|
|
145
|
+
""",
|
|
146
|
+
"""
|
|
147
|
+
CREATE INDEX IF NOT EXISTS jobs_system_time_idx on jobs(system_time);
|
|
148
|
+
""",
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
# Update/Insert SQL
|
|
152
|
+
INSERT_USER = """ insert or replace into users (id,user) values ((select ID from users where user = :user), :user); """
|
|
153
|
+
INSERT_PROJECT = """ insert or replace into projects (id,project) values ((select ID from projects where project = :project), :project); """
|
|
154
|
+
INSERT_JOBS = """
|
|
155
|
+
insert or replace into jobs (id,jobid,user,project,ncpus,recordid)
|
|
156
|
+
values ((select ID from jobs where jobid = :jobid), :jobid, :user ,:project, :ncpus, :recordid);
|
|
157
|
+
"""
|
|
158
|
+
INSERT_NODE = """ insert or replace into node (id,node) values ((select ID from node where node = :node), :node); """
|
|
159
|
+
FETCH_SOFTWARE_ID = """ select ID from software where path = :software; """
|
|
160
|
+
INSERT_SOFTWARE = """ insert or ignore into software (id,path) values ((select ID from software where path = :software), :software); """
|
|
161
|
+
INSERT_COMMAND = """
|
|
162
|
+
insert or ignore into command (id,jobid,node,software,start_time,end_time,user,sys,updated) values
|
|
163
|
+
(
|
|
164
|
+
(
|
|
165
|
+
select ID from command
|
|
166
|
+
where
|
|
167
|
+
jobid = :id
|
|
168
|
+
and
|
|
169
|
+
node = :node_id
|
|
170
|
+
and
|
|
171
|
+
software = :sw_id
|
|
172
|
+
)
|
|
173
|
+
,
|
|
174
|
+
:id,
|
|
175
|
+
:node_id,
|
|
176
|
+
:sw_id,
|
|
177
|
+
:start_time,:end_time,
|
|
178
|
+
:user,:sys,
|
|
179
|
+
strftime('%s','now')
|
|
180
|
+
);
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
UPDATE_MINMAX = """
|
|
184
|
+
update jobs set
|
|
185
|
+
start_time = :start_time,
|
|
186
|
+
end_time = :end_time,
|
|
187
|
+
user_time = :user_time,
|
|
188
|
+
system_time = :system_time
|
|
189
|
+
where id = :id
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
FIND_MINMAX_JOBS = """
|
|
193
|
+
select jobid,min(start_time),max(end_time),sum(user),sum(sys)
|
|
194
|
+
from command
|
|
195
|
+
where jobid in (select id from jobs where start_time is null or end_time is null or user_time is null or system_time is null)
|
|
196
|
+
group by jobid
|
|
197
|
+
"""
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class Aggregator(sams.base.Aggregator):
|
|
201
|
+
"""SAMS Software accounting aggregator"""
|
|
202
|
+
|
|
203
|
+
def __init__(self, id, config):
|
|
204
|
+
super(Aggregator, self).__init__(id, config)
|
|
205
|
+
self.db = {}
|
|
206
|
+
self.db_path = self.config.get([self.id, "db_path"])
|
|
207
|
+
self.cluster = self.config.get([self.id, "cluster"])
|
|
208
|
+
self.file_pattern = self.config.get([self.id, "file_pattern"], "sa-%(jobid_hash)d.db")
|
|
209
|
+
self.jobid_hash_size = self.config.get([self.id, "jobid_hash_size"], 0)
|
|
210
|
+
self.inserted = {}
|
|
211
|
+
|
|
212
|
+
self.sqlite_temp_store = self.config.get([self.id, "sqlite_temp_store"], "DEFAULT")
|
|
213
|
+
|
|
214
|
+
if self.sqlite_temp_store not in ["DEFAULT", "FILE", "MEMORY"]:
|
|
215
|
+
sams.base.AggregatorException("sqlite_temp_store must be one of DEFAULT, FILE or MEMORY")
|
|
216
|
+
|
|
217
|
+
def _open_db(self, jobid_hash):
|
|
218
|
+
"""Open database object"""
|
|
219
|
+
db = os.path.join(self.db_path, self.file_pattern % {"jobid_hash": int(jobid_hash)})
|
|
220
|
+
self.db[jobid_hash] = sqlite3.connect(db)
|
|
221
|
+
self.db[jobid_hash].isolation_level = None
|
|
222
|
+
c = self.db[jobid_hash].cursor()
|
|
223
|
+
c.execute("PRAGMA temp_store = %s" % self.sqlite_temp_store)
|
|
224
|
+
for sql in TABLES:
|
|
225
|
+
logger.debug(sql)
|
|
226
|
+
c.execute(sql)
|
|
227
|
+
self.db[jobid_hash].commit()
|
|
228
|
+
return self.db[jobid_hash]
|
|
229
|
+
|
|
230
|
+
def get_db(self, jobid):
|
|
231
|
+
"""get db connection based on jobid / jobid_hash_size"""
|
|
232
|
+
jobid_hash = 0
|
|
233
|
+
if self.jobid_hash_size > 0:
|
|
234
|
+
jobid_hash = int(jobid / self.jobid_hash_size)
|
|
235
|
+
if jobid_hash in self.db:
|
|
236
|
+
return self.db[jobid_hash]
|
|
237
|
+
return self._open_db(jobid_hash)
|
|
238
|
+
|
|
239
|
+
def save_id(self, jobid, table, value, id):
|
|
240
|
+
"""Only try to insert once / session"""
|
|
241
|
+
jobid_hash = 0
|
|
242
|
+
if self.jobid_hash_size > 0:
|
|
243
|
+
jobid_hash = int(jobid / self.jobid_hash_size)
|
|
244
|
+
if value not in self.inserted[jobid_hash][table]:
|
|
245
|
+
self.inserted[jobid_hash][table][value] = id
|
|
246
|
+
logger.debug("save_id(%d (%d),%s,%s,%d)", jobid, jobid_hash, table, value, id)
|
|
247
|
+
return id
|
|
248
|
+
|
|
249
|
+
def get_id(self, jobid, table, value):
|
|
250
|
+
"""Only try to insert once / session"""
|
|
251
|
+
jobid_hash = 0
|
|
252
|
+
if self.jobid_hash_size > 0:
|
|
253
|
+
jobid_hash = int(jobid / self.jobid_hash_size)
|
|
254
|
+
logger.debug(
|
|
255
|
+
"get_id(%d (%d),%s,%s,%d)",
|
|
256
|
+
jobid,
|
|
257
|
+
jobid_hash,
|
|
258
|
+
table,
|
|
259
|
+
value,
|
|
260
|
+
self.inserted[jobid_hash][table][value],
|
|
261
|
+
)
|
|
262
|
+
return self.inserted[jobid_hash][table][value]
|
|
263
|
+
|
|
264
|
+
def do_insert(self, jobid, table, value):
|
|
265
|
+
"""Only try to insert once / session"""
|
|
266
|
+
jobid_hash = 0
|
|
267
|
+
if self.jobid_hash_size > 0:
|
|
268
|
+
jobid_hash = int(jobid / self.jobid_hash_size)
|
|
269
|
+
if jobid_hash not in self.inserted:
|
|
270
|
+
self.inserted[jobid_hash] = {}
|
|
271
|
+
if table not in self.inserted[jobid_hash]:
|
|
272
|
+
self.inserted[jobid_hash][table] = {}
|
|
273
|
+
if value not in self.inserted[jobid_hash][table]:
|
|
274
|
+
return True
|
|
275
|
+
return False
|
|
276
|
+
|
|
277
|
+
def aggregate(self, data):
|
|
278
|
+
"""Information aggregate method"""
|
|
279
|
+
|
|
280
|
+
jobid = int(data["sams.sampler.Core"]["jobid"])
|
|
281
|
+
node = data["sams.sampler.Core"]["node"]
|
|
282
|
+
|
|
283
|
+
# Get database for jobid
|
|
284
|
+
db = self.get_db(jobid)
|
|
285
|
+
c = db.cursor()
|
|
286
|
+
|
|
287
|
+
for module in ["sams.sampler.Software", "sams.sampler.SlurmInfo"]:
|
|
288
|
+
if module not in data:
|
|
289
|
+
logger.info("Jobid: %d on node %s has no %s", jobid, node, module)
|
|
290
|
+
raise sams.base.AggregatorException("Jobid: %d on node %s has no %s" % (jobid, node, module))
|
|
291
|
+
|
|
292
|
+
if len(data["sams.sampler.Software"]["execs"]) == 0:
|
|
293
|
+
raise sams.base.AggregatorException("Jobid: %d on node %s has no execs" % (jobid, node))
|
|
294
|
+
|
|
295
|
+
# Begin transaction
|
|
296
|
+
c.execute("BEGIN TRANSACTION")
|
|
297
|
+
c.execute("PRAGMA temp_store = %s" % self.sqlite_temp_store)
|
|
298
|
+
|
|
299
|
+
# If project (account) is defined in data insert into table
|
|
300
|
+
project = None
|
|
301
|
+
project_id = None
|
|
302
|
+
if "account" in data["sams.sampler.SlurmInfo"]:
|
|
303
|
+
project = data["sams.sampler.SlurmInfo"]["account"]
|
|
304
|
+
if self.do_insert(jobid, "projects", project):
|
|
305
|
+
c.execute(INSERT_PROJECT, {"project": project})
|
|
306
|
+
project_id = self.save_id(jobid, "projects", project, c.lastrowid)
|
|
307
|
+
logger.debug("Inserted project: %s as %d (%d)", project, c.lastrowid, project_id)
|
|
308
|
+
else:
|
|
309
|
+
project_id = self.get_id(jobid, "projects", project)
|
|
310
|
+
logger.debug("Fetched project: %s as %d", project, project_id)
|
|
311
|
+
|
|
312
|
+
# If username is defined in data insert into table
|
|
313
|
+
user = None
|
|
314
|
+
user_id = None
|
|
315
|
+
if "username" in data["sams.sampler.SlurmInfo"]:
|
|
316
|
+
user = data["sams.sampler.SlurmInfo"]["username"]
|
|
317
|
+
if self.do_insert(jobid, "users", user):
|
|
318
|
+
c.execute(INSERT_USER, {"user": user})
|
|
319
|
+
user_id = self.save_id(jobid, "users", user, c.lastrowid)
|
|
320
|
+
logger.debug("Inserted user: %s as %d (%d)", user, c.lastrowid, user_id)
|
|
321
|
+
else:
|
|
322
|
+
user_id = self.get_id(jobid, "users", user)
|
|
323
|
+
logger.debug("Fetched user: %s as %d", user, user_id)
|
|
324
|
+
|
|
325
|
+
recordid = "%s:%s" % (self.cluster, jobid)
|
|
326
|
+
if "starttime" in data["sams.sampler.SlurmInfo"]:
|
|
327
|
+
starttime = data["sams.sampler.SlurmInfo"]["starttime"]
|
|
328
|
+
starttime = starttime.replace("-", "").replace("T", "").replace(":", "")
|
|
329
|
+
recordid = "%s:%s:%s" % (self.cluster, jobid, starttime)
|
|
330
|
+
|
|
331
|
+
# If username is defined in data insert into table
|
|
332
|
+
ncpus = None
|
|
333
|
+
if "cpus" in data["sams.sampler.SlurmInfo"]:
|
|
334
|
+
ncpus = data["sams.sampler.SlurmInfo"]["cpus"]
|
|
335
|
+
|
|
336
|
+
# Insert information about job
|
|
337
|
+
c.execute(
|
|
338
|
+
INSERT_JOBS,
|
|
339
|
+
{
|
|
340
|
+
"jobid": jobid,
|
|
341
|
+
"user": user_id,
|
|
342
|
+
"project": project_id,
|
|
343
|
+
"ncpus": ncpus,
|
|
344
|
+
"recordid": recordid,
|
|
345
|
+
},
|
|
346
|
+
)
|
|
347
|
+
id = c.lastrowid
|
|
348
|
+
|
|
349
|
+
# Insert node
|
|
350
|
+
node_id = None
|
|
351
|
+
if self.do_insert(jobid, "nodes", node):
|
|
352
|
+
c.execute(INSERT_NODE, {"node": node})
|
|
353
|
+
node_id = self.save_id(jobid, "nodes", node, c.lastrowid)
|
|
354
|
+
logger.debug("Inserted node: %s as %d (%d)", node, c.lastrowid, node_id)
|
|
355
|
+
else:
|
|
356
|
+
node_id = self.get_id(jobid, "nodes", node)
|
|
357
|
+
|
|
358
|
+
# Insert information about running commands
|
|
359
|
+
for sw, info in data["sams.sampler.Software"]["execs"].items():
|
|
360
|
+
# Insert software
|
|
361
|
+
sw_id = None
|
|
362
|
+
if self.do_insert(jobid, "softwares", sw):
|
|
363
|
+
sw_id_row = [ts for ts in c.execute(FETCH_SOFTWARE_ID, {"software": sw})]
|
|
364
|
+
|
|
365
|
+
if sw_id_row:
|
|
366
|
+
sw_id = self.save_id(jobid, "softwares", sw, sw_id_row[0][0])
|
|
367
|
+
logger.debug("Fetched sw: %s as %d (%d)", sw, sw_id_row[0][0], sw_id)
|
|
368
|
+
else:
|
|
369
|
+
c.execute(INSERT_SOFTWARE, {"software": sw})
|
|
370
|
+
sw_id = self.save_id(jobid, "softwares", sw, c.lastrowid)
|
|
371
|
+
logger.debug("Inserted sw: %s as %d (%d)", sw, c.lastrowid, sw_id)
|
|
372
|
+
else:
|
|
373
|
+
sw_id = self.get_id(jobid, "softwares", sw)
|
|
374
|
+
logger.debug("Cached sw: %s as %d", sw, sw_id)
|
|
375
|
+
|
|
376
|
+
c.execute(
|
|
377
|
+
INSERT_COMMAND,
|
|
378
|
+
{
|
|
379
|
+
"id": id,
|
|
380
|
+
"node_id": node_id,
|
|
381
|
+
"sw_id": sw_id,
|
|
382
|
+
"start_time": int(data["sams.sampler.Software"]["start_time"]),
|
|
383
|
+
"end_time": int(data["sams.sampler.Software"]["end_time"]),
|
|
384
|
+
"user": info["user"],
|
|
385
|
+
"sys": info["system"],
|
|
386
|
+
},
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
# Commit data to disk
|
|
390
|
+
c.execute("COMMIT")
|
|
391
|
+
db.commit()
|
|
392
|
+
|
|
393
|
+
def cleanup(self):
|
|
394
|
+
for db in self.db.values():
|
|
395
|
+
db.rollback()
|
|
396
|
+
|
|
397
|
+
def close(self):
|
|
398
|
+
for db in self.db.values():
|
|
399
|
+
# Update jobs table.
|
|
400
|
+
try:
|
|
401
|
+
c = db.cursor()
|
|
402
|
+
c.execute("BEGIN TRANSACTION")
|
|
403
|
+
c.execute("PRAGMA temp_store = %s" % self.sqlite_temp_store)
|
|
404
|
+
rows = [row for row in c.execute(FIND_MINMAX_JOBS)]
|
|
405
|
+
for row in rows:
|
|
406
|
+
c.execute(
|
|
407
|
+
UPDATE_MINMAX,
|
|
408
|
+
{
|
|
409
|
+
"id": row[0],
|
|
410
|
+
"start_time": row[1],
|
|
411
|
+
"end_time": row[2],
|
|
412
|
+
"user_time": row[3],
|
|
413
|
+
"system_time": row[4],
|
|
414
|
+
},
|
|
415
|
+
)
|
|
416
|
+
c.execute("COMMIT")
|
|
417
|
+
db.commit()
|
|
418
|
+
except Exception as e:
|
|
419
|
+
logger.exception(e)
|
|
420
|
+
|
|
421
|
+
db.close()
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Software accounting storage "aggregator" for merging data into database
|
|
3
|
+
|
|
4
|
+
SAMS Software accounting
|
|
5
|
+
Copyright (C) 2018-2021 Swedish National Infrastructure for Computing (SNIC)
|
|
6
|
+
|
|
7
|
+
This program is free software; you can redistribute it and/or
|
|
8
|
+
modify it under the terms of the GNU General Public License
|
|
9
|
+
as published by the Free Software Foundation; either version 2
|
|
10
|
+
of the License, or (at your option) any later version.
|
|
11
|
+
|
|
12
|
+
This program is distributed in the hope that it will be useful,
|
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
GNU General Public License for more details.
|
|
16
|
+
|
|
17
|
+
You should have received a copy of the GNU General Public License
|
|
18
|
+
along with this program; If not, see <http://www.gnu.org/licenses/>.
|
|
19
|
+
|
|
20
|
+
Config options:
|
|
21
|
+
|
|
22
|
+
sams.aggregator.SoftwareAccountingPW:
|
|
23
|
+
# Configuration is the same as
|
|
24
|
+
# sams.backend.SoftwareAccountingPW
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
import logging
|
|
29
|
+
|
|
30
|
+
import sams.base
|
|
31
|
+
from sams.backend.SoftwareAccountingPW import Backend
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Aggregator(Backend, sams.base.Aggregator):
|
|
37
|
+
"""SAMS Software accounting aggregator"""
|
|
File without changes
|