ominfra 0.0.0.dev147__py3-none-any.whl → 0.0.0.dev148__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/configs.py +30 -5
- ominfra/manage/commands/base.py +5 -5
- ominfra/manage/commands/execution.py +2 -2
- ominfra/manage/commands/inject.py +1 -1
- ominfra/manage/commands/interp.py +2 -2
- ominfra/manage/commands/subprocess.py +22 -14
- ominfra/manage/deploy/command.py +1 -1
- ominfra/manage/main.py +48 -32
- ominfra/manage/remote/_main.py +172 -0
- ominfra/manage/remote/channel.py +41 -16
- ominfra/manage/remote/config.py +10 -0
- ominfra/manage/remote/connection.py +106 -0
- ominfra/manage/remote/execution.py +244 -155
- ominfra/manage/remote/inject.py +7 -3
- ominfra/manage/remote/spawning.py +51 -33
- ominfra/pyremote.py +28 -3
- ominfra/scripts/journald2aws.py +127 -28
- ominfra/scripts/manage.py +1360 -485
- ominfra/scripts/supervisor.py +59 -10
- {ominfra-0.0.0.dev147.dist-info → ominfra-0.0.0.dev148.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev147.dist-info → ominfra-0.0.0.dev148.dist-info}/RECORD +25 -23
- {ominfra-0.0.0.dev147.dist-info → ominfra-0.0.0.dev148.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev147.dist-info → ominfra-0.0.0.dev148.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev147.dist-info → ominfra-0.0.0.dev148.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev147.dist-info → ominfra-0.0.0.dev148.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import abc
|
3
|
+
import contextlib
|
4
|
+
import typing as ta
|
5
|
+
|
6
|
+
from omlish.lite.cached import cached_nullary
|
7
|
+
from omlish.lite.marshal import ObjMarshalerManager
|
8
|
+
|
9
|
+
from ...pyremote import PyremoteBootstrapDriver
|
10
|
+
from ...pyremote import PyremoteBootstrapOptions
|
11
|
+
from ...pyremote import pyremote_build_bootstrap_cmd
|
12
|
+
from ..bootstrap import MainBootstrap
|
13
|
+
from ._main import _remote_execution_main # noqa
|
14
|
+
from .channel import RemoteChannelImpl
|
15
|
+
from .execution import RemoteCommandExecutor
|
16
|
+
from .payload import RemoteExecutionPayloadFile
|
17
|
+
from .payload import get_remote_payload_src
|
18
|
+
from .spawning import RemoteSpawning
|
19
|
+
|
20
|
+
|
21
|
+
##
|
22
|
+
|
23
|
+
|
24
|
+
class RemoteExecutionConnector(abc.ABC):
|
25
|
+
@abc.abstractmethod
|
26
|
+
def connect(
|
27
|
+
self,
|
28
|
+
tgt: RemoteSpawning.Target,
|
29
|
+
bs: MainBootstrap,
|
30
|
+
) -> ta.AsyncContextManager[RemoteCommandExecutor]:
|
31
|
+
raise NotImplementedError
|
32
|
+
|
33
|
+
|
34
|
+
##
|
35
|
+
|
36
|
+
|
37
|
+
class PyremoteRemoteExecutionConnector(RemoteExecutionConnector):
|
38
|
+
def __init__(
|
39
|
+
self,
|
40
|
+
*,
|
41
|
+
spawning: RemoteSpawning,
|
42
|
+
msh: ObjMarshalerManager,
|
43
|
+
payload_file: ta.Optional[RemoteExecutionPayloadFile] = None,
|
44
|
+
) -> None:
|
45
|
+
super().__init__()
|
46
|
+
|
47
|
+
self._spawning = spawning
|
48
|
+
self._msh = msh
|
49
|
+
self._payload_file = payload_file
|
50
|
+
|
51
|
+
#
|
52
|
+
|
53
|
+
@cached_nullary
|
54
|
+
def _payload_src(self) -> str:
|
55
|
+
return get_remote_payload_src(file=self._payload_file)
|
56
|
+
|
57
|
+
@cached_nullary
|
58
|
+
def _remote_src(self) -> ta.Sequence[str]:
|
59
|
+
return [
|
60
|
+
self._payload_src(),
|
61
|
+
'_remote_execution_main()',
|
62
|
+
]
|
63
|
+
|
64
|
+
@cached_nullary
|
65
|
+
def _spawn_src(self) -> str:
|
66
|
+
return pyremote_build_bootstrap_cmd(__package__ or 'manage')
|
67
|
+
|
68
|
+
#
|
69
|
+
|
70
|
+
@contextlib.asynccontextmanager
|
71
|
+
async def connect(
|
72
|
+
self,
|
73
|
+
tgt: RemoteSpawning.Target,
|
74
|
+
bs: MainBootstrap,
|
75
|
+
) -> ta.AsyncGenerator[RemoteCommandExecutor, None]:
|
76
|
+
spawn_src = self._spawn_src()
|
77
|
+
remote_src = self._remote_src()
|
78
|
+
|
79
|
+
async with self._spawning.spawn(
|
80
|
+
tgt,
|
81
|
+
spawn_src,
|
82
|
+
debug=bs.main_config.debug,
|
83
|
+
) as proc:
|
84
|
+
res = await PyremoteBootstrapDriver( # noqa
|
85
|
+
remote_src,
|
86
|
+
PyremoteBootstrapOptions(
|
87
|
+
debug=bs.main_config.debug,
|
88
|
+
),
|
89
|
+
).async_run(
|
90
|
+
proc.stdout,
|
91
|
+
proc.stdin,
|
92
|
+
)
|
93
|
+
|
94
|
+
chan = RemoteChannelImpl(
|
95
|
+
proc.stdout,
|
96
|
+
proc.stdin,
|
97
|
+
msh=self._msh,
|
98
|
+
)
|
99
|
+
|
100
|
+
await chan.send_obj(bs)
|
101
|
+
|
102
|
+
rce: RemoteCommandExecutor
|
103
|
+
async with contextlib.aclosing(RemoteCommandExecutor(chan)) as rce:
|
104
|
+
await rce.start()
|
105
|
+
|
106
|
+
yield rce
|
@@ -1,123 +1,182 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
-
import
|
2
|
+
import abc
|
3
|
+
import asyncio
|
3
4
|
import dataclasses as dc
|
5
|
+
import itertools
|
4
6
|
import logging
|
5
|
-
import threading
|
6
7
|
import typing as ta
|
7
8
|
|
8
|
-
from omlish.lite.
|
9
|
+
from omlish.lite.check import check_isinstance
|
10
|
+
from omlish.lite.check import check_none
|
9
11
|
from omlish.lite.check import check_not_none
|
12
|
+
from omlish.lite.check import check_state
|
10
13
|
from omlish.lite.logs import log
|
11
|
-
|
12
|
-
from omlish.lite.pycharm import pycharm_debug_connect
|
13
|
-
|
14
|
-
from ...pyremote import PyremoteBootstrapDriver
|
15
|
-
from ...pyremote import PyremoteBootstrapOptions
|
16
|
-
from ...pyremote import pyremote_bootstrap_finalize
|
17
|
-
from ...pyremote import pyremote_build_bootstrap_cmd
|
18
|
-
from ..bootstrap import MainBootstrap
|
14
|
+
|
19
15
|
from ..commands.base import Command
|
20
16
|
from ..commands.base import CommandException
|
21
17
|
from ..commands.base import CommandExecutor
|
22
18
|
from ..commands.base import CommandOutputOrException
|
23
19
|
from ..commands.base import CommandOutputOrExceptionData
|
24
|
-
from ..commands.execution import LocalCommandExecutor
|
25
20
|
from .channel import RemoteChannel
|
26
|
-
from .payload import RemoteExecutionPayloadFile
|
27
|
-
from .payload import get_remote_payload_src
|
28
|
-
from .spawning import RemoteSpawning
|
29
21
|
|
30
22
|
|
31
|
-
|
32
|
-
from ..bootstrap_ import main_bootstrap
|
33
|
-
else:
|
34
|
-
main_bootstrap: ta.Any = None
|
23
|
+
T = ta.TypeVar('T')
|
35
24
|
|
36
25
|
|
37
26
|
##
|
38
27
|
|
39
28
|
|
40
|
-
class
|
41
|
-
|
42
|
-
|
43
|
-
|
29
|
+
class _RemoteProtocol:
|
30
|
+
class Message(abc.ABC): # noqa
|
31
|
+
async def send(self, chan: RemoteChannel) -> None:
|
32
|
+
await chan.send_obj(self, _RemoteProtocol.Message)
|
44
33
|
|
45
|
-
|
46
|
-
|
47
|
-
|
34
|
+
@classmethod
|
35
|
+
async def recv(cls: ta.Type[T], chan: RemoteChannel) -> ta.Optional[T]:
|
36
|
+
return await chan.recv_obj(cls)
|
48
37
|
|
38
|
+
#
|
49
39
|
|
50
|
-
|
51
|
-
|
52
|
-
c: Command
|
40
|
+
class Request(Message, abc.ABC): # noqa
|
41
|
+
pass
|
53
42
|
|
43
|
+
@dc.dataclass(frozen=True)
|
44
|
+
class CommandRequest(Request):
|
45
|
+
seq: int
|
46
|
+
cmd: Command
|
54
47
|
|
55
|
-
@dc.dataclass(frozen=True)
|
56
|
-
class
|
57
|
-
|
48
|
+
@dc.dataclass(frozen=True)
|
49
|
+
class PingRequest(Request):
|
50
|
+
time: float
|
58
51
|
|
52
|
+
#
|
59
53
|
|
60
|
-
|
61
|
-
|
62
|
-
r: ta.Optional[CommandOutputOrExceptionData] = None
|
63
|
-
l: ta.Optional[_RemoteExecutionLog] = None
|
54
|
+
class Response(Message, abc.ABC): # noqa
|
55
|
+
pass
|
64
56
|
|
57
|
+
@dc.dataclass(frozen=True)
|
58
|
+
class LogResponse(Response):
|
59
|
+
s: str
|
65
60
|
|
66
|
-
|
67
|
-
|
61
|
+
@dc.dataclass(frozen=True)
|
62
|
+
class CommandResponse(Response):
|
63
|
+
seq: int
|
64
|
+
res: CommandOutputOrExceptionData
|
68
65
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
)
|
66
|
+
@dc.dataclass(frozen=True)
|
67
|
+
class PingResponse(Response):
|
68
|
+
time: float
|
73
69
|
|
74
|
-
bs = check_not_none(chan.recv_obj(MainBootstrap))
|
75
70
|
|
76
|
-
|
77
|
-
pycharm_debug_connect(prd)
|
71
|
+
##
|
78
72
|
|
79
|
-
injector = main_bootstrap(bs)
|
80
73
|
|
81
|
-
|
74
|
+
class _RemoteLogHandler(logging.Handler):
|
75
|
+
def __init__(
|
76
|
+
self,
|
77
|
+
chan: RemoteChannel,
|
78
|
+
loop: ta.Any = None,
|
79
|
+
) -> None:
|
80
|
+
super().__init__()
|
82
81
|
|
83
|
-
|
82
|
+
self._chan = chan
|
83
|
+
self._loop = loop
|
84
84
|
|
85
|
-
|
86
|
-
|
85
|
+
def emit(self, record):
|
86
|
+
msg = self.format(record)
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
if send_logs:
|
91
|
-
chan.send_obj(_RemoteExecutionResponse(l=_RemoteExecutionLog(s)))
|
88
|
+
async def inner():
|
89
|
+
await _RemoteProtocol.LogResponse(msg).send(self._chan)
|
92
90
|
|
93
|
-
|
94
|
-
|
91
|
+
loop = self._loop
|
92
|
+
if loop is None:
|
93
|
+
loop = asyncio.get_running_loop()
|
94
|
+
if loop is not None:
|
95
|
+
asyncio.run_coroutine_threadsafe(inner(), loop)
|
95
96
|
|
96
|
-
#
|
97
97
|
|
98
|
-
|
98
|
+
##
|
99
99
|
|
100
|
-
while True:
|
101
|
-
req = chan.recv_obj(_RemoteExecutionRequest)
|
102
|
-
if req is None:
|
103
|
-
break
|
104
100
|
|
105
|
-
|
106
|
-
|
101
|
+
class _RemoteCommandHandler:
|
102
|
+
def __init__(
|
103
|
+
self,
|
104
|
+
chan: RemoteChannel,
|
105
|
+
executor: CommandExecutor,
|
106
|
+
*,
|
107
|
+
stop: ta.Optional[asyncio.Event] = None,
|
108
|
+
) -> None:
|
109
|
+
super().__init__()
|
107
110
|
|
108
|
-
|
109
|
-
|
111
|
+
self._chan = chan
|
112
|
+
self._executor = executor
|
113
|
+
self._stop = stop if stop is not None else asyncio.Event()
|
114
|
+
|
115
|
+
self._cmds_by_seq: ta.Dict[int, _RemoteCommandHandler._Command] = {}
|
116
|
+
|
117
|
+
@dc.dataclass(frozen=True)
|
118
|
+
class _Command:
|
119
|
+
req: _RemoteProtocol.CommandRequest
|
120
|
+
fut: asyncio.Future
|
121
|
+
|
122
|
+
async def run(self) -> None:
|
123
|
+
stop_task = asyncio.create_task(self._stop.wait())
|
124
|
+
recv_task: ta.Optional[asyncio.Task] = None
|
125
|
+
|
126
|
+
while not self._stop.is_set():
|
127
|
+
if recv_task is None:
|
128
|
+
recv_task = asyncio.create_task(_RemoteProtocol.Request.recv(self._chan))
|
129
|
+
|
130
|
+
done, pending = await asyncio.wait([
|
131
|
+
stop_task,
|
132
|
+
recv_task,
|
133
|
+
], return_when=asyncio.FIRST_COMPLETED)
|
134
|
+
|
135
|
+
if recv_task in done:
|
136
|
+
msg: ta.Optional[_RemoteProtocol.Message] = check_isinstance(
|
137
|
+
recv_task.result(),
|
138
|
+
(_RemoteProtocol.Message, type(None)),
|
139
|
+
)
|
140
|
+
recv_task = None
|
141
|
+
|
142
|
+
if msg is None:
|
143
|
+
break
|
144
|
+
|
145
|
+
await self._handle_message(msg)
|
146
|
+
|
147
|
+
async def _handle_message(self, msg: _RemoteProtocol.Message) -> None:
|
148
|
+
if isinstance(msg, _RemoteProtocol.PingRequest):
|
149
|
+
log.debug('Ping: %r', msg)
|
150
|
+
await _RemoteProtocol.PingResponse(
|
151
|
+
time=msg.time,
|
152
|
+
).send(self._chan)
|
153
|
+
|
154
|
+
elif isinstance(msg, _RemoteProtocol.CommandRequest):
|
155
|
+
fut = asyncio.create_task(self._handle_command_request(msg))
|
156
|
+
self._cmds_by_seq[msg.seq] = _RemoteCommandHandler._Command(
|
157
|
+
req=msg,
|
158
|
+
fut=fut,
|
159
|
+
)
|
160
|
+
|
161
|
+
else:
|
162
|
+
raise TypeError(msg)
|
163
|
+
|
164
|
+
async def _handle_command_request(self, req: _RemoteProtocol.CommandRequest) -> None:
|
165
|
+
res = await self._executor.try_execute(
|
166
|
+
req.cmd,
|
110
167
|
log=log,
|
111
168
|
omit_exc_object=True,
|
112
169
|
)
|
113
170
|
|
114
|
-
|
115
|
-
|
171
|
+
await _RemoteProtocol.CommandResponse(
|
172
|
+
seq=req.seq,
|
173
|
+
res=CommandOutputOrExceptionData(
|
174
|
+
output=res.output,
|
175
|
+
exception=res.exception,
|
176
|
+
),
|
177
|
+
).send(self._chan)
|
116
178
|
|
117
|
-
|
118
|
-
output=r.output,
|
119
|
-
exception=r.exception,
|
120
|
-
)))
|
179
|
+
self._cmds_by_seq.pop(req.seq) # noqa
|
121
180
|
|
122
181
|
|
123
182
|
##
|
@@ -134,29 +193,129 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
134
193
|
|
135
194
|
self._chan = chan
|
136
195
|
|
137
|
-
|
138
|
-
self.
|
196
|
+
self._cmd_seq = itertools.count()
|
197
|
+
self._queue: asyncio.Queue = asyncio.Queue() # asyncio.Queue[RemoteCommandExecutor._Request]
|
198
|
+
self._stop = asyncio.Event()
|
199
|
+
self._loop_task: ta.Optional[asyncio.Task] = None
|
200
|
+
self._reqs_by_seq: ta.Dict[int, RemoteCommandExecutor._Request] = {}
|
201
|
+
|
202
|
+
#
|
203
|
+
|
204
|
+
async def start(self) -> None:
|
205
|
+
check_none(self._loop_task)
|
206
|
+
check_state(not self._stop.is_set())
|
207
|
+
self._loop_task = asyncio.create_task(self._loop())
|
208
|
+
|
209
|
+
async def aclose(self) -> None:
|
210
|
+
self._stop.set()
|
211
|
+
if self._loop_task is not None:
|
212
|
+
await self._loop_task
|
139
213
|
|
140
|
-
|
141
|
-
|
142
|
-
|
214
|
+
#
|
215
|
+
|
216
|
+
@dc.dataclass(frozen=True)
|
217
|
+
class _Request:
|
218
|
+
seq: int
|
219
|
+
cmd: Command
|
220
|
+
fut: asyncio.Future
|
221
|
+
|
222
|
+
async def _loop(self) -> None:
|
223
|
+
log.debug('RemoteCommandExecutor loop start: %r', self)
|
224
|
+
|
225
|
+
stop_task = asyncio.create_task(self._stop.wait())
|
226
|
+
queue_task: ta.Optional[asyncio.Task] = None
|
227
|
+
recv_task: ta.Optional[asyncio.Task] = None
|
228
|
+
|
229
|
+
while not self._stop.is_set():
|
230
|
+
if queue_task is None:
|
231
|
+
queue_task = asyncio.create_task(self._queue.get())
|
232
|
+
if recv_task is None:
|
233
|
+
recv_task = asyncio.create_task(_RemoteProtocol.Message.recv(self._chan))
|
234
|
+
|
235
|
+
done, pending = await asyncio.wait([
|
236
|
+
stop_task,
|
237
|
+
queue_task,
|
238
|
+
recv_task,
|
239
|
+
], return_when=asyncio.FIRST_COMPLETED)
|
240
|
+
|
241
|
+
if queue_task in done:
|
242
|
+
req = check_isinstance(queue_task.result(), RemoteCommandExecutor._Request)
|
243
|
+
queue_task = None
|
244
|
+
await self._handle_request(req)
|
245
|
+
|
246
|
+
if recv_task in done:
|
247
|
+
msg: ta.Optional[_RemoteProtocol.Message] = check_isinstance(
|
248
|
+
recv_task.result(),
|
249
|
+
(_RemoteProtocol.Message, type(None)),
|
250
|
+
)
|
251
|
+
recv_task = None
|
252
|
+
|
253
|
+
if msg is None:
|
254
|
+
log.debug('RemoteCommandExecutor got eof: %r', self)
|
255
|
+
break
|
256
|
+
|
257
|
+
await self._handle_message(msg)
|
258
|
+
|
259
|
+
log.debug('RemoteCommandExecutor loop stopping: %r', self)
|
260
|
+
|
261
|
+
for task in [
|
262
|
+
stop_task,
|
263
|
+
queue_task,
|
264
|
+
recv_task,
|
265
|
+
]:
|
266
|
+
if task is not None and not task.done():
|
267
|
+
task.cancel()
|
268
|
+
|
269
|
+
for req in self._reqs_by_seq.values():
|
270
|
+
req.fut.cancel()
|
271
|
+
|
272
|
+
log.debug('RemoteCommandExecutor loop exited: %r', self)
|
273
|
+
|
274
|
+
async def _handle_request(self, req: _Request) -> None:
|
275
|
+
self._reqs_by_seq[req.seq] = req
|
276
|
+
await _RemoteProtocol.CommandRequest(
|
277
|
+
seq=req.seq,
|
278
|
+
cmd=req.cmd,
|
279
|
+
).send(self._chan)
|
280
|
+
|
281
|
+
async def _handle_message(self, msg: _RemoteProtocol.Message) -> None:
|
282
|
+
if isinstance(msg, _RemoteProtocol.PingRequest):
|
283
|
+
log.debug('Ping: %r', msg)
|
284
|
+
await _RemoteProtocol.PingResponse(
|
285
|
+
time=msg.time,
|
286
|
+
).send(self._chan)
|
287
|
+
|
288
|
+
elif isinstance(msg, _RemoteProtocol.LogResponse):
|
289
|
+
log.info(msg.s)
|
290
|
+
|
291
|
+
elif isinstance(msg, _RemoteProtocol.CommandResponse):
|
292
|
+
req = self._reqs_by_seq.pop(msg.seq)
|
293
|
+
req.fut.set_result(msg.res)
|
294
|
+
|
295
|
+
else:
|
296
|
+
raise TypeError(msg)
|
143
297
|
|
144
|
-
|
145
|
-
log.info(r.l.s)
|
298
|
+
#
|
146
299
|
|
147
|
-
|
148
|
-
|
300
|
+
async def _remote_execute(self, cmd: Command) -> CommandOutputOrException:
|
301
|
+
req = RemoteCommandExecutor._Request(
|
302
|
+
seq=next(self._cmd_seq),
|
303
|
+
cmd=cmd,
|
304
|
+
fut=asyncio.Future(),
|
305
|
+
)
|
306
|
+
await self._queue.put(req)
|
307
|
+
return await req.fut
|
149
308
|
|
150
309
|
# @ta.override
|
151
|
-
def execute(self, cmd: Command) -> Command.Output:
|
152
|
-
r = self._remote_execute(cmd)
|
310
|
+
async def execute(self, cmd: Command) -> Command.Output:
|
311
|
+
r = await self._remote_execute(cmd)
|
153
312
|
if (e := r.exception) is not None:
|
154
313
|
raise RemoteCommandError(e)
|
155
314
|
else:
|
156
315
|
return check_not_none(r.output)
|
157
316
|
|
158
317
|
# @ta.override
|
159
|
-
def try_execute(
|
318
|
+
async def try_execute(
|
160
319
|
self,
|
161
320
|
cmd: Command,
|
162
321
|
*,
|
@@ -164,7 +323,7 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
164
323
|
omit_exc_object: bool = False,
|
165
324
|
) -> CommandOutputOrException:
|
166
325
|
try:
|
167
|
-
r = self._remote_execute(cmd)
|
326
|
+
r = await self._remote_execute(cmd)
|
168
327
|
|
169
328
|
except Exception as e: # noqa
|
170
329
|
if log is not None:
|
@@ -178,73 +337,3 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
178
337
|
|
179
338
|
else:
|
180
339
|
return r
|
181
|
-
|
182
|
-
|
183
|
-
##
|
184
|
-
|
185
|
-
|
186
|
-
class RemoteExecution:
|
187
|
-
def __init__(
|
188
|
-
self,
|
189
|
-
*,
|
190
|
-
spawning: RemoteSpawning,
|
191
|
-
msh: ObjMarshalerManager,
|
192
|
-
payload_file: ta.Optional[RemoteExecutionPayloadFile] = None,
|
193
|
-
) -> None:
|
194
|
-
super().__init__()
|
195
|
-
|
196
|
-
self._spawning = spawning
|
197
|
-
self._msh = msh
|
198
|
-
self._payload_file = payload_file
|
199
|
-
|
200
|
-
#
|
201
|
-
|
202
|
-
@cached_nullary
|
203
|
-
def _payload_src(self) -> str:
|
204
|
-
return get_remote_payload_src(file=self._payload_file)
|
205
|
-
|
206
|
-
@cached_nullary
|
207
|
-
def _remote_src(self) -> ta.Sequence[str]:
|
208
|
-
return [
|
209
|
-
self._payload_src(),
|
210
|
-
'_remote_execution_main()',
|
211
|
-
]
|
212
|
-
|
213
|
-
@cached_nullary
|
214
|
-
def _spawn_src(self) -> str:
|
215
|
-
return pyremote_build_bootstrap_cmd(__package__ or 'manage')
|
216
|
-
|
217
|
-
#
|
218
|
-
|
219
|
-
@contextlib.contextmanager
|
220
|
-
def connect(
|
221
|
-
self,
|
222
|
-
tgt: RemoteSpawning.Target,
|
223
|
-
bs: MainBootstrap,
|
224
|
-
) -> ta.Generator[RemoteCommandExecutor, None, None]:
|
225
|
-
spawn_src = self._spawn_src()
|
226
|
-
remote_src = self._remote_src()
|
227
|
-
|
228
|
-
with self._spawning.spawn(
|
229
|
-
tgt,
|
230
|
-
spawn_src,
|
231
|
-
) as proc:
|
232
|
-
res = PyremoteBootstrapDriver( # noqa
|
233
|
-
remote_src,
|
234
|
-
PyremoteBootstrapOptions(
|
235
|
-
debug=bs.main_config.debug,
|
236
|
-
),
|
237
|
-
).run(
|
238
|
-
proc.stdout,
|
239
|
-
proc.stdin,
|
240
|
-
)
|
241
|
-
|
242
|
-
chan = RemoteChannel(
|
243
|
-
proc.stdout,
|
244
|
-
proc.stdin,
|
245
|
-
msh=self._msh,
|
246
|
-
)
|
247
|
-
|
248
|
-
chan.send_obj(bs)
|
249
|
-
|
250
|
-
yield RemoteCommandExecutor(chan)
|
ominfra/manage/remote/inject.py
CHANGED
@@ -6,9 +6,11 @@ from omlish.lite.inject import InjectorBindings
|
|
6
6
|
from omlish.lite.inject import inj
|
7
7
|
|
8
8
|
from .config import RemoteConfig
|
9
|
-
from .
|
9
|
+
from .connection import PyremoteRemoteExecutionConnector
|
10
|
+
from .connection import RemoteExecutionConnector
|
10
11
|
from .payload import RemoteExecutionPayloadFile
|
11
12
|
from .spawning import RemoteSpawning
|
13
|
+
from .spawning import SubprocessRemoteSpawning
|
12
14
|
|
13
15
|
|
14
16
|
def bind_remote(
|
@@ -18,9 +20,11 @@ def bind_remote(
|
|
18
20
|
lst: ta.List[InjectorBindingOrBindings] = [
|
19
21
|
inj.bind(remote_config),
|
20
22
|
|
21
|
-
inj.bind(
|
23
|
+
inj.bind(SubprocessRemoteSpawning, singleton=True),
|
24
|
+
inj.bind(RemoteSpawning, to_key=SubprocessRemoteSpawning),
|
22
25
|
|
23
|
-
inj.bind(
|
26
|
+
inj.bind(PyremoteRemoteExecutionConnector, singleton=True),
|
27
|
+
inj.bind(RemoteExecutionConnector, to_key=PyremoteRemoteExecutionConnector),
|
24
28
|
]
|
25
29
|
|
26
30
|
if (pf := remote_config.payload_file) is not None:
|