Skip to content

Commit a1ff48f

Browse files
petrutlucian94root
authored andcommitted
Allow filtering results by status
We're adding a "status" search option that can be specified when listing the following resources: * deployments * status -> last_execution_status db field * transfers * transfer executions The filtering will be performed on the db side.
1 parent 7a402a3 commit a1ff48f

18 files changed

Lines changed: 208 additions & 18 deletions

File tree

coriolis/api/v1/deployments.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from coriolis.api.v1 import utils as api_utils
99
from coriolis.api.v1.views import deployment_view
1010
from coriolis.api import wsgi as api_wsgi
11+
from coriolis import constants
1112
from coriolis.deployments import api
1213
from coriolis.endpoints import api as endpoints_api
1314
from coriolis import exception
@@ -36,6 +37,18 @@ def show(self, req, id):
3637

3738
return deployment_view.single(deployment)
3839

40+
def _get_filters(self, req) -> dict:
41+
filters = {}
42+
# For simplicity and consistency, we'll use "status" to search for a
43+
# given "last_execution_status".
44+
status = req.GET.get("status")
45+
if status is not None:
46+
if status not in constants.ALL_EXECUTION_STATUSES:
47+
raise exc.HTTPBadRequest(
48+
explanation=f"Unknown deployment status: {status}")
49+
filters["status"] = status
50+
return filters
51+
3952
def _list(self, req):
4053
show_deleted = api_utils.get_bool_url_arg(
4154
req, "show_deleted", default=False)
@@ -47,6 +60,7 @@ def _list(self, req):
4760

4861
marker, limit = common.get_paging_params(req)
4962
sort_keys, sort_dirs = common.get_sort_params(req)
63+
filters = self._get_filters(req)
5064

5165
return deployment_view.collection(
5266
self._deployment_api.get_deployments(
@@ -55,6 +69,7 @@ def _list(self, req):
5569
include_task_info=include_task_info,
5670
marker=marker, limit=limit,
5771
sort_keys=sort_keys, sort_dirs=sort_dirs,
72+
filters=filters,
5873
))
5974

6075
def index(self, req):

coriolis/api/v1/transfer_tasks_executions.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from coriolis.api import common
55
from coriolis.api.v1.views import transfer_tasks_execution_view
66
from coriolis.api import wsgi as api_wsgi
7+
from coriolis import constants
78
from coriolis import exception
89
from coriolis.policies import transfer_tasks_executions as executions_policies
910
from coriolis.transfer_tasks_executions import api
@@ -27,19 +28,31 @@ def show(self, req, transfer_id, id):
2728

2829
return transfer_tasks_execution_view.single(execution)
2930

31+
def _get_filters(self, req) -> dict:
32+
filters = {}
33+
status = req.GET.get("status")
34+
if status is not None:
35+
if status not in constants.ALL_EXECUTION_STATUSES:
36+
raise exc.HTTPBadRequest(
37+
explanation=f"Unknown task execution status: {status}")
38+
filters["status"] = status
39+
return filters
40+
3041
def index(self, req, transfer_id):
3142
context = req.environ["coriolis.context"]
3243
context.can(
3344
executions_policies.get_transfer_executions_policy_label("list"))
3445

3546
marker, limit = common.get_paging_params(req)
3647
sort_keys, sort_dirs = common.get_sort_params(req)
48+
filters = self._get_filters(req)
3749

3850
return transfer_tasks_execution_view.collection(
3951
self._transfer_tasks_execution_api.get_executions(
4052
context, transfer_id, include_tasks=False,
4153
marker=marker, limit=limit,
42-
sort_keys=sort_keys, sort_dirs=sort_dirs))
54+
sort_keys=sort_keys, sort_dirs=sort_dirs,
55+
filters=filters))
4356

4457
def detail(self, req, transfer_id):
4558
context = req.environ["coriolis.context"]

coriolis/api/v1/transfers.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,16 @@ def show(self, req, id):
4242

4343
return transfer_view.single(transfer)
4444

45+
def _get_filters(self, req) -> dict:
46+
filters = {}
47+
status = req.GET.get("status")
48+
if status is not None:
49+
if status not in constants.ALL_TASK_STATUSES:
50+
raise exc.HTTPBadRequest(
51+
explanation=f"Unknown task status: {status}")
52+
filters["status"] = status
53+
return filters
54+
4555
def _list(self, req):
4656
show_deleted = api_utils.get_bool_url_arg(
4757
req, "show_deleted", default=False)
@@ -52,13 +62,15 @@ def _list(self, req):
5262
req, "include_task_info", default=False)
5363
marker, limit = common.get_paging_params(req)
5464
sort_keys, sort_dirs = common.get_sort_params(req)
65+
filters = self._get_filters(req)
5566
return transfer_view.collection(
5667
self._transfer_api.get_transfers(
5768
context,
5869
include_tasks_executions=include_task_info,
5970
include_task_info=include_task_info,
6071
marker=marker, limit=limit,
6172
sort_keys=sort_keys, sort_dirs=sort_dirs,
73+
filters=filters,
6274
))
6375

6476
def index(self, req):

coriolis/conductor/rpc/client.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ def get_transfer_tasks_executions(self, ctxt, transfer_id,
147147
marker=None,
148148
limit=None,
149149
sort_keys=None,
150-
sort_dirs=None):
150+
sort_dirs=None,
151+
filters=None):
151152
return self._call(
152153
ctxt, 'get_transfer_tasks_executions',
153154
transfer_id=transfer_id,
@@ -156,6 +157,7 @@ def get_transfer_tasks_executions(self, ctxt, transfer_id,
156157
limit=limit,
157158
sort_keys=sort_keys,
158159
sort_dirs=sort_dirs,
160+
filters=filters,
159161
)
160162

161163
def get_transfer_tasks_execution(self, ctxt, transfer_id, execution_id,
@@ -208,7 +210,8 @@ def create_instances_transfer(self, ctxt,
208210
def get_transfers(self, ctxt, include_tasks_executions=False,
209211
include_task_info=False,
210212
marker=None, limit=None,
211-
sort_keys=None, sort_dirs=None):
213+
sort_keys=None, sort_dirs=None,
214+
filters=None):
212215
return self._call(
213216
ctxt, 'get_transfers',
214217
include_tasks_executions=include_tasks_executions,
@@ -217,6 +220,7 @@ def get_transfers(self, ctxt, include_tasks_executions=False,
217220
limit=limit,
218221
sort_keys=sort_keys,
219222
sort_dirs=sort_dirs,
223+
filters=filters,
220224
)
221225

222226
def get_transfer(self, ctxt, transfer_id, include_task_info=False):
@@ -235,14 +239,16 @@ def delete_transfer_disks(self, ctxt, transfer_id):
235239
def get_deployments(self, ctxt, include_tasks=False,
236240
include_task_info=False,
237241
marker=None, limit=None,
238-
sort_keys=None, sort_dirs=None):
242+
sort_keys=None, sort_dirs=None,
243+
filters=None):
239244
return self._call(
240245
ctxt, 'get_deployments', include_tasks=include_tasks,
241246
include_task_info=include_task_info,
242247
marker=marker,
243248
limit=limit,
244249
sort_keys=sort_keys,
245250
sort_dirs=sort_dirs,
251+
filters=filters,
246252
)
247253

248254
def get_deployment(self, ctxt, deployment_id, include_task_info=False):

coriolis/conductor/rpc/server.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,14 +1156,16 @@ def get_transfer_tasks_executions(self, ctxt, transfer_id,
11561156
marker=None,
11571157
limit=None,
11581158
sort_keys=None,
1159-
sort_dirs=None):
1159+
sort_dirs=None,
1160+
filters=None):
11601161
return db_api.get_transfer_tasks_executions(
11611162
ctxt, transfer_id, include_tasks,
11621163
include_task_info=include_task_info,
11631164
marker=marker,
11641165
limit=limit,
11651166
sort_keys=sort_keys,
11661167
sort_dirs=sort_dirs,
1168+
filters=filters,
11671169
to_dict=True)
11681170

11691171
@tasks_execution_synchronized
@@ -1217,14 +1219,16 @@ def _get_transfer_tasks_execution(ctxt, transfer_id, execution_id,
12171219
def get_transfers(ctxt, include_tasks_executions=False,
12181220
include_task_info=False,
12191221
marker=None, limit=None,
1220-
sort_keys=None, sort_dirs=None):
1222+
sort_keys=None, sort_dirs=None,
1223+
filters=None):
12211224
return db_api.get_transfers(
12221225
ctxt, include_tasks_executions=include_tasks_executions,
12231226
include_task_info=include_task_info,
12241227
marker=marker,
12251228
limit=limit,
12261229
sort_keys=sort_keys,
12271230
sort_dirs=sort_dirs,
1231+
filters=filters,
12281232
to_dict=True)
12291233

12301234
@transfer_synchronized
@@ -1383,14 +1387,16 @@ def _get_transfer(self, ctxt, transfer_id, include_task_info=False,
13831387
@staticmethod
13841388
def get_deployments(ctxt, include_tasks, include_task_info=False,
13851389
marker=None, limit=None,
1386-
sort_keys=None, sort_dirs=None):
1390+
sort_keys=None, sort_dirs=None,
1391+
filters=None):
13871392
return db_api.get_deployments(
13881393
ctxt, include_tasks,
13891394
include_task_info=include_task_info,
13901395
marker=marker,
13911396
limit=limit,
13921397
sort_keys=sort_keys,
13931398
sort_dirs=sort_dirs,
1399+
filters=filters,
13941400
to_dict=True)
13951401

13961402
@deployment_synchronized

coriolis/constants.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@
3333
EXECUTION_STATUS_ERROR_ALLOCATING_MINIONS
3434
]
3535

36+
ALL_EXECUTION_STATUSES = (
37+
ACTIVE_EXECUTION_STATUSES +
38+
FINALIZED_EXECUTION_STATUSES
39+
)
40+
3641
TASK_STATUS_SCHEDULED = "SCHEDULED"
3742
TASK_STATUS_PENDING = "PENDING"
3843
TASK_STATUS_STARTING = "STARTING"
@@ -83,6 +88,12 @@
8388
TASK_STATUS_FAILED_TO_CANCEL
8489
]
8590

91+
ALL_TASK_STATUSES = (
92+
ACTIVE_TASK_STATUSES +
93+
CANCELED_TASK_STATUSES +
94+
FINALIZED_TASK_STATUSES
95+
)
96+
8697
TASK_TYPE_FINALIZE_INSTANCE_DEPLOYMENT = "FINALIZE_INSTANCE_DEPLOYMENT"
8798
TASK_TYPE_CLEANUP_FAILED_INSTANCE_DEPLOYMENT = (
8899
"CLEANUP_FAILED_INSTANCE_DEPLOYMENT")

coriolis/db/api.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright 2016 Cloudbase Solutions Srl
22
# All Rights Reserved.
33

4+
import copy
45
import uuid
56

67
from oslo_config import cfg
@@ -281,6 +282,7 @@ def get_transfer_tasks_executions(context, transfer_id, include_tasks=False,
281282
limit=None,
282283
sort_keys: list[str] | None = None,
283284
sort_dirs: list[str] | None = None,
285+
filters: dict | None = None,
284286
to_dict=False):
285287
q = _soft_delete_aware_query(context, models.TasksExecution)
286288
q = q.join(models.Transfer)
@@ -293,6 +295,13 @@ def get_transfer_tasks_executions(context, transfer_id, include_tasks=False,
293295

294296
q = q.filter(models.Transfer.id == transfer_id)
295297

298+
filters = copy.deepcopy(filters or {})
299+
if "status" in filters:
300+
status = filters.pop("status")
301+
q = q.filter(models.TasksExecution.status == status)
302+
if filters:
303+
raise ValueError("Unsupported filters: %s" % filters)
304+
296305
sort_keys, sort_dirs = process_sort_params(
297306
sort_keys,
298307
sort_dirs,
@@ -458,6 +467,7 @@ def get_transfers(context,
458467
limit=None,
459468
sort_keys: list[str] | None = None,
460469
sort_dirs: list[str] | None = None,
470+
filters: dict | None = None,
461471
to_dict=False):
462472
q = _soft_delete_aware_query(context, models.Transfer)
463473
if include_tasks_executions:
@@ -471,6 +481,13 @@ def get_transfers(context,
471481
q = q.filter(
472482
models.Transfer.project_id == context.project_id)
473483

484+
filters = copy.deepcopy(filters or {})
485+
if "status" in filters:
486+
status = filters.pop("status")
487+
q = q.filter(models.Transfer.last_execution_status == status)
488+
if filters:
489+
raise ValueError("Unsupported filters: %s" % filters)
490+
474491
sort_keys, sort_dirs = process_sort_params(
475492
sort_keys,
476493
sort_dirs,
@@ -588,6 +605,7 @@ def get_deployments(context,
588605
limit=None,
589606
sort_keys: list[str] | None = None,
590607
sort_dirs: list[str] | None = None,
608+
filters: dict | None = None,
591609
to_dict=False):
592610
q = _soft_delete_aware_query(context, models.Deployment)
593611
if include_tasks:
@@ -600,6 +618,13 @@ def get_deployments(context,
600618
if is_user_context(context):
601619
q = q.filter_by(project_id=context.project_id)
602620

621+
filters = copy.deepcopy(filters or {})
622+
if "status" in filters:
623+
status = filters.pop("status")
624+
q = q.filter(models.Deployment.last_execution_status == status)
625+
if filters:
626+
raise ValueError("Unsupported filters: %s" % filters)
627+
603628
sort_keys, sort_dirs = process_sort_params(
604629
sort_keys,
605630
sort_dirs,

coriolis/deployer_manager/rpc/server.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ def _loop(self):
123123
try:
124124
deployments = self._rpc_conductor_client.get_deployments(
125125
self._admin_ctx, include_tasks=False,
126-
include_task_info=False)
127-
for d in deployments:
128-
if d['last_execution_status'] == PENDING_STATUS:
129-
self._check_deployer_status(d['id'])
126+
include_task_info=False,
127+
filters={'status': PENDING_STATUS})
128+
for pending_deployment in deployments:
129+
self._check_deployer_status(pending_deployment['id'])
130130
except Exception:
131131
LOG.warning(
132132
f"Deployer manager failed to list pending deployments. "

coriolis/deployments/api.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@ def cancel(self, ctxt, deployment_id, force):
2828
def get_deployments(self, ctxt, include_tasks=False,
2929
include_task_info=False,
3030
marker=None, limit=None,
31-
sort_keys=None, sort_dirs=None):
31+
sort_keys=None, sort_dirs=None,
32+
filters=None):
3233
return self._rpc_client.get_deployments(
3334
ctxt, include_tasks, include_task_info=include_task_info,
3435
marker=marker, limit=limit,
35-
sort_keys=sort_keys, sort_dirs=sort_dirs)
36+
sort_keys=sort_keys, sort_dirs=sort_dirs,
37+
filters=filters,
38+
)
3639

3740
def get_deployment(self, ctxt, deployment_id, include_task_info=False):
3841
return self._rpc_client.get_deployment(

coriolis/tests/api/v1/test_transfer_tasks_executions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ def test_index(
9595
mock.sentinel.marker,
9696
mock.sentinel.limit,
9797
)
98+
mock_req.GET = {
99+
"status": "RUNNING",
100+
}
98101

99102
result = self.transfer_api.index(mock_req, transfer_id)
100103

@@ -111,6 +114,7 @@ def test_index(
111114
limit=mock.sentinel.limit,
112115
sort_keys=mock.sentinel.sort_keys,
113116
sort_dirs=mock.sentinel.sort_dirs,
117+
filters={"status": "RUNNING"},
114118
)
115119
mock_collection.assert_called_once_with(
116120
mock_get_executions.return_value)

0 commit comments

Comments
 (0)