ominfra 0.0.0.dev139__py3-none-any.whl → 0.0.0.dev140__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- ominfra/manage/commands/base.py +9 -7
- ominfra/manage/commands/subprocess.py +20 -15
- ominfra/manage/main.py +61 -120
- ominfra/manage/payload.py +35 -0
- ominfra/manage/spawning.py +100 -0
- ominfra/pyremote.py +18 -8
- ominfra/scripts/journald2aws.py +7 -0
- ominfra/scripts/manage.py +236 -141
- ominfra/scripts/supervisor.py +7 -0
- {ominfra-0.0.0.dev139.dist-info → ominfra-0.0.0.dev140.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev139.dist-info → ominfra-0.0.0.dev140.dist-info}/RECORD +15 -13
- {ominfra-0.0.0.dev139.dist-info → ominfra-0.0.0.dev140.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev139.dist-info → ominfra-0.0.0.dev140.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev139.dist-info → ominfra-0.0.0.dev140.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev139.dist-info → ominfra-0.0.0.dev140.dist-info}/top_level.txt +0 -0
ominfra/manage/commands/base.py
CHANGED
@@ -4,22 +4,24 @@ import dataclasses as dc
|
|
4
4
|
import typing as ta
|
5
5
|
|
6
6
|
|
7
|
-
|
7
|
+
CommandT = ta.TypeVar('CommandT', bound='Command')
|
8
8
|
CommandOutputT = ta.TypeVar('CommandOutputT', bound='Command.Output')
|
9
9
|
|
10
10
|
|
11
11
|
##
|
12
12
|
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
class Input(abc.ABC): # noqa
|
17
|
-
pass
|
18
|
-
|
14
|
+
@dc.dataclass(frozen=True)
|
15
|
+
class Command(abc.ABC, ta.Generic[CommandOutputT]):
|
19
16
|
@dc.dataclass(frozen=True)
|
20
17
|
class Output(abc.ABC): # noqa
|
21
18
|
pass
|
22
19
|
|
20
|
+
|
21
|
+
##
|
22
|
+
|
23
|
+
|
24
|
+
class CommandExecutor(abc.ABC, ta.Generic[CommandT, CommandOutputT]):
|
23
25
|
@abc.abstractmethod
|
24
|
-
def
|
26
|
+
def execute(self, i: CommandT) -> CommandOutputT:
|
25
27
|
raise NotImplementedError
|
@@ -8,29 +8,29 @@ import typing as ta
|
|
8
8
|
from omlish.lite.subprocesses import subprocess_maybe_shell_wrap_exec
|
9
9
|
|
10
10
|
from .base import Command
|
11
|
+
from .base import CommandExecutor
|
11
12
|
|
12
13
|
|
13
14
|
##
|
14
15
|
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
args: ta.Sequence[str]
|
17
|
+
@dc.dataclass(frozen=True)
|
18
|
+
class SubprocessCommand(Command['SubprocessCommand.Output']):
|
19
|
+
args: ta.Sequence[str]
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
shell: bool = False
|
22
|
+
cwd: ta.Optional[str] = None
|
23
|
+
env: ta.Optional[ta.Mapping[str, str]] = None
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
capture_stdout: bool = False
|
26
|
+
capture_stderr: bool = False
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
input: ta.Optional[bytes] = None
|
29
|
+
timeout: ta.Optional[float] = None
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
def __post_init__(self) -> None:
|
32
|
+
if isinstance(self.args, str):
|
33
|
+
raise TypeError(self.args)
|
34
34
|
|
35
35
|
@dc.dataclass(frozen=True)
|
36
36
|
class Output(Command.Output):
|
@@ -42,7 +42,12 @@ class SubprocessCommand(Command['SubprocessCommand.Input', 'SubprocessCommand.Ou
|
|
42
42
|
stdout: ta.Optional[bytes] = None
|
43
43
|
stderr: ta.Optional[bytes] = None
|
44
44
|
|
45
|
-
|
45
|
+
|
46
|
+
##
|
47
|
+
|
48
|
+
|
49
|
+
class SubprocessCommandExecutor(CommandExecutor[SubprocessCommand, SubprocessCommand.Output]):
|
50
|
+
def execute(self, inp: SubprocessCommand) -> SubprocessCommand.Output:
|
46
51
|
proc = subprocess.Popen(
|
47
52
|
subprocess_maybe_shell_wrap_exec(*inp.args),
|
48
53
|
|
ominfra/manage/main.py
CHANGED
@@ -3,25 +3,19 @@
|
|
3
3
|
# ruff: noqa: UP006 UP007
|
4
4
|
"""
|
5
5
|
manage.py -s 'docker run -i python:3.12'
|
6
|
-
manage.py -
|
6
|
+
manage.py -s 'ssh -i /foo/bar.pem foo@bar.baz' -q --python=python3.8
|
7
7
|
"""
|
8
|
-
import inspect
|
9
8
|
import json
|
10
|
-
import shlex
|
11
9
|
import struct
|
12
|
-
import subprocess
|
13
|
-
import sys
|
14
10
|
import typing as ta
|
15
11
|
|
16
|
-
from omlish.lite.cached import
|
17
|
-
from omlish.lite.check import check_not_none
|
12
|
+
from omlish.lite.cached import static_init
|
18
13
|
from omlish.lite.json import json_dumps_compact
|
19
14
|
from omlish.lite.marshal import PolymorphicObjMarshaler
|
20
15
|
from omlish.lite.marshal import get_obj_marshaler
|
21
16
|
from omlish.lite.marshal import marshal_obj
|
22
17
|
from omlish.lite.marshal import register_opj_marshaler
|
23
18
|
from omlish.lite.marshal import unmarshal_obj
|
24
|
-
from omlish.lite.subprocesses import subprocess_maybe_shell_wrap_exec
|
25
19
|
|
26
20
|
from ..pyremote import PyremoteBootstrapDriver
|
27
21
|
from ..pyremote import PyremoteBootstrapOptions
|
@@ -29,6 +23,9 @@ from ..pyremote import pyremote_bootstrap_finalize
|
|
29
23
|
from ..pyremote import pyremote_build_bootstrap_cmd
|
30
24
|
from .commands.base import Command
|
31
25
|
from .commands.subprocess import SubprocessCommand
|
26
|
+
from .commands.subprocess import SubprocessCommandExecutor
|
27
|
+
from .payload import get_payload_src
|
28
|
+
from .spawning import PySpawner
|
32
29
|
|
33
30
|
|
34
31
|
##
|
@@ -39,29 +36,23 @@ _COMMAND_TYPES = {
|
|
39
36
|
}
|
40
37
|
|
41
38
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
cty.Output,
|
59
|
-
k,
|
60
|
-
get_obj_marshaler(cty.Output),
|
39
|
+
@static_init
|
40
|
+
def _register_command_marshaling() -> None:
|
41
|
+
for fn in [
|
42
|
+
lambda c: c,
|
43
|
+
lambda c: c.Output,
|
44
|
+
]:
|
45
|
+
register_opj_marshaler(
|
46
|
+
fn(Command),
|
47
|
+
PolymorphicObjMarshaler.of([
|
48
|
+
PolymorphicObjMarshaler.Impl(
|
49
|
+
fn(cty),
|
50
|
+
k,
|
51
|
+
get_obj_marshaler(fn(cty)),
|
52
|
+
)
|
53
|
+
for k, cty in _COMMAND_TYPES.items()
|
54
|
+
]),
|
61
55
|
)
|
62
|
-
for k, cty in _COMMAND_TYPES.items()
|
63
|
-
]),
|
64
|
-
)
|
65
56
|
|
66
57
|
|
67
58
|
##
|
@@ -99,12 +90,12 @@ def _remote_main() -> None:
|
|
99
90
|
rt = pyremote_bootstrap_finalize() # noqa
|
100
91
|
|
101
92
|
while True:
|
102
|
-
i = _recv_obj(rt.input, Command
|
93
|
+
i = _recv_obj(rt.input, Command)
|
103
94
|
if i is None:
|
104
95
|
break
|
105
96
|
|
106
|
-
if isinstance(i, SubprocessCommand
|
107
|
-
o =
|
97
|
+
if isinstance(i, SubprocessCommand):
|
98
|
+
o = SubprocessCommandExecutor().execute(i) # noqa
|
108
99
|
else:
|
109
100
|
raise TypeError(i)
|
110
101
|
|
@@ -114,38 +105,6 @@ def _remote_main() -> None:
|
|
114
105
|
##
|
115
106
|
|
116
107
|
|
117
|
-
@cached_nullary
|
118
|
-
def _get_self_src() -> str:
|
119
|
-
return inspect.getsource(sys.modules[__name__])
|
120
|
-
|
121
|
-
|
122
|
-
def _is_src_amalg(src: str) -> bool:
|
123
|
-
for l in src.splitlines(): # noqa
|
124
|
-
if l.startswith('# @omlish-amalg-output '):
|
125
|
-
return True
|
126
|
-
return False
|
127
|
-
|
128
|
-
|
129
|
-
@cached_nullary
|
130
|
-
def _is_self_amalg() -> bool:
|
131
|
-
return _is_src_amalg(_get_self_src())
|
132
|
-
|
133
|
-
|
134
|
-
def _get_amalg_src(*, amalg_file: ta.Optional[str]) -> str:
|
135
|
-
if amalg_file is not None:
|
136
|
-
with open(amalg_file) as f:
|
137
|
-
return f.read()
|
138
|
-
|
139
|
-
if _is_self_amalg():
|
140
|
-
return _get_self_src()
|
141
|
-
|
142
|
-
import importlib.resources
|
143
|
-
return importlib.resources.files(__package__.split('.')[0] + '.scripts').joinpath('manage.py').read_text()
|
144
|
-
|
145
|
-
|
146
|
-
##
|
147
|
-
|
148
|
-
|
149
108
|
def _main() -> None:
|
150
109
|
import argparse
|
151
110
|
|
@@ -154,19 +113,20 @@ def _main() -> None:
|
|
154
113
|
parser.add_argument('-s', '--shell')
|
155
114
|
parser.add_argument('-q', '--shell-quote', action='store_true')
|
156
115
|
parser.add_argument('--python', default='python3')
|
157
|
-
parser.add_argument('--
|
116
|
+
parser.add_argument('--debug', action='store_true')
|
117
|
+
parser.add_argument('--_payload-file')
|
158
118
|
|
159
119
|
args = parser.parse_args()
|
160
120
|
|
161
121
|
#
|
162
122
|
|
163
|
-
|
123
|
+
payload_src = get_payload_src(file=args._payload_file) # noqa
|
164
124
|
|
165
125
|
#
|
166
126
|
|
167
127
|
remote_src = '\n\n'.join([
|
168
128
|
'__name__ = "__remote__"',
|
169
|
-
|
129
|
+
payload_src,
|
170
130
|
'_remote_main()',
|
171
131
|
])
|
172
132
|
|
@@ -174,60 +134,41 @@ def _main() -> None:
|
|
174
134
|
|
175
135
|
bs_src = pyremote_build_bootstrap_cmd(__package__ or 'manage')
|
176
136
|
|
177
|
-
if args.shell is not None:
|
178
|
-
sh_src = f'{args.python} -c {shlex.quote(bs_src)}'
|
179
|
-
if args.shell_quote:
|
180
|
-
sh_src = shlex.quote(sh_src)
|
181
|
-
sh_cmd = f'{args.shell} {sh_src}'
|
182
|
-
cmd = [sh_cmd]
|
183
|
-
shell = True
|
184
|
-
else:
|
185
|
-
cmd = [args.python, '-c', bs_src]
|
186
|
-
shell = False
|
187
|
-
|
188
|
-
proc = subprocess.Popen(
|
189
|
-
subprocess_maybe_shell_wrap_exec(*cmd),
|
190
|
-
shell=shell,
|
191
|
-
stdin=subprocess.PIPE,
|
192
|
-
stdout=subprocess.PIPE,
|
193
|
-
)
|
194
|
-
|
195
|
-
stdin = check_not_none(proc.stdin)
|
196
|
-
stdout = check_not_none(proc.stdout)
|
197
|
-
|
198
|
-
res = PyremoteBootstrapDriver( # noqa
|
199
|
-
remote_src,
|
200
|
-
PyremoteBootstrapOptions(
|
201
|
-
# debug=True,
|
202
|
-
),
|
203
|
-
).run(stdin, stdout)
|
204
|
-
# print(res)
|
205
|
-
|
206
137
|
#
|
207
138
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
139
|
+
spawner = PySpawner(
|
140
|
+
bs_src,
|
141
|
+
shell=args.shell,
|
142
|
+
shell_quote=args.shell_quote,
|
143
|
+
python=args.python,
|
144
|
+
)
|
145
|
+
with spawner.spawn() as proc:
|
146
|
+
res = PyremoteBootstrapDriver( # noqa
|
147
|
+
remote_src,
|
148
|
+
PyremoteBootstrapOptions(
|
149
|
+
debug=args.debug,
|
150
|
+
),
|
151
|
+
).run(proc.stdin, proc.stdout)
|
152
|
+
# print(res)
|
153
|
+
|
154
|
+
#
|
155
|
+
|
156
|
+
for ci in [
|
157
|
+
SubprocessCommand(
|
158
|
+
args=['python3', '-'],
|
159
|
+
input=b'print(1)\n',
|
160
|
+
capture_stdout=True,
|
161
|
+
),
|
162
|
+
SubprocessCommand(
|
163
|
+
args=['uname'],
|
164
|
+
capture_stdout=True,
|
165
|
+
),
|
166
|
+
]:
|
167
|
+
_send_obj(proc.stdin, ci, Command)
|
168
|
+
|
169
|
+
o = _recv_obj(proc.stdout, Command.Output)
|
170
|
+
|
171
|
+
print(o)
|
231
172
|
|
232
173
|
|
233
174
|
if __name__ == '__main__':
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import inspect
|
3
|
+
import sys
|
4
|
+
import typing as ta
|
5
|
+
|
6
|
+
from omlish.lite.cached import cached_nullary
|
7
|
+
|
8
|
+
|
9
|
+
@cached_nullary
|
10
|
+
def _get_self_src() -> str:
|
11
|
+
return inspect.getsource(sys.modules[__name__])
|
12
|
+
|
13
|
+
|
14
|
+
def _is_src_amalg(src: str) -> bool:
|
15
|
+
for l in src.splitlines(): # noqa
|
16
|
+
if l.startswith('# @omlish-amalg-output '):
|
17
|
+
return True
|
18
|
+
return False
|
19
|
+
|
20
|
+
|
21
|
+
@cached_nullary
|
22
|
+
def _is_self_amalg() -> bool:
|
23
|
+
return _is_src_amalg(_get_self_src())
|
24
|
+
|
25
|
+
|
26
|
+
def get_payload_src(*, file: ta.Optional[str]) -> str:
|
27
|
+
if file is not None:
|
28
|
+
with open(file) as f:
|
29
|
+
return f.read()
|
30
|
+
|
31
|
+
if _is_self_amalg():
|
32
|
+
return _get_self_src()
|
33
|
+
|
34
|
+
import importlib.resources
|
35
|
+
return importlib.resources.files(__package__.split('.')[0] + '.scripts').joinpath('manage.py').read_text()
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import contextlib
|
3
|
+
import dataclasses as dc
|
4
|
+
import shlex
|
5
|
+
import subprocess
|
6
|
+
import typing as ta
|
7
|
+
|
8
|
+
from omlish.lite.check import check_not_none
|
9
|
+
from omlish.lite.subprocesses import subprocess_maybe_shell_wrap_exec
|
10
|
+
|
11
|
+
|
12
|
+
class PySpawner:
|
13
|
+
DEFAULT_PYTHON = 'python3'
|
14
|
+
|
15
|
+
def __init__(
|
16
|
+
self,
|
17
|
+
src: str,
|
18
|
+
*,
|
19
|
+
shell: ta.Optional[str] = None,
|
20
|
+
shell_quote: bool = False,
|
21
|
+
python: str = DEFAULT_PYTHON,
|
22
|
+
stderr: ta.Optional[ta.Literal['pipe', 'stdout', 'devnull']] = None,
|
23
|
+
) -> None:
|
24
|
+
super().__init__()
|
25
|
+
|
26
|
+
self._src = src
|
27
|
+
self._shell = shell
|
28
|
+
self._shell_quote = shell_quote
|
29
|
+
self._python = python
|
30
|
+
self._stderr = stderr
|
31
|
+
|
32
|
+
#
|
33
|
+
|
34
|
+
class _PreparedCmd(ta.NamedTuple):
|
35
|
+
cmd: ta.Sequence[str]
|
36
|
+
shell: bool
|
37
|
+
|
38
|
+
def _prepare_cmd(self) -> _PreparedCmd:
|
39
|
+
if self._shell is not None:
|
40
|
+
sh_src = f'{self._python} -c {shlex.quote(self._src)}'
|
41
|
+
if self._shell_quote:
|
42
|
+
sh_src = shlex.quote(sh_src)
|
43
|
+
sh_cmd = f'{self._shell} {sh_src}'
|
44
|
+
return PySpawner._PreparedCmd(
|
45
|
+
cmd=[sh_cmd],
|
46
|
+
shell=True,
|
47
|
+
)
|
48
|
+
|
49
|
+
else:
|
50
|
+
return PySpawner._PreparedCmd(
|
51
|
+
cmd=[self._python, '-c', self._src],
|
52
|
+
shell=False,
|
53
|
+
)
|
54
|
+
|
55
|
+
#
|
56
|
+
|
57
|
+
_STDERR_KWARG_MAP: ta.Mapping[str, int] = {
|
58
|
+
'pipe': subprocess.PIPE,
|
59
|
+
'stdout': subprocess.STDOUT,
|
60
|
+
'devnull': subprocess.DEVNULL,
|
61
|
+
}
|
62
|
+
|
63
|
+
@dc.dataclass(frozen=True)
|
64
|
+
class Spawned:
|
65
|
+
stdin: ta.IO
|
66
|
+
stdout: ta.IO
|
67
|
+
stderr: ta.Optional[ta.IO]
|
68
|
+
|
69
|
+
@contextlib.contextmanager
|
70
|
+
def spawn(
|
71
|
+
self,
|
72
|
+
*,
|
73
|
+
timeout: ta.Optional[float] = None,
|
74
|
+
) -> ta.Generator[Spawned, None, None]:
|
75
|
+
pc = self._prepare_cmd()
|
76
|
+
|
77
|
+
with subprocess.Popen(
|
78
|
+
subprocess_maybe_shell_wrap_exec(*pc.cmd),
|
79
|
+
shell=pc.shell,
|
80
|
+
stdin=subprocess.PIPE,
|
81
|
+
stdout=subprocess.PIPE,
|
82
|
+
stderr=self._STDERR_KWARG_MAP[self._stderr] if self._stderr is not None else None,
|
83
|
+
) as proc:
|
84
|
+
stdin = check_not_none(proc.stdin)
|
85
|
+
stdout = check_not_none(proc.stdout)
|
86
|
+
|
87
|
+
try:
|
88
|
+
yield PySpawner.Spawned(
|
89
|
+
stdin=stdin,
|
90
|
+
stdout=stdout,
|
91
|
+
stderr=proc.stderr,
|
92
|
+
)
|
93
|
+
|
94
|
+
finally:
|
95
|
+
try:
|
96
|
+
stdin.close()
|
97
|
+
except BrokenPipeError:
|
98
|
+
pass
|
99
|
+
|
100
|
+
proc.wait(timeout)
|
ominfra/pyremote.py
CHANGED
@@ -132,6 +132,8 @@ _PYREMOTE_BOOTSTRAP_SRC_FD = 101
|
|
132
132
|
|
133
133
|
_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR = '_OPYR_CHILD_PID'
|
134
134
|
_PYREMOTE_BOOTSTRAP_ARGV0_VAR = '_OPYR_ARGV0'
|
135
|
+
_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR = '_OPYR_CONTEXT_NAME'
|
136
|
+
_PYREMOTE_BOOTSTRAP_SRC_FILE_VAR = '_OPYR_SRC_FILE'
|
135
137
|
_PYREMOTE_BOOTSTRAP_OPTIONS_JSON_VAR = '_OPYR_OPTIONS_JSON'
|
136
138
|
|
137
139
|
_PYREMOTE_BOOTSTRAP_ACK0 = b'OPYR000\n'
|
@@ -174,11 +176,10 @@ def _pyremote_bootstrap_main(context_name: str) -> None:
|
|
174
176
|
for f in [r0, w0, r1, w1]:
|
175
177
|
os.close(f)
|
176
178
|
|
177
|
-
# Save
|
179
|
+
# Save vars
|
178
180
|
os.environ[_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR] = str(cp)
|
179
|
-
|
180
|
-
# Save original argv0
|
181
181
|
os.environ[_PYREMOTE_BOOTSTRAP_ARGV0_VAR] = sys.executable
|
182
|
+
os.environ[_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR] = context_name
|
182
183
|
|
183
184
|
# Start repl reading stdin from r0
|
184
185
|
os.execl(sys.executable, sys.executable + (_PYREMOTE_BOOTSTRAP_PROC_TITLE_FMT % (context_name,)))
|
@@ -229,6 +230,7 @@ def pyremote_build_bootstrap_cmd(context_name: str) -> str:
|
|
229
230
|
|
230
231
|
'_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR',
|
231
232
|
'_PYREMOTE_BOOTSTRAP_ARGV0_VAR',
|
233
|
+
'_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR',
|
232
234
|
|
233
235
|
'_PYREMOTE_BOOTSTRAP_ACK0',
|
234
236
|
'_PYREMOTE_BOOTSTRAP_ACK1',
|
@@ -264,14 +266,15 @@ def pyremote_build_bootstrap_cmd(context_name: str) -> str:
|
|
264
266
|
class PyremotePayloadRuntime:
|
265
267
|
input: ta.BinaryIO
|
266
268
|
output: ta.BinaryIO
|
269
|
+
context_name: str
|
267
270
|
main_src: str
|
268
271
|
options: PyremoteBootstrapOptions
|
269
272
|
env_info: PyremoteEnvInfo
|
270
273
|
|
271
274
|
|
272
275
|
def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
|
273
|
-
# If
|
274
|
-
if
|
276
|
+
# If src file var is not present we need to do initial finalization
|
277
|
+
if _PYREMOTE_BOOTSTRAP_SRC_FILE_VAR not in os.environ:
|
275
278
|
# Read second copy of main src
|
276
279
|
r1 = os.fdopen(_PYREMOTE_BOOTSTRAP_SRC_FD, 'rb', 0)
|
277
280
|
main_src = r1.read().decode('utf-8')
|
@@ -295,11 +298,14 @@ def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
|
|
295
298
|
os.write(tfd, main_src.encode('utf-8'))
|
296
299
|
os.close(tfd)
|
297
300
|
|
298
|
-
# Set
|
301
|
+
# Set vars
|
302
|
+
os.environ[_PYREMOTE_BOOTSTRAP_SRC_FILE_VAR] = tfn
|
299
303
|
os.environ[_PYREMOTE_BOOTSTRAP_OPTIONS_JSON_VAR] = options_json.decode('utf-8')
|
300
304
|
|
301
305
|
# Re-exec temp file
|
302
|
-
os.
|
306
|
+
exe = os.environ[_PYREMOTE_BOOTSTRAP_ARGV0_VAR]
|
307
|
+
context_name = os.environ[_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR]
|
308
|
+
os.execl(exe, exe + (_PYREMOTE_BOOTSTRAP_PROC_TITLE_FMT % (context_name,)), tfn)
|
303
309
|
|
304
310
|
else:
|
305
311
|
# Load options json var
|
@@ -307,12 +313,15 @@ def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
|
|
307
313
|
options = PyremoteBootstrapOptions(**json.loads(options_json_str))
|
308
314
|
|
309
315
|
# Read temp source file
|
310
|
-
with open(
|
316
|
+
with open(os.environ.pop(_PYREMOTE_BOOTSTRAP_SRC_FILE_VAR)) as sf:
|
311
317
|
main_src = sf.read()
|
312
318
|
|
313
319
|
# Restore original argv0
|
314
320
|
sys.executable = os.environ.pop(_PYREMOTE_BOOTSTRAP_ARGV0_VAR)
|
315
321
|
|
322
|
+
# Grab context name
|
323
|
+
context_name = os.environ.pop(_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR)
|
324
|
+
|
316
325
|
# Write third ack
|
317
326
|
os.write(1, _PYREMOTE_BOOTSTRAP_ACK2)
|
318
327
|
|
@@ -335,6 +344,7 @@ def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
|
|
335
344
|
return PyremotePayloadRuntime(
|
336
345
|
input=input,
|
337
346
|
output=output,
|
347
|
+
context_name=context_name,
|
338
348
|
main_src=main_src,
|
339
349
|
options=options,
|
340
350
|
env_info=env_info,
|
ominfra/scripts/journald2aws.py
CHANGED
@@ -58,6 +58,7 @@ TomlPos = int # ta.TypeAlias
|
|
58
58
|
|
59
59
|
# ../../../../omlish/lite/cached.py
|
60
60
|
T = ta.TypeVar('T')
|
61
|
+
CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
|
61
62
|
|
62
63
|
# ../../../../omlish/lite/check.py
|
63
64
|
SizedT = ta.TypeVar('SizedT', bound=ta.Sized)
|
@@ -915,6 +916,12 @@ def cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
915
916
|
return _cached_nullary(fn)
|
916
917
|
|
917
918
|
|
919
|
+
def static_init(fn: CallableT) -> CallableT:
|
920
|
+
fn = cached_nullary(fn)
|
921
|
+
fn()
|
922
|
+
return fn
|
923
|
+
|
924
|
+
|
918
925
|
########################################
|
919
926
|
# ../../../../../omlish/lite/check.py
|
920
927
|
|
ominfra/scripts/manage.py
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
# ruff: noqa: N802 UP006 UP007 UP036
|
7
7
|
"""
|
8
8
|
manage.py -s 'docker run -i python:3.12'
|
9
|
-
manage.py -
|
9
|
+
manage.py -s 'ssh -i /foo/bar.pem foo@bar.baz' -q --python=python3.8
|
10
10
|
"""
|
11
11
|
import abc
|
12
12
|
import base64
|
@@ -49,11 +49,12 @@ if sys.version_info < (3, 8):
|
|
49
49
|
|
50
50
|
|
51
51
|
# commands/base.py
|
52
|
-
|
52
|
+
CommandT = ta.TypeVar('CommandT', bound='Command')
|
53
53
|
CommandOutputT = ta.TypeVar('CommandOutputT', bound='Command.Output')
|
54
54
|
|
55
55
|
# ../../omlish/lite/cached.py
|
56
56
|
T = ta.TypeVar('T')
|
57
|
+
CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
|
57
58
|
|
58
59
|
# ../../omlish/lite/check.py
|
59
60
|
SizedT = ta.TypeVar('SizedT', bound=ta.Sized)
|
@@ -66,17 +67,19 @@ SizedT = ta.TypeVar('SizedT', bound=ta.Sized)
|
|
66
67
|
##
|
67
68
|
|
68
69
|
|
69
|
-
|
70
|
-
|
71
|
-
class Input(abc.ABC): # noqa
|
72
|
-
pass
|
73
|
-
|
70
|
+
@dc.dataclass(frozen=True)
|
71
|
+
class Command(abc.ABC, ta.Generic[CommandOutputT]):
|
74
72
|
@dc.dataclass(frozen=True)
|
75
73
|
class Output(abc.ABC): # noqa
|
76
74
|
pass
|
77
75
|
|
76
|
+
|
77
|
+
##
|
78
|
+
|
79
|
+
|
80
|
+
class CommandExecutor(abc.ABC, ta.Generic[CommandT, CommandOutputT]):
|
78
81
|
@abc.abstractmethod
|
79
|
-
def
|
82
|
+
def execute(self, i: CommandT) -> CommandOutputT:
|
80
83
|
raise NotImplementedError
|
81
84
|
|
82
85
|
|
@@ -203,6 +206,8 @@ _PYREMOTE_BOOTSTRAP_SRC_FD = 101
|
|
203
206
|
|
204
207
|
_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR = '_OPYR_CHILD_PID'
|
205
208
|
_PYREMOTE_BOOTSTRAP_ARGV0_VAR = '_OPYR_ARGV0'
|
209
|
+
_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR = '_OPYR_CONTEXT_NAME'
|
210
|
+
_PYREMOTE_BOOTSTRAP_SRC_FILE_VAR = '_OPYR_SRC_FILE'
|
206
211
|
_PYREMOTE_BOOTSTRAP_OPTIONS_JSON_VAR = '_OPYR_OPTIONS_JSON'
|
207
212
|
|
208
213
|
_PYREMOTE_BOOTSTRAP_ACK0 = b'OPYR000\n'
|
@@ -245,11 +250,10 @@ def _pyremote_bootstrap_main(context_name: str) -> None:
|
|
245
250
|
for f in [r0, w0, r1, w1]:
|
246
251
|
os.close(f)
|
247
252
|
|
248
|
-
# Save
|
253
|
+
# Save vars
|
249
254
|
os.environ[_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR] = str(cp)
|
250
|
-
|
251
|
-
# Save original argv0
|
252
255
|
os.environ[_PYREMOTE_BOOTSTRAP_ARGV0_VAR] = sys.executable
|
256
|
+
os.environ[_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR] = context_name
|
253
257
|
|
254
258
|
# Start repl reading stdin from r0
|
255
259
|
os.execl(sys.executable, sys.executable + (_PYREMOTE_BOOTSTRAP_PROC_TITLE_FMT % (context_name,)))
|
@@ -300,6 +304,7 @@ def pyremote_build_bootstrap_cmd(context_name: str) -> str:
|
|
300
304
|
|
301
305
|
'_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR',
|
302
306
|
'_PYREMOTE_BOOTSTRAP_ARGV0_VAR',
|
307
|
+
'_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR',
|
303
308
|
|
304
309
|
'_PYREMOTE_BOOTSTRAP_ACK0',
|
305
310
|
'_PYREMOTE_BOOTSTRAP_ACK1',
|
@@ -335,14 +340,15 @@ def pyremote_build_bootstrap_cmd(context_name: str) -> str:
|
|
335
340
|
class PyremotePayloadRuntime:
|
336
341
|
input: ta.BinaryIO
|
337
342
|
output: ta.BinaryIO
|
343
|
+
context_name: str
|
338
344
|
main_src: str
|
339
345
|
options: PyremoteBootstrapOptions
|
340
346
|
env_info: PyremoteEnvInfo
|
341
347
|
|
342
348
|
|
343
349
|
def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
|
344
|
-
# If
|
345
|
-
if
|
350
|
+
# If src file var is not present we need to do initial finalization
|
351
|
+
if _PYREMOTE_BOOTSTRAP_SRC_FILE_VAR not in os.environ:
|
346
352
|
# Read second copy of main src
|
347
353
|
r1 = os.fdopen(_PYREMOTE_BOOTSTRAP_SRC_FD, 'rb', 0)
|
348
354
|
main_src = r1.read().decode('utf-8')
|
@@ -366,11 +372,14 @@ def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
|
|
366
372
|
os.write(tfd, main_src.encode('utf-8'))
|
367
373
|
os.close(tfd)
|
368
374
|
|
369
|
-
# Set
|
375
|
+
# Set vars
|
376
|
+
os.environ[_PYREMOTE_BOOTSTRAP_SRC_FILE_VAR] = tfn
|
370
377
|
os.environ[_PYREMOTE_BOOTSTRAP_OPTIONS_JSON_VAR] = options_json.decode('utf-8')
|
371
378
|
|
372
379
|
# Re-exec temp file
|
373
|
-
os.
|
380
|
+
exe = os.environ[_PYREMOTE_BOOTSTRAP_ARGV0_VAR]
|
381
|
+
context_name = os.environ[_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR]
|
382
|
+
os.execl(exe, exe + (_PYREMOTE_BOOTSTRAP_PROC_TITLE_FMT % (context_name,)), tfn)
|
374
383
|
|
375
384
|
else:
|
376
385
|
# Load options json var
|
@@ -378,12 +387,15 @@ def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
|
|
378
387
|
options = PyremoteBootstrapOptions(**json.loads(options_json_str))
|
379
388
|
|
380
389
|
# Read temp source file
|
381
|
-
with open(
|
390
|
+
with open(os.environ.pop(_PYREMOTE_BOOTSTRAP_SRC_FILE_VAR)) as sf:
|
382
391
|
main_src = sf.read()
|
383
392
|
|
384
393
|
# Restore original argv0
|
385
394
|
sys.executable = os.environ.pop(_PYREMOTE_BOOTSTRAP_ARGV0_VAR)
|
386
395
|
|
396
|
+
# Grab context name
|
397
|
+
context_name = os.environ.pop(_PYREMOTE_BOOTSTRAP_CONTEXT_NAME_VAR)
|
398
|
+
|
387
399
|
# Write third ack
|
388
400
|
os.write(1, _PYREMOTE_BOOTSTRAP_ACK2)
|
389
401
|
|
@@ -406,6 +418,7 @@ def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
|
|
406
418
|
return PyremotePayloadRuntime(
|
407
419
|
input=input,
|
408
420
|
output=output,
|
421
|
+
context_name=context_name,
|
409
422
|
main_src=main_src,
|
410
423
|
options=options,
|
411
424
|
env_info=env_info,
|
@@ -550,6 +563,12 @@ def cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
550
563
|
return _cached_nullary(fn)
|
551
564
|
|
552
565
|
|
566
|
+
def static_init(fn: CallableT) -> CallableT:
|
567
|
+
fn = cached_nullary(fn)
|
568
|
+
fn()
|
569
|
+
return fn
|
570
|
+
|
571
|
+
|
553
572
|
########################################
|
554
573
|
# ../../../omlish/lite/check.py
|
555
574
|
|
@@ -733,6 +752,39 @@ def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
|
|
733
752
|
todo.extend(reversed(cur.__subclasses__()))
|
734
753
|
|
735
754
|
|
755
|
+
########################################
|
756
|
+
# ../payload.py
|
757
|
+
|
758
|
+
|
759
|
+
@cached_nullary
|
760
|
+
def _get_self_src() -> str:
|
761
|
+
return inspect.getsource(sys.modules[__name__])
|
762
|
+
|
763
|
+
|
764
|
+
def _is_src_amalg(src: str) -> bool:
|
765
|
+
for l in src.splitlines(): # noqa
|
766
|
+
if l.startswith('# @omlish-amalg-output '):
|
767
|
+
return True
|
768
|
+
return False
|
769
|
+
|
770
|
+
|
771
|
+
@cached_nullary
|
772
|
+
def _is_self_amalg() -> bool:
|
773
|
+
return _is_src_amalg(_get_self_src())
|
774
|
+
|
775
|
+
|
776
|
+
def get_payload_src(*, file: ta.Optional[str]) -> str:
|
777
|
+
if file is not None:
|
778
|
+
with open(file) as f:
|
779
|
+
return f.read()
|
780
|
+
|
781
|
+
if _is_self_amalg():
|
782
|
+
return _get_self_src()
|
783
|
+
|
784
|
+
import importlib.resources
|
785
|
+
return importlib.resources.files(__package__.split('.')[0] + '.scripts').joinpath('manage.py').read_text()
|
786
|
+
|
787
|
+
|
736
788
|
########################################
|
737
789
|
# ../../../omlish/lite/logs.py
|
738
790
|
"""
|
@@ -1498,24 +1550,23 @@ def subprocess_close(
|
|
1498
1550
|
##
|
1499
1551
|
|
1500
1552
|
|
1501
|
-
|
1502
|
-
|
1503
|
-
|
1504
|
-
args: ta.Sequence[str]
|
1553
|
+
@dc.dataclass(frozen=True)
|
1554
|
+
class SubprocessCommand(Command['SubprocessCommand.Output']):
|
1555
|
+
args: ta.Sequence[str]
|
1505
1556
|
|
1506
|
-
|
1507
|
-
|
1508
|
-
|
1557
|
+
shell: bool = False
|
1558
|
+
cwd: ta.Optional[str] = None
|
1559
|
+
env: ta.Optional[ta.Mapping[str, str]] = None
|
1509
1560
|
|
1510
|
-
|
1511
|
-
|
1561
|
+
capture_stdout: bool = False
|
1562
|
+
capture_stderr: bool = False
|
1512
1563
|
|
1513
|
-
|
1514
|
-
|
1564
|
+
input: ta.Optional[bytes] = None
|
1565
|
+
timeout: ta.Optional[float] = None
|
1515
1566
|
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1567
|
+
def __post_init__(self) -> None:
|
1568
|
+
if isinstance(self.args, str):
|
1569
|
+
raise TypeError(self.args)
|
1519
1570
|
|
1520
1571
|
@dc.dataclass(frozen=True)
|
1521
1572
|
class Output(Command.Output):
|
@@ -1527,7 +1578,12 @@ class SubprocessCommand(Command['SubprocessCommand.Input', 'SubprocessCommand.Ou
|
|
1527
1578
|
stdout: ta.Optional[bytes] = None
|
1528
1579
|
stderr: ta.Optional[bytes] = None
|
1529
1580
|
|
1530
|
-
|
1581
|
+
|
1582
|
+
##
|
1583
|
+
|
1584
|
+
|
1585
|
+
class SubprocessCommandExecutor(CommandExecutor[SubprocessCommand, SubprocessCommand.Output]):
|
1586
|
+
def execute(self, inp: SubprocessCommand) -> SubprocessCommand.Output:
|
1531
1587
|
proc = subprocess.Popen(
|
1532
1588
|
subprocess_maybe_shell_wrap_exec(*inp.args),
|
1533
1589
|
|
@@ -1558,6 +1614,101 @@ class SubprocessCommand(Command['SubprocessCommand.Input', 'SubprocessCommand.Ou
|
|
1558
1614
|
)
|
1559
1615
|
|
1560
1616
|
|
1617
|
+
########################################
|
1618
|
+
# ../spawning.py
|
1619
|
+
|
1620
|
+
|
1621
|
+
class PySpawner:
|
1622
|
+
DEFAULT_PYTHON = 'python3'
|
1623
|
+
|
1624
|
+
def __init__(
|
1625
|
+
self,
|
1626
|
+
src: str,
|
1627
|
+
*,
|
1628
|
+
shell: ta.Optional[str] = None,
|
1629
|
+
shell_quote: bool = False,
|
1630
|
+
python: str = DEFAULT_PYTHON,
|
1631
|
+
stderr: ta.Optional[ta.Literal['pipe', 'stdout', 'devnull']] = None,
|
1632
|
+
) -> None:
|
1633
|
+
super().__init__()
|
1634
|
+
|
1635
|
+
self._src = src
|
1636
|
+
self._shell = shell
|
1637
|
+
self._shell_quote = shell_quote
|
1638
|
+
self._python = python
|
1639
|
+
self._stderr = stderr
|
1640
|
+
|
1641
|
+
#
|
1642
|
+
|
1643
|
+
class _PreparedCmd(ta.NamedTuple):
|
1644
|
+
cmd: ta.Sequence[str]
|
1645
|
+
shell: bool
|
1646
|
+
|
1647
|
+
def _prepare_cmd(self) -> _PreparedCmd:
|
1648
|
+
if self._shell is not None:
|
1649
|
+
sh_src = f'{self._python} -c {shlex.quote(self._src)}'
|
1650
|
+
if self._shell_quote:
|
1651
|
+
sh_src = shlex.quote(sh_src)
|
1652
|
+
sh_cmd = f'{self._shell} {sh_src}'
|
1653
|
+
return PySpawner._PreparedCmd(
|
1654
|
+
cmd=[sh_cmd],
|
1655
|
+
shell=True,
|
1656
|
+
)
|
1657
|
+
|
1658
|
+
else:
|
1659
|
+
return PySpawner._PreparedCmd(
|
1660
|
+
cmd=[self._python, '-c', self._src],
|
1661
|
+
shell=False,
|
1662
|
+
)
|
1663
|
+
|
1664
|
+
#
|
1665
|
+
|
1666
|
+
_STDERR_KWARG_MAP: ta.Mapping[str, int] = {
|
1667
|
+
'pipe': subprocess.PIPE,
|
1668
|
+
'stdout': subprocess.STDOUT,
|
1669
|
+
'devnull': subprocess.DEVNULL,
|
1670
|
+
}
|
1671
|
+
|
1672
|
+
@dc.dataclass(frozen=True)
|
1673
|
+
class Spawned:
|
1674
|
+
stdin: ta.IO
|
1675
|
+
stdout: ta.IO
|
1676
|
+
stderr: ta.Optional[ta.IO]
|
1677
|
+
|
1678
|
+
@contextlib.contextmanager
|
1679
|
+
def spawn(
|
1680
|
+
self,
|
1681
|
+
*,
|
1682
|
+
timeout: ta.Optional[float] = None,
|
1683
|
+
) -> ta.Generator[Spawned, None, None]:
|
1684
|
+
pc = self._prepare_cmd()
|
1685
|
+
|
1686
|
+
with subprocess.Popen(
|
1687
|
+
subprocess_maybe_shell_wrap_exec(*pc.cmd),
|
1688
|
+
shell=pc.shell,
|
1689
|
+
stdin=subprocess.PIPE,
|
1690
|
+
stdout=subprocess.PIPE,
|
1691
|
+
stderr=self._STDERR_KWARG_MAP[self._stderr] if self._stderr is not None else None,
|
1692
|
+
) as proc:
|
1693
|
+
stdin = check_not_none(proc.stdin)
|
1694
|
+
stdout = check_not_none(proc.stdout)
|
1695
|
+
|
1696
|
+
try:
|
1697
|
+
yield PySpawner.Spawned(
|
1698
|
+
stdin=stdin,
|
1699
|
+
stdout=stdout,
|
1700
|
+
stderr=proc.stderr,
|
1701
|
+
)
|
1702
|
+
|
1703
|
+
finally:
|
1704
|
+
try:
|
1705
|
+
stdin.close()
|
1706
|
+
except BrokenPipeError:
|
1707
|
+
pass
|
1708
|
+
|
1709
|
+
proc.wait(timeout)
|
1710
|
+
|
1711
|
+
|
1561
1712
|
########################################
|
1562
1713
|
# main.py
|
1563
1714
|
|
@@ -1570,29 +1721,23 @@ _COMMAND_TYPES = {
|
|
1570
1721
|
}
|
1571
1722
|
|
1572
1723
|
|
1573
|
-
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
)
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
|
1588
|
-
|
1589
|
-
cty.Output,
|
1590
|
-
k,
|
1591
|
-
get_obj_marshaler(cty.Output),
|
1724
|
+
@static_init
|
1725
|
+
def _register_command_marshaling() -> None:
|
1726
|
+
for fn in [
|
1727
|
+
lambda c: c,
|
1728
|
+
lambda c: c.Output,
|
1729
|
+
]:
|
1730
|
+
register_opj_marshaler(
|
1731
|
+
fn(Command),
|
1732
|
+
PolymorphicObjMarshaler.of([
|
1733
|
+
PolymorphicObjMarshaler.Impl(
|
1734
|
+
fn(cty),
|
1735
|
+
k,
|
1736
|
+
get_obj_marshaler(fn(cty)),
|
1737
|
+
)
|
1738
|
+
for k, cty in _COMMAND_TYPES.items()
|
1739
|
+
]),
|
1592
1740
|
)
|
1593
|
-
for k, cty in _COMMAND_TYPES.items()
|
1594
|
-
]),
|
1595
|
-
)
|
1596
1741
|
|
1597
1742
|
|
1598
1743
|
##
|
@@ -1630,12 +1775,12 @@ def _remote_main() -> None:
|
|
1630
1775
|
rt = pyremote_bootstrap_finalize() # noqa
|
1631
1776
|
|
1632
1777
|
while True:
|
1633
|
-
i = _recv_obj(rt.input, Command
|
1778
|
+
i = _recv_obj(rt.input, Command)
|
1634
1779
|
if i is None:
|
1635
1780
|
break
|
1636
1781
|
|
1637
|
-
if isinstance(i, SubprocessCommand
|
1638
|
-
o =
|
1782
|
+
if isinstance(i, SubprocessCommand):
|
1783
|
+
o = SubprocessCommandExecutor().execute(i) # noqa
|
1639
1784
|
else:
|
1640
1785
|
raise TypeError(i)
|
1641
1786
|
|
@@ -1645,38 +1790,6 @@ def _remote_main() -> None:
|
|
1645
1790
|
##
|
1646
1791
|
|
1647
1792
|
|
1648
|
-
@cached_nullary
|
1649
|
-
def _get_self_src() -> str:
|
1650
|
-
return inspect.getsource(sys.modules[__name__])
|
1651
|
-
|
1652
|
-
|
1653
|
-
def _is_src_amalg(src: str) -> bool:
|
1654
|
-
for l in src.splitlines(): # noqa
|
1655
|
-
if l.startswith('# @omlish-amalg-output '):
|
1656
|
-
return True
|
1657
|
-
return False
|
1658
|
-
|
1659
|
-
|
1660
|
-
@cached_nullary
|
1661
|
-
def _is_self_amalg() -> bool:
|
1662
|
-
return _is_src_amalg(_get_self_src())
|
1663
|
-
|
1664
|
-
|
1665
|
-
def _get_amalg_src(*, amalg_file: ta.Optional[str]) -> str:
|
1666
|
-
if amalg_file is not None:
|
1667
|
-
with open(amalg_file) as f:
|
1668
|
-
return f.read()
|
1669
|
-
|
1670
|
-
if _is_self_amalg():
|
1671
|
-
return _get_self_src()
|
1672
|
-
|
1673
|
-
import importlib.resources
|
1674
|
-
return importlib.resources.files(__package__.split('.')[0] + '.scripts').joinpath('manage.py').read_text()
|
1675
|
-
|
1676
|
-
|
1677
|
-
##
|
1678
|
-
|
1679
|
-
|
1680
1793
|
def _main() -> None:
|
1681
1794
|
import argparse
|
1682
1795
|
|
@@ -1685,19 +1798,20 @@ def _main() -> None:
|
|
1685
1798
|
parser.add_argument('-s', '--shell')
|
1686
1799
|
parser.add_argument('-q', '--shell-quote', action='store_true')
|
1687
1800
|
parser.add_argument('--python', default='python3')
|
1688
|
-
parser.add_argument('--
|
1801
|
+
parser.add_argument('--debug', action='store_true')
|
1802
|
+
parser.add_argument('--_payload-file')
|
1689
1803
|
|
1690
1804
|
args = parser.parse_args()
|
1691
1805
|
|
1692
1806
|
#
|
1693
1807
|
|
1694
|
-
|
1808
|
+
payload_src = get_payload_src(file=args._payload_file) # noqa
|
1695
1809
|
|
1696
1810
|
#
|
1697
1811
|
|
1698
1812
|
remote_src = '\n\n'.join([
|
1699
1813
|
'__name__ = "__remote__"',
|
1700
|
-
|
1814
|
+
payload_src,
|
1701
1815
|
'_remote_main()',
|
1702
1816
|
])
|
1703
1817
|
|
@@ -1705,60 +1819,41 @@ def _main() -> None:
|
|
1705
1819
|
|
1706
1820
|
bs_src = pyremote_build_bootstrap_cmd(__package__ or 'manage')
|
1707
1821
|
|
1708
|
-
if args.shell is not None:
|
1709
|
-
sh_src = f'{args.python} -c {shlex.quote(bs_src)}'
|
1710
|
-
if args.shell_quote:
|
1711
|
-
sh_src = shlex.quote(sh_src)
|
1712
|
-
sh_cmd = f'{args.shell} {sh_src}'
|
1713
|
-
cmd = [sh_cmd]
|
1714
|
-
shell = True
|
1715
|
-
else:
|
1716
|
-
cmd = [args.python, '-c', bs_src]
|
1717
|
-
shell = False
|
1718
|
-
|
1719
|
-
proc = subprocess.Popen(
|
1720
|
-
subprocess_maybe_shell_wrap_exec(*cmd),
|
1721
|
-
shell=shell,
|
1722
|
-
stdin=subprocess.PIPE,
|
1723
|
-
stdout=subprocess.PIPE,
|
1724
|
-
)
|
1725
|
-
|
1726
|
-
stdin = check_not_none(proc.stdin)
|
1727
|
-
stdout = check_not_none(proc.stdout)
|
1728
|
-
|
1729
|
-
res = PyremoteBootstrapDriver( # noqa
|
1730
|
-
remote_src,
|
1731
|
-
PyremoteBootstrapOptions(
|
1732
|
-
# debug=True,
|
1733
|
-
),
|
1734
|
-
).run(stdin, stdout)
|
1735
|
-
# print(res)
|
1736
|
-
|
1737
1822
|
#
|
1738
1823
|
|
1739
|
-
|
1740
|
-
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
1744
|
-
|
1745
|
-
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1750
|
-
|
1751
|
-
|
1752
|
-
|
1753
|
-
|
1754
|
-
print(o)
|
1824
|
+
spawner = PySpawner(
|
1825
|
+
bs_src,
|
1826
|
+
shell=args.shell,
|
1827
|
+
shell_quote=args.shell_quote,
|
1828
|
+
python=args.python,
|
1829
|
+
)
|
1830
|
+
with spawner.spawn() as proc:
|
1831
|
+
res = PyremoteBootstrapDriver( # noqa
|
1832
|
+
remote_src,
|
1833
|
+
PyremoteBootstrapOptions(
|
1834
|
+
debug=args.debug,
|
1835
|
+
),
|
1836
|
+
).run(proc.stdin, proc.stdout)
|
1837
|
+
# print(res)
|
1755
1838
|
|
1756
|
-
|
1757
|
-
stdin.close()
|
1758
|
-
except BrokenPipeError:
|
1759
|
-
pass
|
1839
|
+
#
|
1760
1840
|
|
1761
|
-
|
1841
|
+
for ci in [
|
1842
|
+
SubprocessCommand(
|
1843
|
+
args=['python3', '-'],
|
1844
|
+
input=b'print(1)\n',
|
1845
|
+
capture_stdout=True,
|
1846
|
+
),
|
1847
|
+
SubprocessCommand(
|
1848
|
+
args=['uname'],
|
1849
|
+
capture_stdout=True,
|
1850
|
+
),
|
1851
|
+
]:
|
1852
|
+
_send_obj(proc.stdin, ci, Command)
|
1853
|
+
|
1854
|
+
o = _recv_obj(proc.stdout, Command.Output)
|
1855
|
+
|
1856
|
+
print(o)
|
1762
1857
|
|
1763
1858
|
|
1764
1859
|
if __name__ == '__main__':
|
ominfra/scripts/supervisor.py
CHANGED
@@ -101,6 +101,7 @@ V = ta.TypeVar('V')
|
|
101
101
|
|
102
102
|
# ../../omlish/lite/cached.py
|
103
103
|
T = ta.TypeVar('T')
|
104
|
+
CallableT = ta.TypeVar('CallableT', bound=ta.Callable)
|
104
105
|
|
105
106
|
# ../../omlish/lite/check.py
|
106
107
|
SizedT = ta.TypeVar('SizedT', bound=ta.Sized)
|
@@ -1454,6 +1455,12 @@ def cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
1454
1455
|
return _cached_nullary(fn)
|
1455
1456
|
|
1456
1457
|
|
1458
|
+
def static_init(fn: CallableT) -> CallableT:
|
1459
|
+
fn = cached_nullary(fn)
|
1460
|
+
fn()
|
1461
|
+
return fn
|
1462
|
+
|
1463
|
+
|
1457
1464
|
########################################
|
1458
1465
|
# ../../../omlish/lite/check.py
|
1459
1466
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ominfra
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev140
|
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.dev140
|
16
|
+
Requires-Dist: omlish==0.0.0.dev140
|
17
17
|
Provides-Extra: all
|
18
18
|
Requires-Dist: paramiko~=3.5; extra == "all"
|
19
19
|
Requires-Dist: asyncssh~=2.18; extra == "all"
|
@@ -3,7 +3,7 @@ ominfra/__about__.py,sha256=6i1AoruFYQCd-PyhhbDQDWY2d1tiQu9nkwWr-fXAqfY,705
|
|
3
3
|
ominfra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
ominfra/cmds.py,sha256=E0AfnvEmnKntXWvmLW5L05_NeDpBET1VBXn7vV6EwBQ,2083
|
5
5
|
ominfra/configs.py,sha256=8aU1Qmbr-qjaE2iP3gAbA2SWJYMPZ-uGK007L01PoOI,1727
|
6
|
-
ominfra/pyremote.py,sha256=
|
6
|
+
ominfra/pyremote.py,sha256=vuLEZSjYtil7Knl4qlXYI4dqqiEGJvuO7EIcqr8Kabk,13142
|
7
7
|
ominfra/ssh.py,sha256=jQpc4WvkMckIfk4vILda8zFaeharRqc_6wxW50b0OjQ,5431
|
8
8
|
ominfra/threadworkers.py,sha256=oX4ubZn7h932saXpRIJu2MNhBExgGGMuGhdXarZxLJw,4948
|
9
9
|
ominfra/clouds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -28,14 +28,16 @@ ominfra/journald/genmessages.py,sha256=rLTS-K2v7otNOtTz4RoOEVYCm0fQuuBzf47e0T61t
|
|
28
28
|
ominfra/journald/messages.py,sha256=Wr7TjWMOySc0WnKwp_-idR8RfeKlbyJQ_KkELr0VB70,2192
|
29
29
|
ominfra/journald/tailer.py,sha256=5abcFMfgi7fnY9ZEQe2ZVobaJxjQkeu6d9Kagw33a1w,33525
|
30
30
|
ominfra/manage/__init__.py,sha256=YqHcYMfmo04OoVNYc6Ykc1I8WaJot44skwhm9DcnmXE,166
|
31
|
-
ominfra/manage/main.py,sha256=
|
31
|
+
ominfra/manage/main.py,sha256=rTY98MrDqGrpwRxo93z5TkfE82Ze3XrL1TqEZ--nkzk,3996
|
32
|
+
ominfra/manage/payload.py,sha256=NPuQtMGe1q3kDjG5cgOFmd6M9ITyKRc4IyMRY9PHzRI,818
|
33
|
+
ominfra/manage/spawning.py,sha256=EeV4hNcUZOWlM1VuhfGolLHSMWJdz6Dn24OLFtcbisE,2665
|
32
34
|
ominfra/manage/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
33
|
-
ominfra/manage/commands/base.py,sha256=
|
34
|
-
ominfra/manage/commands/subprocess.py,sha256=
|
35
|
+
ominfra/manage/commands/base.py,sha256=nXvqvMYeiuya0hcLnVjQNX3jUdIQN6Brt_UGIQBfNvs,559
|
36
|
+
ominfra/manage/commands/subprocess.py,sha256=7d-q8hOVaI5YY-dMU0R1KbCIo3R2mlgBSZ2g8NKEn9A,1941
|
35
37
|
ominfra/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
36
|
-
ominfra/scripts/journald2aws.py,sha256=
|
37
|
-
ominfra/scripts/manage.py,sha256=
|
38
|
-
ominfra/scripts/supervisor.py,sha256=
|
38
|
+
ominfra/scripts/journald2aws.py,sha256=wALg2habRTCsXEEACYqzB8qIxmZ0gHSL2NoPfu_iKDk,131771
|
39
|
+
ominfra/scripts/manage.py,sha256=nKidMTzCGV0Clfaw3-VlAIpy36LK3afr5gGkPUMaUQo,46670
|
40
|
+
ominfra/scripts/supervisor.py,sha256=q8d1LsBIthlv2-cTi1vb9z_2AfZ0f8mE-Xym7TLeiLU,246037
|
39
41
|
ominfra/supervisor/LICENSE.txt,sha256=yvqaMNsDhWxziHa9ien6qCW1SkZv-DQlAg96XjfSee8,1746
|
40
42
|
ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
41
43
|
ominfra/supervisor/__main__.py,sha256=I0yFw-C08OOiZ3BF6lF1Oiv789EQXu-_j6whDhQUTEA,66
|
@@ -77,9 +79,9 @@ ominfra/tailscale/api.py,sha256=C5-t_b6jZXUWcy5k8bXm7CFnk73pSdrlMOgGDeGVrpw,1370
|
|
77
79
|
ominfra/tailscale/cli.py,sha256=DSGp4hn5xwOW-l_u_InKlSF6kIobxtUtVssf_73STs0,3567
|
78
80
|
ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
79
81
|
ominfra/tools/listresources.py,sha256=4qVg5txsb10EHhvqXXeM6gJ2jx9LbroEnPydDv1uXs0,6176
|
80
|
-
ominfra-0.0.0.
|
81
|
-
ominfra-0.0.0.
|
82
|
-
ominfra-0.0.0.
|
83
|
-
ominfra-0.0.0.
|
84
|
-
ominfra-0.0.0.
|
85
|
-
ominfra-0.0.0.
|
82
|
+
ominfra-0.0.0.dev140.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
83
|
+
ominfra-0.0.0.dev140.dist-info/METADATA,sha256=tCByt2O1Q8y4Tu215MKfxXCWk9zmTZM4nYIUI8uGuII,731
|
84
|
+
ominfra-0.0.0.dev140.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
85
|
+
ominfra-0.0.0.dev140.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
|
86
|
+
ominfra-0.0.0.dev140.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
|
87
|
+
ominfra-0.0.0.dev140.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|