ominfra 0.0.0.dev139__py3-none-any.whl → 0.0.0.dev141__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/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.dev141.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev139.dist-info → ominfra-0.0.0.dev141.dist-info}/RECORD +15 -13
- {ominfra-0.0.0.dev139.dist-info → ominfra-0.0.0.dev141.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev139.dist-info → ominfra-0.0.0.dev141.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev139.dist-info → ominfra-0.0.0.dev141.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev139.dist-info → ominfra-0.0.0.dev141.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.dev141
|
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.dev141
|
16
|
+
Requires-Dist: omlish==0.0.0.dev141
|
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.dev141.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
83
|
+
ominfra-0.0.0.dev141.dist-info/METADATA,sha256=CRa6olAYdI24dF7R_HKUHw0aebJQzvHwvACjG82Mff4,731
|
84
|
+
ominfra-0.0.0.dev141.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
85
|
+
ominfra-0.0.0.dev141.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
|
86
|
+
ominfra-0.0.0.dev141.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
|
87
|
+
ominfra-0.0.0.dev141.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|