|
| 1 | +import logging |
1 | 2 | import pytest |
2 | | -import time |
| 3 | +from pathlib import Path |
| 4 | +from collections import defaultdict |
| 5 | +import os |
3 | 6 | import json |
| 7 | +import time |
4 | 8 |
|
5 | 9 | from tests.common.config_reload import config_reload |
6 | | -from pathlib import Path |
7 | | -from collections import defaultdict |
8 | 10 | from tests.common.helpers.constants import DEFAULT_NAMESPACE |
9 | | -from common.ha.smartswitch_ha_helper import PtfTcpTestAdapter |
10 | | -from common.ha.smartswitch_ha_io import SmartSwitchHaTrafficTest |
11 | | -from common.ha.smartswitch_ha_helper import ( |
| 11 | +from tests.common.ha.smartswitch_ha_helper import PtfTcpTestAdapter |
| 12 | +from tests.common.ha.smartswitch_ha_io import SmartSwitchHaTrafficTest |
| 13 | +from tests.common.ha.smartswitch_ha_helper import ( |
12 | 14 | add_port_to_namespace, |
13 | 15 | remove_namespace, |
14 | 16 | add_static_route_to_ptf, |
15 | 17 | add_static_route_to_dut |
16 | 18 | ) |
17 | 19 |
|
| 20 | +from tests.ha.ha_utils import ( |
| 21 | + |
| 22 | + build_dash_ha_scope_args, |
| 23 | + wait_for_pending_operation_id, |
| 24 | + build_dash_ha_scope_activate_args, |
| 25 | + wait_for_ha_state, |
| 26 | + build_dash_ha_set_args, |
| 27 | + proto_utils_hset |
| 28 | +) |
| 29 | + |
| 30 | +logger = logging.getLogger(__name__) |
| 31 | + |
18 | 32 |
|
19 | 33 | @pytest.fixture(scope="module") |
20 | 34 | def copy_files(ptfhost): |
@@ -408,3 +422,127 @@ def setup_ha_config(duthosts): |
408 | 422 | final_cfg[f"DUT{switch_id}"] = cfg |
409 | 423 |
|
410 | 424 | return final_cfg |
| 425 | + |
| 426 | + |
| 427 | +@pytest.fixture(scope="module") |
| 428 | +def setup_dash_ha_from_json(duthosts): |
| 429 | + current_dir = os.path.dirname(os.path.abspath(__file__)) |
| 430 | + base_dir = os.path.join(current_dir, "..", "common", "ha") |
| 431 | + ha_set_file = os.path.join(base_dir, "dash_ha_set_dpu_config_table.json") |
| 432 | + |
| 433 | + with open(ha_set_file) as f: |
| 434 | + ha_set_data = json.load(f)["DASH_HA_SET_CONFIG_TABLE"] |
| 435 | + |
| 436 | + # ------------------------------------------------- |
| 437 | + # Step 1: Program HA SET on BOTH DUTs |
| 438 | + # ------------------------------------------------- |
| 439 | + for duthost in duthosts: |
| 440 | + for key, fields in ha_set_data.items(): |
| 441 | + proto_utils_hset( |
| 442 | + duthost, |
| 443 | + table="DASH_HA_SET_CONFIG_TABLE", |
| 444 | + key=key, |
| 445 | + args=build_dash_ha_set_args(fields), |
| 446 | + ) |
| 447 | + |
| 448 | + # ------------------------------------------------- |
| 449 | + # Step 2: Initial HA SCOPE per DUT |
| 450 | + # ------------------------------------------------- |
| 451 | + ha_scope_per_dut = [ |
| 452 | + ( |
| 453 | + "vdpu0_0:haset0_0", |
| 454 | + { |
| 455 | + "version": "1", |
| 456 | + "disabled": "true", |
| 457 | + "desired_ha_state": "active", |
| 458 | + "ha_set_id": "haset0_0", |
| 459 | + "owner": "dpu", |
| 460 | + }, |
| 461 | + ), |
| 462 | + ( |
| 463 | + "vdpu1_0:haset0_0", |
| 464 | + { |
| 465 | + "version": "1", |
| 466 | + "disabled": "true", |
| 467 | + "desired_ha_state": "unspecified", |
| 468 | + "ha_set_id": "haset0_0", |
| 469 | + "owner": "dpu", |
| 470 | + }, |
| 471 | + ), |
| 472 | + ] |
| 473 | + |
| 474 | + for duthost, (key, fields) in zip(duthosts, ha_scope_per_dut): |
| 475 | + proto_utils_hset( |
| 476 | + duthost, |
| 477 | + table="DASH_HA_SCOPE_CONFIG_TABLE", |
| 478 | + key=key, |
| 479 | + args=build_dash_ha_scope_args(fields), |
| 480 | + ) |
| 481 | + |
| 482 | + |
| 483 | +@pytest.fixture(scope="module") |
| 484 | +def activate_dash_ha_from_json(duthosts): |
| 485 | + # ------------------------------------------------- |
| 486 | + # Step 4: Activate Role (using pending_operation_ids) |
| 487 | + # ------------------------------------------------- |
| 488 | + activate_scope_per_dut = [ |
| 489 | + ( |
| 490 | + "vdpu0_0:haset0_0", |
| 491 | + { |
| 492 | + "version": "1", |
| 493 | + "disabled": False, |
| 494 | + "desired_ha_state": "active", |
| 495 | + "ha_set_id": "haset0_0", |
| 496 | + "owner": "dpu", |
| 497 | + }, |
| 498 | + ), |
| 499 | + ( |
| 500 | + "vdpu1_0:haset0_0", |
| 501 | + { |
| 502 | + "version": "1", |
| 503 | + "disabled": False, |
| 504 | + "desired_ha_state": "unspecified", |
| 505 | + "ha_set_id": "haset0_0", |
| 506 | + "owner": "dpu", |
| 507 | + }, |
| 508 | + ), |
| 509 | + ] |
| 510 | + for duthost, (key, fields) in zip(duthosts, activate_scope_per_dut): |
| 511 | + proto_utils_hset( |
| 512 | + duthost, |
| 513 | + table="DASH_HA_SCOPE_CONFIG_TABLE", |
| 514 | + key=key, |
| 515 | + args=build_dash_ha_scope_args(fields), |
| 516 | + ) |
| 517 | + for idx, (duthost, (key, fields)) in enumerate(zip(duthosts, activate_scope_per_dut)): |
| 518 | + pending_id = wait_for_pending_operation_id( |
| 519 | + duthost, |
| 520 | + scope_key=key, |
| 521 | + expected_op_type="activate_role", |
| 522 | + timeout=120, |
| 523 | + interval=2 |
| 524 | + ) |
| 525 | + assert pending_id, ( |
| 526 | + f"Timed out waiting for active pending_operation_id " |
| 527 | + f"for {duthost.hostname} scope {key}" |
| 528 | + ) |
| 529 | + |
| 530 | + logger.info(f"DASH HA {duthost.hostname} found pending id {pending_id}") |
| 531 | + proto_utils_hset( |
| 532 | + duthost, |
| 533 | + table="DASH_HA_SCOPE_CONFIG_TABLE", |
| 534 | + key=key, |
| 535 | + args=build_dash_ha_scope_activate_args(fields, pending_id), |
| 536 | + ) |
| 537 | + # Verify HA state using fields |
| 538 | + expected_state = "active" if idx == 0 else "standby" |
| 539 | + assert wait_for_ha_state( |
| 540 | + duthost, |
| 541 | + scope_key=key, |
| 542 | + expected_state=expected_state, |
| 543 | + timeout=120, |
| 544 | + interval=5, |
| 545 | + ), f"HA did not reach expected state {expected_state} for {key} on {duthost.hostname}" |
| 546 | + logger.info(f"DASH HA Step-4 Activate Role completed for {duthost.hostname}") |
| 547 | + logger.info("DASH HA Step-4 Activate Role completed") |
| 548 | + yield |
0 commit comments