reports: pc-relationships matches PC<->machine links in either direction
Prod had 331 relationships, 268 computers, 204 machines, but the report came back empty. The query only matched computer(source) -> machine(target), while the import stores the general machinerelationships as machine(source) -> PC(target) (only the synthetic measuring-tool links are PC -> tool). So the real shop-floor edges never matched. Make the query direction-agnostic (UNION of both orientations); a PC-runs-machine report is conceptually undirected. Also drop the comtypeid=1 filter so the IP is taken from the primary communication regardless of its type. Test: a machine(source) -> PC(target) edge now appears in the report.
This commit is contained in:
@@ -467,9 +467,14 @@ def pc_relationships():
|
|||||||
Query parameters:
|
Query parameters:
|
||||||
- format: 'json' (default) or 'csv'
|
- format: 'json' (default) or 'csv'
|
||||||
"""
|
"""
|
||||||
# Asset relationships where a computer (source) relates to a machine
|
# PC <-> machine relationships in EITHER direction. The import orients edges
|
||||||
# (target) - the asset-model equivalent of the legacy PC->machine links.
|
# both ways: the general machinerelationships migration stores machine(source)
|
||||||
sql = db.text("""
|
# -> PC(target), while the synthetic measuring-tool links store PC(source) ->
|
||||||
|
# tool(target). Match both so the report is not empty just because of edge
|
||||||
|
# direction (this is a conceptually undirected "PC runs machine" report).
|
||||||
|
# Each half joins a computer on one end and a machine on the other; the
|
||||||
|
# machine end supplies machine_number/vendor/model, the PC end hostname/ip.
|
||||||
|
half = """
|
||||||
SELECT
|
SELECT
|
||||||
eq.assetnumber AS machine_number,
|
eq.assetnumber AS machine_number,
|
||||||
v.vendor AS vendor,
|
v.vendor AS vendor,
|
||||||
@@ -477,17 +482,22 @@ def pc_relationships():
|
|||||||
COALESCE(cpc.hostname, pc.assetnumber) AS hostname,
|
COALESCE(cpc.hostname, pc.assetnumber) AS hostname,
|
||||||
c.ipaddress AS ip
|
c.ipaddress AS ip
|
||||||
FROM assetrelationships ar
|
FROM assetrelationships ar
|
||||||
JOIN assets pc ON ar.sourceassetid = pc.assetid
|
JOIN computers cpc ON cpc.assetid = ar.{pc_end}
|
||||||
JOIN computers cpc ON cpc.assetid = pc.assetid
|
JOIN assets pc ON pc.assetid = ar.{pc_end}
|
||||||
JOIN assets eq ON ar.targetassetid = eq.assetid
|
JOIN machines eqx ON eqx.assetid = ar.{machine_end}
|
||||||
JOIN machines eqx ON eqx.assetid = eq.assetid
|
JOIN assets eq ON eq.assetid = ar.{machine_end}
|
||||||
LEFT JOIN communications c ON c.assetid = pc.assetid AND c.isprimary = 1 AND c.comtypeid = 1
|
LEFT JOIN communications c ON c.assetid = pc.assetid AND c.isprimary = 1
|
||||||
LEFT JOIN models mo ON eqx.modelnumberid = mo.modelnumberid
|
LEFT JOIN models mo ON eqx.modelnumberid = mo.modelnumberid
|
||||||
LEFT JOIN vendors v ON mo.vendorid = v.vendorid
|
LEFT JOIN vendors v ON mo.vendorid = v.vendorid
|
||||||
WHERE ar.isactive = 1
|
WHERE ar.isactive = 1
|
||||||
AND eq.assetnumber IS NOT NULL AND eq.assetnumber != ''
|
AND eq.assetnumber IS NOT NULL AND eq.assetnumber != ''
|
||||||
ORDER BY eq.assetnumber
|
"""
|
||||||
""")
|
sql = db.text(
|
||||||
|
half.format(pc_end='sourceassetid', machine_end='targetassetid')
|
||||||
|
+ ' UNION '
|
||||||
|
+ half.format(pc_end='targetassetid', machine_end='sourceassetid')
|
||||||
|
+ ' ORDER BY machine_number'
|
||||||
|
)
|
||||||
|
|
||||||
results = db.session.execute(sql).fetchall()
|
results = db.session.execute(sql).fetchall()
|
||||||
data = [{
|
data = [{
|
||||||
|
|||||||
50
tests/test_core/test_pc_relationships.py
Normal file
50
tests/test_core/test_pc_relationships.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
"""Regression: /api/reports/pc-relationships must return PC<->machine links
|
||||||
|
regardless of edge direction.
|
||||||
|
|
||||||
|
The import stores the general machinerelationships as machine(source) ->
|
||||||
|
PC(target); an earlier query only matched PC(source) -> machine(target), so on
|
||||||
|
prod (331 relationships) the report came back empty. The query is now
|
||||||
|
direction-agnostic.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def _asset(db, assettype_name, plugin, table, assetnumber):
|
||||||
|
from shopdb.core.models import AssetType, Asset
|
||||||
|
at = AssetType.query.filter_by(assettype=assettype_name).first()
|
||||||
|
if not at:
|
||||||
|
at = AssetType(assettype=assettype_name, pluginname=plugin, tablename=table)
|
||||||
|
db.session.add(at)
|
||||||
|
db.session.flush()
|
||||||
|
asset = Asset(assettypeid=at.assettypeid, assetnumber=assetnumber)
|
||||||
|
db.session.add(asset)
|
||||||
|
db.session.flush()
|
||||||
|
return asset
|
||||||
|
|
||||||
|
|
||||||
|
def test_pc_relationships_matches_machine_to_pc_direction(client, db, auth_headers):
|
||||||
|
from shopdb.core.models import AssetRelationship, RelationshipType
|
||||||
|
from plugins.computers.models import Computer
|
||||||
|
from plugins.machines.models import Machine
|
||||||
|
|
||||||
|
pc_asset = _asset(db, 'computer', 'computers', 'computers', 'TESTPC01')
|
||||||
|
eq_asset = _asset(db, 'machine', 'machines', 'machines', '4242')
|
||||||
|
db.session.add(Computer(assetid=pc_asset.assetid, hostname='testpc01'))
|
||||||
|
db.session.add(Machine(assetid=eq_asset.assetid))
|
||||||
|
|
||||||
|
rt = RelationshipType.query.filter_by(relationshiptype='controls').first()
|
||||||
|
if not rt:
|
||||||
|
rt = RelationshipType(relationshiptype='controls')
|
||||||
|
db.session.add(rt)
|
||||||
|
db.session.flush()
|
||||||
|
|
||||||
|
# REVERSE of the old-only direction: machine is the source, PC the target.
|
||||||
|
db.session.add(AssetRelationship(
|
||||||
|
sourceassetid=eq_asset.assetid, targetassetid=pc_asset.assetid,
|
||||||
|
relationshiptypeid=rt.relationshiptypeid, isactive=True))
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
resp = client.get('/api/reports/pc-relationships', headers=auth_headers)
|
||||||
|
assert resp.status_code == 200
|
||||||
|
rows = resp.get_json()['data']['data']
|
||||||
|
assert any(r['machine_number'] == '4242' and r['hostname'] == 'testpc01'
|
||||||
|
for r in rows), rows
|
||||||
Reference in New Issue
Block a user