ominfra 0.0.0.dev126__py3-none-any.whl → 0.0.0.dev128__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/auth.py +1 -1
- ominfra/deploy/_executor.py +1 -1
- ominfra/deploy/poly/_main.py +1 -1
- ominfra/pyremote/_runcommands.py +1 -1
- ominfra/scripts/journald2aws.py +2 -2
- ominfra/scripts/supervisor.py +4736 -4166
- ominfra/supervisor/configs.py +34 -11
- ominfra/supervisor/context.py +7 -345
- ominfra/supervisor/dispatchers.py +21 -324
- ominfra/supervisor/dispatchersimpl.py +343 -0
- ominfra/supervisor/groups.py +33 -111
- ominfra/supervisor/groupsimpl.py +86 -0
- ominfra/supervisor/inject.py +45 -20
- ominfra/supervisor/main.py +3 -3
- ominfra/supervisor/pipes.py +85 -0
- ominfra/supervisor/poller.py +42 -38
- ominfra/supervisor/privileges.py +65 -0
- ominfra/supervisor/process.py +6 -742
- ominfra/supervisor/processimpl.py +516 -0
- ominfra/supervisor/setup.py +38 -0
- ominfra/supervisor/setupimpl.py +262 -0
- ominfra/supervisor/spawning.py +32 -0
- ominfra/supervisor/spawningimpl.py +350 -0
- ominfra/supervisor/supervisor.py +67 -84
- ominfra/supervisor/types.py +101 -47
- ominfra/supervisor/utils/__init__.py +0 -0
- ominfra/supervisor/utils/collections.py +52 -0
- ominfra/supervisor/utils/diag.py +31 -0
- ominfra/supervisor/utils/fds.py +46 -0
- ominfra/supervisor/utils/fs.py +47 -0
- ominfra/supervisor/utils/os.py +45 -0
- ominfra/supervisor/utils/ostypes.py +9 -0
- ominfra/supervisor/utils/signals.py +60 -0
- ominfra/supervisor/utils/strings.py +105 -0
- ominfra/supervisor/utils/users.py +67 -0
- {ominfra-0.0.0.dev126.dist-info → ominfra-0.0.0.dev128.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev126.dist-info → ominfra-0.0.0.dev128.dist-info}/RECORD +41 -25
- ominfra/supervisor/datatypes.py +0 -175
- ominfra/supervisor/signals.py +0 -52
- ominfra/supervisor/utils.py +0 -206
- {ominfra-0.0.0.dev126.dist-info → ominfra-0.0.0.dev128.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev126.dist-info → ominfra-0.0.0.dev128.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev126.dist-info → ominfra-0.0.0.dev128.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev126.dist-info → ominfra-0.0.0.dev128.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import os
|
3
|
+
import tempfile
|
4
|
+
import typing as ta
|
5
|
+
|
6
|
+
|
7
|
+
def try_unlink(path: str) -> bool:
|
8
|
+
try:
|
9
|
+
os.unlink(path)
|
10
|
+
except OSError:
|
11
|
+
return False
|
12
|
+
return True
|
13
|
+
|
14
|
+
|
15
|
+
def mktempfile(suffix: str, prefix: str, dir: str) -> str: # noqa
|
16
|
+
fd, filename = tempfile.mkstemp(suffix, prefix, dir)
|
17
|
+
os.close(fd)
|
18
|
+
return filename
|
19
|
+
|
20
|
+
|
21
|
+
def get_path() -> ta.Sequence[str]:
|
22
|
+
"""Return a list corresponding to $PATH, or a default."""
|
23
|
+
|
24
|
+
path = ['/bin', '/usr/bin', '/usr/local/bin']
|
25
|
+
if 'PATH' in os.environ:
|
26
|
+
p = os.environ['PATH']
|
27
|
+
if p:
|
28
|
+
path = p.split(os.pathsep)
|
29
|
+
return path
|
30
|
+
|
31
|
+
|
32
|
+
def check_existing_dir(v: str) -> str:
|
33
|
+
nv = os.path.expanduser(v)
|
34
|
+
if os.path.isdir(nv):
|
35
|
+
return nv
|
36
|
+
raise ValueError(f'{v} is not an existing directory')
|
37
|
+
|
38
|
+
|
39
|
+
def check_path_with_existing_dir(v: str) -> str:
|
40
|
+
nv = os.path.expanduser(v)
|
41
|
+
dir = os.path.dirname(nv) # noqa
|
42
|
+
if not dir:
|
43
|
+
# relative pathname with no directory component
|
44
|
+
return nv
|
45
|
+
if os.path.isdir(dir):
|
46
|
+
return nv
|
47
|
+
raise ValueError(f'The directory named as part of the path {v} does not exist')
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import os
|
3
|
+
import typing as ta
|
4
|
+
|
5
|
+
from .ostypes import Rc
|
6
|
+
from .signals import sig_name
|
7
|
+
|
8
|
+
|
9
|
+
##
|
10
|
+
|
11
|
+
|
12
|
+
def real_exit(code: Rc) -> None:
|
13
|
+
os._exit(code) # noqa
|
14
|
+
|
15
|
+
|
16
|
+
##
|
17
|
+
|
18
|
+
|
19
|
+
def decode_wait_status(sts: int) -> ta.Tuple[Rc, str]:
|
20
|
+
"""
|
21
|
+
Decode the status returned by wait() or waitpid().
|
22
|
+
|
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. It is the caller's responsibility to display the message.
|
25
|
+
"""
|
26
|
+
|
27
|
+
if os.WIFEXITED(sts):
|
28
|
+
es = os.WEXITSTATUS(sts) & 0xffff
|
29
|
+
msg = f'exit status {es}'
|
30
|
+
return Rc(es), msg
|
31
|
+
|
32
|
+
elif os.WIFSIGNALED(sts):
|
33
|
+
sig = os.WTERMSIG(sts)
|
34
|
+
msg = f'terminated by {sig_name(sig)}'
|
35
|
+
if hasattr(os, 'WCOREDUMP'):
|
36
|
+
iscore = os.WCOREDUMP(sts)
|
37
|
+
else:
|
38
|
+
iscore = bool(sts & 0x80)
|
39
|
+
if iscore:
|
40
|
+
msg += ' (core dumped)'
|
41
|
+
return Rc(-1), msg
|
42
|
+
|
43
|
+
else:
|
44
|
+
msg = 'unknown termination cause 0x%04x' % sts # noqa
|
45
|
+
return Rc(-1), msg
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import signal
|
3
|
+
import typing as ta
|
4
|
+
|
5
|
+
|
6
|
+
##
|
7
|
+
|
8
|
+
|
9
|
+
_SIGS_BY_NUM: ta.Mapping[int, signal.Signals] = {s.value: s for s in signal.Signals}
|
10
|
+
_SIGS_BY_NAME: ta.Mapping[str, signal.Signals] = {s.name: s for s in signal.Signals}
|
11
|
+
|
12
|
+
|
13
|
+
def sig_num(value: ta.Union[int, str]) -> int:
|
14
|
+
try:
|
15
|
+
num = int(value)
|
16
|
+
|
17
|
+
except (ValueError, TypeError):
|
18
|
+
name = value.strip().upper() # type: ignore
|
19
|
+
if not name.startswith('SIG'):
|
20
|
+
name = f'SIG{name}'
|
21
|
+
|
22
|
+
if (sn := _SIGS_BY_NAME.get(name)) is None:
|
23
|
+
raise ValueError(f'value {value!r} is not a valid signal name') # noqa
|
24
|
+
num = sn
|
25
|
+
|
26
|
+
if num not in _SIGS_BY_NUM:
|
27
|
+
raise ValueError(f'value {value!r} is not a valid signal number')
|
28
|
+
|
29
|
+
return num
|
30
|
+
|
31
|
+
|
32
|
+
def sig_name(num: int) -> str:
|
33
|
+
if (sig := _SIGS_BY_NUM.get(num)) is not None:
|
34
|
+
return sig.name
|
35
|
+
return f'signal {sig}'
|
36
|
+
|
37
|
+
|
38
|
+
##
|
39
|
+
|
40
|
+
|
41
|
+
class SignalReceiver:
|
42
|
+
def __init__(self) -> None:
|
43
|
+
super().__init__()
|
44
|
+
|
45
|
+
self._signals_recvd: ta.List[int] = []
|
46
|
+
|
47
|
+
def receive(self, sig: int, frame: ta.Any = None) -> None:
|
48
|
+
if sig not in self._signals_recvd:
|
49
|
+
self._signals_recvd.append(sig)
|
50
|
+
|
51
|
+
def install(self, *sigs: int) -> None:
|
52
|
+
for sig in sigs:
|
53
|
+
signal.signal(sig, self.receive)
|
54
|
+
|
55
|
+
def get_signal(self) -> ta.Optional[int]:
|
56
|
+
if self._signals_recvd:
|
57
|
+
sig = self._signals_recvd.pop(0)
|
58
|
+
else:
|
59
|
+
sig = None
|
60
|
+
return sig
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
|
5
|
+
##
|
6
|
+
|
7
|
+
|
8
|
+
def as_bytes(s: ta.Union[str, bytes], encoding: str = 'utf8') -> bytes:
|
9
|
+
if isinstance(s, bytes):
|
10
|
+
return s
|
11
|
+
else:
|
12
|
+
return s.encode(encoding)
|
13
|
+
|
14
|
+
|
15
|
+
@ta.overload
|
16
|
+
def find_prefix_at_end(haystack: str, needle: str) -> int:
|
17
|
+
...
|
18
|
+
|
19
|
+
|
20
|
+
@ta.overload
|
21
|
+
def find_prefix_at_end(haystack: bytes, needle: bytes) -> int:
|
22
|
+
...
|
23
|
+
|
24
|
+
|
25
|
+
def find_prefix_at_end(haystack, needle):
|
26
|
+
l = len(needle) - 1
|
27
|
+
while l and not haystack.endswith(needle[:l]):
|
28
|
+
l -= 1
|
29
|
+
return l
|
30
|
+
|
31
|
+
|
32
|
+
##
|
33
|
+
|
34
|
+
|
35
|
+
ANSI_ESCAPE_BEGIN = b'\x1b['
|
36
|
+
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')
|
37
|
+
|
38
|
+
|
39
|
+
def strip_escapes(s: bytes) -> bytes:
|
40
|
+
"""Remove all ANSI color escapes from the given string."""
|
41
|
+
|
42
|
+
result = b''
|
43
|
+
show = 1
|
44
|
+
i = 0
|
45
|
+
l = len(s)
|
46
|
+
while i < l:
|
47
|
+
if show == 0 and s[i:i + 1] in ANSI_TERMINATORS:
|
48
|
+
show = 1
|
49
|
+
elif show:
|
50
|
+
n = s.find(ANSI_ESCAPE_BEGIN, i)
|
51
|
+
if n == -1:
|
52
|
+
return result + s[i:]
|
53
|
+
else:
|
54
|
+
result = result + s[i:n]
|
55
|
+
i = n
|
56
|
+
show = 0
|
57
|
+
i += 1
|
58
|
+
return result
|
59
|
+
|
60
|
+
|
61
|
+
##
|
62
|
+
|
63
|
+
|
64
|
+
class SuffixMultiplier:
|
65
|
+
# d is a dictionary of suffixes to integer multipliers. If no suffixes match, default is the multiplier. Matches
|
66
|
+
# are case insensitive. Return values are in the fundamental unit.
|
67
|
+
def __init__(self, d, default=1):
|
68
|
+
super().__init__()
|
69
|
+
self._d = d
|
70
|
+
self._default = default
|
71
|
+
# all keys must be the same size
|
72
|
+
self._keysz = None
|
73
|
+
for k in d:
|
74
|
+
if self._keysz is None:
|
75
|
+
self._keysz = len(k)
|
76
|
+
elif self._keysz != len(k): # type: ignore
|
77
|
+
raise ValueError(k)
|
78
|
+
|
79
|
+
def __call__(self, v: ta.Union[str, int]) -> int:
|
80
|
+
if isinstance(v, int):
|
81
|
+
return v
|
82
|
+
v = v.lower()
|
83
|
+
for s, m in self._d.items():
|
84
|
+
if v[-self._keysz:] == s: # type: ignore
|
85
|
+
return int(v[:-self._keysz]) * m # type: ignore
|
86
|
+
return int(v) * self._default
|
87
|
+
|
88
|
+
|
89
|
+
parse_bytes_size = SuffixMultiplier({
|
90
|
+
'kb': 1024,
|
91
|
+
'mb': 1024 * 1024,
|
92
|
+
'gb': 1024 * 1024 * 1024,
|
93
|
+
})
|
94
|
+
|
95
|
+
|
96
|
+
#
|
97
|
+
|
98
|
+
|
99
|
+
def parse_octal(arg: ta.Union[str, int]) -> int:
|
100
|
+
if isinstance(arg, int):
|
101
|
+
return arg
|
102
|
+
try:
|
103
|
+
return int(arg, 8)
|
104
|
+
except (TypeError, ValueError):
|
105
|
+
raise ValueError(f'{arg} can not be converted to an octal type') # noqa
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# ruff: noqa: UP007
|
2
|
+
import dataclasses as dc
|
3
|
+
import grp
|
4
|
+
import pwd
|
5
|
+
|
6
|
+
from .ostypes import Gid
|
7
|
+
from .ostypes import Uid
|
8
|
+
|
9
|
+
|
10
|
+
##
|
11
|
+
|
12
|
+
|
13
|
+
def name_to_uid(name: str) -> Uid:
|
14
|
+
try:
|
15
|
+
uid = int(name)
|
16
|
+
except ValueError:
|
17
|
+
try:
|
18
|
+
pwdrec = pwd.getpwnam(name)
|
19
|
+
except KeyError:
|
20
|
+
raise ValueError(f'Invalid user name {name}') # noqa
|
21
|
+
uid = pwdrec[2]
|
22
|
+
else:
|
23
|
+
try:
|
24
|
+
pwd.getpwuid(uid) # check if uid is valid
|
25
|
+
except KeyError:
|
26
|
+
raise ValueError(f'Invalid user id {name}') # noqa
|
27
|
+
return Uid(uid)
|
28
|
+
|
29
|
+
|
30
|
+
def name_to_gid(name: str) -> Gid:
|
31
|
+
try:
|
32
|
+
gid = int(name)
|
33
|
+
except ValueError:
|
34
|
+
try:
|
35
|
+
grprec = grp.getgrnam(name)
|
36
|
+
except KeyError:
|
37
|
+
raise ValueError(f'Invalid group name {name}') # noqa
|
38
|
+
gid = grprec[2]
|
39
|
+
else:
|
40
|
+
try:
|
41
|
+
grp.getgrgid(gid) # check if gid is valid
|
42
|
+
except KeyError:
|
43
|
+
raise ValueError(f'Invalid group id {name}') # noqa
|
44
|
+
return Gid(gid)
|
45
|
+
|
46
|
+
|
47
|
+
def gid_for_uid(uid: Uid) -> Gid:
|
48
|
+
pwrec = pwd.getpwuid(uid)
|
49
|
+
return Gid(pwrec[3])
|
50
|
+
|
51
|
+
|
52
|
+
##
|
53
|
+
|
54
|
+
|
55
|
+
@dc.dataclass(frozen=True)
|
56
|
+
class User:
|
57
|
+
name: str
|
58
|
+
uid: Uid
|
59
|
+
gid: Gid
|
60
|
+
|
61
|
+
|
62
|
+
def get_user(name: str) -> User:
|
63
|
+
return User(
|
64
|
+
name=name,
|
65
|
+
uid=(uid := name_to_uid(name)),
|
66
|
+
gid=gid_for_uid(uid),
|
67
|
+
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ominfra
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev128
|
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.dev128
|
16
|
+
Requires-Dist: omlish==0.0.0.dev128
|
17
17
|
Provides-Extra: all
|
18
18
|
Requires-Dist: paramiko~=3.5; extra == "all"
|
19
19
|
Requires-Dist: asyncssh~=2.18; extra == "all"
|
@@ -8,7 +8,7 @@ ominfra/threadworkers.py,sha256=oX4ubZn7h932saXpRIJu2MNhBExgGGMuGhdXarZxLJw,4948
|
|
8
8
|
ominfra/clouds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
9
|
ominfra/clouds/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
10
|
ominfra/clouds/aws/__main__.py,sha256=HXMoxEl9KHhv6zOOPQxiJAftfR2SjBqeVTYw-og9aFw,163
|
11
|
-
ominfra/clouds/aws/auth.py,sha256=
|
11
|
+
ominfra/clouds/aws/auth.py,sha256=qXS3X6Zl0FHqvfv1MNVYK1iy1TLbN0Md6S8N4Goq6kU,6204
|
12
12
|
ominfra/clouds/aws/cli.py,sha256=OJVVLIwSy1378drkgP1ke_JltbyzBmnrB_Lom6A83os,510
|
13
13
|
ominfra/clouds/aws/dataclasses.py,sha256=rKhtJKJ0JhMssU9n9CABX_JaUiokIboEATJ9TZgZQ6A,3868
|
14
14
|
ominfra/clouds/aws/logs.py,sha256=z9ouU2IYXNHsl7_Whbjs1FGtlUwsEq0RV8LNrM_QNTE,5471
|
@@ -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=osVBYirgpX1iJKyLHf7JwKD3AhPqJrnCrjI4qVrNFJo,34662
|
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=RyuYQCytPyRqBx8qtzrMiP8xa9C9E3nF2fpLTubt5v8,24180
|
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,39 +56,55 @@ 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=86bIzkhi5YLmtxQYyk8SBwPv8fCCfdu2NHHlxug4ACk,28498
|
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=UpwV8P1ZE8ywXW-8xpCaTCBRWe94BuG_MS1CXfD3wcw,128547
|
64
|
+
ominfra/scripts/supervisor.py,sha256=ZqUDlxRxSML5Ty0sOKuils35km5-9xjYBQF4yQDnVaY,222164
|
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/context.py,sha256=
|
70
|
-
ominfra/supervisor/
|
71
|
-
ominfra/supervisor/
|
68
|
+
ominfra/supervisor/configs.py,sha256=AhBlbifwDXc0acEhcbdv9jphJL-SBFODFDAWDVckzAE,3945
|
69
|
+
ominfra/supervisor/context.py,sha256=UDJc0mVHHFg3T7MyO7gehWX1wwmFvw-7xeKLl-cC8jc,2595
|
70
|
+
ominfra/supervisor/dispatchers.py,sha256=qWtVLx-4H3I-Io7OPcVgRpIYehGsA4q3Duo5ZWdUM4Y,970
|
71
|
+
ominfra/supervisor/dispatchersimpl.py,sha256=t1VFcofj1kTH1q13Z-S1OUTXixPwgSqJkh5A5IkHKPA,10956
|
72
72
|
ominfra/supervisor/events.py,sha256=w3HQFrq-SuroYWoQfNFYeU1phnTvHTgsAqA6TGtAafI,6593
|
73
73
|
ominfra/supervisor/exceptions.py,sha256=Qbu211H3CLlSmi9LsSikOwrcL5HgJP9ugvcKWlGTAoI,750
|
74
|
-
ominfra/supervisor/groups.py,sha256=
|
75
|
-
ominfra/supervisor/
|
76
|
-
ominfra/supervisor/
|
77
|
-
ominfra/supervisor/
|
78
|
-
ominfra/supervisor/
|
79
|
-
ominfra/supervisor/
|
74
|
+
ominfra/supervisor/groups.py,sha256=g5Zp_lkVhn1FSe6GSEPbaELincG5a46ctv1xpB-WmnQ,2163
|
75
|
+
ominfra/supervisor/groupsimpl.py,sha256=_5Mxf6VdVV375KgwcuUTpErUH4FBpmzbNm3vbGB_JaQ,2304
|
76
|
+
ominfra/supervisor/inject.py,sha256=ZCfloXxURjiVTutzudGFWybrVCvjDD_C3HayMATCMrY,3042
|
77
|
+
ominfra/supervisor/main.py,sha256=RCCpMX4D2RKT8vZMF82pENKpXfW3GUdNgMEUzUtpqL0,4140
|
78
|
+
ominfra/supervisor/pipes.py,sha256=XrJ9lD04tPdzZD3xhhYKxpBKHWhZ0Ii315E78bgj7ws,2233
|
79
|
+
ominfra/supervisor/poller.py,sha256=LnQVttPCm8a1UtnDvsho6zLw8NP-2_2VUiNM-d0w_FU,7776
|
80
|
+
ominfra/supervisor/privileges.py,sha256=bO7rJGT7cMOBALK_4D4NiQnOS5dOYb14Sz66R-ymG24,2071
|
81
|
+
ominfra/supervisor/process.py,sha256=UaubVxsxVqDnbuWVpTH0DTGbJGLO0vGJ9mNcvy2kCXM,217
|
82
|
+
ominfra/supervisor/processimpl.py,sha256=0i0P3gdxuJsgcvy2VTKN6-NYgcBjozUaPsA_tUcEmb4,18769
|
83
|
+
ominfra/supervisor/setup.py,sha256=7HwwwI-WT_Z0WjZ9_l5Orr4K298nKKhQ1f_ZgGsi9TU,622
|
84
|
+
ominfra/supervisor/setupimpl.py,sha256=S_YgCH3XzLsFIAriJROvDMUDh7OzVVJoxzEzCkbb4g4,9648
|
85
|
+
ominfra/supervisor/spawning.py,sha256=i1k3tmqWyU-KIN7kel-JVxTVGnLiTIVmZzlstJSZpjM,622
|
86
|
+
ominfra/supervisor/spawningimpl.py,sha256=0InDyRPh7gAEX07lg6eUYMymX0RikHOz_ieAghxKx8Y,11063
|
80
87
|
ominfra/supervisor/states.py,sha256=9yoNOSwalRcKEnCP9zG6tVS0oivo5tCeuH6AaaW7Jpc,890
|
81
|
-
ominfra/supervisor/supervisor.py,sha256=
|
82
|
-
ominfra/supervisor/types.py,sha256=
|
83
|
-
ominfra/supervisor/utils.py,sha256=
|
88
|
+
ominfra/supervisor/supervisor.py,sha256=3yBaGJHJGqDXlARjpHWg7371N6jb29HaFEI-_fSp-xU,12028
|
89
|
+
ominfra/supervisor/types.py,sha256=i2C7ZBvLqjVliIYAYQnPx2WwIQ14HIVV1hTUgB2mbBM,4740
|
90
|
+
ominfra/supervisor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
91
|
+
ominfra/supervisor/utils/collections.py,sha256=vcfmVYS4QngMdtEI1DvdRIcubmy55Wj40NCzW27_rIY,1361
|
92
|
+
ominfra/supervisor/utils/diag.py,sha256=ujz4gkW7p3wmbaKFM8Hz5eHEwpoUkbB8JeDvcHilCz0,705
|
93
|
+
ominfra/supervisor/utils/fds.py,sha256=lz8DWXzGYvu93dqhWK0WrhXrrJVQ_psoom4Nj_o8g2g,849
|
94
|
+
ominfra/supervisor/utils/fs.py,sha256=ABbNcsCpzSXAvq_ZZSCj61mj5kGnVuC4spUmoWenlqw,1155
|
95
|
+
ominfra/supervisor/utils/os.py,sha256=9fw--tpHOrSjGTCkUo1KRBgbGGxKW2va5xKw2cHwtRU,1096
|
96
|
+
ominfra/supervisor/utils/ostypes.py,sha256=B7VjwbzVesz9we9MztoSk8bH8sTxMIWtILy_Qde0G7w,164
|
97
|
+
ominfra/supervisor/utils/signals.py,sha256=uZkTvissbtq7TlJD4MkTiL3F-zyWmAFUuWQtFjsf0MI,1474
|
98
|
+
ominfra/supervisor/utils/strings.py,sha256=B0UOuVM_NIWmcznycmiEbwJ0lcoTGEd3Ir1AeLkBXeU,2478
|
99
|
+
ominfra/supervisor/utils/users.py,sha256=PRUhWy74WQCxix4BLNYcWW1i2mF1IyAxj1RzElnP4iM,1345
|
84
100
|
ominfra/tailscale/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
85
101
|
ominfra/tailscale/api.py,sha256=C5-t_b6jZXUWcy5k8bXm7CFnk73pSdrlMOgGDeGVrpw,1370
|
86
102
|
ominfra/tailscale/cli.py,sha256=DSGp4hn5xwOW-l_u_InKlSF6kIobxtUtVssf_73STs0,3567
|
87
103
|
ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
88
104
|
ominfra/tools/listresources.py,sha256=4qVg5txsb10EHhvqXXeM6gJ2jx9LbroEnPydDv1uXs0,6176
|
89
|
-
ominfra-0.0.0.
|
90
|
-
ominfra-0.0.0.
|
91
|
-
ominfra-0.0.0.
|
92
|
-
ominfra-0.0.0.
|
93
|
-
ominfra-0.0.0.
|
94
|
-
ominfra-0.0.0.
|
105
|
+
ominfra-0.0.0.dev128.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
106
|
+
ominfra-0.0.0.dev128.dist-info/METADATA,sha256=JV6Hw2ZOpDub73wDD4p69Qq9F6XbbKlthV7CmH6G_-k,731
|
107
|
+
ominfra-0.0.0.dev128.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
108
|
+
ominfra-0.0.0.dev128.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
|
109
|
+
ominfra-0.0.0.dev128.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
|
110
|
+
ominfra-0.0.0.dev128.dist-info/RECORD,,
|
ominfra/supervisor/datatypes.py
DELETED
@@ -1,175 +0,0 @@
|
|
1
|
-
# ruff: noqa: UP007
|
2
|
-
import grp
|
3
|
-
import logging
|
4
|
-
import os
|
5
|
-
import pwd
|
6
|
-
import signal
|
7
|
-
import typing as ta
|
8
|
-
|
9
|
-
|
10
|
-
class Automatic:
|
11
|
-
pass
|
12
|
-
|
13
|
-
|
14
|
-
class Syslog:
|
15
|
-
"""TODO deprecated; remove this special 'syslog' filename in the future"""
|
16
|
-
|
17
|
-
|
18
|
-
LOGFILE_NONES = ('none', 'off', None)
|
19
|
-
LOGFILE_AUTOS = (Automatic, 'auto')
|
20
|
-
LOGFILE_SYSLOGS = (Syslog, 'syslog')
|
21
|
-
|
22
|
-
|
23
|
-
def logfile_name(val):
|
24
|
-
if hasattr(val, 'lower'):
|
25
|
-
coerced = val.lower()
|
26
|
-
else:
|
27
|
-
coerced = val
|
28
|
-
|
29
|
-
if coerced in LOGFILE_NONES:
|
30
|
-
return None
|
31
|
-
elif coerced in LOGFILE_AUTOS:
|
32
|
-
return Automatic
|
33
|
-
elif coerced in LOGFILE_SYSLOGS:
|
34
|
-
return Syslog
|
35
|
-
else:
|
36
|
-
return existing_dirpath(val)
|
37
|
-
|
38
|
-
|
39
|
-
def name_to_uid(name: str) -> int:
|
40
|
-
try:
|
41
|
-
uid = int(name)
|
42
|
-
except ValueError:
|
43
|
-
try:
|
44
|
-
pwdrec = pwd.getpwnam(name)
|
45
|
-
except KeyError:
|
46
|
-
raise ValueError(f'Invalid user name {name}') # noqa
|
47
|
-
uid = pwdrec[2]
|
48
|
-
else:
|
49
|
-
try:
|
50
|
-
pwd.getpwuid(uid) # check if uid is valid
|
51
|
-
except KeyError:
|
52
|
-
raise ValueError(f'Invalid user id {name}') # noqa
|
53
|
-
return uid
|
54
|
-
|
55
|
-
|
56
|
-
def name_to_gid(name: str) -> int:
|
57
|
-
try:
|
58
|
-
gid = int(name)
|
59
|
-
except ValueError:
|
60
|
-
try:
|
61
|
-
grprec = grp.getgrnam(name)
|
62
|
-
except KeyError:
|
63
|
-
raise ValueError(f'Invalid group name {name}') # noqa
|
64
|
-
gid = grprec[2]
|
65
|
-
else:
|
66
|
-
try:
|
67
|
-
grp.getgrgid(gid) # check if gid is valid
|
68
|
-
except KeyError:
|
69
|
-
raise ValueError(f'Invalid group id {name}') # noqa
|
70
|
-
return gid
|
71
|
-
|
72
|
-
|
73
|
-
def gid_for_uid(uid: int) -> int:
|
74
|
-
pwrec = pwd.getpwuid(uid)
|
75
|
-
return pwrec[3]
|
76
|
-
|
77
|
-
|
78
|
-
def octal_type(arg: ta.Union[str, int]) -> int:
|
79
|
-
if isinstance(arg, int):
|
80
|
-
return arg
|
81
|
-
try:
|
82
|
-
return int(arg, 8)
|
83
|
-
except (TypeError, ValueError):
|
84
|
-
raise ValueError(f'{arg} can not be converted to an octal type') # noqa
|
85
|
-
|
86
|
-
|
87
|
-
def existing_directory(v: str) -> str:
|
88
|
-
nv = os.path.expanduser(v)
|
89
|
-
if os.path.isdir(nv):
|
90
|
-
return nv
|
91
|
-
raise ValueError(f'{v} is not an existing directory')
|
92
|
-
|
93
|
-
|
94
|
-
def existing_dirpath(v: str) -> str:
|
95
|
-
nv = os.path.expanduser(v)
|
96
|
-
dir = os.path.dirname(nv) # noqa
|
97
|
-
if not dir:
|
98
|
-
# relative pathname with no directory component
|
99
|
-
return nv
|
100
|
-
if os.path.isdir(dir):
|
101
|
-
return nv
|
102
|
-
raise ValueError(f'The directory named as part of the path {v} does not exist')
|
103
|
-
|
104
|
-
|
105
|
-
def logging_level(value: ta.Union[str, int]) -> int:
|
106
|
-
if isinstance(value, int):
|
107
|
-
return value
|
108
|
-
s = str(value).lower()
|
109
|
-
level = logging.getLevelNamesMapping().get(s.upper())
|
110
|
-
if level is None:
|
111
|
-
raise ValueError(f'bad logging level name {value!r}')
|
112
|
-
return level
|
113
|
-
|
114
|
-
|
115
|
-
class SuffixMultiplier:
|
116
|
-
# d is a dictionary of suffixes to integer multipliers. If no suffixes match, default is the multiplier. Matches
|
117
|
-
# are case insensitive. Return values are in the fundamental unit.
|
118
|
-
def __init__(self, d, default=1):
|
119
|
-
super().__init__()
|
120
|
-
self._d = d
|
121
|
-
self._default = default
|
122
|
-
# all keys must be the same size
|
123
|
-
self._keysz = None
|
124
|
-
for k in d:
|
125
|
-
if self._keysz is None:
|
126
|
-
self._keysz = len(k)
|
127
|
-
elif self._keysz != len(k): # type: ignore
|
128
|
-
raise ValueError(k)
|
129
|
-
|
130
|
-
def __call__(self, v: ta.Union[str, int]) -> int:
|
131
|
-
if isinstance(v, int):
|
132
|
-
return v
|
133
|
-
v = v.lower()
|
134
|
-
for s, m in self._d.items():
|
135
|
-
if v[-self._keysz:] == s: # type: ignore
|
136
|
-
return int(v[:-self._keysz]) * m # type: ignore
|
137
|
-
return int(v) * self._default
|
138
|
-
|
139
|
-
|
140
|
-
byte_size = SuffixMultiplier({
|
141
|
-
'kb': 1024,
|
142
|
-
'mb': 1024 * 1024,
|
143
|
-
'gb': 1024 * 1024 * 1024,
|
144
|
-
})
|
145
|
-
|
146
|
-
|
147
|
-
# all valid signal numbers
|
148
|
-
SIGNUMS = [getattr(signal, k) for k in dir(signal) if k.startswith('SIG')]
|
149
|
-
|
150
|
-
|
151
|
-
def signal_number(value: ta.Union[int, str]) -> int:
|
152
|
-
try:
|
153
|
-
num = int(value)
|
154
|
-
|
155
|
-
except (ValueError, TypeError):
|
156
|
-
name = value.strip().upper() # type: ignore
|
157
|
-
if not name.startswith('SIG'):
|
158
|
-
name = f'SIG{name}'
|
159
|
-
|
160
|
-
num = getattr(signal, name, None) # type: ignore
|
161
|
-
if num is None:
|
162
|
-
raise ValueError(f'value {value!r} is not a valid signal name') # noqa
|
163
|
-
|
164
|
-
if num not in SIGNUMS:
|
165
|
-
raise ValueError(f'value {value!r} is not a valid signal number')
|
166
|
-
|
167
|
-
return num
|
168
|
-
|
169
|
-
|
170
|
-
class RestartWhenExitUnexpected:
|
171
|
-
pass
|
172
|
-
|
173
|
-
|
174
|
-
class RestartUnconditionally:
|
175
|
-
pass
|
ominfra/supervisor/signals.py
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
# ruff: noqa: UP006 UP007
|
2
|
-
import signal
|
3
|
-
import typing as ta
|
4
|
-
|
5
|
-
|
6
|
-
##
|
7
|
-
|
8
|
-
|
9
|
-
_SIG_NAMES: ta.Optional[ta.Mapping[int, str]] = None
|
10
|
-
|
11
|
-
|
12
|
-
def sig_name(sig: int) -> str:
|
13
|
-
global _SIG_NAMES
|
14
|
-
if _SIG_NAMES is None:
|
15
|
-
_SIG_NAMES = _init_sig_names()
|
16
|
-
return _SIG_NAMES.get(sig) or 'signal %d' % sig
|
17
|
-
|
18
|
-
|
19
|
-
def _init_sig_names() -> ta.Dict[int, str]:
|
20
|
-
d = {}
|
21
|
-
for k, v in signal.__dict__.items(): # noqa
|
22
|
-
k_startswith = getattr(k, 'startswith', None)
|
23
|
-
if k_startswith is None:
|
24
|
-
continue
|
25
|
-
if k_startswith('SIG') and not k_startswith('SIG_'):
|
26
|
-
d[v] = k
|
27
|
-
return d
|
28
|
-
|
29
|
-
|
30
|
-
##
|
31
|
-
|
32
|
-
|
33
|
-
class SignalReceiver:
|
34
|
-
def __init__(self) -> None:
|
35
|
-
super().__init__()
|
36
|
-
|
37
|
-
self._signals_recvd: ta.List[int] = []
|
38
|
-
|
39
|
-
def receive(self, sig: int, frame: ta.Any) -> None:
|
40
|
-
if sig not in self._signals_recvd:
|
41
|
-
self._signals_recvd.append(sig)
|
42
|
-
|
43
|
-
def install(self, *sigs: int) -> None:
|
44
|
-
for sig in sigs:
|
45
|
-
signal.signal(sig, self.receive)
|
46
|
-
|
47
|
-
def get_signal(self) -> ta.Optional[int]:
|
48
|
-
if self._signals_recvd:
|
49
|
-
sig = self._signals_recvd.pop(0)
|
50
|
-
else:
|
51
|
-
sig = None
|
52
|
-
return sig
|