From 346c42840944ffe643bbe49a45ab327f01b5da5d Mon Sep 17 00:00:00 2001 From: cproudlock Date: Thu, 30 Jul 2026 07:10:16 -0400 Subject: [PATCH] scripts: reclassify server 'computer' assets to network_device Servers were imported as computers (a PC type) so they show under PCs, not Network. This one-shot re-points each server's asset in place - assetid is unchanged, so comms/relationships/map/name/location/audit all carry over; only the extension row is swapped (computers -> networkdevices), the asset type is flipped, and the device gets the 'Server' networkdevicetype (created if absent). Identify servers by their computer type name (--type, default 'Server'). Dry-run by default; --commit applies. Run on the target instance. --- scripts/reclassify_servers_to_network.py | 101 +++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 scripts/reclassify_servers_to_network.py diff --git a/scripts/reclassify_servers_to_network.py b/scripts/reclassify_servers_to_network.py new file mode 100644 index 0000000..b33bb8e --- /dev/null +++ b/scripts/reclassify_servers_to_network.py @@ -0,0 +1,101 @@ +"""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 their computer type name (default 'Server'); pass --type to +match a different one. + +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() + parser.add_argument('--type', default='Server', + help="computer type name that holds the servers (default 'Server')") + 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?") + + ctype = ComputerType.query.filter_by(computertype=args.type).first() + if not ctype: + sys.exit("No computer type named %r. Pass --type with the exact name." + % args.type) + + servers = (Computer.query + .filter(Computer.computertypeid == ctype.computertypeid) + .all()) + if not servers: + print("No computers under type %r - nothing to do." % args.type) + return + + ndt = _get_or_create_networkdevicetype('Server') + print("%d server(s) under computer type %r -> network_device / type 'Server':" + % (len(servers), args.type)) + + 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()