ominfra 0.0.0.dev91__py3-none-any.whl → 0.0.0.dev92__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.
- ominfra/clouds/aws/journald2aws/main.py +1 -1
- ominfra/scripts/journald2aws.py +1 -1
- ominfra/scripts/supervisor.py +484 -112
- ominfra/supervisor/compat.py +6 -2
- ominfra/supervisor/configs.py +54 -54
- ominfra/supervisor/context.py +2 -0
- ominfra/supervisor/datatypes.py +4 -0
- ominfra/supervisor/dispatchers.py +28 -16
- ominfra/supervisor/events.py +6 -7
- ominfra/supervisor/exceptions.py +7 -5
- ominfra/supervisor/process.py +14 -6
- ominfra/supervisor/supervisor.py +15 -29
- {ominfra-0.0.0.dev91.dist-info → ominfra-0.0.0.dev92.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev91.dist-info → ominfra-0.0.0.dev92.dist-info}/RECORD +18 -18
- {ominfra-0.0.0.dev91.dist-info → ominfra-0.0.0.dev92.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev91.dist-info → ominfra-0.0.0.dev92.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev91.dist-info → ominfra-0.0.0.dev92.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev91.dist-info → ominfra-0.0.0.dev92.dist-info}/top_level.txt +0 -0
ominfra/supervisor/compat.py
CHANGED
@@ -32,9 +32,10 @@ def compact_traceback() -> ta.Tuple[
|
|
32
32
|
types.TracebackType,
|
33
33
|
]:
|
34
34
|
t, v, tb = sys.exc_info()
|
35
|
-
tbinfo = []
|
36
35
|
if not tb:
|
37
36
|
raise RuntimeError('No traceback')
|
37
|
+
|
38
|
+
tbinfo = []
|
38
39
|
while tb:
|
39
40
|
tbinfo.append((
|
40
41
|
tb.tb_frame.f_code.co_filename,
|
@@ -72,6 +73,7 @@ def decode_wait_status(sts: int) -> ta.Tuple[int, str]:
|
|
72
73
|
Return a tuple (exitstatus, message) where exitstatus is the exit status, or -1 if the process was killed by a
|
73
74
|
signal; and message is a message telling what happened. It is the caller's responsibility to display the message.
|
74
75
|
"""
|
76
|
+
|
75
77
|
if os.WIFEXITED(sts):
|
76
78
|
es = os.WEXITSTATUS(sts) & 0xffff
|
77
79
|
msg = f'exit status {es}'
|
@@ -171,6 +173,7 @@ def real_exit(code: int) -> None:
|
|
171
173
|
|
172
174
|
def get_path() -> ta.Sequence[str]:
|
173
175
|
"""Return a list corresponding to $PATH, or a default."""
|
176
|
+
|
174
177
|
path = ['/bin', '/usr/bin', '/usr/local/bin']
|
175
178
|
if 'PATH' in os.environ:
|
176
179
|
p = os.environ['PATH']
|
@@ -187,8 +190,9 @@ ANSI_ESCAPE_BEGIN = b'\x1b['
|
|
187
190
|
ANSI_TERMINATORS = (b'H', b'f', b'A', b'B', b'C', b'D', b'R', b's', b'u', b'J', b'K', b'h', b'l', b'p', b'm')
|
188
191
|
|
189
192
|
|
190
|
-
def strip_escapes(s):
|
193
|
+
def strip_escapes(s: bytes) -> bytes:
|
191
194
|
"""Remove all ANSI color escapes from the given string."""
|
195
|
+
|
192
196
|
result = b''
|
193
197
|
show = 1
|
194
198
|
i = 0
|
ominfra/supervisor/configs.py
CHANGED
@@ -12,6 +12,59 @@ from .datatypes import logging_level
|
|
12
12
|
from .datatypes import octal_type
|
13
13
|
|
14
14
|
|
15
|
+
@dc.dataclass(frozen=True)
|
16
|
+
class ProcessConfig:
|
17
|
+
name: str
|
18
|
+
command: str
|
19
|
+
|
20
|
+
uid: ta.Optional[int] = None
|
21
|
+
directory: ta.Optional[str] = None
|
22
|
+
umask: ta.Optional[int] = None
|
23
|
+
priority: int = 999
|
24
|
+
|
25
|
+
autostart: bool = True
|
26
|
+
autorestart: str = 'unexpected'
|
27
|
+
|
28
|
+
startsecs: int = 1
|
29
|
+
startretries: int = 3
|
30
|
+
|
31
|
+
numprocs: int = 1
|
32
|
+
numprocs_start: int = 0
|
33
|
+
|
34
|
+
@dc.dataclass(frozen=True)
|
35
|
+
class Log:
|
36
|
+
file: ta.Optional[str] = None
|
37
|
+
capture_maxbytes: ta.Optional[int] = None
|
38
|
+
events_enabled: bool = False
|
39
|
+
syslog: bool = False
|
40
|
+
backups: ta.Optional[int] = None
|
41
|
+
maxbytes: ta.Optional[int] = None
|
42
|
+
|
43
|
+
stdout: Log = Log()
|
44
|
+
stderr: Log = Log()
|
45
|
+
|
46
|
+
stopsignal: int = signal.SIGTERM
|
47
|
+
stopwaitsecs: int = 10
|
48
|
+
stopasgroup: bool = False
|
49
|
+
|
50
|
+
killasgroup: bool = False
|
51
|
+
|
52
|
+
exitcodes: ta.Sequence[int] = (0,)
|
53
|
+
|
54
|
+
redirect_stderr: bool = False
|
55
|
+
|
56
|
+
environment: ta.Optional[ta.Mapping[str, str]] = None
|
57
|
+
|
58
|
+
|
59
|
+
@dc.dataclass(frozen=True)
|
60
|
+
class ProcessGroupConfig:
|
61
|
+
name: str
|
62
|
+
|
63
|
+
priority: int = 999
|
64
|
+
|
65
|
+
processes: ta.Optional[ta.Sequence[ProcessConfig]] = None
|
66
|
+
|
67
|
+
|
15
68
|
@dc.dataclass(frozen=True)
|
16
69
|
class ServerConfig:
|
17
70
|
user: ta.Optional[str] = None
|
@@ -31,7 +84,7 @@ class ServerConfig:
|
|
31
84
|
strip_ansi: bool = False
|
32
85
|
silent: bool = False
|
33
86
|
|
34
|
-
groups: ta.Optional[ta.Sequence[
|
87
|
+
groups: ta.Optional[ta.Sequence[ProcessGroupConfig]] = None
|
35
88
|
|
36
89
|
@classmethod
|
37
90
|
def new(
|
@@ -55,56 +108,3 @@ class ServerConfig:
|
|
55
108
|
child_logdir=child_logdir if child_logdir else tempfile.gettempdir(),
|
56
109
|
**kwargs,
|
57
110
|
)
|
58
|
-
|
59
|
-
|
60
|
-
@dc.dataclass(frozen=True)
|
61
|
-
class ProcessGroupConfig:
|
62
|
-
name: str
|
63
|
-
|
64
|
-
priority: int = 999
|
65
|
-
|
66
|
-
processes: ta.Optional[ta.Sequence['ProcessConfig']] = None
|
67
|
-
|
68
|
-
|
69
|
-
@dc.dataclass(frozen=True)
|
70
|
-
class ProcessConfig:
|
71
|
-
name: str
|
72
|
-
command: str
|
73
|
-
|
74
|
-
uid: ta.Optional[int] = None
|
75
|
-
directory: ta.Optional[str] = None
|
76
|
-
umask: ta.Optional[int] = None
|
77
|
-
priority: int = 999
|
78
|
-
|
79
|
-
autostart: bool = True
|
80
|
-
autorestart: str = 'unexpected'
|
81
|
-
|
82
|
-
startsecs: int = 1
|
83
|
-
startretries: int = 3
|
84
|
-
|
85
|
-
numprocs: int = 1
|
86
|
-
numprocs_start: int = 0
|
87
|
-
|
88
|
-
@dc.dataclass(frozen=True)
|
89
|
-
class Log:
|
90
|
-
file: ta.Optional[str] = None
|
91
|
-
capture_maxbytes: ta.Optional[int] = None
|
92
|
-
events_enabled: bool = False
|
93
|
-
syslog: bool = False
|
94
|
-
backups: ta.Optional[int] = None
|
95
|
-
maxbytes: ta.Optional[int] = None
|
96
|
-
|
97
|
-
stdout: Log = Log()
|
98
|
-
stderr: Log = Log()
|
99
|
-
|
100
|
-
stopsignal: int = signal.SIGTERM
|
101
|
-
stopwaitsecs: int = 10
|
102
|
-
stopasgroup: bool = False
|
103
|
-
|
104
|
-
killasgroup: bool = False
|
105
|
-
|
106
|
-
exitcodes: ta.Iterable[int] = (0,)
|
107
|
-
|
108
|
-
redirect_stderr: bool = False
|
109
|
-
|
110
|
-
environment: ta.Optional[ta.Mapping[str, str]] = None
|
ominfra/supervisor/context.py
CHANGED
@@ -114,6 +114,7 @@ class ServerContext(AbstractServerContext):
|
|
114
114
|
Set the uid of the supervisord process. Called during supervisord startup only. No return value. Exits the
|
115
115
|
process via usage() if privileges could not be dropped.
|
116
116
|
"""
|
117
|
+
|
117
118
|
if self.uid is None:
|
118
119
|
if os.getuid() == 0:
|
119
120
|
warnings.warn(
|
@@ -293,6 +294,7 @@ def drop_privileges(user: ta.Union[int, str, None]) -> ta.Optional[str]:
|
|
293
294
|
and when spawning subprocesses. Returns None on success or a string error message if privileges could not be
|
294
295
|
dropped.
|
295
296
|
"""
|
297
|
+
|
296
298
|
if user is None:
|
297
299
|
return 'No user specified to setuid to!'
|
298
300
|
|
ominfra/supervisor/datatypes.py
CHANGED
@@ -151,15 +151,19 @@ SIGNUMS = [getattr(signal, k) for k in dir(signal) if k.startswith('SIG')]
|
|
151
151
|
def signal_number(value: ta.Union[int, str]) -> int:
|
152
152
|
try:
|
153
153
|
num = int(value)
|
154
|
+
|
154
155
|
except (ValueError, TypeError):
|
155
156
|
name = value.strip().upper() # type: ignore
|
156
157
|
if not name.startswith('SIG'):
|
157
158
|
name = f'SIG{name}'
|
159
|
+
|
158
160
|
num = getattr(signal, name, None) # type: ignore
|
159
161
|
if num is None:
|
160
162
|
raise ValueError(f'value {value!r} is not a valid signal name') # noqa
|
163
|
+
|
161
164
|
if num not in SIGNUMS:
|
162
165
|
raise ValueError(f'value {value!r} is not a valid signal number')
|
166
|
+
|
163
167
|
return num
|
164
168
|
|
165
169
|
|
@@ -93,7 +93,9 @@ class OutputDispatcher(Dispatcher):
|
|
93
93
|
|
94
94
|
`event_type` should be one of ProcessLogStdoutEvent or ProcessLogStderrEvent
|
95
95
|
"""
|
96
|
+
|
96
97
|
super().__init__(process, event_type.channel, fd)
|
98
|
+
|
97
99
|
self.event_type = event_type
|
98
100
|
|
99
101
|
self.lc: ProcessConfig.Log = getattr(process.config, self._channel)
|
@@ -107,25 +109,30 @@ class OutputDispatcher(Dispatcher):
|
|
107
109
|
self._output_buffer = b'' # data waiting to be logged
|
108
110
|
|
109
111
|
# all code below is purely for minor speedups
|
112
|
+
|
110
113
|
begin_token = self.event_type.BEGIN_TOKEN
|
111
114
|
end_token = self.event_type.END_TOKEN
|
112
|
-
self.
|
113
|
-
self.
|
114
|
-
|
115
|
+
self._begin_token_data = (begin_token, len(begin_token))
|
116
|
+
self._end_token_data = (end_token, len(end_token))
|
117
|
+
|
118
|
+
self._main_log_level = logging.DEBUG
|
119
|
+
|
120
|
+
self._log_to_main_log = process.context.config.loglevel <= self._main_log_level
|
121
|
+
|
115
122
|
config = self._process.config
|
116
|
-
self.
|
117
|
-
self.
|
118
|
-
self.stderr_events_enabled = config.stderr.events_enabled
|
123
|
+
self._stdout_events_enabled = config.stdout.events_enabled
|
124
|
+
self._stderr_events_enabled = config.stderr.events_enabled
|
119
125
|
|
120
|
-
_child_log: ta.Optional[logging.Logger] # the current logger (normal_log or capture_log)
|
121
|
-
_normal_log: ta.Optional[logging.Logger] # the "normal" (non-capture) logger
|
122
|
-
_capture_log: ta.Optional[logging.Logger] # the logger used while we're in capture_mode
|
126
|
+
_child_log: ta.Optional[logging.Logger] = None # the current logger (normal_log or capture_log)
|
127
|
+
_normal_log: ta.Optional[logging.Logger] = None # the "normal" (non-capture) logger
|
128
|
+
_capture_log: ta.Optional[logging.Logger] = None # the logger used while we're in capture_mode
|
123
129
|
|
124
130
|
def _init_normal_log(self) -> None:
|
125
131
|
"""
|
126
132
|
Configure the "normal" (non-capture) log for this channel of this process. Sets self.normal_log if logging is
|
127
133
|
enabled.
|
128
134
|
"""
|
135
|
+
|
129
136
|
config = self._process.config # noqa
|
130
137
|
channel = self._channel # noqa
|
131
138
|
|
@@ -146,7 +153,7 @@ class OutputDispatcher(Dispatcher):
|
|
146
153
|
# maxbytes=maxbytes,
|
147
154
|
# backups=backups,
|
148
155
|
# )
|
149
|
-
|
156
|
+
|
150
157
|
# if to_syslog:
|
151
158
|
# loggers.handle_syslog(
|
152
159
|
# self.normal_log,
|
@@ -158,6 +165,7 @@ class OutputDispatcher(Dispatcher):
|
|
158
165
|
Configure the capture log for this process. This log is used to temporarily capture output when special output
|
159
166
|
is detected. Sets self.capture_log if capturing is enabled.
|
160
167
|
"""
|
168
|
+
|
161
169
|
capture_maxbytes = self.lc.capture_maxbytes
|
162
170
|
if capture_maxbytes:
|
163
171
|
self._capture_log = logging.getLogger(__name__)
|
@@ -184,9 +192,11 @@ class OutputDispatcher(Dispatcher):
|
|
184
192
|
if data:
|
185
193
|
if self._process.context.config.strip_ansi:
|
186
194
|
data = strip_escapes(data)
|
195
|
+
|
187
196
|
if self._child_log:
|
188
197
|
self._child_log.info(data)
|
189
|
-
|
198
|
+
|
199
|
+
if self._log_to_main_log:
|
190
200
|
if not isinstance(data, bytes):
|
191
201
|
text = data
|
192
202
|
else:
|
@@ -194,11 +204,13 @@ class OutputDispatcher(Dispatcher):
|
|
194
204
|
text = data.decode('utf-8')
|
195
205
|
except UnicodeDecodeError:
|
196
206
|
text = f'Undecodable: {data!r}'
|
197
|
-
log.log(self.
|
207
|
+
log.log(self._main_log_level, '%r %s output:\n%s', self._process.config.name, self._channel, text) # noqa
|
208
|
+
|
198
209
|
if self._channel == 'stdout':
|
199
|
-
if self.
|
210
|
+
if self._stdout_events_enabled:
|
200
211
|
notify_event(ProcessLogStdoutEvent(self._process, self._process.pid, data))
|
201
|
-
|
212
|
+
|
213
|
+
elif self._stderr_events_enabled:
|
202
214
|
notify_event(ProcessLogStderrEvent(self._process, self._process.pid, data))
|
203
215
|
|
204
216
|
def record_output(self):
|
@@ -210,9 +222,9 @@ class OutputDispatcher(Dispatcher):
|
|
210
222
|
return
|
211
223
|
|
212
224
|
if self._capture_mode:
|
213
|
-
token, tokenlen = self.
|
225
|
+
token, tokenlen = self._end_token_data
|
214
226
|
else:
|
215
|
-
token, tokenlen = self.
|
227
|
+
token, tokenlen = self._begin_token_data
|
216
228
|
|
217
229
|
if len(self._output_buffer) <= tokenlen:
|
218
230
|
return # not enough data
|
ominfra/supervisor/events.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
+
import abc
|
2
3
|
import typing as ta
|
3
4
|
|
4
5
|
from .compat import as_string
|
@@ -32,12 +33,11 @@ notify_event = EVENT_CALLBACKS.notify
|
|
32
33
|
clear_events = EVENT_CALLBACKS.clear
|
33
34
|
|
34
35
|
|
35
|
-
class Event:
|
36
|
+
class Event(abc.ABC): # noqa
|
36
37
|
"""Abstract event type """
|
37
38
|
|
38
39
|
|
39
|
-
class ProcessLogEvent(Event):
|
40
|
-
"""Abstract"""
|
40
|
+
class ProcessLogEvent(Event, abc.ABC):
|
41
41
|
channel: ta.Optional[str] = None
|
42
42
|
|
43
43
|
def __init__(self, process, pid, data):
|
@@ -54,8 +54,8 @@ class ProcessLogEvent(Event):
|
|
54
54
|
data = as_string(self.data)
|
55
55
|
except UnicodeDecodeError:
|
56
56
|
data = f'Undecodable: {self.data!r}'
|
57
|
-
|
58
|
-
result =
|
57
|
+
|
58
|
+
result = 'processname:%s groupname:%s pid:%s channel:%s\n%s' % ( # noqa
|
59
59
|
as_string(self.process.config.name),
|
60
60
|
as_string(groupname),
|
61
61
|
self.pid,
|
@@ -73,8 +73,7 @@ class ProcessLogStderrEvent(ProcessLogEvent):
|
|
73
73
|
channel = 'stderr'
|
74
74
|
|
75
75
|
|
76
|
-
class ProcessCommunicationEvent(Event):
|
77
|
-
""" Abstract """
|
76
|
+
class ProcessCommunicationEvent(Event, abc.ABC):
|
78
77
|
# event mode tokens
|
79
78
|
BEGIN_TOKEN = b'<!--XSUPERVISOR:BEGIN-->'
|
80
79
|
END_TOKEN = b'<!--XSUPERVISOR:END-->'
|
ominfra/supervisor/exceptions.py
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
class ProcessError(Exception):
|
2
|
-
"""
|
2
|
+
"""Specialized exceptions used when attempting to start a process."""
|
3
3
|
|
4
4
|
|
5
5
|
class BadCommandError(ProcessError):
|
6
|
-
"""
|
6
|
+
"""Indicates the command could not be parsed properly."""
|
7
7
|
|
8
8
|
|
9
9
|
class NotExecutableError(ProcessError):
|
10
|
-
"""
|
11
|
-
resolves to a file which is not executable, or which
|
10
|
+
"""
|
11
|
+
Indicates that the filespec cannot be executed because its path resolves to a file which is not executable, or which
|
12
|
+
is a directory.
|
13
|
+
"""
|
12
14
|
|
13
15
|
|
14
16
|
class NotFoundError(ProcessError):
|
15
|
-
"""
|
17
|
+
"""Indicates that the filespec cannot be executed because it could not be found."""
|
16
18
|
|
17
19
|
|
18
20
|
class NoPermissionError(ProcessError):
|
ominfra/supervisor/process.py
CHANGED
@@ -143,6 +143,7 @@ class Subprocess(AbstractSubprocess):
|
|
143
143
|
Internal: turn a program name into a file name, using $PATH, make sure it exists / is executable, raising a
|
144
144
|
ProcessError if not
|
145
145
|
"""
|
146
|
+
|
146
147
|
try:
|
147
148
|
commandargs = shlex.split(self.config.command)
|
148
149
|
except ValueError as e:
|
@@ -526,8 +527,12 @@ class Subprocess(AbstractSubprocess):
|
|
526
527
|
os.kill(self.pid, sig)
|
527
528
|
except OSError as exc:
|
528
529
|
if exc.errno == errno.ESRCH:
|
529
|
-
log.debug(
|
530
|
-
|
530
|
+
log.debug(
|
531
|
+
'unable to signal %s (pid %s), it probably just now exited on its own: %s',
|
532
|
+
processname,
|
533
|
+
self.pid,
|
534
|
+
str(exc),
|
535
|
+
)
|
531
536
|
# we could change the state here but we intentionally do not. we will do it during normal SIGCHLD
|
532
537
|
# processing.
|
533
538
|
return None
|
@@ -543,6 +548,7 @@ class Subprocess(AbstractSubprocess):
|
|
543
548
|
|
544
549
|
def finish(self, sts: int) -> None:
|
545
550
|
""" The process was reaped and we need to report and manage its state """
|
551
|
+
|
546
552
|
self.drain()
|
547
553
|
|
548
554
|
es, msg = decode_wait_status(sts)
|
@@ -559,9 +565,11 @@ class Subprocess(AbstractSubprocess):
|
|
559
565
|
else:
|
560
566
|
too_quickly = False
|
561
567
|
log.warning(
|
562
|
-
"process '%s' (%s) laststart time is in the future, don't "
|
563
|
-
"
|
564
|
-
|
568
|
+
"process '%s' (%s) laststart time is in the future, don't know how long process was running so "
|
569
|
+
"assuming it did not exit too quickly",
|
570
|
+
processname,
|
571
|
+
self.pid,
|
572
|
+
)
|
565
573
|
|
566
574
|
exit_expected = es in self.config.exitcodes
|
567
575
|
|
@@ -658,7 +666,7 @@ class Subprocess(AbstractSubprocess):
|
|
658
666
|
if self.config.autorestart is RestartUnconditionally:
|
659
667
|
# EXITED -> STARTING
|
660
668
|
self.spawn()
|
661
|
-
elif self.exitstatus not in self.config.exitcodes:
|
669
|
+
elif self.exitstatus not in self.config.exitcodes:
|
662
670
|
# EXITED -> STARTING
|
663
671
|
self.spawn()
|
664
672
|
|
ominfra/supervisor/supervisor.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
# ruff: noqa: UP006 UP007
|
3
3
|
# @omlish-amalg ../scripts/supervisor.py
|
4
|
+
import json
|
4
5
|
import logging
|
5
6
|
import signal
|
6
7
|
import time
|
@@ -8,12 +9,12 @@ import typing as ta
|
|
8
9
|
|
9
10
|
from omlish.lite.check import check_not_none
|
10
11
|
from omlish.lite.logs import configure_standard_logging
|
12
|
+
from omlish.lite.marshal import unmarshal_obj
|
11
13
|
|
12
14
|
from .compat import ExitNow
|
13
15
|
from .compat import as_string
|
14
16
|
from .compat import decode_wait_status
|
15
17
|
from .compat import signame
|
16
|
-
from .configs import ProcessConfig
|
17
18
|
from .configs import ProcessGroupConfig
|
18
19
|
from .configs import ServerConfig
|
19
20
|
from .context import ServerContext
|
@@ -331,39 +332,24 @@ def timeslice(period, when):
|
|
331
332
|
|
332
333
|
|
333
334
|
def main(args=None, test=False):
|
335
|
+
import argparse
|
336
|
+
|
337
|
+
parser = argparse.ArgumentParser()
|
338
|
+
parser.add_argument('config_file', metavar='config-file')
|
339
|
+
args = parser.parse_args()
|
340
|
+
|
334
341
|
configure_standard_logging('INFO')
|
335
342
|
|
343
|
+
if not (cf := args.config_file):
|
344
|
+
raise RuntimeError('No config file specified')
|
345
|
+
|
336
346
|
# if we hup, restart by making a new Supervisor()
|
337
347
|
first = True
|
338
348
|
while True:
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
name='default',
|
344
|
-
processes=[
|
345
|
-
ProcessConfig(
|
346
|
-
name='sleep',
|
347
|
-
command='sleep 600',
|
348
|
-
stdout=ProcessConfig.Log(
|
349
|
-
file='/dev/fd/1',
|
350
|
-
maxbytes=0,
|
351
|
-
),
|
352
|
-
redirect_stderr=True,
|
353
|
-
),
|
354
|
-
ProcessConfig(
|
355
|
-
name='ls',
|
356
|
-
command='ls -al',
|
357
|
-
stdout=ProcessConfig.Log(
|
358
|
-
file='/dev/fd/1',
|
359
|
-
maxbytes=0,
|
360
|
-
),
|
361
|
-
redirect_stderr=True,
|
362
|
-
),
|
363
|
-
],
|
364
|
-
),
|
365
|
-
],
|
366
|
-
)
|
349
|
+
with open(cf) as f:
|
350
|
+
config_src = f.read()
|
351
|
+
config_dct = json.loads(config_src)
|
352
|
+
config: ServerConfig = unmarshal_obj(config_dct, ServerConfig)
|
367
353
|
|
368
354
|
context = ServerContext(
|
369
355
|
config,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ominfra
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev92
|
4
4
|
Summary: ominfra
|
5
5
|
Author: wrmsr
|
6
6
|
License: BSD-3-Clause
|
@@ -12,8 +12,8 @@ Classifier: Operating System :: OS Independent
|
|
12
12
|
Classifier: Operating System :: POSIX
|
13
13
|
Requires-Python: >=3.12
|
14
14
|
License-File: LICENSE
|
15
|
-
Requires-Dist: omdev ==0.0.0.
|
16
|
-
Requires-Dist: omlish ==0.0.0.
|
15
|
+
Requires-Dist: omdev ==0.0.0.dev92
|
16
|
+
Requires-Dist: omlish ==0.0.0.dev92
|
17
17
|
Provides-Extra: all
|
18
18
|
Requires-Dist: paramiko ~=3.5 ; extra == 'all'
|
19
19
|
Requires-Dist: asyncssh ~=2.18 ; extra == 'all'
|
@@ -13,7 +13,7 @@ ominfra/clouds/aws/dataclasses.py,sha256=rKhtJKJ0JhMssU9n9CABX_JaUiokIboEATJ9TZg
|
|
13
13
|
ominfra/clouds/aws/logs.py,sha256=7Cl9vjco6G-5wW06TmuzU9GZ-diFP8V26X2UZnfJD3U,5232
|
14
14
|
ominfra/clouds/aws/metadata.py,sha256=XR1BuMdQheyeFjjA3MN8GCNWVAp5ahoPdbWXEmViutQ,2767
|
15
15
|
ominfra/clouds/aws/journald2aws/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
16
|
-
ominfra/clouds/aws/journald2aws/main.py,sha256=
|
16
|
+
ominfra/clouds/aws/journald2aws/main.py,sha256=d7jSbcaxjGgpVpDCPl1kJCOZg3S7g2n0Lf7gI0ZL3j0,9126
|
17
17
|
ominfra/deploy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
18
|
ominfra/deploy/_executor.py,sha256=zHn4zAz6Ch1i5R_EdKTfJv_4SE0QPNuQEk7O1ptB_7A,32834
|
19
19
|
ominfra/deploy/configs.py,sha256=qi0kwT7G2NH7dXLOQic-u6R3yeadup_QtvrjwWIggbM,435
|
@@ -52,29 +52,29 @@ ominfra/pyremote/_runcommands.py,sha256=2UVHaUJjmWP8jMZE79j2Qk1E5IOyVV1qNSUbdr-z
|
|
52
52
|
ominfra/pyremote/bootstrap.py,sha256=RvMO3YGaN1E4sgUi1JEtiPak8cjvqtc_vRCq1yqbeZg,3370
|
53
53
|
ominfra/pyremote/runcommands.py,sha256=bviS0_TDIoZVAe4h-_iavbvJtVSFu8lnk7fQ5iasCWE,1571
|
54
54
|
ominfra/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
|
-
ominfra/scripts/journald2aws.py,sha256=
|
56
|
-
ominfra/scripts/supervisor.py,sha256=
|
55
|
+
ominfra/scripts/journald2aws.py,sha256=AgOHKPujUo4SqTFoz_EiN-oJ-HwZJB-UNyCFJypsNus,91403
|
56
|
+
ominfra/scripts/supervisor.py,sha256=iWTZQIrzqNjlmuDH489AlfXGb0i_0sfoYIYP7h1LH-E,115374
|
57
57
|
ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
58
58
|
ominfra/supervisor/__main__.py,sha256=usW9jjq5JPe_2SL8H5PrjDdksO75MX85Ir0HFfb35eM,72
|
59
|
-
ominfra/supervisor/compat.py,sha256=
|
60
|
-
ominfra/supervisor/configs.py,sha256=
|
61
|
-
ominfra/supervisor/context.py,sha256=
|
62
|
-
ominfra/supervisor/datatypes.py,sha256=
|
63
|
-
ominfra/supervisor/dispatchers.py,sha256=
|
64
|
-
ominfra/supervisor/events.py,sha256=
|
65
|
-
ominfra/supervisor/exceptions.py,sha256=
|
59
|
+
ominfra/supervisor/compat.py,sha256=Y1d_pk4eN18AbVYjDHAXMMnPwOKTFpc7JDb1uClYMsQ,5064
|
60
|
+
ominfra/supervisor/configs.py,sha256=KpibZJ-V-4UpoJM2fnjXOXJLvDbwRJzNLXLGESUljV4,2966
|
61
|
+
ominfra/supervisor/context.py,sha256=D2TCMX_P6M98_3JR2sgO97bsXEpP8EK_LTmYWgsUXqY,15337
|
62
|
+
ominfra/supervisor/datatypes.py,sha256=UnXO_UlCyJD9u0uvea1wvnk_UZCzxNMeFvPK83gv530,4432
|
63
|
+
ominfra/supervisor/dispatchers.py,sha256=FEZeHmrIyM6WWojJsp0wQcGacgAUpMrtHNfWVoC6vhs,10404
|
64
|
+
ominfra/supervisor/events.py,sha256=OGGCuf1RWobFPDecksHJO3I4GmzBPgFvPce4-DOaZ3s,7729
|
65
|
+
ominfra/supervisor/exceptions.py,sha256=Qbu211H3CLlSmi9LsSikOwrcL5HgJP9ugvcKWlGTAoI,750
|
66
66
|
ominfra/supervisor/poller.py,sha256=RwVnjEl63-mNQUsJcVEEsFrwuh5aOKr9e-rrB2lWCgs,7726
|
67
|
-
ominfra/supervisor/process.py,sha256=
|
67
|
+
ominfra/supervisor/process.py,sha256=RlwlHjHy8CPPMqTn1ljk2uHX628SCGwVEDfvnN22KgA,31390
|
68
68
|
ominfra/supervisor/states.py,sha256=JMxXYTZhJkMNQZ2tTV6wId7wrvnWgiZteskACprKskM,1374
|
69
|
-
ominfra/supervisor/supervisor.py,sha256=
|
69
|
+
ominfra/supervisor/supervisor.py,sha256=eXmVKX-A3exX8yHmmJEhHVd-3VnjTtrfDCvV7EEb7o8,13238
|
70
70
|
ominfra/supervisor/types.py,sha256=ec62QG0CDJc0XNxCnf3lXxhsxrr4CCScLPI-1SpQjlc,1141
|
71
71
|
ominfra/tailscale/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
72
72
|
ominfra/tailscale/cli.py,sha256=Ltg6RVFsMLLPjLzoGwM6sxjmwjEVEYHAdrqmCc4N1HM,3174
|
73
73
|
ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
74
74
|
ominfra/tools/listresources.py,sha256=L4t5rszm9ulcdWyr7n48_R9d5Etg4S2a4WQhlbHDtnQ,6106
|
75
|
-
ominfra-0.0.0.
|
76
|
-
ominfra-0.0.0.
|
77
|
-
ominfra-0.0.0.
|
78
|
-
ominfra-0.0.0.
|
79
|
-
ominfra-0.0.0.
|
80
|
-
ominfra-0.0.0.
|
75
|
+
ominfra-0.0.0.dev92.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
76
|
+
ominfra-0.0.0.dev92.dist-info/METADATA,sha256=3EP4RSIaP8hFXGqSoduoMjsCVPwtA9nWUhGOxvKkpWU,739
|
77
|
+
ominfra-0.0.0.dev92.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
78
|
+
ominfra-0.0.0.dev92.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
|
79
|
+
ominfra-0.0.0.dev92.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
|
80
|
+
ominfra-0.0.0.dev92.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|