From 51b2bf445c4c509ed09a1bde2dc63d8bb5bc6ff9 Mon Sep 17 00:00:00 2001 From: Erik Reid <erik.reid@geant.org> Date: Sun, 19 Mar 2023 18:16:31 +0100 Subject: [PATCH] added next lag/physical dummy placeholders --- resource_management/router_interfaces.py | 1 - resource_management/routes/interfaces.py | 75 ++++++++++++++++++++++++ test/test_interfaces_routes.py | 18 ++++++ 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/resource_management/router_interfaces.py b/resource_management/router_interfaces.py index 77a08c7..d0cbc88 100644 --- a/resource_management/router_interfaces.py +++ b/resource_management/router_interfaces.py @@ -15,7 +15,6 @@ def load_router_interfaces(fqdn: str): """ params = config.load() - db.init_db_model(params['db']) with juniper.router( hostname=fqdn, diff --git a/resource_management/routes/interfaces.py b/resource_management/routes/interfaces.py index 771bc2a..ca15f20 100644 --- a/resource_management/routes/interfaces.py +++ b/resource_management/routes/interfaces.py @@ -2,6 +2,7 @@ from fastapi import APIRouter, HTTPException import pydantic from resource_management import db +from resource_management import config from resource_management.db import model from resource_management import router_interfaces @@ -19,9 +20,23 @@ class InterfacesSummary(pydantic.BaseModel): physical: InterfaceCounts +class NextLAG(pydantic.BaseModel): + fqdn: str + name: str + + +class NextPhysicalInterface(pydantic.BaseModel): + fqdn: str + lag: str + name: str + + @router.post('/import/{fqdn}') async def load_router_interfaces(fqdn: str) -> InterfacesSummary: + params = config.load() + db.init_db_model(params['db']) + router_interfaces.load_router_interfaces(fqdn) with db.session_scope() as session: @@ -38,3 +53,63 @@ async def load_router_interfaces(fqdn: str) -> InterfacesSummary: 'available': num_available_physical } } + +@router.post('/next-lag/{fqdn}') +async def reserve_next_lag(fqdn: str) -> NextLAG: + """ + compute the next available lag name for the given router + + TODO: _next_lag_name is a placeholder for + whatever logic turns out to be right + """ + + params = config.load() + db.init_db_model(params['db']) + + with db.session_scope() as session: + records = session.query(model.LAG.name) \ + .join(model.Router).filter_by(fqdn=fqdn).all() + names = set(r[0] for r in records) + + def _next_lag_name(): + index = 1 + while True: + candidate = f'ae{index}' + if candidate not in names: + return candidate + index += 1 + + return { + 'fqdn': fqdn, + 'name': _next_lag_name() + } + + +@router.post('/next-physical/{fqdn}/{lag_name}') +async def reserve_physical_bundle_member(fqdn: str, lag_name: str) -> NextPhysicalInterface: + """ + compute the next available lag name for the given router + + TODO: _find_available_physical is a placeholder for + whatever logic turns out to be right (e.g. speeds, etc) + """ + + params = config.load() + db.init_db_model(params['db']) + + with db.session_scope() as session: + router = session.query(model.Router).filter_by(fqdn=fqdn).one() + + def _find_available_physical(): + for ifc in router.physical: + if not ifc.lag: + return ifc.name + raise HTTPException( + status_code=404, + detail=f'no available physical ports for "{lag_name}"') + + return { + 'fqdn': fqdn, + 'lag': lag_name, + 'name': _find_available_physical() + } diff --git a/test/test_interfaces_routes.py b/test/test_interfaces_routes.py index 09e1f93..4b5ece4 100644 --- a/test/test_interfaces_routes.py +++ b/test/test_interfaces_routes.py @@ -2,6 +2,8 @@ import jsonschema from resource_management.routes.default import Version from resource_management.routes import interfaces +from resource_management import router_interfaces + def test_bad_method(client): rv = client.post('/api/version') @@ -20,3 +22,19 @@ def test_update_router_interfaces(client, resources_db, mocked_router, router_na jsonschema.validate(rv.json(), interfaces.InterfacesSummary.schema()) +def test_next_lag(client, resources_db, mocked_router, router_name): + + router_interfaces.load_router_interfaces(router_name) + + rv = client.post(f'/api/interfaces/next-lag/{router_name}') + assert rv.status_code == 200 + jsonschema.validate(rv.json(), interfaces.NextLAG.schema()) + + +def test_next_physical(client, resources_db, mocked_router, router_name): + + router_interfaces.load_router_interfaces(router_name) + + rv = client.post(f'/api/interfaces/next-physical/{router_name}/ae123123') + assert rv.status_code == 200 + jsonschema.validate(rv.json(), interfaces.NextPhysicalInterface.schema()) -- GitLab