Files
shopdb-flask/plugins/computers/migrations/versions/0004_policies.py
Cam Proudlock 7bda8e6d60 Store the policy JSON columns as TEXT for MySQL 5.6
The branch stored scopejson, desiredstate and params as sa.JSON, the only JSON
columns in the product. MySQL 5.6 has no JSON type - it arrived in 5.7 - and the
migration failed there with a bare syntax error near the word JSON.

They are TEXT now, through a JSONText type decorator, so the seventeen call sites
still assign and read dicts. The convention elsewhere is already TEXT:
guides.blocksjson, geenforce.manifestjson.

Spec regenerated: 331 paths, 477 operations across 22 surfaces.
2026-08-28 16:18:34 -04:00

163 lines
7.6 KiB
Python

"""Add Configuration and Business Policy tables (RMM-style policies).
Creates configurationpolicies, configurationpolicyactions, businesspolicies,
and businesspolicyitems. These back the DT-authored policy feature that is gated
by the computers_configpolicies_enabled setting; the tables land regardless so
the switch can be flipped without a schema change, and the downgrade drops all
four for a clean rollback of the whole scope.
Idempotent: each create_table is skipped when the table already exists (e.g. a
test DB built by db.create_all()).
Revision ID: computers0004policies
Revises: computers0003azurefields
"""
from alembic import op
import sqlalchemy as sa
revision = 'computers0004policies'
down_revision = 'computers0003azurefields'
branch_labels = None
depends_on = None
# TEXT rather than sa.JSON on purpose. MySQL 5.6 has no JSON type - it arrived
# in 5.7 - and this migration failed there with a bare syntax error near the
# word JSON. Every other JSON-bearing column in the product is TEXT for the same
# reason (guides.blocksjson, geenforce.manifestjson); the model reads and writes
# dicts through the JSONText type decorator, so nothing above the database
# changes.
def upgrade():
bind = op.get_bind()
insp = sa.inspect(bind)
existing = set(insp.get_table_names())
if 'configurationpolicies' not in existing:
op.create_table(
'configurationpolicies',
sa.Column('configurationpolicyid', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=150), nullable=False),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('scopejson', sa.Text(), nullable=True),
sa.Column('source', sa.String(length=50), nullable=False,
server_default='local'),
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.PrimaryKeyConstraint('configurationpolicyid'),
sa.UniqueConstraint('name', name='uq_configurationpolicy_name'),
)
op.create_index('idx_configpolicy_source', 'configurationpolicies',
['source'])
op.create_index('idx_configpolicy_active', 'configurationpolicies',
['isactive'])
if 'configurationpolicyactions' not in existing:
op.create_table(
'configurationpolicyactions',
sa.Column('configurationpolicyactionid', sa.Integer(),
nullable=False),
sa.Column('configurationpolicyid', sa.Integer(), nullable=False),
sa.Column('action', sa.String(length=100), nullable=False),
sa.Column('mode', sa.String(length=20), nullable=False,
server_default='gate'),
sa.Column('desiredstate', sa.Text(), nullable=True),
sa.Column('params', sa.Text(), nullable=True),
sa.Column('intervalminutes', sa.Integer(), nullable=True),
sa.Column('sortorder', sa.Integer(), nullable=False,
server_default='0'),
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(
['configurationpolicyid'],
['configurationpolicies.configurationpolicyid'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('configurationpolicyactionid'),
sa.UniqueConstraint('configurationpolicyid', 'action',
name='uq_configpolicyaction'),
)
op.create_index('idx_configpolicyaction_policy',
'configurationpolicyactions',
['configurationpolicyid'])
if 'businesspolicies' not in existing:
op.create_table(
'businesspolicies',
sa.Column('businesspolicyid', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=150), nullable=False),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('priority', sa.Integer(), nullable=False,
server_default='100'),
sa.Column('source', sa.String(length=50), nullable=False,
server_default='local'),
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.PrimaryKeyConstraint('businesspolicyid'),
sa.UniqueConstraint('name', name='uq_businesspolicy_name'),
)
op.create_index('idx_businesspolicy_priority', 'businesspolicies',
['priority'])
op.create_index('idx_businesspolicy_active', 'businesspolicies',
['isactive'])
if 'businesspolicyitems' not in existing:
op.create_table(
'businesspolicyitems',
sa.Column('businesspolicyitemid', sa.Integer(), nullable=False),
sa.Column('businesspolicyid', sa.Integer(), nullable=False),
sa.Column('configurationpolicyid', sa.Integer(), nullable=False),
sa.Column('sortorder', sa.Integer(), nullable=False,
server_default='0'),
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(
['businesspolicyid'], ['businesspolicies.businesspolicyid'],
ondelete='CASCADE'),
sa.ForeignKeyConstraint(
['configurationpolicyid'],
['configurationpolicies.configurationpolicyid'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('businesspolicyitemid'),
sa.UniqueConstraint('businesspolicyid', 'configurationpolicyid',
name='uq_businesspolicyitem'),
)
op.create_index('idx_bpitem_business', 'businesspolicyitems',
['businesspolicyid'])
op.create_index('idx_bpitem_config', 'businesspolicyitems',
['configurationpolicyid'])
def downgrade():
bind = op.get_bind()
insp = sa.inspect(bind)
existing = set(insp.get_table_names())
if 'businesspolicyitems' in existing:
op.drop_index('idx_bpitem_config', table_name='businesspolicyitems')
op.drop_index('idx_bpitem_business', table_name='businesspolicyitems')
op.drop_table('businesspolicyitems')
if 'businesspolicies' in existing:
op.drop_index('idx_businesspolicy_active', table_name='businesspolicies')
op.drop_index('idx_businesspolicy_priority', table_name='businesspolicies')
op.drop_table('businesspolicies')
if 'configurationpolicyactions' in existing:
op.drop_index('idx_configpolicyaction_policy',
table_name='configurationpolicyactions')
op.drop_table('configurationpolicyactions')
if 'configurationpolicies' in existing:
op.drop_index('idx_configpolicy_active',
table_name='configurationpolicies')
op.drop_index('idx_configpolicy_source',
table_name='configurationpolicies')
op.drop_table('configurationpolicies')