diff --git a/.zuul.yaml b/.zuul.yaml index 6e3fcd70..145287f0 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -140,6 +140,37 @@ pre-run: playbooks/pre.yml run: playbooks/test-integration.yml +# End-to-end golden test for the SONiC config generator: provisions NetBox +# with a docker compose stack, seeds it from the in-repo fixtures under +# tests/e2e/scenario/, runs sync_sonic() and compares the exported config_db +# files against tests/e2e/golden/. In check the job only runs when files +# that can change the generated output (or the harness itself) are touched; +# periodic-daily runs it unconditionally. netbox-manager is still pulled at +# tip-of-main via required-projects because it remains the seeding tool, so +# a Depends-On is honored for its code -- but its example/ seed data is no +# longer used, so this job no longer detects drift in that data. +- job: + name: python-osism-sonic-e2e + nodeset: ubuntu-noble + pre-run: playbooks/pre-sonic-e2e.yml + run: playbooks/test-sonic-e2e.yml + required-projects: + - osism/netbox-manager + timeout: 2400 + files: + - ^\.zuul\.yaml$ + - ^Makefile$ + - ^Pipfile\.lock$ + - ^files/sonic/.* + - ^osism/settings\.py$ + - ^osism/tasks/conductor/.* + - ^osism/utils/.* + - ^playbooks/(pre-|test-)sonic-e2e\.yml$ + - ^requirements\.ansible\.txt$ + - ^requirements\.txt$ + - ^setup\.cfg$ + - ^tests/e2e/.* + - project: merge-mode: squash-merge default-branch: main @@ -154,6 +185,7 @@ - python-osism-test-setup - python-osism-unit-tests - python-osism-integration-tests + - python-osism-sonic-e2e periodic-daily: jobs: - flake8 @@ -163,6 +195,7 @@ - python-osism-test-setup - python-osism-unit-tests - python-osism-integration-tests + - python-osism-sonic-e2e periodic-midnight: jobs: - container-image-python-osism-push diff --git a/Makefile b/Makefile index 05a6a103..0ac8b869 100644 --- a/Makefile +++ b/Makefile @@ -21,4 +21,10 @@ sonic-e2e-up: sonic-e2e-down: docker compose -f tests/e2e/compose.yaml down --volumes --remove-orphans -.PHONY: sonic-e2e sonic-e2e-regen sonic-e2e-up sonic-e2e-down +# Report config_db table coverage of the golden set (tests/e2e/coverage.py). +# A reporting tool only -- not part of the gating check, which stays the +# golden comparison run by sonic-e2e above. +sonic-e2e-coverage: + pipenv run python -m tests.e2e.coverage + +.PHONY: sonic-e2e sonic-e2e-regen sonic-e2e-up sonic-e2e-down sonic-e2e-coverage diff --git a/README.md b/README.md index 1c9cea93..916a16f0 100644 --- a/README.md +++ b/README.md @@ -44,3 +44,60 @@ REDIS_HOST=localhost REDIS_DB=15 pipenv run pytest tests/integration > above, or `OSISM_ALLOW_DEFAULT_REDIS_DB=1` if the Redis itself is disposable. > `REDIS_DB` moves the direct client, the Celery broker and the result backend > together. + +## Running the SONiC E2E golden test + +The end-to-end test in `tests/e2e/` provisions NetBox with a docker compose +stack, seeds it from the fixtures in `tests/e2e/scenario/`, generates the SONiC +`config_db.json` files and compares them against the goldens in +`tests/e2e/golden/`. Besides the development dependencies it needs docker with +the compose plugin, `openssl`, and a `netbox-manager` checkout for the seeding +CLI — a sibling directory by default, `NETBOX_MANAGER_DIR` otherwise. + +``` +pipenv install --dev +make sonic-e2e +``` + +A cold run takes roughly ten minutes, most of it starting NetBox. To iterate +without paying that each time, bring the stack up separately and leave it +running: + +``` +make sonic-e2e-up # start NetBox and leave it up; sonic-e2e reuses it +make sonic-e2e-down # stop it again and remove its volumes +``` + +After an intentional generator change, rewrite the goldens and review the diff +before committing it. Regeneration deliberately refuses to run against a stack +left over from an earlier run, because applying the fixtures over a populated +database can produce goldens that CI — which always starts fresh — would not +reproduce: + +``` +make sonic-e2e-down +make sonic-e2e-regen +``` + +How much of the generated config the golden set actually covers is reported +separately, because nothing in CI reports it: + +``` +make sonic-e2e-coverage +``` + +That compares the `config_db` tables the generator can emit against the tables +that are non-empty in at least one golden, and names any that no golden covers. +It exits non-zero while that list is non-empty, so it is worth running after +adding a scenario to confirm the new tables landed. It gates nothing on its own +— the golden comparison above is the only check that fails a run. + +`tests/e2e/sonic_golden_test.sh` documents the remaining environment overrides +(`NETBOX_PORT`, `KEEP_STACK`, `SEED_PARALLEL` and the regeneration escape +hatch). + +> **Warning:** Seeding applies *every* file under +> `tests/e2e/scenario/resources/`, tracked or not, so a stray file there joins +> the fixture set — which either breaks the run or silently changes the +> goldens. Check that directory with `git status --ignored` before regenerating +> or debugging a mismatch. diff --git a/playbooks/pre-sonic-e2e.yml b/playbooks/pre-sonic-e2e.yml new file mode 100644 index 00000000..5aa7e7a4 --- /dev/null +++ b/playbooks/pre-sonic-e2e.yml @@ -0,0 +1,74 @@ +--- +# Node preparation for the SONiC config-generation E2E golden test. +# +# The test's NetBox fixture is a docker compose stack (tests/e2e/compose.yaml), +# so the node only needs Docker: ensure-docker installs docker-compose-plugin +# along with docker-ce. No kind, kubectl or helm. netbox-manager's own E2E job +# still provisions NetBox on kind, so there is nothing to keep in sync here. +- name: Prepare the SONiC E2E node + hosts: all + + pre_tasks: + # This CI node is IPv6-only and learns its address and default route via + # SLAAC / Router Advertisements. If Docker enables + # net.ipv6.conf.all.forwarding=1, the kernel stops honouring RAs at the + # default accept_ra=1, so the SLAAC default route expires and the node + # drops off the network a few minutes into the run. accept_ra=2 keeps RAs + # honoured even while forwarding is on, preserving the default route. + # Compose's default bridge network is IPv4-only, so Docker probably will + # not turn on IPv6 forwarding here -- but this guard is cheap insurance + # against a severe failure mode (an unreachable CI node) and is kept + # deliberately; removing it should be its own separate experiment, not a + # side effect of some other change. Set it here -- before Docker enables + # forwarding -- so the route never lapses. See + # https://docs.docker.com/engine/daemon/ipv6/ and + # https://forums.docker.com/t/docker-removes-host-ipv6-default-route/83238 + - name: Keep accepting IPv6 RAs after Docker enables forwarding (preserve default route) + become: true + ansible.builtin.copy: + dest: /etc/sysctl.d/99-sonic-e2e-accept-ra.conf + owner: root + group: root + mode: "0644" + content: | + net.ipv6.conf.all.accept_ra = 2 + net.ipv6.conf.default.accept_ra = 2 + {% if ansible_default_ipv6.interface is defined %} + net.ipv6.conf.{{ ansible_default_ipv6.interface }}.accept_ra = 2 + {% endif %} + + - name: Apply the accept_ra sysctl settings now + become: true + ansible.builtin.command: + cmd: sysctl -p /etc/sysctl.d/99-sonic-e2e-accept-ra.conf + changed_when: true + # A node without an ansible_default_ipv6.interface fact (or otherwise + # missing these IPv6 keys) fails sysctl -p; this is best-effort + # insurance for the common IPv6-only case, not a hard requirement, so + # do not fail pre-run over it. + failed_when: false + + roles: + - ensure-pip + - ensure-pipenv + - ensure-docker + + tasks: + - name: Ensure the Docker service is running + become: true + ansible.builtin.service: + name: docker + state: started + enabled: true + + # openssl is used by tests/e2e/sonic_golden_test.sh directly. curl is used + # by the NetBox container's healthcheck rather than by the script itself, + # but ensure-docker needs it anyway. python3-venv provides the venv module + # the script uses for the seeding venv. + - name: Install required packages + become: true + ansible.builtin.apt: + name: + - curl + - openssl + - python3-venv diff --git a/playbooks/test-sonic-e2e.yml b/playbooks/test-sonic-e2e.yml new file mode 100644 index 00000000..ab8ebfc0 --- /dev/null +++ b/playbooks/test-sonic-e2e.yml @@ -0,0 +1,40 @@ +--- +- name: Run the SONiC config-generation E2E golden test + hosts: all + + vars: + python_venv_dir: /tmp/venv + + tasks: + - name: Install dependencies + ansible.builtin.shell: + executable: /bin/bash + chdir: "{{ zuul.project.src_dir }}" + cmd: | + set -e + set -o pipefail + set -x + + {{ python_venv_dir }}/bin/pipenv install --dev --deploy + {{ python_venv_dir }}/bin/pipenv run pip install . + + - name: Run the E2E golden test + ansible.builtin.shell: + executable: /bin/bash + chdir: "{{ zuul.project.src_dir }}" + cmd: | + set -e + set -o pipefail + set -x + + # The script invokes bare `pipenv`; the netbox-manager checkout comes + # from Zuul's required-projects, so a Depends-On change to it is + # tested against the changed code and seed data. + export PATH="{{ python_venv_dir }}/bin:${PATH}" + export NETBOX_MANAGER_DIR="{{ ansible_user_dir }}/{{ zuul.projects['github.com/osism/netbox-manager'].src_dir }}" + + # Serial by default: concurrent seeding deadlocks on dcim_device FK + # row locks (see tests/e2e/sonic_golden_test.sh, Phase 2). Set + # `sonic_e2e_seed_parallel: 4` in the job vars to opt back in. + export SEED_PARALLEL="{{ sonic_e2e_seed_parallel | default(1) }}" + tests/e2e/sonic_golden_test.sh diff --git a/tests/e2e/coverage.py b/tests/e2e/coverage.py new file mode 100644 index 00000000..a9aded4e --- /dev/null +++ b/tests/e2e/coverage.py @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: Apache-2.0 + +"""config_db table coverage report for the SONiC E2E golden set. + +This is a reporting tool, not a gate: it is not invoked from +sonic_golden_test.sh, and the golden comparison (tests/e2e/compare.py) +remains the only check that actually fails a run. It exists so the "N of M +config_db tables covered" claim made when the golden set is extended can be +re-derived by anyone, at any time, instead of only having existed as an +ad-hoc one-off script run once during development. + +It works in two independent steps: + +1. Derive the set of tables the generator can emit by grepping + osism/tasks/conductor/sonic/ (excluding the generated schema package, + _generated/, which is data rather than emission logic) for direct + ``config["TABLE"]``/``cfg["TABLE"]`` assignments -- including a nested + item assignment such as ``config["ACL_TABLE"]["SSH_ONLY"] = ...`` or a + ``.update(...)`` call, but not a mere read such as + ``"x" in config["VERSIONS"]``. This is a static, syntactic approximation + of "tables the generator can populate", not a guarantee every branch + that reaches it is exercised. +2. Collect the set of tables that are non-empty in at least one file under + tests/e2e/golden/*.json. + +The report prints both counts and, if any emitted table is never non-empty +across the golden set, lists them and exits 1. +""" + +import re +import sys +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[2] +GENERATOR_DIR = REPO_ROOT / "osism" / "tasks" / "conductor" / "sonic" +GOLDEN_DIR = REPO_ROOT / "tests" / "e2e" / "golden" + +# Matches config["TABLE"] or cfg["TABLE"], optionally followed by one or +# more ["key"]/[expr] accessors, then either an assignment ("=" but not +# "==") or a .update(...) call -- i.e. the table is a write target, not +# merely read. +_TABLE_ASSIGNMENT_RE = re.compile( + r'(?:config|cfg)\["([A-Z][A-Z0-9_]*)"\](?:\[[^\]]*\])*\s*(?:=(?!=)|\.update\()' +) + + +def emitted_tables(generator_dir=GENERATOR_DIR): + """Tables the generator can emit, derived from source assignments.""" + tables = set() + for path in sorted(Path(generator_dir).rglob("*.py")): + if "_generated" in path.parts: + continue + for line in path.read_text().splitlines(): + if line.lstrip().startswith("#"): + continue + for match in _TABLE_ASSIGNMENT_RE.finditer(line): + tables.add(match.group(1)) + return tables + + +def covered_tables(golden_dir=GOLDEN_DIR): + """Tables that are non-empty in at least one golden file.""" + import json + + tables = set() + for path in sorted(Path(golden_dir).glob("*.json")): + config = json.loads(path.read_text()) + for table, value in config.items(): + if value: + tables.add(table) + return tables + + +def main(argv=None): + emitted = emitted_tables() + covered = covered_tables() + missing = sorted(emitted - covered) + + print(f"generator emits {len(emitted)} tables; {len(covered)} non-empty") + if missing: + print("not covered by any golden file:") + for table in missing: + print(f" {table}") + return 1 + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tests/e2e/golden/osism_e2e-leaf-1_config_db.json b/tests/e2e/golden/osism_e2e-leaf-1_config_db.json new file mode 100644 index 00000000..b34178d6 --- /dev/null +++ b/tests/e2e/golden/osism_e2e-leaf-1_config_db.json @@ -0,0 +1,698 @@ +{ + "ACL_RULE": { + "GNMI_ONLY|RULE_1": { + "IP_TYPE": "IP", + "L4_DST_PORT": "8080", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9999", + "SRC_IP": "172.16.0.0/20" + }, + "SNMP_ONLY|RULE_1": { + "IP_TYPE": "IP", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9999", + "SRC_IP": "172.16.0.0/20" + }, + "SSH_ONLY|RULE_1": { + "IP_TYPE": "IP", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9999", + "SRC_IP": "172.16.0.0/20" + } + }, + "ACL_TABLE": { + "GNMI_ONLY": { + "policy_desc": "GNMI_ONLY", + "services": [ + "EXTERNAL_CLIENT" + ], + "type": "CTRLPLANE" + }, + "SNMP_ONLY": { + "policy_desc": "SNMP_ONLY", + "services": [ + "SNMP" + ], + "type": "CTRLPLANE" + }, + "SSH_ONLY": { + "policy_desc": "SSH_ONLY", + "services": [ + "SSH" + ], + "type": "CTRLPLANE" + } + }, + "BGP_GLOBALS": { + "default": { + "always_compare_med": "true", + "ebgp_requires_policy": "false", + "external_compare_router_id": "false", + "fast_external_failover": "true", + "holdtime": "180", + "ignore_as_path_length": "false", + "keepalive": "60", + "load_balance_mp_relax": "false", + "local_asn": "4200020011", + "log_nbr_state_changes": "true", + "network_import_check": "true", + "router_id": "192.168.20.11" + } + }, + "BGP_GLOBALS_AF": { + "default|ipv4_unicast": { + "ibgp_equal_cluster_length": "false", + "max_ebgp_paths": "2", + "max_ibgp_paths": "2", + "route_flap_dampen": "false" + }, + "default|ipv6_unicast": { + "ibgp_equal_cluster_length": "false", + "max_ebgp_paths": "2", + "max_ibgp_paths": "2" + }, + "default|l2vpn_evpn": { + "advertise-all-vni": "true", + "advertise-svi-ip": "true", + "dad-enabled": "true" + } + }, + "BGP_GLOBALS_AF_NETWORK": { + "default|ipv4_unicast|192.168.20.11/32": {} + }, + "BGP_GLOBALS_ROUTE_ADVERTISE": { + "default|L2VPN_EVPN|IPV4_UNICAST": {}, + "default|L2VPN_EVPN|IPV6_UNICAST": {} + }, + "BGP_NEIGHBOR": { + "default|192.168.30.0": { + "local_addr": "192.168.30.1", + "peer_type": "external", + "v6only": "false" + } + }, + "BGP_NEIGHBOR_AF": { + "default|Ethernet0|ipv4_unicast": { + "admin_status": "true" + }, + "default|Ethernet0|l2vpn_evpn": { + "admin_status": "true" + } + }, + "BREAKOUT_CFG": {}, + "BREAKOUT_PORTS": {}, + "DEVICE_METADATA": { + "localhost": { + "hostname": "e2e-leaf-1", + "hwsku": "Accton-AS7726-32X", + "mac": "00:00:00:00:00:00", + "platform": "x86_64-accton_as7726_32x-r0" + } + }, + "DNS_NAMESERVER": { + "172.16.10.254": {} + }, + "INTERFACE": { + "Ethernet0": {}, + "Ethernet0|192.168.30.1/31": {} + }, + "LOOPBACK": { + "Loopback0": { + "admin_status": "up" + } + }, + "LOOPBACK_INTERFACE": { + "Loopback0": {}, + "Loopback0|192.168.20.11/32": {} + }, + "MGMT_INTERFACE": { + "eth0": { + "admin_status": "up" + }, + "eth0|172.16.10.11/20": {} + }, + "NTP_SERVER": { + "172.16.10.254": { + "maxpoll": "10", + "minpoll": "6", + "prefer": "false" + } + }, + "PORT": { + "Ethernet0": { + "admin_status": "up", + "adv_speeds": "all", + "alias": "Eth1/1", + "autoneg": "off", + "index": "1", + "lanes": "1,2,3,4", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet100": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/26", + "autoneg": "off", + "index": "26", + "lanes": "101,102,103,104", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet104": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/27", + "autoneg": "off", + "index": "27", + "lanes": "105,106,107,108", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet108": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/28", + "autoneg": "off", + "index": "28", + "lanes": "109,110,111,112", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet112": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/29", + "autoneg": "off", + "index": "29", + "lanes": "113,114,115,116", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet116": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/30", + "autoneg": "off", + "index": "30", + "lanes": "117,118,119,120", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet12": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/4", + "autoneg": "off", + "index": "4", + "lanes": "13,14,15,16", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "tagged_vlans": [ + "200" + ], + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet120": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/31", + "autoneg": "off", + "index": "31", + "lanes": "121,122,123,124", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet124": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/32", + "autoneg": "off", + "index": "32", + "lanes": "125,126,127,128", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet125": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/33", + "autoneg": "off", + "index": "33", + "lanes": "129", + "link_training": "off", + "mtu": "9100", + "speed": "10000", + "unreliable_los": "auto", + "valid_speeds": "10000,1000" + }, + "Ethernet126": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/34", + "autoneg": "off", + "index": "34", + "lanes": "128", + "link_training": "off", + "mtu": "9100", + "speed": "10000", + "unreliable_los": "auto", + "valid_speeds": "10000,1000" + }, + "Ethernet16": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/5", + "autoneg": "off", + "index": "5", + "lanes": "17,18,19,20", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet20": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/6", + "autoneg": "off", + "index": "6", + "lanes": "21,22,23,24", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet24": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/7", + "autoneg": "off", + "index": "7", + "lanes": "25,26,27,28", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet28": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/8", + "autoneg": "off", + "index": "8", + "lanes": "29,30,31,32", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet32": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/9", + "autoneg": "off", + "index": "9", + "lanes": "33,34,35,36", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet36": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/10", + "autoneg": "off", + "index": "10", + "lanes": "37,38,39,40", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet4": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/2", + "autoneg": "off", + "index": "2", + "lanes": "5,6,7,8", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet40": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/11", + "autoneg": "off", + "index": "11", + "lanes": "41,42,43,44", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet44": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/12", + "autoneg": "off", + "index": "12", + "lanes": "45,46,47,48", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet48": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/13", + "autoneg": "off", + "index": "13", + "lanes": "49,50,51,52", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet52": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/14", + "autoneg": "off", + "index": "14", + "lanes": "53,54,55,56", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet56": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/15", + "autoneg": "off", + "index": "15", + "lanes": "57,58,59,60", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet60": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/16", + "autoneg": "off", + "index": "16", + "lanes": "61,62,63,64", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet64": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/17", + "autoneg": "off", + "index": "17", + "lanes": "65,66,67,68", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet68": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/18", + "autoneg": "off", + "index": "18", + "lanes": "69,70,71,72", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet72": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/19", + "autoneg": "off", + "index": "19", + "lanes": "73,74,75,76", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet76": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/20", + "autoneg": "off", + "index": "20", + "lanes": "77,78,79,80", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet8": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/3", + "autoneg": "off", + "index": "3", + "lanes": "9,10,11,12", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet80": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/21", + "autoneg": "off", + "index": "21", + "lanes": "81,82,83,84", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet84": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/22", + "autoneg": "off", + "index": "22", + "lanes": "85,86,87,88", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet88": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/23", + "autoneg": "off", + "index": "23", + "lanes": "89,90,91,92", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet92": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/24", + "autoneg": "off", + "index": "24", + "lanes": "93,94,95,96", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet96": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/25", + "autoneg": "off", + "index": "25", + "lanes": "97,98,99,100", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + } + }, + "PORTCHANNEL": {}, + "PORTCHANNEL_INTERFACE": {}, + "PORTCHANNEL_MEMBER": {}, + "ROUTE_REDISTRIBUTE": { + "default|connected|bgp|ipv4": {}, + "default|connected|bgp|ipv6": {} + }, + "SNMP_AGENT_ADDRESS_CONFIG": { + "172.16.10.11|161|mgmt": { + "name": "agentEntry1" + } + }, + "SNMP_SERVER": { + "SYSTEM": { + "sysContact": "e2e@example.com", + "sysLocation": "E2E Lab", + "traps": "enable" + } + }, + "SNMP_SERVER_GROUP_MEMBER": { + "monitoring|e2e-monitor": { + "securityModel": [ + "usm" + ] + } + }, + "SNMP_SERVER_PARAMS": { + "targetEntry1": { + "security-level": "auth-priv", + "user": "e2e-monitor" + } + }, + "SNMP_SERVER_TARGET": { + "targetEntry1": { + "ip": "172.16.10.254", + "port": "162", + "retries": "3", + "tag": [ + "trapNotify", + "mgmt" + ], + "targetParams": "targetEntry1", + "timeout": "1500" + } + }, + "SNMP_SERVER_USER": { + "e2e-monitor": { + "aesKey": "OBFUSCATEDPRIVSECRET", + "shaKey": "OBFUSCATEDAUTHSECRET" + } + }, + "STATIC_ROUTE": { + "mgmt|0.0.0.0/0": { + "nexthop": "172.16.10.254" + } + }, + "SYSLOG_SERVER": { + "172.16.10.254": { + "message-type": "log", + "protocol": "UDP", + "remote-port": "514", + "severity": "info", + "vrf_name": "mgmt" + } + }, + "VERSIONS": { + "DATABASE": { + "VERSION": "version_4_0_1" + } + }, + "VLAN": { + "Vlan100": { + "admin_status": "up", + "autostate": "enable", + "members": [ + "Ethernet8" + ], + "vlanid": "100" + }, + "Vlan200": { + "admin_status": "up", + "autostate": "enable", + "members": [ + "Ethernet12" + ], + "vlanid": "200" + } + }, + "VLAN_INTERFACE": { + "Vlan200": { + "admin_status": "up" + }, + "Vlan200|192.168.40.1/24": {} + }, + "VLAN_MEMBER": { + "Vlan100|Ethernet8": { + "tagging_mode": "untagged" + }, + "Vlan200|Ethernet12": { + "tagging_mode": "tagged" + } + }, + "VRF": { + "default": { + "enabled": "true" + } + }, + "VXLAN_EVPN_NVO": {}, + "VXLAN_TUNNEL": {}, + "VXLAN_TUNNEL_MAP": {} +} diff --git a/tests/e2e/golden/osism_e2e-leaf-2_config_db.json b/tests/e2e/golden/osism_e2e-leaf-2_config_db.json new file mode 100644 index 00000000..1d52120d --- /dev/null +++ b/tests/e2e/golden/osism_e2e-leaf-2_config_db.json @@ -0,0 +1,683 @@ +{ + "ACL_RULE": { + "GNMI_ONLY|RULE_1": { + "IP_TYPE": "IP", + "L4_DST_PORT": "8080", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9999", + "SRC_IP": "172.16.0.0/20" + }, + "SNMP_ONLY|RULE_1": { + "IP_TYPE": "IP", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9999", + "SRC_IP": "172.16.0.0/20" + }, + "SSH_ONLY|RULE_1": { + "IP_TYPE": "IP", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9999", + "SRC_IP": "172.16.0.0/20" + } + }, + "ACL_TABLE": { + "GNMI_ONLY": { + "policy_desc": "GNMI_ONLY", + "services": [ + "EXTERNAL_CLIENT" + ], + "type": "CTRLPLANE" + }, + "SNMP_ONLY": { + "policy_desc": "SNMP_ONLY", + "services": [ + "SNMP" + ], + "type": "CTRLPLANE" + }, + "SSH_ONLY": { + "policy_desc": "SSH_ONLY", + "services": [ + "SSH" + ], + "type": "CTRLPLANE" + } + }, + "BGP_GLOBALS": { + "Vrf99": { + "always_compare_med": "true", + "ebgp_requires_policy": "false", + "external_compare_router_id": "false", + "fast_external_failover": "true", + "holdtime": "180", + "ignore_as_path_length": "false", + "keepalive": "60", + "load_balance_mp_relax": "false", + "local_asn": "4200020012", + "log_nbr_state_changes": "true", + "network_import_check": "true", + "router_id": "192.168.20.12" + }, + "default": { + "always_compare_med": "true", + "ebgp_requires_policy": "false", + "external_compare_router_id": "false", + "fast_external_failover": "true", + "holdtime": "180", + "ignore_as_path_length": "false", + "keepalive": "60", + "load_balance_mp_relax": "false", + "local_asn": "4200020012", + "log_nbr_state_changes": "true", + "network_import_check": "true", + "router_id": "192.168.20.12" + } + }, + "BGP_GLOBALS_AF": { + "default|ipv4_unicast": { + "ibgp_equal_cluster_length": "false", + "max_ebgp_paths": "2", + "max_ibgp_paths": "2", + "route_flap_dampen": "false" + }, + "default|ipv6_unicast": { + "ibgp_equal_cluster_length": "false", + "max_ebgp_paths": "2", + "max_ibgp_paths": "2" + }, + "default|l2vpn_evpn": { + "advertise-all-vni": "true", + "advertise-svi-ip": "true", + "dad-enabled": "true" + } + }, + "BGP_GLOBALS_AF_NETWORK": { + "default|ipv4_unicast|192.168.20.12/32": {} + }, + "BGP_GLOBALS_ROUTE_ADVERTISE": { + "default|L2VPN_EVPN|IPV4_UNICAST": {}, + "default|L2VPN_EVPN|IPV6_UNICAST": {} + }, + "BGP_NEIGHBOR": { + "default|192.168.30.2": { + "local_addr": "192.168.30.3", + "peer_type": "external", + "v6only": "false" + } + }, + "BGP_NEIGHBOR_AF": { + "default|Ethernet0|ipv4_unicast": { + "admin_status": "true" + }, + "default|Ethernet0|l2vpn_evpn": { + "admin_status": "true" + } + }, + "BREAKOUT_CFG": {}, + "BREAKOUT_PORTS": {}, + "DEVICE_METADATA": { + "localhost": { + "hostname": "e2e-leaf-2", + "hwsku": "Accton-AS7726-32X", + "mac": "00:00:00:00:00:00", + "platform": "x86_64-accton_as7726_32x-r0" + } + }, + "DNS_NAMESERVER": { + "172.16.10.254": {} + }, + "INTERFACE": { + "Ethernet0": {}, + "Ethernet0|192.168.30.3/31": {} + }, + "LOOPBACK": { + "Loopback0": { + "admin_status": "up" + } + }, + "LOOPBACK_INTERFACE": { + "Loopback0": {}, + "Loopback0|192.168.20.12/32": {} + }, + "MGMT_INTERFACE": { + "eth0": { + "admin_status": "up" + }, + "eth0|172.16.10.12/20": {} + }, + "NTP_SERVER": { + "172.16.10.254": { + "maxpoll": "10", + "minpoll": "6", + "prefer": "false" + } + }, + "PORT": { + "Ethernet0": { + "admin_status": "up", + "adv_speeds": "all", + "alias": "Eth1/1", + "autoneg": "off", + "index": "1", + "lanes": "1,2,3,4", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet100": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/26", + "autoneg": "off", + "index": "26", + "lanes": "101,102,103,104", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet104": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/27", + "autoneg": "off", + "index": "27", + "lanes": "105,106,107,108", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet108": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/28", + "autoneg": "off", + "index": "28", + "lanes": "109,110,111,112", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet112": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/29", + "autoneg": "off", + "index": "29", + "lanes": "113,114,115,116", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet116": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/30", + "autoneg": "off", + "index": "30", + "lanes": "117,118,119,120", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet12": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/4", + "autoneg": "off", + "index": "4", + "lanes": "13,14,15,16", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet120": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/31", + "autoneg": "off", + "index": "31", + "lanes": "121,122,123,124", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet124": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/32", + "autoneg": "off", + "index": "32", + "lanes": "125,126,127,128", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet125": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/33", + "autoneg": "off", + "index": "33", + "lanes": "129", + "link_training": "off", + "mtu": "9100", + "speed": "10000", + "unreliable_los": "auto", + "valid_speeds": "10000,1000" + }, + "Ethernet126": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/34", + "autoneg": "off", + "index": "34", + "lanes": "128", + "link_training": "off", + "mtu": "9100", + "speed": "10000", + "unreliable_los": "auto", + "valid_speeds": "10000,1000" + }, + "Ethernet16": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/5", + "autoneg": "off", + "index": "5", + "lanes": "17,18,19,20", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet20": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/6", + "autoneg": "off", + "index": "6", + "lanes": "21,22,23,24", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet24": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/7", + "autoneg": "off", + "index": "7", + "lanes": "25,26,27,28", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet28": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/8", + "autoneg": "off", + "index": "8", + "lanes": "29,30,31,32", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet32": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/9", + "autoneg": "off", + "index": "9", + "lanes": "33,34,35,36", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet36": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/10", + "autoneg": "off", + "index": "10", + "lanes": "37,38,39,40", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet4": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/2", + "autoneg": "off", + "index": "2", + "lanes": "5,6,7,8", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet40": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/11", + "autoneg": "off", + "index": "11", + "lanes": "41,42,43,44", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet44": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/12", + "autoneg": "off", + "index": "12", + "lanes": "45,46,47,48", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet48": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/13", + "autoneg": "off", + "index": "13", + "lanes": "49,50,51,52", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet52": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/14", + "autoneg": "off", + "index": "14", + "lanes": "53,54,55,56", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet56": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/15", + "autoneg": "off", + "index": "15", + "lanes": "57,58,59,60", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet60": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/16", + "autoneg": "off", + "index": "16", + "lanes": "61,62,63,64", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet64": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/17", + "autoneg": "off", + "index": "17", + "lanes": "65,66,67,68", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet68": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/18", + "autoneg": "off", + "index": "18", + "lanes": "69,70,71,72", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet72": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/19", + "autoneg": "off", + "index": "19", + "lanes": "73,74,75,76", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet76": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/20", + "autoneg": "off", + "index": "20", + "lanes": "77,78,79,80", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet8": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/3", + "autoneg": "off", + "index": "3", + "lanes": "9,10,11,12", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet80": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/21", + "autoneg": "off", + "index": "21", + "lanes": "81,82,83,84", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet84": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/22", + "autoneg": "off", + "index": "22", + "lanes": "85,86,87,88", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet88": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/23", + "autoneg": "off", + "index": "23", + "lanes": "89,90,91,92", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet92": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/24", + "autoneg": "off", + "index": "24", + "lanes": "93,94,95,96", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet96": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/25", + "autoneg": "off", + "index": "25", + "lanes": "97,98,99,100", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + } + }, + "PORTCHANNEL": {}, + "PORTCHANNEL_INTERFACE": {}, + "PORTCHANNEL_MEMBER": {}, + "ROUTE_REDISTRIBUTE": { + "default|connected|bgp|ipv4": {}, + "default|connected|bgp|ipv6": {} + }, + "SNMP_AGENT_ADDRESS_CONFIG": { + "172.16.10.12|161|mgmt": { + "name": "agentEntry1" + } + }, + "SNMP_SERVER": { + "SYSTEM": { + "sysContact": "e2e@example.com", + "sysLocation": "E2E Lab", + "traps": "enable" + } + }, + "SNMP_SERVER_GROUP_MEMBER": { + "monitoring|e2e-monitor": { + "securityModel": [ + "usm" + ] + } + }, + "SNMP_SERVER_PARAMS": { + "targetEntry1": { + "security-level": "auth-priv", + "user": "e2e-monitor" + } + }, + "SNMP_SERVER_TARGET": { + "targetEntry1": { + "ip": "172.16.10.254", + "port": "162", + "retries": "3", + "tag": [ + "trapNotify", + "mgmt" + ], + "targetParams": "targetEntry1", + "timeout": "1500" + } + }, + "SNMP_SERVER_USER": { + "e2e-monitor": { + "aesKey": "OBFUSCATEDPRIVSECRET", + "shaKey": "OBFUSCATEDAUTHSECRET" + } + }, + "STATIC_ROUTE": { + "mgmt|0.0.0.0/0": { + "nexthop": "172.16.10.254" + } + }, + "SYSLOG_SERVER": { + "172.16.10.254": { + "message-type": "log", + "protocol": "UDP", + "remote-port": "514", + "severity": "info", + "vrf_name": "mgmt" + } + }, + "VERSIONS": { + "DATABASE": { + "VERSION": "version_4_0_1" + } + }, + "VLAN": {}, + "VLAN_INTERFACE": {}, + "VLAN_MEMBER": {}, + "VRF": { + "Vrf99": { + "vrf_table_id": 99 + }, + "default": { + "enabled": "true" + } + }, + "VXLAN_EVPN_NVO": {}, + "VXLAN_TUNNEL": {}, + "VXLAN_TUNNEL_MAP": {} +} diff --git a/tests/e2e/golden/osism_e2e-oob-1_config_db.json b/tests/e2e/golden/osism_e2e-oob-1_config_db.json new file mode 100644 index 00000000..e48a309f --- /dev/null +++ b/tests/e2e/golden/osism_e2e-oob-1_config_db.json @@ -0,0 +1,650 @@ +{ + "ACL_RULE": { + "GNMI_ONLY|RULE_1": { + "IP_TYPE": "IP", + "L4_DST_PORT": "8080", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9999", + "SRC_IP": "172.16.0.0/20" + }, + "SNMP_ONLY|RULE_1": { + "IP_TYPE": "IP", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9999", + "SRC_IP": "172.16.0.0/20" + }, + "SSH_ONLY|RULE_1": { + "IP_TYPE": "IP", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9999", + "SRC_IP": "172.16.0.0/20" + } + }, + "ACL_TABLE": { + "GNMI_ONLY": { + "policy_desc": "GNMI_ONLY", + "services": [ + "EXTERNAL_CLIENT" + ], + "type": "CTRLPLANE" + }, + "SNMP_ONLY": { + "policy_desc": "SNMP_ONLY", + "services": [ + "SNMP" + ], + "type": "CTRLPLANE" + }, + "SSH_ONLY": { + "policy_desc": "SSH_ONLY", + "services": [ + "SSH" + ], + "type": "CTRLPLANE" + } + }, + "BGP_GLOBALS": { + "default": { + "always_compare_med": "true", + "ebgp_requires_policy": "false", + "external_compare_router_id": "false", + "fast_external_failover": "true", + "holdtime": "180", + "ignore_as_path_length": "false", + "keepalive": "60", + "load_balance_mp_relax": "false", + "local_asn": "4200020021", + "log_nbr_state_changes": "true", + "network_import_check": "true", + "router_id": "192.168.20.21" + } + }, + "BGP_GLOBALS_AF": { + "default|ipv4_unicast": { + "ibgp_equal_cluster_length": "false", + "max_ebgp_paths": "2", + "max_ibgp_paths": "2", + "route_flap_dampen": "false" + }, + "default|ipv6_unicast": { + "ibgp_equal_cluster_length": "false", + "max_ebgp_paths": "2", + "max_ibgp_paths": "2" + }, + "default|l2vpn_evpn": { + "advertise-all-vni": "true", + "advertise-svi-ip": "true", + "dad-enabled": "true" + } + }, + "BGP_GLOBALS_AF_NETWORK": { + "default|ipv4_unicast|192.168.20.21/32": {} + }, + "BGP_GLOBALS_ROUTE_ADVERTISE": { + "default|L2VPN_EVPN|IPV4_UNICAST": {}, + "default|L2VPN_EVPN|IPV6_UNICAST": {} + }, + "BGP_NEIGHBOR": {}, + "BGP_NEIGHBOR_AF": {}, + "BREAKOUT_CFG": {}, + "BREAKOUT_PORTS": {}, + "DEVICE_METADATA": { + "localhost": { + "hostname": "e2e-oob-1", + "hwsku": "Accton-AS7726-32X", + "mac": "00:00:00:00:00:00", + "platform": "x86_64-accton_as7726_32x-r0" + } + }, + "DNS_NAMESERVER": { + "172.16.10.254": {} + }, + "INTERFACE": {}, + "LOOPBACK": { + "Loopback0": { + "admin_status": "up" + } + }, + "LOOPBACK_INTERFACE": { + "Loopback0": {}, + "Loopback0|192.168.20.21/32": {} + }, + "MGMT_INTERFACE": { + "eth0": { + "admin_status": "up" + }, + "eth0|172.16.10.21/20": {} + }, + "NTP_SERVER": { + "172.16.10.254": { + "maxpoll": "10", + "minpoll": "6", + "prefer": "false" + } + }, + "PORT": { + "Ethernet0": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/1", + "autoneg": "off", + "index": "1", + "lanes": "1,2,3,4", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet100": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/26", + "autoneg": "off", + "index": "26", + "lanes": "101,102,103,104", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet104": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/27", + "autoneg": "off", + "index": "27", + "lanes": "105,106,107,108", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet108": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/28", + "autoneg": "off", + "index": "28", + "lanes": "109,110,111,112", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet112": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/29", + "autoneg": "off", + "index": "29", + "lanes": "113,114,115,116", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet116": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/30", + "autoneg": "off", + "index": "30", + "lanes": "117,118,119,120", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet12": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/4", + "autoneg": "off", + "index": "4", + "lanes": "13,14,15,16", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet120": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/31", + "autoneg": "off", + "index": "31", + "lanes": "121,122,123,124", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet124": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/32", + "autoneg": "off", + "index": "32", + "lanes": "125,126,127,128", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet125": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/33", + "autoneg": "off", + "index": "33", + "lanes": "129", + "link_training": "off", + "mtu": "9100", + "speed": "10000", + "unreliable_los": "auto", + "valid_speeds": "10000,1000" + }, + "Ethernet126": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/34", + "autoneg": "off", + "index": "34", + "lanes": "128", + "link_training": "off", + "mtu": "9100", + "speed": "10000", + "unreliable_los": "auto", + "valid_speeds": "10000,1000" + }, + "Ethernet16": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/5", + "autoneg": "off", + "index": "5", + "lanes": "17,18,19,20", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet20": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/6", + "autoneg": "off", + "index": "6", + "lanes": "21,22,23,24", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet24": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/7", + "autoneg": "off", + "index": "7", + "lanes": "25,26,27,28", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet28": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/8", + "autoneg": "off", + "index": "8", + "lanes": "29,30,31,32", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet32": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/9", + "autoneg": "off", + "index": "9", + "lanes": "33,34,35,36", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet36": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/10", + "autoneg": "off", + "index": "10", + "lanes": "37,38,39,40", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet4": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/2", + "autoneg": "off", + "index": "2", + "lanes": "5,6,7,8", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet40": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/11", + "autoneg": "off", + "index": "11", + "lanes": "41,42,43,44", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet44": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/12", + "autoneg": "off", + "index": "12", + "lanes": "45,46,47,48", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet48": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/13", + "autoneg": "off", + "index": "13", + "lanes": "49,50,51,52", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet52": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/14", + "autoneg": "off", + "index": "14", + "lanes": "53,54,55,56", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet56": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/15", + "autoneg": "off", + "index": "15", + "lanes": "57,58,59,60", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet60": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/16", + "autoneg": "off", + "index": "16", + "lanes": "61,62,63,64", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet64": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/17", + "autoneg": "off", + "index": "17", + "lanes": "65,66,67,68", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet68": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/18", + "autoneg": "off", + "index": "18", + "lanes": "69,70,71,72", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet72": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/19", + "autoneg": "off", + "index": "19", + "lanes": "73,74,75,76", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet76": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/20", + "autoneg": "off", + "index": "20", + "lanes": "77,78,79,80", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet8": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/3", + "autoneg": "off", + "index": "3", + "lanes": "9,10,11,12", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet80": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/21", + "autoneg": "off", + "index": "21", + "lanes": "81,82,83,84", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet84": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/22", + "autoneg": "off", + "index": "22", + "lanes": "85,86,87,88", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet88": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/23", + "autoneg": "off", + "index": "23", + "lanes": "89,90,91,92", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet92": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/24", + "autoneg": "off", + "index": "24", + "lanes": "93,94,95,96", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet96": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/25", + "autoneg": "off", + "index": "25", + "lanes": "97,98,99,100", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + } + }, + "PORTCHANNEL": {}, + "PORTCHANNEL_INTERFACE": {}, + "PORTCHANNEL_MEMBER": {}, + "ROUTE_REDISTRIBUTE": { + "default|connected|bgp|ipv4": {}, + "default|connected|bgp|ipv6": {} + }, + "SNMP_AGENT_ADDRESS_CONFIG": { + "172.16.10.21|161|mgmt": { + "name": "agentEntry1" + } + }, + "SNMP_SERVER": { + "SYSTEM": { + "sysContact": "e2e@example.com", + "sysLocation": "E2E Lab", + "traps": "enable" + } + }, + "SNMP_SERVER_GROUP_MEMBER": { + "monitoring|e2e-monitor": { + "securityModel": [ + "usm" + ] + } + }, + "SNMP_SERVER_PARAMS": { + "targetEntry1": { + "security-level": "auth-priv", + "user": "e2e-monitor" + } + }, + "SNMP_SERVER_TARGET": { + "targetEntry1": { + "ip": "172.16.10.254", + "port": "162", + "retries": "3", + "tag": [ + "trapNotify", + "mgmt" + ], + "targetParams": "targetEntry1", + "timeout": "1500" + } + }, + "SNMP_SERVER_USER": { + "e2e-monitor": { + "aesKey": "OBFUSCATEDPRIVSECRET", + "shaKey": "OBFUSCATEDAUTHSECRET" + } + }, + "STATIC_ROUTE": { + "mgmt|0.0.0.0/0": { + "nexthop": "172.16.10.254" + } + }, + "SYSLOG_SERVER": { + "172.16.10.254": { + "message-type": "log", + "protocol": "UDP", + "remote-port": "514", + "severity": "info", + "vrf_name": "mgmt" + } + }, + "VERSIONS": { + "DATABASE": { + "VERSION": "version_4_0_1" + } + }, + "VLAN": {}, + "VLAN_INTERFACE": {}, + "VLAN_MEMBER": {}, + "VRF": { + "default": { + "enabled": "true" + } + }, + "VXLAN_EVPN_NVO": {}, + "VXLAN_TUNNEL": {}, + "VXLAN_TUNNEL_MAP": {} +} diff --git a/tests/e2e/golden/osism_e2e-spine-1_config_db.json b/tests/e2e/golden/osism_e2e-spine-1_config_db.json new file mode 100644 index 00000000..ced04a8a --- /dev/null +++ b/tests/e2e/golden/osism_e2e-spine-1_config_db.json @@ -0,0 +1,679 @@ +{ + "ACL_RULE": { + "GNMI_ONLY|RULE_1": { + "IP_TYPE": "IP", + "L4_DST_PORT": "8080", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9999", + "SRC_IP": "172.16.0.0/20" + }, + "SNMP_ONLY|RULE_1": { + "IP_TYPE": "IP", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9999", + "SRC_IP": "172.16.0.0/20" + }, + "SSH_ONLY|RULE_1": { + "IP_TYPE": "IP", + "PACKET_ACTION": "ACCEPT", + "PRIORITY": "9999", + "SRC_IP": "172.16.0.0/20" + } + }, + "ACL_TABLE": { + "GNMI_ONLY": { + "policy_desc": "GNMI_ONLY", + "services": [ + "EXTERNAL_CLIENT" + ], + "type": "CTRLPLANE" + }, + "SNMP_ONLY": { + "policy_desc": "SNMP_ONLY", + "services": [ + "SNMP" + ], + "type": "CTRLPLANE" + }, + "SSH_ONLY": { + "policy_desc": "SSH_ONLY", + "services": [ + "SSH" + ], + "type": "CTRLPLANE" + } + }, + "BGP_GLOBALS": { + "default": { + "always_compare_med": "true", + "ebgp_requires_policy": "false", + "external_compare_router_id": "false", + "fast_external_failover": "true", + "holdtime": "180", + "ignore_as_path_length": "false", + "keepalive": "60", + "load_balance_mp_relax": "false", + "local_asn": "4200020001", + "log_nbr_state_changes": "true", + "network_import_check": "true", + "router_id": "192.168.20.1" + } + }, + "BGP_GLOBALS_AF": { + "default|ipv4_unicast": { + "ibgp_equal_cluster_length": "false", + "max_ebgp_paths": "2", + "max_ibgp_paths": "2", + "route_flap_dampen": "false" + }, + "default|ipv6_unicast": { + "ibgp_equal_cluster_length": "false", + "max_ebgp_paths": "2", + "max_ibgp_paths": "2" + }, + "default|l2vpn_evpn": { + "advertise-all-vni": "true", + "advertise-svi-ip": "true", + "dad-enabled": "true" + } + }, + "BGP_GLOBALS_AF_NETWORK": { + "default|ipv4_unicast|192.168.20.1/32": {} + }, + "BGP_GLOBALS_ROUTE_ADVERTISE": { + "default|L2VPN_EVPN|IPV4_UNICAST": {}, + "default|L2VPN_EVPN|IPV6_UNICAST": {} + }, + "BGP_NEIGHBOR": { + "default|192.168.30.1": { + "local_addr": "192.168.30.0", + "peer_type": "external", + "v6only": "false" + }, + "default|192.168.30.3": { + "local_addr": "192.168.30.2", + "peer_type": "external", + "v6only": "false" + } + }, + "BGP_NEIGHBOR_AF": { + "default|Ethernet0|ipv4_unicast": { + "admin_status": "true" + }, + "default|Ethernet0|l2vpn_evpn": { + "admin_status": "true" + }, + "default|Ethernet4|ipv4_unicast": { + "admin_status": "true" + }, + "default|Ethernet4|l2vpn_evpn": { + "admin_status": "true" + } + }, + "BREAKOUT_CFG": {}, + "BREAKOUT_PORTS": {}, + "DEVICE_METADATA": { + "localhost": { + "hostname": "e2e-spine-1", + "hwsku": "Accton-AS7726-32X", + "mac": "00:00:00:00:00:00", + "platform": "x86_64-accton_as7726_32x-r0" + } + }, + "DNS_NAMESERVER": { + "172.16.10.254": {} + }, + "INTERFACE": { + "Ethernet0": {}, + "Ethernet0|192.168.30.0/31": {}, + "Ethernet4": {}, + "Ethernet4|192.168.30.2/31": {} + }, + "LOOPBACK": { + "Loopback0": { + "admin_status": "up" + } + }, + "LOOPBACK_INTERFACE": { + "Loopback0": {}, + "Loopback0|192.168.20.1/32": {} + }, + "MGMT_INTERFACE": { + "eth0": { + "admin_status": "up" + }, + "eth0|172.16.10.1/20": {} + }, + "NTP_SERVER": { + "172.16.10.254": { + "maxpoll": "10", + "minpoll": "6", + "prefer": "false" + } + }, + "PORT": { + "Ethernet0": { + "admin_status": "up", + "adv_speeds": "all", + "alias": "Eth1/1", + "autoneg": "off", + "index": "1", + "lanes": "1,2,3,4", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet100": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/26", + "autoneg": "off", + "index": "26", + "lanes": "101,102,103,104", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet104": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/27", + "autoneg": "off", + "index": "27", + "lanes": "105,106,107,108", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet108": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/28", + "autoneg": "off", + "index": "28", + "lanes": "109,110,111,112", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet112": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/29", + "autoneg": "off", + "index": "29", + "lanes": "113,114,115,116", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet116": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/30", + "autoneg": "off", + "index": "30", + "lanes": "117,118,119,120", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet12": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/4", + "autoneg": "off", + "index": "4", + "lanes": "13,14,15,16", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet120": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/31", + "autoneg": "off", + "index": "31", + "lanes": "121,122,123,124", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet124": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/32", + "autoneg": "off", + "index": "32", + "lanes": "125,126,127,128", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet125": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/33", + "autoneg": "off", + "index": "33", + "lanes": "129", + "link_training": "off", + "mtu": "9100", + "speed": "10000", + "unreliable_los": "auto", + "valid_speeds": "10000,1000" + }, + "Ethernet126": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/34", + "autoneg": "off", + "index": "34", + "lanes": "128", + "link_training": "off", + "mtu": "9100", + "speed": "10000", + "unreliable_los": "auto", + "valid_speeds": "10000,1000" + }, + "Ethernet16": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/5", + "autoneg": "off", + "index": "5", + "lanes": "17,18,19,20", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet20": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/6", + "autoneg": "off", + "index": "6", + "lanes": "21,22,23,24", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet24": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/7", + "autoneg": "off", + "index": "7", + "lanes": "25,26,27,28", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet28": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/8", + "autoneg": "off", + "index": "8", + "lanes": "29,30,31,32", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet32": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/9", + "autoneg": "off", + "index": "9", + "lanes": "33,34,35,36", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet36": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/10", + "autoneg": "off", + "index": "10", + "lanes": "37,38,39,40", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet4": { + "admin_status": "up", + "adv_speeds": "all", + "alias": "Eth1/2", + "autoneg": "off", + "index": "2", + "lanes": "5,6,7,8", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet40": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/11", + "autoneg": "off", + "index": "11", + "lanes": "41,42,43,44", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet44": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/12", + "autoneg": "off", + "index": "12", + "lanes": "45,46,47,48", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet48": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/13", + "autoneg": "off", + "index": "13", + "lanes": "49,50,51,52", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet52": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/14", + "autoneg": "off", + "index": "14", + "lanes": "53,54,55,56", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet56": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/15", + "autoneg": "off", + "index": "15", + "lanes": "57,58,59,60", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet60": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/16", + "autoneg": "off", + "index": "16", + "lanes": "61,62,63,64", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet64": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/17", + "autoneg": "off", + "index": "17", + "lanes": "65,66,67,68", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet68": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/18", + "autoneg": "off", + "index": "18", + "lanes": "69,70,71,72", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet72": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/19", + "autoneg": "off", + "index": "19", + "lanes": "73,74,75,76", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet76": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/20", + "autoneg": "off", + "index": "20", + "lanes": "77,78,79,80", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet8": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/3", + "autoneg": "off", + "index": "3", + "lanes": "9,10,11,12", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet80": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/21", + "autoneg": "off", + "index": "21", + "lanes": "81,82,83,84", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet84": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/22", + "autoneg": "off", + "index": "22", + "lanes": "85,86,87,88", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet88": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/23", + "autoneg": "off", + "index": "23", + "lanes": "89,90,91,92", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet92": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/24", + "autoneg": "off", + "index": "24", + "lanes": "93,94,95,96", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + }, + "Ethernet96": { + "admin_status": "down", + "adv_speeds": "all", + "alias": "Eth1/25", + "autoneg": "off", + "index": "25", + "lanes": "97,98,99,100", + "link_training": "off", + "mtu": "9100", + "speed": "100000", + "unreliable_los": "auto", + "valid_speeds": "100000,40000" + } + }, + "PORTCHANNEL": {}, + "PORTCHANNEL_INTERFACE": {}, + "PORTCHANNEL_MEMBER": {}, + "ROUTE_REDISTRIBUTE": { + "default|connected|bgp|ipv4": {}, + "default|connected|bgp|ipv6": {} + }, + "SNMP_AGENT_ADDRESS_CONFIG": { + "172.16.10.1|161|mgmt": { + "name": "agentEntry1" + } + }, + "SNMP_SERVER": { + "SYSTEM": { + "sysContact": "e2e@example.com", + "sysLocation": "E2E Lab", + "traps": "enable" + } + }, + "SNMP_SERVER_GROUP_MEMBER": { + "monitoring|e2e-monitor": { + "securityModel": [ + "usm" + ] + } + }, + "SNMP_SERVER_PARAMS": { + "targetEntry1": { + "security-level": "auth-priv", + "user": "e2e-monitor" + } + }, + "SNMP_SERVER_TARGET": { + "targetEntry1": { + "ip": "172.16.10.254", + "port": "162", + "retries": "3", + "tag": [ + "trapNotify", + "mgmt" + ], + "targetParams": "targetEntry1", + "timeout": "1500" + } + }, + "SNMP_SERVER_USER": { + "e2e-monitor": { + "aesKey": "OBFUSCATEDPRIVSECRET", + "shaKey": "OBFUSCATEDAUTHSECRET" + } + }, + "STATIC_ROUTE": { + "mgmt|0.0.0.0/0": { + "nexthop": "172.16.10.254" + } + }, + "SYSLOG_SERVER": { + "172.16.10.254": { + "message-type": "log", + "protocol": "UDP", + "remote-port": "514", + "severity": "info", + "vrf_name": "mgmt" + } + }, + "VERSIONS": { + "DATABASE": { + "VERSION": "version_4_0_1" + } + }, + "VLAN": {}, + "VLAN_INTERFACE": {}, + "VLAN_MEMBER": {}, + "VRF": { + "default": { + "enabled": "true" + } + }, + "VXLAN_EVPN_NVO": {}, + "VXLAN_TUNNEL": {}, + "VXLAN_TUNNEL_MAP": {} +} diff --git a/tests/e2e/scenario/devicetypes/Edgecore/7726-32X-E2E.yaml b/tests/e2e/scenario/devicetypes/Edgecore/7726-32X-E2E.yaml new file mode 100644 index 00000000..8e16b9f4 --- /dev/null +++ b/tests/e2e/scenario/devicetypes/Edgecore/7726-32X-E2E.yaml @@ -0,0 +1,27 @@ +--- +# Minimal device type shared by two SONiC E2E scenarios: the base +# spine/leaf/OOB fabric (100-base.yml/200-fabric.yml/250-oob.yml/ +# 260-metalbox.yml) and the port-channel scenario (600-portchannel.yml). +# +# Not a faithful model of the real 7726-32X; it defines only a management +# port and two data ports. The fabric scenario uses the two data ports as +# plain point-to-point uplinks (any access/trunk/VLAN ports it needs are +# created separately, not from this device type); the port-channel scenario +# instead bonds them into a LAG. Config generation is driven by the hwsku +# custom field (Accton-AS7726-32X on the scenario devices), not by this +# device type -- the device type only controls which NetBox interfaces +# exist. The LAG interface itself is created in the port-channel scenario's +# resources overlay (type: lag) with these two ports as members. +manufacturer: Edgecore +model: 7726-32X-E2E +slug: edgecore-7726-32x-e2e +u_height: 1.0 +is_full_depth: true +interfaces: + - name: eth0 + type: 1000base-t + mgmt_only: true + - name: Ethernet0 + type: 100gbase-x-qsfp28 + - name: Ethernet4 + type: 100gbase-x-qsfp28 diff --git a/tests/e2e/scenario/resources/100-base.yml b/tests/e2e/scenario/resources/100-base.yml new file mode 100644 index 00000000..ac70066a --- /dev/null +++ b/tests/e2e/scenario/resources/100-base.yml @@ -0,0 +1,118 @@ +--- +# Base objects for the SONiC E2E synthetic fixtures. +# +# Everything here is referenced (by name/slug) from the later numbered +# files in this directory, so it must be seeded first. `site`/`location`/ +# `tenant` are kept from testbed's own conventions (Discworld / +# Ankh-Morpork / Testbed) purely so the fixtures stay recognisable to +# anyone used to the retired testbed-derived seed data -- there is no +# functional dependency on osism/testbed itself. + +- vars: + site: Discworld + location: Ankh-Morpork + tenant: Testbed + +- tenant: + name: "{{ tenant }}" + slug: testbed + +- site: + name: "{{ site }}" + slug: discworld + +- location: + name: "{{ location }}" + slug: ankh-morpork + site: "{{ site }}" + +# Device roles. spine/leaf/switch are in DEFAULT_SONIC_ROLES, so a device +# tagged managed-by-metalbox with one of these roles gets a golden; metalbox +# is deliberately excluded from DEFAULT_SONIC_ROLES since the metalbox is +# not a SONiC device and must never be generated. +- device_role: + name: Spine + slug: spine + +- device_role: + name: Leaf + slug: leaf + +- device_role: + name: Switch + slug: switch + +- device_role: + name: Metalbox + slug: metalbox + +# Required by the device filter (status=active + this tag + role in +# DEFAULT_SONIC_ROLES). A device missing this tag is skipped silently, with +# no golden and no error. +- tag: + name: Managed by Metalbox + slug: managed-by-metalbox + +# The generator reads sonic_parameters.hwsku (and .version) from this field +# to decide whether -- and how -- to generate a device's SONiC config; PR 3 +# also stores its breakout_mode declaration under the same field. +- custom_field: + name: sonic_parameters + type: json + label: sonic parameters + description: SONiC parameters + required: false + object_types: + - dcim.device + +- ipam_role: + name: OOB + +# Referenced by the fabric's point-to-point link prefix in 200-fabric.yml. +# _get_transfer_role_ipv4_addresses() only treats a link as numbered +# (rather than IP-unnumbered) when its address falls inside a prefix with +# this role -- without it, BGP_NEIGHBOR/BGP_NEIGHBOR_AF stay empty even +# though the link is cabled and addressed. +- ipam_role: + name: Transfer + slug: transfer + +# VLAN 100 carries vlan_role: OOB because it is the fixture's real-world +# out-of-band management VLAN (matching how these are modelled in NetBox in +# practice); the generator does not currently read vlan_role itself. VLAN +# 200 below is deliberately role-less: it exists only to exercise the plain +# tagged-VLAN path (untagged/tagged port coverage in 200-fabric.yml) and has +# no OOB-like real-world counterpart, so giving it a role would be +# unmotivated decoration. This is intentional, not an oversight -- don't +# "fix" the asymmetry by adding one, since regenerating after that edit +# would move goldens for no functional reason. +- vlan: + name: oob + vid: 100 + site: "{{ site }}" + tenant: "{{ tenant }}" + vlan_role: OOB + +- vlan: + name: data + vid: 200 + site: "{{ site }}" + tenant: "{{ tenant }}" + +- prefix: + family: 4 + prefix: 172.16.0.0/20 + prefix_role: OOB + tenant: "{{ tenant }}" + +- prefix: + family: 4 + prefix: 192.168.20.0/24 + tenant: "{{ tenant }}" + +- rack: + name: E2E + site: "{{ site }}" + location: "{{ location }}" + tenant: "{{ tenant }}" + u_height: 47 diff --git a/tests/e2e/scenario/resources/150-context.yml b/tests/e2e/scenario/resources/150-context.yml new file mode 100644 index 00000000..5a8937cd --- /dev/null +++ b/tests/e2e/scenario/resources/150-context.yml @@ -0,0 +1,28 @@ +--- +# Config context supplying the segment-level log-server and SNMP settings +# every fixture device inherits through the Testbed tenant (every device in +# this scenario belongs to it). +# +# _segment_log_server_hosts unlocks SYSLOG_SERVER. _segment_snmp_server_username +# unlocks SNMP_SERVER_USER and SNMP_SERVER_GROUP_MEMBER; +# _segment_snmp_server_hosts additionally unlocks SNMP_SERVER_PARAMS and +# SNMP_SERVER_TARGET. No `secrets` custom field is set anywhere in this +# scenario, so get_vault() is never called and the SNMP auth/priv passwords +# fall back to the literals OBFUSCATEDAUTHSECRET / OBFUSCATEDPRIVSECRET -- +# that is the evidence the no-vault path was exercised. + +- config_context: + name: e2e-segment + tenants: + - Testbed + data: + _segment_log_server_hosts: + - 172.16.10.254 + _segment_log_server_proto: udp + _segment_log_server_severity: info + _segment_log_server_vrf: mgmt + _segment_snmp_server_username: e2e-monitor + _segment_snmp_server_hosts: + - 172.16.10.254 + _segment_snmp_server_location: E2E Lab + _segment_snmp_server_contact: e2e@example.com diff --git a/tests/e2e/scenario/resources/200-fabric.yml b/tests/e2e/scenario/resources/200-fabric.yml new file mode 100644 index 00000000..b101825a --- /dev/null +++ b/tests/e2e/scenario/resources/200-fabric.yml @@ -0,0 +1,258 @@ +--- +# Spine/leaf fabric for the SONiC E2E base scenario: one spine and two +# leaves, cabled spine<->leaf, one leaf carrying an access and a trunk +# port, and one VRF assigned to a data port. +# +# oob_ip / Loopback0 values are fixed by the fixture value contract in the +# plan (docs/superpowers/plans/2026-07-30-sonic-e2e-synthetic-fixtures.md): +# the ASN is derived from Loopback0 (4200 + zero-padded 3rd/4th octet), so +# these addresses are not free choices. +# +# Interface names come from the Accton-AS7726-32X hwsku's port_config +# (files/sonic/port_config/Accton-AS7726-32X.ini), not from the minimal +# edgecore-7726-32x-e2e device type -- that device type only defines eth0, +# Ethernet0 and Ethernet4, so every other interface used here is created +# explicitly via device_interface stanzas. + +# ---------------------------------------------------------------- spine -- +- device: + name: e2e-spine-1 + tenant: Testbed + site: Discworld + location: Ankh-Morpork + rack: E2E + device_type: edgecore-7726-32x-e2e + device_role: spine + status: active + face: front + position: 1 + tags: + - managed-by-metalbox + custom_fields: + sonic_parameters: + hwsku: Accton-AS7726-32X + version: 4.5.0 + +- device_interface: + device: e2e-spine-1 + name: Loopback0 + type: virtual + enabled: true + +- ip_address: + tenant: Testbed + address: 172.16.10.1/20 + assigned_object: + name: eth0 + device: e2e-spine-1 + +- ip_address: + tenant: Testbed + address: 192.168.20.1/32 + assigned_object: + name: Loopback0 + device: e2e-spine-1 + +- device: + name: e2e-spine-1 + oob_ip: 172.16.10.1/20 + primary_ip4: 192.168.20.1/32 + +# --------------------------------------------------------------- leaf-1 -- +- device: + name: e2e-leaf-1 + tenant: Testbed + site: Discworld + location: Ankh-Morpork + rack: E2E + device_type: edgecore-7726-32x-e2e + device_role: leaf + status: active + face: front + position: 2 + tags: + - managed-by-metalbox + custom_fields: + sonic_parameters: + hwsku: Accton-AS7726-32X + version: 4.5.0 + +- device_interface: + device: e2e-leaf-1 + name: Loopback0 + type: virtual + enabled: true + +- ip_address: + tenant: Testbed + address: 172.16.10.11/20 + assigned_object: + name: eth0 + device: e2e-leaf-1 + +- ip_address: + tenant: Testbed + address: 192.168.20.11/32 + assigned_object: + name: Loopback0 + device: e2e-leaf-1 + +- device: + name: e2e-leaf-1 + oob_ip: 172.16.10.11/20 + primary_ip4: 192.168.20.11/32 + +# --------------------------------------------------------------- leaf-2 -- +- device: + name: e2e-leaf-2 + tenant: Testbed + site: Discworld + location: Ankh-Morpork + rack: E2E + device_type: edgecore-7726-32x-e2e + device_role: leaf + status: active + face: front + position: 3 + tags: + - managed-by-metalbox + custom_fields: + sonic_parameters: + hwsku: Accton-AS7726-32X + version: 4.5.0 + +- device_interface: + device: e2e-leaf-2 + name: Loopback0 + type: virtual + enabled: true + +- ip_address: + tenant: Testbed + address: 172.16.10.12/20 + assigned_object: + name: eth0 + device: e2e-leaf-2 + +- ip_address: + tenant: Testbed + address: 192.168.20.12/32 + assigned_object: + name: Loopback0 + device: e2e-leaf-2 + +- device: + name: e2e-leaf-2 + oob_ip: 172.16.10.12/20 + primary_ip4: 192.168.20.12/32 + +# ---------------------------------------------------------- fabric links -- +# Point-to-point link addresses must fall inside a prefix with the +# Transfer role, or _get_transfer_role_ipv4_addresses() treats the link as +# IP-unnumbered and BGP_NEIGHBOR/BGP_NEIGHBOR_AF stay empty even though the +# link is cabled and addressed. +- prefix: + family: 4 + prefix: 192.168.30.0/24 + prefix_role: Transfer + tenant: Testbed + +# e2e-spine-1 Ethernet0 <-> e2e-leaf-1 Ethernet0, on a /31. +- cable: + termination_a_type: dcim.interface + termination_a: + device: e2e-spine-1 + name: Ethernet0 + termination_b_type: dcim.interface + termination_b: + device: e2e-leaf-1 + name: Ethernet0 + +- ip_address: + tenant: Testbed + address: 192.168.30.0/31 + assigned_object: + name: Ethernet0 + device: e2e-spine-1 + +- ip_address: + tenant: Testbed + address: 192.168.30.1/31 + assigned_object: + name: Ethernet0 + device: e2e-leaf-1 + +# e2e-spine-1 Ethernet4 <-> e2e-leaf-2 Ethernet0, on a /31. +- cable: + termination_a_type: dcim.interface + termination_a: + device: e2e-spine-1 + name: Ethernet4 + termination_b_type: dcim.interface + termination_b: + device: e2e-leaf-2 + name: Ethernet0 + +- ip_address: + tenant: Testbed + address: 192.168.30.2/31 + assigned_object: + name: Ethernet4 + device: e2e-spine-1 + +- ip_address: + tenant: Testbed + address: 192.168.30.3/31 + assigned_object: + name: Ethernet0 + device: e2e-leaf-2 + +# ------------------------------------------------------ leaf-1 VLAN ports -- +# Access port with untagged VLAN 100 (oob) and a trunk port with tagged +# VLAN 200 (data), so VLAN, VLAN_INTERFACE and VLAN_MEMBER populate. +- device_interface: + device: e2e-leaf-1 + name: Ethernet8 + type: 100gbase-x-qsfp28 + mode: access + untagged_vlan: + name: oob + site: Discworld + +- device_interface: + device: e2e-leaf-1 + name: Ethernet12 + type: 100gbase-x-qsfp28 + mode: tagged + tagged_vlans: + - name: data + site: Discworld + +# VLAN_INTERFACE (SVI) needs an actual NetBox virtual interface named +# Vlan carrying an IP address -- VLAN_MEMBER from the ports above +# does not by itself create one. +- device_interface: + device: e2e-leaf-1 + name: Vlan200 + type: virtual + enabled: true + +- ip_address: + tenant: Testbed + address: 192.168.40.1/24 + assigned_object: + name: Vlan200 + device: e2e-leaf-1 + +# ------------------------------------------------------------------ VRF -- +# vrf99 has no RD, so it takes the table_id-only branch (VRF["Vrf99"] = +# {vrf_table_id: 99}), which is enough to populate VRF, the BGP_GLOBALS* +# family and ROUTE_REDISTRIBUTE without pulling in EVPN/VXLAN. +- vrf: + name: vrf99 + tenant: Testbed + +- device_interface: + device: e2e-leaf-2 + name: Ethernet4 + vrf: vrf99 diff --git a/tests/e2e/scenario/resources/250-oob.yml b/tests/e2e/scenario/resources/250-oob.yml new file mode 100644 index 00000000..bdb24bba --- /dev/null +++ b/tests/e2e/scenario/resources/250-oob.yml @@ -0,0 +1,47 @@ +--- +# Standalone OOB switch. Role "switch" is in DEFAULT_SONIC_ROLES, so this +# device also gets a golden -- it exercises the filter with a role other +# than spine/leaf. + +- device: + name: e2e-oob-1 + tenant: Testbed + site: Discworld + location: Ankh-Morpork + rack: E2E + device_type: edgecore-7726-32x-e2e + device_role: switch + status: active + face: front + position: 4 + tags: + - managed-by-metalbox + custom_fields: + sonic_parameters: + hwsku: Accton-AS7726-32X + version: 4.5.0 + +- device_interface: + device: e2e-oob-1 + name: Loopback0 + type: virtual + enabled: true + +- ip_address: + tenant: Testbed + address: 172.16.10.21/20 + assigned_object: + name: eth0 + device: e2e-oob-1 + +- ip_address: + tenant: Testbed + address: 192.168.20.21/32 + assigned_object: + name: Loopback0 + device: e2e-oob-1 + +- device: + name: e2e-oob-1 + oob_ip: 172.16.10.21/20 + primary_ip4: 192.168.20.21/32 diff --git a/tests/e2e/scenario/resources/260-metalbox.yml b/tests/e2e/scenario/resources/260-metalbox.yml new file mode 100644 index 00000000..fbffcc01 --- /dev/null +++ b/tests/e2e/scenario/resources/260-metalbox.yml @@ -0,0 +1,40 @@ +--- +# The metalbox. Role "metalbox" is NOT in DEFAULT_SONIC_ROLES and this +# device is deliberately NOT tagged managed-by-metalbox, so it must never +# get a golden of its own -- if one appears, this device wrongly acquired a +# SONiC role or the tag. +# +# _get_metalbox_ip_for_device() walks every role=metalbox device's +# interfaces and returns the first IPv4 that falls inside the SONiC +# device's OOB network; it does not follow a cable. All four switches use +# /20 oob_ips, so that network is 172.16.0.0/20, and 172.16.10.254 sits +# inside it -- that subnet membership, not any cabling, is what unlocks +# DNS_NAMESERVER and NTP_SERVER. +# +# The address must NOT sit on a mgmt_only interface: +# _load_metalbox_devices_cache() explicitly skips those, so it cannot be on +# eth0 (mgmt_only: true in the device type). Ethernet0 is a plain data port +# on this device type and is otherwise unused here. + +- device: + name: e2e-metalbox-1 + tenant: Testbed + site: Discworld + location: Ankh-Morpork + rack: E2E + device_type: edgecore-7726-32x-e2e + device_role: metalbox + status: active + face: front + position: 5 + +- ip_address: + tenant: Testbed + address: 172.16.10.254/20 + assigned_object: + name: Ethernet0 + device: e2e-metalbox-1 + +- device: + name: e2e-metalbox-1 + primary_ip4: 172.16.10.254/20 diff --git a/tests/unit/e2e/test_coverage.py b/tests/unit/e2e/test_coverage.py new file mode 100644 index 00000000..b165cc0f --- /dev/null +++ b/tests/unit/e2e/test_coverage.py @@ -0,0 +1,162 @@ +# SPDX-License-Identifier: Apache-2.0 + +"""Unit tests for the E2E config_db coverage report. + +Both halves of tests/e2e/coverage.py are pure functions over a directory +tree, so they are tested here as part of the regular unit suite. The +emitted-table regex carries most of the risk: it produces the denominator +of the "N of M config_db tables covered" claim and decides the exit code, +and a silent widening or narrowing of it would otherwise go unnoticed. +""" + +import json + +from tests.e2e import coverage +from tests.e2e.coverage import covered_tables, emitted_tables, main + + +class TestEmittedTables: + @staticmethod + def _write(directory, name, source): + path = directory / name + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(source) + + def test_direct_assignment_is_an_emission(self, tmp_path): + self._write(tmp_path, "port.py", 'config["PORT"] = {}\n') + + assert emitted_tables(tmp_path) == {"PORT"} + + def test_cfg_alias_is_recognised(self, tmp_path): + self._write(tmp_path, "vlan.py", 'cfg["VLAN"] = {}\n') + + assert emitted_tables(tmp_path) == {"VLAN"} + + def test_nested_item_assignment_is_an_emission(self, tmp_path): + self._write(tmp_path, "acl.py", 'config["ACL_TABLE"]["SSH_ONLY"] = {}\n') + + assert emitted_tables(tmp_path) == {"ACL_TABLE"} + + def test_update_call_is_an_emission(self, tmp_path): + self._write(tmp_path, "meta.py", 'config["DEVICE_METADATA"].update(other)\n') + + assert emitted_tables(tmp_path) == {"DEVICE_METADATA"} + + def test_membership_read_is_not_an_emission(self, tmp_path): + self._write(tmp_path, "versions.py", 'if "DATABASE" in config["VERSIONS"]:\n') + + assert emitted_tables(tmp_path) == set() + + def test_equality_comparison_is_not_an_emission(self, tmp_path): + self._write(tmp_path, "guard.py", 'if config["PORT"] == {}:\n') + + assert emitted_tables(tmp_path) == set() + + def test_read_on_the_right_hand_side_is_not_an_emission(self, tmp_path): + self._write( + tmp_path, "copy.py", 'config["INTERFACE"]["x"] = config["PORT"]["y"]\n' + ) + + assert emitted_tables(tmp_path) == {"INTERFACE"} + + def test_commented_out_assignment_is_ignored(self, tmp_path): + self._write(tmp_path, "todo.py", ' # config["VXLAN_TUNNEL"] = {}\n') + + assert emitted_tables(tmp_path) == set() + + def test_generated_schema_package_is_excluded(self, tmp_path): + self._write(tmp_path, "_generated/schema.py", 'config["SFLOW"] = {}\n') + + assert emitted_tables(tmp_path) == set() + + def test_subdirectories_are_searched(self, tmp_path): + self._write(tmp_path, "sub/bgp.py", 'config["BGP_NEIGHBOR"] = {}\n') + + assert emitted_tables(tmp_path) == {"BGP_NEIGHBOR"} + + def test_non_python_files_are_ignored(self, tmp_path): + self._write(tmp_path, "notes.txt", 'config["MIRROR_SESSION"] = {}\n') + + assert emitted_tables(tmp_path) == set() + + def test_lowercase_keys_are_not_table_names(self, tmp_path): + self._write(tmp_path, "local.py", 'config["scratch"] = {}\n') + + assert emitted_tables(tmp_path) == set() + + def test_tables_accumulate_across_files(self, tmp_path): + self._write(tmp_path, "a.py", 'config["PORT"] = {}\n') + self._write(tmp_path, "b.py", 'config["VLAN"] = {}\n') + + assert emitted_tables(tmp_path) == {"PORT", "VLAN"} + + +class TestCoveredTables: + @staticmethod + def _write(directory, name, config): + (directory / name).write_text(json.dumps(config)) + + def test_populated_table_is_covered(self, tmp_path): + self._write(tmp_path, "sw1.json", {"PORT": {"Ethernet0": {"speed": "100000"}}}) + + assert covered_tables(tmp_path) == {"PORT"} + + def test_empty_table_is_not_covered(self, tmp_path): + self._write(tmp_path, "sw1.json", {"PORT": {"Ethernet0": {}}, "VLAN": {}}) + + assert covered_tables(tmp_path) == {"PORT"} + + def test_table_empty_in_every_file_is_not_covered(self, tmp_path): + self._write(tmp_path, "sw1.json", {"VXLAN_TUNNEL": {}}) + self._write(tmp_path, "sw2.json", {"VXLAN_TUNNEL": {}}) + + assert covered_tables(tmp_path) == set() + + def test_coverage_accumulates_across_files(self, tmp_path): + # A table populated on one device and empty on another is covered: + # this is how VLAN and BGP_NEIGHBOR reach the count in the real set. + self._write(tmp_path, "sw1.json", {"VLAN": {}, "PORT": {"Ethernet0": {}}}) + self._write(tmp_path, "sw2.json", {"VLAN": {"Vlan100": {}}, "PORT": {}}) + + assert covered_tables(tmp_path) == {"VLAN", "PORT"} + + def test_non_json_files_are_ignored(self, tmp_path): + self._write(tmp_path, "sw1.json", {"PORT": {"Ethernet0": {}}}) + (tmp_path / "notes.txt").write_text('{"VLAN": {"Vlan100": {}}}') + + assert covered_tables(tmp_path) == {"PORT"} + + +class TestMain: + @staticmethod + def _stub(monkeypatch, emitted, covered): + monkeypatch.setattr(coverage, "emitted_tables", lambda: set(emitted)) + monkeypatch.setattr(coverage, "covered_tables", lambda: set(covered)) + + def test_full_coverage_returns_zero_and_prints_counts(self, monkeypatch, capsys): + self._stub(monkeypatch, {"PORT", "VLAN"}, {"PORT", "VLAN"}) + + rc = main() + + assert rc == 0 + assert "generator emits 2 tables; 2 non-empty" in capsys.readouterr().out + + def test_uncovered_tables_fail_and_are_listed_sorted(self, monkeypatch, capsys): + self._stub(monkeypatch, {"PORT", "VXLAN_TUNNEL", "BREAKOUT_CFG"}, {"PORT"}) + + rc = main() + out = capsys.readouterr().out + + assert rc == 1 + assert "not covered by any golden file:" in out + assert out.splitlines()[-2:] == [" BREAKOUT_CFG", " VXLAN_TUNNEL"] + + def test_covered_table_the_generator_cannot_emit_is_not_a_failure( + self, monkeypatch, capsys + ): + self._stub(monkeypatch, {"PORT"}, {"PORT", "HAND_WRITTEN_TABLE"}) + + rc = main() + + assert rc == 0 + assert "generator emits 1 tables; 2 non-empty" in capsys.readouterr().out