ominfra 0.0.0.dev216__py3-none-any.whl → 0.0.0.dev218__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/scripts/journald2aws.py +65 -3
- ominfra/scripts/manage.py +65 -3
- ominfra/scripts/supervisor.py +135 -163
- ominfra/supervisor/http.py +1 -2
- {ominfra-0.0.0.dev216.dist-info → ominfra-0.0.0.dev218.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev216.dist-info → ominfra-0.0.0.dev218.dist-info}/RECORD +10 -10
- {ominfra-0.0.0.dev216.dist-info → ominfra-0.0.0.dev218.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev216.dist-info → ominfra-0.0.0.dev218.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev216.dist-info → ominfra-0.0.0.dev218.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev216.dist-info → ominfra-0.0.0.dev218.dist-info}/top_level.txt +0 -0
ominfra/scripts/journald2aws.py
CHANGED
@@ -4235,6 +4235,12 @@ def configure_standard_logging(
|
|
4235
4235
|
##
|
4236
4236
|
|
4237
4237
|
|
4238
|
+
# Valid channel type kwarg values:
|
4239
|
+
# - A special flag negative int
|
4240
|
+
# - A positive fd int
|
4241
|
+
# - A file-like object
|
4242
|
+
# - None
|
4243
|
+
|
4238
4244
|
SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
|
4239
4245
|
'pipe': subprocess.PIPE,
|
4240
4246
|
'stdout': subprocess.STDOUT,
|
@@ -4280,6 +4286,25 @@ def subprocess_close(
|
|
4280
4286
|
##
|
4281
4287
|
|
4282
4288
|
|
4289
|
+
class VerboseCalledProcessError(subprocess.CalledProcessError):
|
4290
|
+
@classmethod
|
4291
|
+
def from_std(cls, e: subprocess.CalledProcessError) -> 'VerboseCalledProcessError':
|
4292
|
+
return cls(
|
4293
|
+
e.returncode,
|
4294
|
+
e.cmd,
|
4295
|
+
output=e.output,
|
4296
|
+
stderr=e.stderr,
|
4297
|
+
)
|
4298
|
+
|
4299
|
+
def __str__(self) -> str:
|
4300
|
+
msg = super().__str__()
|
4301
|
+
if self.output is not None:
|
4302
|
+
msg += f' Output: {self.output!r}'
|
4303
|
+
if self.stderr is not None:
|
4304
|
+
msg += f' Stderr: {self.stderr!r}'
|
4305
|
+
return msg
|
4306
|
+
|
4307
|
+
|
4283
4308
|
class BaseSubprocesses(abc.ABC): # noqa
|
4284
4309
|
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] = None
|
4285
4310
|
|
@@ -4313,16 +4338,31 @@ class BaseSubprocesses(abc.ABC): # noqa
|
|
4313
4338
|
if extra_env:
|
4314
4339
|
self._log.debug('Subprocesses.prepare_args: extra_env=%r', extra_env)
|
4315
4340
|
|
4341
|
+
#
|
4342
|
+
|
4316
4343
|
if extra_env:
|
4317
4344
|
env = {**(env if env is not None else os.environ), **extra_env}
|
4318
4345
|
|
4346
|
+
#
|
4347
|
+
|
4319
4348
|
if quiet and 'stderr' not in kwargs:
|
4320
4349
|
if self._log and not self._log.isEnabledFor(logging.DEBUG):
|
4321
4350
|
kwargs['stderr'] = subprocess.DEVNULL
|
4322
4351
|
|
4352
|
+
for chk in ('stdout', 'stderr'):
|
4353
|
+
try:
|
4354
|
+
chv = kwargs[chk]
|
4355
|
+
except KeyError:
|
4356
|
+
continue
|
4357
|
+
kwargs[chk] = SUBPROCESS_CHANNEL_OPTION_VALUES.get(chv, chv)
|
4358
|
+
|
4359
|
+
#
|
4360
|
+
|
4323
4361
|
if not shell:
|
4324
4362
|
cmd = subprocess_maybe_shell_wrap_exec(*cmd)
|
4325
4363
|
|
4364
|
+
#
|
4365
|
+
|
4326
4366
|
return cmd, dict(
|
4327
4367
|
env=env,
|
4328
4368
|
shell=shell,
|
@@ -4330,35 +4370,57 @@ class BaseSubprocesses(abc.ABC): # noqa
|
|
4330
4370
|
)
|
4331
4371
|
|
4332
4372
|
@contextlib.contextmanager
|
4333
|
-
def wrap_call(
|
4373
|
+
def wrap_call(
|
4374
|
+
self,
|
4375
|
+
*cmd: ta.Any,
|
4376
|
+
raise_verbose: bool = False,
|
4377
|
+
**kwargs: ta.Any,
|
4378
|
+
) -> ta.Iterator[None]:
|
4334
4379
|
start_time = time.time()
|
4335
4380
|
try:
|
4336
4381
|
if self._log:
|
4337
4382
|
self._log.debug('Subprocesses.wrap_call.try: cmd=%r', cmd)
|
4383
|
+
|
4338
4384
|
yield
|
4339
4385
|
|
4340
4386
|
except Exception as exc: # noqa
|
4341
4387
|
if self._log:
|
4342
4388
|
self._log.debug('Subprocesses.wrap_call.except: exc=%r', exc)
|
4389
|
+
|
4390
|
+
if (
|
4391
|
+
raise_verbose and
|
4392
|
+
isinstance(exc, subprocess.CalledProcessError) and
|
4393
|
+
not isinstance(exc, VerboseCalledProcessError) and
|
4394
|
+
(exc.output is not None or exc.stderr is not None)
|
4395
|
+
):
|
4396
|
+
raise VerboseCalledProcessError.from_std(exc) from exc
|
4397
|
+
|
4343
4398
|
raise
|
4344
4399
|
|
4345
4400
|
finally:
|
4346
4401
|
end_time = time.time()
|
4347
4402
|
elapsed_s = end_time - start_time
|
4403
|
+
|
4348
4404
|
if self._log:
|
4349
|
-
self._log.debug('
|
4405
|
+
self._log.debug('Subprocesses.wrap_call.finally: elapsed_s=%f cmd=%r', elapsed_s, cmd)
|
4350
4406
|
|
4351
4407
|
@contextlib.contextmanager
|
4352
4408
|
def prepare_and_wrap(
|
4353
4409
|
self,
|
4354
4410
|
*cmd: ta.Any,
|
4411
|
+
raise_verbose: bool = False,
|
4355
4412
|
**kwargs: ta.Any,
|
4356
4413
|
) -> ta.Iterator[ta.Tuple[
|
4357
4414
|
ta.Tuple[ta.Any, ...],
|
4358
4415
|
ta.Dict[str, ta.Any],
|
4359
4416
|
]]:
|
4360
4417
|
cmd, kwargs = self.prepare_args(*cmd, **kwargs)
|
4361
|
-
|
4418
|
+
|
4419
|
+
with self.wrap_call(
|
4420
|
+
*cmd,
|
4421
|
+
raise_verbose=raise_verbose,
|
4422
|
+
**kwargs,
|
4423
|
+
):
|
4362
4424
|
yield cmd, kwargs
|
4363
4425
|
|
4364
4426
|
#
|
ominfra/scripts/manage.py
CHANGED
@@ -8172,6 +8172,12 @@ def configure_standard_logging(
|
|
8172
8172
|
##
|
8173
8173
|
|
8174
8174
|
|
8175
|
+
# Valid channel type kwarg values:
|
8176
|
+
# - A special flag negative int
|
8177
|
+
# - A positive fd int
|
8178
|
+
# - A file-like object
|
8179
|
+
# - None
|
8180
|
+
|
8175
8181
|
SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
|
8176
8182
|
'pipe': subprocess.PIPE,
|
8177
8183
|
'stdout': subprocess.STDOUT,
|
@@ -8217,6 +8223,25 @@ def subprocess_close(
|
|
8217
8223
|
##
|
8218
8224
|
|
8219
8225
|
|
8226
|
+
class VerboseCalledProcessError(subprocess.CalledProcessError):
|
8227
|
+
@classmethod
|
8228
|
+
def from_std(cls, e: subprocess.CalledProcessError) -> 'VerboseCalledProcessError':
|
8229
|
+
return cls(
|
8230
|
+
e.returncode,
|
8231
|
+
e.cmd,
|
8232
|
+
output=e.output,
|
8233
|
+
stderr=e.stderr,
|
8234
|
+
)
|
8235
|
+
|
8236
|
+
def __str__(self) -> str:
|
8237
|
+
msg = super().__str__()
|
8238
|
+
if self.output is not None:
|
8239
|
+
msg += f' Output: {self.output!r}'
|
8240
|
+
if self.stderr is not None:
|
8241
|
+
msg += f' Stderr: {self.stderr!r}'
|
8242
|
+
return msg
|
8243
|
+
|
8244
|
+
|
8220
8245
|
class BaseSubprocesses(abc.ABC): # noqa
|
8221
8246
|
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] = None
|
8222
8247
|
|
@@ -8250,16 +8275,31 @@ class BaseSubprocesses(abc.ABC): # noqa
|
|
8250
8275
|
if extra_env:
|
8251
8276
|
self._log.debug('Subprocesses.prepare_args: extra_env=%r', extra_env)
|
8252
8277
|
|
8278
|
+
#
|
8279
|
+
|
8253
8280
|
if extra_env:
|
8254
8281
|
env = {**(env if env is not None else os.environ), **extra_env}
|
8255
8282
|
|
8283
|
+
#
|
8284
|
+
|
8256
8285
|
if quiet and 'stderr' not in kwargs:
|
8257
8286
|
if self._log and not self._log.isEnabledFor(logging.DEBUG):
|
8258
8287
|
kwargs['stderr'] = subprocess.DEVNULL
|
8259
8288
|
|
8289
|
+
for chk in ('stdout', 'stderr'):
|
8290
|
+
try:
|
8291
|
+
chv = kwargs[chk]
|
8292
|
+
except KeyError:
|
8293
|
+
continue
|
8294
|
+
kwargs[chk] = SUBPROCESS_CHANNEL_OPTION_VALUES.get(chv, chv)
|
8295
|
+
|
8296
|
+
#
|
8297
|
+
|
8260
8298
|
if not shell:
|
8261
8299
|
cmd = subprocess_maybe_shell_wrap_exec(*cmd)
|
8262
8300
|
|
8301
|
+
#
|
8302
|
+
|
8263
8303
|
return cmd, dict(
|
8264
8304
|
env=env,
|
8265
8305
|
shell=shell,
|
@@ -8267,35 +8307,57 @@ class BaseSubprocesses(abc.ABC): # noqa
|
|
8267
8307
|
)
|
8268
8308
|
|
8269
8309
|
@contextlib.contextmanager
|
8270
|
-
def wrap_call(
|
8310
|
+
def wrap_call(
|
8311
|
+
self,
|
8312
|
+
*cmd: ta.Any,
|
8313
|
+
raise_verbose: bool = False,
|
8314
|
+
**kwargs: ta.Any,
|
8315
|
+
) -> ta.Iterator[None]:
|
8271
8316
|
start_time = time.time()
|
8272
8317
|
try:
|
8273
8318
|
if self._log:
|
8274
8319
|
self._log.debug('Subprocesses.wrap_call.try: cmd=%r', cmd)
|
8320
|
+
|
8275
8321
|
yield
|
8276
8322
|
|
8277
8323
|
except Exception as exc: # noqa
|
8278
8324
|
if self._log:
|
8279
8325
|
self._log.debug('Subprocesses.wrap_call.except: exc=%r', exc)
|
8326
|
+
|
8327
|
+
if (
|
8328
|
+
raise_verbose and
|
8329
|
+
isinstance(exc, subprocess.CalledProcessError) and
|
8330
|
+
not isinstance(exc, VerboseCalledProcessError) and
|
8331
|
+
(exc.output is not None or exc.stderr is not None)
|
8332
|
+
):
|
8333
|
+
raise VerboseCalledProcessError.from_std(exc) from exc
|
8334
|
+
|
8280
8335
|
raise
|
8281
8336
|
|
8282
8337
|
finally:
|
8283
8338
|
end_time = time.time()
|
8284
8339
|
elapsed_s = end_time - start_time
|
8340
|
+
|
8285
8341
|
if self._log:
|
8286
|
-
self._log.debug('
|
8342
|
+
self._log.debug('Subprocesses.wrap_call.finally: elapsed_s=%f cmd=%r', elapsed_s, cmd)
|
8287
8343
|
|
8288
8344
|
@contextlib.contextmanager
|
8289
8345
|
def prepare_and_wrap(
|
8290
8346
|
self,
|
8291
8347
|
*cmd: ta.Any,
|
8348
|
+
raise_verbose: bool = False,
|
8292
8349
|
**kwargs: ta.Any,
|
8293
8350
|
) -> ta.Iterator[ta.Tuple[
|
8294
8351
|
ta.Tuple[ta.Any, ...],
|
8295
8352
|
ta.Dict[str, ta.Any],
|
8296
8353
|
]]:
|
8297
8354
|
cmd, kwargs = self.prepare_args(*cmd, **kwargs)
|
8298
|
-
|
8355
|
+
|
8356
|
+
with self.wrap_call(
|
8357
|
+
*cmd,
|
8358
|
+
raise_verbose=raise_verbose,
|
8359
|
+
**kwargs,
|
8360
|
+
):
|
8299
8361
|
yield cmd, kwargs
|
8300
8362
|
|
8301
8363
|
#
|
ominfra/scripts/supervisor.py
CHANGED
@@ -142,10 +142,6 @@ ConfigDataT = ta.TypeVar('ConfigDataT', bound='ConfigData')
|
|
142
142
|
# ../../omlish/http/parsing.py
|
143
143
|
HttpHeaders = http.client.HTTPMessage # ta.TypeAlias
|
144
144
|
|
145
|
-
# ../../omlish/lite/contextmanagers.py
|
146
|
-
ExitStackedT = ta.TypeVar('ExitStackedT', bound='ExitStacked')
|
147
|
-
AsyncExitStackedT = ta.TypeVar('AsyncExitStackedT', bound='AsyncExitStacked')
|
148
|
-
|
149
145
|
# ../../omlish/lite/inject.py
|
150
146
|
U = ta.TypeVar('U')
|
151
147
|
InjectorKeyCls = ta.Union[type, ta.NewType]
|
@@ -154,10 +150,11 @@ InjectorProviderFnMap = ta.Mapping['InjectorKey', 'InjectorProviderFn']
|
|
154
150
|
InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings']
|
155
151
|
|
156
152
|
# ../../omlish/sockets/handlers.py
|
157
|
-
|
153
|
+
SocketHandler = ta.Callable[[SocketAddress, 'SocketIoPair'], None] # ta.TypeAlias
|
158
154
|
|
159
155
|
# ../../omlish/http/handlers.py
|
160
156
|
HttpHandler = ta.Callable[['HttpHandlerRequest'], 'HttpHandlerResponse'] # ta.TypeAlias
|
157
|
+
HttpHandlerResponseData = ta.Union[bytes, 'HttpHandlerResponseStreamedData'] # ta.TypeAlias # noqa
|
161
158
|
|
162
159
|
# ../../omlish/http/coro/server.py
|
163
160
|
CoroHttpServerFactory = ta.Callable[[SocketAddress], 'CoroHttpServer']
|
@@ -2812,8 +2809,7 @@ class ProxyLogHandler(ProxyLogFilterer, logging.Handler):
|
|
2812
2809
|
# ../../../omlish/sockets/addresses.py
|
2813
2810
|
"""
|
2814
2811
|
TODO:
|
2815
|
-
-
|
2816
|
-
+ codification of https://docs.python.org/3/library/socket.html#socket-families
|
2812
|
+
- codification of https://docs.python.org/3/library/socket.html#socket-families
|
2817
2813
|
"""
|
2818
2814
|
|
2819
2815
|
|
@@ -2839,11 +2835,16 @@ class SocketAddressInfo:
|
|
2839
2835
|
sockaddr: SocketAddress
|
2840
2836
|
|
2841
2837
|
|
2838
|
+
class SocketFamilyAndAddress(ta.NamedTuple):
|
2839
|
+
family: socket.AddressFamily
|
2840
|
+
address: SocketAddress
|
2841
|
+
|
2842
|
+
|
2842
2843
|
def get_best_socket_family(
|
2843
2844
|
host: ta.Optional[str],
|
2844
2845
|
port: ta.Union[str, int, None],
|
2845
2846
|
family: ta.Union[int, socket.AddressFamily] = socket.AddressFamily.AF_UNSPEC,
|
2846
|
-
) ->
|
2847
|
+
) -> SocketFamilyAndAddress:
|
2847
2848
|
"""https://github.com/python/cpython/commit/f289084c83190cc72db4a70c58f007ec62e75247"""
|
2848
2849
|
|
2849
2850
|
infos = socket.getaddrinfo(
|
@@ -2854,7 +2855,80 @@ def get_best_socket_family(
|
|
2854
2855
|
flags=socket.AI_PASSIVE,
|
2855
2856
|
)
|
2856
2857
|
ai = SocketAddressInfo(*next(iter(infos)))
|
2857
|
-
return ai.family, ai.sockaddr
|
2858
|
+
return SocketFamilyAndAddress(ai.family, ai.sockaddr)
|
2859
|
+
|
2860
|
+
|
2861
|
+
class SocketAndAddress(ta.NamedTuple):
|
2862
|
+
socket: socket.socket
|
2863
|
+
address: SocketAddress
|
2864
|
+
|
2865
|
+
|
2866
|
+
########################################
|
2867
|
+
# ../../../omlish/sockets/io.py
|
2868
|
+
|
2869
|
+
|
2870
|
+
##
|
2871
|
+
|
2872
|
+
|
2873
|
+
class SocketWriter(io.BufferedIOBase):
|
2874
|
+
"""
|
2875
|
+
Simple writable BufferedIOBase implementation for a socket
|
2876
|
+
|
2877
|
+
Does not hold data in a buffer, avoiding any need to call flush().
|
2878
|
+
"""
|
2879
|
+
|
2880
|
+
def __init__(self, sock):
|
2881
|
+
super().__init__()
|
2882
|
+
|
2883
|
+
self._sock = sock
|
2884
|
+
|
2885
|
+
def writable(self):
|
2886
|
+
return True
|
2887
|
+
|
2888
|
+
def write(self, b):
|
2889
|
+
self._sock.sendall(b)
|
2890
|
+
with memoryview(b) as view:
|
2891
|
+
return view.nbytes
|
2892
|
+
|
2893
|
+
def fileno(self):
|
2894
|
+
return self._sock.fileno()
|
2895
|
+
|
2896
|
+
|
2897
|
+
class SocketIoPair(ta.NamedTuple):
|
2898
|
+
r: ta.BinaryIO
|
2899
|
+
w: ta.BinaryIO
|
2900
|
+
|
2901
|
+
@classmethod
|
2902
|
+
def from_socket(
|
2903
|
+
cls,
|
2904
|
+
sock: socket.socket,
|
2905
|
+
*,
|
2906
|
+
r_buf_size: int = -1,
|
2907
|
+
w_buf_size: int = 0,
|
2908
|
+
) -> 'SocketIoPair':
|
2909
|
+
rf: ta.Any = sock.makefile('rb', r_buf_size)
|
2910
|
+
|
2911
|
+
if w_buf_size:
|
2912
|
+
wf: ta.Any = SocketWriter(sock)
|
2913
|
+
else:
|
2914
|
+
wf = sock.makefile('wb', w_buf_size)
|
2915
|
+
|
2916
|
+
return cls(rf, wf)
|
2917
|
+
|
2918
|
+
|
2919
|
+
##
|
2920
|
+
|
2921
|
+
|
2922
|
+
def close_socket_immediately(sock: socket.socket) -> None:
|
2923
|
+
try:
|
2924
|
+
# Explicitly shutdown. socket.close() merely releases the socket and waits for GC to perform the actual close.
|
2925
|
+
sock.shutdown(socket.SHUT_WR)
|
2926
|
+
|
2927
|
+
except OSError:
|
2928
|
+
# Some platforms may raise ENOTCONN here
|
2929
|
+
pass
|
2930
|
+
|
2931
|
+
sock.close()
|
2858
2932
|
|
2859
2933
|
|
2860
2934
|
########################################
|
@@ -4426,116 +4500,6 @@ else:
|
|
4426
4500
|
KqueueFdioPoller = None
|
4427
4501
|
|
4428
4502
|
|
4429
|
-
########################################
|
4430
|
-
# ../../../omlish/lite/contextmanagers.py
|
4431
|
-
|
4432
|
-
|
4433
|
-
##
|
4434
|
-
|
4435
|
-
|
4436
|
-
class ExitStacked:
|
4437
|
-
_exit_stack: ta.Optional[contextlib.ExitStack] = None
|
4438
|
-
|
4439
|
-
def __enter__(self: ExitStackedT) -> ExitStackedT:
|
4440
|
-
check.state(self._exit_stack is None)
|
4441
|
-
es = self._exit_stack = contextlib.ExitStack()
|
4442
|
-
es.__enter__()
|
4443
|
-
return self
|
4444
|
-
|
4445
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
4446
|
-
if (es := self._exit_stack) is None:
|
4447
|
-
return None
|
4448
|
-
self._exit_contexts()
|
4449
|
-
return es.__exit__(exc_type, exc_val, exc_tb)
|
4450
|
-
|
4451
|
-
def _exit_contexts(self) -> None:
|
4452
|
-
pass
|
4453
|
-
|
4454
|
-
def _enter_context(self, cm: ta.ContextManager[T]) -> T:
|
4455
|
-
es = check.not_none(self._exit_stack)
|
4456
|
-
return es.enter_context(cm)
|
4457
|
-
|
4458
|
-
|
4459
|
-
class AsyncExitStacked:
|
4460
|
-
_exit_stack: ta.Optional[contextlib.AsyncExitStack] = None
|
4461
|
-
|
4462
|
-
async def __aenter__(self: AsyncExitStackedT) -> AsyncExitStackedT:
|
4463
|
-
check.state(self._exit_stack is None)
|
4464
|
-
es = self._exit_stack = contextlib.AsyncExitStack()
|
4465
|
-
await es.__aenter__()
|
4466
|
-
return self
|
4467
|
-
|
4468
|
-
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
4469
|
-
if (es := self._exit_stack) is None:
|
4470
|
-
return None
|
4471
|
-
await self._async_exit_contexts()
|
4472
|
-
return await es.__aexit__(exc_type, exc_val, exc_tb)
|
4473
|
-
|
4474
|
-
async def _async_exit_contexts(self) -> None:
|
4475
|
-
pass
|
4476
|
-
|
4477
|
-
def _enter_context(self, cm: ta.ContextManager[T]) -> T:
|
4478
|
-
es = check.not_none(self._exit_stack)
|
4479
|
-
return es.enter_context(cm)
|
4480
|
-
|
4481
|
-
async def _enter_async_context(self, cm: ta.AsyncContextManager[T]) -> T:
|
4482
|
-
es = check.not_none(self._exit_stack)
|
4483
|
-
return await es.enter_async_context(cm)
|
4484
|
-
|
4485
|
-
|
4486
|
-
##
|
4487
|
-
|
4488
|
-
|
4489
|
-
@contextlib.contextmanager
|
4490
|
-
def defer(fn: ta.Callable) -> ta.Generator[ta.Callable, None, None]:
|
4491
|
-
try:
|
4492
|
-
yield fn
|
4493
|
-
finally:
|
4494
|
-
fn()
|
4495
|
-
|
4496
|
-
|
4497
|
-
@contextlib.asynccontextmanager
|
4498
|
-
async def adefer(fn: ta.Callable) -> ta.AsyncGenerator[ta.Callable, None]:
|
4499
|
-
try:
|
4500
|
-
yield fn
|
4501
|
-
finally:
|
4502
|
-
await fn()
|
4503
|
-
|
4504
|
-
|
4505
|
-
##
|
4506
|
-
|
4507
|
-
|
4508
|
-
@contextlib.contextmanager
|
4509
|
-
def attr_setting(obj, attr, val, *, default=None): # noqa
|
4510
|
-
not_set = object()
|
4511
|
-
orig = getattr(obj, attr, not_set)
|
4512
|
-
try:
|
4513
|
-
setattr(obj, attr, val)
|
4514
|
-
if orig is not not_set:
|
4515
|
-
yield orig
|
4516
|
-
else:
|
4517
|
-
yield default
|
4518
|
-
finally:
|
4519
|
-
if orig is not_set:
|
4520
|
-
delattr(obj, attr)
|
4521
|
-
else:
|
4522
|
-
setattr(obj, attr, orig)
|
4523
|
-
|
4524
|
-
|
4525
|
-
##
|
4526
|
-
|
4527
|
-
|
4528
|
-
class aclosing(contextlib.AbstractAsyncContextManager): # noqa
|
4529
|
-
def __init__(self, thing):
|
4530
|
-
self.thing = thing
|
4531
|
-
|
4532
|
-
async def __aenter__(self):
|
4533
|
-
return self.thing
|
4534
|
-
|
4535
|
-
async def __aexit__(self, *exc_info):
|
4536
|
-
await self.thing.aclose()
|
4537
|
-
|
4538
|
-
|
4539
4503
|
########################################
|
4540
4504
|
# ../../../omlish/lite/inject.py
|
4541
4505
|
|
@@ -6427,24 +6391,6 @@ def journald_log_handler_factory(
|
|
6427
6391
|
##
|
6428
6392
|
|
6429
6393
|
|
6430
|
-
class SocketHandler(abc.ABC):
|
6431
|
-
def __init__(
|
6432
|
-
self,
|
6433
|
-
client_address: SocketAddress,
|
6434
|
-
rfile: ta.BinaryIO,
|
6435
|
-
wfile: ta.BinaryIO,
|
6436
|
-
) -> None:
|
6437
|
-
super().__init__()
|
6438
|
-
|
6439
|
-
self._client_address = client_address
|
6440
|
-
self._rfile = rfile
|
6441
|
-
self._wfile = wfile
|
6442
|
-
|
6443
|
-
@abc.abstractmethod
|
6444
|
-
def handle(self) -> None:
|
6445
|
-
raise NotImplementedError
|
6446
|
-
|
6447
|
-
|
6448
6394
|
########################################
|
6449
6395
|
# ../configs.py
|
6450
6396
|
|
@@ -6865,6 +6811,9 @@ class SupervisorSetup(abc.ABC):
|
|
6865
6811
|
# ../../../omlish/http/handlers.py
|
6866
6812
|
|
6867
6813
|
|
6814
|
+
##
|
6815
|
+
|
6816
|
+
|
6868
6817
|
@dc.dataclass(frozen=True)
|
6869
6818
|
class HttpHandlerRequest:
|
6870
6819
|
client_address: SocketAddress
|
@@ -6879,10 +6828,16 @@ class HttpHandlerResponse:
|
|
6879
6828
|
status: ta.Union[http.HTTPStatus, int]
|
6880
6829
|
|
6881
6830
|
headers: ta.Optional[ta.Mapping[str, str]] = None
|
6882
|
-
data: ta.Optional[
|
6831
|
+
data: ta.Optional[HttpHandlerResponseData] = None
|
6883
6832
|
close_connection: ta.Optional[bool] = None
|
6884
6833
|
|
6885
6834
|
|
6835
|
+
@dc.dataclass(frozen=True)
|
6836
|
+
class HttpHandlerResponseStreamedData:
|
6837
|
+
iter: ta.Iterable[bytes]
|
6838
|
+
length: ta.Optional[int] = None
|
6839
|
+
|
6840
|
+
|
6886
6841
|
class HttpHandlerError(Exception):
|
6887
6842
|
pass
|
6888
6843
|
|
@@ -7394,7 +7349,7 @@ class CoroHttpServer:
|
|
7394
7349
|
|
7395
7350
|
message: ta.Optional[str] = None
|
7396
7351
|
headers: ta.Optional[ta.Sequence['CoroHttpServer._Header']] = None
|
7397
|
-
data: ta.Optional[
|
7352
|
+
data: ta.Optional[HttpHandlerResponseData] = None
|
7398
7353
|
close_connection: ta.Optional[bool] = False
|
7399
7354
|
|
7400
7355
|
def get_header(self, key: str) -> ta.Optional['CoroHttpServer._Header']:
|
@@ -7405,7 +7360,7 @@ class CoroHttpServer:
|
|
7405
7360
|
|
7406
7361
|
#
|
7407
7362
|
|
7408
|
-
def
|
7363
|
+
def _build_response_head_bytes(self, a: _Response) -> bytes:
|
7409
7364
|
out = io.BytesIO()
|
7410
7365
|
|
7411
7366
|
if a.version >= HttpProtocolVersions.HTTP_1_0:
|
@@ -7420,11 +7375,22 @@ class CoroHttpServer:
|
|
7420
7375
|
|
7421
7376
|
out.write(b'\r\n')
|
7422
7377
|
|
7423
|
-
if a.data is not None:
|
7424
|
-
out.write(a.data)
|
7425
|
-
|
7426
7378
|
return out.getvalue()
|
7427
7379
|
|
7380
|
+
def _yield_response_data(self, a: _Response) -> ta.Iterator[bytes]:
|
7381
|
+
if a.data is None:
|
7382
|
+
return
|
7383
|
+
|
7384
|
+
elif isinstance(a.data, bytes):
|
7385
|
+
yield a.data
|
7386
|
+
return
|
7387
|
+
|
7388
|
+
elif isinstance(a.data, HttpHandlerResponseStreamedData):
|
7389
|
+
yield from a.data.iter
|
7390
|
+
|
7391
|
+
else:
|
7392
|
+
raise TypeError(a.data)
|
7393
|
+
|
7428
7394
|
#
|
7429
7395
|
|
7430
7396
|
DEFAULT_CONTENT_TYPE = 'text/plain'
|
@@ -7435,8 +7401,17 @@ class CoroHttpServer:
|
|
7435
7401
|
|
7436
7402
|
if resp.get_header('Content-Type') is None:
|
7437
7403
|
nh.append(self._Header('Content-Type', self._default_content_type))
|
7404
|
+
|
7438
7405
|
if resp.data is not None and resp.get_header('Content-Length') is None:
|
7439
|
-
|
7406
|
+
cl: ta.Optional[int]
|
7407
|
+
if isinstance(resp.data, bytes):
|
7408
|
+
cl = len(resp.data)
|
7409
|
+
elif isinstance(resp.data, HttpHandlerResponseStreamedData):
|
7410
|
+
cl = resp.data.length
|
7411
|
+
else:
|
7412
|
+
raise TypeError(resp.data)
|
7413
|
+
if cl is not None:
|
7414
|
+
nh.append(self._Header('Content-Length', str(cl)))
|
7440
7415
|
|
7441
7416
|
if nh:
|
7442
7417
|
kw.update(headers=[*(resp.headers or []), *nh])
|
@@ -7610,9 +7585,13 @@ class CoroHttpServer:
|
|
7610
7585
|
|
7611
7586
|
elif isinstance(o, self._Response):
|
7612
7587
|
i = None
|
7588
|
+
|
7613
7589
|
r = self._preprocess_response(o)
|
7614
|
-
|
7615
|
-
check.none((yield self.WriteIo(
|
7590
|
+
hb = self._build_response_head_bytes(r)
|
7591
|
+
check.none((yield self.WriteIo(hb)))
|
7592
|
+
|
7593
|
+
for b in self._yield_response_data(r):
|
7594
|
+
yield self.WriteIo(b)
|
7616
7595
|
|
7617
7596
|
else:
|
7618
7597
|
raise TypeError(o)
|
@@ -7731,27 +7710,20 @@ class CoroHttpServer:
|
|
7731
7710
|
##
|
7732
7711
|
|
7733
7712
|
|
7734
|
-
class CoroHttpServerSocketHandler
|
7713
|
+
class CoroHttpServerSocketHandler: # SocketHandler
|
7735
7714
|
def __init__(
|
7736
7715
|
self,
|
7737
|
-
client_address: SocketAddress,
|
7738
|
-
rfile: ta.BinaryIO,
|
7739
|
-
wfile: ta.BinaryIO,
|
7740
|
-
*,
|
7741
7716
|
server_factory: CoroHttpServerFactory,
|
7717
|
+
*,
|
7742
7718
|
log_handler: ta.Optional[ta.Callable[[CoroHttpServer, CoroHttpServer.AnyLogIo], None]] = None,
|
7743
7719
|
) -> None:
|
7744
|
-
super().__init__(
|
7745
|
-
client_address,
|
7746
|
-
rfile,
|
7747
|
-
wfile,
|
7748
|
-
)
|
7720
|
+
super().__init__()
|
7749
7721
|
|
7750
7722
|
self._server_factory = server_factory
|
7751
7723
|
self._log_handler = log_handler
|
7752
7724
|
|
7753
|
-
def
|
7754
|
-
server = self._server_factory(
|
7725
|
+
def __call__(self, client_address: SocketAddress, fp: SocketIoPair) -> None:
|
7726
|
+
server = self._server_factory(client_address)
|
7755
7727
|
|
7756
7728
|
gen = server.coro_handle()
|
7757
7729
|
|
@@ -7763,15 +7735,15 @@ class CoroHttpServerSocketHandler(SocketHandler):
|
|
7763
7735
|
self._log_handler(server, o)
|
7764
7736
|
|
7765
7737
|
elif isinstance(o, CoroHttpServer.ReadIo):
|
7766
|
-
i =
|
7738
|
+
i = fp.r.read(o.sz)
|
7767
7739
|
|
7768
7740
|
elif isinstance(o, CoroHttpServer.ReadLineIo):
|
7769
|
-
i =
|
7741
|
+
i = fp.r.readline(o.sz)
|
7770
7742
|
|
7771
7743
|
elif isinstance(o, CoroHttpServer.WriteIo):
|
7772
7744
|
i = None
|
7773
|
-
|
7774
|
-
|
7745
|
+
fp.w.write(o.data)
|
7746
|
+
fp.w.flush()
|
7775
7747
|
|
7776
7748
|
else:
|
7777
7749
|
raise TypeError(o)
|
@@ -8877,7 +8849,7 @@ class HttpServer(HasDispatchers):
|
|
8877
8849
|
|
8878
8850
|
self._conns: ta.List[CoroHttpServerConnectionFdioHandler] = []
|
8879
8851
|
|
8880
|
-
exit_stack.
|
8852
|
+
exit_stack.callback(self._server.close)
|
8881
8853
|
|
8882
8854
|
def get_dispatchers(self) -> Dispatchers:
|
8883
8855
|
l = []
|
ominfra/supervisor/http.py
CHANGED
@@ -10,7 +10,6 @@ from omlish.http.handlers import HttpHandlerRequest
|
|
10
10
|
from omlish.http.handlers import HttpHandlerResponse
|
11
11
|
from omlish.io.fdio.handlers import SocketFdioHandler
|
12
12
|
from omlish.lite.check import check
|
13
|
-
from omlish.lite.contextmanagers import defer
|
14
13
|
from omlish.lite.json import JSON_PRETTY_KWARGS
|
15
14
|
from omlish.sockets.addresses import SocketAddress
|
16
15
|
|
@@ -73,7 +72,7 @@ class HttpServer(HasDispatchers):
|
|
73
72
|
|
74
73
|
self._conns: ta.List[CoroHttpServerConnectionFdioHandler] = []
|
75
74
|
|
76
|
-
exit_stack.
|
75
|
+
exit_stack.callback(self._server.close)
|
77
76
|
|
78
77
|
def get_dispatchers(self) -> Dispatchers:
|
79
78
|
l = []
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: ominfra
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev218
|
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.dev218
|
16
|
+
Requires-Dist: omlish==0.0.0.dev218
|
17
17
|
Provides-Extra: all
|
18
18
|
Requires-Dist: paramiko~=3.5; extra == "all"
|
19
19
|
Requires-Dist: asyncssh~=2.18; extra == "all"
|
@@ -112,9 +112,9 @@ ominfra/manage/targets/connection.py,sha256=rVI1YJxFClcF-sdttqWyIz9_XjPI01GUdwxY
|
|
112
112
|
ominfra/manage/targets/inject.py,sha256=P4597xWM-V3I_gCt2O71OLhYQkkXtuJvkYRsIbhhMcE,1561
|
113
113
|
ominfra/manage/targets/targets.py,sha256=7GP6UAZyJFEhpkJN6UQdpr_WN3p7C76v-s445y-WB6U,1885
|
114
114
|
ominfra/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
115
|
-
ominfra/scripts/journald2aws.py,sha256=
|
116
|
-
ominfra/scripts/manage.py,sha256=
|
117
|
-
ominfra/scripts/supervisor.py,sha256=
|
115
|
+
ominfra/scripts/journald2aws.py,sha256=CM1nZMpecXJpcg7icJUCJ-_DX-7CduQurxZQ7EmhQmA,171450
|
116
|
+
ominfra/scripts/manage.py,sha256=MaUur1_dDdMHt5YnE6Waxa_v70kydHzKCBHXAuTmKd0,362827
|
117
|
+
ominfra/scripts/supervisor.py,sha256=ejPO7r3Ta0RQbP28MyL8MJNS1jop6g8d9qdv-vJ0OYA,294602
|
118
118
|
ominfra/supervisor/LICENSE.txt,sha256=ZrHY15PVR98y26Yg6iQfa-SXnUaYTDhrUsPVcEO5OKM,1874
|
119
119
|
ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
120
120
|
ominfra/supervisor/__main__.py,sha256=I0yFw-C08OOiZ3BF6lF1Oiv789EQXu-_j6whDhQUTEA,66
|
@@ -125,7 +125,7 @@ ominfra/supervisor/events.py,sha256=XGrtzHr1xm0dwjz329fn9eR0_Ap-LQL6Sk8LJ8eVDEo,
|
|
125
125
|
ominfra/supervisor/exceptions.py,sha256=Qbu211H3CLlSmi9LsSikOwrcL5HgJP9ugvcKWlGTAoI,750
|
126
126
|
ominfra/supervisor/groups.py,sha256=MBbsbt8Zh_WEYkGOr1KXa82gnPVw9wPB2lAnqhugXSc,2457
|
127
127
|
ominfra/supervisor/groupsimpl.py,sha256=PCDyc_Wc-pnvIj56_aEyiA5exCpK6n9iErqnJzO2rZk,2281
|
128
|
-
ominfra/supervisor/http.py,sha256=
|
128
|
+
ominfra/supervisor/http.py,sha256=P7afN223jeR_g36bPK-cWulnJo1wAeFUBWAaMKPycmw,3387
|
129
129
|
ominfra/supervisor/inject.py,sha256=IeR-WKvK1sGNxMe6G2OBT5kSP7EUP5ipkDgcUFmDPCA,4838
|
130
130
|
ominfra/supervisor/io.py,sha256=moaGNaPuYXEAUzLg8Qjo05DEIcOUNYUj8SSr8eT0d24,3198
|
131
131
|
ominfra/supervisor/main.py,sha256=zCVuHZG2kGIPHwTLH4EUr5xpN4vJYessmKO2P0NE5RU,4381
|
@@ -156,9 +156,9 @@ ominfra/tailscale/api.py,sha256=C5-t_b6jZXUWcy5k8bXm7CFnk73pSdrlMOgGDeGVrpw,1370
|
|
156
156
|
ominfra/tailscale/cli.py,sha256=3FnJbgpLw6gInTfhERd1mDy9ijjMUGxkdYVo43Tnxx4,3555
|
157
157
|
ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
158
158
|
ominfra/tools/listresources.py,sha256=4qVg5txsb10EHhvqXXeM6gJ2jx9LbroEnPydDv1uXs0,6176
|
159
|
-
ominfra-0.0.0.
|
160
|
-
ominfra-0.0.0.
|
161
|
-
ominfra-0.0.0.
|
162
|
-
ominfra-0.0.0.
|
163
|
-
ominfra-0.0.0.
|
164
|
-
ominfra-0.0.0.
|
159
|
+
ominfra-0.0.0.dev218.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
160
|
+
ominfra-0.0.0.dev218.dist-info/METADATA,sha256=CIoVjeFWhR47YXXqQ65hW7lHeJK6XpLd0jTGOcP6RA4,731
|
161
|
+
ominfra-0.0.0.dev218.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
162
|
+
ominfra-0.0.0.dev218.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
|
163
|
+
ominfra-0.0.0.dev218.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
|
164
|
+
ominfra-0.0.0.dev218.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|