ominfra 0.0.0.dev129__py3-none-any.whl → 0.0.0.dev131__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/deploy/_executor.py +16 -1
- ominfra/deploy/poly/_main.py +2 -2
- ominfra/pyremote/_runcommands.py +16 -1
- ominfra/scripts/journald2aws.py +117 -5
- ominfra/scripts/supervisor.py +1450 -703
- ominfra/supervisor/configs.py +17 -17
- ominfra/supervisor/dispatchers.py +7 -6
- ominfra/supervisor/dispatchersimpl.py +11 -15
- ominfra/supervisor/groups.py +16 -1
- ominfra/supervisor/http.py +130 -0
- ominfra/supervisor/inject.py +44 -5
- ominfra/supervisor/io.py +39 -24
- ominfra/supervisor/pipes.py +2 -2
- ominfra/supervisor/privileges.py +4 -6
- ominfra/supervisor/processimpl.py +33 -34
- ominfra/supervisor/setupimpl.py +16 -16
- ominfra/supervisor/spawningimpl.py +3 -3
- ominfra/supervisor/supervisor.py +6 -3
- ominfra/supervisor/types.py +6 -56
- ominfra/supervisor/utils/os.py +1 -1
- ominfra/supervisor/utils/strings.py +2 -2
- {ominfra-0.0.0.dev129.dist-info → ominfra-0.0.0.dev131.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev129.dist-info → ominfra-0.0.0.dev131.dist-info}/RECORD +27 -27
- ominfra/supervisor/poller.py +0 -240
- {ominfra-0.0.0.dev129.dist-info → ominfra-0.0.0.dev131.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev129.dist-info → ominfra-0.0.0.dev131.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev129.dist-info → ominfra-0.0.0.dev131.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev129.dist-info → ominfra-0.0.0.dev131.dist-info}/top_level.txt +0 -0
@@ -79,7 +79,7 @@ class ProcessImpl(Process):
|
|
79
79
|
|
80
80
|
self._killing = False # true if we are trying to kill this process
|
81
81
|
|
82
|
-
self._backoff = 0 # backoff counter (to
|
82
|
+
self._backoff = 0 # backoff counter (to start_retries)
|
83
83
|
|
84
84
|
self._exitstatus: ta.Optional[Rc] = None # status attached to dead process by finish()
|
85
85
|
self._spawn_err: ta.Optional[str] = None # error message attached by spawn() if any
|
@@ -156,7 +156,7 @@ class ProcessImpl(Process):
|
|
156
156
|
self._pipes = sp.pipes
|
157
157
|
self._dispatchers = sp.dispatchers
|
158
158
|
|
159
|
-
self._delay = time.time() + self.config.
|
159
|
+
self._delay = time.time() + self.config.start_secs
|
160
160
|
|
161
161
|
return sp.pid
|
162
162
|
|
@@ -214,17 +214,17 @@ class ProcessImpl(Process):
|
|
214
214
|
|
215
215
|
if self._state == ProcessState.STARTING:
|
216
216
|
self._last_start = min(test_time, self._last_start)
|
217
|
-
if self._delay > 0 and test_time < (self._delay - self._config.
|
218
|
-
self._delay = test_time + self._config.
|
217
|
+
if self._delay > 0 and test_time < (self._delay - self._config.start_secs):
|
218
|
+
self._delay = test_time + self._config.start_secs
|
219
219
|
|
220
220
|
elif self._state == ProcessState.RUNNING:
|
221
|
-
if test_time > self._last_start and test_time < (self._last_start + self._config.
|
222
|
-
self._last_start = test_time - self._config.
|
221
|
+
if test_time > self._last_start and test_time < (self._last_start + self._config.start_secs):
|
222
|
+
self._last_start = test_time - self._config.start_secs
|
223
223
|
|
224
224
|
elif self._state == ProcessState.STOPPING:
|
225
225
|
self._last_stop_report = min(test_time, self._last_stop_report)
|
226
|
-
if self._delay > 0 and test_time < (self._delay - self._config.
|
227
|
-
self._delay = test_time + self._config.
|
226
|
+
if self._delay > 0 and test_time < (self._delay - self._config.stop_wait_secs):
|
227
|
+
self._delay = test_time + self._config.stop_wait_secs
|
228
228
|
|
229
229
|
elif self._state == ProcessState.BACKOFF:
|
230
230
|
if self._delay > 0 and test_time < (self._delay - self._backoff):
|
@@ -233,7 +233,7 @@ class ProcessImpl(Process):
|
|
233
233
|
def stop(self) -> ta.Optional[str]:
|
234
234
|
self._administrative_stop = True
|
235
235
|
self._last_stop_report = 0
|
236
|
-
return self.kill(self._config.
|
236
|
+
return self.kill(self._config.stop_signal)
|
237
237
|
|
238
238
|
def stop_report(self) -> None:
|
239
239
|
"""Log a 'waiting for x to stop' message with throttling."""
|
@@ -256,7 +256,7 @@ class ProcessImpl(Process):
|
|
256
256
|
|
257
257
|
def kill(self, sig: int) -> ta.Optional[str]:
|
258
258
|
"""
|
259
|
-
Send a signal to the subprocess with the intention to kill it (to make it exit).
|
259
|
+
Send a signal to the subprocess with the intention to kill it (to make it exit). This may or may not actually
|
260
260
|
kill it.
|
261
261
|
|
262
262
|
Return None if the signal was sent, or an error message string if an error occurred or if the subprocess is not
|
@@ -264,8 +264,8 @@ class ProcessImpl(Process):
|
|
264
264
|
"""
|
265
265
|
now = time.time()
|
266
266
|
|
267
|
-
# If the process is in BACKOFF and we want to stop or kill it, then BACKOFF -> STOPPED.
|
268
|
-
# if
|
267
|
+
# If the process is in BACKOFF and we want to stop or kill it, then BACKOFF -> STOPPED. This is needed because
|
268
|
+
# if start_retries is a large number and the process isn't starting successfully, the stop request would be
|
269
269
|
# blocked for a long time waiting for the retries.
|
270
270
|
if self._state == ProcessState.BACKOFF:
|
271
271
|
log.debug('Attempted to kill %s, which is in BACKOFF state.', self.name)
|
@@ -280,25 +280,25 @@ class ProcessImpl(Process):
|
|
280
280
|
|
281
281
|
# If we're in the stopping state, then we've already sent the stop signal and this is the kill signal
|
282
282
|
if self._state == ProcessState.STOPPING:
|
283
|
-
|
283
|
+
kill_as_group = self._config.kill_as_group
|
284
284
|
else:
|
285
|
-
|
285
|
+
kill_as_group = self._config.stop_as_group
|
286
286
|
|
287
287
|
as_group = ''
|
288
|
-
if
|
288
|
+
if kill_as_group:
|
289
289
|
as_group = 'process group '
|
290
290
|
|
291
291
|
log.debug('killing %s (pid %s) %s with signal %s', self.name, self.pid, as_group, sig_name(sig))
|
292
292
|
|
293
293
|
# RUNNING/STARTING/STOPPING -> STOPPING
|
294
294
|
self._killing = True
|
295
|
-
self._delay = now + self._config.
|
296
|
-
# we will already be in the STOPPING state if we're doing a SIGKILL as a result of overrunning
|
295
|
+
self._delay = now + self._config.stop_wait_secs
|
296
|
+
# we will already be in the STOPPING state if we're doing a SIGKILL as a result of overrunning stop_wait_secs
|
297
297
|
self.check_in_state(ProcessState.RUNNING, ProcessState.STARTING, ProcessState.STOPPING)
|
298
298
|
self.change_state(ProcessState.STOPPING)
|
299
299
|
|
300
300
|
kpid = int(self.pid)
|
301
|
-
if
|
301
|
+
if kill_as_group:
|
302
302
|
# send to the whole process group instead
|
303
303
|
kpid = -kpid
|
304
304
|
|
@@ -308,7 +308,7 @@ class ProcessImpl(Process):
|
|
308
308
|
except OSError as exc:
|
309
309
|
if exc.errno == errno.ESRCH:
|
310
310
|
log.debug('unable to signal %s (pid %s), it probably just exited on its own: %s', self.name, self.pid, str(exc)) # noqa
|
311
|
-
# we could change the state here but we intentionally do not.
|
311
|
+
# we could change the state here but we intentionally do not. we will do it during normal SIGCHLD
|
312
312
|
# processing.
|
313
313
|
return None
|
314
314
|
raise
|
@@ -351,7 +351,7 @@ class ProcessImpl(Process):
|
|
351
351
|
self.pid,
|
352
352
|
str(exc),
|
353
353
|
)
|
354
|
-
# we could change the state here but we intentionally do not.
|
354
|
+
# we could change the state here but we intentionally do not. we will do it during normal SIGCHLD
|
355
355
|
# processing.
|
356
356
|
return None
|
357
357
|
raise
|
@@ -378,7 +378,8 @@ class ProcessImpl(Process):
|
|
378
378
|
self._last_stop = now
|
379
379
|
|
380
380
|
if now > self._last_start:
|
381
|
-
|
381
|
+
log.info(f'{now - self._last_start=}') # noqa
|
382
|
+
too_quickly = now - self._last_start < self._config.start_secs
|
382
383
|
else:
|
383
384
|
too_quickly = False
|
384
385
|
log.warning(
|
@@ -447,13 +448,11 @@ class ProcessImpl(Process):
|
|
447
448
|
|
448
449
|
self._check_and_adjust_for_system_clock_rollback(now)
|
449
450
|
|
450
|
-
logger = log
|
451
|
-
|
452
451
|
if self._supervisor_states.state > SupervisorState.RESTARTING:
|
453
452
|
# dont start any processes if supervisor is shutting down
|
454
453
|
if state == ProcessState.EXITED:
|
455
|
-
if self._config.
|
456
|
-
if self._config.
|
454
|
+
if self._config.auto_restart:
|
455
|
+
if self._config.auto_restart is RestartUnconditionally:
|
457
456
|
# EXITED -> STARTING
|
458
457
|
self.spawn()
|
459
458
|
elif self._exitstatus not in self._config.exitcodes:
|
@@ -461,38 +460,38 @@ class ProcessImpl(Process):
|
|
461
460
|
self.spawn()
|
462
461
|
|
463
462
|
elif state == ProcessState.STOPPED and not self._last_start:
|
464
|
-
if self._config.
|
463
|
+
if self._config.auto_start:
|
465
464
|
# STOPPED -> STARTING
|
466
465
|
self.spawn()
|
467
466
|
|
468
467
|
elif state == ProcessState.BACKOFF:
|
469
|
-
if self._backoff <= self._config.
|
468
|
+
if self._backoff <= self._config.start_retries:
|
470
469
|
if now > self._delay:
|
471
470
|
# BACKOFF -> STARTING
|
472
471
|
self.spawn()
|
473
472
|
|
474
473
|
if state == ProcessState.STARTING:
|
475
|
-
if now - self._last_start > self._config.
|
474
|
+
if now - self._last_start > self._config.start_secs:
|
476
475
|
# STARTING -> RUNNING if the proc has started successfully and it has stayed up for at least
|
477
|
-
# proc.config.
|
476
|
+
# proc.config.start_secs,
|
478
477
|
self._delay = 0
|
479
478
|
self._backoff = 0
|
480
479
|
self.check_in_state(ProcessState.STARTING)
|
481
480
|
self.change_state(ProcessState.RUNNING)
|
482
|
-
msg = ('entered RUNNING state, process has stayed up for > than %s seconds (
|
483
|
-
|
481
|
+
msg = ('entered RUNNING state, process has stayed up for > than %s seconds (start_secs)' % self._config.start_secs) # noqa
|
482
|
+
log.info('success: %s %s', self.name, msg)
|
484
483
|
|
485
484
|
if state == ProcessState.BACKOFF:
|
486
|
-
if self._backoff > self._config.
|
485
|
+
if self._backoff > self._config.start_retries:
|
487
486
|
# BACKOFF -> FATAL if the proc has exceeded its number of retries
|
488
487
|
self.give_up()
|
489
488
|
msg = ('entered FATAL state, too many start retries too quickly')
|
490
|
-
|
489
|
+
log.info('gave up: %s %s', self.name, msg)
|
491
490
|
|
492
491
|
elif state == ProcessState.STOPPING:
|
493
492
|
time_left = self._delay - now
|
494
493
|
if time_left <= 0:
|
495
|
-
# kill processes which are taking too long to stop with a final sigkill.
|
494
|
+
# kill processes which are taking too long to stop with a final sigkill. if this doesn't kill it, the
|
496
495
|
# process will be stuck in the STOPPING state forever.
|
497
496
|
log.warning('killing \'%s\' (%s) with SIGKILL', self.name, self.pid)
|
498
497
|
self.kill(signal.SIGKILL)
|
ominfra/supervisor/setupimpl.py
CHANGED
@@ -77,21 +77,21 @@ class SupervisorSetupImpl(SupervisorSetup):
|
|
77
77
|
def _cleanup_fds(self) -> None:
|
78
78
|
# try to close any leaked file descriptors (for reload)
|
79
79
|
start = 5
|
80
|
-
os.closerange(start, self._config.
|
80
|
+
os.closerange(start, self._config.min_fds)
|
81
81
|
|
82
82
|
#
|
83
83
|
|
84
84
|
def _set_uid_or_exit(self) -> None:
|
85
85
|
"""
|
86
|
-
Set the uid of the supervisord process.
|
86
|
+
Set the uid of the supervisord process. Called during supervisord startup only. No return value. Exits the
|
87
87
|
process via usage() if privileges could not be dropped.
|
88
88
|
"""
|
89
89
|
|
90
90
|
if self._user is None:
|
91
91
|
if os.getuid() == 0:
|
92
92
|
warnings.warn(
|
93
|
-
'Supervisor is running as root.
|
94
|
-
'config file.
|
93
|
+
'Supervisor is running as root. Privileges were not dropped because no user is specified in the '
|
94
|
+
'config file. If you intend to run as root, you can set user=root in the config file to avoid '
|
95
95
|
'this message.',
|
96
96
|
)
|
97
97
|
else:
|
@@ -105,8 +105,8 @@ class SupervisorSetupImpl(SupervisorSetup):
|
|
105
105
|
|
106
106
|
def _set_rlimits_or_exit(self) -> None:
|
107
107
|
"""
|
108
|
-
Set the rlimits of the supervisord process.
|
109
|
-
|
108
|
+
Set the rlimits of the supervisord process. Called during supervisord startup only. No return value. Exits the
|
109
|
+
process via usage() if any rlimits could not be set.
|
110
110
|
"""
|
111
111
|
|
112
112
|
limits = []
|
@@ -115,12 +115,12 @@ class SupervisorSetupImpl(SupervisorSetup):
|
|
115
115
|
limits.append({
|
116
116
|
'msg': (
|
117
117
|
'The minimum number of file descriptors required to run this process is %(min_limit)s as per the '
|
118
|
-
'"
|
119
|
-
'you to open %(hard)s file descriptors.
|
120
|
-
'your environment (see README.rst) or lower the
|
118
|
+
'"min_fds" command-line argument or config file setting. The current environment will only allow '
|
119
|
+
'you to open %(hard)s file descriptors. Either raise the number of usable file descriptors in '
|
120
|
+
'your environment (see README.rst) or lower the min_fds setting in the config file to allow the '
|
121
121
|
'process to start.'
|
122
122
|
),
|
123
|
-
'min': self._config.
|
123
|
+
'min': self._config.min_fds,
|
124
124
|
'resource': resource.RLIMIT_NOFILE,
|
125
125
|
'name': 'RLIMIT_NOFILE',
|
126
126
|
})
|
@@ -130,11 +130,11 @@ class SupervisorSetupImpl(SupervisorSetup):
|
|
130
130
|
'msg': (
|
131
131
|
'The minimum number of available processes required to run this program is %(min_limit)s as per '
|
132
132
|
'the "minprocs" command-line argument or config file setting. The current environment will only '
|
133
|
-
'allow you to open %(hard)s processes.
|
133
|
+
'allow you to open %(hard)s processes. Either raise the number of usable processes in your '
|
134
134
|
'environment (see README.rst) or lower the minprocs setting in the config file to allow the '
|
135
135
|
'program to start.'
|
136
136
|
),
|
137
|
-
'min': self._config.
|
137
|
+
'min': self._config.min_procs,
|
138
138
|
'resource': resource.RLIMIT_NPROC,
|
139
139
|
'name': 'RLIMIT_NPROC',
|
140
140
|
})
|
@@ -220,11 +220,11 @@ class SupervisorSetupImpl(SupervisorSetup):
|
|
220
220
|
dl.after_daemonize()
|
221
221
|
|
222
222
|
def _do_daemonize(self) -> None:
|
223
|
-
# To daemonize, we need to become the leader of our own session (process) group.
|
224
|
-
# our parent process will also be sent to us.
|
223
|
+
# To daemonize, we need to become the leader of our own session (process) group. If we do not, signals sent to
|
224
|
+
# our parent process will also be sent to us. This might be bad because signals such as SIGINT can be sent to
|
225
225
|
# our parent process during normal (uninteresting) operations such as when we press Ctrl-C in the parent
|
226
226
|
# terminal window to escape from a logtail command. To disassociate ourselves from our parent's session group we
|
227
|
-
# use os.setsid.
|
227
|
+
# use os.setsid. It means "set session id", which has the effect of disassociating a process from is current
|
228
228
|
# session and process group and setting itself up as a new session leader.
|
229
229
|
#
|
230
230
|
# Unfortunately we cannot call setsid if we're already a session group leader, so we use "fork" to make a copy
|
@@ -256,7 +256,7 @@ class SupervisorSetupImpl(SupervisorSetup):
|
|
256
256
|
os.dup2(2, os.open('/dev/null', os.O_WRONLY))
|
257
257
|
|
258
258
|
# XXX Stevens, in his Advanced Unix book, section 13.3 (page 417) recommends calling umask(0) and closing unused
|
259
|
-
# file descriptors.
|
259
|
+
# file descriptors. In his Network Programming book, he additionally recommends ignoring SIGHUP and forking
|
260
260
|
# again after the setsid() call, for obscure SVR4 reasons.
|
261
261
|
os.setsid()
|
262
262
|
os.umask(self._config.umask)
|
@@ -7,6 +7,7 @@ import typing as ta
|
|
7
7
|
|
8
8
|
from omlish.lite.check import check_isinstance
|
9
9
|
from omlish.lite.check import check_not_none
|
10
|
+
from omlish.lite.fdio.handlers import FdIoHandler
|
10
11
|
from omlish.lite.typing import Func3
|
11
12
|
|
12
13
|
from .configs import ProcessConfig
|
@@ -29,7 +30,6 @@ from .process import PidHistory
|
|
29
30
|
from .spawning import ProcessSpawnError
|
30
31
|
from .spawning import ProcessSpawning
|
31
32
|
from .spawning import SpawnedProcess
|
32
|
-
from .types import Dispatcher
|
33
33
|
from .types import Process
|
34
34
|
from .types import ProcessGroup
|
35
35
|
from .types import ProcessInputDispatcher
|
@@ -200,7 +200,7 @@ class ProcessSpawningImpl(ProcessSpawning):
|
|
200
200
|
return exe, args
|
201
201
|
|
202
202
|
def _make_dispatchers(self, pipes: ProcessPipes) -> Dispatchers:
|
203
|
-
dispatchers: ta.List[
|
203
|
+
dispatchers: ta.List[FdIoHandler] = []
|
204
204
|
|
205
205
|
if pipes.stdout is not None:
|
206
206
|
dispatchers.append(check_isinstance(self._output_dispatcher_factory(
|
@@ -316,7 +316,7 @@ class ProcessSpawningImpl(ProcessSpawning):
|
|
316
316
|
else:
|
317
317
|
os.dup2(check_not_none(pipes.child_stderr), 2)
|
318
318
|
|
319
|
-
for i in range(3, self._server_config.
|
319
|
+
for i in range(3, self._server_config.min_fds):
|
320
320
|
if i in self._inherited_fds:
|
321
321
|
continue
|
322
322
|
close_fd(Fd(i))
|
ominfra/supervisor/supervisor.py
CHANGED
@@ -5,6 +5,7 @@ import time
|
|
5
5
|
import typing as ta
|
6
6
|
|
7
7
|
from omlish.lite.check import check_isinstance
|
8
|
+
from omlish.lite.fdio.pollers import FdIoPoller
|
8
9
|
from omlish.lite.logs import log
|
9
10
|
from omlish.lite.typing import Func1
|
10
11
|
|
@@ -17,7 +18,6 @@ from .events import SupervisorStoppingEvent
|
|
17
18
|
from .groups import ProcessGroup
|
18
19
|
from .groups import ProcessGroupManager
|
19
20
|
from .io import IoManager
|
20
|
-
from .poller import Poller
|
21
21
|
from .process import PidHistory
|
22
22
|
from .setup import SupervisorSetup
|
23
23
|
from .signals import SignalHandler
|
@@ -66,7 +66,7 @@ class Supervisor:
|
|
66
66
|
self,
|
67
67
|
*,
|
68
68
|
config: ServerConfig,
|
69
|
-
poller:
|
69
|
+
poller: FdIoPoller,
|
70
70
|
process_groups: ProcessGroupManager,
|
71
71
|
signal_handler: SignalHandler,
|
72
72
|
event_callbacks: EventCallbacks,
|
@@ -182,7 +182,9 @@ class Supervisor:
|
|
182
182
|
#
|
183
183
|
|
184
184
|
def _run_once(self) -> None:
|
185
|
+
now = time.time()
|
185
186
|
self._poll()
|
187
|
+
log.info(f'Poll took {time.time() - now}') # noqa
|
186
188
|
self._reap()
|
187
189
|
self._signal_handler.handle_signals()
|
188
190
|
self._tick()
|
@@ -234,6 +236,7 @@ class Supervisor:
|
|
234
236
|
return
|
235
237
|
|
236
238
|
wp = waitpid()
|
239
|
+
log.info(f'Waited pid: {wp}') # noqa
|
237
240
|
if wp is None or not wp.pid:
|
238
241
|
return
|
239
242
|
|
@@ -279,7 +282,7 @@ class WaitedPid(ta.NamedTuple):
|
|
279
282
|
|
280
283
|
|
281
284
|
def waitpid() -> ta.Optional[WaitedPid]:
|
282
|
-
# Need pthread_sigmask here to avoid concurrent sigchld, but Python doesn't offer in Python < 3.4.
|
285
|
+
# Need pthread_sigmask here to avoid concurrent sigchld, but Python doesn't offer in Python < 3.4. There is
|
283
286
|
# still a race condition here; we can get a sigchld while we're sitting in the waitpid call. However, AFAICT, if
|
284
287
|
# waitpid is interrupted by SIGCHLD, as long as we call waitpid again (which happens every so often during the
|
285
288
|
# normal course in the mainloop), we'll eventually reap the child that we tried to reap during the interrupted
|
ominfra/supervisor/types.py
CHANGED
@@ -3,12 +3,13 @@ import abc
|
|
3
3
|
import functools
|
4
4
|
import typing as ta
|
5
5
|
|
6
|
+
from omlish.lite.fdio.handlers import FdIoHandler
|
7
|
+
|
6
8
|
from .configs import ProcessConfig
|
7
9
|
from .configs import ProcessGroupConfig
|
8
10
|
from .states import ProcessState
|
9
11
|
from .states import SupervisorState
|
10
12
|
from .utils.collections import KeyedCollectionAccessors
|
11
|
-
from .utils.ostypes import Fd
|
12
13
|
from .utils.ostypes import Pid
|
13
14
|
from .utils.ostypes import Rc
|
14
15
|
|
@@ -61,69 +62,18 @@ class SupervisorStateManager(abc.ABC):
|
|
61
62
|
##
|
62
63
|
|
63
64
|
|
64
|
-
class
|
65
|
-
@property
|
65
|
+
class HasDispatchers(abc.ABC):
|
66
66
|
@abc.abstractmethod
|
67
|
-
def
|
67
|
+
def get_dispatchers(self) -> 'Dispatchers':
|
68
68
|
raise NotImplementedError
|
69
69
|
|
70
|
-
@property
|
71
|
-
@abc.abstractmethod
|
72
|
-
def fd(self) -> Fd:
|
73
|
-
raise NotImplementedError
|
74
70
|
|
71
|
+
class ProcessDispatcher(FdIoHandler, abc.ABC):
|
75
72
|
@property
|
76
73
|
@abc.abstractmethod
|
77
|
-
def
|
78
|
-
raise NotImplementedError
|
79
|
-
|
80
|
-
#
|
81
|
-
|
82
|
-
@abc.abstractmethod
|
83
|
-
def close(self) -> None:
|
84
|
-
raise NotImplementedError
|
85
|
-
|
86
|
-
@abc.abstractmethod
|
87
|
-
def handle_error(self) -> None:
|
88
|
-
raise NotImplementedError
|
89
|
-
|
90
|
-
#
|
91
|
-
|
92
|
-
@abc.abstractmethod
|
93
|
-
def readable(self) -> bool:
|
94
|
-
raise NotImplementedError
|
95
|
-
|
96
|
-
@abc.abstractmethod
|
97
|
-
def writable(self) -> bool:
|
98
|
-
raise NotImplementedError
|
99
|
-
|
100
|
-
#
|
101
|
-
|
102
|
-
def handle_read_event(self) -> None:
|
103
|
-
raise TypeError
|
104
|
-
|
105
|
-
def handle_write_event(self) -> None:
|
106
|
-
raise TypeError
|
107
|
-
|
108
|
-
#
|
109
|
-
|
110
|
-
def handle_connect(self) -> None:
|
111
|
-
raise TypeError
|
112
|
-
|
113
|
-
def handle_close(self) -> None:
|
114
|
-
raise TypeError
|
115
|
-
|
116
|
-
def handle_accepted(self, sock, addr) -> None:
|
117
|
-
raise TypeError
|
118
|
-
|
119
|
-
|
120
|
-
class HasDispatchers(abc.ABC):
|
121
|
-
@abc.abstractmethod
|
122
|
-
def get_dispatchers(self) -> 'Dispatchers':
|
74
|
+
def channel(self) -> str:
|
123
75
|
raise NotImplementedError
|
124
76
|
|
125
|
-
|
126
|
-
class ProcessDispatcher(Dispatcher, abc.ABC):
|
127
77
|
@property
|
128
78
|
@abc.abstractmethod
|
129
79
|
def process(self) -> 'Process':
|
ominfra/supervisor/utils/os.py
CHANGED
@@ -21,7 +21,7 @@ def decode_wait_status(sts: int) -> ta.Tuple[Rc, str]:
|
|
21
21
|
Decode the status returned by wait() or waitpid().
|
22
22
|
|
23
23
|
Return a tuple (exitstatus, message) where exitstatus is the exit status, or -1 if the process was killed by a
|
24
|
-
signal; and message is a message telling what happened.
|
24
|
+
signal; and message is a message telling what happened. It is the caller's responsibility to display the message.
|
25
25
|
"""
|
26
26
|
|
27
27
|
if os.WIFEXITED(sts):
|
@@ -62,8 +62,8 @@ def strip_escapes(s: bytes) -> bytes:
|
|
62
62
|
|
63
63
|
|
64
64
|
class SuffixMultiplier:
|
65
|
-
# d is a dictionary of suffixes to integer multipliers.
|
66
|
-
#
|
65
|
+
# d is a dictionary of suffixes to integer multipliers. If no suffixes match, default is the multiplier. Matches are
|
66
|
+
# case insensitive. Return values are in the fundamental unit.
|
67
67
|
def __init__(self, d, default=1):
|
68
68
|
super().__init__()
|
69
69
|
self._d = d
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ominfra
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev131
|
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.dev131
|
16
|
+
Requires-Dist: omlish==0.0.0.dev131
|
17
17
|
Provides-Extra: all
|
18
18
|
Requires-Dist: paramiko~=3.5; extra == "all"
|
19
19
|
Requires-Dist: asyncssh~=2.18; extra == "all"
|
@@ -22,7 +22,7 @@ ominfra/clouds/aws/journald2aws/poster.py,sha256=hz1XuctW8GtLmfjhRvCFY6py52D4BzX
|
|
22
22
|
ominfra/clouds/gcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
23
|
ominfra/clouds/gcp/auth.py,sha256=3PyfRJNgajjMqJFem3SKui0CqGeHEsZlvbRhuxFcZG8,1348
|
24
24
|
ominfra/deploy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
25
|
-
ominfra/deploy/_executor.py,sha256=
|
25
|
+
ominfra/deploy/_executor.py,sha256=4i5JP4tiF-MJQHxwstja4tRoYprnAMyzGd9f_az3r98,35355
|
26
26
|
ominfra/deploy/configs.py,sha256=qi0kwT7G2NH7dXLOQic-u6R3yeadup_QtvrjwWIggbM,435
|
27
27
|
ominfra/deploy/remote.py,sha256=6ACmpXU1uBdyGs3Xsp97ktKFq30cJlzN9LRWNUWlGY4,2144
|
28
28
|
ominfra/deploy/executor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
@@ -37,7 +37,7 @@ ominfra/deploy/executor/concerns/systemd.py,sha256=MtsSEToEa1HNouern_JukcYTnypw_
|
|
37
37
|
ominfra/deploy/executor/concerns/user.py,sha256=j5LDfQXquIp-eEM7t6aShsrYoQrM_ILXZycTmTcRVxA,686
|
38
38
|
ominfra/deploy/executor/concerns/venv.py,sha256=jbRriqJHO4r9Zyo5Hfl_qVmcU6Qm6UgrouBroKcPn2g,775
|
39
39
|
ominfra/deploy/poly/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
40
|
-
ominfra/deploy/poly/_main.py,sha256=
|
40
|
+
ominfra/deploy/poly/_main.py,sha256=fqlcDbbfY6gmebcO9BMWD9sz6V6_gxFTQr194xi69N4,24174
|
41
41
|
ominfra/deploy/poly/base.py,sha256=1dGuzWxi2Z6Hm6-YlkVxPk9r3In2aCJ0p8lGR-QQI_s,4166
|
42
42
|
ominfra/deploy/poly/configs.py,sha256=9bzWdbxhOk_Q4KokDjmRz254KHnUU71Vl1frLlhQyU4,584
|
43
43
|
ominfra/deploy/poly/deploy.py,sha256=tMYKslXLjstcv86siRt5j37USsS0Wd6lsfeGRE26zio,544
|
@@ -56,56 +56,56 @@ ominfra/journald/tailer.py,sha256=5abcFMfgi7fnY9ZEQe2ZVobaJxjQkeu6d9Kagw33a1w,33
|
|
56
56
|
ominfra/manage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
57
57
|
ominfra/manage/manage.py,sha256=BttL8LFEknHZE_h2Pt5dAqbfUkv6qy43WI0raXBZ1a8,151
|
58
58
|
ominfra/pyremote/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
59
|
-
ominfra/pyremote/_runcommands.py,sha256=
|
59
|
+
ominfra/pyremote/_runcommands.py,sha256=RKNvaHje-QGpvwwmFQ6OfEn3eEJ2c6zVUBYnDo2RV9U,29188
|
60
60
|
ominfra/pyremote/bootstrap.py,sha256=RvMO3YGaN1E4sgUi1JEtiPak8cjvqtc_vRCq1yqbeZg,3370
|
61
61
|
ominfra/pyremote/runcommands.py,sha256=bviS0_TDIoZVAe4h-_iavbvJtVSFu8lnk7fQ5iasCWE,1571
|
62
62
|
ominfra/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
63
|
-
ominfra/scripts/journald2aws.py,sha256=
|
64
|
-
ominfra/scripts/supervisor.py,sha256=
|
63
|
+
ominfra/scripts/journald2aws.py,sha256=qNGdiXxng21BBO5kqOQvnOf1Ftc3rTJZXpCu8MO-Kvc,131387
|
64
|
+
ominfra/scripts/supervisor.py,sha256=a0oz88cW-9y0P_LNFXuDBKLgDywv3RIUxxXuZ8VezCE,242615
|
65
65
|
ominfra/supervisor/LICENSE.txt,sha256=yvqaMNsDhWxziHa9ien6qCW1SkZv-DQlAg96XjfSee8,1746
|
66
66
|
ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
67
67
|
ominfra/supervisor/__main__.py,sha256=I0yFw-C08OOiZ3BF6lF1Oiv789EQXu-_j6whDhQUTEA,66
|
68
|
-
ominfra/supervisor/configs.py,sha256=
|
69
|
-
ominfra/supervisor/dispatchers.py,sha256=
|
70
|
-
ominfra/supervisor/dispatchersimpl.py,sha256=
|
68
|
+
ominfra/supervisor/configs.py,sha256=OPtiL5_SjBYQ9xDqMgZvjoXgpleTxv4d3C4fD1X2Dz0,3966
|
69
|
+
ominfra/supervisor/dispatchers.py,sha256=dfjog5PyVAJaFzgFI0tpy38ZgDiFrewMjVi21ksrlAg,1007
|
70
|
+
ominfra/supervisor/dispatchersimpl.py,sha256=dZpfG7Z2_AcRpfa2RaZ-xolsbM5iKkifdQpON7w7Upo,11257
|
71
71
|
ominfra/supervisor/events.py,sha256=w3HQFrq-SuroYWoQfNFYeU1phnTvHTgsAqA6TGtAafI,6593
|
72
72
|
ominfra/supervisor/exceptions.py,sha256=Qbu211H3CLlSmi9LsSikOwrcL5HgJP9ugvcKWlGTAoI,750
|
73
|
-
ominfra/supervisor/groups.py,sha256=
|
73
|
+
ominfra/supervisor/groups.py,sha256=MBbsbt8Zh_WEYkGOr1KXa82gnPVw9wPB2lAnqhugXSc,2457
|
74
74
|
ominfra/supervisor/groupsimpl.py,sha256=nIrW4SmB0W6c2jOR_HhkfVcH4eHyLZnG1FJ0MCzc6mQ,2292
|
75
|
-
ominfra/supervisor/
|
76
|
-
ominfra/supervisor/
|
75
|
+
ominfra/supervisor/http.py,sha256=y0tos6zbb4k-WvNQXlgAeK1qi5mKXkyXO9bVJt4OXew,3227
|
76
|
+
ominfra/supervisor/inject.py,sha256=onKUudx5eBbNuXwEqeiaVIIA3ZbpUSDiEAKg9GBiWG8,4514
|
77
|
+
ominfra/supervisor/io.py,sha256=2NO4BYC-PznIrJpTFxN8UEAhd_codfNm_HI424gYQ3c,3294
|
77
78
|
ominfra/supervisor/main.py,sha256=ebe7skFPfwXV2meMVRndhuLZmz-LiuHH1x1CgiarR0o,4132
|
78
|
-
ominfra/supervisor/pipes.py,sha256=
|
79
|
-
ominfra/supervisor/
|
80
|
-
ominfra/supervisor/privileges.py,sha256=bO7rJGT7cMOBALK_4D4NiQnOS5dOYb14Sz66R-ymG24,2071
|
79
|
+
ominfra/supervisor/pipes.py,sha256=2ZihNTnRNjnIPOtPbm3_pyqO15f7BNs7WnNtO5V8ahM,2231
|
80
|
+
ominfra/supervisor/privileges.py,sha256=kaRTHI7XjqzxEWCeHp3_0J0Vc4gSPugRbXEwxuw6MYE,2054
|
81
81
|
ominfra/supervisor/process.py,sha256=UaubVxsxVqDnbuWVpTH0DTGbJGLO0vGJ9mNcvy2kCXM,217
|
82
|
-
ominfra/supervisor/processimpl.py,sha256=
|
82
|
+
ominfra/supervisor/processimpl.py,sha256=YRHIVYdPXighBXAVNmW3ur7IhoSxhkxFYCQI1B8CpDo,18748
|
83
83
|
ominfra/supervisor/setup.py,sha256=7HwwwI-WT_Z0WjZ9_l5Orr4K298nKKhQ1f_ZgGsi9TU,622
|
84
|
-
ominfra/supervisor/setupimpl.py,sha256=
|
84
|
+
ominfra/supervisor/setupimpl.py,sha256=88h3oYsdJ0LAo7sZZZGRQti14oQay3b-0Vd_h3Cl108,9638
|
85
85
|
ominfra/supervisor/signals.py,sha256=jY52naUifcAjd6nICTP1ZW3IQSPsHB4cvbsJo8_QV_U,2196
|
86
86
|
ominfra/supervisor/spawning.py,sha256=i1k3tmqWyU-KIN7kel-JVxTVGnLiTIVmZzlstJSZpjM,622
|
87
|
-
ominfra/supervisor/spawningimpl.py,sha256=
|
87
|
+
ominfra/supervisor/spawningimpl.py,sha256=Pkp6mefJhOGCCj5T2I1jXEsVp15g9KMKbANYgoX-ws8,11162
|
88
88
|
ominfra/supervisor/states.py,sha256=9yoNOSwalRcKEnCP9zG6tVS0oivo5tCeuH6AaaW7Jpc,890
|
89
|
-
ominfra/supervisor/supervisor.py,sha256=
|
90
|
-
ominfra/supervisor/types.py,sha256=
|
89
|
+
ominfra/supervisor/supervisor.py,sha256=Ryvs80cDOe4pvBdZazLLaOCR1We0aj44Y1Hw4l3FUnk,9514
|
90
|
+
ominfra/supervisor/types.py,sha256=RamAYEF3fISfKwlIMRleLOFuKVWrxjQJGI6p76jK03c,3959
|
91
91
|
ominfra/supervisor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
92
92
|
ominfra/supervisor/utils/collections.py,sha256=vcfmVYS4QngMdtEI1DvdRIcubmy55Wj40NCzW27_rIY,1361
|
93
93
|
ominfra/supervisor/utils/diag.py,sha256=ujz4gkW7p3wmbaKFM8Hz5eHEwpoUkbB8JeDvcHilCz0,705
|
94
94
|
ominfra/supervisor/utils/fds.py,sha256=lz8DWXzGYvu93dqhWK0WrhXrrJVQ_psoom4Nj_o8g2g,849
|
95
95
|
ominfra/supervisor/utils/fs.py,sha256=ABbNcsCpzSXAvq_ZZSCj61mj5kGnVuC4spUmoWenlqw,1155
|
96
|
-
ominfra/supervisor/utils/os.py,sha256=
|
96
|
+
ominfra/supervisor/utils/os.py,sha256=IZJ9mBV23CAI0hSBVQiyCNcf-sWqHAmjAW9bbsvKFao,1095
|
97
97
|
ominfra/supervisor/utils/ostypes.py,sha256=B7VjwbzVesz9we9MztoSk8bH8sTxMIWtILy_Qde0G7w,164
|
98
98
|
ominfra/supervisor/utils/signals.py,sha256=uZkTvissbtq7TlJD4MkTiL3F-zyWmAFUuWQtFjsf0MI,1474
|
99
|
-
ominfra/supervisor/utils/strings.py,sha256=
|
99
|
+
ominfra/supervisor/utils/strings.py,sha256=gZOYiFI3ZQEMrXq6VlK2WadK12JPO6zYjPenq_OPcYU,2475
|
100
100
|
ominfra/supervisor/utils/users.py,sha256=PRUhWy74WQCxix4BLNYcWW1i2mF1IyAxj1RzElnP4iM,1345
|
101
101
|
ominfra/tailscale/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
102
102
|
ominfra/tailscale/api.py,sha256=C5-t_b6jZXUWcy5k8bXm7CFnk73pSdrlMOgGDeGVrpw,1370
|
103
103
|
ominfra/tailscale/cli.py,sha256=DSGp4hn5xwOW-l_u_InKlSF6kIobxtUtVssf_73STs0,3567
|
104
104
|
ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
105
105
|
ominfra/tools/listresources.py,sha256=4qVg5txsb10EHhvqXXeM6gJ2jx9LbroEnPydDv1uXs0,6176
|
106
|
-
ominfra-0.0.0.
|
107
|
-
ominfra-0.0.0.
|
108
|
-
ominfra-0.0.0.
|
109
|
-
ominfra-0.0.0.
|
110
|
-
ominfra-0.0.0.
|
111
|
-
ominfra-0.0.0.
|
106
|
+
ominfra-0.0.0.dev131.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
107
|
+
ominfra-0.0.0.dev131.dist-info/METADATA,sha256=tX48aF4l92ov4-dQc50yn6pbYrXTAz3j73ZJS7H9p04,731
|
108
|
+
ominfra-0.0.0.dev131.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
109
|
+
ominfra-0.0.0.dev131.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
|
110
|
+
ominfra-0.0.0.dev131.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
|
111
|
+
ominfra-0.0.0.dev131.dist-info/RECORD,,
|