Migration tests knew no endpoints head revision, so the parametrized guards raised KeyError. Register it in EXPECTED_HEAD_REVISION. EndpointState declared lastreportedat both index=True and an explicit db.Index over the same column, and the baseline migration named single-column indexes differently from what create_all builds. On a pre-existing table the name-keyed guard could not see the create_all index and added a duplicate, tripping the idempotency guard. Drop the redundant declaration and rename migration indexes to ix_<table>_<column> to match. endpoints was absent from the universal site profile, so the installer would not offer it and prune-schema would drop its tables at provisioning. Add it. The agent design record lived under docs/, which is stripped to the public wiki and normally absent from the tree; a lone file there un-skipped the wiki-publish guards. Move it into the plugin.
97 lines
4.4 KiB
Python
97 lines
4.4 KiB
Python
"""endpoints plugin baseline (real create).
|
|
|
|
A NEW plugin: the core chain never knew about endpointstates or endpointevents,
|
|
so this per-plugin chain is their sole authoritative creator.
|
|
|
|
Emits explicit Alembic ops rather than using the create_plugin_tables helper:
|
|
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 (NoReferencedTableError). Tables inherit the connection's default charset,
|
|
matching how the core chain creates its own.
|
|
"""
|
|
from alembic import op
|
|
|
|
from shopdb.plugins.alembic_template import (
|
|
create_index_if_missing,
|
|
create_table_if_missing,
|
|
)
|
|
import sqlalchemy as sa
|
|
|
|
|
|
# revision identifiers, used by Alembic.
|
|
revision = 'endpoints0001baseline'
|
|
down_revision = None
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade():
|
|
create_table_if_missing(
|
|
'endpointstates',
|
|
sa.Column('endpointstateid', sa.Integer(), nullable=False),
|
|
sa.Column('assetid', sa.Integer(), nullable=False),
|
|
sa.Column('hostname', sa.String(length=100), nullable=True),
|
|
sa.Column('loggedinuser', sa.String(length=100), nullable=True),
|
|
sa.Column('agentversion', sa.String(length=40), nullable=True),
|
|
sa.Column('lastboottime', sa.DateTime(), nullable=True),
|
|
sa.Column('uptimeseconds', sa.BigInteger(), nullable=True),
|
|
sa.Column('idleseconds', sa.BigInteger(), nullable=True),
|
|
sa.Column('cpupercent', sa.Float(), nullable=True),
|
|
sa.Column('memorypercent', sa.Float(), nullable=True),
|
|
sa.Column('servicesjson', sa.Text(length=16777215), nullable=True),
|
|
sa.Column('portsjson', sa.Text(length=16777215), nullable=True),
|
|
sa.Column('interfacesjson', sa.Text(length=16777215), nullable=True),
|
|
sa.Column('scheduledtasksjson', sa.Text(length=16777215),
|
|
nullable=True),
|
|
sa.Column('lastreportedat', sa.DateTime(), nullable=True),
|
|
sa.Column('createdat', sa.DateTime(), nullable=False),
|
|
sa.ForeignKeyConstraint(['assetid'], ['assets.assetid'],
|
|
ondelete='CASCADE'),
|
|
sa.PrimaryKeyConstraint('endpointstateid'),
|
|
sa.UniqueConstraint('assetid'),
|
|
)
|
|
create_index_if_missing('ix_endpointstates_assetid',
|
|
'endpointstates', ['assetid'])
|
|
create_index_if_missing('ix_endpointstates_lastreportedat',
|
|
'endpointstates', ['lastreportedat'])
|
|
|
|
create_table_if_missing(
|
|
'endpointevents',
|
|
sa.Column('endpointeventid', sa.Integer(), nullable=False),
|
|
sa.Column('assetid', sa.Integer(), nullable=False),
|
|
sa.Column('eventid', sa.Integer(), nullable=False),
|
|
sa.Column('eventchannel', sa.String(length=50), nullable=True),
|
|
sa.Column('eventsource', sa.String(length=255), nullable=True),
|
|
sa.Column('eventtime', sa.DateTime(), nullable=True),
|
|
sa.Column('eventmessage', sa.Text(), nullable=True),
|
|
sa.Column('payloadjson', sa.Text(length=16777215), nullable=True),
|
|
sa.Column('recordedat', sa.DateTime(), nullable=False),
|
|
sa.ForeignKeyConstraint(['assetid'], ['assets.assetid'],
|
|
ondelete='CASCADE'),
|
|
sa.PrimaryKeyConstraint('endpointeventid'),
|
|
)
|
|
create_index_if_missing('ix_endpointevents_assetid', 'endpointevents',
|
|
['assetid'])
|
|
create_index_if_missing('ix_endpointevents_eventid', 'endpointevents',
|
|
['eventid'])
|
|
create_index_if_missing('ix_endpointevents_eventtime', 'endpointevents',
|
|
['eventtime'])
|
|
# Alerting/history reads by "this endpoint's events over time", so the
|
|
# composite is the index that actually gets used.
|
|
create_index_if_missing('idx_endpointevents_assetevent', 'endpointevents',
|
|
['assetid', 'eventtime'])
|
|
|
|
|
|
def downgrade():
|
|
op.drop_index('idx_endpointevents_assetevent',
|
|
table_name='endpointevents')
|
|
op.drop_index('ix_endpointevents_eventtime', table_name='endpointevents')
|
|
op.drop_index('ix_endpointevents_eventid', table_name='endpointevents')
|
|
op.drop_index('ix_endpointevents_assetid', table_name='endpointevents')
|
|
op.drop_table('endpointevents')
|
|
|
|
op.drop_index('ix_endpointstates_lastreportedat',
|
|
table_name='endpointstates')
|
|
op.drop_index('ix_endpointstates_assetid', table_name='endpointstates')
|
|
op.drop_table('endpointstates')
|