ominfra 0.0.0.dev151__tar.gz → 0.0.0.dev153__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {ominfra-0.0.0.dev151/ominfra.egg-info → ominfra-0.0.0.dev153}/PKG-INFO +3 -3
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/aws/journald2aws/driver.py +1 -1
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/bootstrap.py +3 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/bootstrap_.py +1 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/commands/interp.py +0 -3
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/commands/subprocess.py +0 -3
- ominfra-0.0.0.dev151/ominfra/manage/deploy/command.py → ominfra-0.0.0.dev153/ominfra/manage/deploy/commands.py +0 -3
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/deploy/inject.py +2 -2
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/inject.py +8 -1
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/main.py +7 -7
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/remote/_main.py +3 -3
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/remote/config.py +2 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/remote/connection.py +48 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/remote/execution.py +90 -12
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/remote/inject.py +19 -4
- ominfra-0.0.0.dev153/ominfra/manage/system/commands.py +24 -0
- ominfra-0.0.0.dev153/ominfra/manage/system/config.py +8 -0
- ominfra-0.0.0.dev153/ominfra/manage/system/inject.py +54 -0
- ominfra-0.0.0.dev153/ominfra/manage/system/packages.py +106 -0
- ominfra-0.0.0.dev153/ominfra/manage/system/types.py +5 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/scripts/journald2aws.py +68 -68
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/scripts/manage.py +483 -83
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/scripts/supervisor.py +157 -157
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/main.py +1 -1
- ominfra-0.0.0.dev153/ominfra/tools/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153/ominfra.egg-info}/PKG-INFO +3 -3
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra.egg-info/SOURCES.txt +7 -1
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra.egg-info/requires.txt +2 -2
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/pyproject.toml +3 -3
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/LICENSE +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/MANIFEST.in +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/README.rst +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/.manifests.json +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/__about__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/aws/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/aws/__main__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/aws/auth.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/aws/cli.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/aws/dataclasses.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/aws/journald2aws/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/aws/journald2aws/__main__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/aws/journald2aws/cursor.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/aws/journald2aws/main.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/aws/journald2aws/poster.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/aws/logs.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/aws/metadata.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/gcp/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/clouds/gcp/auth.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/cmds.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/configs.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/journald/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/journald/fields.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/journald/genmessages.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/journald/messages.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/journald/tailer.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/__main__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/commands/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/commands/base.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/commands/execution.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/commands/inject.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/commands/marshal.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/config.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/deploy/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/deploy/paths.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/marshal.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/remote/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/remote/channel.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/remote/payload.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/manage/remote/spawning.py +0 -0
- {ominfra-0.0.0.dev151/ominfra/scripts → ominfra-0.0.0.dev153/ominfra/manage/system}/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/pyremote.py +0 -0
- {ominfra-0.0.0.dev151/ominfra/supervisor/utils → ominfra-0.0.0.dev153/ominfra/scripts}/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/ssh.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/LICENSE.txt +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/__main__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/configs.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/dispatchers.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/dispatchersimpl.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/events.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/exceptions.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/groups.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/groupsimpl.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/http.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/inject.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/io.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/pipes.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/privileges.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/process.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/processimpl.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/setup.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/setupimpl.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/signals.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/spawning.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/spawningimpl.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/states.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/supervisor.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/types.py +0 -0
- {ominfra-0.0.0.dev151/ominfra/tailscale → ominfra-0.0.0.dev153/ominfra/supervisor/utils}/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/utils/collections.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/utils/diag.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/utils/fds.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/utils/fs.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/utils/os.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/utils/ostypes.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/utils/signals.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/utils/strings.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/supervisor/utils/users.py +0 -0
- {ominfra-0.0.0.dev151/ominfra/tools → ominfra-0.0.0.dev153/ominfra/tailscale}/__init__.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/tailscale/api.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/tailscale/cli.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/threadworkers.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra/tools/listresources.py +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra.egg-info/dependency_links.txt +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra.egg-info/entry_points.txt +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/ominfra.egg-info/top_level.txt +0 -0
- {ominfra-0.0.0.dev151 → ominfra-0.0.0.dev153}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ominfra
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev153
|
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.dev153
|
16
|
+
Requires-Dist: omlish==0.0.0.dev153
|
17
17
|
Provides-Extra: all
|
18
18
|
Requires-Dist: paramiko~=3.5; extra == "all"
|
19
19
|
Requires-Dist: asyncssh~=2.18; extra == "all"
|
@@ -41,8 +41,8 @@ from omlish.lite.cached import cached_nullary
|
|
41
41
|
from omlish.lite.check import check
|
42
42
|
from omlish.lite.contextmanagers import ExitStacked
|
43
43
|
from omlish.lite.logs import log
|
44
|
-
from omlish.lite.pidfile import Pidfile
|
45
44
|
from omlish.lite.runtime import is_debugger_attached
|
45
|
+
from omlish.os.pidfile import Pidfile
|
46
46
|
|
47
47
|
from ....journald.messages import JournalctlMessage # noqa
|
48
48
|
from ....journald.tailer import JournalctlTailerWorker
|
@@ -2,6 +2,7 @@ import dataclasses as dc
|
|
2
2
|
|
3
3
|
from .config import MainConfig
|
4
4
|
from .remote.config import RemoteConfig
|
5
|
+
from .system.config import SystemConfig
|
5
6
|
|
6
7
|
|
7
8
|
@dc.dataclass(frozen=True)
|
@@ -9,3 +10,5 @@ class MainBootstrap:
|
|
9
10
|
main_config: MainConfig = MainConfig()
|
10
11
|
|
11
12
|
remote_config: RemoteConfig = RemoteConfig()
|
13
|
+
|
14
|
+
system_config: SystemConfig = SystemConfig()
|
@@ -25,9 +25,6 @@ class InterpCommand(Command['InterpCommand.Output']):
|
|
25
25
|
opts: InterpOpts
|
26
26
|
|
27
27
|
|
28
|
-
##
|
29
|
-
|
30
|
-
|
31
28
|
class InterpCommandExecutor(CommandExecutor[InterpCommand, InterpCommand.Output]):
|
32
29
|
async def execute(self, cmd: InterpCommand) -> InterpCommand.Output:
|
33
30
|
i = InterpSpecifier.parse(check.not_none(cmd.spec))
|
@@ -48,9 +48,6 @@ class SubprocessCommand(Command['SubprocessCommand.Output']):
|
|
48
48
|
stderr: ta.Optional[bytes] = None
|
49
49
|
|
50
50
|
|
51
|
-
##
|
52
|
-
|
53
|
-
|
54
51
|
class SubprocessCommandExecutor(CommandExecutor[SubprocessCommand, SubprocessCommand.Output]):
|
55
52
|
async def execute(self, cmd: SubprocessCommand) -> SubprocessCommand.Output:
|
56
53
|
proc: asyncio.subprocess.Process
|
@@ -17,9 +17,6 @@ class DeployCommand(Command['DeployCommand.Output']):
|
|
17
17
|
pass
|
18
18
|
|
19
19
|
|
20
|
-
##
|
21
|
-
|
22
|
-
|
23
20
|
class DeployCommandExecutor(CommandExecutor[DeployCommand, DeployCommand.Output]):
|
24
21
|
async def execute(self, cmd: DeployCommand) -> DeployCommand.Output:
|
25
22
|
log.info('Deploying!')
|
@@ -6,8 +6,8 @@ from omlish.lite.inject import InjectorBindings
|
|
6
6
|
from omlish.lite.inject import inj
|
7
7
|
|
8
8
|
from ..commands.inject import bind_command
|
9
|
-
from .
|
10
|
-
from .
|
9
|
+
from .commands import DeployCommand
|
10
|
+
from .commands import DeployCommandExecutor
|
11
11
|
|
12
12
|
|
13
13
|
def bind_deploy(
|
@@ -13,6 +13,8 @@ from .marshal import ObjMarshalerInstaller
|
|
13
13
|
from .marshal import ObjMarshalerInstallers
|
14
14
|
from .remote.config import RemoteConfig
|
15
15
|
from .remote.inject import bind_remote
|
16
|
+
from .system.config import SystemConfig
|
17
|
+
from .system.inject import bind_system
|
16
18
|
|
17
19
|
|
18
20
|
##
|
@@ -22,6 +24,7 @@ def bind_main(
|
|
22
24
|
*,
|
23
25
|
main_config: MainConfig,
|
24
26
|
remote_config: RemoteConfig,
|
27
|
+
system_config: SystemConfig,
|
25
28
|
) -> InjectorBindings:
|
26
29
|
lst: ta.List[InjectorBindingOrBindings] = [
|
27
30
|
inj.bind(main_config),
|
@@ -30,11 +33,15 @@ def bind_main(
|
|
30
33
|
main_config=main_config,
|
31
34
|
),
|
32
35
|
|
36
|
+
bind_deploy(),
|
37
|
+
|
33
38
|
bind_remote(
|
34
39
|
remote_config=remote_config,
|
35
40
|
),
|
36
41
|
|
37
|
-
|
42
|
+
bind_system(
|
43
|
+
system_config=system_config,
|
44
|
+
),
|
38
45
|
]
|
39
46
|
|
40
47
|
#
|
@@ -8,6 +8,7 @@ manage.py -s 'ssh -i /foo/bar.pem foo@bar.baz' -q --python=python3.8
|
|
8
8
|
import asyncio
|
9
9
|
import contextlib
|
10
10
|
import json
|
11
|
+
import sys
|
11
12
|
import typing as ta
|
12
13
|
|
13
14
|
from omlish.argparse.cli import ArgparseCli
|
@@ -31,7 +32,7 @@ from .remote.spawning import RemoteSpawning
|
|
31
32
|
|
32
33
|
class MainCli(ArgparseCli):
|
33
34
|
@argparse_command(
|
34
|
-
argparse_arg('--
|
35
|
+
argparse_arg('--_payload-file'),
|
35
36
|
|
36
37
|
argparse_arg('-s', '--shell'),
|
37
38
|
argparse_arg('-q', '--shell-quote', action='store_true'),
|
@@ -49,10 +50,7 @@ class MainCli(ArgparseCli):
|
|
49
50
|
|
50
51
|
argparse_arg('command', nargs='+'),
|
51
52
|
)
|
52
|
-
def run(self) -> None:
|
53
|
-
asyncio.run(self._async_run())
|
54
|
-
|
55
|
-
async def _async_run(self) -> None:
|
53
|
+
async def run(self) -> None:
|
56
54
|
bs = MainBootstrap(
|
57
55
|
main_config=MainConfig(
|
58
56
|
log_level='DEBUG' if self.args.debug else 'INFO',
|
@@ -61,7 +59,7 @@ class MainCli(ArgparseCli):
|
|
61
59
|
),
|
62
60
|
|
63
61
|
remote_config=RemoteConfig(
|
64
|
-
payload_file=self.args.
|
62
|
+
payload_file=self.args._payload_file, # noqa
|
65
63
|
|
66
64
|
pycharm_remote_debug=PycharmRemoteDebug(
|
67
65
|
port=self.args.pycharm_debug_port,
|
@@ -70,6 +68,8 @@ class MainCli(ArgparseCli):
|
|
70
68
|
) if self.args.pycharm_debug_port is not None else None,
|
71
69
|
|
72
70
|
timebomb_delay_s=self.args.remote_timebomb_delay_s,
|
71
|
+
|
72
|
+
use_in_process_remote_executor=True,
|
73
73
|
),
|
74
74
|
)
|
75
75
|
|
@@ -124,7 +124,7 @@ class MainCli(ArgparseCli):
|
|
124
124
|
|
125
125
|
|
126
126
|
def _main() -> None:
|
127
|
-
MainCli().
|
127
|
+
sys.exit(asyncio.run(MainCli().async_cli_run()))
|
128
128
|
|
129
129
|
|
130
130
|
if __name__ == '__main__':
|
@@ -8,15 +8,15 @@ import threading
|
|
8
8
|
import time
|
9
9
|
import typing as ta
|
10
10
|
|
11
|
-
from omlish.
|
12
|
-
from omlish.
|
11
|
+
from omlish.asyncs.asyncio.streams import asyncio_open_stream_reader
|
12
|
+
from omlish.asyncs.asyncio.streams import asyncio_open_stream_writer
|
13
13
|
from omlish.lite.cached import cached_nullary
|
14
14
|
from omlish.lite.check import check
|
15
|
-
from omlish.lite.deathsig import set_process_deathsig
|
16
15
|
from omlish.lite.inject import Injector
|
17
16
|
from omlish.lite.logs import log
|
18
17
|
from omlish.lite.marshal import ObjMarshalerManager
|
19
18
|
from omlish.lite.pycharm import pycharm_debug_connect
|
19
|
+
from omlish.os.deathsig import set_process_deathsig
|
20
20
|
|
21
21
|
from ...pyremote import pyremote_bootstrap_finalize
|
22
22
|
from ..bootstrap import MainBootstrap
|
@@ -1,8 +1,10 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
2
|
import abc
|
3
|
+
import asyncio
|
3
4
|
import contextlib
|
4
5
|
import typing as ta
|
5
6
|
|
7
|
+
from omlish.asyncs.asyncio.channels import asyncio_create_bytes_channel
|
6
8
|
from omlish.lite.cached import cached_nullary
|
7
9
|
from omlish.lite.marshal import ObjMarshalerManager
|
8
10
|
|
@@ -10,9 +12,11 @@ from ...pyremote import PyremoteBootstrapDriver
|
|
10
12
|
from ...pyremote import PyremoteBootstrapOptions
|
11
13
|
from ...pyremote import pyremote_build_bootstrap_cmd
|
12
14
|
from ..bootstrap import MainBootstrap
|
15
|
+
from ..commands.execution import LocalCommandExecutor
|
13
16
|
from ._main import _remote_execution_main # noqa
|
14
17
|
from .channel import RemoteChannelImpl
|
15
18
|
from .execution import RemoteCommandExecutor
|
19
|
+
from .execution import _RemoteCommandHandler
|
16
20
|
from .payload import RemoteExecutionPayloadFile
|
17
21
|
from .payload import get_remote_payload_src
|
18
22
|
from .spawning import RemoteSpawning
|
@@ -104,3 +108,47 @@ class PyremoteRemoteExecutionConnector(RemoteExecutionConnector):
|
|
104
108
|
await rce.start()
|
105
109
|
|
106
110
|
yield rce
|
111
|
+
|
112
|
+
|
113
|
+
##
|
114
|
+
|
115
|
+
|
116
|
+
class InProcessRemoteExecutionConnector(RemoteExecutionConnector):
|
117
|
+
def __init__(
|
118
|
+
self,
|
119
|
+
*,
|
120
|
+
msh: ObjMarshalerManager,
|
121
|
+
local_executor: LocalCommandExecutor,
|
122
|
+
) -> None:
|
123
|
+
super().__init__()
|
124
|
+
|
125
|
+
self._msh = msh
|
126
|
+
self._local_executor = local_executor
|
127
|
+
|
128
|
+
@contextlib.asynccontextmanager
|
129
|
+
async def connect(
|
130
|
+
self,
|
131
|
+
tgt: RemoteSpawning.Target,
|
132
|
+
bs: MainBootstrap,
|
133
|
+
) -> ta.AsyncGenerator[RemoteCommandExecutor, None]:
|
134
|
+
r0, w0 = asyncio_create_bytes_channel()
|
135
|
+
r1, w1 = asyncio_create_bytes_channel()
|
136
|
+
|
137
|
+
remote_chan = RemoteChannelImpl(r0, w1, msh=self._msh)
|
138
|
+
local_chan = RemoteChannelImpl(r1, w0, msh=self._msh)
|
139
|
+
|
140
|
+
rch = _RemoteCommandHandler(
|
141
|
+
remote_chan,
|
142
|
+
self._local_executor,
|
143
|
+
)
|
144
|
+
rch_task = asyncio.create_task(rch.run()) # noqa
|
145
|
+
try:
|
146
|
+
rce: RemoteCommandExecutor
|
147
|
+
async with contextlib.aclosing(RemoteCommandExecutor(local_chan)) as rce:
|
148
|
+
await rce.start()
|
149
|
+
|
150
|
+
yield rce
|
151
|
+
|
152
|
+
finally:
|
153
|
+
rch.stop()
|
154
|
+
await rch_task
|
@@ -1,9 +1,14 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
+
"""
|
3
|
+
TODO:
|
4
|
+
- sequence all messages
|
5
|
+
"""
|
2
6
|
import abc
|
3
7
|
import asyncio
|
4
8
|
import dataclasses as dc
|
5
9
|
import itertools
|
6
10
|
import logging
|
11
|
+
import time
|
7
12
|
import typing as ta
|
8
13
|
|
9
14
|
from omlish.lite.check import check
|
@@ -96,38 +101,80 @@ class _RemoteLogHandler(logging.Handler):
|
|
96
101
|
|
97
102
|
|
98
103
|
class _RemoteCommandHandler:
|
104
|
+
DEFAULT_PING_INTERVAL_S: float = 3.
|
105
|
+
|
99
106
|
def __init__(
|
100
107
|
self,
|
101
108
|
chan: RemoteChannel,
|
102
109
|
executor: CommandExecutor,
|
103
110
|
*,
|
104
111
|
stop: ta.Optional[asyncio.Event] = None,
|
112
|
+
ping_interval_s: float = DEFAULT_PING_INTERVAL_S,
|
105
113
|
) -> None:
|
106
114
|
super().__init__()
|
107
115
|
|
108
116
|
self._chan = chan
|
109
117
|
self._executor = executor
|
110
118
|
self._stop = stop if stop is not None else asyncio.Event()
|
119
|
+
self._ping_interval_s = ping_interval_s
|
111
120
|
|
112
121
|
self._cmds_by_seq: ta.Dict[int, _RemoteCommandHandler._Command] = {}
|
113
122
|
|
123
|
+
self._last_ping_send: float = 0.
|
124
|
+
self._ping_in_flight: bool = False
|
125
|
+
self._last_ping_recv: ta.Optional[float] = None
|
126
|
+
|
127
|
+
def stop(self) -> None:
|
128
|
+
self._stop.set()
|
129
|
+
|
114
130
|
@dc.dataclass(frozen=True)
|
115
131
|
class _Command:
|
116
132
|
req: _RemoteProtocol.CommandRequest
|
117
133
|
fut: asyncio.Future
|
118
134
|
|
119
135
|
async def run(self) -> None:
|
136
|
+
log.debug('_RemoteCommandHandler loop start: %r', self)
|
137
|
+
|
120
138
|
stop_task = asyncio.create_task(self._stop.wait())
|
121
139
|
recv_task: ta.Optional[asyncio.Task] = None
|
122
140
|
|
123
141
|
while not self._stop.is_set():
|
124
142
|
if recv_task is None:
|
125
|
-
recv_task = asyncio.create_task(_RemoteProtocol.
|
143
|
+
recv_task = asyncio.create_task(_RemoteProtocol.Message.recv(self._chan))
|
126
144
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
145
|
+
if not self._ping_in_flight:
|
146
|
+
if not self._last_ping_recv:
|
147
|
+
ping_wait_time = 0.
|
148
|
+
else:
|
149
|
+
ping_wait_time = self._ping_interval_s - (time.time() - self._last_ping_recv)
|
150
|
+
else:
|
151
|
+
ping_wait_time = float('inf')
|
152
|
+
wait_time = min(self._ping_interval_s, ping_wait_time)
|
153
|
+
log.debug('_RemoteCommandHandler loop wait: %f', wait_time)
|
154
|
+
|
155
|
+
done, pending = await asyncio.wait(
|
156
|
+
[
|
157
|
+
stop_task,
|
158
|
+
recv_task,
|
159
|
+
],
|
160
|
+
return_when=asyncio.FIRST_COMPLETED,
|
161
|
+
timeout=wait_time,
|
162
|
+
)
|
163
|
+
|
164
|
+
#
|
165
|
+
|
166
|
+
if (
|
167
|
+
(time.time() - self._last_ping_send >= self._ping_interval_s) and
|
168
|
+
not self._ping_in_flight
|
169
|
+
):
|
170
|
+
now = time.time()
|
171
|
+
self._last_ping_send = now
|
172
|
+
self._ping_in_flight = True
|
173
|
+
await _RemoteProtocol.PingRequest(
|
174
|
+
time=now,
|
175
|
+
).send(self._chan)
|
176
|
+
|
177
|
+
#
|
131
178
|
|
132
179
|
if recv_task in done:
|
133
180
|
msg: ta.Optional[_RemoteProtocol.Message] = check.isinstance(
|
@@ -141,6 +188,20 @@ class _RemoteCommandHandler:
|
|
141
188
|
|
142
189
|
await self._handle_message(msg)
|
143
190
|
|
191
|
+
log.debug('_RemoteCommandHandler loop stopping: %r', self)
|
192
|
+
|
193
|
+
for task in [
|
194
|
+
stop_task,
|
195
|
+
recv_task,
|
196
|
+
]:
|
197
|
+
if task is not None and not task.done():
|
198
|
+
task.cancel()
|
199
|
+
|
200
|
+
for cmd in self._cmds_by_seq.values():
|
201
|
+
cmd.fut.cancel()
|
202
|
+
|
203
|
+
log.debug('_RemoteCommandHandler loop exited: %r', self)
|
204
|
+
|
144
205
|
async def _handle_message(self, msg: _RemoteProtocol.Message) -> None:
|
145
206
|
if isinstance(msg, _RemoteProtocol.PingRequest):
|
146
207
|
log.debug('Ping: %r', msg)
|
@@ -148,6 +209,12 @@ class _RemoteCommandHandler:
|
|
148
209
|
time=msg.time,
|
149
210
|
).send(self._chan)
|
150
211
|
|
212
|
+
elif isinstance(msg, _RemoteProtocol.PingResponse):
|
213
|
+
latency_s = time.time() - msg.time
|
214
|
+
log.debug('Pong: %0.2f ms %r', latency_s * 1000., msg)
|
215
|
+
self._last_ping_recv = time.time()
|
216
|
+
self._ping_in_flight = False
|
217
|
+
|
151
218
|
elif isinstance(msg, _RemoteProtocol.CommandRequest):
|
152
219
|
fut = asyncio.create_task(self._handle_command_request(msg))
|
153
220
|
self._cmds_by_seq[msg.seq] = _RemoteCommandHandler._Command(
|
@@ -229,16 +296,23 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
229
296
|
if recv_task is None:
|
230
297
|
recv_task = asyncio.create_task(_RemoteProtocol.Message.recv(self._chan))
|
231
298
|
|
232
|
-
done, pending = await asyncio.wait(
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
299
|
+
done, pending = await asyncio.wait(
|
300
|
+
[
|
301
|
+
stop_task,
|
302
|
+
queue_task,
|
303
|
+
recv_task,
|
304
|
+
],
|
305
|
+
return_when=asyncio.FIRST_COMPLETED,
|
306
|
+
)
|
307
|
+
|
308
|
+
#
|
237
309
|
|
238
310
|
if queue_task in done:
|
239
311
|
req = check.isinstance(queue_task.result(), RemoteCommandExecutor._Request)
|
240
312
|
queue_task = None
|
241
|
-
await self.
|
313
|
+
await self._handle_queued_request(req)
|
314
|
+
|
315
|
+
#
|
242
316
|
|
243
317
|
if recv_task in done:
|
244
318
|
msg: ta.Optional[_RemoteProtocol.Message] = check.isinstance(
|
@@ -268,7 +342,7 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
268
342
|
|
269
343
|
log.debug('RemoteCommandExecutor loop exited: %r', self)
|
270
344
|
|
271
|
-
async def
|
345
|
+
async def _handle_queued_request(self, req: _Request) -> None:
|
272
346
|
self._reqs_by_seq[req.seq] = req
|
273
347
|
await _RemoteProtocol.CommandRequest(
|
274
348
|
seq=req.seq,
|
@@ -282,6 +356,10 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
282
356
|
time=msg.time,
|
283
357
|
).send(self._chan)
|
284
358
|
|
359
|
+
elif isinstance(msg, _RemoteProtocol.PingResponse):
|
360
|
+
latency_s = time.time() - msg.time
|
361
|
+
log.debug('Pong: %0.2f ms %r', latency_s * 1000., msg)
|
362
|
+
|
285
363
|
elif isinstance(msg, _RemoteProtocol.LogResponse):
|
286
364
|
log.info(msg.s)
|
287
365
|
|
@@ -6,6 +6,7 @@ from omlish.lite.inject import InjectorBindings
|
|
6
6
|
from omlish.lite.inject import inj
|
7
7
|
|
8
8
|
from .config import RemoteConfig
|
9
|
+
from .connection import InProcessRemoteExecutionConnector
|
9
10
|
from .connection import PyremoteRemoteExecutionConnector
|
10
11
|
from .connection import RemoteExecutionConnector
|
11
12
|
from .payload import RemoteExecutionPayloadFile
|
@@ -22,12 +23,26 @@ def bind_remote(
|
|
22
23
|
|
23
24
|
inj.bind(SubprocessRemoteSpawning, singleton=True),
|
24
25
|
inj.bind(RemoteSpawning, to_key=SubprocessRemoteSpawning),
|
25
|
-
|
26
|
-
inj.bind(PyremoteRemoteExecutionConnector, singleton=True),
|
27
|
-
inj.bind(RemoteExecutionConnector, to_key=PyremoteRemoteExecutionConnector),
|
28
26
|
]
|
29
27
|
|
28
|
+
#
|
29
|
+
|
30
|
+
if remote_config.use_in_process_remote_executor:
|
31
|
+
lst.extend([
|
32
|
+
inj.bind(InProcessRemoteExecutionConnector, singleton=True),
|
33
|
+
inj.bind(RemoteExecutionConnector, to_key=InProcessRemoteExecutionConnector),
|
34
|
+
])
|
35
|
+
else:
|
36
|
+
lst.extend([
|
37
|
+
inj.bind(PyremoteRemoteExecutionConnector, singleton=True),
|
38
|
+
inj.bind(RemoteExecutionConnector, to_key=PyremoteRemoteExecutionConnector),
|
39
|
+
])
|
40
|
+
|
41
|
+
#
|
42
|
+
|
30
43
|
if (pf := remote_config.payload_file) is not None:
|
31
|
-
lst.append(inj.bind(pf,
|
44
|
+
lst.append(inj.bind(pf, key=RemoteExecutionPayloadFile))
|
45
|
+
|
46
|
+
#
|
32
47
|
|
33
48
|
return inj.as_bindings(*lst)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import dataclasses as dc
|
3
|
+
|
4
|
+
from omlish.lite.logs import log
|
5
|
+
|
6
|
+
from ..commands.base import Command
|
7
|
+
from ..commands.base import CommandExecutor
|
8
|
+
|
9
|
+
|
10
|
+
##
|
11
|
+
|
12
|
+
|
13
|
+
@dc.dataclass(frozen=True)
|
14
|
+
class CheckSystemPackageCommand(Command['CheckSystemPackageCommand.Output']):
|
15
|
+
@dc.dataclass(frozen=True)
|
16
|
+
class Output(Command.Output):
|
17
|
+
pass
|
18
|
+
|
19
|
+
|
20
|
+
class CheckSystemPackageCommandExecutor(CommandExecutor[CheckSystemPackageCommand, CheckSystemPackageCommand.Output]):
|
21
|
+
async def execute(self, cmd: CheckSystemPackageCommand) -> CheckSystemPackageCommand.Output:
|
22
|
+
log.info('Checking system package!')
|
23
|
+
|
24
|
+
return CheckSystemPackageCommand.Output()
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import sys
|
3
|
+
import typing as ta
|
4
|
+
|
5
|
+
from omlish.lite.inject import InjectorBindingOrBindings
|
6
|
+
from omlish.lite.inject import InjectorBindings
|
7
|
+
from omlish.lite.inject import inj
|
8
|
+
|
9
|
+
from ..commands.inject import bind_command
|
10
|
+
from .commands import CheckSystemPackageCommand
|
11
|
+
from .commands import CheckSystemPackageCommandExecutor
|
12
|
+
from .config import SystemConfig
|
13
|
+
from .packages import AptSystemPackageManager
|
14
|
+
from .packages import BrewSystemPackageManager
|
15
|
+
from .packages import SystemPackageManager
|
16
|
+
from .types import SystemPlatform
|
17
|
+
|
18
|
+
|
19
|
+
def bind_system(
|
20
|
+
*,
|
21
|
+
system_config: SystemConfig,
|
22
|
+
) -> InjectorBindings:
|
23
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
24
|
+
inj.bind(system_config),
|
25
|
+
]
|
26
|
+
|
27
|
+
#
|
28
|
+
|
29
|
+
platform = system_config.platform or sys.platform
|
30
|
+
lst.append(inj.bind(platform, key=SystemPlatform))
|
31
|
+
|
32
|
+
#
|
33
|
+
|
34
|
+
if platform == 'linux':
|
35
|
+
lst.extend([
|
36
|
+
inj.bind(AptSystemPackageManager, singleton=True),
|
37
|
+
inj.bind(SystemPackageManager, to_key=AptSystemPackageManager),
|
38
|
+
])
|
39
|
+
|
40
|
+
elif platform == 'darwin':
|
41
|
+
lst.extend([
|
42
|
+
inj.bind(BrewSystemPackageManager, singleton=True),
|
43
|
+
inj.bind(SystemPackageManager, to_key=BrewSystemPackageManager),
|
44
|
+
])
|
45
|
+
|
46
|
+
#
|
47
|
+
|
48
|
+
lst.extend([
|
49
|
+
bind_command(CheckSystemPackageCommand, CheckSystemPackageCommandExecutor),
|
50
|
+
])
|
51
|
+
|
52
|
+
#
|
53
|
+
|
54
|
+
return inj.as_bindings(*lst)
|