|
14 | 14 | import argparse |
15 | 15 | import getpass |
16 | 16 | import datetime |
| 17 | +import os |
17 | 18 | import sys |
18 | 19 |
|
19 | 20 | from codechecker_api.codeCheckerDBAccess_v6 import ttypes |
20 | 21 |
|
21 | | -from codechecker_client import cmd_line_client |
22 | | -from codechecker_client import product_client |
23 | | -from codechecker_client import permission_client, source_component_client, \ |
| 22 | +from codechecker_client import \ |
| 23 | + cmd_line_client, \ |
| 24 | + permission_client, \ |
| 25 | + product_client, \ |
| 26 | + source_component_client, \ |
| 27 | + task_client, \ |
24 | 28 | token_client |
25 | 29 |
|
26 | 30 | from codechecker_common import arg, logger, util |
@@ -1229,6 +1233,231 @@ def __register_permissions(parser): |
1229 | 1233 | help="The output format to use in showing the data.") |
1230 | 1234 |
|
1231 | 1235 |
|
| 1236 | +def __register_tasks(parser): |
| 1237 | + """ |
| 1238 | + Add `argparse` subcommand `parser` options for the "handle server-side |
| 1239 | + tasks" action. |
| 1240 | + """ |
| 1241 | + if "TEST_WORKSPACE" in os.environ: |
| 1242 | + testing_args = parser.add_argument_group("testing arguments") |
| 1243 | + testing_args.add_argument("--create-dummy-task", |
| 1244 | + dest="dummy_task_args", |
| 1245 | + metavar="ARG", |
| 1246 | + default=argparse.SUPPRESS, |
| 1247 | + type=str, |
| 1248 | + nargs=2, |
| 1249 | + help=""" |
| 1250 | +Exercises the 'createDummyTask(int timeout, bool shouldFail)' API endpoint. |
| 1251 | +Used for testing purposes. |
| 1252 | +Note, that the server **MUST** be started in a testing environment as well, |
| 1253 | +otherwise, the request will be rejected by the server! |
| 1254 | +""") |
| 1255 | + |
| 1256 | + parser.add_argument("-t", "--token", |
| 1257 | + dest="token", |
| 1258 | + metavar="TOKEN", |
| 1259 | + type=str, |
| 1260 | + nargs='*', |
| 1261 | + help="The identifying token(s) of the task(s) to " |
| 1262 | + "query. Each task is associated with a unique " |
| 1263 | + "token.") |
| 1264 | + |
| 1265 | + parser.add_argument("--await", |
| 1266 | + dest="wait_and_block", |
| 1267 | + action="store_true", |
| 1268 | + help=""" |
| 1269 | +Instead of querying the status and reporting that, followed by an exit, block |
| 1270 | +execution of the 'CodeChecker cmd serverside-tasks' program until the queried |
| 1271 | +task(s) terminate(s). |
| 1272 | +Makes the CLI's return code '0' if the task(s) completed successfully, and |
| 1273 | +non-zero otherwise. |
| 1274 | +If '--kill' is also specified, the CLI will await the shutdown of the task(s), |
| 1275 | +but will return '0' if the task(s) were successfully killed as well. |
| 1276 | +""") |
| 1277 | + |
| 1278 | + parser.add_argument("--kill", |
| 1279 | + dest="cancel_task", |
| 1280 | + action="store_true", |
| 1281 | + help=""" |
| 1282 | +Request the co-operative and graceful termination of the tasks matching the |
| 1283 | +filter(s) specified. |
| 1284 | +'--kill' is only available to SUPERUSERs! |
| 1285 | +Note, that this action only submits a *REQUEST* of termination to the server, |
| 1286 | +and tasks are free to not support in-progress kills. |
| 1287 | +Even for tasks that support getting killed, due to its graceful nature, it |
| 1288 | +might take a considerable time for the killing to conclude. |
| 1289 | +Killing a task that has not started RUNNING yet results in it automatically |
| 1290 | +terminating before it would start. |
| 1291 | +""") |
| 1292 | + |
| 1293 | + output = parser.add_argument_group("output arguments") |
| 1294 | + output.add_argument("--output", |
| 1295 | + dest="output_format", |
| 1296 | + required=False, |
| 1297 | + default="plaintext", |
| 1298 | + choices=["plaintext", "table", "json"], |
| 1299 | + help="The format of the output to use when showing " |
| 1300 | + "the result of the request.") |
| 1301 | + |
| 1302 | + task_list = parser.add_argument_group( |
| 1303 | + "task list filter arguments", |
| 1304 | + """These options can be used to obtain and filter the list of tasks |
| 1305 | +associated with the 'CodeChecker server' specified by '--url', based on the |
| 1306 | +various information columns stored for tasks. |
| 1307 | +
|
| 1308 | +'--token' is usable with the following filters as well. |
| 1309 | +
|
| 1310 | +Filters with a variable number of options (e.g., '--machine-id A B') will be |
| 1311 | +in a Boolean OR relation with each other (meaning: machine ID is either "A" |
| 1312 | +or "B"). |
| 1313 | +Specifying multiple filters (e.g., '--machine-id A B --username John') will |
| 1314 | +be considered in a Boolean AND relation (meaning: [machine ID is either "A" or |
| 1315 | +"B"] and [the task was created by "John"]). |
| 1316 | +
|
| 1317 | +Listing is only available for the following, privileged users: |
| 1318 | + - For tasks that are associated with a specific product, the PRODUCT_ADMINs |
| 1319 | + of that product. |
| 1320 | + - Server administrators (SUPERUSERs). |
| 1321 | +
|
| 1322 | +Unprivileged users MUST use only the task's token to query information about |
| 1323 | +the task. |
| 1324 | + """) |
| 1325 | + |
| 1326 | + task_list.add_argument("--machine-id", |
| 1327 | + type=str, |
| 1328 | + nargs='*', |
| 1329 | + help="The IDs of the server instance executing " |
| 1330 | + "the tasks. This is an internal identifier " |
| 1331 | + "set by server administrators via the " |
| 1332 | + "'CodeChecker server' command.") |
| 1333 | + |
| 1334 | + task_list.add_argument("--type", |
| 1335 | + type=str, |
| 1336 | + nargs='*', |
| 1337 | + help="The descriptive, but still " |
| 1338 | + "machine-readable \"type\" of the tasks to " |
| 1339 | + "filter for.") |
| 1340 | + |
| 1341 | + task_list.add_argument("--status", |
| 1342 | + type=str, |
| 1343 | + nargs='*', |
| 1344 | + choices=["allocated", "enqueued", "running", |
| 1345 | + "completed", "failed", "cancelled", |
| 1346 | + "dropped"], |
| 1347 | + help="The task's execution status(es) in the " |
| 1348 | + "pipeline.") |
| 1349 | + |
| 1350 | + username = task_list.add_mutually_exclusive_group(required=False) |
| 1351 | + username.add_argument("--username", |
| 1352 | + type=str, |
| 1353 | + nargs='*', |
| 1354 | + help="The user(s) who executed the action that " |
| 1355 | + "caused the tasks' creation.") |
| 1356 | + username.add_argument("--no-username", |
| 1357 | + action="store_true", |
| 1358 | + help="Filter for tasks without a responsible user " |
| 1359 | + "that created them.") |
| 1360 | + |
| 1361 | + product = task_list.add_mutually_exclusive_group(required=False) |
| 1362 | + product.add_argument("--product", |
| 1363 | + type=str, |
| 1364 | + nargs='*', |
| 1365 | + help="Filter for tasks that execute in the context " |
| 1366 | + "of products specified by the given ENDPOINTs. " |
| 1367 | + "This query is only available if you are a " |
| 1368 | + "PRODUCT_ADMIN of the specified product(s).") |
| 1369 | + product.add_argument("--no-product", |
| 1370 | + action="store_true", |
| 1371 | + help="Filter for server-wide tasks (not associated " |
| 1372 | + "with any products). This query is only " |
| 1373 | + "available to SUPERUSERs.") |
| 1374 | + |
| 1375 | + timestamp_documentation: str = """ |
| 1376 | +TIMESTAMP, which is given in the format of 'year:month:day' or |
| 1377 | +'year:month:day:hour:minute:second'. |
| 1378 | +If the "time" part (':hour:minute:second') is not given, 00:00:00 (midnight) |
| 1379 | +is assumed instead. |
| 1380 | +Timestamps for tasks are always understood as Coordinated Universal Time (UTC). |
| 1381 | +""" |
| 1382 | + |
| 1383 | + task_list.add_argument("--enqueued-before", |
| 1384 | + type=valid_time, |
| 1385 | + metavar="TIMESTAMP", |
| 1386 | + help="Filter for tasks that were created BEFORE " |
| 1387 | + "(or on) the specified " + |
| 1388 | + timestamp_documentation) |
| 1389 | + task_list.add_argument("--enqueued-after", |
| 1390 | + type=valid_time, |
| 1391 | + metavar="TIMESTAMP", |
| 1392 | + help="Filter for tasks that were created AFTER " |
| 1393 | + "(or on) the specified " + |
| 1394 | + timestamp_documentation) |
| 1395 | + |
| 1396 | + task_list.add_argument("--started-before", |
| 1397 | + type=valid_time, |
| 1398 | + metavar="TIMESTAMP", |
| 1399 | + help="Filter for tasks that were started " |
| 1400 | + "execution BEFORE (or on) the specified " + |
| 1401 | + timestamp_documentation) |
| 1402 | + task_list.add_argument("--started-after", |
| 1403 | + type=valid_time, |
| 1404 | + metavar="TIMESTAMP", |
| 1405 | + help="Filter for tasks that were started " |
| 1406 | + "execution AFTER (or on) the specified " + |
| 1407 | + timestamp_documentation) |
| 1408 | + |
| 1409 | + task_list.add_argument("--finished-before", |
| 1410 | + type=valid_time, |
| 1411 | + metavar="TIMESTAMP", |
| 1412 | + help="Filter for tasks that concluded execution " |
| 1413 | + "BEFORE (or on) the specified " + |
| 1414 | + timestamp_documentation) |
| 1415 | + task_list.add_argument("--finished-after", |
| 1416 | + type=valid_time, |
| 1417 | + metavar="TIMESTAMP", |
| 1418 | + help="Filter for tasks that concluded execution " |
| 1419 | + "execution AFTER (or on) the specified " + |
| 1420 | + timestamp_documentation) |
| 1421 | + |
| 1422 | + task_list.add_argument("--last-seen-before", |
| 1423 | + type=valid_time, |
| 1424 | + metavar="TIMESTAMP", |
| 1425 | + help="Filter for tasks that reported actual " |
| 1426 | + "forward progress in its execution " |
| 1427 | + "(\"heartbeat\") BEFORE (or on) the " |
| 1428 | + "specified " + timestamp_documentation) |
| 1429 | + task_list.add_argument("--last-seen-after", |
| 1430 | + type=valid_time, |
| 1431 | + metavar="TIMESTAMP", |
| 1432 | + help="Filter for tasks that reported actual " |
| 1433 | + "forward progress in its execution " |
| 1434 | + "(\"heartbeat\") AFTER (or on) the " |
| 1435 | + "specified " + timestamp_documentation) |
| 1436 | + |
| 1437 | + cancel = task_list.add_mutually_exclusive_group(required=False) |
| 1438 | + cancel.add_argument("--only-cancelled", |
| 1439 | + action="store_true", |
| 1440 | + help="Show only tasks that received a cancel request " |
| 1441 | + "from a SUPERUSER (see '--kill').") |
| 1442 | + cancel.add_argument("--no-cancelled", |
| 1443 | + action="store_true", |
| 1444 | + help="Show only tasks that had not received a " |
| 1445 | + "cancel request from a SUPERUSER " |
| 1446 | + "(see '--kill').") |
| 1447 | + |
| 1448 | + consumed = task_list.add_mutually_exclusive_group(required=False) |
| 1449 | + consumed.add_argument("--only-consumed", |
| 1450 | + action="store_true", |
| 1451 | + help="Show only tasks that concluded their " |
| 1452 | + "execution and the responsible user (see " |
| 1453 | + "'--username') \"downloaded\" this fact.") |
| 1454 | + consumed.add_argument("--no-consumed", |
| 1455 | + action="store_true", |
| 1456 | + help="Show only tasks that concluded their " |
| 1457 | + "execution but the responsible user (see " |
| 1458 | + "'--username') did not \"check\" on the task.") |
| 1459 | + |
| 1460 | + |
1232 | 1461 | def __register_token(parser): |
1233 | 1462 | """ |
1234 | 1463 | Add argparse subcommand parser for the "handle token" action. |
@@ -1552,5 +1781,41 @@ def add_arguments_to_parser(parser): |
1552 | 1781 | permissions.set_defaults(func=permission_client.handle_permissions) |
1553 | 1782 | __add_common_arguments(permissions, needs_product_url=False) |
1554 | 1783 |
|
| 1784 | + tasks = subcommands.add_parser( |
| 1785 | + "serverside-tasks", |
| 1786 | + formatter_class=arg.RawDescriptionDefaultHelpFormatter, |
| 1787 | + description=""" |
| 1788 | +Query the status of and otherwise filter information for server-side |
| 1789 | +background tasks executing on a CodeChecker server. In addition, for server |
| 1790 | +administartors, allows requesting tasks to cancel execution. |
| 1791 | +
|
| 1792 | +Normally, the querying of a task's status is available only to the following |
| 1793 | +users: |
| 1794 | + - The user who caused the creation of the task. |
| 1795 | + - For tasks that are associated with a specific product, the PRODUCT_ADMIN |
| 1796 | + users of that product. |
| 1797 | + - Accounts with SUPERUSER rights (server administrators). |
| 1798 | +""", |
| 1799 | + help="Await, query, and cancel background tasks executing on the " |
| 1800 | + "server.", |
| 1801 | + epilog=""" |
| 1802 | +The return code of 'CodeChecker cmd serverside-tasks' is almost always '0', |
| 1803 | +unless there is an error. |
| 1804 | +If **EXACTLY** one '--token' is specified in the arguments without the use of |
| 1805 | +'--await' or '--kill', the return code is based on the current status of the |
| 1806 | +task, as identified by the token: |
| 1807 | + - 0: The task completed successfully. |
| 1808 | + - 1: (Reserved for operational errors.) |
| 1809 | + - 2: (Reserved for command-line errors.) |
| 1810 | + - 4: The task failed to complete due to an error during execution. |
| 1811 | + - 8: The task is still running... |
| 1812 | + - 16: The task was cancelled by the administrators, or the server was shut |
| 1813 | + down. |
| 1814 | +""" |
| 1815 | + ) |
| 1816 | + __register_tasks(tasks) |
| 1817 | + tasks.set_defaults(func=task_client.handle_tasks) |
| 1818 | + __add_common_arguments(tasks, needs_product_url=False) |
| 1819 | + |
1555 | 1820 | # 'cmd' does not have a main() method in itself, as individual subcommands are |
1556 | 1821 | # handled later on separately. |
0 commit comments