"""Endpoint monitor definitions (the reusable monitor catalog). A monitor definition is the "what": a named process or service the agent should watch, with a bespoke display label separate from the raw OS name, plus optional launch and collector paths. Definitions are the noun that a configuration policy action points at; attaching a monitor to a PC type is a policy concern, not a property of the definition itself. Two sources: shipped Internal apps we ship (eDNC, MTConnect, UDC). Seeded by migration. Read-only in the UI: name and identity are fixed by the product. local User-defined monitors built on the Settings page. A definition is watched on an endpoint when a site policy in effect for that endpoint's PC type includes a monitor action pointing at it. """ from datetime import datetime from shopdb.api import db def _utciso(value): """Naive-UTC datetime -> ISO string marked UTC, or None.""" return value.isoformat() + 'Z' if value else None class EndpointMonitor(db.Model): """One reusable process or service monitor definition.""" __tablename__ = 'endpointmonitors' endpointmonitorid = db.Column(db.Integer, primary_key=True) # 'process' or 'service'. Decides which identity column is authoritative and # which start/stop/status actions the row exposes. kind = db.Column(db.String(16), nullable=False) # The bespoke label operators see (e.g. 'MTConnect'). Distinct from the raw # OS name because agent.exe is not obviously MTConnect. displayname = db.Column(db.String(128), nullable=False) # OS identity. For a process monitor, processname is the executable the agent # matches (e.g. 'agent.exe'); for a service monitor, servicename is the # Windows service name (e.g. 'MTConnect UDC Agent'). Exactly one is the # authoritative identity for a given kind; the other stays null. processname = db.Column(db.String(255), nullable=True) servicename = db.Column(db.String(255), nullable=True) # Optional paths supplied per monitor. launchpath starts the app; the # collector paths point the agent at where the app writes data and logs. launchpath = db.Column(db.String(512), nullable=True) datacollectorpath = db.Column(db.String(512), nullable=True) logcollectorpath = db.Column(db.String(512), nullable=True) # 'shipped' (product-owned, seeded) or 'local' (user-built). Shipped rows are # not editable or deletable through the CRUD API. source = db.Column(db.String(16), nullable=False, default='local') # Soft on/off so a monitor can be retired without losing policy references. isactive = db.Column(db.Boolean, nullable=False, default=True) createdat = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) __table_args__ = ( db.UniqueConstraint('kind', 'displayname', name='uq_endpointmonitors_kinddisplay'), db.Index('idx_endpointmonitors_source', 'source'), ) def __repr__(self): return f"" def to_dict(self): return { 'endpointmonitorid': self.endpointmonitorid, 'kind': self.kind, 'displayname': self.displayname, 'processname': self.processname, 'servicename': self.servicename, 'launchpath': self.launchpath, 'datacollectorpath': self.datacollectorpath, 'logcollectorpath': self.logcollectorpath, 'source': self.source, 'isactive': self.isactive, 'createdat': _utciso(self.createdat), }