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:
@@ -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)
|
||||||
|
)
|
||||||
@@ -177,6 +177,7 @@ class Audit(Base):
|
|||||||
start_time = Column(DateTime, nullable=True)
|
start_time = Column(DateTime, nullable=True)
|
||||||
end_time = Column(DateTime, nullable=True)
|
end_time = Column(DateTime, nullable=True)
|
||||||
force = Column(Boolean, nullable=False)
|
force = Column(Boolean, nullable=False)
|
||||||
|
status_message = Column(String(255), nullable=True)
|
||||||
|
|
||||||
goal = orm.relationship(Goal, foreign_keys=goal_id, lazy=None)
|
goal = orm.relationship(Goal, foreign_keys=goal_id, lazy=None)
|
||||||
strategy = orm.relationship(Strategy, foreign_keys=strategy_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)
|
state = Column(String(20), nullable=True)
|
||||||
global_efficacy = Column(JSONEncodedList, nullable=True)
|
global_efficacy = Column(JSONEncodedList, nullable=True)
|
||||||
hostname = Column(String(255), 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)
|
audit = orm.relationship(Audit, foreign_keys=audit_id, lazy=None)
|
||||||
strategy = orm.relationship(Strategy, foreign_keys=strategy_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)
|
input_parameters = Column(JSONEncodedDict, nullable=True)
|
||||||
state = Column(String(20), nullable=True)
|
state = Column(String(20), nullable=True)
|
||||||
parents = Column(JSONEncodedList, nullable=True)
|
parents = Column(JSONEncodedList, nullable=True)
|
||||||
|
status_message = Column(String(255), nullable=True)
|
||||||
|
|
||||||
action_plan = orm.relationship(
|
action_plan = orm.relationship(
|
||||||
ActionPlan, foreign_keys=action_plan_id, lazy=None)
|
ActionPlan, foreign_keys=action_plan_id, lazy=None)
|
||||||
|
|||||||
@@ -401,3 +401,11 @@ class DbActionTestCase(base.DbTestCase):
|
|||||||
self.assertRaises(exception.ActionAlreadyExists,
|
self.assertRaises(exception.ActionAlreadyExists,
|
||||||
utils.create_test_action,
|
utils.create_test_action,
|
||||||
id=2, uuid=uuid)
|
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')
|
||||||
|
|||||||
@@ -389,3 +389,12 @@ class DbActionPlanTestCase(base.DbTestCase):
|
|||||||
self.assertRaises(exception.ActionPlanAlreadyExists,
|
self.assertRaises(exception.ActionPlanAlreadyExists,
|
||||||
utils.create_test_action_plan,
|
utils.create_test_action_plan,
|
||||||
id=2, uuid=uuid)
|
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')
|
||||||
|
|||||||
@@ -442,3 +442,11 @@ class DbAuditTestCase(base.DbTestCase):
|
|||||||
utils.create_test_audit,
|
utils.create_test_audit,
|
||||||
uuid=w_utils.generate_uuid(),
|
uuid=w_utils.generate_uuid(),
|
||||||
name='my_audit')
|
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')
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ from alembic.script import ScriptDirectory
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_db.sqlalchemy import enginefacade
|
from oslo_db.sqlalchemy import enginefacade
|
||||||
from oslo_db.sqlalchemy import test_fixtures
|
from oslo_db.sqlalchemy import test_fixtures
|
||||||
|
from oslo_db.sqlalchemy import utils as oslodbutils
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
|
||||||
@@ -55,7 +56,7 @@ class MySQLDbMigrationsTestCase(test_fixtures.OpportunisticDBTestMixin,
|
|||||||
self.engine = enginefacade.writer.get_engine()
|
self.engine = enginefacade.writer.get_engine()
|
||||||
self.dbapi = dbapi.get_instance()
|
self.dbapi = dbapi.get_instance()
|
||||||
self.alembic_config = migration._alembic_config()
|
self.alembic_config = migration._alembic_config()
|
||||||
self.revisions_tested = set(["15f7375ca737"])
|
self.revisions_tested = set(["15f7375ca737", "7150a7d8f228"])
|
||||||
|
|
||||||
def _apply_migration(self, connection, revision):
|
def _apply_migration(self, connection, revision):
|
||||||
if revision not in self.revisions_tested:
|
if revision not in self.revisions_tested:
|
||||||
@@ -113,6 +114,32 @@ class MySQLDbMigrationsTestCase(test_fixtures.OpportunisticDBTestMixin,
|
|||||||
|
|
||||||
|
|
||||||
class MySQLDbDataMigrationsTestCase(MySQLDbMigrationsTestCase):
|
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):
|
def _create_manual_efficacy_indicator(self, connection, **kwargs):
|
||||||
eff_ind_values = utils.get_test_efficacy_indicator(**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')
|
name="STRATEGY_ID_1", display_name='My Strategy 1')
|
||||||
self.audit_template = utils.create_test_audit_template(
|
self.audit_template = utils.create_test_audit_template(
|
||||||
name="Audit Template", id=1, uuid=None)
|
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,
|
audit_template_id=self.audit_template.id, id=1, uuid=None,
|
||||||
name="AUDIT_1")
|
name="AUDIT_1")
|
||||||
self.action_plan = utils.create_test_action_plan(
|
self._create_manual_action_plan(
|
||||||
audit_id=self.audit.id, id=1, uuid=None)
|
connection,
|
||||||
|
audit_id=1, id=1, uuid=None)
|
||||||
|
|
||||||
self._create_manual_efficacy_indicator(
|
self._create_manual_efficacy_indicator(
|
||||||
connection,
|
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",
|
name="efficacy_indicator1", description="Test Indicator 1",
|
||||||
value=1.01234567912345678)
|
value=1.01234567912345678)
|
||||||
self._create_manual_efficacy_indicator(
|
self._create_manual_efficacy_indicator(
|
||||||
connection,
|
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",
|
name="efficacy_indicator2", description="Test Indicator 2",
|
||||||
value=2.01234567912345678)
|
value=2.01234567912345678)
|
||||||
|
|
||||||
@@ -171,7 +200,7 @@ class MySQLDbDataMigrationsTestCase(MySQLDbMigrationsTestCase):
|
|||||||
# check that creating a new efficacy_indicator after the migration
|
# check that creating a new efficacy_indicator after the migration
|
||||||
# works
|
# works
|
||||||
utils.create_test_efficacy_indicator(
|
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",
|
name="efficacy_indicator3", description="Test Indicator 3",
|
||||||
value=0.01234567912345678)
|
value=0.01234567912345678)
|
||||||
db_efficacy_indicator = self.dbapi.get_efficacy_indicator_by_id(
|
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])
|
self.assertIsNone(self._read_efficacy_indicator(connection, 2)[0])
|
||||||
|
|
||||||
# check that the existing data is there after the migration
|
# 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(
|
db_efficacy_indicator_1 = self.dbapi.get_efficacy_indicator_by_id(
|
||||||
self.context, 1)
|
self.context, 1)
|
||||||
self.assertAlmostEqual(db_efficacy_indicator_1.data,
|
self.assertAlmostEqual(db_efficacy_indicator_1.data,
|
||||||
@@ -227,6 +247,21 @@ class MySQLDbDataMigrationsTestCase(MySQLDbMigrationsTestCase):
|
|||||||
self.assertAlmostEqual(eff_ind_2_data,
|
self.assertAlmostEqual(eff_ind_2_data,
|
||||||
2.00, places=2)
|
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):
|
def test_migration_revisions(self):
|
||||||
with self.engine.connect() as connection:
|
with self.engine.connect() as connection:
|
||||||
self.alembic_config.attributes["connection"] = connection
|
self.alembic_config.attributes["connection"] = connection
|
||||||
|
|||||||
Reference in New Issue
Block a user