manta-node 0.6b0.dev585__py3-none-any.whl → 0.6b0.dev587__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.
- manta_node/cli/commands/start.py +128 -14
- {manta_node-0.6b0.dev585.dist-info → manta_node-0.6b0.dev587.dist-info}/METADATA +1 -1
- {manta_node-0.6b0.dev585.dist-info → manta_node-0.6b0.dev587.dist-info}/RECORD +7 -7
- {manta_node-0.6b0.dev585.dist-info → manta_node-0.6b0.dev587.dist-info}/WHEEL +0 -0
- {manta_node-0.6b0.dev585.dist-info → manta_node-0.6b0.dev587.dist-info}/entry_points.txt +0 -0
- {manta_node-0.6b0.dev585.dist-info → manta_node-0.6b0.dev587.dist-info}/licenses/LICENSE +0 -0
- {manta_node-0.6b0.dev585.dist-info → manta_node-0.6b0.dev587.dist-info}/top_level.txt +0 -0
manta_node/cli/commands/start.py
CHANGED
|
@@ -21,6 +21,68 @@ from ...node_orchestrator import Node, NodeFatalError
|
|
|
21
21
|
|
|
22
22
|
console = Console()
|
|
23
23
|
|
|
24
|
+
_DEFAULT_LOG_MAX_BYTES = 100 * 1024 * 1024
|
|
25
|
+
|
|
26
|
+
_SIZE_SUFFIXES = {"K": 1024, "M": 1024**2, "G": 1024**3}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _log_file_max_bytes(declared: str) -> int:
|
|
30
|
+
"""Turn a ``LoggingConfig.max_file_size`` string into a byte count.
|
|
31
|
+
|
|
32
|
+
Accepts a bare number of bytes or a K/M/G suffix. An unparsable value falls
|
|
33
|
+
back to the default rather than raising: this runs on the start path, and
|
|
34
|
+
refusing to start a node over a typo in a log setting would turn a cosmetic
|
|
35
|
+
config error into an outage.
|
|
36
|
+
"""
|
|
37
|
+
text = str(declared).strip().upper().removesuffix("B")
|
|
38
|
+
multiplier = _SIZE_SUFFIXES.get(text[-1:], 1)
|
|
39
|
+
if multiplier != 1:
|
|
40
|
+
text = text[:-1]
|
|
41
|
+
try:
|
|
42
|
+
return int(float(text) * multiplier)
|
|
43
|
+
except ValueError:
|
|
44
|
+
return _DEFAULT_LOG_MAX_BYTES
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _stdout_file_is_held(stdout_file: Path) -> bool:
|
|
48
|
+
"""True when a still-running recorded instance has this path open."""
|
|
49
|
+
instance_dir = Path.home() / ".manta" / "nodes" / "instances"
|
|
50
|
+
target = str(stdout_file)
|
|
51
|
+
try:
|
|
52
|
+
recorded = sorted(instance_dir.glob("*.json"))
|
|
53
|
+
except OSError:
|
|
54
|
+
# Unknown counts as held, and the asymmetry is deliberate: a roll
|
|
55
|
+
# skipped under a dead writer costs disk, one performed under a live
|
|
56
|
+
# writer costs that writer's output.
|
|
57
|
+
return True
|
|
58
|
+
|
|
59
|
+
for instance_file in recorded:
|
|
60
|
+
try:
|
|
61
|
+
data = json.loads(instance_file.read_text())
|
|
62
|
+
except (OSError, ValueError):
|
|
63
|
+
continue
|
|
64
|
+
# `isinstance` and not `.get`: a JSON list or bare string parses fine and
|
|
65
|
+
# has no `.get`, and the AttributeError would escape both this function
|
|
66
|
+
# and the caller's `except OSError` to land in `start_node_background`'s
|
|
67
|
+
# `except Exception` -- a node that will not start because a file in an
|
|
68
|
+
# unrelated directory is malformed.
|
|
69
|
+
if not isinstance(data, dict) or data.get("stdout_file") != target:
|
|
70
|
+
continue
|
|
71
|
+
pid = data.get("pid")
|
|
72
|
+
# `pid > 0` is load-bearing, not a range check: os.kill(0, ...) addresses
|
|
73
|
+
# the caller's whole process group and os.kill(-1, ...) every process it
|
|
74
|
+
# may signal. This pid is read from a file on disk, so it is untrusted.
|
|
75
|
+
if not isinstance(pid, int) or isinstance(pid, bool) or pid <= 0:
|
|
76
|
+
continue
|
|
77
|
+
try:
|
|
78
|
+
os.kill(pid, 0)
|
|
79
|
+
except ProcessLookupError:
|
|
80
|
+
continue
|
|
81
|
+
except OSError:
|
|
82
|
+
pass # Alive, but not ours to signal (EPERM). Still a writer.
|
|
83
|
+
return True
|
|
84
|
+
return False
|
|
85
|
+
|
|
24
86
|
|
|
25
87
|
def print_error(message: str):
|
|
26
88
|
"""Print error message in red."""
|
|
@@ -172,22 +234,42 @@ def start_node_foreground(
|
|
|
172
234
|
},
|
|
173
235
|
},
|
|
174
236
|
"handlers": {
|
|
237
|
+
# NEVER give this handler `mode: "w"`, and never swap it back to
|
|
238
|
+
# a plain FileHandler. This file is the only untruncated account
|
|
239
|
+
# of a crash, and it is opened by the restart the crash causes:
|
|
240
|
+
# truncating on open destroys the evidence of the very incident
|
|
241
|
+
# a reader came for. Rotation is what keeps that append bounded.
|
|
175
242
|
"file": {
|
|
176
|
-
"class": "logging.
|
|
243
|
+
"class": "logging.handlers.RotatingFileHandler",
|
|
177
244
|
"formatter": "standard",
|
|
178
245
|
"filename": log_config.filename,
|
|
179
246
|
"filters": ["manta_filter"],
|
|
180
|
-
"
|
|
181
|
-
|
|
182
|
-
"rich": {
|
|
183
|
-
"class": "rich.logging.RichHandler",
|
|
184
|
-
"formatter": "standard",
|
|
185
|
-
"markup": True,
|
|
186
|
-
"filters": ["manta_filter"],
|
|
187
|
-
"console": Console(
|
|
188
|
-
_environ={"COLUMNS": "284"},
|
|
189
|
-
),
|
|
247
|
+
"maxBytes": _log_file_max_bytes(log_config.max_file_size),
|
|
248
|
+
"backupCount": log_config.backup_count,
|
|
190
249
|
},
|
|
250
|
+
# Rich elides each line to the console width as it renders, so
|
|
251
|
+
# what systemd captures is already cut -- `journalctl` cannot
|
|
252
|
+
# restore characters that were never written. Under a unit there
|
|
253
|
+
# is no tty, and the journal is then the only surviving record,
|
|
254
|
+
# so it gets a plain handler that formats the message whole.
|
|
255
|
+
# Rich stays for an operator running the node interactively.
|
|
256
|
+
"console": (
|
|
257
|
+
{
|
|
258
|
+
"class": "rich.logging.RichHandler",
|
|
259
|
+
"formatter": "standard",
|
|
260
|
+
"markup": True,
|
|
261
|
+
"filters": ["manta_filter"],
|
|
262
|
+
"console": Console(
|
|
263
|
+
_environ={"COLUMNS": "284"},
|
|
264
|
+
),
|
|
265
|
+
}
|
|
266
|
+
if sys.stdout.isatty()
|
|
267
|
+
else {
|
|
268
|
+
"class": "logging.StreamHandler",
|
|
269
|
+
"formatter": "standard",
|
|
270
|
+
"filters": ["manta_filter"],
|
|
271
|
+
}
|
|
272
|
+
),
|
|
191
273
|
},
|
|
192
274
|
"root": {"level": log_config.level, "handlers": []},
|
|
193
275
|
}
|
|
@@ -196,7 +278,7 @@ def start_node_foreground(
|
|
|
196
278
|
if log_config.log_to_file:
|
|
197
279
|
config_dict["root"]["handlers"].append("file")
|
|
198
280
|
if log_config.log_to_console:
|
|
199
|
-
config_dict["root"]["handlers"].append("
|
|
281
|
+
config_dict["root"]["handlers"].append("console")
|
|
200
282
|
|
|
201
283
|
# Call configure_logging with the config dictionary
|
|
202
284
|
configure_logging(config=config_dict, debug=log_config.debug_mode)
|
|
@@ -304,8 +386,35 @@ def start_node_background(
|
|
|
304
386
|
# Ensure log directory exists
|
|
305
387
|
log_file.parent.mkdir(parents=True, exist_ok=True)
|
|
306
388
|
|
|
307
|
-
#
|
|
308
|
-
|
|
389
|
+
# One writer per path, and NEVER `log_file`: the child rotates that
|
|
390
|
+
# path, and a rename does not retarget an fd already open here, so this
|
|
391
|
+
# stream would follow the orphaned inode down the .1/.2 chain and be
|
|
392
|
+
# deleted at backupCount -- taking with it any traceback written before
|
|
393
|
+
# logging is configured.
|
|
394
|
+
# The suffix must stay off `.log`: logs.py globs `*.log` beside this
|
|
395
|
+
# file and keys by stem, so a `.log` sibling appears as a second node
|
|
396
|
+
# and defeats the single-instance auto-select.
|
|
397
|
+
stdout_file = log_file.with_suffix(".stdout")
|
|
398
|
+
|
|
399
|
+
# Bounds an append that never truncates. One previous run is kept: it is
|
|
400
|
+
# what explains the restart that replaced it.
|
|
401
|
+
# Rolled BEFORE the fd is opened, and never while another instance holds
|
|
402
|
+
# it. A rename does not retarget an already-open fd, so either mistake
|
|
403
|
+
# leaves a writer appending to an inode the next roll unlinks.
|
|
404
|
+
max_bytes = _log_file_max_bytes(config_manager.config.logging.max_file_size)
|
|
405
|
+
try:
|
|
406
|
+
if stdout_file.stat().st_size >= max_bytes and not _stdout_file_is_held(
|
|
407
|
+
stdout_file
|
|
408
|
+
):
|
|
409
|
+
stdout_file.replace(stdout_file.with_name(f"{stdout_file.name}.1"))
|
|
410
|
+
except OSError:
|
|
411
|
+
# Housekeeping on a log file, running inside the caller's `except
|
|
412
|
+
# Exception`: anything escaping here becomes a node that will not
|
|
413
|
+
# start. Failing to roll costs disk; failing to start costs the node.
|
|
414
|
+
pass
|
|
415
|
+
|
|
416
|
+
# Append, never "w": a restart must not erase the run that prompted it.
|
|
417
|
+
with open(stdout_file, "a") as log:
|
|
309
418
|
proc = subprocess.Popen(
|
|
310
419
|
cmd,
|
|
311
420
|
stdout=log,
|
|
@@ -337,6 +446,7 @@ def start_node_background(
|
|
|
337
446
|
"manager_host": config_manager.config.network.manager_host,
|
|
338
447
|
"manager_port": config_manager.config.network.manager_port,
|
|
339
448
|
"log_file": str(log_file),
|
|
449
|
+
"stdout_file": str(stdout_file),
|
|
340
450
|
}
|
|
341
451
|
|
|
342
452
|
with open(instance_file, "w") as f:
|
|
@@ -344,7 +454,11 @@ def start_node_background(
|
|
|
344
454
|
|
|
345
455
|
return 0
|
|
346
456
|
else:
|
|
457
|
+
# stdout_file first: a node that died this early never reached
|
|
458
|
+
# configure_logging, so log_file holds nothing about it.
|
|
347
459
|
print_error("Node failed to start. Check logs for details.")
|
|
460
|
+
if stdout_file.exists():
|
|
461
|
+
console.print(f"Startup output: {stdout_file}")
|
|
348
462
|
if log_file.exists():
|
|
349
463
|
console.print(f"Log file: {log_file}")
|
|
350
464
|
return 1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: manta_node
|
|
3
|
-
Version: 0.6b0.
|
|
3
|
+
Version: 0.6b0.dev587
|
|
4
4
|
Summary: Node side software of the Manta platform. It is responsible for the communication with the Manta Core and the execution of the tasks.
|
|
5
5
|
Author-email: Hugo Miralles <hugo.miralles@manta-tech.io>, Matthew Thompson <matthew.thompson@manta-tech.io>
|
|
6
6
|
License-Expression: AGPL-3.0-or-later
|
|
@@ -13,7 +13,7 @@ manta_node/cli/commands/cluster.py,sha256=kUVopCN4xkEk-IR1aKpr7bfBSQEtG6pEj_hlWn
|
|
|
13
13
|
manta_node/cli/commands/config.py,sha256=BiarCD0S8rcNYbio4RLzDvUS7A50s5dd5F4TiZqLR6M,16577
|
|
14
14
|
manta_node/cli/commands/logs.py,sha256=cXOSdwhDIJAiKMmJYdzrnpapIxudxVdMzYT-KAWDKVk,5259
|
|
15
15
|
manta_node/cli/commands/network.py,sha256=QqncD6vbNlg65ptQdFYexEUMALQm8UwcftbW3sfQrjw,42070
|
|
16
|
-
manta_node/cli/commands/start.py,sha256=
|
|
16
|
+
manta_node/cli/commands/start.py,sha256=5l6AG3nBvJqu3TrqtBSBAHVR71o1YWAlUHWiYOL2Bos,24547
|
|
17
17
|
manta_node/cli/commands/status.py,sha256=FhlJuFxIRzxv9y8jUJRuWaCLfDBsGBqv6DCHUFQta3A,6401
|
|
18
18
|
manta_node/cli/commands/stop.py,sha256=8on7NqqaBeHRcbrZ5pGJ3Ms_6E_HNcF22mZ908JVu4A,7695
|
|
19
19
|
manta_node/domain/__init__.py,sha256=uyJXDf0QgfGCsXLMggqKCB5QV9oneYJ4iM-REaJGXDM,217
|
|
@@ -50,9 +50,9 @@ manta_node/infrastructure/process/executor.py,sha256=Ab1XvNuelEGCD5KdZLgYYnpjYZ5
|
|
|
50
50
|
manta_node/infrastructure/security/__init__.py,sha256=lI6vkbUmfmt0m363iO4HzuzVNoQAc7Clp2R5vAhZbgE,64
|
|
51
51
|
manta_node/infrastructure/security/auth_agent.py,sha256=WkPTg_g0gix7xomb_on_Ft3TNX0FpeqS7gwgJW9mTvk,11037
|
|
52
52
|
manta_node/infrastructure/security/token_provider.py,sha256=u3bcbQYNBskFzunO-wOSZpGkDN_CU1BCB5HUbZTC4Vg,1832
|
|
53
|
-
manta_node-0.6b0.
|
|
54
|
-
manta_node-0.6b0.
|
|
55
|
-
manta_node-0.6b0.
|
|
56
|
-
manta_node-0.6b0.
|
|
57
|
-
manta_node-0.6b0.
|
|
58
|
-
manta_node-0.6b0.
|
|
53
|
+
manta_node-0.6b0.dev587.dist-info/licenses/LICENSE,sha256=9mBgLhiB9goQPQjg9XQJ6FjgVxYw9Q8lyOZYkPGwF_c,34484
|
|
54
|
+
manta_node-0.6b0.dev587.dist-info/METADATA,sha256=UmduRXnFC2bzwzzQa06NsSBDwAo6gdrilYwV2WnEcHE,4213
|
|
55
|
+
manta_node-0.6b0.dev587.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
56
|
+
manta_node-0.6b0.dev587.dist-info/entry_points.txt,sha256=C_zcw6mdmztNxVUZGLZ83UH5TwcSuqb2C-rB4e2CQoc,56
|
|
57
|
+
manta_node-0.6b0.dev587.dist-info/top_level.txt,sha256=nbT5J5WETuXM9UPoQckl29uUOq8wMYdRb9QDx5kAFeo,11
|
|
58
|
+
manta_node-0.6b0.dev587.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|