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
This database holds information about router port resources
"""
import enum
import logging
from typing import Any
from sqlalchemy import Column, ForeignKey, Integer, String
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
......@@ -18,10 +19,16 @@ logger = logging.getLogger(__name__)
base_schema: Any = declarative_base()
class AvalabilityStates(enum.Enum):
AVAILABLE = enum.auto()
USED = enum.auto()
RESERVED = enum.auto()
class Router(base_schema):
__tablename__ = 'routers'
id = Column('id', Integer, primary_key=True)
fqdn = Column('fqdn', String, nullable=False)
id = sa.Column('id', sa.Integer, primary_key=True)
fqdn = sa.Column('fqdn', sa.String, nullable=False)
physical = relationship(
"PhysicalInterface",
......@@ -36,13 +43,18 @@ class Router(base_schema):
class LAG(base_schema):
__tablename__ = 'lags'
id = Column('id', Integer, primary_key=True)
name = Column('name', String, nullable=False)
id = sa.Column('id', sa.Integer, primary_key=True)
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',
Integer,
ForeignKey('routers.id'),
sa.Integer,
sa.ForeignKey('routers.id'),
nullable=False)
router = relationship('Router', back_populates='lags')
......@@ -54,20 +66,25 @@ class LAG(base_schema):
class PhysicalInterface(base_schema):
__tablename__ = 'physical_interfaces'
id = Column('id', Integer, primary_key=True)
name = Column('name', String, nullable=False)
id = sa.Column('id', sa.Integer, primary_key=True)
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',
Integer,
ForeignKey('routers.id'),
sa.Integer,
sa.ForeignKey('routers.id'),
nullable=False)
router = relationship('Router', back_populates='physical')
lag_id = Column(
lag_id = sa.Column(
'lag_id',
Integer,
ForeignKey('lags.id'),
sa.Integer,
sa.ForeignKey('lags.id'),
nullable=True)
lag = relationship('LAG', back_populates='physical')
......@@ -79,11 +96,11 @@ class PhysicalInterface(base_schema):
class LogicalInterface(base_schema):
__tablename__ = 'logical_interfaces'
id = Column('id', Integer, primary_key=True)
name = Column('name', String, nullable=False)
physical_id = Column(
id = sa.Column('id', sa.Integer, primary_key=True)
name = sa.Column('name', sa.String, nullable=False)
physical_id = sa.Column(
'physical_id',
Integer,
ForeignKey('physical_interfaces.id'),
sa.Integer,
sa.ForeignKey('physical_interfaces.id'),
nullable=False)
physical = relationship('PhysicalInterface', back_populates='logical')
......@@ -6,12 +6,10 @@ from resource_management.db import model
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
update the db with the current information
TODO: merge, not just create new
"""
params = config.load()
......@@ -25,11 +23,19 @@ def load_router_interfaces(fqdn: str):
physical = juniper.load_installed_ethernet_ports(dev)
logical = juniper.load_logical_interfaces(dev)
def _find_lag_name(interface_name):
for name, interfaces in aggregates.items():
if interface_name in interfaces:
return name
return None
_inverted_aggregate_map = {}
for lag_name, physical_interfaces in aggregates.items():
for pn in physical_interfaces:
_inverted_aggregate_map[pn] = lag_name
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:
......@@ -38,13 +44,15 @@ def load_router_interfaces(fqdn: str):
# add all the lag records
# keep a map for referencing below when adding physical interfaces
agg_records = {}
lag_records = {}
for a in aggregates.keys():
record = model.LAG(
name=a,
# if present, then used
availability=model.AvalabilityStates.USED.name,
router=router_record)
session.add(record)
agg_records[a] = record
lag_records[a] = record
# add all the physical interface records
# keep a map for referencing below when adding logical interfaces
......@@ -52,10 +60,11 @@ def load_router_interfaces(fqdn: str):
for physical_name, _ in physical.items():
record = model.PhysicalInterface(
name=physical_name,
availability=_interface_availability(physical_name),
router=router_record)
lag_name = _find_lag_name(physical_name)
lag_name = _inverted_aggregate_map.get(physical_name, None)
if lag_name:
record.lag = agg_records[lag_name]
record.lag = lag_records[lag_name]
physical_records[physical_name] = record
session.add(record)
......
from fastapi import APIRouter, HTTPException
import pydantic
import sqlalchemy as sa
from resource_management import db
from resource_management import config
from resource_management.db import model
......@@ -31,13 +33,21 @@ class NextPhysicalInterface(pydantic.BaseModel):
name: str
@router.post('/import/{fqdn}')
async def load_router_interfaces(fqdn: str) -> InterfacesSummary:
@router.post('/initialize-router/{fqdn}')
async def load_new_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:
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:
router = session.query(model.Router).filter_by(fqdn=fqdn).one()
......@@ -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}')
async def reserve_next_lag(fqdn: str) -> NextLAG:
"""
......
......@@ -18,14 +18,14 @@ def test_version_request(client):
def test_update_router_interfaces(
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
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)
router_interfaces.load_new_router_interfaces(router_name)
rv = client.post(f'/api/interfaces/next-lag/{router_name}')
assert rv.status_code == 200
......@@ -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):
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')
assert rv.status_code == 200
......
......@@ -83,7 +83,7 @@ def test_load_interfaces(
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:
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