ominfra 0.0.0.dev154__py3-none-any.whl → 0.0.0.dev155__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- ominfra/manage/bootstrap.py +4 -0
- ominfra/manage/bootstrap_.py +5 -0
- ominfra/manage/commands/inject.py +8 -11
- ominfra/manage/commands/{execution.py → local.py} +1 -5
- ominfra/manage/commands/ping.py +23 -0
- ominfra/manage/commands/types.py +8 -0
- ominfra/manage/deploy/apps.py +72 -0
- ominfra/manage/deploy/config.py +8 -0
- ominfra/manage/deploy/git.py +136 -0
- ominfra/manage/deploy/inject.py +21 -0
- ominfra/manage/deploy/paths.py +81 -28
- ominfra/manage/deploy/types.py +13 -0
- ominfra/manage/deploy/venvs.py +66 -0
- ominfra/manage/inject.py +20 -4
- ominfra/manage/main.py +15 -27
- ominfra/manage/remote/_main.py +1 -1
- ominfra/manage/remote/config.py +0 -2
- ominfra/manage/remote/connection.py +7 -24
- ominfra/manage/remote/execution.py +1 -1
- ominfra/manage/remote/inject.py +3 -14
- ominfra/manage/system/commands.py +22 -2
- ominfra/manage/system/config.py +3 -1
- ominfra/manage/system/inject.py +16 -6
- ominfra/manage/system/packages.py +33 -7
- ominfra/manage/system/platforms.py +72 -0
- ominfra/manage/targets/__init__.py +0 -0
- ominfra/manage/targets/connection.py +150 -0
- ominfra/manage/targets/inject.py +42 -0
- ominfra/manage/targets/targets.py +87 -0
- ominfra/scripts/journald2aws.py +24 -7
- ominfra/scripts/manage.py +1880 -438
- ominfra/scripts/supervisor.py +187 -25
- ominfra/supervisor/configs.py +163 -18
- {ominfra-0.0.0.dev154.dist-info → ominfra-0.0.0.dev155.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev154.dist-info → ominfra-0.0.0.dev155.dist-info}/RECORD +40 -29
- ominfra/manage/system/types.py +0 -5
- /ominfra/manage/{commands → deploy}/interp.py +0 -0
- {ominfra-0.0.0.dev154.dist-info → ominfra-0.0.0.dev155.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev154.dist-info → ominfra-0.0.0.dev155.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev154.dist-info → ominfra-0.0.0.dev155.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev154.dist-info → ominfra-0.0.0.dev155.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,150 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import abc
|
3
|
+
import contextlib
|
4
|
+
import dataclasses as dc
|
5
|
+
import typing as ta
|
6
|
+
|
7
|
+
from omlish.lite.check import check
|
8
|
+
|
9
|
+
from ..bootstrap import MainBootstrap
|
10
|
+
from ..commands.base import CommandExecutor
|
11
|
+
from ..commands.local import LocalCommandExecutor
|
12
|
+
from ..remote.connection import InProcessRemoteExecutionConnector
|
13
|
+
from ..remote.connection import PyremoteRemoteExecutionConnector
|
14
|
+
from ..remote.spawning import RemoteSpawning
|
15
|
+
from .targets import DockerManageTarget
|
16
|
+
from .targets import InProcessManageTarget
|
17
|
+
from .targets import LocalManageTarget
|
18
|
+
from .targets import ManageTarget
|
19
|
+
from .targets import SshManageTarget
|
20
|
+
from .targets import SubprocessManageTarget
|
21
|
+
|
22
|
+
|
23
|
+
##
|
24
|
+
|
25
|
+
|
26
|
+
class ManageTargetConnector(abc.ABC):
|
27
|
+
@abc.abstractmethod
|
28
|
+
def connect(self, tgt: ManageTarget) -> ta.AsyncContextManager[CommandExecutor]:
|
29
|
+
raise NotImplementedError
|
30
|
+
|
31
|
+
|
32
|
+
##
|
33
|
+
|
34
|
+
|
35
|
+
ManageTargetConnectorMap = ta.NewType('ManageTargetConnectorMap', ta.Mapping[ta.Type[ManageTarget], ManageTargetConnector]) # noqa
|
36
|
+
|
37
|
+
|
38
|
+
@dc.dataclass(frozen=True)
|
39
|
+
class TypeSwitchedManageTargetConnector(ManageTargetConnector):
|
40
|
+
connectors: ManageTargetConnectorMap
|
41
|
+
|
42
|
+
def get_connector(self, ty: ta.Type[ManageTarget]) -> ManageTargetConnector:
|
43
|
+
for k, v in self.connectors.items():
|
44
|
+
if issubclass(ty, k):
|
45
|
+
return v
|
46
|
+
raise KeyError(ty)
|
47
|
+
|
48
|
+
def connect(self, tgt: ManageTarget) -> ta.AsyncContextManager[CommandExecutor]:
|
49
|
+
return self.get_connector(type(tgt)).connect(tgt)
|
50
|
+
|
51
|
+
|
52
|
+
##
|
53
|
+
|
54
|
+
|
55
|
+
@dc.dataclass(frozen=True)
|
56
|
+
class LocalManageTargetConnector(ManageTargetConnector):
|
57
|
+
_local_executor: LocalCommandExecutor
|
58
|
+
_in_process_connector: InProcessRemoteExecutionConnector
|
59
|
+
_pyremote_connector: PyremoteRemoteExecutionConnector
|
60
|
+
_bootstrap: MainBootstrap
|
61
|
+
|
62
|
+
@contextlib.asynccontextmanager
|
63
|
+
async def connect(self, tgt: ManageTarget) -> ta.AsyncGenerator[CommandExecutor, None]:
|
64
|
+
lmt = check.isinstance(tgt, LocalManageTarget)
|
65
|
+
|
66
|
+
if isinstance(lmt, InProcessManageTarget):
|
67
|
+
imt = check.isinstance(lmt, InProcessManageTarget)
|
68
|
+
|
69
|
+
if imt.mode == InProcessManageTarget.Mode.DIRECT:
|
70
|
+
yield self._local_executor
|
71
|
+
|
72
|
+
elif imt.mode == InProcessManageTarget.Mode.FAKE_REMOTE:
|
73
|
+
async with self._in_process_connector.connect() as rce:
|
74
|
+
yield rce
|
75
|
+
|
76
|
+
else:
|
77
|
+
raise TypeError(imt.mode)
|
78
|
+
|
79
|
+
elif isinstance(lmt, SubprocessManageTarget):
|
80
|
+
async with self._pyremote_connector.connect(
|
81
|
+
RemoteSpawning.Target(
|
82
|
+
python=lmt.python,
|
83
|
+
),
|
84
|
+
self._bootstrap,
|
85
|
+
) as rce:
|
86
|
+
yield rce
|
87
|
+
|
88
|
+
else:
|
89
|
+
raise TypeError(lmt)
|
90
|
+
|
91
|
+
|
92
|
+
##
|
93
|
+
|
94
|
+
|
95
|
+
@dc.dataclass(frozen=True)
|
96
|
+
class DockerManageTargetConnector(ManageTargetConnector):
|
97
|
+
_pyremote_connector: PyremoteRemoteExecutionConnector
|
98
|
+
_bootstrap: MainBootstrap
|
99
|
+
|
100
|
+
@contextlib.asynccontextmanager
|
101
|
+
async def connect(self, tgt: ManageTarget) -> ta.AsyncGenerator[CommandExecutor, None]:
|
102
|
+
dmt = check.isinstance(tgt, DockerManageTarget)
|
103
|
+
|
104
|
+
sh_parts: ta.List[str] = ['docker']
|
105
|
+
if dmt.image is not None:
|
106
|
+
sh_parts.extend(['run', '-i', dmt.image])
|
107
|
+
elif dmt.container_id is not None:
|
108
|
+
sh_parts.extend(['exec', dmt.container_id])
|
109
|
+
else:
|
110
|
+
raise ValueError(dmt)
|
111
|
+
|
112
|
+
async with self._pyremote_connector.connect(
|
113
|
+
RemoteSpawning.Target(
|
114
|
+
shell=' '.join(sh_parts),
|
115
|
+
python=dmt.python,
|
116
|
+
),
|
117
|
+
self._bootstrap,
|
118
|
+
) as rce:
|
119
|
+
yield rce
|
120
|
+
|
121
|
+
|
122
|
+
##
|
123
|
+
|
124
|
+
|
125
|
+
@dc.dataclass(frozen=True)
|
126
|
+
class SshManageTargetConnector(ManageTargetConnector):
|
127
|
+
_pyremote_connector: PyremoteRemoteExecutionConnector
|
128
|
+
_bootstrap: MainBootstrap
|
129
|
+
|
130
|
+
@contextlib.asynccontextmanager
|
131
|
+
async def connect(self, tgt: ManageTarget) -> ta.AsyncGenerator[CommandExecutor, None]:
|
132
|
+
smt = check.isinstance(tgt, SshManageTarget)
|
133
|
+
|
134
|
+
sh_parts: ta.List[str] = ['ssh']
|
135
|
+
if smt.key_file is not None:
|
136
|
+
sh_parts.extend(['-i', smt.key_file])
|
137
|
+
addr = check.not_none(smt.host)
|
138
|
+
if smt.username is not None:
|
139
|
+
addr = f'{smt.username}@{addr}'
|
140
|
+
sh_parts.append(addr)
|
141
|
+
|
142
|
+
async with self._pyremote_connector.connect(
|
143
|
+
RemoteSpawning.Target(
|
144
|
+
shell=' '.join(sh_parts),
|
145
|
+
shell_quote=True,
|
146
|
+
python=smt.python,
|
147
|
+
),
|
148
|
+
self._bootstrap,
|
149
|
+
) as rce:
|
150
|
+
yield rce
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
from omlish.lite.inject import Injector
|
5
|
+
from omlish.lite.inject import InjectorBindingOrBindings
|
6
|
+
from omlish.lite.inject import InjectorBindings
|
7
|
+
from omlish.lite.inject import inj
|
8
|
+
|
9
|
+
from .connection import DockerManageTargetConnector
|
10
|
+
from .connection import LocalManageTargetConnector
|
11
|
+
from .connection import ManageTargetConnector
|
12
|
+
from .connection import ManageTargetConnectorMap
|
13
|
+
from .connection import SshManageTargetConnector
|
14
|
+
from .connection import TypeSwitchedManageTargetConnector
|
15
|
+
from .targets import DockerManageTarget
|
16
|
+
from .targets import LocalManageTarget
|
17
|
+
from .targets import SshManageTarget
|
18
|
+
|
19
|
+
|
20
|
+
def bind_targets() -> InjectorBindings:
|
21
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
22
|
+
inj.bind(LocalManageTargetConnector, singleton=True),
|
23
|
+
inj.bind(DockerManageTargetConnector, singleton=True),
|
24
|
+
inj.bind(SshManageTargetConnector, singleton=True),
|
25
|
+
|
26
|
+
inj.bind(TypeSwitchedManageTargetConnector, singleton=True),
|
27
|
+
inj.bind(ManageTargetConnector, to_key=TypeSwitchedManageTargetConnector),
|
28
|
+
]
|
29
|
+
|
30
|
+
#
|
31
|
+
|
32
|
+
def provide_manage_target_connector_map(injector: Injector) -> ManageTargetConnectorMap:
|
33
|
+
return ManageTargetConnectorMap({
|
34
|
+
LocalManageTarget: injector[LocalManageTargetConnector],
|
35
|
+
DockerManageTarget: injector[DockerManageTargetConnector],
|
36
|
+
SshManageTarget: injector[SshManageTargetConnector],
|
37
|
+
})
|
38
|
+
lst.append(inj.bind(provide_manage_target_connector_map, singleton=True))
|
39
|
+
|
40
|
+
#
|
41
|
+
|
42
|
+
return inj.as_bindings(*lst)
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
"""
|
3
|
+
It's desugaring. Subprocess and locals are only leafs. Retain an origin?
|
4
|
+
** TWO LAYERS ** - ManageTarget is user-facing, ConnectorTarget is bound, internal
|
5
|
+
"""
|
6
|
+
import abc
|
7
|
+
import dataclasses as dc
|
8
|
+
import enum
|
9
|
+
import typing as ta
|
10
|
+
|
11
|
+
from omlish.lite.check import check
|
12
|
+
|
13
|
+
|
14
|
+
##
|
15
|
+
|
16
|
+
|
17
|
+
class ManageTarget(abc.ABC): # noqa
|
18
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
19
|
+
super().__init_subclass__(**kwargs)
|
20
|
+
|
21
|
+
check.state(cls.__name__.endswith('ManageTarget'))
|
22
|
+
|
23
|
+
|
24
|
+
#
|
25
|
+
|
26
|
+
|
27
|
+
@dc.dataclass(frozen=True)
|
28
|
+
class PythonRemoteManageTarget:
|
29
|
+
DEFAULT_PYTHON: ta.ClassVar[str] = 'python3'
|
30
|
+
python: str = DEFAULT_PYTHON
|
31
|
+
|
32
|
+
|
33
|
+
#
|
34
|
+
|
35
|
+
|
36
|
+
class RemoteManageTarget(ManageTarget, abc.ABC):
|
37
|
+
pass
|
38
|
+
|
39
|
+
|
40
|
+
class PhysicallyRemoteManageTarget(RemoteManageTarget, abc.ABC):
|
41
|
+
pass
|
42
|
+
|
43
|
+
|
44
|
+
class LocalManageTarget(ManageTarget, abc.ABC):
|
45
|
+
pass
|
46
|
+
|
47
|
+
|
48
|
+
##
|
49
|
+
|
50
|
+
|
51
|
+
@dc.dataclass(frozen=True)
|
52
|
+
class SshManageTarget(PhysicallyRemoteManageTarget, PythonRemoteManageTarget):
|
53
|
+
host: ta.Optional[str] = None
|
54
|
+
username: ta.Optional[str] = None
|
55
|
+
key_file: ta.Optional[str] = None
|
56
|
+
|
57
|
+
def __post_init__(self) -> None:
|
58
|
+
check.non_empty_str(self.host)
|
59
|
+
|
60
|
+
|
61
|
+
##
|
62
|
+
|
63
|
+
|
64
|
+
@dc.dataclass(frozen=True)
|
65
|
+
class DockerManageTarget(RemoteManageTarget, PythonRemoteManageTarget): # noqa
|
66
|
+
image: ta.Optional[str] = None
|
67
|
+
container_id: ta.Optional[str] = None
|
68
|
+
|
69
|
+
def __post_init__(self) -> None:
|
70
|
+
check.arg(bool(self.image) ^ bool(self.container_id))
|
71
|
+
|
72
|
+
|
73
|
+
##
|
74
|
+
|
75
|
+
|
76
|
+
@dc.dataclass(frozen=True)
|
77
|
+
class InProcessManageTarget(LocalManageTarget):
|
78
|
+
class Mode(enum.Enum):
|
79
|
+
DIRECT = enum.auto()
|
80
|
+
FAKE_REMOTE = enum.auto()
|
81
|
+
|
82
|
+
mode: Mode = Mode.DIRECT
|
83
|
+
|
84
|
+
|
85
|
+
@dc.dataclass(frozen=True)
|
86
|
+
class SubprocessManageTarget(LocalManageTarget, PythonRemoteManageTarget):
|
87
|
+
pass
|
ominfra/scripts/journald2aws.py
CHANGED
@@ -961,8 +961,6 @@ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
|
|
961
961
|
"""
|
962
962
|
TODO:
|
963
963
|
- def maybe(v: lang.Maybe[T])
|
964
|
-
- patch / override lite.check ?
|
965
|
-
- checker interface?
|
966
964
|
"""
|
967
965
|
|
968
966
|
|
@@ -2270,6 +2268,20 @@ def attr_setting(obj, attr, val, *, default=None): # noqa
|
|
2270
2268
|
setattr(obj, attr, orig)
|
2271
2269
|
|
2272
2270
|
|
2271
|
+
##
|
2272
|
+
|
2273
|
+
|
2274
|
+
class aclosing(contextlib.AbstractAsyncContextManager): # noqa
|
2275
|
+
def __init__(self, thing):
|
2276
|
+
self.thing = thing
|
2277
|
+
|
2278
|
+
async def __aenter__(self):
|
2279
|
+
return self.thing
|
2280
|
+
|
2281
|
+
async def __aexit__(self, *exc_info):
|
2282
|
+
await self.thing.aclose()
|
2283
|
+
|
2284
|
+
|
2273
2285
|
########################################
|
2274
2286
|
# ../../../../../omlish/lite/logs.py
|
2275
2287
|
"""
|
@@ -2545,7 +2557,8 @@ def configure_standard_logging(
|
|
2545
2557
|
"""
|
2546
2558
|
TODO:
|
2547
2559
|
- pickle stdlib objs? have to pin to 3.8 pickle protocol, will be cross-version
|
2548
|
-
-
|
2560
|
+
- namedtuple
|
2561
|
+
- literals
|
2549
2562
|
"""
|
2550
2563
|
|
2551
2564
|
|
@@ -2835,14 +2848,18 @@ class ObjMarshalerManager:
|
|
2835
2848
|
) -> ObjMarshaler:
|
2836
2849
|
if isinstance(ty, type):
|
2837
2850
|
if abc.ABC in ty.__bases__:
|
2838
|
-
|
2851
|
+
impls = [ity for ity in deep_subclasses(ty) if abc.ABC not in ity.__bases__] # type: ignore
|
2852
|
+
if all(ity.__qualname__.endswith(ty.__name__) for ity in impls):
|
2853
|
+
ins = {ity: snake_case(ity.__qualname__[:-len(ty.__name__)]) for ity in impls}
|
2854
|
+
else:
|
2855
|
+
ins = {ity: ity.__qualname__ for ity in impls}
|
2856
|
+
return PolymorphicObjMarshaler.of([
|
2839
2857
|
PolymorphicObjMarshaler.Impl(
|
2840
2858
|
ity,
|
2841
|
-
|
2859
|
+
itn,
|
2842
2860
|
rec(ity),
|
2843
2861
|
)
|
2844
|
-
for ity in
|
2845
|
-
if abc.ABC not in ity.__bases__
|
2862
|
+
for ity, itn in ins.items()
|
2846
2863
|
])
|
2847
2864
|
|
2848
2865
|
if issubclass(ty, enum.Enum):
|