Skip to content

Commit a286622

Browse files
committed
Merge branch 'master' of github.com:ITISFoundation/osparc-simcore into product-favicons
2 parents a4c68c3 + e880d71 commit a286622

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+580
-129
lines changed

.env-devel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ CLUSTERS_KEEPER_COMPUTATIONAL_BACKEND_DOCKER_IMAGE_TAG=master-github-latest
5050
CLUSTERS_KEEPER_DASK_NTHREADS=0
5151
CLUSTERS_KEEPER_DASK_WORKER_SATURATION=inf
5252
CLUSTERS_KEEPER_EC2_ACCESS=null
53+
CLUSTERS_KEEPER_SSM_ACCESS=null
5354
CLUSTERS_KEEPER_EC2_INSTANCES_PREFIX=""
5455
CLUSTERS_KEEPER_LOGLEVEL=WARNING
5556
CLUSTERS_KEEPER_MAX_MISSED_HEARTBEATS_BEFORE_CLUSTER_TERMINATION=5

.github/workflows/ci-testing-deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ jobs:
590590
unit-test-autoscaling:
591591
needs: changes
592592
if: ${{ needs.changes.outputs.autoscaling == 'true' || github.event_name == 'push' }}
593-
timeout-minutes: 19 # if this timeout gets too small, then split the tests
593+
timeout-minutes: 22 # temporary: mypy takes a huge amount of time to run here, maybe we should cache it
594594
name: "[unit] autoscaling"
595595
runs-on: ${{ matrix.os }}
596596
strategy:

packages/models-library/src/models_library/clusters.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ class Config(BaseAuthentication.Config):
9696
class NoAuthentication(BaseAuthentication):
9797
type: Literal["none"] = "none"
9898

99+
class Config(BaseAuthentication.Config):
100+
schema_extra: ClassVar[dict[str, Any]] = {"examples": [{"type": "none"}]}
101+
99102

100103
class TLSAuthentication(BaseAuthentication):
101104
type: Literal["tls"] = "tls"

packages/models-library/src/models_library/users.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class UserBillingDetails(BaseModel):
2222
address: str | None
2323
city: str | None
2424
state: str | None = Field(description="State, province, canton, ...")
25-
country: str
25+
country: str # Required for taxes
2626
postal_code: str | None
2727
phone: str | None
2828

packages/pytest-simcore/src/pytest_simcore/helpers/logging_tools.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,14 @@ def log_context(
133133
else:
134134
ctx_msg = msg
135135

136-
started_time = datetime.datetime.now(tz=datetime.timezone.utc)
136+
started_time = datetime.datetime.now(tz=datetime.UTC)
137137
try:
138138
DynamicIndentFormatter.cls_increase_indent()
139139

140140
logger.log(level, ctx_msg.starting, *args, **kwargs)
141141
with _increased_logger_indent(logger):
142142
yield SimpleNamespace(logger=logger, messages=ctx_msg)
143-
elapsed_time = datetime.datetime.now(tz=datetime.timezone.utc) - started_time
143+
elapsed_time = datetime.datetime.now(tz=datetime.UTC) - started_time
144144
done_message = (
145145
f"{ctx_msg.done} ({_timedelta_as_minute_second_ms(elapsed_time)})"
146146
)
@@ -152,7 +152,7 @@ def log_context(
152152
)
153153

154154
except:
155-
elapsed_time = datetime.datetime.now(tz=datetime.timezone.utc) - started_time
155+
elapsed_time = datetime.datetime.now(tz=datetime.UTC) - started_time
156156
error_message = (
157157
f"{ctx_msg.raised} ({_timedelta_as_minute_second_ms(elapsed_time)})"
158158
)

packages/pytest-simcore/src/pytest_simcore/helpers/playwright.py

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import logging
44
import re
55
from collections import defaultdict
6-
from contextlib import ExitStack
6+
from collections.abc import Generator, Iterator
77
from dataclasses import dataclass, field
88
from enum import Enum, unique
9-
from typing import Any, Final, Generator
9+
from typing import Any, Final
1010

1111
from playwright.sync_api import FrameLocator, Page, Request, WebSocket
1212
from pytest_simcore.helpers.logging_tools import log_context
@@ -263,28 +263,37 @@ def wait_for_pipeline_state(
263263
return current_state
264264

265265

266-
def on_web_socket_default_handler(ws) -> None:
267-
"""Usage
268-
269-
from pytest_simcore.playwright_utils import on_web_socket_default_handler
270-
271-
page.on("websocket", on_web_socket_default_handler)
272-
273-
"""
274-
stack = ExitStack()
275-
ctx = stack.enter_context(
276-
log_context(
277-
logging.INFO,
278-
(
279-
f"WebSocket opened: {ws.url}",
280-
"WebSocket closed",
281-
),
282-
)
283-
)
266+
@contextlib.contextmanager
267+
def web_socket_default_log_handler(web_socket: WebSocket) -> Iterator[None]:
284268

285-
ws.on("framesent", lambda payload: ctx.logger.info("⬇️ %s", payload))
286-
ws.on("framereceived", lambda payload: ctx.logger.info("⬆️ %s", payload))
287-
ws.on("close", lambda payload: stack.close()) # noqa: ARG005
269+
try:
270+
with log_context(
271+
logging.DEBUG,
272+
msg="handle websocket message (set to --log-cli-level=DEBUG level if you wanna see all of them)",
273+
) as ctx:
274+
275+
def on_framesent(payload: str | bytes) -> None:
276+
ctx.logger.debug("⬇️ Frame sent: %s", payload)
277+
278+
def on_framereceived(payload: str | bytes) -> None:
279+
ctx.logger.debug("⬆️ Frame received: %s", payload)
280+
281+
def on_close(payload: WebSocket) -> None:
282+
ctx.logger.warning("⚠️ Websocket closed: %s", payload)
283+
284+
def on_socketerror(error_msg: str) -> None:
285+
ctx.logger.error("❌ Websocket error: %s", error_msg)
286+
287+
web_socket.on("framesent", on_framesent)
288+
web_socket.on("framereceived", on_framereceived)
289+
web_socket.on("close", on_close)
290+
web_socket.on("socketerror", on_socketerror)
291+
yield
292+
finally:
293+
web_socket.remove_listener("framesent", on_framesent)
294+
web_socket.remove_listener("framereceived", on_framereceived)
295+
web_socket.remove_listener("close", on_close)
296+
web_socket.remove_listener("socketerror", on_socketerror)
288297

289298

290299
def _node_started_predicate(request: Request) -> bool:

packages/pytest-simcore/src/pytest_simcore/helpers/playwright_sim4life.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
import arrow
88
from playwright.sync_api import FrameLocator, Page, WebSocket, expect
9+
from pydantic import TypeAdapter # pylint: disable=no-name-in-module
10+
from pydantic import ByteSize
911

1012
from .logging_tools import log_context
1113
from .playwright import (
@@ -17,7 +19,7 @@
1719
wait_for_service_running,
1820
)
1921

20-
_S4L_STREAMING_ESTABLISHMENT_MAX_TIME: Final[int] = 15 * SECOND
22+
_S4L_STREAMING_ESTABLISHMENT_MAX_TIME: Final[int] = 30 * SECOND
2123
_S4L_SOCKETIO_REGEX: Final[re.Pattern] = re.compile(
2224
r"^(?P<protocol>[^:]+)://(?P<node_id>[^\.]+)\.services\.(?P<hostname>[^\/]+)\/socket\.io\/.+$"
2325
)
@@ -63,7 +65,7 @@ def __call__(self, message: str) -> bool:
6365
self._initial_bit_rate_time = arrow.utcnow().datetime
6466
self.logger.info(
6567
"%s",
66-
f"{self._initial_bit_rate=} at {self._initial_bit_rate_time.isoformat()}",
68+
f"{TypeAdapter(ByteSize).validate_python(self._initial_bit_rate).human_readable()}/s at {self._initial_bit_rate_time.isoformat()}",
6769
)
6870
return False
6971

@@ -78,7 +80,7 @@ def __call__(self, message: str) -> bool:
7880
bitrate_test = bool(self._initial_bit_rate != current_bitrate)
7981
self.logger.info(
8082
"%s",
81-
f"{current_bitrate=} after {elapsed_time=}: {'good!' if bitrate_test else 'failed! bitrate did not change! TIP: talk with MaG about underwater cables!'}",
83+
f"{TypeAdapter(ByteSize).validate_python(current_bitrate).human_readable()}/s after {elapsed_time=}: {'good!' if bitrate_test else 'failed! bitrate did not change! TIP: talk with MaG about underwater cables!'}",
8284
)
8385
return bitrate_test
8486

services/clusters-keeper/src/simcore_service_clusters_keeper/api/health.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
@router.get("/", include_in_schema=True, response_class=PlainTextResponse)
2222
async def health_check():
2323
# NOTE: sync url in docker/healthcheck.py with this entrypoint!
24-
return f"{__name__}.health_check@{datetime.datetime.now(datetime.timezone.utc).isoformat()}"
24+
return f"{__name__}.health_check@{datetime.datetime.now(datetime.UTC).isoformat()}"
2525

2626

2727
class _ComponentStatus(BaseModel):
@@ -33,25 +33,34 @@ class _StatusGet(BaseModel):
3333
rabbitmq: _ComponentStatus
3434
ec2: _ComponentStatus
3535
redis_client_sdk: _ComponentStatus
36+
ssm: _ComponentStatus
3637

3738

3839
@router.get("/status", include_in_schema=True, response_model=_StatusGet)
3940
async def get_status(app: Annotated[FastAPI, Depends(get_app)]) -> _StatusGet:
4041
return _StatusGet(
4142
rabbitmq=_ComponentStatus(
4243
is_enabled=is_rabbitmq_enabled(app),
43-
is_responsive=await get_rabbitmq_client(app).ping()
44-
if is_rabbitmq_enabled(app)
45-
else False,
44+
is_responsive=(
45+
await get_rabbitmq_client(app).ping()
46+
if is_rabbitmq_enabled(app)
47+
else False
48+
),
4649
),
4750
ec2=_ComponentStatus(
4851
is_enabled=bool(app.state.ec2_client),
49-
is_responsive=await app.state.ec2_client.ping()
50-
if app.state.ec2_client
51-
else False,
52+
is_responsive=(
53+
await app.state.ec2_client.ping() if app.state.ec2_client else False
54+
),
5255
),
5356
redis_client_sdk=_ComponentStatus(
5457
is_enabled=bool(app.state.redis_client_sdk),
5558
is_responsive=await get_redis_client(app).ping(),
5659
),
60+
ssm=_ComponentStatus(
61+
is_enabled=(app.state.ssm_client is not None),
62+
is_responsive=(
63+
await app.state.ssm_client.ping() if app.state.ssm_client else False
64+
),
65+
),
5766
)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from typing import Final
2+
3+
from aws_library.ec2._models import AWSTagKey, AWSTagValue
4+
from pydantic import parse_obj_as
5+
6+
DOCKER_STACK_DEPLOY_COMMAND_NAME: Final[str] = "private cluster docker deploy"
7+
DOCKER_STACK_DEPLOY_COMMAND_EC2_TAG_KEY: Final[AWSTagKey] = parse_obj_as(
8+
AWSTagKey, "io.simcore.clusters-keeper.private_cluster_docker_deploy"
9+
)
10+
11+
USER_ID_TAG_KEY: Final[AWSTagKey] = parse_obj_as(AWSTagKey, "user_id")
12+
WALLET_ID_TAG_KEY: Final[AWSTagKey] = parse_obj_as(AWSTagKey, "wallet_id")
13+
ROLE_TAG_KEY: Final[AWSTagKey] = parse_obj_as(AWSTagKey, "role")
14+
WORKER_ROLE_TAG_VALUE: Final[AWSTagValue] = parse_obj_as(AWSTagValue, "worker")
15+
MANAGER_ROLE_TAG_VALUE: Final[AWSTagValue] = parse_obj_as(AWSTagValue, "manager")

services/clusters-keeper/src/simcore_service_clusters_keeper/core/application.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from ..modules.ec2 import setup as setup_ec2
2020
from ..modules.rabbitmq import setup as setup_rabbitmq
2121
from ..modules.redis import setup as setup_redis
22+
from ..modules.ssm import setup as setup_ssm
2223
from ..rpc.rpc_routes import setup_rpc_routes
2324
from .settings import ApplicationSettings
2425

@@ -55,6 +56,7 @@ def create_app(settings: ApplicationSettings) -> FastAPI:
5556
setup_rabbitmq(app)
5657
setup_rpc_routes(app)
5758
setup_ec2(app)
59+
setup_ssm(app)
5860
setup_redis(app)
5961
setup_clusters_management(app)
6062

0 commit comments

Comments
 (0)