Skip to content

Commit

Permalink
ENG-474: Expose apps_config to users (#2194)
Browse files Browse the repository at this point in the history
* ENG-474: Expose apps_config to users

* fix tests

* update admin client

* fix tests
  • Loading branch information
YevheniiSemendiak authored Nov 17, 2024
1 parent 007ffc7 commit f869d8d
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 5 deletions.
15 changes: 14 additions & 1 deletion platform_api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@
)

from .cluster import ClusterConfig, ClusterConfigRegistry, ClusterUpdater
from .cluster_config import EnergySchedule, EnergySchedulePeriod, VolumeConfig
from .cluster_config import (
AppsConfig,
EnergySchedule,
EnergySchedulePeriod,
VolumeConfig,
)
from .config import Config, CORSConfig
from .config_client import ConfigClient
from .config_factory import EnvironConfigFactory
Expand Down Expand Up @@ -190,6 +195,7 @@ def _convert_cluster_config_to_payload(
self._convert_storage_volume_to_payload(volume)
for volume in cluster_config.storage.volumes
],
"apps": self._convert_apps_config_to_payload(cluster_config.apps),
}
if cluster_config.location:
result["location"] = cluster_config.location
Expand Down Expand Up @@ -320,6 +326,13 @@ def _convert_storage_volume_to_payload(
"credits_per_hour_per_gb": str(volume.credits_per_hour_per_gb),
}

def _convert_apps_config_to_payload(
self, apps_config: AppsConfig
) -> dict[str, Any]:
return {
"apps_hostname_templates": apps_config.apps_hostname_templates,
}


@aiohttp.web.middleware
async def handle_exceptions(
Expand Down
6 changes: 6 additions & 0 deletions platform_api/cluster_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,18 @@ def with_volumes(self, value: Sequence[VolumeConfig]) -> "StorageConfig":
return replace(self, volumes=value)


@dataclass(frozen=True)
class AppsConfig:
apps_hostname_templates: list[str]


@dataclass(frozen=True)
class ClusterConfig:
name: str
orchestrator: OrchestratorConfig
storage: StorageConfig
ingress: IngressConfig
apps: AppsConfig
timezone: tzinfo = UTC
energy: EnergyConfig = EnergyConfig()
location: Optional[str] = None
Expand Down
8 changes: 8 additions & 0 deletions platform_api/cluster_config_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from .cluster_config import (
DEFAULT_ENERGY_SCHEDULE_NAME,
AppsConfig,
ClusterConfig,
EnergyConfig,
EnergySchedule,
Expand Down Expand Up @@ -54,6 +55,7 @@ def create_cluster_config(self, payload: dict[str, Any]) -> Optional[ClusterConf
timezone=timezone,
energy=self._create_energy_config(payload, timezone=timezone),
storage=self._create_storage_config(payload),
apps=self._create_apps_config(payload),
)
except t.DataError as err:
logging.warning(f"failed to parse cluster config: {err}")
Expand Down Expand Up @@ -235,3 +237,9 @@ def _create_storage_config(self, payload: dict[str, Any]) -> StorageConfig:
for p in payload["storage"].get("volumes", ())
]
)

def _create_apps_config(self, payload: dict[str, Any]) -> AppsConfig:
apps_payload: dict[str, Any] = payload.get("apps", {})
return AppsConfig(
apps_hostname_templates=apps_payload.get("apps_hostname_templates", []),
)
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ install_requires =
alembic==1.9.4
psycopg2-binary==2.9.7
typing-extensions==4.9.0
neuro-admin-client==23.3.0
neuro-admin-client==24.11.0
yarl==1.12.1

[options.entry_points]
Expand Down
6 changes: 6 additions & 0 deletions tests/integration/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from collections.abc import AsyncGenerator, AsyncIterator, Awaitable, Callable
from contextlib import asynccontextmanager
from dataclasses import dataclass, field
from decimal import Decimal
from typing import Protocol

import aiodocker
Expand Down Expand Up @@ -235,6 +236,11 @@ async def _factory(
cluster_name=cluster,
org_name=org_name,
)
await admin_client.update_org_cluster_balance(
cluster_name=cluster,
org_name=org_name,
credits=Decimal("100"),
)
except ClientResponseError:
pass
try:
Expand Down
4 changes: 4 additions & 0 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

from platform_api.cluster_config import (
UTC,
AppsConfig,
ClusterConfig,
EnergyConfig,
EnergySchedule,
Expand Down Expand Up @@ -952,6 +953,9 @@ def _f(cluster_name: str = "test-cluster") -> ClusterConfig:
)
]
),
apps=AppsConfig(
apps_hostname_templates=["{app_name}.apps.dev.neu.ro"],
),
)

return _f
Expand Down
4 changes: 4 additions & 0 deletions tests/integration/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def cluster_configs_payload() -> list[dict[str, Any]]:
"blob_storage": {"url": "https://dev.neu.ro/api/v1/blob"},
"disks": {"url": "https://dev.neu.ro/api/v1/disk"},
"buckets": {"url": "https://dev.neu.ro/api/v1/buckets"},
"apps": {"apps_hostname_templates": ["{app_name}.apps.dev.neu.ro"]},
}
]

Expand Down Expand Up @@ -504,6 +505,7 @@ async def test_config(
"credits_per_hour_per_gb": "100",
}
],
"apps": {"apps_hostname_templates": ["{app_name}.apps.dev.neu.ro"]},
}
expected_payload: dict[str, Any] = {
"authorized": True,
Expand Down Expand Up @@ -735,6 +737,7 @@ async def test_config__with_orgs_and_projects(
"timezone": "UTC",
"energy_schedules": mock.ANY,
"storage_volumes": mock.ANY,
"apps": {"apps_hostname_templates": ["{app_name}.apps.dev.neu.ro"]},
}
expected_payload: dict[str, Any] = {
"authorized": True,
Expand Down Expand Up @@ -981,6 +984,7 @@ async def test_config_with_oauth(
"timezone": "UTC",
"energy_schedules": mock.ANY,
"storage_volumes": mock.ANY,
"apps": {"apps_hostname_templates": ["{app_name}.apps.dev.neu.ro"]},
}
expected_payload: dict[str, Any] = {
"authorized": True,
Expand Down
13 changes: 10 additions & 3 deletions tests/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
)
from platform_api.cluster_config import (
UTC,
AppsConfig,
EnergyConfig,
EnergySchedule,
EnergySchedulePeriod,
Expand Down Expand Up @@ -286,7 +287,9 @@ def __init__(self) -> None:
self.spending_log: list[
tuple[str, Optional[str], str, Decimal, Optional[str]]
] = []
self.debts_log: list[tuple[str, str, Decimal, str]] = []
self.debts_log: list[tuple[str, Decimal, str, Optional[str], Optional[str]]] = (
[]
)
self.raise_404: bool = False

async def get_user_with_clusters(self, name: str) -> tuple[User, list[ClusterUser]]:
Expand Down Expand Up @@ -316,11 +319,14 @@ async def charge_cluster_user( # type: ignore
async def add_debt(
self,
cluster_name: str,
username: str,
credits: Decimal,
idempotency_key: str,
org_name: Optional[str] = None,
username: Optional[str] = None,
) -> None:
self.debts_log.append((cluster_name, username, credits, idempotency_key))
self.debts_log.append(
(cluster_name, credits, idempotency_key, org_name, username)
)

async def get_cluster_user( # type: ignore
self,
Expand Down Expand Up @@ -471,6 +477,7 @@ def cluster_config() -> ClusterConfig:
]
),
storage=StorageConfig(volumes=()),
apps=AppsConfig(apps_hostname_templates=[]),
)


Expand Down
10 changes: 10 additions & 0 deletions tests/unit/test_cluster_config_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ def clusters_payload(storage_payload: dict[str, Any]) -> list[dict[str, Any]]:
"disks": {"url": "https://dev.neu.ro/api/v1/disk"},
"buckets": {"url": "https://dev.neu.ro/api/v1/buckets"},
"blob_storage": {"url": "https://dev.neu.ro/api/v1/blob"},
"apps": {"apps_hostname_templates": ["{app_name}.apps.dev.neu.ro"]},
**storage_payload,
}
]
Expand Down Expand Up @@ -462,6 +463,15 @@ def test_energy(self, clusters_payload: Sequence[dict[str, Any]]) -> None:
),
]

def test_apps(self, clusters_payload: Sequence[dict[str, Any]]) -> None:
factory = ClusterConfigFactory()
clusters = factory.create_cluster_configs(clusters_payload)

assert clusters[0].apps
assert clusters[0].apps.apps_hostname_templates == [
"{app_name}.apps.dev.neu.ro"
]


class TestEnergySchedulePeriod:
def test__post_init__missing_start_time_tzinfo(self) -> None:
Expand Down

0 comments on commit f869d8d

Please sign in to comment.