jolt 0.9.172__py3-none-any.whl → 0.9.435__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.
- jolt/__init__.py +80 -7
- jolt/__main__.py +9 -1
- jolt/bin/fstree-darwin-x86_64 +0 -0
- jolt/bin/fstree-linux-x86_64 +0 -0
- jolt/cache.py +596 -252
- jolt/chroot.py +36 -11
- jolt/cli.py +143 -130
- jolt/common_pb2.py +45 -45
- jolt/config.py +76 -40
- jolt/error.py +19 -4
- jolt/filesystem.py +2 -6
- jolt/graph.py +400 -82
- jolt/influence.py +110 -3
- jolt/loader.py +338 -174
- jolt/log.py +127 -31
- jolt/manifest.py +13 -46
- jolt/options.py +35 -11
- jolt/pkgs/abseil.py +42 -0
- jolt/pkgs/asio.py +25 -0
- jolt/pkgs/autoconf.py +41 -0
- jolt/pkgs/automake.py +41 -0
- jolt/pkgs/b2.py +31 -0
- jolt/pkgs/boost.py +111 -0
- jolt/pkgs/boringssl.py +32 -0
- jolt/pkgs/busybox.py +39 -0
- jolt/pkgs/bzip2.py +43 -0
- jolt/pkgs/cares.py +29 -0
- jolt/pkgs/catch2.py +36 -0
- jolt/pkgs/cbindgen.py +17 -0
- jolt/pkgs/cista.py +19 -0
- jolt/pkgs/clang.py +44 -0
- jolt/pkgs/cli11.py +24 -0
- jolt/pkgs/cmake.py +48 -0
- jolt/pkgs/cpython.py +196 -0
- jolt/pkgs/crun.py +29 -0
- jolt/pkgs/curl.py +38 -0
- jolt/pkgs/dbus.py +18 -0
- jolt/pkgs/double_conversion.py +24 -0
- jolt/pkgs/fastfloat.py +21 -0
- jolt/pkgs/ffmpeg.py +28 -0
- jolt/pkgs/flatbuffers.py +29 -0
- jolt/pkgs/fmt.py +27 -0
- jolt/pkgs/fstree.py +20 -0
- jolt/pkgs/gflags.py +18 -0
- jolt/pkgs/glib.py +18 -0
- jolt/pkgs/glog.py +25 -0
- jolt/pkgs/glslang.py +21 -0
- jolt/pkgs/golang.py +16 -11
- jolt/pkgs/googlebenchmark.py +18 -0
- jolt/pkgs/googletest.py +46 -0
- jolt/pkgs/gperf.py +15 -0
- jolt/pkgs/grpc.py +73 -0
- jolt/pkgs/hdf5.py +19 -0
- jolt/pkgs/help2man.py +14 -0
- jolt/pkgs/inja.py +28 -0
- jolt/pkgs/jsoncpp.py +31 -0
- jolt/pkgs/libarchive.py +43 -0
- jolt/pkgs/libcap.py +44 -0
- jolt/pkgs/libdrm.py +44 -0
- jolt/pkgs/libedit.py +42 -0
- jolt/pkgs/libevent.py +31 -0
- jolt/pkgs/libexpat.py +27 -0
- jolt/pkgs/libfastjson.py +21 -0
- jolt/pkgs/libffi.py +16 -0
- jolt/pkgs/libglvnd.py +30 -0
- jolt/pkgs/libogg.py +28 -0
- jolt/pkgs/libpciaccess.py +18 -0
- jolt/pkgs/libseccomp.py +21 -0
- jolt/pkgs/libtirpc.py +24 -0
- jolt/pkgs/libtool.py +42 -0
- jolt/pkgs/libunwind.py +35 -0
- jolt/pkgs/libva.py +18 -0
- jolt/pkgs/libvorbis.py +33 -0
- jolt/pkgs/libxml2.py +35 -0
- jolt/pkgs/libxslt.py +17 -0
- jolt/pkgs/libyajl.py +16 -0
- jolt/pkgs/llvm.py +81 -0
- jolt/pkgs/lua.py +54 -0
- jolt/pkgs/lz4.py +26 -0
- jolt/pkgs/m4.py +14 -0
- jolt/pkgs/make.py +17 -0
- jolt/pkgs/mesa.py +81 -0
- jolt/pkgs/meson.py +17 -0
- jolt/pkgs/mstch.py +28 -0
- jolt/pkgs/mysql.py +60 -0
- jolt/pkgs/nasm.py +49 -0
- jolt/pkgs/ncurses.py +30 -0
- jolt/pkgs/ng_log.py +25 -0
- jolt/pkgs/ninja.py +45 -0
- jolt/pkgs/nlohmann_json.py +25 -0
- jolt/pkgs/nodejs.py +19 -11
- jolt/pkgs/opencv.py +24 -0
- jolt/pkgs/openjdk.py +26 -0
- jolt/pkgs/openssl.py +103 -0
- jolt/pkgs/paho.py +76 -0
- jolt/pkgs/patchelf.py +16 -0
- jolt/pkgs/perl.py +42 -0
- jolt/pkgs/pkgconfig.py +64 -0
- jolt/pkgs/poco.py +39 -0
- jolt/pkgs/protobuf.py +77 -0
- jolt/pkgs/pugixml.py +27 -0
- jolt/pkgs/python.py +19 -0
- jolt/pkgs/qt.py +35 -0
- jolt/pkgs/rapidjson.py +26 -0
- jolt/pkgs/rapidyaml.py +28 -0
- jolt/pkgs/re2.py +30 -0
- jolt/pkgs/re2c.py +17 -0
- jolt/pkgs/readline.py +15 -0
- jolt/pkgs/rust.py +41 -0
- jolt/pkgs/sdl.py +28 -0
- jolt/pkgs/simdjson.py +27 -0
- jolt/pkgs/soci.py +46 -0
- jolt/pkgs/spdlog.py +29 -0
- jolt/pkgs/spirv_llvm.py +21 -0
- jolt/pkgs/spirv_tools.py +24 -0
- jolt/pkgs/sqlite.py +83 -0
- jolt/pkgs/ssl.py +12 -0
- jolt/pkgs/texinfo.py +15 -0
- jolt/pkgs/tomlplusplus.py +22 -0
- jolt/pkgs/wayland.py +26 -0
- jolt/pkgs/x11.py +58 -0
- jolt/pkgs/xerces_c.py +20 -0
- jolt/pkgs/xorg.py +360 -0
- jolt/pkgs/xz.py +29 -0
- jolt/pkgs/yamlcpp.py +30 -0
- jolt/pkgs/zeromq.py +47 -0
- jolt/pkgs/zlib.py +87 -0
- jolt/pkgs/zstd.py +33 -0
- jolt/plugins/alias.py +3 -0
- jolt/plugins/allure.py +2 -2
- jolt/plugins/autotools.py +66 -0
- jolt/plugins/cache.py +1 -1
- jolt/plugins/cmake.py +74 -6
- jolt/plugins/conan.py +238 -0
- jolt/plugins/cxxinfo.py +7 -0
- jolt/plugins/docker.py +76 -19
- jolt/plugins/email.xslt +141 -118
- jolt/plugins/environ.py +11 -0
- jolt/plugins/fetch.py +141 -0
- jolt/plugins/gdb.py +33 -14
- jolt/plugins/gerrit.py +0 -13
- jolt/plugins/git.py +248 -66
- jolt/plugins/googletest.py +1 -1
- jolt/plugins/http.py +1 -1
- jolt/plugins/libtool.py +63 -0
- jolt/plugins/linux.py +990 -0
- jolt/plugins/logstash.py +4 -4
- jolt/plugins/meson.py +61 -0
- jolt/plugins/ninja-compdb.py +96 -28
- jolt/plugins/ninja.py +424 -150
- jolt/plugins/paths.py +11 -1
- jolt/plugins/pkgconfig.py +219 -0
- jolt/plugins/podman.py +131 -87
- jolt/plugins/python.py +137 -0
- jolt/plugins/remote_execution/administration_pb2.py +27 -19
- jolt/plugins/remote_execution/log_pb2.py +12 -12
- jolt/plugins/remote_execution/scheduler_pb2.py +23 -23
- jolt/plugins/remote_execution/worker_pb2.py +19 -19
- jolt/plugins/report.py +7 -2
- jolt/plugins/rust.py +25 -0
- jolt/plugins/scheduler.py +135 -86
- jolt/plugins/selfdeploy/setup.py +6 -6
- jolt/plugins/selfdeploy.py +49 -31
- jolt/plugins/strings.py +35 -22
- jolt/plugins/symlinks.py +11 -4
- jolt/plugins/telemetry.py +1 -2
- jolt/plugins/timeline.py +13 -3
- jolt/scheduler.py +467 -165
- jolt/tasks.py +427 -111
- jolt/templates/timeline.html.template +44 -47
- jolt/timer.py +22 -0
- jolt/tools.py +527 -188
- jolt/utils.py +183 -3
- jolt/version.py +1 -1
- jolt/xmldom.py +12 -2
- {jolt-0.9.172.dist-info → jolt-0.9.435.dist-info}/METADATA +97 -41
- jolt-0.9.435.dist-info/RECORD +207 -0
- {jolt-0.9.172.dist-info → jolt-0.9.435.dist-info}/WHEEL +1 -1
- jolt/plugins/amqp.py +0 -855
- jolt/plugins/debian.py +0 -338
- jolt/plugins/repo.py +0 -253
- jolt/plugins/snap.py +0 -122
- jolt-0.9.172.dist-info/RECORD +0 -92
- {jolt-0.9.172.dist-info → jolt-0.9.435.dist-info}/entry_points.txt +0 -0
- {jolt-0.9.172.dist-info → jolt-0.9.435.dist-info}/top_level.txt +0 -0
jolt/plugins/scheduler.py
CHANGED
|
@@ -2,6 +2,7 @@ import click
|
|
|
2
2
|
import grpc
|
|
3
3
|
import queue
|
|
4
4
|
from threading import Lock
|
|
5
|
+
import time
|
|
5
6
|
|
|
6
7
|
from google.protobuf.timestamp_pb2 import Timestamp
|
|
7
8
|
|
|
@@ -12,11 +13,10 @@ from jolt import config
|
|
|
12
13
|
from jolt import hooks
|
|
13
14
|
from jolt import loader
|
|
14
15
|
from jolt import log
|
|
15
|
-
from jolt import manifest
|
|
16
16
|
from jolt import common_pb2 as common_pb
|
|
17
17
|
from jolt import scheduler
|
|
18
18
|
from jolt import utils
|
|
19
|
-
from jolt.error import JoltError, raise_error, raise_error_if, raise_task_error, raise_task_error_if
|
|
19
|
+
from jolt.error import LoggedJoltError, JoltError, raise_error, raise_error_if, raise_task_error, raise_task_error_if
|
|
20
20
|
from jolt.graph import GraphBuilder
|
|
21
21
|
from jolt.scheduler import ExecutorRegistry, JoltEnvironment, NetworkExecutor, NetworkExecutorFactory, WorkerStrategy
|
|
22
22
|
from jolt.tasks import TaskRegistry
|
|
@@ -81,7 +81,7 @@ class LogHandler(object):
|
|
|
81
81
|
loglines=[
|
|
82
82
|
common_pb.LogLine(
|
|
83
83
|
context=self.task.task_id[:8],
|
|
84
|
-
level=record.levelno,
|
|
84
|
+
level=log.level_to_pb(record.levelno),
|
|
85
85
|
time=timestamp,
|
|
86
86
|
message=record.message,
|
|
87
87
|
),
|
|
@@ -108,12 +108,17 @@ class Queue(object):
|
|
|
108
108
|
def __next__(self):
|
|
109
109
|
""" Get the next item from the queue. """
|
|
110
110
|
data = self.q.get()
|
|
111
|
+
if data is None:
|
|
112
|
+
raise StopIteration
|
|
111
113
|
return data
|
|
112
114
|
|
|
113
115
|
def push(self, item):
|
|
114
116
|
""" Push an item to the queue. """
|
|
115
117
|
self.q.put(item)
|
|
116
118
|
|
|
119
|
+
def close(self):
|
|
120
|
+
self.q.put(None)
|
|
121
|
+
|
|
117
122
|
|
|
118
123
|
class RemoteExecutor(NetworkExecutor):
|
|
119
124
|
"""
|
|
@@ -139,6 +144,15 @@ class RemoteExecutor(NetworkExecutor):
|
|
|
139
144
|
self.session = session
|
|
140
145
|
self.task = task
|
|
141
146
|
|
|
147
|
+
def schedule(self, env):
|
|
148
|
+
"""
|
|
149
|
+
Schedule the task for execution.
|
|
150
|
+
|
|
151
|
+
The task is marked as in progress before scheduling.
|
|
152
|
+
"""
|
|
153
|
+
self.task.set_in_progress()
|
|
154
|
+
return super().schedule(env)
|
|
155
|
+
|
|
142
156
|
def cancel(self):
|
|
143
157
|
"""
|
|
144
158
|
Cancel the build session.
|
|
@@ -169,12 +183,17 @@ class RemoteExecutor(NetworkExecutor):
|
|
|
169
183
|
self.download_session_artifacts(extension)
|
|
170
184
|
if not task.has_artifact():
|
|
171
185
|
return
|
|
172
|
-
if not task.cache.
|
|
186
|
+
if not task.cache.download_session_enabled():
|
|
173
187
|
return
|
|
174
188
|
if not task.is_downloadable():
|
|
175
189
|
return
|
|
176
190
|
if not task.download(session_only=True):
|
|
177
191
|
task.warning("Failed to download session artifact")
|
|
192
|
+
if not task.is_resource():
|
|
193
|
+
# Tasks also download session artifacts of consumed resources
|
|
194
|
+
for resource in filter(lambda task: task.is_resource() and not task.is_workspace_resource(), task.children):
|
|
195
|
+
if not resource.is_available_locally(persistent_only=False):
|
|
196
|
+
self.download_session_artifacts(resource)
|
|
178
197
|
|
|
179
198
|
def download_log(self, task):
|
|
180
199
|
""" Download log and transfer lines into local logging system. """
|
|
@@ -184,7 +203,7 @@ class RemoteExecutor(NetworkExecutor):
|
|
|
184
203
|
for response in self.session.logs.ReadLog(request):
|
|
185
204
|
for line in response.loglines:
|
|
186
205
|
log.log(
|
|
187
|
-
line.level,
|
|
206
|
+
log.pb_to_level(line.level),
|
|
188
207
|
line.message,
|
|
189
208
|
created=line.time.ToMicroseconds() / 1000000,
|
|
190
209
|
context=line.context[:7],
|
|
@@ -196,10 +215,19 @@ class RemoteExecutor(NetworkExecutor):
|
|
|
196
215
|
|
|
197
216
|
def run(self, env):
|
|
198
217
|
""" Run the task. """
|
|
218
|
+
if self.is_aborted():
|
|
219
|
+
return
|
|
199
220
|
try:
|
|
200
|
-
self.
|
|
201
|
-
|
|
202
|
-
|
|
221
|
+
with hooks.task_run([self.task] + self.task.extensions), self.task.run_resources():
|
|
222
|
+
try:
|
|
223
|
+
self.run_build(env)
|
|
224
|
+
except (grpc.RpcError, grpc._channel._MultiThreadedRendezvous) as rpc_error:
|
|
225
|
+
raise_task_error(self.task, rpc_error.details(), type="Scheduler Error")
|
|
226
|
+
except Exception as e:
|
|
227
|
+
if not self.task.is_unstable:
|
|
228
|
+
raise e
|
|
229
|
+
finally:
|
|
230
|
+
self.download_session_artifacts(self.task)
|
|
203
231
|
|
|
204
232
|
@utils.retried.on_exception(grpc.RpcError)
|
|
205
233
|
def run_build(self, env):
|
|
@@ -219,10 +247,7 @@ class RemoteExecutor(NetworkExecutor):
|
|
|
219
247
|
response = self.session.exec.ScheduleTask(request)
|
|
220
248
|
|
|
221
249
|
self.update_logstash(self.task)
|
|
222
|
-
|
|
223
|
-
with hooks.task_run([self.task] + self.task.extensions):
|
|
224
|
-
self.run_task(env, response)
|
|
225
|
-
|
|
250
|
+
self.run_task(env, response)
|
|
226
251
|
self.download_persistent_artifacts(self.task)
|
|
227
252
|
|
|
228
253
|
self.task.finished_execution(remote=True)
|
|
@@ -232,15 +257,23 @@ class RemoteExecutor(NetworkExecutor):
|
|
|
232
257
|
except TaskCancelledException:
|
|
233
258
|
pass
|
|
234
259
|
|
|
235
|
-
except grpc.RpcError as rpc_error:
|
|
236
|
-
if
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
260
|
+
except (grpc.RpcError, grpc._channel._MultiThreadedRendezvous) as rpc_error:
|
|
261
|
+
if self.is_aborted():
|
|
262
|
+
if self.task.is_running():
|
|
263
|
+
self.task.failed_execution(remote=True, interrupt=True)
|
|
264
|
+
for extension in self.task.extensions:
|
|
265
|
+
extension.failed_execution(remote=True, interrupt=True)
|
|
266
|
+
return
|
|
267
|
+
|
|
268
|
+
if rpc_error.code() not in [grpc.StatusCode.NOT_FOUND, grpc.StatusCode.UNAVAILABLE]:
|
|
269
|
+
raise_task_error(self.task, rpc_error.details(), type="Scheduler Error")
|
|
270
|
+
|
|
271
|
+
self.session.clear_build_request(f"Scheduler Error: {rpc_error.details()}")
|
|
240
272
|
raise rpc_error
|
|
241
273
|
|
|
242
274
|
except Exception as e:
|
|
243
|
-
|
|
275
|
+
if not isinstance(e, LoggedJoltError):
|
|
276
|
+
log.exception()
|
|
244
277
|
|
|
245
278
|
if self.factory.options.mute:
|
|
246
279
|
try:
|
|
@@ -251,11 +284,8 @@ class RemoteExecutor(NetworkExecutor):
|
|
|
251
284
|
self.task.failed_execution(remote=True)
|
|
252
285
|
for extension in self.task.extensions:
|
|
253
286
|
extension.failed_execution(remote=True)
|
|
254
|
-
if not self.task.is_unstable:
|
|
255
|
-
raise e
|
|
256
287
|
|
|
257
|
-
|
|
258
|
-
self.download_session_artifacts(self.task)
|
|
288
|
+
raise e
|
|
259
289
|
|
|
260
290
|
def run_task(self, env, response):
|
|
261
291
|
""" Run the task.
|
|
@@ -276,18 +306,27 @@ class RemoteExecutor(NetworkExecutor):
|
|
|
276
306
|
for progress in response:
|
|
277
307
|
for line in progress.loglines:
|
|
278
308
|
log.log(
|
|
279
|
-
line.level,
|
|
309
|
+
log.pb_to_level(line.level),
|
|
280
310
|
line.message,
|
|
281
311
|
created=line.time.ToMicroseconds() / 1000000,
|
|
282
312
|
context=line.context[:7],
|
|
283
313
|
prefix=True)
|
|
284
314
|
|
|
315
|
+
if progress.worker:
|
|
316
|
+
self.task.worker = progress.worker.hostname
|
|
317
|
+
|
|
285
318
|
if progress.status in [common_pb.TaskStatus.TASK_RUNNING] \
|
|
286
319
|
and progress.status != self.task.status():
|
|
287
320
|
self.task.running_execution(remote=True)
|
|
288
321
|
for extension in self.task.extensions:
|
|
289
322
|
extension.running_execution(remote=True)
|
|
290
323
|
|
|
324
|
+
if progress.status in [common_pb.TaskStatus.TASK_QUEUED]:
|
|
325
|
+
if last_status in [common_pb.TaskStatus.TASK_RUNNING]:
|
|
326
|
+
self.task.restarted_execution(remote=True)
|
|
327
|
+
for extension in self.task.extensions:
|
|
328
|
+
extension.restarted_execution(remote=True)
|
|
329
|
+
|
|
291
330
|
if progress.status in [
|
|
292
331
|
common_pb.TaskStatus.TASK_PASSED,
|
|
293
332
|
common_pb.TaskStatus.TASK_DOWNLOADED,
|
|
@@ -296,14 +335,17 @@ class RemoteExecutor(NetworkExecutor):
|
|
|
296
335
|
]:
|
|
297
336
|
break
|
|
298
337
|
|
|
338
|
+
if progress.status in [common_pb.TaskStatus.TASK_CANCELLED]:
|
|
339
|
+
if last_status in [common_pb.TaskStatus.TASK_RUNNING]:
|
|
340
|
+
self.task.failed_execution(remote=True, interrupt=True)
|
|
341
|
+
for extension in self.task.extensions:
|
|
342
|
+
extension.failed_execution(remote=True, interrupt=True)
|
|
343
|
+
raise TaskCancelledException()
|
|
344
|
+
|
|
299
345
|
if progress.status in [
|
|
300
|
-
common_pb.TaskStatus.TASK_CANCELLED,
|
|
301
346
|
common_pb.TaskStatus.TASK_FAILED,
|
|
302
347
|
common_pb.TaskStatus.TASK_UNSTABLE,
|
|
303
348
|
]:
|
|
304
|
-
if last_status in [common_pb.TaskStatus.TASK_QUEUED]:
|
|
305
|
-
raise TaskCancelledException()
|
|
306
|
-
|
|
307
349
|
for error in progress.errors:
|
|
308
350
|
with self.task.task.report() as report:
|
|
309
351
|
report.add_error(
|
|
@@ -312,14 +354,19 @@ class RemoteExecutor(NetworkExecutor):
|
|
|
312
354
|
error.message,
|
|
313
355
|
error.details,
|
|
314
356
|
)
|
|
315
|
-
|
|
316
|
-
for error in report.errors:
|
|
317
|
-
raise_error(f"{error.type}: {error.message}")
|
|
357
|
+
self.task.raise_for_status()
|
|
318
358
|
raise raise_error("Remote execution failed")
|
|
319
359
|
|
|
320
360
|
if progress.status in [
|
|
321
361
|
common_pb.TaskStatus.TASK_ERROR,
|
|
322
362
|
]:
|
|
363
|
+
log.log(
|
|
364
|
+
log.VERBOSE,
|
|
365
|
+
f"Host: {progress.worker.hostname}",
|
|
366
|
+
created=time.time(),
|
|
367
|
+
context=self.task.identity[:7],
|
|
368
|
+
prefix=True)
|
|
369
|
+
|
|
323
370
|
for error in progress.errors:
|
|
324
371
|
with self.task.task.report() as report:
|
|
325
372
|
report.add_error(
|
|
@@ -328,11 +375,7 @@ class RemoteExecutor(NetworkExecutor):
|
|
|
328
375
|
error.message,
|
|
329
376
|
error.details,
|
|
330
377
|
)
|
|
331
|
-
|
|
332
|
-
for error in report.errors:
|
|
333
|
-
for line in error.details.splitlines():
|
|
334
|
-
log.error(line)
|
|
335
|
-
raise_error(f"{error.type}: {error.message}")
|
|
378
|
+
self.task.raise_for_status(log_details=not self.factory.options.mute)
|
|
336
379
|
raise raise_error("Remote execution failed")
|
|
337
380
|
|
|
338
381
|
last_status = progress.status
|
|
@@ -384,31 +427,16 @@ class RemoteSession(object):
|
|
|
384
427
|
# Lock to ensure only one build is registered at a time.
|
|
385
428
|
self.lock = Lock()
|
|
386
429
|
|
|
430
|
+
# The build environment: client, workspace, etc.
|
|
431
|
+
self.buildenv = None
|
|
432
|
+
|
|
387
433
|
def initialize(self, graph):
|
|
388
434
|
""" Initialize the session with the scheduler. """
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
# Create a list of parameters to send to the scheduler.
|
|
393
|
-
parameters = []
|
|
394
|
-
for key, value in registry.get_network_parameters(None).items():
|
|
395
|
-
parameters.append(common_pb.Property(key=key, value=value))
|
|
396
|
-
|
|
397
|
-
# Add parameters from the config / command line (-c params.key).
|
|
398
|
-
parameters.extend(config.export_params())
|
|
399
|
-
|
|
400
|
-
# Create the build environment.
|
|
401
|
-
self.buildenv = common_pb.BuildEnvironment(
|
|
402
|
-
client=selfdeploy.get_client(),
|
|
403
|
-
parameters=parameters,
|
|
404
|
-
task_default_parameters=scheduler.export_task_default_params(graph.tasks),
|
|
405
|
-
tasks=scheduler.export_tasks(graph.tasks + graph.pruned),
|
|
406
|
-
workspace=loader.export_workspace(graph.tasks),
|
|
407
|
-
loglevel=log.get_level(),
|
|
408
|
-
config=config.export_config(),
|
|
409
|
-
)
|
|
435
|
+
self.tasks = graph.tasks
|
|
436
|
+
self.pruned = graph.pruned
|
|
410
437
|
|
|
411
438
|
@locked
|
|
439
|
+
@utils.retried.on_exception(grpc.RpcError)
|
|
412
440
|
def make_build_request(self):
|
|
413
441
|
""" Create a build request with the scheduler. """
|
|
414
442
|
|
|
@@ -416,6 +444,18 @@ class RemoteSession(object):
|
|
|
416
444
|
if self.build:
|
|
417
445
|
return
|
|
418
446
|
|
|
447
|
+
if not self.buildenv:
|
|
448
|
+
# Create the build environment.
|
|
449
|
+
self.buildenv = common_pb.BuildEnvironment(
|
|
450
|
+
client=selfdeploy.get_client(),
|
|
451
|
+
parameters=config.export_params(),
|
|
452
|
+
task_default_parameters=scheduler.export_task_default_params(self.tasks),
|
|
453
|
+
tasks=scheduler.export_tasks(self.tasks + self.pruned),
|
|
454
|
+
workspace=loader.export_workspace(self.tasks),
|
|
455
|
+
loglevel=log.get_level_pb(),
|
|
456
|
+
config=config.export_config(),
|
|
457
|
+
)
|
|
458
|
+
|
|
419
459
|
# Create the build request.
|
|
420
460
|
req = scheduler_pb.BuildRequest(
|
|
421
461
|
environment=self.buildenv,
|
|
@@ -439,12 +479,15 @@ class RemoteSession(object):
|
|
|
439
479
|
log.info(colors.blue("Build registered with scheduler, waiting for worker"))
|
|
440
480
|
return self.build
|
|
441
481
|
|
|
442
|
-
|
|
482
|
+
@locked
|
|
483
|
+
def clear_build_request(self, message=None):
|
|
443
484
|
""" Clear the build request. Called when a build fails. """
|
|
444
485
|
|
|
445
486
|
# Close grpc server response stream
|
|
446
487
|
if self.build:
|
|
447
488
|
self.build.cancel()
|
|
489
|
+
if message:
|
|
490
|
+
log.warning(message)
|
|
448
491
|
self.build = None
|
|
449
492
|
self.build_id = None
|
|
450
493
|
|
|
@@ -510,7 +553,7 @@ class RemoteExecutionFactory(NetworkExecutorFactory):
|
|
|
510
553
|
log.verbose("[Remote] Loaded")
|
|
511
554
|
|
|
512
555
|
|
|
513
|
-
@cli.cli.command()
|
|
556
|
+
@cli.cli.command(hidden=True)
|
|
514
557
|
@click.option("-w", "--worker", required=True, help="Worker identifier.")
|
|
515
558
|
@click.option("-b", "--build", required=True, help="Build identifier to enlist for.")
|
|
516
559
|
@click.argument("request", required=True)
|
|
@@ -533,13 +576,19 @@ def executor(ctx, worker, build, request):
|
|
|
533
576
|
|
|
534
577
|
# Set log level
|
|
535
578
|
loglevel = request.environment.loglevel
|
|
536
|
-
log.
|
|
579
|
+
log.set_level_pb(loglevel)
|
|
580
|
+
|
|
581
|
+
# Import workspace
|
|
582
|
+
loader.import_workspace(request.environment)
|
|
537
583
|
|
|
538
|
-
# Import
|
|
539
|
-
|
|
584
|
+
# Import configuration snippet
|
|
585
|
+
config.import_config(request.environment.config)
|
|
586
|
+
|
|
587
|
+
# Import configuration parameters (-c params.key)
|
|
588
|
+
config.import_params({param.key: param.value for param in request.environment.parameters})
|
|
540
589
|
|
|
541
590
|
options = JoltOptions(
|
|
542
|
-
network=
|
|
591
|
+
network=True,
|
|
543
592
|
local=False,
|
|
544
593
|
download=config.getboolean("network", "download", True),
|
|
545
594
|
upload=config.getboolean("network", "upload", True),
|
|
@@ -569,12 +618,13 @@ def executor(ctx, worker, build, request):
|
|
|
569
618
|
|
|
570
619
|
# Build the graph of tasks
|
|
571
620
|
gb = GraphBuilder(registry, acache, options=options, progress=True, buildenv=request.environment)
|
|
572
|
-
|
|
621
|
+
task_names = [task.name for task in request.environment.tasks.values()]
|
|
622
|
+
dag = gb.build(task_names)
|
|
573
623
|
|
|
574
624
|
# Enlist to execute build tasks from the scheduler
|
|
575
625
|
enlist_msg = scheduler_pb.TaskUpdate(
|
|
576
626
|
request=scheduler_pb.TaskRequest(build_id=build),
|
|
577
|
-
worker=scheduler_pb.WorkerAllocation(id=worker),
|
|
627
|
+
worker=scheduler_pb.WorkerAllocation(id=worker, hostname=utils.hostname()),
|
|
578
628
|
)
|
|
579
629
|
|
|
580
630
|
# A queue to send updates to the scheduler
|
|
@@ -586,11 +636,12 @@ def executor(ctx, worker, build, request):
|
|
|
586
636
|
|
|
587
637
|
# Subscribe to tasks
|
|
588
638
|
for task in sched.GetTasks(updates):
|
|
589
|
-
log.
|
|
639
|
+
log.set_level_pb(loglevel)
|
|
590
640
|
|
|
591
641
|
log.info("Queuing {}", task.task_id)
|
|
592
642
|
graph_task = dag.get_task_by_identity(task.task_id)
|
|
593
643
|
executor = None
|
|
644
|
+
status = None
|
|
594
645
|
|
|
595
646
|
try:
|
|
596
647
|
session = {}
|
|
@@ -600,27 +651,30 @@ def executor(ctx, worker, build, request):
|
|
|
600
651
|
|
|
601
652
|
# Run the task
|
|
602
653
|
with log.handler(LogHandler(updates, task)):
|
|
603
|
-
executor.run(JoltEnvironment(cache=acache))
|
|
604
|
-
|
|
605
|
-
except KeyboardInterrupt as interrupt:
|
|
606
|
-
log.info("Task cancelled")
|
|
654
|
+
executor.run(JoltEnvironment(cache=acache, queue=None, worker=True))
|
|
607
655
|
|
|
656
|
+
except KeyboardInterrupt:
|
|
608
657
|
# Send an update to the scheduler
|
|
609
658
|
update = scheduler_pb.TaskUpdate(
|
|
610
659
|
request=task,
|
|
611
660
|
status=common_pb.TaskStatus.TASK_CANCELLED,
|
|
612
661
|
)
|
|
613
662
|
updates.push(update)
|
|
663
|
+
continue
|
|
614
664
|
|
|
615
|
-
|
|
616
|
-
|
|
665
|
+
except Exception:
|
|
666
|
+
status = common_pb.TaskStatus.TASK_FAILED
|
|
617
667
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
log.exception(e)
|
|
668
|
+
else:
|
|
669
|
+
status = graph_task.status()
|
|
621
670
|
|
|
671
|
+
finally:
|
|
622
672
|
errors = []
|
|
623
673
|
|
|
674
|
+
# If the task status remains queued, mark it as failed
|
|
675
|
+
if status in [common_pb.TaskStatus.TASK_QUEUED]:
|
|
676
|
+
status = common_pb.TaskStatus.TASK_FAILED
|
|
677
|
+
|
|
624
678
|
# Add errors from the task to the update sent to the scheduler
|
|
625
679
|
with graph_task.task.report() as report:
|
|
626
680
|
for error in report.errors:
|
|
@@ -634,24 +688,19 @@ def executor(ctx, worker, build, request):
|
|
|
634
688
|
# Send an update to the scheduler
|
|
635
689
|
update = scheduler_pb.TaskUpdate(
|
|
636
690
|
request=task,
|
|
637
|
-
status=
|
|
691
|
+
status=status,
|
|
638
692
|
errors=errors,
|
|
639
693
|
)
|
|
640
694
|
updates.push(update)
|
|
641
695
|
|
|
642
|
-
|
|
643
|
-
|
|
696
|
+
# Release references to cache artifacts
|
|
697
|
+
acache.release()
|
|
644
698
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
status = common_pb.TaskStatus.TASK_FAILED
|
|
699
|
+
except grpc.RpcError as rpc_error:
|
|
700
|
+
log.warning("Scheduler Error: {}", rpc_error.details())
|
|
648
701
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
request=task,
|
|
652
|
-
status=status,
|
|
653
|
-
)
|
|
654
|
-
updates.push(update)
|
|
702
|
+
except KeyboardInterrupt:
|
|
703
|
+
log.info("Interrupted, exiting")
|
|
655
704
|
|
|
656
705
|
except Exception as e:
|
|
657
706
|
log.set_level(log.EXCEPTION)
|
jolt/plugins/selfdeploy/setup.py
CHANGED
|
@@ -74,32 +74,32 @@ setup(
|
|
|
74
74
|
"click>=8.1",
|
|
75
75
|
"colorama",
|
|
76
76
|
"fasteners",
|
|
77
|
-
"grpcio",
|
|
77
|
+
"grpcio>=1.62.2",
|
|
78
78
|
"jinja2",
|
|
79
79
|
"keyring",
|
|
80
80
|
"keyrings.alt",
|
|
81
81
|
"importlib_metadata",
|
|
82
82
|
"lxml",
|
|
83
83
|
"multi_key_dict",
|
|
84
|
-
"ninja
|
|
84
|
+
"ninja",
|
|
85
85
|
"protobuf",
|
|
86
86
|
"psutil",
|
|
87
87
|
"pygit2",
|
|
88
|
+
"py7zr",
|
|
88
89
|
"requests",
|
|
90
|
+
"zstandard",
|
|
89
91
|
"tqdm",
|
|
90
|
-
"unshare",
|
|
91
92
|
],
|
|
92
93
|
dependency_links=[],
|
|
93
94
|
extras_require={
|
|
94
95
|
"allure": ["allure-python-commons"],
|
|
95
|
-
"
|
|
96
|
-
"conan": ["conan<2.0"],
|
|
96
|
+
"conan": ["conan>=2.0"],
|
|
97
97
|
"dev": ["check-manifest"],
|
|
98
98
|
"doc": ["sphinx-click", "sphinx-rtd-theme"],
|
|
99
99
|
"test": ["coverage"],
|
|
100
100
|
},
|
|
101
101
|
package_data={
|
|
102
|
-
"jolt": ["**/*.sh", "**/*.xslt", "**/*.template"],
|
|
102
|
+
"jolt": ["**/*.sh", "**/*.xslt", "**/*.template", "**/fstree-*-x86_64"],
|
|
103
103
|
},
|
|
104
104
|
entry_points={
|
|
105
105
|
"console_scripts": [
|
jolt/plugins/selfdeploy.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import importlib_metadata
|
|
2
|
+
import os
|
|
2
3
|
|
|
3
4
|
from jolt import config
|
|
4
5
|
from jolt import filesystem as fs
|
|
@@ -11,12 +12,9 @@ from jolt.cache import ArtifactCache
|
|
|
11
12
|
from jolt.error import raise_error_if
|
|
12
13
|
from jolt.graph import GraphBuilder
|
|
13
14
|
from jolt.loader import JoltLoader
|
|
14
|
-
from jolt.manifest import JoltManifest
|
|
15
15
|
from jolt.scheduler import JoltEnvironment
|
|
16
16
|
from jolt.scheduler import LocalExecutor
|
|
17
17
|
from jolt.scheduler import LocalExecutorFactory
|
|
18
|
-
from jolt.scheduler import NetworkExecutorExtension
|
|
19
|
-
from jolt.scheduler import NetworkExecutorExtensionFactory
|
|
20
18
|
from jolt.tasks import Task, TaskRegistry
|
|
21
19
|
|
|
22
20
|
|
|
@@ -90,6 +88,7 @@ class Jolt(Task):
|
|
|
90
88
|
artifact.collect('jolt/*/*/*.py')
|
|
91
89
|
artifact.collect('jolt/*/*.xslt')
|
|
92
90
|
artifact.collect('jolt/*/*.template')
|
|
91
|
+
artifact.collect('jolt/bin')
|
|
93
92
|
artifact.collect('jolt/plugins/selfdeploy/README.rst', flatten=True)
|
|
94
93
|
artifact.collect('jolt/plugins/selfdeploy/setup.py', flatten=True)
|
|
95
94
|
for e in self.extra_files:
|
|
@@ -97,43 +96,37 @@ class Jolt(Task):
|
|
|
97
96
|
artifact.collect(fs.path.basename(e))
|
|
98
97
|
|
|
99
98
|
|
|
100
|
-
class SelfDeployExtension(NetworkExecutorExtension):
|
|
101
|
-
@utils.cached.instance
|
|
102
|
-
def get_parameters(self, _):
|
|
103
|
-
client = get_client()
|
|
104
|
-
params = {}
|
|
105
|
-
if client.identity:
|
|
106
|
-
params["jolt_identity"] = client.identity
|
|
107
|
-
if client.url:
|
|
108
|
-
params["jolt_url"] = client.url
|
|
109
|
-
return params
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
@NetworkExecutorExtensionFactory.Register
|
|
113
|
-
class SelfDeployExtensionFactory(NetworkExecutorExtensionFactory):
|
|
114
|
-
def create(self):
|
|
115
|
-
return SelfDeployExtension()
|
|
116
|
-
|
|
117
|
-
|
|
118
99
|
@utils.cached.method
|
|
119
100
|
def get_dependencies(packages=None):
|
|
120
101
|
reqs = packages or ["jolt"]
|
|
121
102
|
pkgs = {}
|
|
103
|
+
skip = set()
|
|
122
104
|
|
|
123
105
|
while reqs:
|
|
124
106
|
req = reqs.pop()
|
|
125
107
|
|
|
126
|
-
|
|
108
|
+
try:
|
|
109
|
+
dist = importlib_metadata.distribution(req)
|
|
110
|
+
except (ImportError, importlib_metadata.PackageNotFoundError):
|
|
111
|
+
dist = None
|
|
112
|
+
except Exception:
|
|
113
|
+
dist = None
|
|
127
114
|
if dist is None:
|
|
128
|
-
|
|
129
|
-
pkgs[req] = req
|
|
115
|
+
skip.add(req)
|
|
130
116
|
continue
|
|
131
117
|
|
|
132
|
-
for dep in dist.requires
|
|
133
|
-
|
|
134
|
-
|
|
118
|
+
for dep in dist.requires or []:
|
|
119
|
+
dep = dep.split(" ", 1)[0].strip()
|
|
120
|
+
dep = dep.split("[", 1)[0].strip()
|
|
121
|
+
dep = dep.split(";", 1)[0].strip()
|
|
122
|
+
dep = dep.split(">", 1)[0].strip()
|
|
123
|
+
dep = dep.split("=", 1)[0].strip()
|
|
124
|
+
dep = dep.split("<", 1)[0].strip()
|
|
125
|
+
dep = dep.split("!", 1)[0].strip()
|
|
126
|
+
if dep not in pkgs and dep not in skip:
|
|
127
|
+
reqs.append(dep)
|
|
135
128
|
|
|
136
|
-
pkgs[req] = f"{dist.
|
|
129
|
+
pkgs[req] = f"{dist.name}=={dist.version}"
|
|
137
130
|
|
|
138
131
|
try:
|
|
139
132
|
del pkgs["jolt"]
|
|
@@ -154,8 +147,8 @@ def publish_artifact():
|
|
|
154
147
|
registry = TaskRegistry()
|
|
155
148
|
registry.add_task_class(Jolt)
|
|
156
149
|
acache = ArtifactCache.get()
|
|
157
|
-
env = JoltEnvironment(cache=acache)
|
|
158
|
-
gb = GraphBuilder(registry, acache
|
|
150
|
+
env = JoltEnvironment(cache=acache, queue=None)
|
|
151
|
+
gb = GraphBuilder(registry, acache)
|
|
159
152
|
dag = gb.build(["jolt"])
|
|
160
153
|
task = dag.select(lambda graph, task: True)
|
|
161
154
|
assert len(task) == 1, "Too many selfdeploy tasks found"
|
|
@@ -189,8 +182,33 @@ def get_pinned_version():
|
|
|
189
182
|
)
|
|
190
183
|
|
|
191
184
|
|
|
185
|
+
def get_nix_version():
|
|
186
|
+
return common_pb.Client(
|
|
187
|
+
requirements=get_extra_dependencies(),
|
|
188
|
+
version=version.__version__,
|
|
189
|
+
nix=True,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
192
193
|
def get_client():
|
|
194
|
+
# Floating version is a special case where we want to deploy the Jolt
|
|
195
|
+
# source code to a remote cache and use that URL as the client URL
|
|
196
|
+
# for workers.
|
|
193
197
|
floating = config.getboolean("selfdeploy", "floating", False)
|
|
194
198
|
if floating:
|
|
195
199
|
return get_floating_version()
|
|
200
|
+
|
|
201
|
+
# If Nix has been explicitly disabled, we want to pin versions.
|
|
202
|
+
if not config.getboolean("selfdeploy", "nix", True):
|
|
203
|
+
return get_pinned_version()
|
|
204
|
+
|
|
205
|
+
# If Nix has been explicitly enabled, we want to use the Nix shell.
|
|
206
|
+
if config.getboolean("selfdeploy", "nix", False):
|
|
207
|
+
return get_nix_version()
|
|
208
|
+
|
|
209
|
+
# If we are in a Nix shell, we want to use the Nix shell.
|
|
210
|
+
if os.environ.get("IN_NIX_SHELL"):
|
|
211
|
+
return get_nix_version()
|
|
212
|
+
|
|
213
|
+
# Default to pinned version
|
|
196
214
|
return get_pinned_version()
|