ominfra 0.0.0.dev149__tar.gz → 0.0.0.dev151__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {ominfra-0.0.0.dev149/ominfra.egg-info → ominfra-0.0.0.dev151}/PKG-INFO +3 -3
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/aws/auth.py +7 -9
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/aws/journald2aws/driver.py +4 -4
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/aws/logs.py +4 -5
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/gcp/auth.py +1 -1
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/configs.py +3 -4
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/journald/messages.py +2 -2
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/journald/tailer.py +2 -2
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/commands/base.py +2 -2
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/commands/interp.py +3 -3
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/commands/subprocess.py +3 -4
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/deploy/paths.py +12 -15
- ominfra-0.0.0.dev151/ominfra/manage/main.py +131 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/remote/_main.py +6 -7
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/remote/execution.py +7 -10
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/remote/spawning.py +3 -3
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/scripts/journald2aws.py +449 -93
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/scripts/manage.py +770 -186
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/scripts/supervisor.py +1137 -781
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/groupsimpl.py +2 -2
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/http.py +5 -5
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/main.py +1 -1
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/processimpl.py +2 -2
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/spawningimpl.py +8 -9
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/supervisor.py +2 -2
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151/ominfra.egg-info}/PKG-INFO +3 -3
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra.egg-info/requires.txt +2 -2
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/pyproject.toml +3 -3
- ominfra-0.0.0.dev149/ominfra/manage/main.py +0 -134
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/LICENSE +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/MANIFEST.in +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/README.rst +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/.manifests.json +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/__about__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/aws/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/aws/__main__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/aws/cli.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/aws/dataclasses.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/aws/journald2aws/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/aws/journald2aws/__main__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/aws/journald2aws/cursor.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/aws/journald2aws/main.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/aws/journald2aws/poster.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/aws/metadata.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/clouds/gcp/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/cmds.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/journald/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/journald/fields.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/journald/genmessages.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/__main__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/bootstrap.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/bootstrap_.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/commands/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/commands/execution.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/commands/inject.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/commands/marshal.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/config.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/deploy/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/deploy/command.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/deploy/inject.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/inject.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/marshal.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/remote/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/remote/channel.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/remote/config.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/remote/connection.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/remote/inject.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/manage/remote/payload.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/pyremote.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/scripts/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/ssh.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/LICENSE.txt +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/__main__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/configs.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/dispatchers.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/dispatchersimpl.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/events.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/exceptions.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/groups.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/inject.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/io.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/pipes.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/privileges.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/process.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/setup.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/setupimpl.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/signals.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/spawning.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/states.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/types.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/utils/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/utils/collections.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/utils/diag.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/utils/fds.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/utils/fs.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/utils/os.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/utils/ostypes.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/utils/signals.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/utils/strings.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/supervisor/utils/users.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/tailscale/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/tailscale/api.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/tailscale/cli.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/threadworkers.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/tools/__init__.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra/tools/listresources.py +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra.egg-info/SOURCES.txt +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra.egg-info/dependency_links.txt +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra.egg-info/entry_points.txt +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/ominfra.egg-info/top_level.txt +0 -0
- {ominfra-0.0.0.dev149 → ominfra-0.0.0.dev151}/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.dev151
|
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.dev151
|
16
|
+
Requires-Dist: omlish==0.0.0.dev151
|
17
17
|
Provides-Extra: all
|
18
18
|
Requires-Dist: paramiko~=3.5; extra == "all"
|
19
19
|
Requires-Dist: asyncssh~=2.18; extra == "all"
|
@@ -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
|
@@ -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
|
)
|
@@ -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
|
|
@@ -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()
|
@@ -5,7 +5,7 @@ import json
|
|
5
5
|
import typing as ta
|
6
6
|
|
7
7
|
from omlish.io.buffers import DelimitingBuffer
|
8
|
-
from omlish.lite.check import
|
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
|
@@ -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)
|
@@ -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,
|
@@ -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_str
|
41
|
-
from omlish.lite.check import check_not_empty
|
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]),
|
@@ -0,0 +1,131 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
# @omlish-amalg ../scripts/manage.py
|
3
|
+
# ruff: noqa: UP006 UP007
|
4
|
+
"""
|
5
|
+
manage.py -s 'docker run -i python:3.12'
|
6
|
+
manage.py -s 'ssh -i /foo/bar.pem foo@bar.baz' -q --python=python3.8
|
7
|
+
"""
|
8
|
+
import asyncio
|
9
|
+
import contextlib
|
10
|
+
import json
|
11
|
+
import typing as ta
|
12
|
+
|
13
|
+
from omlish.argparse.cli import ArgparseCli
|
14
|
+
from omlish.argparse.cli import argparse_arg
|
15
|
+
from omlish.argparse.cli import argparse_command
|
16
|
+
from omlish.lite.logs import log # noqa
|
17
|
+
from omlish.lite.marshal import ObjMarshalerManager
|
18
|
+
from omlish.lite.marshal import ObjMarshalOptions
|
19
|
+
from omlish.lite.pycharm import PycharmRemoteDebug
|
20
|
+
|
21
|
+
from .bootstrap import MainBootstrap
|
22
|
+
from .bootstrap_ import main_bootstrap
|
23
|
+
from .commands.base import Command
|
24
|
+
from .commands.base import CommandExecutor
|
25
|
+
from .commands.execution import LocalCommandExecutor
|
26
|
+
from .config import MainConfig
|
27
|
+
from .remote.config import RemoteConfig
|
28
|
+
from .remote.connection import RemoteExecutionConnector
|
29
|
+
from .remote.spawning import RemoteSpawning
|
30
|
+
|
31
|
+
|
32
|
+
class MainCli(ArgparseCli):
|
33
|
+
@argparse_command(
|
34
|
+
argparse_arg('--payload-file'),
|
35
|
+
|
36
|
+
argparse_arg('-s', '--shell'),
|
37
|
+
argparse_arg('-q', '--shell-quote', action='store_true'),
|
38
|
+
argparse_arg('--python', default='python3'),
|
39
|
+
|
40
|
+
argparse_arg('--pycharm-debug-port', type=int),
|
41
|
+
argparse_arg('--pycharm-debug-host'),
|
42
|
+
argparse_arg('--pycharm-debug-version'),
|
43
|
+
|
44
|
+
argparse_arg('--remote-timebomb-delay-s', type=float),
|
45
|
+
|
46
|
+
argparse_arg('--debug', action='store_true'),
|
47
|
+
|
48
|
+
argparse_arg('--local', action='store_true'),
|
49
|
+
|
50
|
+
argparse_arg('command', nargs='+'),
|
51
|
+
)
|
52
|
+
def run(self) -> None:
|
53
|
+
asyncio.run(self._async_run())
|
54
|
+
|
55
|
+
async def _async_run(self) -> None:
|
56
|
+
bs = MainBootstrap(
|
57
|
+
main_config=MainConfig(
|
58
|
+
log_level='DEBUG' if self.args.debug else 'INFO',
|
59
|
+
|
60
|
+
debug=bool(self.args.debug),
|
61
|
+
),
|
62
|
+
|
63
|
+
remote_config=RemoteConfig(
|
64
|
+
payload_file=self.args.payload_file, # noqa
|
65
|
+
|
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,
|
71
|
+
|
72
|
+
timebomb_delay_s=self.args.remote_timebomb_delay_s,
|
73
|
+
),
|
74
|
+
)
|
75
|
+
|
76
|
+
#
|
77
|
+
|
78
|
+
injector = main_bootstrap(
|
79
|
+
bs,
|
80
|
+
)
|
81
|
+
|
82
|
+
#
|
83
|
+
|
84
|
+
msh = injector[ObjMarshalerManager]
|
85
|
+
|
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)
|
93
|
+
|
94
|
+
#
|
95
|
+
|
96
|
+
async with contextlib.AsyncExitStack() as es:
|
97
|
+
ce: CommandExecutor
|
98
|
+
|
99
|
+
if self.args.local:
|
100
|
+
ce = injector[LocalCommandExecutor]
|
101
|
+
|
102
|
+
else:
|
103
|
+
tgt = RemoteSpawning.Target(
|
104
|
+
shell=self.args.shell,
|
105
|
+
shell_quote=self.args.shell_quote,
|
106
|
+
python=self.args.python,
|
107
|
+
)
|
108
|
+
|
109
|
+
ce = await es.enter_async_context(injector[RemoteExecutionConnector].connect(tgt, bs)) # noqa
|
110
|
+
|
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
|
+
|
118
|
+
print(msh.marshal_obj(res, opts=ObjMarshalOptions(raw_bytes=True)))
|
119
|
+
|
120
|
+
await asyncio.gather(*[
|
121
|
+
run_command(cmd)
|
122
|
+
for cmd in cmds
|
123
|
+
])
|
124
|
+
|
125
|
+
|
126
|
+
def _main() -> None:
|
127
|
+
MainCli().call_and_exit()
|
128
|
+
|
129
|
+
|
130
|
+
if __name__ == '__main__':
|
131
|
+
_main()
|
@@ -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(
|