computers: a part marker is its own asset, under the operation it serves
Several Telesis markers serve one operation number - 0613, 0615 and WJPRT each have more than one - so treating the operation as the marker collapsed separate devices into a single record. Their configurations differ by COM port, so in the backup history they overwrote each other, and no question about an individual marker could be asked at all: how many there are, which port one is on, which one failed. There is one marker per PC, which makes the PC the marker's identity, so the collector can mint the marker the same way it already mints a CMM or a Keyence unit for a metrology PC. A marker PC now gets a Part Marker machine asset, the PC controls it, and the marker is partof the operation whose number the PC reports. An operation holds any number of markers. A marker PC therefore does not claim the operation directly. controls propagates through partof, which reference-data already seeds, so control of the operation still follows from controlling its marker - without two markers contesting a link only one of them can hold. Backups from a marker PC resolve to the marker rather than the operation, and fall back to the machine number whenever the marker cannot be resolved: no hostname on the payload, a lean build without the computers or machines plugin, or a marker PC that has not reported to the computers collector yet. Filing under the operation is the old behaviour and beats rejecting a backup. Moving a marker to another operation archives the old membership rather than deleting it, so where a marker used to live stays answerable.
This commit is contained in:
@@ -52,6 +52,52 @@ def byteshash(raw):
|
||||
return hashlib.sha256(raw).hexdigest()
|
||||
|
||||
|
||||
def markerforsource(sourcehostname):
|
||||
"""Asset id of the part marker the reporting PC drives, or None.
|
||||
|
||||
A part-marker PC's config describes ITS marker, not the operation the
|
||||
marker serves. Several markers can serve one operation - 0613, 0615 and
|
||||
WJPRT each do - so filing by machine number put several devices' configs in
|
||||
one history where they overwrote each other. The computers collector gives
|
||||
each marker PC a marker asset (`collector:partmarker`), and that is what a
|
||||
backup from that PC belongs to.
|
||||
|
||||
Falls through to None, and so to the machine number, whenever anything is
|
||||
missing: no hostname, no computers or machines plugin on a lean build
|
||||
(ADR-014), or a marker PC that has not reported to the computers collector
|
||||
yet. Filing under the operation is the old behaviour and still better than
|
||||
rejecting the backup.
|
||||
"""
|
||||
from shopdb.api import db, AssetRelationship, RelationshipType
|
||||
|
||||
hostname = (sourcehostname or '').strip()
|
||||
if not hostname:
|
||||
return None
|
||||
try:
|
||||
from plugins.computers.models import Computer
|
||||
from plugins.computers.plugin import PARTMARKER_LINK_ORIGIN
|
||||
except ImportError:
|
||||
return None
|
||||
|
||||
computer = Computer.query.filter(Computer.hostname.ilike(hostname)).first()
|
||||
if computer is None or not computer.assetid:
|
||||
return None
|
||||
|
||||
controls = RelationshipType.query.filter_by(
|
||||
relationshiptype='controls').first()
|
||||
if controls is None:
|
||||
return None
|
||||
|
||||
link = (db.session.query(AssetRelationship)
|
||||
.filter(AssetRelationship.sourceassetid == computer.assetid,
|
||||
AssetRelationship.relationshiptypeid ==
|
||||
controls.relationshiptypeid,
|
||||
AssetRelationship.label == PARTMARKER_LINK_ORIGIN,
|
||||
AssetRelationship.isactive.is_(True))
|
||||
.first())
|
||||
return link.targetassetid if link else None
|
||||
|
||||
|
||||
class BackupKind:
|
||||
"""Base class. Subclasses override what applies to them."""
|
||||
|
||||
@@ -198,6 +244,10 @@ class NtlarsKind(BackupKind):
|
||||
def resolveassetid(self, payload):
|
||||
from shopdb.api import db, Asset
|
||||
|
||||
marker = markerforsource(payload.get('sourcehostname'))
|
||||
if marker is not None:
|
||||
return marker, None
|
||||
|
||||
machinenumber = (payload.get('machinenumber') or '').strip()
|
||||
if not machinenumber:
|
||||
return None, 'no machinenumber in payload'
|
||||
@@ -229,6 +279,10 @@ class PartMarkerKind(BackupKind):
|
||||
def resolveassetid(self, payload):
|
||||
from shopdb.api import db, Asset
|
||||
|
||||
marker = markerforsource(payload.get('sourcehostname'))
|
||||
if marker is not None:
|
||||
return marker, None
|
||||
|
||||
identifier = (payload.get('machinenumber')
|
||||
or payload.get('assetnumber') or '').strip()
|
||||
if not identifier:
|
||||
|
||||
Reference in New Issue
Block a user