Declarative subordinate devices + shared-machine check

This commit is contained in:
2026-08-11 11:14:51 -04:00
parent 321d0a3799
commit 5c33b06688
5 changed files with 280 additions and 53 deletions

View File

@@ -728,9 +728,13 @@ class ComputersPlugin(BasePlugin):
ordinary machine link to run.
"""
from shopdb.api import AssetRelationship, RelationshipType, Asset
from .pctypemap import drives_partmarker, PARTMARKER_TYPENAME
from .pctypemap import subordinate_device_for
if not drives_partmarker(pctype) or not comp or not comp.asset:
spec = subordinate_device_for(pctype)
if not spec or not spec.get('partof') or not comp or not comp.asset:
# Only a device that FILES UNDER an operation goes through here.
# A measuring tool is a subordinate device too, but it does not
# share a machine number, so it keeps the simpler path.
return []
pcasset = comp.asset
@@ -744,15 +748,18 @@ class ComputersPlugin(BasePlugin):
try:
from plugins.machines.models import Machine, MachineType
except ImportError:
warnings.append('machines plugin unavailable; part marker skipped')
warnings.append('machines plugin unavailable; {} device skipped'
.format(spec['typename']))
return []
# Reuse this PC's existing marker before minting one, so a re-image
# never leaves a second marker behind for the same physical device.
label = spec['label']
# Reuse this PC's existing device before minting one, so a re-image
# never leaves a second device behind for the same physical unit.
existing = AssetRelationship.query.filter(
AssetRelationship.sourceassetid == pcasset.assetid,
AssetRelationship.relationshiptypeid == controls.relationshiptypeid,
AssetRelationship.label == PARTMARKER_LINK_ORIGIN,
AssetRelationship.label == label,
).all()
reuse = next((rel for rel in existing if rel.isactive), None) \
or (existing[0] if existing else None)
@@ -761,35 +768,36 @@ class ComputersPlugin(BasePlugin):
reuse.isactive = True
markerasset = db.session.get(Asset, reuse.targetassetid)
else:
machinetype = AssetType.query.filter_by(assettype='machine').first()
if not machinetype:
warnings.append('machine asset type missing; part marker '
'skipped')
coretype = AssetType.query.filter_by(
assettype=spec['assettype']).first()
if not coretype:
warnings.append('{} asset type missing; {} skipped'.format(
spec['assettype'], spec['typename']))
return []
markertype = MachineType.query.filter_by(
machinetype=PARTMARKER_TYPENAME).first()
if not markertype:
markertype = MachineType(machinetype=PARTMARKER_TYPENAME,
description='Telesis part marker')
db.session.add(markertype)
devicetype = MachineType.query.filter_by(
machinetype=spec['typename']).first()
if not devicetype:
devicetype = MachineType(machinetype=spec['typename'],
description=spec.get('description'))
db.session.add(devicetype)
db.session.flush()
hostname = comp.hostname
markerasset = Asset(
assetnumber='{}-PARTMARKER'.format(
pcasset.assetnumber or hostname),
name='Part Marker ({})'.format(hostname),
assettypeid=machinetype.assettypeid,
assetnumber='{}-{}'.format(
pcasset.assetnumber or hostname, spec['suffix']),
name='{} ({})'.format(spec['typename'], hostname),
assettypeid=coretype.assettypeid,
statusid=1)
db.session.add(markerasset)
db.session.flush()
db.session.add(Machine(assetid=markerasset.assetid,
machinetypeid=markertype.machinetypeid))
machinetypeid=devicetype.machinetypeid))
db.session.add(AssetRelationship(
sourceassetid=pcasset.assetid,
targetassetid=markerasset.assetid,
relationshiptypeid=controls.relationshiptypeid,
label=PARTMARKER_LINK_ORIGIN,
label=label,
isactive=True))
# One marker per PC: archive any other collector marker link.
@@ -798,14 +806,14 @@ class ComputersPlugin(BasePlugin):
rel.isactive = False
operation = self._link_marker_to_operation(
markerasset, machinenumber, pcasset, warnings)
markerasset, machinenumber, pcasset, label, warnings)
return [{'assetid': markerasset.assetid,
'assetnumber': markerasset.assetnumber,
'operationassetid': operation}]
def _link_marker_to_operation(self, markerasset, machinenumber, pcasset,
warnings):
label, warnings):
"""Make a marker `partof` the operation whose number its PC reports.
Unlike the PC-to-machine link this does NOT contest: an operation can
@@ -852,7 +860,7 @@ class ComputersPlugin(BasePlugin):
links = AssetRelationship.query.filter(
AssetRelationship.sourceassetid == markerasset.assetid,
AssetRelationship.relationshiptypeid == partof.relationshiptypeid,
AssetRelationship.label == PARTMARKER_LINK_ORIGIN,
AssetRelationship.label == label,
).all()
found = None
for rel in links:
@@ -866,7 +874,7 @@ class ComputersPlugin(BasePlugin):
sourceassetid=markerasset.assetid,
targetassetid=operation.assetid,
relationshiptypeid=partof.relationshiptypeid,
label=PARTMARKER_LINK_ORIGIN,
label=label,
isactive=True))
return operation.assetid