Files
shopdb-flask/scripts/reclassify_servers_to_network.py

115 lines
4.7 KiB
Python

"""Reclassify server 'computer' assets into 'network_device' assets.
Servers were imported as computers (a PC type), so they show under PCs instead
of Network. This re-points each server's asset in place - the assetid does NOT
change, so its communications, relationships, map position, name, location, and
audit history all carry over. Only the extension row is swapped (computers ->
networkdevices) and the asset's type is flipped, and the network device is given
the 'Server' networkdevicetype.
Identify servers by a name/hostname prefix (default 'SVR-'), or pass --type to
match an exact computer type instead.
Usage (on the target instance, in the app dir):
DATABASE_URL=... venv/bin/python scripts/reclassify_servers_to_network.py # dry run
DATABASE_URL=... venv/bin/python scripts/reclassify_servers_to_network.py --commit # apply
... --type "Server" --commit
"""
import argparse
import os
import sys
# Run from anywhere: put the repo root (parent of scripts/) on the path.
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from shopdb import create_app
from shopdb.api import db
from shopdb.core.models import Asset, AssetType
from plugins.computers.models import Computer, ComputerType
from plugins.network.models import NetworkDevice, NetworkDeviceType
def _get_or_create_networkdevicetype(name):
ndt = NetworkDeviceType.query.filter_by(networkdevicetype=name).first()
if not ndt:
ndt = NetworkDeviceType(networkdevicetype=name,
description='Server (reclassified from PCs)')
db.session.add(ndt)
db.session.flush()
return ndt
def main():
parser = argparse.ArgumentParser(description=__doc__)
group = parser.add_mutually_exclusive_group()
group.add_argument('--prefix', default='SVR-',
help="match servers by name/assetnumber/hostname starting "
"with this (default 'SVR-')")
group.add_argument('--type',
help="instead of --prefix, match by an exact computer type name")
parser.add_argument('--commit', action='store_true',
help='apply the change; without it this is a dry run')
args = parser.parse_args()
app = create_app()
with app.app_context():
nd_assettype = AssetType.query.filter_by(assettype='network_device').first()
if not nd_assettype:
sys.exit("No 'network_device' asset type - is the network plugin installed?")
query = Computer.query.join(Asset)
if args.type:
ctype = ComputerType.query.filter_by(computertype=args.type).first()
if not ctype:
sys.exit("No computer type named %r." % args.type)
query = query.filter(Computer.computertypeid == ctype.computertypeid)
criterion = "computer type %r" % args.type
else:
like = args.prefix + '%'
query = query.filter(db.or_(
Asset.assetnumber.like(like),
Asset.name.like(like),
Computer.hostname.like(like),
))
criterion = "name/hostname prefix %r" % args.prefix
servers = query.all()
if not servers:
print("No computers match %s - nothing to do." % criterion)
return
ndt = _get_or_create_networkdevicetype('Server')
print("%d server(s) matching %s -> network_device / type 'Server':"
% (len(servers), criterion))
moved = 0
for computer in servers:
asset = computer.asset
if not asset:
continue
label = asset.name or asset.assetnumber or ('asset %d' % asset.assetid)
print(" - %s (assetid %d)" % (label, asset.assetid))
if args.commit:
# Swap extension: create the network device on the SAME asset,
# re-point the asset's type, then drop the computer extension.
asset.assettypeid = nd_assettype.assettypeid
db.session.add(NetworkDevice(
assetid=asset.assetid,
networkdevicetypeid=ndt.networkdevicetypeid,
hostname=getattr(computer, 'hostname', None),
vendorid=getattr(computer, 'vendorid', None),
))
db.session.delete(computer) # asset stays (FK cascade is asset->computer)
moved += 1
if args.commit:
db.session.commit()
print("\nDone: %d reclassified. They now appear under Network." % moved)
else:
print("\nDRY RUN - nothing changed. Re-run with --commit to apply.")
if __name__ == '__main__':
main()