ominfra 0.0.0.dev91__py3-none-any.whl → 0.0.0.dev92__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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
|