Ver Fonte

Add 'scenario' field in DB models layer.

Adds the 'scenario' field to the `Replica` DB model and afferent
DB API functions for creating/filtering Replicas based on it.

The `scenario` can be one of:
    * `replica` (the auto-default for all newly-created replicas)
    * `live_migration` (special case for replicas-as-migrations)

Signed-off-by: Nashwan Azhari <nazhari@cloudbasesolutions.com>
Nashwan Azhari há 2 anos atrás
pai
commit
31a425e6e9

+ 3 - 0
coriolis/constants.py

@@ -3,6 +3,9 @@
 
 DEFAULT_CORIOLIS_REGION_NAME = "Default Region"
 
+REPLICA_SCENARIO_REPLICA = "replica"
+REPLICA_SCENARIO_LIVE_MIGRATION = "live_migration"
+
 EXECUTION_STATUS_UNEXECUTED = "UNEXECUTED"
 EXECUTION_STATUS_RUNNING = "RUNNING"
 EXECUTION_STATUS_COMPLETED = "COMPLETED"

+ 28 - 4
coriolis/db/api.py

@@ -15,6 +15,7 @@ from sqlalchemy import orm
 from sqlalchemy.sql import null
 
 from coriolis.db.sqlalchemy import models
+from coriolis import constants
 from coriolis import exception
 from coriolis import utils
 
@@ -424,6 +425,7 @@ def _get_replica_with_tasks_executions_options(q):
 
 @enginefacade.reader
 def get_replicas(context,
+                 replica_scenario=None,
                  include_tasks_executions=False,
                  include_task_info=False,
                  to_dict=False):
@@ -433,6 +435,8 @@ def get_replicas(context,
     if include_task_info:
         q = q.options(orm.undefer('info'))
     q = q.filter()
+    if replica_scenario:
+        q.filter(models.Replica.scenario == replica_scenario)
     if is_user_context(context):
         q = q.filter(
             models.Replica.project_id == context.project_id)
@@ -447,11 +451,17 @@ def get_replicas(context,
 
 
 @enginefacade.reader
-def get_replica(context, replica_id, include_task_info=False, to_dict=False):
+def get_replica(context, replica_id,
+                replica_scenario=None,
+                include_task_info=False,
+                to_dict=False):
     q = _soft_delete_aware_query(context, models.Replica)
     q = _get_replica_with_tasks_executions_options(q)
     if include_task_info:
         q = q.options(orm.undefer('info'))
+    if replica_scenario:
+        q = q.filter(
+            models.Replica.scenario == replica_scenario)
     if is_user_context(context):
         q = q.filter(
             models.Replica.project_id == context.project_id)
@@ -465,12 +475,20 @@ def get_replica(context, replica_id, include_task_info=False, to_dict=False):
 
 
 @enginefacade.reader
-def get_endpoint_replicas_count(context, endpoint_id):
+def get_endpoint_replicas_count(
+        context, endpoint_id, replica_scenario=None):
+
+    scenario_filter_kwargs = {}
+    if replica_scenario:
+        scenario_filter_kwargs = {"scenario": replica_scenario}
+
     origin_args = {'origin_endpoint_id': endpoint_id}
+    origin_args.update(scenario_filter_kwargs)
     q_origin_count = _soft_delete_aware_query(
         context, models.Replica).filter_by(**origin_args).count()
 
     destination_args = {'destination_endpoint_id': endpoint_id}
+    destination_args.update(scenario_filter_kwargs)
     q_destination_count = _soft_delete_aware_query(
         context, models.Replica).filter_by(**destination_args).count()
 
@@ -516,8 +534,11 @@ def get_replica_migrations(context, replica_id):
 
 
 @enginefacade.reader
-def get_migrations(context, include_tasks=False,
-                   include_task_info=False, to_dict=False):
+def get_migrations(context,
+                   include_tasks=False,
+                   include_task_info=False,
+                   to_dict=False,
+                   replica_migrations_only=False):
     q = _soft_delete_aware_query(context, models.Migration)
     if include_tasks:
         q = _get_migration_task_query_options(q)
@@ -526,6 +547,9 @@ def get_migrations(context, include_tasks=False,
     if include_task_info:
         q = q.options(orm.undefer('info'))
 
+    if replica_migrations_only:
+        q.filter(models.Migration.replica_id != None)
+
     args = {}
     if is_user_context(context):
         args["project_id"] = context.project_id

+ 18 - 0
coriolis/db/sqlalchemy/migrate_repo/versions/019_add_replica_scenario_field.py

@@ -0,0 +1,18 @@
+# Copyright 2024 Cloudbase Solutions Srl
+# All Rights Reserved.
+
+import sqlalchemy
+
+
+def upgrade(migrate_engine):
+    meta = sqlalchemy.MetaData()
+    meta.bind = migrate_engine
+
+    replica = sqlalchemy.Table(
+        'replica', meta, autoload=True)
+
+    replica_scenario = sqlalchemy.Column(
+        "scenario", sqlalchemy.String(255), nullable=False,
+        default="replica")
+
+    replica.create_column(replica_scenario)

+ 10 - 1
coriolis/db/sqlalchemy/models.py

@@ -330,6 +330,9 @@ class Replica(BaseTransferAction):
         sqlalchemy.String(36),
         sqlalchemy.ForeignKey(
             'base_transfer_action.base_id'), primary_key=True)
+    scenario = sqlalchemy.Column(
+        sqlalchemy.String(255),
+        default=constants.REPLICA_SCENARIO_REPLICA)
 
     __mapper_args__ = {
         'polymorphic_identity': 'replica',
@@ -339,7 +342,9 @@ class Replica(BaseTransferAction):
         base = super(Replica, self).to_dict(
             include_task_info=include_task_info,
             include_executions=include_executions)
-        base.update({"id": self.id})
+        base.update({
+            "id": self.id,
+            "scenario": self.scenario})
         return base
 
 
@@ -368,9 +373,13 @@ class Migration(BaseTransferAction):
         base = super(Migration, self).to_dict(
             include_task_info=include_task_info,
             include_executions=include_tasks)
+        replica_scenario_type = None
+        if self.replica:
+            replica_scenario_type = self.replica.scenario
         base.update({
             "id": self.id,
             "replica_id": self.replica_id,
+            "replica_scenario_type": replica_scenario_type,
             "shutdown_instances": self.shutdown_instances,
             "replication_count": self.replication_count,
         })