ominfra 0.0.0.dev125__py3-none-any.whl → 0.0.0.dev127__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.
Files changed (34) hide show
  1. ominfra/clouds/aws/auth.py +1 -1
  2. ominfra/deploy/_executor.py +1 -1
  3. ominfra/deploy/poly/_main.py +1 -1
  4. ominfra/pyremote/_runcommands.py +1 -1
  5. ominfra/scripts/journald2aws.py +2 -2
  6. ominfra/scripts/supervisor.py +1825 -1217
  7. ominfra/supervisor/collections.py +52 -0
  8. ominfra/supervisor/context.py +2 -336
  9. ominfra/supervisor/datatypes.py +1 -63
  10. ominfra/supervisor/dispatchers.py +22 -338
  11. ominfra/supervisor/dispatchersimpl.py +342 -0
  12. ominfra/supervisor/groups.py +33 -110
  13. ominfra/supervisor/groupsimpl.py +86 -0
  14. ominfra/supervisor/inject.py +45 -13
  15. ominfra/supervisor/main.py +1 -1
  16. ominfra/supervisor/pipes.py +83 -0
  17. ominfra/supervisor/poller.py +6 -3
  18. ominfra/supervisor/privileges.py +65 -0
  19. ominfra/supervisor/processes.py +18 -0
  20. ominfra/supervisor/{process.py → processesimpl.py} +99 -317
  21. ominfra/supervisor/setup.py +38 -0
  22. ominfra/supervisor/setupimpl.py +261 -0
  23. ominfra/supervisor/signals.py +24 -16
  24. ominfra/supervisor/spawning.py +31 -0
  25. ominfra/supervisor/spawningimpl.py +347 -0
  26. ominfra/supervisor/supervisor.py +54 -78
  27. ominfra/supervisor/types.py +122 -39
  28. ominfra/supervisor/users.py +64 -0
  29. {ominfra-0.0.0.dev125.dist-info → ominfra-0.0.0.dev127.dist-info}/METADATA +3 -3
  30. {ominfra-0.0.0.dev125.dist-info → ominfra-0.0.0.dev127.dist-info}/RECORD +34 -23
  31. {ominfra-0.0.0.dev125.dist-info → ominfra-0.0.0.dev127.dist-info}/LICENSE +0 -0
  32. {ominfra-0.0.0.dev125.dist-info → ominfra-0.0.0.dev127.dist-info}/WHEEL +0 -0
  33. {ominfra-0.0.0.dev125.dist-info → ominfra-0.0.0.dev127.dist-info}/entry_points.txt +0 -0
  34. {ominfra-0.0.0.dev125.dist-info → ominfra-0.0.0.dev127.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,6 @@
1
1
  # ruff: noqa: UP006 UP007
2
2
  import errno
3
3
  import os.path
4
- import shlex
5
4
  import signal
6
5
  import time
7
6
  import traceback
@@ -9,40 +8,31 @@ import typing as ta
9
8
 
10
9
  from omlish.lite.check import check_isinstance
11
10
  from omlish.lite.logs import log
11
+ from omlish.lite.typing import Func1
12
12
 
13
13
  from .configs import ProcessConfig
14
- from .context import check_execv_args
15
- from .context import close_child_pipes
16
- from .context import close_parent_pipes
17
- from .context import drop_privileges
18
- from .context import make_pipes
19
14
  from .datatypes import RestartUnconditionally
20
- from .dispatchers import Dispatcher
21
- from .dispatchers import InputDispatcher
22
- from .dispatchers import OutputDispatcher
15
+ from .dispatchers import Dispatchers
23
16
  from .events import PROCESS_STATE_EVENT_MAP
24
17
  from .events import EventCallbacks
25
- from .events import ProcessCommunicationEvent
26
- from .events import ProcessCommunicationStderrEvent
27
- from .events import ProcessCommunicationStdoutEvent
28
- from .exceptions import BadCommandError
29
- from .exceptions import ProcessError
18
+ from .pipes import ProcessPipes
19
+ from .pipes import close_parent_pipes
20
+ from .processes import ProcessStateError
30
21
  from .signals import sig_name
22
+ from .spawning import ProcessSpawnError
23
+ from .spawning import ProcessSpawning
31
24
  from .states import ProcessState
32
25
  from .states import SupervisorState
26
+ from .types import InputDispatcher
33
27
  from .types import Process
34
28
  from .types import ProcessGroup
35
29
  from .types import ServerContext
36
- from .utils import as_bytes
37
30
  from .utils import as_string
38
- from .utils import close_fd
39
- from .utils import compact_traceback
40
31
  from .utils import decode_wait_status
41
- from .utils import get_path
42
- from .utils import real_exit
43
32
 
44
33
 
45
- InheritedFds = ta.NewType('InheritedFds', ta.FrozenSet[int])
34
+ class ProcessSpawningFactory(Func1[Process, ProcessSpawning]):
35
+ pass
46
36
 
47
37
 
48
38
  ##
@@ -58,19 +48,22 @@ class ProcessImpl(Process):
58
48
  *,
59
49
  context: ServerContext,
60
50
  event_callbacks: EventCallbacks,
61
-
62
- inherited_fds: ta.Optional[InheritedFds] = None,
51
+ process_spawning_factory: ProcessSpawningFactory,
63
52
  ) -> None:
64
53
  super().__init__()
65
54
 
66
55
  self._config = config
67
56
  self._group = group
57
+
68
58
  self._context = context
69
59
  self._event_callbacks = event_callbacks
70
- self._inherited_fds = InheritedFds(frozenset(inherited_fds or []))
71
60
 
72
- self._dispatchers: ta.Dict[int, Dispatcher] = {}
73
- self._pipes: ta.Dict[str, int] = {}
61
+ self._spawning = process_spawning_factory(self)
62
+
63
+ #
64
+
65
+ self._dispatchers = Dispatchers([])
66
+ self._pipes = ProcessPipes()
74
67
 
75
68
  self._state = ProcessState.STOPPED
76
69
  self._pid = 0 # 0 when not running
@@ -90,17 +83,30 @@ class ProcessImpl(Process):
90
83
  self._exitstatus: ta.Optional[int] = None # status attached to dead process by finish()
91
84
  self._spawn_err: ta.Optional[str] = None # error message attached by spawn() if any
92
85
 
86
+ #
87
+
88
+ def __repr__(self) -> str:
89
+ return f'<Subprocess at {id(self)} with name {self._config.name} in state {self.get_state().name}>'
90
+
91
+ #
92
+
93
93
  @property
94
- def pid(self) -> int:
95
- return self._pid
94
+ def name(self) -> str:
95
+ return self._config.name
96
+
97
+ @property
98
+ def config(self) -> ProcessConfig:
99
+ return self._config
96
100
 
97
101
  @property
98
102
  def group(self) -> ProcessGroup:
99
103
  return self._group
100
104
 
101
105
  @property
102
- def config(self) -> ProcessConfig:
103
- return self._config
106
+ def pid(self) -> int:
107
+ return self._pid
108
+
109
+ #
104
110
 
105
111
  @property
106
112
  def context(self) -> ServerContext:
@@ -114,33 +120,59 @@ class ProcessImpl(Process):
114
120
  def backoff(self) -> int:
115
121
  return self._backoff
116
122
 
117
- def get_dispatchers(self) -> ta.Mapping[int, Dispatcher]:
118
- return self._dispatchers
123
+ #
124
+
125
+ def spawn(self) -> ta.Optional[int]:
126
+ process_name = as_string(self._config.name)
127
+
128
+ if self.pid:
129
+ log.warning('process \'%s\' already running', process_name)
130
+ return None
119
131
 
120
- def remove_logs(self) -> None:
121
- for dispatcher in self._dispatchers.values():
122
- if hasattr(dispatcher, 'remove_logs'):
123
- dispatcher.remove_logs()
124
-
125
- def reopen_logs(self) -> None:
126
- for dispatcher in self._dispatchers.values():
127
- if hasattr(dispatcher, 'reopen_logs'):
128
- dispatcher.reopen_logs()
129
-
130
- def drain(self) -> None:
131
- for dispatcher in self._dispatchers.values():
132
- # note that we *must* call readable() for every dispatcher, as it may have side effects for a given
133
- # dispatcher (eg. call handle_listener_state_change for event listener processes)
134
- if dispatcher.readable():
135
- dispatcher.handle_read_event()
136
- if dispatcher.writable():
137
- dispatcher.handle_write_event()
132
+ self.check_in_state(
133
+ ProcessState.EXITED,
134
+ ProcessState.FATAL,
135
+ ProcessState.BACKOFF,
136
+ ProcessState.STOPPED,
137
+ )
138
+
139
+ self._killing = False
140
+ self._spawn_err = None
141
+ self._exitstatus = None
142
+ self._system_stop = False
143
+ self._administrative_stop = False
144
+
145
+ self._last_start = time.time()
146
+
147
+ self.change_state(ProcessState.STARTING)
148
+
149
+ try:
150
+ sp = self._spawning.spawn()
151
+ except ProcessSpawnError as err:
152
+ log.exception('Spawn error')
153
+ self._spawn_err = err.args[0]
154
+ self.check_in_state(ProcessState.STARTING)
155
+ self.change_state(ProcessState.BACKOFF)
156
+ return None
157
+
158
+ log.info("Spawned: '%s' with pid %s", self.name, sp.pid)
159
+
160
+ self._pid = sp.pid
161
+ self._pipes = sp.pipes
162
+ self._dispatchers = sp.dispatchers
163
+
164
+ self._delay = time.time() + self.config.startsecs
165
+
166
+ return sp.pid
167
+
168
+ def get_dispatchers(self) -> Dispatchers:
169
+ return self._dispatchers
138
170
 
139
171
  def write(self, chars: ta.Union[bytes, str]) -> None:
140
172
  if not self.pid or self._killing:
141
173
  raise OSError(errno.EPIPE, 'Process already closed')
142
174
 
143
- stdin_fd = self._pipes['stdin']
175
+ stdin_fd = self._pipes.stdin
144
176
  if stdin_fd is None:
145
177
  raise OSError(errno.EPIPE, 'Process has no stdin channel')
146
178
 
@@ -151,51 +183,7 @@ class ProcessImpl(Process):
151
183
  dispatcher.write(chars)
152
184
  dispatcher.flush() # this must raise EPIPE if the pipe is closed
153
185
 
154
- def _get_execv_args(self) -> ta.Tuple[str, ta.Sequence[str]]:
155
- """
156
- Internal: turn a program name into a file name, using $PATH, make sure it exists / is executable, raising a
157
- ProcessError if not
158
- """
159
-
160
- try:
161
- commandargs = shlex.split(self._config.command)
162
- except ValueError as e:
163
- raise BadCommandError(f"can't parse command {self._config.command!r}: {e}") # noqa
164
-
165
- if commandargs:
166
- program = commandargs[0]
167
- else:
168
- raise BadCommandError('command is empty')
169
-
170
- if '/' in program:
171
- filename = program
172
- try:
173
- st = os.stat(filename)
174
- except OSError:
175
- st = None
176
-
177
- else:
178
- path = get_path()
179
- found = None
180
- st = None
181
- for dir in path: # noqa
182
- found = os.path.join(dir, program)
183
- try:
184
- st = os.stat(found)
185
- except OSError:
186
- pass
187
- else:
188
- break
189
- if st is None:
190
- filename = program
191
- else:
192
- filename = found # type: ignore
193
-
194
- # check_execv_args will raise a ProcessError if the execv args are bogus, we break it out into a separate
195
- # options method call here only to service unit tests
196
- check_execv_args(filename, commandargs, st)
197
-
198
- return filename, commandargs
186
+ #
199
187
 
200
188
  def change_state(self, new_state: ProcessState, expected: bool = True) -> bool:
201
189
  old_state = self._state
@@ -215,209 +203,14 @@ class ProcessImpl(Process):
215
203
 
216
204
  return True
217
205
 
218
- def _check_in_state(self, *states: ProcessState) -> None:
206
+ def check_in_state(self, *states: ProcessState) -> None:
219
207
  if self._state not in states:
220
- current_state = self._state.name
221
- allowable_states = ' '.join(s.name for s in states)
222
- process_name = as_string(self._config.name)
223
- raise RuntimeError('Assertion failed for %s: %s not in %s' % (process_name, current_state, allowable_states)) # noqa
224
-
225
- def _record_spawn_err(self, msg: str) -> None:
226
- self._spawn_err = msg
227
- log.info('_spawn_err: %s', msg)
228
-
229
- def spawn(self) -> ta.Optional[int]:
230
- process_name = as_string(self._config.name)
231
-
232
- if self.pid:
233
- log.warning('process \'%s\' already running', process_name)
234
- return None
235
-
236
- self._killing = False
237
- self._spawn_err = None
238
- self._exitstatus = None
239
- self._system_stop = False
240
- self._administrative_stop = False
241
-
242
- self._last_start = time.time()
243
-
244
- self._check_in_state(
245
- ProcessState.EXITED,
246
- ProcessState.FATAL,
247
- ProcessState.BACKOFF,
248
- ProcessState.STOPPED,
249
- )
250
-
251
- self.change_state(ProcessState.STARTING)
252
-
253
- try:
254
- filename, argv = self._get_execv_args()
255
- except ProcessError as what:
256
- self._record_spawn_err(what.args[0])
257
- self._check_in_state(ProcessState.STARTING)
258
- self.change_state(ProcessState.BACKOFF)
259
- return None
260
-
261
- try:
262
- self._dispatchers, self._pipes = self._make_dispatchers() # type: ignore
263
- except OSError as why:
264
- code = why.args[0]
265
- if code == errno.EMFILE:
266
- # too many file descriptors open
267
- msg = f"too many open files to spawn '{process_name}'"
268
- else:
269
- msg = f"unknown error making dispatchers for '{process_name}': {errno.errorcode.get(code, code)}"
270
- self._record_spawn_err(msg)
271
- self._check_in_state(ProcessState.STARTING)
272
- self.change_state(ProcessState.BACKOFF)
273
- return None
274
-
275
- try:
276
- pid = os.fork()
277
- except OSError as why:
278
- code = why.args[0]
279
- if code == errno.EAGAIN:
280
- # process table full
281
- msg = f'Too many processes in process table to spawn \'{process_name}\''
282
- else:
283
- msg = f'unknown error during fork for \'{process_name}\': {errno.errorcode.get(code, code)}'
284
- self._record_spawn_err(msg)
285
- self._check_in_state(ProcessState.STARTING)
286
- self.change_state(ProcessState.BACKOFF)
287
- close_parent_pipes(self._pipes)
288
- close_child_pipes(self._pipes)
289
- return None
290
-
291
- if pid != 0:
292
- return self._spawn_as_parent(pid)
293
-
294
- else:
295
- self._spawn_as_child(filename, argv)
296
- return None
297
-
298
- def _make_dispatchers(self) -> ta.Tuple[ta.Mapping[int, Dispatcher], ta.Mapping[str, int]]:
299
- use_stderr = not self._config.redirect_stderr
300
-
301
- p = make_pipes(use_stderr)
302
- stdout_fd, stderr_fd, stdin_fd = p['stdout'], p['stderr'], p['stdin']
303
-
304
- dispatchers: ta.Dict[int, Dispatcher] = {}
305
-
306
- dispatcher_kw = dict(
307
- event_callbacks=self._event_callbacks,
308
- )
309
-
310
- etype: ta.Type[ProcessCommunicationEvent]
311
- if stdout_fd is not None:
312
- etype = ProcessCommunicationStdoutEvent
313
- dispatchers[stdout_fd] = OutputDispatcher(
314
- self,
315
- etype,
316
- stdout_fd,
317
- **dispatcher_kw,
208
+ raise ProcessStateError(
209
+ f'Check failed for {self._config.name}: '
210
+ f'{self._state.name} not in {" ".join(s.name for s in states)}',
318
211
  )
319
212
 
320
- if stderr_fd is not None:
321
- etype = ProcessCommunicationStderrEvent
322
- dispatchers[stderr_fd] = OutputDispatcher(
323
- self,
324
- etype,
325
- stderr_fd,
326
- **dispatcher_kw,
327
- )
328
-
329
- if stdin_fd is not None:
330
- dispatchers[stdin_fd] = InputDispatcher(
331
- self,
332
- 'stdin',
333
- stdin_fd,
334
- **dispatcher_kw,
335
- )
336
-
337
- return dispatchers, p
338
-
339
- def _spawn_as_parent(self, pid: int) -> int:
340
- # Parent
341
- self._pid = pid
342
- close_child_pipes(self._pipes)
343
- log.info('spawned: \'%s\' with pid %s', as_string(self._config.name), pid)
344
- self._spawn_err = None
345
- self._delay = time.time() + self._config.startsecs
346
- self.context.pid_history[pid] = self
347
- return pid
348
-
349
- def _prepare_child_fds(self) -> None:
350
- os.dup2(self._pipes['child_stdin'], 0)
351
- os.dup2(self._pipes['child_stdout'], 1)
352
- if self._config.redirect_stderr:
353
- os.dup2(self._pipes['child_stdout'], 2)
354
- else:
355
- os.dup2(self._pipes['child_stderr'], 2)
356
-
357
- for i in range(3, self.context.config.minfds):
358
- if i in self._inherited_fds:
359
- continue
360
- close_fd(i)
361
-
362
- def _spawn_as_child(self, filename: str, argv: ta.Sequence[str]) -> None:
363
- try:
364
- # prevent child from receiving signals sent to the parent by calling os.setpgrp to create a new process
365
- # group for the child; this prevents, for instance, the case of child processes being sent a SIGINT when
366
- # running supervisor in foreground mode and Ctrl-C in the terminal window running supervisord is pressed.
367
- # Presumably it also prevents HUP, etc received by supervisord from being sent to children.
368
- os.setpgrp()
369
-
370
- self._prepare_child_fds()
371
- # sending to fd 2 will put this output in the stderr log
372
-
373
- # set user
374
- setuid_msg = self.set_uid()
375
- if setuid_msg:
376
- uid = self._config.uid
377
- msg = f"couldn't setuid to {uid}: {setuid_msg}\n"
378
- os.write(2, as_bytes('supervisor: ' + msg))
379
- return # finally clause will exit the child process
380
-
381
- # set environment
382
- env = os.environ.copy()
383
- env['SUPERVISOR_ENABLED'] = '1'
384
- env['SUPERVISOR_PROCESS_NAME'] = self._config.name
385
- if self._group:
386
- env['SUPERVISOR_GROUP_NAME'] = self._group.config.name
387
- if self._config.environment is not None:
388
- env.update(self._config.environment)
389
-
390
- # change directory
391
- cwd = self._config.directory
392
- try:
393
- if cwd is not None:
394
- os.chdir(os.path.expanduser(cwd))
395
- except OSError as why:
396
- code = errno.errorcode.get(why.args[0], why.args[0])
397
- msg = f"couldn't chdir to {cwd}: {code}\n"
398
- os.write(2, as_bytes('supervisor: ' + msg))
399
- return # finally clause will exit the child process
400
-
401
- # set umask, then execve
402
- try:
403
- if self._config.umask is not None:
404
- os.umask(self._config.umask)
405
- os.execve(filename, list(argv), env)
406
- except OSError as why:
407
- code = errno.errorcode.get(why.args[0], why.args[0])
408
- msg = f"couldn't exec {argv[0]}: {code}\n"
409
- os.write(2, as_bytes('supervisor: ' + msg))
410
- except Exception: # noqa
411
- (file, fun, line), t, v, tbinfo = compact_traceback()
412
- error = f'{t}, {v}: file: {file} line: {line}'
413
- msg = f"couldn't exec {filename}: {error}\n"
414
- os.write(2, as_bytes('supervisor: ' + msg))
415
-
416
- # this point should only be reached if execve failed. the finally clause will exit the child process.
417
-
418
- finally:
419
- os.write(2, as_bytes('supervisor: child process was not spawned\n'))
420
- real_exit(127) # exit process with code for spawn failure
213
+ #
421
214
 
422
215
  def _check_and_adjust_for_system_clock_rollback(self, test_time):
423
216
  """
@@ -463,7 +256,7 @@ class ProcessImpl(Process):
463
256
  self._delay = 0
464
257
  self._backoff = 0
465
258
  self._system_stop = True
466
- self._check_in_state(ProcessState.BACKOFF)
259
+ self.check_in_state(ProcessState.BACKOFF)
467
260
  self.change_state(ProcessState.FATAL)
468
261
 
469
262
  def kill(self, sig: int) -> ta.Optional[str]:
@@ -507,7 +300,7 @@ class ProcessImpl(Process):
507
300
  self._killing = True
508
301
  self._delay = now + self._config.stopwaitsecs
509
302
  # we will already be in the STOPPING state if we're doing a SIGKILL as a result of overrunning stopwaitsecs
510
- self._check_in_state(ProcessState.RUNNING, ProcessState.STARTING, ProcessState.STOPPING)
303
+ self.check_in_state(ProcessState.RUNNING, ProcessState.STARTING, ProcessState.STOPPING)
511
304
  self.change_state(ProcessState.STOPPING)
512
305
 
513
306
  pid = self.pid
@@ -552,7 +345,7 @@ class ProcessImpl(Process):
552
345
 
553
346
  log.debug('sending %s (pid %s) sig %s', process_name, self.pid, sig_name(sig))
554
347
 
555
- self._check_in_state(ProcessState.RUNNING, ProcessState.STARTING, ProcessState.STOPPING)
348
+ self.check_in_state(ProcessState.RUNNING, ProcessState.STARTING, ProcessState.STOPPING)
556
349
 
557
350
  try:
558
351
  try:
@@ -581,7 +374,7 @@ class ProcessImpl(Process):
581
374
  def finish(self, sts: int) -> None:
582
375
  """The process was reaped and we need to report and manage its state."""
583
376
 
584
- self.drain()
377
+ self._dispatchers.drain()
585
378
 
586
379
  es, msg = decode_wait_status(sts)
587
380
 
@@ -612,7 +405,7 @@ class ProcessImpl(Process):
612
405
  self._exitstatus = es
613
406
 
614
407
  fmt, args = 'stopped: %s (%s)', (process_name, msg)
615
- self._check_in_state(ProcessState.STOPPING)
408
+ self.check_in_state(ProcessState.STOPPING)
616
409
  self.change_state(ProcessState.STOPPED)
617
410
  if exit_expected:
618
411
  log.info(fmt, *args)
@@ -623,7 +416,7 @@ class ProcessImpl(Process):
623
416
  # the program did not stay up long enough to make it to RUNNING implies STARTING -> BACKOFF
624
417
  self._exitstatus = None
625
418
  self._spawn_err = 'Exited too quickly (process log may have details)'
626
- self._check_in_state(ProcessState.STARTING)
419
+ self.check_in_state(ProcessState.STARTING)
627
420
  self.change_state(ProcessState.BACKOFF)
628
421
  log.warning('exited: %s (%s)', process_name, msg + '; not expected')
629
422
 
@@ -639,7 +432,7 @@ class ProcessImpl(Process):
639
432
  if self._state == ProcessState.STARTING:
640
433
  self.change_state(ProcessState.RUNNING)
641
434
 
642
- self._check_in_state(ProcessState.RUNNING)
435
+ self.check_in_state(ProcessState.RUNNING)
643
436
 
644
437
  if exit_expected:
645
438
  # expected exit code
@@ -653,19 +446,8 @@ class ProcessImpl(Process):
653
446
 
654
447
  self._pid = 0
655
448
  close_parent_pipes(self._pipes)
656
- self._pipes = {}
657
- self._dispatchers = {}
658
-
659
- def set_uid(self) -> ta.Optional[str]:
660
- if self._config.uid is None:
661
- return None
662
- msg = drop_privileges(self._config.uid)
663
- return msg
664
-
665
- def __repr__(self) -> str:
666
- # repr can't return anything other than a native string, but the name might be unicode - a problem on Python 2.
667
- name = self._config.name
668
- return f'<Subprocess at {id(self)} with name {name} in state {self.get_state().name}>'
449
+ self._pipes = ProcessPipes()
450
+ self._dispatchers = Dispatchers([])
669
451
 
670
452
  def get_state(self) -> ProcessState:
671
453
  return self._state
@@ -707,7 +489,7 @@ class ProcessImpl(Process):
707
489
  # proc.config.startsecs,
708
490
  self._delay = 0
709
491
  self._backoff = 0
710
- self._check_in_state(ProcessState.STARTING)
492
+ self.check_in_state(ProcessState.STARTING)
711
493
  self.change_state(ProcessState.RUNNING)
712
494
  msg = ('entered RUNNING state, process has stayed up for > than %s seconds (startsecs)' % self._config.startsecs) # noqa
713
495
  logger.info('success: %s %s', process_name, msg)
@@ -727,7 +509,7 @@ class ProcessImpl(Process):
727
509
  log.warning('killing \'%s\' (%s) with SIGKILL', process_name, self.pid)
728
510
  self.kill(signal.SIGKILL)
729
511
 
730
- def create_auto_child_logs(self) -> None:
512
+ def after_setuid(self) -> None:
731
513
  # temporary logfiles which are erased at start time
732
514
  # get_autoname = self.context.get_auto_child_log_name # noqa
733
515
  # sid = self.context.config.identifier # noqa
@@ -0,0 +1,38 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import abc
3
+ import typing as ta
4
+
5
+ from .users import User
6
+
7
+
8
+ ##
9
+
10
+
11
+ SupervisorUser = ta.NewType('SupervisorUser', User)
12
+
13
+
14
+ ##
15
+
16
+
17
+ class DaemonizeListener(abc.ABC): # noqa
18
+ def before_daemonize(self) -> None: # noqa
19
+ pass
20
+
21
+ def after_daemonize(self) -> None: # noqa
22
+ pass
23
+
24
+
25
+ DaemonizeListeners = ta.NewType('DaemonizeListeners', ta.Sequence[DaemonizeListener])
26
+
27
+
28
+ ##
29
+
30
+
31
+ class SupervisorSetup(abc.ABC):
32
+ @abc.abstractmethod
33
+ def setup(self) -> None:
34
+ raise NotImplementedError
35
+
36
+ @abc.abstractmethod
37
+ def cleanup(self) -> None:
38
+ raise NotImplementedError