Assign printers to a MACHINE and let whichever PC controls it install them, with the observed half kept strictly apart from the assigned half: a collector report can never write an assignment row. Adoption is explicit. Adds a singular relationship type so defaultprinter can mean exactly one, client scripts that converge a bay's queues and correct a drifted one in place, and a wave gate so a fleet-wide driver rollout cannot stampede its own share. On the container side: the compose stack never persisted the instance directory, so a rebuild discarded plugins.json and every upload. It is a volume now, the image ships instance/ owned by the app user so the mountpoint is writable, and the database moves to MySQL 8.4 LTS, which the Windows runbook has recommended since 8.0 went end of life. The image also could not build at all: the frontend stage never copied the plugin staging script it runs. Adds a topology migration guide covering IIS to Docker and back.
86 lines
3.8 KiB
Python
86 lines
3.8 KiB
Python
"""printers: printerobservedqueues table (what a bay reported it HAS).
|
|
|
|
ShopDB already knows what a bay SHOULD have (usesprinter/defaultprinter rows on
|
|
the machine). This table holds the other half: the queues a PC reported through
|
|
POST /api/collector/printers. Observed and assigned stay in separate tables on
|
|
purpose, so observed drift can never be mistaken for desired state.
|
|
|
|
One row per observed queue; the latest report for a host replaces all of that
|
|
host's rows. The unique index on (hostname, queuename) is the guard that turns a
|
|
half-finished replace into an IntegrityError instead of duplicate queues.
|
|
|
|
Explicit ops rather than create_plugin_tables: the helper builds a per-plugin
|
|
MetaData filtered to the plugin's own tables, so the foreign key to the core
|
|
assets table cannot resolve at CreateTable-compile time. Same reason the backups
|
|
baseline spells its ops out.
|
|
|
|
Guarded both ways, so a re-run (or a database where db.create_all already built
|
|
the table) is a no-op.
|
|
|
|
Revision ID: printers0005observedqueues
|
|
Revises: printers0004drivervendor
|
|
"""
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
|
|
|
|
# revision identifiers, used by Alembic.
|
|
revision = 'printers0005observedqueues'
|
|
down_revision = 'printers0004drivervendor'
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade():
|
|
bind = op.get_bind()
|
|
inspector = sa.inspect(bind)
|
|
if 'printerobservedqueues' in inspector.get_table_names():
|
|
return
|
|
op.create_table(
|
|
'printerobservedqueues',
|
|
sa.Column('printerobservedqueueid', sa.Integer(), nullable=False),
|
|
# Nullable and no index of its own beyond the explicit one below: an
|
|
# unenrolled bay still gets to report, and hostname is what identifies
|
|
# the report.
|
|
sa.Column('assetid', sa.Integer(), nullable=True),
|
|
sa.Column('hostname', sa.String(length=255), nullable=False),
|
|
sa.Column('queuename', sa.String(length=255), nullable=False),
|
|
sa.Column('drivername', sa.String(length=255), nullable=True),
|
|
sa.Column('portname', sa.String(length=255), nullable=True),
|
|
sa.Column('portaddress', sa.String(length=255), nullable=True),
|
|
sa.Column('isdefault', sa.Boolean(), nullable=False,
|
|
server_default=sa.false()),
|
|
sa.Column('isshared', sa.Boolean(), nullable=False,
|
|
server_default=sa.false()),
|
|
sa.Column('observedat', sa.DateTime(), nullable=False),
|
|
sa.Column('createddate', sa.DateTime(), nullable=False),
|
|
sa.Column('modifieddate', sa.DateTime(), nullable=False),
|
|
sa.Column('isactive', sa.Boolean(), nullable=False,
|
|
server_default=sa.true()),
|
|
sa.ForeignKeyConstraint(['assetid'], ['assets.assetid'],
|
|
ondelete='CASCADE'),
|
|
sa.PrimaryKeyConstraint('printerobservedqueueid'),
|
|
# Doubles as the read index for the hostname filter (leftmost column),
|
|
# so no separate hostname index is created.
|
|
sa.UniqueConstraint('hostname', 'queuename',
|
|
name='uq_printerobservedqueue_host_queue'),
|
|
)
|
|
# Port address is the primary match key from an observed queue back to a
|
|
# printer asset, so every comparison read hits it.
|
|
op.create_index('idx_printerobservedqueues_portaddress',
|
|
'printerobservedqueues', ['portaddress'])
|
|
op.create_index('idx_printerobservedqueues_assetid',
|
|
'printerobservedqueues', ['assetid'])
|
|
|
|
|
|
def downgrade():
|
|
bind = op.get_bind()
|
|
inspector = sa.inspect(bind)
|
|
if 'printerobservedqueues' not in inspector.get_table_names():
|
|
return
|
|
op.drop_index('idx_printerobservedqueues_assetid',
|
|
table_name='printerobservedqueues')
|
|
op.drop_index('idx_printerobservedqueues_portaddress',
|
|
table_name='printerobservedqueues')
|
|
op.drop_table('printerobservedqueues')
|