ominfra 0.0.0.dev153__py3-none-any.whl → 0.0.0.dev155__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/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.dev153.dist-info → ominfra-0.0.0.dev155.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev153.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.dev153.dist-info → ominfra-0.0.0.dev155.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev153.dist-info → ominfra-0.0.0.dev155.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev153.dist-info → ominfra-0.0.0.dev155.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev153.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):
|