Skip to content
Snippets Groups Projects
Commit 1aabc59e authored by Erik Reid's avatar Erik Reid
Browse files

added state to schema, and initialize correct value

parent 6548545b
No related branches found
No related tags found
No related merge requests found
...@@ -5,10 +5,11 @@ Resources Database ...@@ -5,10 +5,11 @@ Resources Database
This database holds information about router port resources This database holds information about router port resources
""" """
import enum
import logging import logging
from typing import Any from typing import Any
from sqlalchemy import Column, ForeignKey, Integer, String import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
...@@ -18,10 +19,16 @@ logger = logging.getLogger(__name__) ...@@ -18,10 +19,16 @@ logger = logging.getLogger(__name__)
base_schema: Any = declarative_base() base_schema: Any = declarative_base()
class AvalabilityStates(enum.Enum):
AVAILABLE = enum.auto()
USED = enum.auto()
RESERVED = enum.auto()
class Router(base_schema): class Router(base_schema):
__tablename__ = 'routers' __tablename__ = 'routers'
id = Column('id', Integer, primary_key=True) id = sa.Column('id', sa.Integer, primary_key=True)
fqdn = Column('fqdn', String, nullable=False) fqdn = sa.Column('fqdn', sa.String, nullable=False)
physical = relationship( physical = relationship(
"PhysicalInterface", "PhysicalInterface",
...@@ -36,13 +43,18 @@ class Router(base_schema): ...@@ -36,13 +43,18 @@ class Router(base_schema):
class LAG(base_schema): class LAG(base_schema):
__tablename__ = 'lags' __tablename__ = 'lags'
id = Column('id', Integer, primary_key=True) id = sa.Column('id', sa.Integer, primary_key=True)
name = Column('name', String, nullable=False) name = sa.Column('name', sa.String, nullable=False)
availability = sa.Column(
'availability',
sa.Enum(*[a.name for a in AvalabilityStates]),
nullable=False)
router_id = Column( router_id = sa.Column(
'router_id', 'router_id',
Integer, sa.Integer,
ForeignKey('routers.id'), sa.ForeignKey('routers.id'),
nullable=False) nullable=False)
router = relationship('Router', back_populates='lags') router = relationship('Router', back_populates='lags')
...@@ -54,20 +66,25 @@ class LAG(base_schema): ...@@ -54,20 +66,25 @@ class LAG(base_schema):
class PhysicalInterface(base_schema): class PhysicalInterface(base_schema):
__tablename__ = 'physical_interfaces' __tablename__ = 'physical_interfaces'
id = Column('id', Integer, primary_key=True) id = sa.Column('id', sa.Integer, primary_key=True)
name = Column('name', String, nullable=False) name = sa.Column('name', sa.String, nullable=False)
availability = sa.Column(
'availability',
sa.Enum(*[a.name for a in AvalabilityStates]),
nullable=False)
router_id = Column( router_id = sa.Column(
'router_id', 'router_id',
Integer, sa.Integer,
ForeignKey('routers.id'), sa.ForeignKey('routers.id'),
nullable=False) nullable=False)
router = relationship('Router', back_populates='physical') router = relationship('Router', back_populates='physical')
lag_id = Column( lag_id = sa.Column(
'lag_id', 'lag_id',
Integer, sa.Integer,
ForeignKey('lags.id'), sa.ForeignKey('lags.id'),
nullable=True) nullable=True)
lag = relationship('LAG', back_populates='physical') lag = relationship('LAG', back_populates='physical')
...@@ -79,11 +96,11 @@ class PhysicalInterface(base_schema): ...@@ -79,11 +96,11 @@ class PhysicalInterface(base_schema):
class LogicalInterface(base_schema): class LogicalInterface(base_schema):
__tablename__ = 'logical_interfaces' __tablename__ = 'logical_interfaces'
id = Column('id', Integer, primary_key=True) id = sa.Column('id', sa.Integer, primary_key=True)
name = Column('name', String, nullable=False) name = sa.Column('name', sa.String, nullable=False)
physical_id = Column( physical_id = sa.Column(
'physical_id', 'physical_id',
Integer, sa.Integer,
ForeignKey('physical_interfaces.id'), sa.ForeignKey('physical_interfaces.id'),
nullable=False) nullable=False)
physical = relationship('PhysicalInterface', back_populates='logical') physical = relationship('PhysicalInterface', back_populates='logical')
...@@ -6,12 +6,10 @@ from resource_management.db import model ...@@ -6,12 +6,10 @@ from resource_management.db import model
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def load_router_interfaces(fqdn: str): def load_new_router_interfaces(fqdn: str):
""" """
load all interface info from the router and load all interface info from the router and
update the db with the current information update the db with the current information
TODO: merge, not just create new
""" """
params = config.load() params = config.load()
...@@ -25,11 +23,19 @@ def load_router_interfaces(fqdn: str): ...@@ -25,11 +23,19 @@ def load_router_interfaces(fqdn: str):
physical = juniper.load_installed_ethernet_ports(dev) physical = juniper.load_installed_ethernet_ports(dev)
logical = juniper.load_logical_interfaces(dev) logical = juniper.load_logical_interfaces(dev)
def _find_lag_name(interface_name): _inverted_aggregate_map = {}
for name, interfaces in aggregates.items(): for lag_name, physical_interfaces in aggregates.items():
if interface_name in interfaces: for pn in physical_interfaces:
return name _inverted_aggregate_map[pn] = lag_name
return None
def _interface_availability(ifc_name):
if physical[ifc_name]['oper']:
return model.AvalabilityStates.USED.name
if ifc_name in _inverted_aggregate_map:
return model.AvalabilityStates.USED.name
if ifc_name in logical:
return model.AvalabilityStates.USED.name
return model.AvalabilityStates.AVAILABLE.name
with db.session_scope() as session: with db.session_scope() as session:
...@@ -38,13 +44,15 @@ def load_router_interfaces(fqdn: str): ...@@ -38,13 +44,15 @@ def load_router_interfaces(fqdn: str):
# add all the lag records # add all the lag records
# keep a map for referencing below when adding physical interfaces # keep a map for referencing below when adding physical interfaces
agg_records = {} lag_records = {}
for a in aggregates.keys(): for a in aggregates.keys():
record = model.LAG( record = model.LAG(
name=a, name=a,
# if present, then used
availability=model.AvalabilityStates.USED.name,
router=router_record) router=router_record)
session.add(record) session.add(record)
agg_records[a] = record lag_records[a] = record
# add all the physical interface records # add all the physical interface records
# keep a map for referencing below when adding logical interfaces # keep a map for referencing below when adding logical interfaces
...@@ -52,10 +60,11 @@ def load_router_interfaces(fqdn: str): ...@@ -52,10 +60,11 @@ def load_router_interfaces(fqdn: str):
for physical_name, _ in physical.items(): for physical_name, _ in physical.items():
record = model.PhysicalInterface( record = model.PhysicalInterface(
name=physical_name, name=physical_name,
availability=_interface_availability(physical_name),
router=router_record) router=router_record)
lag_name = _find_lag_name(physical_name) lag_name = _inverted_aggregate_map.get(physical_name, None)
if lag_name: if lag_name:
record.lag = agg_records[lag_name] record.lag = lag_records[lag_name]
physical_records[physical_name] = record physical_records[physical_name] = record
session.add(record) session.add(record)
......
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
import pydantic import pydantic
import sqlalchemy as sa
from resource_management import db from resource_management import db
from resource_management import config from resource_management import config
from resource_management.db import model from resource_management.db import model
...@@ -31,13 +33,21 @@ class NextPhysicalInterface(pydantic.BaseModel): ...@@ -31,13 +33,21 @@ class NextPhysicalInterface(pydantic.BaseModel):
name: str name: str
@router.post('/import/{fqdn}') @router.post('/initialize-router/{fqdn}')
async def load_router_interfaces(fqdn: str) -> InterfacesSummary: async def load_new_router_interfaces(fqdn: str) -> InterfacesSummary:
params = config.load() params = config.load()
db.init_db_model(params['db']) db.init_db_model(params['db'])
router_interfaces.load_router_interfaces(fqdn) with db.session_scope() as session:
num_routers = session.query(sa.func.count(model.Router.fqdn)) \
.filter_by(fqdn=fqdn).scalar()
if num_routers != 0:
raise HTTPException(
status_code=400,
detail=f'router "{fqdn}" already exists')
router_interfaces.load_new_router_interfaces(fqdn)
with db.session_scope() as session: with db.session_scope() as session:
router = session.query(model.Router).filter_by(fqdn=fqdn).one() router = session.query(model.Router).filter_by(fqdn=fqdn).one()
...@@ -55,6 +65,13 @@ async def load_router_interfaces(fqdn: str) -> InterfacesSummary: ...@@ -55,6 +65,13 @@ async def load_router_interfaces(fqdn: str) -> InterfacesSummary:
} }
@router.post('/reconcile-router/{fqdn}')
async def reconcile_current_router_interfaces(fqdn: str):
raise HTTPException(
status_code=501,
detail=f'not implemented')
@router.post('/next-lag/{fqdn}') @router.post('/next-lag/{fqdn}')
async def reserve_next_lag(fqdn: str) -> NextLAG: async def reserve_next_lag(fqdn: str) -> NextLAG:
""" """
......
...@@ -18,14 +18,14 @@ def test_version_request(client): ...@@ -18,14 +18,14 @@ def test_version_request(client):
def test_update_router_interfaces( def test_update_router_interfaces(
client, resources_db, mocked_router, router_name): client, resources_db, mocked_router, router_name):
rv = client.post(f'/api/interfaces/import/{router_name}') rv = client.post(f'/api/interfaces/initialize-router/{router_name}')
assert rv.status_code == 200 assert rv.status_code == 200
jsonschema.validate(rv.json(), interfaces.InterfacesSummary.schema()) jsonschema.validate(rv.json(), interfaces.InterfacesSummary.schema())
def test_next_lag(client, resources_db, mocked_router, router_name): def test_next_lag(client, resources_db, mocked_router, router_name):
router_interfaces.load_router_interfaces(router_name) router_interfaces.load_new_router_interfaces(router_name)
rv = client.post(f'/api/interfaces/next-lag/{router_name}') rv = client.post(f'/api/interfaces/next-lag/{router_name}')
assert rv.status_code == 200 assert rv.status_code == 200
...@@ -34,7 +34,7 @@ def test_next_lag(client, resources_db, mocked_router, router_name): ...@@ -34,7 +34,7 @@ def test_next_lag(client, resources_db, mocked_router, router_name):
def test_next_physical(client, resources_db, mocked_router, router_name): def test_next_physical(client, resources_db, mocked_router, router_name):
router_interfaces.load_router_interfaces(router_name) router_interfaces.load_new_router_interfaces(router_name)
rv = client.post(f'/api/interfaces/next-physical/{router_name}/ae123123') rv = client.post(f'/api/interfaces/next-physical/{router_name}/ae123123')
assert rv.status_code == 200 assert rv.status_code == 200
......
...@@ -83,7 +83,7 @@ def test_load_interfaces( ...@@ -83,7 +83,7 @@ def test_load_interfaces(
new design for this app: no chassis info for now new design for this app: no chassis info for now
""" """
router_interfaces.load_router_interfaces(router_name) router_interfaces.load_new_router_interfaces(router_name)
with db.session_scope() as session: with db.session_scope() as session:
router = session.query(model.Router).filter_by(fqdn=router_name).one() router = session.query(model.Router).filter_by(fqdn=router_name).one()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment