Add status_message column to Actions, Audits and ActionPlans tables

This patch implements the changes in the database required for the
skipped action blueprint.

It just adds a new nullable column to the required tables and add tests
for it.

Note that I am  also introducing a fix in a previous tables tests which
will be affected by the changes in the objects.

Implements: blueprint add-skip-actions

Change-Id: I027bc3861b589bd281a7216583a8c5c351a53c57
Signed-off-by: Alfredo Moralejo <amoralej@redhat.com>
This commit is contained in:
Alfredo Moralejo
2025-08-05 13:36:53 +02:00
parent 1fb89aeac3
commit 84742be8c2
6 changed files with 99 additions and 16 deletions

View File

@@ -0,0 +1,20 @@
"""Add status_message to Audits, ActionPlans and Actions
Revision ID: 7150a7d8f228
Revises: 15f7375ca737
Create Date: 2025-07-03 11:57:05.875500
"""
# revision identifiers, used by Alembic.
revision = '7150a7d8f228'
down_revision = '15f7375ca737'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column('action_plans',
sa.Column('status_message', sa.String(length=255), nullable=True)
)
op.add_column('actions',
sa.Column('status_message', sa.String(length=255), nullable=True)
)
op.add_column('audits',
sa.Column('status_message', sa.String(length=255), nullable=True)
)

View File

@@ -177,6 +177,7 @@ class Audit(Base):
start_time = Column(DateTime, nullable=True)
end_time = Column(DateTime, nullable=True)
force = Column(Boolean, nullable=False)
status_message = Column(String(255), nullable=True)
goal = orm.relationship(Goal, foreign_keys=goal_id, lazy=None)
strategy = orm.relationship(Strategy, foreign_keys=strategy_id, lazy=None)
@@ -197,6 +198,7 @@ class ActionPlan(Base):
state = Column(String(20), nullable=True)
global_efficacy = Column(JSONEncodedList, nullable=True)
hostname = Column(String(255), nullable=True)
status_message = Column(String(255), nullable=True)
audit = orm.relationship(Audit, foreign_keys=audit_id, lazy=None)
strategy = orm.relationship(Strategy, foreign_keys=strategy_id, lazy=None)
@@ -219,6 +221,7 @@ class Action(Base):
input_parameters = Column(JSONEncodedDict, nullable=True)
state = Column(String(20), nullable=True)
parents = Column(JSONEncodedList, nullable=True)
status_message = Column(String(255), nullable=True)
action_plan = orm.relationship(
ActionPlan, foreign_keys=action_plan_id, lazy=None)

View File

@@ -401,3 +401,11 @@ class DbActionTestCase(base.DbTestCase):
self.assertRaises(exception.ActionAlreadyExists,
utils.create_test_action,
id=2, uuid=uuid)
def test_action_status_message(self):
action = utils.create_test_action()
self.assertIsNone(action.status_message)
self.dbapi.update_action(action['id'],
{'status_message': 'test'})
action = self.dbapi.get_action_by_id(self.context, action['id'])
self.assertEqual(action.status_message, 'test')

View File

@@ -389,3 +389,12 @@ class DbActionPlanTestCase(base.DbTestCase):
self.assertRaises(exception.ActionPlanAlreadyExists,
utils.create_test_action_plan,
id=2, uuid=uuid)
def test_action_plan_status_message(self):
action_plan = utils.create_test_action_plan()
self.assertIsNone(action_plan.status_message)
self.dbapi.update_action_plan(action_plan['id'],
{'status_message': 'test'})
action_plan = self.dbapi.get_action_plan_by_id(
self.context, action_plan['id'])
self.assertEqual(action_plan.status_message, 'test')

View File

@@ -442,3 +442,11 @@ class DbAuditTestCase(base.DbTestCase):
utils.create_test_audit,
uuid=w_utils.generate_uuid(),
name='my_audit')
def test_audit_status_message(self):
audit = utils.create_test_audit()
self.assertIsNone(audit.status_message)
self.dbapi.update_audit(audit['id'],
{'status_message': 'test'})
audit = self.dbapi.get_audit_by_id(self.context, audit['id'])
self.assertEqual(audit.status_message, 'test')

View File

@@ -29,6 +29,7 @@ from alembic.script import ScriptDirectory
from oslo_config import cfg
from oslo_db.sqlalchemy import enginefacade
from oslo_db.sqlalchemy import test_fixtures
from oslo_db.sqlalchemy import utils as oslodbutils
from oslo_log import log as logging
import sqlalchemy
@@ -55,7 +56,7 @@ class MySQLDbMigrationsTestCase(test_fixtures.OpportunisticDBTestMixin,
self.engine = enginefacade.writer.get_engine()
self.dbapi = dbapi.get_instance()
self.alembic_config = migration._alembic_config()
self.revisions_tested = set(["15f7375ca737"])
self.revisions_tested = set(["15f7375ca737", "7150a7d8f228"])
def _apply_migration(self, connection, revision):
if revision not in self.revisions_tested:
@@ -113,6 +114,32 @@ class MySQLDbMigrationsTestCase(test_fixtures.OpportunisticDBTestMixin,
class MySQLDbDataMigrationsTestCase(MySQLDbMigrationsTestCase):
def _transform_mutable_fields_to_text(self, obj_values):
transformed = {}
for key, value in obj_values.items():
if type(value) in (dict, list):
transformed[key] = str(value)
else:
transformed[key] = value
return transformed
def _create_manual_action_plan(self, connection, **kwargs):
ap_values = utils.get_test_action_plan(**kwargs)
ap_values = self._transform_mutable_fields_to_text(ap_values)
metadata = sqlalchemy.MetaData()
metadata.reflect(bind=self.engine)
ap_table = sqlalchemy.Table('action_plans', metadata)
with connection.begin():
connection.execute(ap_table.insert(), ap_values)
def _create_manual_audit(self, connection, **kwargs):
audit_values = utils.get_test_audit(**kwargs)
audit_values = self._transform_mutable_fields_to_text(audit_values)
metadata = sqlalchemy.MetaData()
metadata.reflect(bind=self.engine)
audit_table = sqlalchemy.Table('audits', metadata)
with connection.begin():
connection.execute(audit_table.insert(), audit_values)
def _create_manual_efficacy_indicator(self, connection, **kwargs):
eff_ind_values = utils.get_test_efficacy_indicator(**kwargs)
@@ -149,20 +176,22 @@ class MySQLDbDataMigrationsTestCase(MySQLDbMigrationsTestCase):
name="STRATEGY_ID_1", display_name='My Strategy 1')
self.audit_template = utils.create_test_audit_template(
name="Audit Template", id=1, uuid=None)
self.audit = utils.create_test_audit(
self._create_manual_audit(
connection,
audit_template_id=self.audit_template.id, id=1, uuid=None,
name="AUDIT_1")
self.action_plan = utils.create_test_action_plan(
audit_id=self.audit.id, id=1, uuid=None)
self._create_manual_action_plan(
connection,
audit_id=1, id=1, uuid=None)
self._create_manual_efficacy_indicator(
connection,
action_plan_id=self.action_plan.id, id=1, uuid=None,
action_plan_id=1, id=1, uuid=None,
name="efficacy_indicator1", description="Test Indicator 1",
value=1.01234567912345678)
self._create_manual_efficacy_indicator(
connection,
action_plan_id=self.action_plan.id, id=2, uuid=None,
action_plan_id=1, id=2, uuid=None,
name="efficacy_indicator2", description="Test Indicator 2",
value=2.01234567912345678)
@@ -171,7 +200,7 @@ class MySQLDbDataMigrationsTestCase(MySQLDbMigrationsTestCase):
# check that creating a new efficacy_indicator after the migration
# works
utils.create_test_efficacy_indicator(
action_plan_id=self.action_plan.id, id=3, uuid=None,
action_plan_id=1, id=3, uuid=None,
name="efficacy_indicator3", description="Test Indicator 3",
value=0.01234567912345678)
db_efficacy_indicator = self.dbapi.get_efficacy_indicator_by_id(
@@ -183,15 +212,6 @@ class MySQLDbDataMigrationsTestCase(MySQLDbMigrationsTestCase):
self.assertIsNone(self._read_efficacy_indicator(connection, 2)[0])
# check that the existing data is there after the migration
db_goal = self.dbapi.get_goal_by_id(self.context, 1)
self.assertEqual(db_goal.name, "GOAL_1")
db_strategy = self.dbapi.get_strategy_by_id(self.context, 1)
self.assertEqual(db_strategy.name, "STRATEGY_ID_1")
db_audit_template = self.dbapi.get_audit_template_by_id(
self.context, 1)
self.assertEqual(db_audit_template.name, "Audit Template")
db_audit = self.dbapi.get_audit_by_id(self.context, 1)
self.assertEqual(db_audit.name, "AUDIT_1")
db_efficacy_indicator_1 = self.dbapi.get_efficacy_indicator_by_id(
self.context, 1)
self.assertAlmostEqual(db_efficacy_indicator_1.data,
@@ -227,6 +247,21 @@ class MySQLDbDataMigrationsTestCase(MySQLDbMigrationsTestCase):
self.assertAlmostEqual(eff_ind_2_data,
2.00, places=2)
def _check_7150a7d8f228(self, connection):
"""Check new columen status_message have been created."""
self.assertTrue(
oslodbutils.column_exists(
connection, "action_plans", "status_message")
)
self.assertTrue(
oslodbutils.column_exists(
connection, "actions", "status_message")
)
self.assertTrue(
oslodbutils.column_exists(
connection, "audits", "status_message")
)
def test_migration_revisions(self):
with self.engine.connect() as connection:
self.alembic_config.attributes["connection"] = connection