ominfra 0.0.0.dev148__py3-none-any.whl → 0.0.0.dev150__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ominfra/clouds/aws/auth.py +7 -9
- ominfra/clouds/aws/cli.py +1 -1
- ominfra/clouds/aws/journald2aws/driver.py +4 -4
- ominfra/clouds/aws/logs.py +4 -5
- ominfra/clouds/gcp/auth.py +1 -1
- ominfra/configs.py +3 -4
- ominfra/journald/messages.py +3 -3
- ominfra/journald/tailer.py +2 -2
- ominfra/manage/commands/base.py +2 -2
- ominfra/manage/commands/interp.py +3 -3
- ominfra/manage/commands/subprocess.py +3 -4
- ominfra/manage/deploy/paths.py +12 -15
- ominfra/manage/main.py +72 -75
- ominfra/manage/remote/_main.py +6 -7
- ominfra/manage/remote/execution.py +7 -10
- ominfra/manage/remote/spawning.py +3 -3
- ominfra/scripts/journald2aws.py +508 -147
- ominfra/scripts/manage.py +772 -183
- ominfra/scripts/supervisor.py +1144 -783
- ominfra/supervisor/dispatchers.py +1 -1
- ominfra/supervisor/groupsimpl.py +2 -2
- ominfra/supervisor/http.py +7 -7
- ominfra/supervisor/inject.py +4 -4
- ominfra/supervisor/io.py +1 -1
- ominfra/supervisor/main.py +1 -1
- ominfra/supervisor/processimpl.py +2 -2
- ominfra/supervisor/spawningimpl.py +9 -10
- ominfra/supervisor/supervisor.py +3 -3
- ominfra/supervisor/types.py +1 -1
- ominfra/tailscale/cli.py +1 -1
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/RECORD +36 -36
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev148.dist-info → ominfra-0.0.0.dev150.dist-info}/top_level.txt +0 -0
ominfra/clouds/aws/auth.py
CHANGED
@@ -17,9 +17,7 @@ import hmac
|
|
17
17
|
import typing as ta
|
18
18
|
import urllib.parse
|
19
19
|
|
20
|
-
from omlish.lite.check import
|
21
|
-
from omlish.lite.check import check_non_empty_str
|
22
|
-
from omlish.lite.check import check_not_isinstance
|
20
|
+
from omlish.lite.check import check
|
23
21
|
|
24
22
|
|
25
23
|
##
|
@@ -60,7 +58,7 @@ class AwsSigner:
|
|
60
58
|
@staticmethod
|
61
59
|
def _host_from_url(url: str) -> str:
|
62
60
|
url_parts = urllib.parse.urlsplit(url)
|
63
|
-
host =
|
61
|
+
host = check.non_empty_str(url_parts.hostname)
|
64
62
|
default_ports = {
|
65
63
|
'http': 80,
|
66
64
|
'https': 443,
|
@@ -74,7 +72,7 @@ class AwsSigner:
|
|
74
72
|
def _lower_case_http_map(d: ta.Mapping[str, ta.Sequence[str]]) -> ta.Mapping[str, ta.Sequence[str]]:
|
75
73
|
o: ta.Dict[str, ta.List[str]] = {}
|
76
74
|
for k, vs in d.items():
|
77
|
-
o.setdefault(k.lower(), []).extend(
|
75
|
+
o.setdefault(k.lower(), []).extend(check.not_isinstance(vs, str))
|
78
76
|
return o
|
79
77
|
|
80
78
|
#
|
@@ -107,12 +105,12 @@ class AwsSigner:
|
|
107
105
|
])
|
108
106
|
|
109
107
|
def _validate_request(self, req: Request) -> None:
|
110
|
-
|
111
|
-
|
108
|
+
check.non_empty_str(req.method)
|
109
|
+
check.equal(req.method.upper(), req.method)
|
112
110
|
for k, vs in req.headers.items():
|
113
|
-
|
111
|
+
check.equal(k.strip(), k)
|
114
112
|
for v in vs:
|
115
|
-
|
113
|
+
check.equal(v.strip(), v)
|
116
114
|
|
117
115
|
|
118
116
|
AwsSigner._EMPTY_SHA256 = AwsSigner._sha256(b'') # noqa
|
ominfra/clouds/aws/cli.py
CHANGED
@@ -38,7 +38,7 @@ import time
|
|
38
38
|
import typing as ta
|
39
39
|
|
40
40
|
from omlish.lite.cached import cached_nullary
|
41
|
-
from omlish.lite.check import
|
41
|
+
from omlish.lite.check import check
|
42
42
|
from omlish.lite.contextmanagers import ExitStacked
|
43
43
|
from omlish.lite.logs import log
|
44
44
|
from omlish.lite.pidfile import Pidfile
|
@@ -126,15 +126,15 @@ class JournalctlToAwsDriver(ExitStacked):
|
|
126
126
|
return None
|
127
127
|
|
128
128
|
return AwsSigner.Credentials(
|
129
|
-
access_key_id=
|
130
|
-
secret_access_key=
|
129
|
+
access_key_id=check.non_empty_str(self._config.aws_access_key_id),
|
130
|
+
secret_access_key=check.non_empty_str(self._config.aws_secret_access_key),
|
131
131
|
)
|
132
132
|
|
133
133
|
@cached_nullary
|
134
134
|
def _aws_log_message_builder(self) -> AwsLogMessageBuilder:
|
135
135
|
return AwsLogMessageBuilder(
|
136
136
|
log_group_name=self._config.aws_log_group_name,
|
137
|
-
log_stream_name=
|
137
|
+
log_stream_name=check.non_empty_str(self._config.aws_log_stream_name),
|
138
138
|
region_name=self._config.aws_region_name,
|
139
139
|
credentials=self._aws_credentials(),
|
140
140
|
)
|
ominfra/clouds/aws/logs.py
CHANGED
@@ -19,8 +19,7 @@ import dataclasses as dc
|
|
19
19
|
import json
|
20
20
|
import typing as ta
|
21
21
|
|
22
|
-
from omlish.lite.check import
|
23
|
-
from omlish.lite.check import check_single
|
22
|
+
from omlish.lite.check import check
|
24
23
|
|
25
24
|
from .auth import AwsSigner
|
26
25
|
from .auth import V4AwsSigner
|
@@ -97,8 +96,8 @@ class AwsLogMessageBuilder:
|
|
97
96
|
) -> None:
|
98
97
|
super().__init__()
|
99
98
|
|
100
|
-
self._log_group_name =
|
101
|
-
self._log_stream_name =
|
99
|
+
self._log_group_name = check.non_empty_str(log_group_name)
|
100
|
+
self._log_stream_name = check.non_empty_str(log_stream_name)
|
102
101
|
|
103
102
|
if url is None:
|
104
103
|
url = self.DEFAULT_URL.format(region_name=region_name)
|
@@ -172,7 +171,7 @@ class AwsLogMessageBuilder:
|
|
172
171
|
|
173
172
|
post = AwsLogMessageBuilder.Post(
|
174
173
|
url=self._url,
|
175
|
-
headers={k:
|
174
|
+
headers={k: check.single(v) for k, v in sig_req.headers.items()},
|
176
175
|
data=sig_req.payload,
|
177
176
|
)
|
178
177
|
|
ominfra/clouds/gcp/auth.py
CHANGED
ominfra/configs.py
CHANGED
@@ -5,8 +5,7 @@ import os.path
|
|
5
5
|
import typing as ta
|
6
6
|
|
7
7
|
from omdev.toml.parser import toml_loads
|
8
|
-
from omlish.lite.check import
|
9
|
-
from omlish.lite.check import check_not_isinstance
|
8
|
+
from omlish.lite.check import check
|
10
9
|
from omlish.lite.marshal import unmarshal_obj
|
11
10
|
|
12
11
|
|
@@ -72,7 +71,7 @@ def build_config_named_children(
|
|
72
71
|
lst: ta.List[ConfigMapping] = []
|
73
72
|
if isinstance(o, ta.Mapping):
|
74
73
|
for k, v in o.items():
|
75
|
-
|
74
|
+
check.isinstance(v, ta.Mapping)
|
76
75
|
if name_key in v:
|
77
76
|
n = v[name_key]
|
78
77
|
if k != n:
|
@@ -82,7 +81,7 @@ def build_config_named_children(
|
|
82
81
|
lst.append({name_key: k, **v})
|
83
82
|
|
84
83
|
else:
|
85
|
-
|
84
|
+
check.not_isinstance(o, str)
|
86
85
|
lst.extend(o)
|
87
86
|
|
88
87
|
seen = set()
|
ominfra/journald/messages.py
CHANGED
@@ -4,8 +4,8 @@ import dataclasses as dc
|
|
4
4
|
import json
|
5
5
|
import typing as ta
|
6
6
|
|
7
|
-
from omlish.
|
8
|
-
from omlish.lite.
|
7
|
+
from omlish.io.buffers import DelimitingBuffer
|
8
|
+
from omlish.lite.check import check
|
9
9
|
from omlish.lite.logs import log
|
10
10
|
|
11
11
|
|
@@ -74,5 +74,5 @@ class JournalctlMessageBuilder:
|
|
74
74
|
def feed(self, data: bytes) -> ta.Sequence[JournalctlMessage]:
|
75
75
|
ret: ta.List[JournalctlMessage] = []
|
76
76
|
for line in self._buf.feed(data):
|
77
|
-
ret.append(self._make_message(
|
77
|
+
ret.append(self._make_message(check.isinstance(line, bytes)))
|
78
78
|
return ret
|
ominfra/journald/tailer.py
CHANGED
@@ -408,7 +408,7 @@ import time
|
|
408
408
|
import typing as ta
|
409
409
|
|
410
410
|
from omlish.lite.cached import cached_nullary
|
411
|
-
from omlish.lite.check import
|
411
|
+
from omlish.lite.check import check
|
412
412
|
from omlish.lite.logs import log
|
413
413
|
from omlish.lite.subprocesses import subprocess_close
|
414
414
|
from omlish.lite.subprocesses import subprocess_shell_wrap_exec
|
@@ -499,7 +499,7 @@ class JournalctlTailerWorker(ThreadWorker):
|
|
499
499
|
stdout=subprocess.PIPE,
|
500
500
|
) as self._proc:
|
501
501
|
try:
|
502
|
-
stdout =
|
502
|
+
stdout = check.not_none(self._proc.stdout)
|
503
503
|
|
504
504
|
fd = stdout.fileno()
|
505
505
|
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
|
ominfra/manage/commands/base.py
CHANGED
@@ -5,7 +5,7 @@ import logging
|
|
5
5
|
import traceback
|
6
6
|
import typing as ta
|
7
7
|
|
8
|
-
from omlish.lite.check import
|
8
|
+
from omlish.lite.check import check
|
9
9
|
from omlish.lite.strings import snake_case
|
10
10
|
|
11
11
|
|
@@ -24,7 +24,7 @@ class Command(abc.ABC, ta.Generic[CommandOutputT]):
|
|
24
24
|
|
25
25
|
@ta.final
|
26
26
|
async def execute(self, executor: 'CommandExecutor') -> CommandOutputT:
|
27
|
-
return
|
27
|
+
return check.isinstance(await executor.execute(self), self.Output) # type: ignore[return-value]
|
28
28
|
|
29
29
|
|
30
30
|
##
|
@@ -4,7 +4,7 @@ import dataclasses as dc
|
|
4
4
|
from omdev.interp.resolvers import DEFAULT_INTERP_RESOLVER
|
5
5
|
from omdev.interp.types import InterpOpts
|
6
6
|
from omdev.interp.types import InterpSpecifier
|
7
|
-
from omlish.lite.check import
|
7
|
+
from omlish.lite.check import check
|
8
8
|
|
9
9
|
from ..commands.base import Command
|
10
10
|
from ..commands.base import CommandExecutor
|
@@ -30,8 +30,8 @@ class InterpCommand(Command['InterpCommand.Output']):
|
|
30
30
|
|
31
31
|
class InterpCommandExecutor(CommandExecutor[InterpCommand, InterpCommand.Output]):
|
32
32
|
async def execute(self, cmd: InterpCommand) -> InterpCommand.Output:
|
33
|
-
i = InterpSpecifier.parse(
|
34
|
-
o =
|
33
|
+
i = InterpSpecifier.parse(check.not_none(cmd.spec))
|
34
|
+
o = check.not_none(await DEFAULT_INTERP_RESOLVER.resolve(i, install=cmd.install))
|
35
35
|
return InterpCommand.Output(
|
36
36
|
exe=o.exe,
|
37
37
|
version=str(o.version.version),
|
@@ -8,8 +8,7 @@ import typing as ta
|
|
8
8
|
|
9
9
|
from omlish.lite.asyncio.subprocesses import asyncio_subprocess_communicate
|
10
10
|
from omlish.lite.asyncio.subprocesses import asyncio_subprocess_popen
|
11
|
-
from omlish.lite.check import
|
12
|
-
from omlish.lite.check import check_not_none
|
11
|
+
from omlish.lite.check import check
|
13
12
|
from omlish.lite.subprocesses import SUBPROCESS_CHANNEL_OPTION_VALUES
|
14
13
|
from omlish.lite.subprocesses import SubprocessChannelOption
|
15
14
|
from omlish.lite.subprocesses import subprocess_maybe_shell_wrap_exec
|
@@ -36,7 +35,7 @@ class SubprocessCommand(Command['SubprocessCommand.Output']):
|
|
36
35
|
timeout: ta.Optional[float] = None
|
37
36
|
|
38
37
|
def __post_init__(self) -> None:
|
39
|
-
|
38
|
+
check.not_isinstance(self.cmd, str)
|
40
39
|
|
41
40
|
@dc.dataclass(frozen=True)
|
42
41
|
class Output(Command.Output):
|
@@ -77,7 +76,7 @@ class SubprocessCommandExecutor(CommandExecutor[SubprocessCommand, SubprocessCom
|
|
77
76
|
end_time = time.time()
|
78
77
|
|
79
78
|
return SubprocessCommand.Output(
|
80
|
-
rc=
|
79
|
+
rc=check.not_none(proc.returncode),
|
81
80
|
pid=proc.pid,
|
82
81
|
|
83
82
|
elapsed_s=end_time - start_time,
|
ominfra/manage/deploy/paths.py
CHANGED
@@ -36,10 +36,7 @@ import dataclasses as dc
|
|
36
36
|
import os.path
|
37
37
|
import typing as ta
|
38
38
|
|
39
|
-
from omlish.lite.check import
|
40
|
-
from omlish.lite.check import check_non_empty
|
41
|
-
from omlish.lite.check import check_non_empty_str
|
42
|
-
from omlish.lite.check import check_not_in
|
39
|
+
from omlish.lite.check import check
|
43
40
|
|
44
41
|
|
45
42
|
DeployPathKind = ta.Literal['dir', 'file'] # ta.TypeAlias
|
@@ -74,7 +71,7 @@ class DeployPathDir(DeployPathPart, abc.ABC):
|
|
74
71
|
@classmethod
|
75
72
|
def parse(cls, s: str) -> 'DeployPathDir':
|
76
73
|
if DEPLOY_PATH_SPEC_PLACEHOLDER in s:
|
77
|
-
|
74
|
+
check.equal(s, DEPLOY_PATH_SPEC_PLACEHOLDER)
|
78
75
|
return SpecDeployPathDir()
|
79
76
|
else:
|
80
77
|
return ConstDeployPathDir(s)
|
@@ -88,7 +85,7 @@ class DeployPathFile(DeployPathPart, abc.ABC):
|
|
88
85
|
@classmethod
|
89
86
|
def parse(cls, s: str) -> 'DeployPathFile':
|
90
87
|
if DEPLOY_PATH_SPEC_PLACEHOLDER in s:
|
91
|
-
|
88
|
+
check.equal(s[0], DEPLOY_PATH_SPEC_PLACEHOLDER)
|
92
89
|
return SpecDeployPathFile(s[1:])
|
93
90
|
else:
|
94
91
|
return ConstDeployPathFile(s)
|
@@ -102,9 +99,9 @@ class ConstDeployPathPart(DeployPathPart, abc.ABC):
|
|
102
99
|
name: str
|
103
100
|
|
104
101
|
def __post_init__(self) -> None:
|
105
|
-
|
106
|
-
|
107
|
-
|
102
|
+
check.non_empty_str(self.name)
|
103
|
+
check.not_in('/', self.name)
|
104
|
+
check.not_in(DEPLOY_PATH_SPEC_PLACEHOLDER, self.name)
|
108
105
|
|
109
106
|
def render(self) -> str:
|
110
107
|
return self.name
|
@@ -135,9 +132,9 @@ class SpecDeployPathFile(SpecDeployPathPart, DeployPathFile):
|
|
135
132
|
suffix: str
|
136
133
|
|
137
134
|
def __post_init__(self) -> None:
|
138
|
-
|
139
|
-
|
140
|
-
|
135
|
+
check.non_empty_str(self.suffix)
|
136
|
+
check.not_in('/', self.suffix)
|
137
|
+
check.not_in(DEPLOY_PATH_SPEC_PLACEHOLDER, self.suffix)
|
141
138
|
|
142
139
|
def render(self) -> str:
|
143
140
|
return DEPLOY_PATH_SPEC_PLACEHOLDER + self.suffix
|
@@ -151,9 +148,9 @@ class DeployPath:
|
|
151
148
|
parts: ta.Sequence[DeployPathPart]
|
152
149
|
|
153
150
|
def __post_init__(self) -> None:
|
154
|
-
|
151
|
+
check.not_empty(self.parts)
|
155
152
|
for p in self.parts[:-1]:
|
156
|
-
|
153
|
+
check.equal(p.kind, 'dir')
|
157
154
|
|
158
155
|
@property
|
159
156
|
def kind(self) -> ta.Literal['file', 'dir']:
|
@@ -173,7 +170,7 @@ class DeployPath:
|
|
173
170
|
s = s[:-1]
|
174
171
|
else:
|
175
172
|
tail_parse = DeployPathFile.parse
|
176
|
-
ps =
|
173
|
+
ps = check.non_empty_str(s).split('/')
|
177
174
|
return cls([
|
178
175
|
*([DeployPathDir.parse(p) for p in ps[:-1]] if len(ps) > 1 else []),
|
179
176
|
tail_parse(ps[-1]),
|
ominfra/manage/main.py
CHANGED
@@ -10,6 +10,9 @@ import contextlib
|
|
10
10
|
import json
|
11
11
|
import typing as ta
|
12
12
|
|
13
|
+
from omlish.argparse.cli import ArgparseCli
|
14
|
+
from omlish.argparse.cli import argparse_arg
|
15
|
+
from omlish.argparse.cli import argparse_command
|
13
16
|
from omlish.lite.logs import log # noqa
|
14
17
|
from omlish.lite.marshal import ObjMarshalerManager
|
15
18
|
from omlish.lite.marshal import ObjMarshalOptions
|
@@ -26,108 +29,102 @@ from .remote.connection import RemoteExecutionConnector
|
|
26
29
|
from .remote.spawning import RemoteSpawning
|
27
30
|
|
28
31
|
|
29
|
-
|
32
|
+
class MainCli(ArgparseCli):
|
33
|
+
@argparse_command(
|
34
|
+
argparse_arg('--payload-file'),
|
30
35
|
|
36
|
+
argparse_arg('-s', '--shell'),
|
37
|
+
argparse_arg('-q', '--shell-quote', action='store_true'),
|
38
|
+
argparse_arg('--python', default='python3'),
|
31
39
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
log_level='DEBUG' if args.debug else 'INFO',
|
40
|
+
argparse_arg('--pycharm-debug-port', type=int),
|
41
|
+
argparse_arg('--pycharm-debug-host'),
|
42
|
+
argparse_arg('--pycharm-debug-version'),
|
36
43
|
|
37
|
-
|
38
|
-
),
|
44
|
+
argparse_arg('--remote-timebomb-delay-s', type=float),
|
39
45
|
|
40
|
-
|
41
|
-
payload_file=args._payload_file, # noqa
|
46
|
+
argparse_arg('--debug', action='store_true'),
|
42
47
|
|
43
|
-
|
44
|
-
port=args.pycharm_debug_port,
|
45
|
-
**(dict(host=args.pycharm_debug_host) if args.pycharm_debug_host is not None else {}),
|
46
|
-
install_version=args.pycharm_debug_version,
|
47
|
-
) if args.pycharm_debug_port is not None else None,
|
48
|
+
argparse_arg('--local', action='store_true'),
|
48
49
|
|
49
|
-
|
50
|
-
),
|
50
|
+
argparse_arg('command', nargs='+'),
|
51
51
|
)
|
52
|
+
def run(self) -> None:
|
53
|
+
asyncio.run(self._async_run())
|
52
54
|
|
53
|
-
|
55
|
+
async def _async_run(self) -> None:
|
56
|
+
bs = MainBootstrap(
|
57
|
+
main_config=MainConfig(
|
58
|
+
log_level='DEBUG' if self.args.debug else 'INFO',
|
54
59
|
|
55
|
-
|
56
|
-
|
57
|
-
)
|
58
|
-
|
59
|
-
#
|
60
|
-
|
61
|
-
msh = injector[ObjMarshalerManager]
|
60
|
+
debug=bool(self.args.debug),
|
61
|
+
),
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
for c in args.command:
|
66
|
-
if not c.startswith('{'):
|
67
|
-
c = json.dumps({c: {}})
|
68
|
-
cmd = msh.unmarshal_obj(json.loads(c), Command)
|
69
|
-
cmds.append(cmd)
|
63
|
+
remote_config=RemoteConfig(
|
64
|
+
payload_file=self.args.payload_file, # noqa
|
70
65
|
|
71
|
-
|
66
|
+
pycharm_remote_debug=PycharmRemoteDebug(
|
67
|
+
port=self.args.pycharm_debug_port,
|
68
|
+
**(dict(host=self.args.pycharm_debug_host) if self.args.pycharm_debug_host is not None else {}),
|
69
|
+
install_version=self.args.pycharm_debug_version,
|
70
|
+
) if self.args.pycharm_debug_port is not None else None,
|
72
71
|
|
73
|
-
|
74
|
-
|
72
|
+
timebomb_delay_s=self.args.remote_timebomb_delay_s,
|
73
|
+
),
|
74
|
+
)
|
75
75
|
|
76
|
-
|
77
|
-
ce = injector[LocalCommandExecutor]
|
76
|
+
#
|
78
77
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
shell_quote=args.shell_quote,
|
83
|
-
python=args.python,
|
84
|
-
)
|
78
|
+
injector = main_bootstrap(
|
79
|
+
bs,
|
80
|
+
)
|
85
81
|
|
86
|
-
|
82
|
+
#
|
87
83
|
|
88
|
-
|
89
|
-
res = await ce.try_execute(
|
90
|
-
cmd,
|
91
|
-
log=log,
|
92
|
-
omit_exc_object=True,
|
93
|
-
)
|
84
|
+
msh = injector[ObjMarshalerManager]
|
94
85
|
|
95
|
-
|
86
|
+
cmds: ta.List[Command] = []
|
87
|
+
cmd: Command
|
88
|
+
for c in self.args.command:
|
89
|
+
if not c.startswith('{'):
|
90
|
+
c = json.dumps({c: {}})
|
91
|
+
cmd = msh.unmarshal_obj(json.loads(c), Command)
|
92
|
+
cmds.append(cmd)
|
96
93
|
|
97
|
-
|
98
|
-
run_command(cmd)
|
99
|
-
for cmd in cmds
|
100
|
-
])
|
94
|
+
#
|
101
95
|
|
96
|
+
async with contextlib.AsyncExitStack() as es:
|
97
|
+
ce: CommandExecutor
|
102
98
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
parser = argparse.ArgumentParser()
|
99
|
+
if self.args.local:
|
100
|
+
ce = injector[LocalCommandExecutor]
|
107
101
|
|
108
|
-
|
102
|
+
else:
|
103
|
+
tgt = RemoteSpawning.Target(
|
104
|
+
shell=self.args.shell,
|
105
|
+
shell_quote=self.args.shell_quote,
|
106
|
+
python=self.args.python,
|
107
|
+
)
|
109
108
|
|
110
|
-
|
111
|
-
parser.add_argument('-q', '--shell-quote', action='store_true')
|
112
|
-
parser.add_argument('--python', default='python3')
|
109
|
+
ce = await es.enter_async_context(injector[RemoteExecutionConnector].connect(tgt, bs)) # noqa
|
113
110
|
|
114
|
-
|
115
|
-
|
116
|
-
|
111
|
+
async def run_command(cmd: Command) -> None:
|
112
|
+
res = await ce.try_execute(
|
113
|
+
cmd,
|
114
|
+
log=log,
|
115
|
+
omit_exc_object=True,
|
116
|
+
)
|
117
117
|
|
118
|
-
|
118
|
+
print(msh.marshal_obj(res, opts=ObjMarshalOptions(raw_bytes=True)))
|
119
119
|
|
120
|
-
|
120
|
+
await asyncio.gather(*[
|
121
|
+
run_command(cmd)
|
122
|
+
for cmd in cmds
|
123
|
+
])
|
121
124
|
|
122
|
-
parser.add_argument('--local', action='store_true')
|
123
125
|
|
124
|
-
|
125
|
-
|
126
|
-
args = parser.parse_args()
|
127
|
-
|
128
|
-
#
|
129
|
-
|
130
|
-
asyncio.run(_async_main(args))
|
126
|
+
def _main() -> None:
|
127
|
+
MainCli().call_and_exit()
|
131
128
|
|
132
129
|
|
133
130
|
if __name__ == '__main__':
|
ominfra/manage/remote/_main.py
CHANGED
@@ -11,8 +11,7 @@ import typing as ta
|
|
11
11
|
from omlish.lite.asyncio.asyncio import asyncio_open_stream_reader
|
12
12
|
from omlish.lite.asyncio.asyncio import asyncio_open_stream_writer
|
13
13
|
from omlish.lite.cached import cached_nullary
|
14
|
-
from omlish.lite.check import
|
15
|
-
from omlish.lite.check import check_not_none
|
14
|
+
from omlish.lite.check import check
|
16
15
|
from omlish.lite.deathsig import set_process_deathsig
|
17
16
|
from omlish.lite.inject import Injector
|
18
17
|
from omlish.lite.logs import log
|
@@ -64,11 +63,11 @@ class _RemoteExecutionMain:
|
|
64
63
|
|
65
64
|
@property
|
66
65
|
def _bootstrap(self) -> MainBootstrap:
|
67
|
-
return
|
66
|
+
return check.not_none(self.__bootstrap)
|
68
67
|
|
69
68
|
@property
|
70
69
|
def _injector(self) -> Injector:
|
71
|
-
return
|
70
|
+
return check.not_none(self.__injector)
|
72
71
|
|
73
72
|
#
|
74
73
|
|
@@ -112,12 +111,12 @@ class _RemoteExecutionMain:
|
|
112
111
|
#
|
113
112
|
|
114
113
|
async def _setup(self) -> None:
|
115
|
-
|
116
|
-
|
114
|
+
check.none(self.__bootstrap)
|
115
|
+
check.none(self.__injector)
|
117
116
|
|
118
117
|
# Bootstrap
|
119
118
|
|
120
|
-
self.__bootstrap =
|
119
|
+
self.__bootstrap = check.not_none(await self._chan.recv_obj(MainBootstrap))
|
121
120
|
|
122
121
|
if (prd := self._bootstrap.remote_config.pycharm_remote_debug) is not None:
|
123
122
|
pycharm_debug_connect(prd)
|
@@ -6,10 +6,7 @@ import itertools
|
|
6
6
|
import logging
|
7
7
|
import typing as ta
|
8
8
|
|
9
|
-
from omlish.lite.check import
|
10
|
-
from omlish.lite.check import check_none
|
11
|
-
from omlish.lite.check import check_not_none
|
12
|
-
from omlish.lite.check import check_state
|
9
|
+
from omlish.lite.check import check
|
13
10
|
from omlish.lite.logs import log
|
14
11
|
|
15
12
|
from ..commands.base import Command
|
@@ -133,7 +130,7 @@ class _RemoteCommandHandler:
|
|
133
130
|
], return_when=asyncio.FIRST_COMPLETED)
|
134
131
|
|
135
132
|
if recv_task in done:
|
136
|
-
msg: ta.Optional[_RemoteProtocol.Message] =
|
133
|
+
msg: ta.Optional[_RemoteProtocol.Message] = check.isinstance(
|
137
134
|
recv_task.result(),
|
138
135
|
(_RemoteProtocol.Message, type(None)),
|
139
136
|
)
|
@@ -202,8 +199,8 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
202
199
|
#
|
203
200
|
|
204
201
|
async def start(self) -> None:
|
205
|
-
|
206
|
-
|
202
|
+
check.none(self._loop_task)
|
203
|
+
check.state(not self._stop.is_set())
|
207
204
|
self._loop_task = asyncio.create_task(self._loop())
|
208
205
|
|
209
206
|
async def aclose(self) -> None:
|
@@ -239,12 +236,12 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
239
236
|
], return_when=asyncio.FIRST_COMPLETED)
|
240
237
|
|
241
238
|
if queue_task in done:
|
242
|
-
req =
|
239
|
+
req = check.isinstance(queue_task.result(), RemoteCommandExecutor._Request)
|
243
240
|
queue_task = None
|
244
241
|
await self._handle_request(req)
|
245
242
|
|
246
243
|
if recv_task in done:
|
247
|
-
msg: ta.Optional[_RemoteProtocol.Message] =
|
244
|
+
msg: ta.Optional[_RemoteProtocol.Message] = check.isinstance(
|
248
245
|
recv_task.result(),
|
249
246
|
(_RemoteProtocol.Message, type(None)),
|
250
247
|
)
|
@@ -312,7 +309,7 @@ class RemoteCommandExecutor(CommandExecutor):
|
|
312
309
|
if (e := r.exception) is not None:
|
313
310
|
raise RemoteCommandError(e)
|
314
311
|
else:
|
315
|
-
return
|
312
|
+
return check.not_none(r.output)
|
316
313
|
|
317
314
|
# @ta.override
|
318
315
|
async def try_execute(
|
@@ -8,7 +8,7 @@ import subprocess
|
|
8
8
|
import typing as ta
|
9
9
|
|
10
10
|
from omlish.lite.asyncio.subprocesses import asyncio_subprocess_popen
|
11
|
-
from omlish.lite.check import
|
11
|
+
from omlish.lite.check import check
|
12
12
|
from omlish.lite.subprocesses import SUBPROCESS_CHANNEL_OPTION_VALUES
|
13
13
|
from omlish.lite.subprocesses import SubprocessChannelOption
|
14
14
|
from omlish.lite.subprocesses import subprocess_maybe_shell_wrap_exec
|
@@ -97,8 +97,8 @@ class SubprocessRemoteSpawning(RemoteSpawning):
|
|
97
97
|
),
|
98
98
|
timeout=timeout,
|
99
99
|
) as proc:
|
100
|
-
stdin =
|
101
|
-
stdout =
|
100
|
+
stdin = check.not_none(proc.stdin)
|
101
|
+
stdout = check.not_none(proc.stdout)
|
102
102
|
|
103
103
|
try:
|
104
104
|
yield RemoteSpawning.Spawned(
|