feature: dynamicallt allocate port and save in service registry. Update iocs overview on service creation
This commit is contained in:
+41
-5
@@ -15,10 +15,13 @@ MASTER_SERVICE_DIR = REPO_ROOT / "services" / "000-master" / "current"
|
||||
MASTER_SERVICE_CONFIG_DIR = MASTER_SERVICE_DIR / "app" / "config"
|
||||
MASTER_HLA_NAMES_FILENAME = MASTER_SERVICE_CONFIG_DIR / "hla_names.yml"
|
||||
|
||||
IOCS_OVERVIEW_FILENAME = REPO_ROOT / "docs" / "ioc" / "ioc_overview.md"
|
||||
|
||||
|
||||
class Service(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
ioc_port: int
|
||||
status: ServiceStatus
|
||||
|
||||
@property
|
||||
@@ -39,7 +42,7 @@ class Service(BaseModel):
|
||||
return f"{self.id:03d}"
|
||||
|
||||
def to_dict(self):
|
||||
return {"name": self.name_lower, "status": str(self.status)}
|
||||
return {"name": self.name_lower, "ioc_port": self.ioc_port, "status": str(self.status)}
|
||||
|
||||
class Config:
|
||||
use_enum_values = True
|
||||
@@ -56,7 +59,8 @@ class ServiceRegistry(BaseModel):
|
||||
config_path: ClassVar[str] = str(SERVICE_REGISTRY_FILENAME)
|
||||
|
||||
next_available_id: int
|
||||
services: dict[int, dict]
|
||||
next_available_ioc_port: int
|
||||
services: dict[str, dict]
|
||||
|
||||
@classmethod
|
||||
def read_from_config(cls) -> "ServiceRegistry":
|
||||
@@ -67,12 +71,18 @@ class ServiceRegistry(BaseModel):
|
||||
return registry
|
||||
|
||||
def get_services(self) -> list[Service]:
|
||||
return [Service(id=svc_id, **svc_data) for svc_id, svc_data in self.services.items()]
|
||||
return [Service(id=int(svc_id), **svc_data) for svc_id, svc_data in self.services.items()]
|
||||
|
||||
def add_service(self, name: str) -> Service:
|
||||
svc = Service(id=self.next_available_id, name=name, status=ServiceStatus.ACTIVE)
|
||||
self.services.update({svc.id: svc.to_dict()})
|
||||
svc = Service(
|
||||
id=self.next_available_id,
|
||||
name=name,
|
||||
ioc_port=self.next_available_ioc_port,
|
||||
status=ServiceStatus.ACTIVE,
|
||||
)
|
||||
self.services.update({svc.id_str: svc.to_dict()})
|
||||
self.next_available_id += 1
|
||||
self.next_available_ioc_port += 1
|
||||
|
||||
return svc
|
||||
|
||||
@@ -100,3 +110,29 @@ class MasterHLANames(BaseModel):
|
||||
def write_to_config(self) -> None:
|
||||
with open(self.config_path, "w") as f:
|
||||
yaml.safe_dump(self.model_dump(), f, indent=4)
|
||||
|
||||
|
||||
class IocsOverview(BaseModel):
|
||||
config_path: ClassVar[str] = str(IOCS_OVERVIEW_FILENAME)
|
||||
|
||||
content: str
|
||||
|
||||
@classmethod
|
||||
def read_from_file(cls) -> "IocsOverview":
|
||||
with open(cls.config_path, "r", encoding="utf-8") as f:
|
||||
s = f.read()
|
||||
|
||||
return IocsOverview(content=s)
|
||||
|
||||
def add_ioc(self, service: Service, description: str):
|
||||
new_row = f"| AGEBD-CPCL-{service.name_upper} | {service.ioc_port} | {description} |\n"
|
||||
|
||||
# Ensuring it starts on a clean new line if the file didn't end with one
|
||||
if not self.content.endswith("\n"):
|
||||
self.content += "\n"
|
||||
|
||||
self.content += new_row
|
||||
|
||||
def write_to_file(self):
|
||||
with open(self.config_path, "w") as f:
|
||||
f.write(self.content)
|
||||
|
||||
@@ -14,7 +14,7 @@ from core.git import (
|
||||
git_push_changes,
|
||||
switch_branch,
|
||||
)
|
||||
from core.models import MasterHLANames, Service, ServiceRegistry
|
||||
from core.models import IocsOverview, MasterHLANames, Service, ServiceRegistry
|
||||
from core.utils import get_git_root
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -30,13 +30,9 @@ MASTER_IOC_SUBS_FILE = MASTER_SERVICE_DIR / "ioc" / "AGEBD-CPCL-MASTER_main.subs
|
||||
|
||||
|
||||
class ServiceCreator:
|
||||
def __init__(
|
||||
self,
|
||||
ioc_port: int,
|
||||
user: str,
|
||||
) -> None:
|
||||
self.ioc_port = ioc_port
|
||||
def __init__(self, user: str, ioc_description: str) -> None:
|
||||
self.user = user
|
||||
self.ioc_description = ioc_description
|
||||
|
||||
def add_service(self, name: str):
|
||||
repo = git.Repo(REPO_ROOT)
|
||||
@@ -50,6 +46,9 @@ class ServiceCreator:
|
||||
hla_names_old = MasterHLANames.read_from_config()
|
||||
hla_names = MasterHLANames.read_from_config()
|
||||
hla_names.add_hla_name(service.name_upper)
|
||||
iocs_overview_old = IocsOverview.read_from_file()
|
||||
iocs_overview = IocsOverview.read_from_file()
|
||||
iocs_overview.add_ioc(service, description=self.ioc_description)
|
||||
|
||||
branch_name = f"feature/add-service-{service.dir_name}"
|
||||
delete_local_branch(repo, branch_name)
|
||||
@@ -58,12 +57,12 @@ class ServiceCreator:
|
||||
try:
|
||||
self._render_new_service_templates(
|
||||
service=service,
|
||||
ioc_port=self.ioc_port,
|
||||
user=self.user,
|
||||
)
|
||||
self._generate_uv_lock(service=service)
|
||||
registry.write_to_config()
|
||||
hla_names.write_to_config()
|
||||
iocs_overview.write_to_file()
|
||||
|
||||
self._append_to_master_ioc_subs(
|
||||
service_name=service.name_upper,
|
||||
@@ -87,13 +86,13 @@ class ServiceCreator:
|
||||
shutil.rmtree(Path(SERVICE_DEST_DIR / service.dir_name), ignore_errors=True)
|
||||
registry_old.write_to_config()
|
||||
hla_names_old.write_to_config()
|
||||
iocs_overview_old.write_to_file()
|
||||
switch_branch(repo, original_branch)
|
||||
raise e
|
||||
|
||||
def _render_new_service_templates(
|
||||
self,
|
||||
service: Service,
|
||||
ioc_port: int,
|
||||
user: str,
|
||||
):
|
||||
"""
|
||||
@@ -106,7 +105,6 @@ class ServiceCreator:
|
||||
"service_id": service.id_str,
|
||||
"service_name_upper": service.name_upper,
|
||||
"service_name_lower": service.name_lower,
|
||||
"ioc_port": ioc_port,
|
||||
"user": user,
|
||||
},
|
||||
)
|
||||
|
||||
+4
-2
@@ -12,13 +12,15 @@ REPO_ROOT = get_git_root(__file__)
|
||||
@service.command()
|
||||
def add(
|
||||
name: str = typer.Option(..., "--name", "-n"),
|
||||
ioc_port: int = typer.Option(..., "--ioc-port", "-p"),
|
||||
user: str = typer.Option(..., "--user", "-u"),
|
||||
ioc_description: str = typer.Option(
|
||||
..., "--ioc-description", "-d", help="See <repo-root>/docs/ioc/ioc_overview.md for examples"
|
||||
),
|
||||
):
|
||||
init_logging()
|
||||
ServiceCreator(
|
||||
ioc_port=ioc_port, # TODO: read from registry
|
||||
user=user, # TODO: read from 'whoami'?
|
||||
ioc_description=ioc_description,
|
||||
).add_service(name=name)
|
||||
|
||||
|
||||
|
||||
Generated
+71
-8
@@ -2,7 +2,16 @@ version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.9"
|
||||
resolution-markers = [
|
||||
"python_full_version >= '3.10'",
|
||||
"python_full_version >= '3.14' and sys_platform == 'win32'",
|
||||
"python_full_version >= '3.14' and sys_platform == 'emscripten'",
|
||||
"python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32'",
|
||||
"python_full_version == '3.11.*' and sys_platform == 'win32'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten'",
|
||||
"python_full_version == '3.11.*' and sys_platform == 'emscripten'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version == '3.10.*'",
|
||||
"python_full_version < '3.10'",
|
||||
]
|
||||
|
||||
@@ -117,7 +126,16 @@ name = "copier"
|
||||
version = "9.16.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
resolution-markers = [
|
||||
"python_full_version >= '3.10'",
|
||||
"python_full_version >= '3.14' and sys_platform == 'win32'",
|
||||
"python_full_version >= '3.14' and sys_platform == 'emscripten'",
|
||||
"python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32'",
|
||||
"python_full_version == '3.11.*' and sys_platform == 'win32'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten'",
|
||||
"python_full_version == '3.11.*' and sys_platform == 'emscripten'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version == '3.10.*'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "python_full_version >= '3.10'" },
|
||||
@@ -166,7 +184,7 @@ name = "exceptiongroup"
|
||||
version = "1.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
|
||||
wheels = [
|
||||
@@ -224,7 +242,16 @@ name = "iniconfig"
|
||||
version = "2.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
resolution-markers = [
|
||||
"python_full_version >= '3.10'",
|
||||
"python_full_version >= '3.14' and sys_platform == 'win32'",
|
||||
"python_full_version >= '3.14' and sys_platform == 'emscripten'",
|
||||
"python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32'",
|
||||
"python_full_version == '3.11.*' and sys_platform == 'win32'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten'",
|
||||
"python_full_version == '3.11.*' and sys_platform == 'emscripten'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version == '3.10.*'",
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
|
||||
wheels = [
|
||||
@@ -276,7 +303,16 @@ name = "markdown-it-py"
|
||||
version = "4.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
resolution-markers = [
|
||||
"python_full_version >= '3.10'",
|
||||
"python_full_version >= '3.14' and sys_platform == 'win32'",
|
||||
"python_full_version >= '3.14' and sys_platform == 'emscripten'",
|
||||
"python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32'",
|
||||
"python_full_version == '3.11.*' and sys_platform == 'win32'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten'",
|
||||
"python_full_version == '3.11.*' and sys_platform == 'emscripten'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version == '3.10.*'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "mdurl", marker = "python_full_version >= '3.10'" },
|
||||
@@ -435,7 +471,16 @@ name = "platformdirs"
|
||||
version = "4.10.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
resolution-markers = [
|
||||
"python_full_version >= '3.10'",
|
||||
"python_full_version >= '3.14' and sys_platform == 'win32'",
|
||||
"python_full_version >= '3.14' and sys_platform == 'emscripten'",
|
||||
"python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32'",
|
||||
"python_full_version == '3.11.*' and sys_platform == 'win32'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten'",
|
||||
"python_full_version == '3.11.*' and sys_platform == 'emscripten'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version == '3.10.*'",
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d7/47/e4501f49c178ae1d9f4a75073fda4204f52647993f075a9db4d14930e0c5/platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7", size = 31224, upload-time = "2026-05-28T03:32:53.587Z" }
|
||||
wheels = [
|
||||
@@ -668,7 +713,16 @@ name = "pytest"
|
||||
version = "9.1.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
resolution-markers = [
|
||||
"python_full_version >= '3.10'",
|
||||
"python_full_version >= '3.14' and sys_platform == 'win32'",
|
||||
"python_full_version >= '3.14' and sys_platform == 'emscripten'",
|
||||
"python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32'",
|
||||
"python_full_version == '3.11.*' and sys_platform == 'win32'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten'",
|
||||
"python_full_version == '3.11.*' and sys_platform == 'emscripten'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version == '3.10.*'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" },
|
||||
@@ -903,7 +957,16 @@ name = "typer"
|
||||
version = "0.26.8"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
resolution-markers = [
|
||||
"python_full_version >= '3.10'",
|
||||
"python_full_version >= '3.14' and sys_platform == 'win32'",
|
||||
"python_full_version >= '3.14' and sys_platform == 'emscripten'",
|
||||
"python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'win32'",
|
||||
"python_full_version == '3.11.*' and sys_platform == 'win32'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform == 'emscripten'",
|
||||
"python_full_version == '3.11.*' and sys_platform == 'emscripten'",
|
||||
"python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'",
|
||||
"python_full_version == '3.10.*'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "annotated-doc", marker = "python_full_version >= '3.10'" },
|
||||
|
||||
Reference in New Issue
Block a user