Security hardening, multi-site portability, and a documentation and API-surface sweep
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
"""Asset-number prefix per network device type.
|
||||
|
||||
Every network device already follows one convention, applied by hand:
|
||||
AP-<name>, SW-<name>, SVR-<name>, IDF-<name>. 45 records, no exceptions. This
|
||||
stores the prefix on the type so the create path can generate the asset number
|
||||
instead of asking someone to retype the same value twice.
|
||||
|
||||
Nullable: a type with no prefix generates the bare name. Nobody has to invent
|
||||
one for a type that does not want it.
|
||||
|
||||
It deliberately is NOT derived from the type name - 'Access Point' and 'Access
|
||||
Panel' both initialise to AP, and assetnumber is unique, so the second type
|
||||
would collide with the first on every device it created.
|
||||
|
||||
Backfilled for the four types already in use so existing conventions carry
|
||||
forward. A site whose types are named differently gets NULL and generates bare
|
||||
names, which is correct rather than wrong.
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'network0003prefix'
|
||||
down_revision = 'network0002model'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
# type name -> prefix, from what the existing records already use
|
||||
SEEDPREFIXES = {
|
||||
'Access Point': 'AP',
|
||||
'Switch': 'SW',
|
||||
'Server': 'SVR',
|
||||
'IDF': 'IDF',
|
||||
}
|
||||
|
||||
|
||||
def upgrade():
|
||||
# Guarded like network0002model: on a FRESH database the table is built from
|
||||
# the SQLAlchemy models, which already declare this column, so an
|
||||
# unconditional add fails with "duplicate column name".
|
||||
bind = op.get_bind()
|
||||
insp = sa.inspect(bind)
|
||||
if 'networkdevicetypes' not in insp.get_table_names():
|
||||
return
|
||||
cols = {c['name'] for c in insp.get_columns('networkdevicetypes')}
|
||||
if 'prefix' not in cols:
|
||||
op.add_column('networkdevicetypes',
|
||||
sa.Column('prefix', sa.String(length=12), nullable=True))
|
||||
|
||||
# Backfill only where the type exists and has no prefix yet, so a re-run and
|
||||
# a site that already set its own are both left alone.
|
||||
for typename, prefix in SEEDPREFIXES.items():
|
||||
bind.execute(
|
||||
sa.text('UPDATE networkdevicetypes SET prefix = :prefix '
|
||||
'WHERE networkdevicetype = :typename '
|
||||
'AND (prefix IS NULL OR prefix = :empty)'),
|
||||
{'prefix': prefix, 'typename': typename, 'empty': ''})
|
||||
|
||||
|
||||
def downgrade():
|
||||
bind = op.get_bind()
|
||||
insp = sa.inspect(bind)
|
||||
if 'networkdevicetypes' not in insp.get_table_names():
|
||||
return
|
||||
cols = {c['name'] for c in insp.get_columns('networkdevicetypes')}
|
||||
if 'prefix' in cols:
|
||||
op.drop_column('networkdevicetypes', 'prefix')
|
||||
Reference in New Issue
Block a user