From f46dcc01ae31d66f129e75e8cbf63111810bbc14 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 10:15:45 +0000 Subject: [PATCH 01/20] Tests - ACL End-to-end integration test: - Initial version --- src/tests/acl_end2end/.gitignore | 19 + src/tests/acl_end2end/.gitlab-ci.yml | 324 ++++++++++++++++++ src/tests/acl_end2end/Dockerfile | 86 +++++ src/tests/acl_end2end/README.md | 111 ++++++ src/tests/acl_end2end/__init__.py | 14 + .../acl_end2end/clab/acl_end2end.clab.yml | 74 ++++ src/tests/acl_end2end/clab/r1-startup.cfg | 48 +++ src/tests/acl_end2end/clab/r2-startup.cfg | 48 +++ src/tests/acl_end2end/clab/r3-startup.cfg | 48 +++ .../acl_end2end/data/ietf-l3vpn-service.json | 83 +++++ src/tests/acl_end2end/data/tfs-service.json | 26 ++ src/tests/acl_end2end/data/tfs-topology.json | 126 +++++++ .../deploy-scripts/clab-cli-dc1.sh | 16 + .../deploy-scripts/clab-cli-dc2.sh | 16 + .../acl_end2end/deploy-scripts/clab-cli-r1.sh | 16 + .../acl_end2end/deploy-scripts/clab-cli-r2.sh | 16 + .../acl_end2end/deploy-scripts/clab-cli-r3.sh | 16 + .../acl_end2end/deploy-scripts/clab-deploy.sh | 17 + .../deploy-scripts/clab-destroy.sh | 18 + .../deploy-scripts/clab-inspect.sh | 17 + src/tests/acl_end2end/deploy_specs.sh | 208 +++++++++++ src/tests/acl_end2end/redeploy-tfs.sh | 17 + src/tests/acl_end2end/requirements.in | 15 + src/tests/acl_end2end/scripts/run-cleanup.sh | 20 ++ .../acl_end2end/scripts/run-onboarding.sh | 20 ++ .../scripts/run-service-ietf-create.sh | 20 ++ .../scripts/run-service-ietf-remove.sh | 20 ++ .../scripts/run-service-tfs-create.sh | 20 ++ .../scripts/run-service-tfs-remove.sh | 20 ++ src/tests/acl_end2end/tests/Fixtures.py | 43 +++ src/tests/acl_end2end/tests/Tools.py | 109 ++++++ src/tests/acl_end2end/tests/__init__.py | 14 + src/tests/acl_end2end/tests/test_cleanup.py | 44 +++ .../acl_end2end/tests/test_onboarding.py | 67 ++++ .../tests/test_service_ietf_create.py | 71 ++++ .../tests/test_service_ietf_remove.py | 77 +++++ .../tests/test_service_tfs_create.py | 76 ++++ .../tests/test_service_tfs_remove.py | 80 +++++ 38 files changed, 2080 insertions(+) create mode 100644 src/tests/acl_end2end/.gitignore create mode 100644 src/tests/acl_end2end/.gitlab-ci.yml create mode 100644 src/tests/acl_end2end/Dockerfile create mode 100644 src/tests/acl_end2end/README.md create mode 100644 src/tests/acl_end2end/__init__.py create mode 100644 src/tests/acl_end2end/clab/acl_end2end.clab.yml create mode 100644 src/tests/acl_end2end/clab/r1-startup.cfg create mode 100644 src/tests/acl_end2end/clab/r2-startup.cfg create mode 100644 src/tests/acl_end2end/clab/r3-startup.cfg create mode 100644 src/tests/acl_end2end/data/ietf-l3vpn-service.json create mode 100644 src/tests/acl_end2end/data/tfs-service.json create mode 100644 src/tests/acl_end2end/data/tfs-topology.json create mode 100755 src/tests/acl_end2end/deploy-scripts/clab-cli-dc1.sh create mode 100755 src/tests/acl_end2end/deploy-scripts/clab-cli-dc2.sh create mode 100755 src/tests/acl_end2end/deploy-scripts/clab-cli-r1.sh create mode 100755 src/tests/acl_end2end/deploy-scripts/clab-cli-r2.sh create mode 100755 src/tests/acl_end2end/deploy-scripts/clab-cli-r3.sh create mode 100755 src/tests/acl_end2end/deploy-scripts/clab-deploy.sh create mode 100755 src/tests/acl_end2end/deploy-scripts/clab-destroy.sh create mode 100755 src/tests/acl_end2end/deploy-scripts/clab-inspect.sh create mode 100755 src/tests/acl_end2end/deploy_specs.sh create mode 100755 src/tests/acl_end2end/redeploy-tfs.sh create mode 100644 src/tests/acl_end2end/requirements.in create mode 100755 src/tests/acl_end2end/scripts/run-cleanup.sh create mode 100755 src/tests/acl_end2end/scripts/run-onboarding.sh create mode 100755 src/tests/acl_end2end/scripts/run-service-ietf-create.sh create mode 100755 src/tests/acl_end2end/scripts/run-service-ietf-remove.sh create mode 100755 src/tests/acl_end2end/scripts/run-service-tfs-create.sh create mode 100755 src/tests/acl_end2end/scripts/run-service-tfs-remove.sh create mode 100644 src/tests/acl_end2end/tests/Fixtures.py create mode 100644 src/tests/acl_end2end/tests/Tools.py create mode 100644 src/tests/acl_end2end/tests/__init__.py create mode 100644 src/tests/acl_end2end/tests/test_cleanup.py create mode 100644 src/tests/acl_end2end/tests/test_onboarding.py create mode 100644 src/tests/acl_end2end/tests/test_service_ietf_create.py create mode 100644 src/tests/acl_end2end/tests/test_service_ietf_remove.py create mode 100644 src/tests/acl_end2end/tests/test_service_tfs_create.py create mode 100644 src/tests/acl_end2end/tests/test_service_tfs_remove.py diff --git a/src/tests/acl_end2end/.gitignore b/src/tests/acl_end2end/.gitignore new file mode 100644 index 000000000..a47dc9eff --- /dev/null +++ b/src/tests/acl_end2end/.gitignore @@ -0,0 +1,19 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +clab-*/ +images/ +*.clab.yml.bak +*.tar +*.tar.gz diff --git a/src/tests/acl_end2end/.gitlab-ci.yml b/src/tests/acl_end2end/.gitlab-ci.yml new file mode 100644 index 000000000..25dc770ba --- /dev/null +++ b/src/tests/acl_end2end/.gitlab-ci.yml @@ -0,0 +1,324 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Build, tag, and push the Docker image to the GitLab Docker registry +build acl_end2end: + variables: + TEST_NAME: 'acl_end2end' + stage: build + before_script: + - docker image prune --force + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY + script: + - docker buildx build -t "${TEST_NAME}:latest" -f ./src/tests/${TEST_NAME}/Dockerfile . + - docker tag "${TEST_NAME}:latest" "$CI_REGISTRY_IMAGE/${TEST_NAME}:latest" + - docker push "$CI_REGISTRY_IMAGE/${TEST_NAME}:latest" + after_script: + - docker image prune --force + rules: + - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)' + - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"' + - changes: + - src/common/**/*.py + - proto/*.proto + - src/tests/${TEST_NAME}/**/*.{py,in,sh,yml} + - src/tests/${TEST_NAME}/Dockerfile + - .gitlab-ci.yml + +# Deploy TeraFlowSDN and Execute end-2-end test +end2end_test acl_end2end: + timeout: 45m + variables: + TEST_NAME: 'acl_end2end' + stage: end2end_test + # Disable to force running it after all other tasks + #needs: + # - build acl_end2end + before_script: + # Cleanup old ContainerLab scenarios + - containerlab destroy --all --cleanup || true + + # Do Docker cleanup + - docker ps --all --quiet | xargs --no-run-if-empty docker stop + - docker container prune --force + - docker ps --all --quiet | xargs --no-run-if-empty docker rm --force + - docker image prune --force + - docker network prune --force + - docker volume prune --all --force + - docker buildx prune --force + + # Check MicroK8s is ready + - microk8s status --wait-ready + - LOOP_MAX_ATTEMPTS=10 + - LOOP_COUNTER=0 + - > + while ! kubectl get pods --all-namespaces &> /dev/null; do + printf "%c" "." + sleep 1 + LOOP_COUNTER=$((LOOP_COUNTER + 1)) + if [ "$LOOP_COUNTER" -ge "$LOOP_MAX_ATTEMPTS" ]; then + echo "Max attempts reached, exiting the loop." + exit 1 + fi + done + - kubectl get pods --all-namespaces + + # Always delete Kubernetes namespaces + - export K8S_NAMESPACES=$(kubectl get namespace -o jsonpath='{.items[*].metadata.name}') + - echo "K8S_NAMESPACES=${K8S_NAMESPACES}" + + - export OLD_NATS_NAMESPACES=$(echo "${K8S_NAMESPACES}" | tr ' ' '\n' | grep -E '^nats') + - echo "OLD_NATS_NAMESPACES=${OLD_NATS_NAMESPACES}" + - > + for ns in ${OLD_NATS_NAMESPACES}; do + if [[ "$ns" == nats* ]]; then + if helm3 status "$ns" &>/dev/null; then + helm3 uninstall "$ns" -n "$ns" + else + echo "Release '$ns' not found, skipping..." + fi + fi + done + - export OLD_NAMESPACES=$(echo "${K8S_NAMESPACES}" | tr ' ' '\n' | grep -E '^(tfs|crdb|qdb|kafka|nats)') + - echo "OLD_NAMESPACES=${OLD_NAMESPACES}" + - kubectl delete namespace ${OLD_NAMESPACES} || true + + # Clean-up Kubernetes Failed pods + - > + kubectl get pods --all-namespaces --no-headers --field-selector=status.phase=Failed + -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name | + xargs --no-run-if-empty --max-args=2 kubectl delete pod --namespace + + # Login Docker repository + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY + + script: + # Download Docker image to run the test + - docker pull "${CI_REGISTRY_IMAGE}/${TEST_NAME}:latest" + + # Check MicroK8s is ready + - microk8s status --wait-ready + - LOOP_MAX_ATTEMPTS=10 + - LOOP_COUNTER=0 + - > + while ! kubectl get pods --all-namespaces &> /dev/null; do + printf "%c" "." + sleep 1 + LOOP_COUNTER=$((LOOP_COUNTER + 1)) + if [ "$LOOP_COUNTER" -ge "$LOOP_MAX_ATTEMPTS" ]; then + echo "Max attempts reached, exiting the loop." + exit 1 + fi + done + - kubectl get pods --all-namespaces + + # Deploy ContainerLab Scenario + - RUNNER_PATH=`pwd` + #- cd $PWD/src/tests/${TEST_NAME} + - mkdir -p /tmp/clab/${TEST_NAME} + - cp -R src/tests/${TEST_NAME}/clab/* /tmp/clab/${TEST_NAME} + - tree -la /tmp/clab/${TEST_NAME} + - cd /tmp/clab/${TEST_NAME} + - containerlab deploy --reconfigure --topo acl_end2end.clab.yml + - cd $RUNNER_PATH + + # Wait for initialization of Device NOSes + - sleep 3 + - docker ps -a + + # Dump configuration of the routers (before any configuration) + - containerlab exec --name acl_end2end --label clab-node-name=r1 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + - containerlab exec --name acl_end2end --label clab-node-name=r2 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + - containerlab exec --name acl_end2end --label clab-node-name=r3 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + + # Configure TeraFlowSDN deployment + # Uncomment if DEBUG log level is needed for the components + #- yq -i '((select(.kind=="Deployment").spec.template.spec.containers.[] | select(.name=="server").env.[]) | select(.name=="LOG_LEVEL").value) |= "DEBUG"' manifests/contextservice.yaml + #- yq -i '((select(.kind=="Deployment").spec.template.spec.containers.[] | select(.name=="server").env.[]) | select(.name=="LOG_LEVEL").value) |= "DEBUG"' manifests/deviceservice.yaml + #- yq -i '((select(.kind=="Deployment").spec.template.spec.containers.[] | select(.name=="frontend").env.[]) | select(.name=="LOG_LEVEL").value) |= "DEBUG"' manifests/pathcompservice.yaml + #- yq -i '((select(.kind=="Deployment").spec.template.spec.containers.[] | select(.name=="server").env.[]) | select(.name=="LOG_LEVEL").value) |= "DEBUG"' manifests/serviceservice.yaml + #- yq -i '((select(.kind=="Deployment").spec.template.spec.containers.[] | select(.name=="server").env.[]) | select(.name=="LOG_LEVEL").value) |= "DEBUG"' manifests/nbiservice.yaml + + - source src/tests/${TEST_NAME}/deploy_specs.sh + #- export TFS_REGISTRY_IMAGES="${CI_REGISTRY_IMAGE}" + #- export TFS_SKIP_BUILD="YES" + #- export TFS_IMAGE_TAG="latest" + #- echo "TFS_REGISTRY_IMAGES=${CI_REGISTRY_IMAGE}" + + # Deploy TeraFlowSDN + - ./deploy/crdb.sh + - ./deploy/nats.sh + - ./deploy/kafka.sh + #- ./deploy/qdb.sh + - ./deploy/tfs.sh + - ./deploy/show.sh + + ## Wait for Context to be subscribed to NATS + ## WARNING: this loop is infinite if there is no subscriber (such as monitoring). + ## Investigate if we can use a counter to limit the number of iterations. + ## For now, keep it commented out. + #- LOOP_MAX_ATTEMPTS=180 + #- LOOP_COUNTER=0 + #- > + # while ! kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/contextservice -c server 2>&1 | grep -q 'Subscriber is Ready? True'; do + # echo "Attempt: $LOOP_COUNTER" + # kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/contextservice -c server 2>&1; + # sleep 1; + # LOOP_COUNTER=$((LOOP_COUNTER + 1)) + # if [ "$LOOP_COUNTER" -ge "$LOOP_MAX_ATTEMPTS" ]; then + # echo "Max attempts reached, exiting the loop." + # break + # fi + # done + - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/contextservice -c server + + # Run end-to-end test: onboard scenario + - > + docker run -t --rm --name ${TEST_NAME} --network=host + --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh" + --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" + $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-onboarding.sh + + # Run end-to-end test: configure service TFS + - > + docker run -t --rm --name ${TEST_NAME} --network=host + --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh" + --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" + $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-service-tfs-create.sh + + # Dump configuration of the routers (after configure TFS service) + - containerlab exec --name acl_end2end --label clab-node-name=r1 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + - containerlab exec --name acl_end2end --label clab-node-name=r2 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + - containerlab exec --name acl_end2end --label clab-node-name=r3 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + + # Run end-to-end test: test connectivity with ping + - export TEST1_10=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.1.10' --format json) + - echo $TEST1_10 + - echo $TEST1_10 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST1_1=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.1.1' --format json) + - echo $TEST1_1 + - echo $TEST1_1 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST2_1=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.2.1' --format json) + - echo $TEST2_1 + - echo $TEST2_1 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST2_10=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.2.10' --format json) + - echo $TEST2_10 + - echo $TEST2_10 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST3_1=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.3.1' --format json) + - echo $TEST3_1 + - echo $TEST3_1 | grep -E '3 packets transmitted, 0 received, 100\% packet loss' + - export TEST3_10=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.3.10' --format json) + - echo $TEST3_10 + - echo $TEST3_10 | grep -E '3 packets transmitted, 0 received, 100\% packet loss' + + # Run end-to-end test: deconfigure service TFS + - > + docker run -t --rm --name ${TEST_NAME} --network=host + --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh" + --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" + $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-service-tfs-remove.sh + + # Dump configuration of the routers (after deconfigure TFS service) + - containerlab exec --name acl_end2end --label clab-node-name=r1 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + - containerlab exec --name acl_end2end --label clab-node-name=r2 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + - containerlab exec --name acl_end2end --label clab-node-name=r3 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + + # Run end-to-end test: configure service IETF + - > + docker run -t --rm --name ${TEST_NAME} --network=host + --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh" + --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" + $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-service-ietf-create.sh + + # Dump configuration of the routers (after configure IETF service) + - containerlab exec --name acl_end2end --label clab-node-name=r1 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + - containerlab exec --name acl_end2end --label clab-node-name=r2 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + - containerlab exec --name acl_end2end --label clab-node-name=r3 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + + # Run end-to-end test: test connectivity with ping + - export TEST1_10=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.1.10' --format json) + - echo $TEST1_10 + - echo $TEST1_10 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST1_1=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.1.1' --format json) + - echo $TEST1_1 + - echo $TEST1_1 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST2_1=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.2.1' --format json) + - echo $TEST2_1 + - echo $TEST2_1 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST2_10=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.2.10' --format json) + - echo $TEST2_10 + - echo $TEST2_10 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST3_1=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.3.1' --format json) + - echo $TEST3_1 + - echo $TEST3_1 | grep -E '3 packets transmitted, 0 received, 100\% packet loss' + - export TEST3_10=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.3.10' --format json) + - echo $TEST3_10 + - echo $TEST3_10 | grep -E '3 packets transmitted, 0 received, 100\% packet loss' + + # Run end-to-end test: deconfigure service IETF + - > + docker run -t --rm --name ${TEST_NAME} --network=host + --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh" + --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" + $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-service-ietf-remove.sh + + # Dump configuration of the routers (after deconfigure IETF service) + - containerlab exec --name acl_end2end --label clab-node-name=r1 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + - containerlab exec --name acl_end2end --label clab-node-name=r2 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + - containerlab exec --name acl_end2end --label clab-node-name=r3 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + + # Run end-to-end test: cleanup scenario + - > + docker run -t --rm --name ${TEST_NAME} --network=host + --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh" + --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" + $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-cleanup.sh + + after_script: + # Dump configuration of the routers (on after_script) + - containerlab exec --name acl_end2end --label clab-node-name=r1 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + - containerlab exec --name acl_end2end --label clab-node-name=r2 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + - containerlab exec --name acl_end2end --label clab-node-name=r3 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + + # Dump TeraFlowSDN component logs + - source src/tests/${TEST_NAME}/deploy_specs.sh + - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/contextservice -c server + - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/deviceservice -c server + - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/pathcompservice -c frontend + - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/serviceservice -c server + - kubectl --namespace $TFS_K8S_NAMESPACE logs deployment/nbiservice -c server + + # Clean up + - RUNNER_PATH=`pwd` + #- cd $PWD/src/tests/${TEST_NAME} + - cd /tmp/clab/${TEST_NAME} + - containerlab destroy --topo acl_end2end.clab.yml --cleanup || true + - sudo rm -rf clab-acl_end2end/ .acl_end2end.clab.yml.bak || true + - cd $RUNNER_PATH + - kubectl delete namespaces tfs || true + - docker ps --all --quiet | xargs --no-run-if-empty docker stop + - docker container prune --force + - docker ps --all --quiet | xargs --no-run-if-empty docker rm --force + - docker network prune --force + - docker volume prune --all --force + - docker image prune --force + + #coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/' + rules: + - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)' + - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"' + artifacts: + when: always + reports: + junit: ./src/tests/${TEST_NAME}/report_*.xml diff --git a/src/tests/acl_end2end/Dockerfile b/src/tests/acl_end2end/Dockerfile new file mode 100644 index 000000000..3e3828d0b --- /dev/null +++ b/src/tests/acl_end2end/Dockerfile @@ -0,0 +1,86 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM python:3.9-slim + +# Install dependencies +RUN apt-get --yes --quiet --quiet update && \ + apt-get --yes --quiet --quiet install wget g++ git && \ + rm -rf /var/lib/apt/lists/* + +# Set Python to show logs as they occur +ENV PYTHONUNBUFFERED=0 + +# Get generic Python packages +RUN python3 -m pip install --upgrade 'pip==25.2' +RUN python3 -m pip install --upgrade 'setuptools==79.0.0' 'wheel==0.45.1' +RUN python3 -m pip install --upgrade 'pip-tools==7.3.0' + +# Get common Python packages +# Note: this step enables sharing the previous Docker build steps among all the Python components +WORKDIR /var/teraflow +COPY common_requirements.in common_requirements.in +RUN pip-compile --quiet --output-file=common_requirements.txt common_requirements.in +RUN python3 -m pip install -r common_requirements.txt + +# Add common files into working directory +WORKDIR /var/teraflow/common +COPY src/common/. ./ +RUN rm -rf proto + +# Create proto sub-folder, copy .proto files, and generate Python code +RUN mkdir -p /var/teraflow/common/proto +WORKDIR /var/teraflow/common/proto +RUN touch __init__.py +COPY proto/*.proto ./ +RUN python3 -m grpc_tools.protoc -I=. --python_out=. --grpc_python_out=. *.proto +RUN rm *.proto +RUN find . -type f -exec sed -i -E 's/^(import\ .*)_pb2/from . \1_pb2/g' {} \; + +# Create component sub-folders, get specific Python packages +RUN mkdir -p /var/teraflow/tests/acl_end2end +WORKDIR /var/teraflow/tests/acl_end2end +COPY src/tests/acl_end2end/requirements.in requirements.in +RUN pip-compile --quiet --output-file=requirements.txt requirements.in +RUN python3 -m pip install -r requirements.txt + +# Add component files into working directory +WORKDIR /var/teraflow +COPY src/__init__.py ./__init__.py +COPY src/common/*.py ./common/ +COPY src/common/tests/. ./common/tests/ +COPY src/common/tools/. ./common/tools/ +COPY src/context/__init__.py context/__init__.py +COPY src/context/client/. context/client/ +COPY src/device/__init__.py device/__init__.py +COPY src/device/client/. device/client/ +COPY src/monitoring/__init__.py monitoring/__init__.py +COPY src/monitoring/client/. monitoring/client/ +COPY src/service/__init__.py service/__init__.py +COPY src/service/client/. service/client/ +COPY src/slice/__init__.py slice/__init__.py +COPY src/slice/client/. slice/client/ +COPY src/vnt_manager/__init__.py vnt_manager/__init__.py +COPY src/vnt_manager/client/. vnt_manager/client/ +COPY src/tests/*.py ./tests/ +COPY src/tests/acl_end2end/__init__.py ./tests/acl_end2end/__init__.py +COPY src/tests/acl_end2end/data/. ./tests/acl_end2end/data/ +COPY src/tests/acl_end2end/tests/. ./tests/acl_end2end/tests/ +COPY src/tests/acl_end2end/scripts/. ./ + +RUN apt-get --yes --quiet --quiet update && \ + apt-get --yes --quiet --quiet install tree && \ + rm -rf /var/lib/apt/lists/* + +RUN tree -la /var/teraflow diff --git a/src/tests/acl_end2end/README.md b/src/tests/acl_end2end/README.md new file mode 100644 index 000000000..51bb9d3c6 --- /dev/null +++ b/src/tests/acl_end2end/README.md @@ -0,0 +1,111 @@ +# DataPlane-in-a-Box - Control an Emulated DataPlane through TeraFlowSDN + +## Emulated DataPlane Deployment +- ContainerLab +- Scenario +- Descriptor + +## TeraFlowSDN Deployment +```bash +cd ~/tfs-ctrl +source ~/tfs-ctrl/src/tests/acl_end2end/deploy_specs.sh +./deploy/all.sh +``` + +# ContainerLab - Arista cEOS - Commands + +## Download and install ContainerLab +```bash +sudo bash -c "$(curl -sL https://get.containerlab.dev)" -- -v 0.59.0 +``` + +## Download Arista cEOS image and create Docker image +```bash +cd ~/tfs-ctrl/src/tests/acl_end2end/ +docker import arista/cEOS64-lab-4.32.2F.tar ceos:4.32.2F +``` + +## Deploy scenario +```bash +cd ~/tfs-ctrl/src/tests/acl_end2end/ +sudo containerlab deploy --topo acl_end2end.clab.yml +``` + +## Inspect scenario +```bash +cd ~/tfs-ctrl/src/tests/acl_end2end/ +sudo containerlab inspect --topo acl_end2end.clab.yml +``` + +## Destroy scenario +```bash +cd ~/tfs-ctrl/src/tests/acl_end2end/ +sudo containerlab destroy --topo acl_end2end.clab.yml +sudo rm -rf clab-acl_end2end/ .acl_end2end.clab.yml.bak +``` + +## Access cEOS Bash/CLI +```bash +docker exec -it clab-acl_end2end-r1 bash +docker exec -it clab-acl_end2end-r2 bash +docker exec -it clab-acl_end2end-r3 bash +docker exec -it clab-acl_end2end-r1 Cli +docker exec -it clab-acl_end2end-r2 Cli +docker exec -it clab-acl_end2end-r3 Cli +``` + +## Configure ContainerLab clients +```bash +docker exec -it clab-acl_end2end-dc1 bash + ip address add 172.16.1.10/24 dev eth1 + ip route add 172.16.2.0/24 via 172.16.1.1 + ping 172.16.2.10 + +docker exec -it clab-acl_end2end-dc2 bash + ip address add 172.16.2.10/24 dev eth1 + ip route add 172.16.1.0/24 via 172.16.2.1 + ping 172.16.1.10 +``` + +## Install gNMIc +```bash +sudo bash -c "$(curl -sL https://get-gnmic.kmrd.dev)" +``` + +## gNMI Capabilities request +```bash +gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure capabilities +``` + +## gNMI Get request +```bash +gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path / > r1.json +gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path /interfaces/interface > r1-ifaces.json +``` + +## gNMI Set request +```bash +gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf set --update-path /system/config/hostname --update-value srl11 +gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path /system/config/hostname +``` + +## Subscribe request +```bash +gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf subscribe --path /interfaces/interface[name=Management0]/state/ + +# In another terminal, you can generate traffic opening SSH connection +ssh admin@clab-acl_end2end-r1 +``` + +# Check configurations done: +```bash +gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path '/network-instances' > r1-nis.json +gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path '/interfaces' > r1-ifs.json +``` + +# Delete elements: +```bash +--address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf set --delete '/network-instances/network-instance[name=b19229e8]' +--address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf set --delete '/interfaces/interface[name=ethernet-1/1]/subinterfaces/subinterface[index=0]' +--address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf set --delete '/interfaces/interface[name=ethernet-1/2]/subinterfaces/subinterface[index=0]' +``` diff --git a/src/tests/acl_end2end/__init__.py b/src/tests/acl_end2end/__init__.py new file mode 100644 index 000000000..3ccc21c7d --- /dev/null +++ b/src/tests/acl_end2end/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/tests/acl_end2end/clab/acl_end2end.clab.yml b/src/tests/acl_end2end/clab/acl_end2end.clab.yml new file mode 100644 index 000000000..6a31872dc --- /dev/null +++ b/src/tests/acl_end2end/clab/acl_end2end.clab.yml @@ -0,0 +1,74 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# TFS - Arista devices + Linux clients + +name: acl_end2end + +mgmt: + network: mgmt-net + ipv4-subnet: 172.20.20.0/24 + +topology: + kinds: + arista_ceos: + kind: arista_ceos + #image: ceos:4.30.4M + #image: ceos:4.31.2F + #image: ceos:4.31.5M # tested, works + #image: ceos:4.32.0F + image: ceos:4.32.2F # tested, works + #image: ceos:4.32.2.1F + #image: ceos:4.33.1F # does not work, libyang.util.LibyangError: failed to parse data tree: No module named "openconfig-platform-healthz" in the context. + linux: + kind: linux + image: ghcr.io/hellt/network-multitool:latest + + nodes: + r1: + kind: arista_ceos + mgmt-ipv4: 172.20.20.101 + startup-config: r1-startup.cfg + + r2: + kind: arista_ceos + mgmt-ipv4: 172.20.20.102 + startup-config: r2-startup.cfg + + r3: + kind: arista_ceos + mgmt-ipv4: 172.20.20.103 + startup-config: r3-startup.cfg + + dc1: + kind: linux + mgmt-ipv4: 172.20.20.201 + exec: + - ip link set address 00:c1:ab:00:01:01 dev eth1 + - ip address add 172.16.1.10/24 dev eth1 + - ip route add 172.16.2.0/24 via 172.16.1.1 + + dc2: + kind: linux + mgmt-ipv4: 172.20.20.202 + exec: + - ip link set address 00:c1:ab:00:02:01 dev eth1 + - ip address add 172.16.2.10/24 dev eth1 + - ip route add 172.16.1.0/24 via 172.16.2.1 + + links: + - endpoints: ["r1:eth2", "r2:eth1"] + - endpoints: ["r2:eth3", "r3:eth2"] + - endpoints: ["r1:eth10", "dc1:eth1"] + - endpoints: ["r3:eth10", "dc2:eth1"] diff --git a/src/tests/acl_end2end/clab/r1-startup.cfg b/src/tests/acl_end2end/clab/r1-startup.cfg new file mode 100644 index 000000000..b7feebe06 --- /dev/null +++ b/src/tests/acl_end2end/clab/r1-startup.cfg @@ -0,0 +1,48 @@ +! device: r1 (cEOSLab, EOS-4.32.2F-38195967.4322F (engineering build)) +! +no aaa root +! +username admin privilege 15 role network-admin secret sha512 $6$OmfaAwJRg/r44r5U$9Fca1O1G6Bgsd4NKwSyvdRJcHHk71jHAR3apDWAgSTN/t/j1iroEhz5J36HjWjOF/jEVC/R8Wa60VmbX6.cr70 +! +management api http-commands + no shutdown +! +no service interface inactive port-id allocation disabled +! +transceiver qsfp default-mode 4x10G +! +service routing protocols model multi-agent +! +hostname r1 +! +spanning-tree mode mstp +! +system l1 + unsupported speed action error + unsupported error-correction action error +! +management api gnmi + transport grpc default +! +management api netconf + transport ssh default +! +interface Ethernet2 +! +interface Ethernet10 +! +interface Management0 + ip address 172.20.20.101/24 +! +ip routing +! +ip route 0.0.0.0/0 172.20.20.1 +! +router multicast + ipv4 + software-forwarding kernel + ! + ipv6 + software-forwarding kernel +! +end diff --git a/src/tests/acl_end2end/clab/r2-startup.cfg b/src/tests/acl_end2end/clab/r2-startup.cfg new file mode 100644 index 000000000..e1ab661a0 --- /dev/null +++ b/src/tests/acl_end2end/clab/r2-startup.cfg @@ -0,0 +1,48 @@ +! device: r2 (cEOSLab, EOS-4.32.2F-38195967.4322F (engineering build)) +! +no aaa root +! +username admin privilege 15 role network-admin secret sha512 $6$OmfaAwJRg/r44r5U$9Fca1O1G6Bgsd4NKwSyvdRJcHHk71jHAR3apDWAgSTN/t/j1iroEhz5J36HjWjOF/jEVC/R8Wa60VmbX6.cr70 +! +management api http-commands + no shutdown +! +no service interface inactive port-id allocation disabled +! +transceiver qsfp default-mode 4x10G +! +service routing protocols model multi-agent +! +hostname r2 +! +spanning-tree mode mstp +! +system l1 + unsupported speed action error + unsupported error-correction action error +! +management api gnmi + transport grpc default +! +management api netconf + transport ssh default +! +interface Ethernet1 +! +interface Ethernet3 +! +interface Management0 + ip address 172.20.20.102/24 +! +ip routing +! +ip route 0.0.0.0/0 172.20.20.1 +! +router multicast + ipv4 + software-forwarding kernel + ! + ipv6 + software-forwarding kernel +! +end diff --git a/src/tests/acl_end2end/clab/r3-startup.cfg b/src/tests/acl_end2end/clab/r3-startup.cfg new file mode 100644 index 000000000..63c062593 --- /dev/null +++ b/src/tests/acl_end2end/clab/r3-startup.cfg @@ -0,0 +1,48 @@ +! device: r3 (cEOSLab, EOS-4.32.2F-38195967.4322F (engineering build)) +! +no aaa root +! +username admin privilege 15 role network-admin secret sha512 $6$OmfaAwJRg/r44r5U$9Fca1O1G6Bgsd4NKwSyvdRJcHHk71jHAR3apDWAgSTN/t/j1iroEhz5J36HjWjOF/jEVC/R8Wa60VmbX6.cr70 +! +management api http-commands + no shutdown +! +no service interface inactive port-id allocation disabled +! +transceiver qsfp default-mode 4x10G +! +service routing protocols model multi-agent +! +hostname r3 +! +spanning-tree mode mstp +! +system l1 + unsupported speed action error + unsupported error-correction action error +! +management api gnmi + transport grpc default +! +management api netconf + transport ssh default +! +interface Ethernet2 +! +interface Ethernet10 +! +interface Management0 + ip address 172.20.20.103/24 +! +ip routing +! +ip route 0.0.0.0/0 172.20.20.1 +! +router multicast + ipv4 + software-forwarding kernel + ! + ipv6 + software-forwarding kernel +! +end diff --git a/src/tests/acl_end2end/data/ietf-l3vpn-service.json b/src/tests/acl_end2end/data/ietf-l3vpn-service.json new file mode 100644 index 000000000..a0f28ee06 --- /dev/null +++ b/src/tests/acl_end2end/data/ietf-l3vpn-service.json @@ -0,0 +1,83 @@ +{ + "ietf-l3vpn-svc:l3vpn-svc": { + "vpn-services": {"vpn-service": [{"vpn-id": "ietf-l3vpn-svc"}]}, + "sites": { + "site": [ + { + "site-id": "site_DC1", + "management": {"type": "ietf-l3vpn-svc:provider-managed"}, + "locations": {"location": [{"location-id": "DC1"}]}, + "devices": {"device": [{"device-id": "dc1", "location": "DC1"}]}, + "site-network-accesses": { + "site-network-access": [ + { + "site-network-access-id": "eth1", + "site-network-access-type": "ietf-l3vpn-svc:multipoint", + "device-reference": "dc1", + "vpn-attachment": {"vpn-id": "ietf-l3vpn-svc", "site-role": "ietf-l3vpn-svc:spoke-role"}, + "ip-connection": { + "ipv4": { + "address-allocation-type": "ietf-l3vpn-svc:static-address", + "addresses": { + "provider-address": "172.16.1.1", + "customer-address": "172.16.1.10", + "prefix-length": 24 + } + } + }, + "service": { + "svc-mtu": 1500, + "svc-input-bandwidth": 1000000000, + "svc-output-bandwidth": 1000000000, + "qos": {"qos-profile": {"classes": {"class": [{ + "class-id": "qos-realtime", + "direction": "ietf-l3vpn-svc:both", + "latency": {"latency-boundary": 10}, + "bandwidth": {"guaranteed-bw-percent": 100} + }]}}} + } + } + ] + } + }, + { + "site-id": "site_DC2", + "management": {"type": "ietf-l3vpn-svc:provider-managed"}, + "locations": {"location": [{"location-id": "DC2"}]}, + "devices": {"device": [{"device-id": "dc2", "location": "DC2"}]}, + "site-network-accesses": { + "site-network-access": [ + { + "site-network-access-id": "eth1", + "site-network-access-type": "ietf-l3vpn-svc:multipoint", + "device-reference": "dc2", + "vpn-attachment": {"vpn-id": "ietf-l3vpn-svc", "site-role": "ietf-l3vpn-svc:hub-role"}, + "ip-connection": { + "ipv4": { + "address-allocation-type": "ietf-l3vpn-svc:static-address", + "addresses": { + "provider-address": "172.16.2.1", + "customer-address": "172.16.2.10", + "prefix-length": 24 + } + } + }, + "service": { + "svc-mtu": 1500, + "svc-input-bandwidth": 1000000000, + "svc-output-bandwidth": 1000000000, + "qos": {"qos-profile": {"classes": {"class": [{ + "class-id": "qos-realtime", + "direction": "ietf-l3vpn-svc:both", + "latency": {"latency-boundary": 10}, + "bandwidth": {"guaranteed-bw-percent": 100} + }]}}} + } + } + ] + } + } + ] + } + } +} diff --git a/src/tests/acl_end2end/data/tfs-service.json b/src/tests/acl_end2end/data/tfs-service.json new file mode 100644 index 000000000..e4bb7c2d2 --- /dev/null +++ b/src/tests/acl_end2end/data/tfs-service.json @@ -0,0 +1,26 @@ +{ + "services": [ + { + "service_id": { + "context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "tfs-l3vpn-svc"} + }, + "service_type": "SERVICETYPE_L3NM", + "service_status": {"service_status": "SERVICESTATUS_PLANNED"}, + "service_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "dc1"}}, "endpoint_uuid": {"uuid": "int"}}, + {"device_id": {"device_uuid": {"uuid": "dc2"}}, "endpoint_uuid": {"uuid": "int"}} + ], + "service_constraints": [], + "service_config": {"config_rules": [ + {"action": "CONFIGACTION_SET", "custom": { + "resource_key": "/device[dc1]/endpoint[eth1]/settings", + "resource_value": {"address_ip": "172.16.1.10", "address_prefix": 24, "index": 0} + }}, + {"action": "CONFIGACTION_SET", "custom": { + "resource_key": "/device[dc2]/endpoint[eth1]/settings", + "resource_value": {"address_ip": "172.16.2.10", "address_prefix": 24, "index": 0} + }} + ]} + } + ] +} diff --git a/src/tests/acl_end2end/data/tfs-topology.json b/src/tests/acl_end2end/data/tfs-topology.json new file mode 100644 index 000000000..ac87af62d --- /dev/null +++ b/src/tests/acl_end2end/data/tfs-topology.json @@ -0,0 +1,126 @@ +{ + "contexts": [ + {"context_id": {"context_uuid": {"uuid": "admin"}}} + ], + "topologies": [ + {"topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}}} + ], + "devices": [ + { + "device_id": {"device_uuid": {"uuid": "dc1"}}, "device_type": "emu-datacenter", + "device_drivers": ["DEVICEDRIVER_UNDEFINED"], + "device_config": {"config_rules": [ + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"uuid": "eth1", "type": "copper"}, {"uuid": "int", "type": "copper"} + ]}}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "dc2"}}, "device_type": "emu-datacenter", + "device_drivers": ["DEVICEDRIVER_UNDEFINED"], + "device_config": {"config_rules": [ + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"uuid": "eth1", "type": "copper"}, {"uuid": "int", "type": "copper"} + ]}}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "r1"}}, "device_type": "packet-router", + "device_drivers": ["DEVICEDRIVER_GNMI_OPENCONFIG"], + "device_config": {"config_rules": [ + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "172.20.20.101"}}, + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "6030"}}, + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": { + "username": "admin", "password": "admin", "use_tls": false + }}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "r2"}}, "device_type": "packet-router", + "device_drivers": ["DEVICEDRIVER_GNMI_OPENCONFIG"], + "device_config": {"config_rules": [ + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "172.20.20.102"}}, + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "6030"}}, + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": { + "username": "admin", "password": "admin", "use_tls": false + }}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "r3"}}, "device_type": "packet-router", + "device_drivers": ["DEVICEDRIVER_GNMI_OPENCONFIG"], + "device_config": {"config_rules": [ + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "172.20.20.103"}}, + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "6030"}}, + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": { + "username": "admin", "password": "admin", "use_tls": false + }}} + ]} + } + ], + "links": [ + { + "link_id": {"link_uuid": {"uuid": "r1/Ethernet2==r2/Ethernet1"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "r1"}}, "endpoint_uuid": {"uuid": "Ethernet2"}}, + {"device_id": {"device_uuid": {"uuid": "r2"}}, "endpoint_uuid": {"uuid": "Ethernet1"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "r2/Ethernet1==r1/Ethernet2"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "r2"}}, "endpoint_uuid": {"uuid": "Ethernet1"}}, + {"device_id": {"device_uuid": {"uuid": "r1"}}, "endpoint_uuid": {"uuid": "Ethernet2"}} + ] + }, + + { + "link_id": {"link_uuid": {"uuid": "r2/Ethernet3==r3/Ethernet2"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "r2"}}, "endpoint_uuid": {"uuid": "Ethernet3"}}, + {"device_id": {"device_uuid": {"uuid": "r3"}}, "endpoint_uuid": {"uuid": "Ethernet2"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "r3/Ethernet2==r2/Ethernet3"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "r3"}}, "endpoint_uuid": {"uuid": "Ethernet2"}}, + {"device_id": {"device_uuid": {"uuid": "r2"}}, "endpoint_uuid": {"uuid": "Ethernet3"}} + ] + }, + + { + "link_id": {"link_uuid": {"uuid": "r1/Ethernet10==dc1/eth1"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "r1"}}, "endpoint_uuid": {"uuid": "Ethernet10"}}, + {"device_id": {"device_uuid": {"uuid": "dc1"}}, "endpoint_uuid": {"uuid": "eth1"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "dc1/eth1==r1/Ethernet10"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "dc1"}}, "endpoint_uuid": {"uuid": "eth1"}}, + {"device_id": {"device_uuid": {"uuid": "r1"}}, "endpoint_uuid": {"uuid": "Ethernet10"}} + ] + }, + + { + "link_id": {"link_uuid": {"uuid": "r3/Ethernet10==dc2/eth1"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "r3"}}, "endpoint_uuid": {"uuid": "Ethernet10"}}, + {"device_id": {"device_uuid": {"uuid": "dc2"}}, "endpoint_uuid": {"uuid": "eth1"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "dc2/eth1==r3/Ethernet10"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "dc2"}}, "endpoint_uuid": {"uuid": "eth1"}}, + {"device_id": {"device_uuid": {"uuid": "r3"}}, "endpoint_uuid": {"uuid": "Ethernet10"}} + ] + } + ] +} diff --git a/src/tests/acl_end2end/deploy-scripts/clab-cli-dc1.sh b/src/tests/acl_end2end/deploy-scripts/clab-cli-dc1.sh new file mode 100755 index 000000000..2da0f61cb --- /dev/null +++ b/src/tests/acl_end2end/deploy-scripts/clab-cli-dc1.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +docker exec -it clab-acl_end2end-dc1 bash diff --git a/src/tests/acl_end2end/deploy-scripts/clab-cli-dc2.sh b/src/tests/acl_end2end/deploy-scripts/clab-cli-dc2.sh new file mode 100755 index 000000000..873c1cbc8 --- /dev/null +++ b/src/tests/acl_end2end/deploy-scripts/clab-cli-dc2.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +docker exec -it clab-acl_end2end-dc2 bash diff --git a/src/tests/acl_end2end/deploy-scripts/clab-cli-r1.sh b/src/tests/acl_end2end/deploy-scripts/clab-cli-r1.sh new file mode 100755 index 000000000..bb68a32e1 --- /dev/null +++ b/src/tests/acl_end2end/deploy-scripts/clab-cli-r1.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +docker exec -it clab-acl_end2end-r1 Cli diff --git a/src/tests/acl_end2end/deploy-scripts/clab-cli-r2.sh b/src/tests/acl_end2end/deploy-scripts/clab-cli-r2.sh new file mode 100755 index 000000000..1aebae12d --- /dev/null +++ b/src/tests/acl_end2end/deploy-scripts/clab-cli-r2.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +docker exec -it clab-acl_end2end-r2 Cli diff --git a/src/tests/acl_end2end/deploy-scripts/clab-cli-r3.sh b/src/tests/acl_end2end/deploy-scripts/clab-cli-r3.sh new file mode 100755 index 000000000..47b12cc90 --- /dev/null +++ b/src/tests/acl_end2end/deploy-scripts/clab-cli-r3.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +docker exec -it clab-acl_end2end-r3 Cli diff --git a/src/tests/acl_end2end/deploy-scripts/clab-deploy.sh b/src/tests/acl_end2end/deploy-scripts/clab-deploy.sh new file mode 100755 index 000000000..5389305a4 --- /dev/null +++ b/src/tests/acl_end2end/deploy-scripts/clab-deploy.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cd ~/tfs-ctrl/src/tests/acl_end2end +sudo containerlab deploy --topo acl_end2end.clab.yml diff --git a/src/tests/acl_end2end/deploy-scripts/clab-destroy.sh b/src/tests/acl_end2end/deploy-scripts/clab-destroy.sh new file mode 100755 index 000000000..f9bcc9883 --- /dev/null +++ b/src/tests/acl_end2end/deploy-scripts/clab-destroy.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cd ~/tfs-ctrl/src/tests/acl_end2end +sudo containerlab destroy --topo acl_end2end.clab.yml +sudo rm -rf clab-acl_end2end/ .acl_end2end.clab.yml.bak diff --git a/src/tests/acl_end2end/deploy-scripts/clab-inspect.sh b/src/tests/acl_end2end/deploy-scripts/clab-inspect.sh new file mode 100755 index 000000000..bec97444d --- /dev/null +++ b/src/tests/acl_end2end/deploy-scripts/clab-inspect.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cd ~/tfs-ctrl/src/tests/acl_end2end +sudo containerlab inspect --topo acl_end2end.clab.yml diff --git a/src/tests/acl_end2end/deploy_specs.sh b/src/tests/acl_end2end/deploy_specs.sh new file mode 100755 index 000000000..72cd25b58 --- /dev/null +++ b/src/tests/acl_end2end/deploy_specs.sh @@ -0,0 +1,208 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# ----- TeraFlowSDN ------------------------------------------------------------ + +# Set the URL of the internal MicroK8s Docker registry where the images will be uploaded to. +export TFS_REGISTRY_IMAGES="http://localhost:32000/tfs/" + +# Set the list of components, separated by spaces, you want to build images for, and deploy. +#export TFS_COMPONENTS="context device pathcomp service slice nbi webui load_generator" +export TFS_COMPONENTS="context device pathcomp service nbi" + +# Uncomment to activate Monitoring (old) +#export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring" + +# Uncomment to activate Monitoring Framework (new) +#export TFS_COMPONENTS="${TFS_COMPONENTS} kpi_manager kpi_value_writer kpi_value_api telemetry analytics automation" + +# Uncomment to activate QoS Profiles +#export TFS_COMPONENTS="${TFS_COMPONENTS} qos_profile" + +# Uncomment to activate BGP-LS Speaker +#export TFS_COMPONENTS="${TFS_COMPONENTS} bgpls_speaker" + +# Uncomment to activate Optical Controller +# To manage optical connections, "service" requires "opticalcontroller" to be deployed +# before "service", thus we "hack" the TFS_COMPONENTS environment variable prepending the +# "opticalcontroller" only if "service" is already in TFS_COMPONENTS, and re-export it. +#if [[ "$TFS_COMPONENTS" == *"service"* ]]; then +# BEFORE="${TFS_COMPONENTS% service*}" +# AFTER="${TFS_COMPONENTS#* service}" +# export TFS_COMPONENTS="${BEFORE} opticalcontroller service ${AFTER}" +#fi + +# Uncomment to activate ZTP +#export TFS_COMPONENTS="${TFS_COMPONENTS} ztp" + +# Uncomment to activate Policy Manager +#export TFS_COMPONENTS="${TFS_COMPONENTS} policy" + +# Uncomment to activate Optical CyberSecurity +#export TFS_COMPONENTS="${TFS_COMPONENTS} dbscanserving opticalattackmitigator opticalattackdetector opticalattackmanager" + +# Uncomment to activate L3 CyberSecurity +#export TFS_COMPONENTS="${TFS_COMPONENTS} l3_attackmitigator l3_centralizedattackdetector" + +# Uncomment to activate TE +#export TFS_COMPONENTS="${TFS_COMPONENTS} te" + +# Uncomment to activate Forecaster +#export TFS_COMPONENTS="${TFS_COMPONENTS} forecaster" + +# Uncomment to activate E2E Orchestrator +#export TFS_COMPONENTS="${TFS_COMPONENTS} e2e_orchestrator" + +# Uncomment to activate DLT and Interdomain +#export TFS_COMPONENTS="${TFS_COMPONENTS} interdomain dlt" +#if [[ "$TFS_COMPONENTS" == *"dlt"* ]]; then +# export KEY_DIRECTORY_PATH="src/dlt/gateway/keys/priv_sk" +# export CERT_DIRECTORY_PATH="src/dlt/gateway/keys/cert.pem" +# export TLS_CERT_PATH="src/dlt/gateway/keys/ca.crt" +#fi + +# Uncomment to activate QKD App +# To manage QKD Apps, "service" requires "qkd_app" to be deployed +# before "service", thus we "hack" the TFS_COMPONENTS environment variable prepending the +# "qkd_app" only if "service" is already in TFS_COMPONENTS, and re-export it. +#if [[ "$TFS_COMPONENTS" == *"service"* ]]; then +# BEFORE="${TFS_COMPONENTS% service*}" +# AFTER="${TFS_COMPONENTS#* service}" +# export TFS_COMPONENTS="${BEFORE} qkd_app service ${AFTER}" +#fi + + +# Set the tag you want to use for your images. +export TFS_IMAGE_TAG="dev" + +# Set the name of the Kubernetes namespace to deploy TFS to. +export TFS_K8S_NAMESPACE="tfs" + +# Set additional manifest files to be applied after the deployment +export TFS_EXTRA_MANIFESTS="manifests/nginx_ingress_http.yaml" + +# Uncomment to monitor performance of components +#export TFS_EXTRA_MANIFESTS="${TFS_EXTRA_MANIFESTS} manifests/servicemonitors.yaml" + +# Uncomment when deploying Optical CyberSecurity +#export TFS_EXTRA_MANIFESTS="${TFS_EXTRA_MANIFESTS} manifests/cachingservice.yaml" + +# Set the new Grafana admin password +export TFS_GRAFANA_PASSWORD="admin123+" + +# Disable skip-build flag to rebuild the Docker images. +export TFS_SKIP_BUILD="" + + +# ----- CockroachDB ------------------------------------------------------------ + +# Set the namespace where CockroackDB will be deployed. +export CRDB_NAMESPACE="crdb" + +# Set the external port CockroackDB Postgre SQL interface will be exposed to. +export CRDB_EXT_PORT_SQL="26257" + +# Set the external port CockroackDB HTTP Mgmt GUI interface will be exposed to. +export CRDB_EXT_PORT_HTTP="8081" + +# Set the database username to be used by Context. +export CRDB_USERNAME="tfs" + +# Set the database user's password to be used by Context. +export CRDB_PASSWORD="tfs123" + +# Set CockroachDB installation mode to 'single'. This option is convenient for development and testing. +# See ./deploy/all.sh or ./deploy/crdb.sh for additional details +export CRDB_DEPLOY_MODE="single" + +# Disable flag for dropping database, if it exists. +export CRDB_DROP_DATABASE_IF_EXISTS="YES" + +# Disable flag for re-deploying CockroachDB from scratch. +export CRDB_REDEPLOY="" + + +# ----- NATS ------------------------------------------------------------------- + +# Set the namespace where NATS will be deployed. +export NATS_NAMESPACE="nats" + +# Set the external port NATS Client interface will be exposed to. +export NATS_EXT_PORT_CLIENT="4222" + +# Set the external port NATS HTTP Mgmt GUI interface will be exposed to. +export NATS_EXT_PORT_HTTP="8222" + +# Set NATS installation mode to 'single'. This option is convenient for development and testing. +# See ./deploy/all.sh or ./deploy/nats.sh for additional details +export NATS_DEPLOY_MODE="single" + +# Disable flag for re-deploying NATS from scratch. +export NATS_REDEPLOY="" + + +# ----- QuestDB ---------------------------------------------------------------- + +# Set the namespace where QuestDB will be deployed. +export QDB_NAMESPACE="qdb" + +# Set the external port QuestDB Postgre SQL interface will be exposed to. +export QDB_EXT_PORT_SQL="8812" + +# Set the external port QuestDB Influx Line Protocol interface will be exposed to. +export QDB_EXT_PORT_ILP="9009" + +# Set the external port QuestDB HTTP Mgmt GUI interface will be exposed to. +export QDB_EXT_PORT_HTTP="9000" + +# Set the database username to be used for QuestDB. +export QDB_USERNAME="admin" + +# Set the database user's password to be used for QuestDB. +export QDB_PASSWORD="quest" + +# Set the table name to be used by Monitoring for KPIs. +export QDB_TABLE_MONITORING_KPIS="tfs_monitoring_kpis" + +# Set the table name to be used by Slice for plotting groups. +export QDB_TABLE_SLICE_GROUPS="tfs_slice_groups" + +# Disable flag for dropping tables if they exist. +export QDB_DROP_TABLES_IF_EXIST="YES" + +# Disable flag for re-deploying QuestDB from scratch. +export QDB_REDEPLOY="" + + +# ----- K8s Observability ------------------------------------------------------ + +# Set the external port Prometheus Mgmt HTTP GUI interface will be exposed to. +export PROM_EXT_PORT_HTTP="9090" + +# Set the external port Grafana HTTP Dashboards will be exposed to. +export GRAF_EXT_PORT_HTTP="3000" + + +# ----- Apache Kafka ----------------------------------------------------------- + +# Set the namespace where Apache Kafka will be deployed. +export KFK_NAMESPACE="kafka" + +# Set the port Apache Kafka server will be exposed to. +export KFK_SERVER_PORT="9092" + +# Set the flag to YES for redeploying of Apache Kafka +export KFK_REDEPLOY="" diff --git a/src/tests/acl_end2end/redeploy-tfs.sh b/src/tests/acl_end2end/redeploy-tfs.sh new file mode 100755 index 000000000..614cbf2a7 --- /dev/null +++ b/src/tests/acl_end2end/redeploy-tfs.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source ~/tfs-ctrl/src/tests/acl_end2end/deploy_specs.sh +./deploy/all.sh diff --git a/src/tests/acl_end2end/requirements.in b/src/tests/acl_end2end/requirements.in new file mode 100644 index 000000000..5c92783a2 --- /dev/null +++ b/src/tests/acl_end2end/requirements.in @@ -0,0 +1,15 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +requests==2.27.* diff --git a/src/tests/acl_end2end/scripts/run-cleanup.sh b/src/tests/acl_end2end/scripts/run-cleanup.sh new file mode 100755 index 000000000..65329f32f --- /dev/null +++ b/src/tests/acl_end2end/scripts/run-cleanup.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source /var/teraflow/tfs_runtime_env_vars.sh +export PYTHONPATH=/var/teraflow +pytest --verbose --log-level=INFO \ + --junitxml=/opt/results/report_cleanup.xml \ + /var/teraflow/tests/acl_end2end/tests/test_cleanup.py diff --git a/src/tests/acl_end2end/scripts/run-onboarding.sh b/src/tests/acl_end2end/scripts/run-onboarding.sh new file mode 100755 index 000000000..c01580ac4 --- /dev/null +++ b/src/tests/acl_end2end/scripts/run-onboarding.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source /var/teraflow/tfs_runtime_env_vars.sh +export PYTHONPATH=/var/teraflow +pytest --verbose --log-level=INFO \ + --junitxml=/opt/results/report_onboarding.xml \ + /var/teraflow/tests/acl_end2end/tests/test_onboarding.py diff --git a/src/tests/acl_end2end/scripts/run-service-ietf-create.sh b/src/tests/acl_end2end/scripts/run-service-ietf-create.sh new file mode 100755 index 000000000..bc592f32f --- /dev/null +++ b/src/tests/acl_end2end/scripts/run-service-ietf-create.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source /var/teraflow/tfs_runtime_env_vars.sh +export PYTHONPATH=/var/teraflow +pytest --verbose --log-level=INFO \ + --junitxml=/opt/results/report_service_ietf_create.xml \ + /var/teraflow/tests/acl_end2end/tests/test_service_ietf_create.py diff --git a/src/tests/acl_end2end/scripts/run-service-ietf-remove.sh b/src/tests/acl_end2end/scripts/run-service-ietf-remove.sh new file mode 100755 index 000000000..cd55fdaa1 --- /dev/null +++ b/src/tests/acl_end2end/scripts/run-service-ietf-remove.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source /var/teraflow/tfs_runtime_env_vars.sh +export PYTHONPATH=/var/teraflow +pytest --verbose --log-level=INFO \ + --junitxml=/opt/results/report_service_ietf_remove.xml \ + /var/teraflow/tests/acl_end2end/tests/test_service_ietf_remove.py diff --git a/src/tests/acl_end2end/scripts/run-service-tfs-create.sh b/src/tests/acl_end2end/scripts/run-service-tfs-create.sh new file mode 100755 index 000000000..9a902e422 --- /dev/null +++ b/src/tests/acl_end2end/scripts/run-service-tfs-create.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source /var/teraflow/tfs_runtime_env_vars.sh +export PYTHONPATH=/var/teraflow +pytest --verbose --log-level=INFO \ + --junitxml=/opt/results/report_service_tfs_create.xml \ + /var/teraflow/tests/acl_end2end/tests/test_service_tfs_create.py diff --git a/src/tests/acl_end2end/scripts/run-service-tfs-remove.sh b/src/tests/acl_end2end/scripts/run-service-tfs-remove.sh new file mode 100755 index 000000000..d284097c7 --- /dev/null +++ b/src/tests/acl_end2end/scripts/run-service-tfs-remove.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source /var/teraflow/tfs_runtime_env_vars.sh +export PYTHONPATH=/var/teraflow +pytest --verbose --log-level=INFO \ + --junitxml=/opt/results/report_service_tfs_remove.xml \ + /var/teraflow/tests/acl_end2end/tests/test_service_tfs_remove.py diff --git a/src/tests/acl_end2end/tests/Fixtures.py b/src/tests/acl_end2end/tests/Fixtures.py new file mode 100644 index 000000000..5997e58c8 --- /dev/null +++ b/src/tests/acl_end2end/tests/Fixtures.py @@ -0,0 +1,43 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from context.client.ContextClient import ContextClient +from device.client.DeviceClient import DeviceClient +from monitoring.client.MonitoringClient import MonitoringClient +from service.client.ServiceClient import ServiceClient + +@pytest.fixture(scope='session') +def context_client(): + _client = ContextClient() + yield _client + _client.close() + +@pytest.fixture(scope='session') +def device_client(): + _client = DeviceClient() + yield _client + _client.close() + +@pytest.fixture(scope='session') +def monitoring_client(): + _client = MonitoringClient() + yield _client + _client.close() + +@pytest.fixture(scope='session') +def service_client(): + _client = ServiceClient() + yield _client + _client.close() diff --git a/src/tests/acl_end2end/tests/Tools.py b/src/tests/acl_end2end/tests/Tools.py new file mode 100644 index 000000000..bbee845cd --- /dev/null +++ b/src/tests/acl_end2end/tests/Tools.py @@ -0,0 +1,109 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import enum, logging, requests +from typing import Any, Dict, List, Optional, Set, Union +from common.Constants import ServiceNameEnum +from common.Settings import get_service_host, get_service_port_http + +NBI_ADDRESS = get_service_host(ServiceNameEnum.NBI) +NBI_PORT = get_service_port_http(ServiceNameEnum.NBI) +NBI_USERNAME = 'admin' +NBI_PASSWORD = 'admin' +NBI_BASE_URL = '' + +class RestRequestMethod(enum.Enum): + GET = 'get' + POST = 'post' + PUT = 'put' + PATCH = 'patch' + DELETE = 'delete' + +EXPECTED_STATUS_CODES : Set[int] = { + requests.codes['OK' ], + requests.codes['CREATED' ], + requests.codes['ACCEPTED' ], + requests.codes['NO_CONTENT'], +} + +def do_rest_request( + method : RestRequestMethod, url : str, body : Optional[Any] = None, timeout : int = 10, + allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES, + logger : Optional[logging.Logger] = None +) -> Optional[Union[Dict, List]]: + request_url = 'http://{:s}:{:s}@{:s}:{:d}{:s}{:s}'.format( + NBI_USERNAME, NBI_PASSWORD, NBI_ADDRESS, NBI_PORT, str(NBI_BASE_URL), url + ) + + if logger is not None: + msg = 'Request: {:s} {:s}'.format(str(method.value).upper(), str(request_url)) + if body is not None: msg += ' body={:s}'.format(str(body)) + logger.warning(msg) + reply = requests.request(method.value, request_url, timeout=timeout, json=body, allow_redirects=allow_redirects) + if logger is not None: + logger.warning('Reply: {:s}'.format(str(reply.text))) + assert reply.status_code in expected_status_codes, 'Reply failed with status code {:d}'.format(reply.status_code) + + if reply.content and len(reply.content) > 0: return reply.json() + return None + +def do_rest_get_request( + url : str, body : Optional[Any] = None, timeout : int = 10, + allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES, + logger : Optional[logging.Logger] = None +) -> Optional[Union[Dict, List]]: + return do_rest_request( + RestRequestMethod.GET, url, body=body, timeout=timeout, allow_redirects=allow_redirects, + expected_status_codes=expected_status_codes, logger=logger + ) + +def do_rest_post_request( + url : str, body : Optional[Any] = None, timeout : int = 10, + allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES, + logger : Optional[logging.Logger] = None +) -> Optional[Union[Dict, List]]: + return do_rest_request( + RestRequestMethod.POST, url, body=body, timeout=timeout, allow_redirects=allow_redirects, + expected_status_codes=expected_status_codes, logger=logger + ) + +def do_rest_put_request( + url : str, body : Optional[Any] = None, timeout : int = 10, + allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES, + logger : Optional[logging.Logger] = None +) -> Optional[Union[Dict, List]]: + return do_rest_request( + RestRequestMethod.PUT, url, body=body, timeout=timeout, allow_redirects=allow_redirects, + expected_status_codes=expected_status_codes, logger=logger + ) + +def do_rest_patch_request( + url : str, body : Optional[Any] = None, timeout : int = 10, + allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES, + logger : Optional[logging.Logger] = None +) -> Optional[Union[Dict, List]]: + return do_rest_request( + RestRequestMethod.PATCH, url, body=body, timeout=timeout, allow_redirects=allow_redirects, + expected_status_codes=expected_status_codes, logger=logger + ) + +def do_rest_delete_request( + url : str, body : Optional[Any] = None, timeout : int = 10, + allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES, + logger : Optional[logging.Logger] = None +) -> Optional[Union[Dict, List]]: + return do_rest_request( + RestRequestMethod.DELETE, url, body=body, timeout=timeout, allow_redirects=allow_redirects, + expected_status_codes=expected_status_codes, logger=logger + ) diff --git a/src/tests/acl_end2end/tests/__init__.py b/src/tests/acl_end2end/tests/__init__.py new file mode 100644 index 000000000..3ccc21c7d --- /dev/null +++ b/src/tests/acl_end2end/tests/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/tests/acl_end2end/tests/test_cleanup.py b/src/tests/acl_end2end/tests/test_cleanup.py new file mode 100644 index 000000000..20afb5fe0 --- /dev/null +++ b/src/tests/acl_end2end/tests/test_cleanup.py @@ -0,0 +1,44 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging, os +from common.Constants import DEFAULT_CONTEXT_NAME +from common.proto.context_pb2 import ContextId +from common.tools.descriptor.Loader import DescriptorLoader, validate_empty_scenario +from common.tools.object_factory.Context import json_context_id +from context.client.ContextClient import ContextClient +from device.client.DeviceClient import DeviceClient +from .Fixtures import context_client, device_client # pylint: disable=unused-import + +LOGGER = logging.getLogger(__name__) +LOGGER.setLevel(logging.DEBUG) + +DESCRIPTOR_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'tfs-topology.json') +ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) + +def test_scenario_cleanup( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name +) -> None: + # Verify the scenario has no services/slices + response = context_client.GetContext(ADMIN_CONTEXT_ID) + assert len(response.service_ids) == 0 + assert len(response.slice_ids) == 0 + + # Load descriptors and validate the base scenario + descriptor_loader = DescriptorLoader( + descriptors_file=DESCRIPTOR_FILE, context_client=context_client, device_client=device_client) + descriptor_loader.validate() + descriptor_loader.unload() + validate_empty_scenario(context_client) diff --git a/src/tests/acl_end2end/tests/test_onboarding.py b/src/tests/acl_end2end/tests/test_onboarding.py new file mode 100644 index 000000000..763d7da17 --- /dev/null +++ b/src/tests/acl_end2end/tests/test_onboarding.py @@ -0,0 +1,67 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging, os, time +from common.Constants import DEFAULT_CONTEXT_NAME +from common.proto.context_pb2 import ContextId, DeviceOperationalStatusEnum, Empty +from common.tools.descriptor.Loader import DescriptorLoader, check_descriptor_load_results, validate_empty_scenario +from common.tools.object_factory.Context import json_context_id +from context.client.ContextClient import ContextClient +from device.client.DeviceClient import DeviceClient +from .Fixtures import context_client, device_client # pylint: disable=unused-import + +LOGGER = logging.getLogger(__name__) +LOGGER.setLevel(logging.DEBUG) + +DESCRIPTOR_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'tfs-topology.json') +ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) + +def test_scenario_onboarding( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name +) -> None: + validate_empty_scenario(context_client) + + descriptor_loader = DescriptorLoader( + descriptors_file=DESCRIPTOR_FILE, context_client=context_client, device_client=device_client) + results = descriptor_loader.process() + check_descriptor_load_results(results, descriptor_loader) + descriptor_loader.validate() + + # Verify the scenario has no services/slices + response = context_client.GetContext(ADMIN_CONTEXT_ID) + assert len(response.service_ids) == 0 + assert len(response.slice_ids) == 0 + +def test_scenario_devices_enabled( + context_client : ContextClient, # pylint: disable=redefined-outer-name +) -> None: + """ + This test validates that the devices are enabled. + """ + DEVICE_OP_STATUS_ENABLED = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED + + num_devices = -1 + num_devices_enabled, num_retry = 0, 0 + while (num_devices != num_devices_enabled) and (num_retry < 10): + time.sleep(1.0) + response = context_client.ListDevices(Empty()) + num_devices = len(response.devices) + num_devices_enabled = 0 + for device in response.devices: + if device.device_operational_status != DEVICE_OP_STATUS_ENABLED: continue + num_devices_enabled += 1 + LOGGER.info('Num Devices enabled: {:d}/{:d}'.format(num_devices_enabled, num_devices)) + num_retry += 1 + assert num_devices_enabled == num_devices diff --git a/src/tests/acl_end2end/tests/test_service_ietf_create.py b/src/tests/acl_end2end/tests/test_service_ietf_create.py new file mode 100644 index 000000000..f3a68801d --- /dev/null +++ b/src/tests/acl_end2end/tests/test_service_ietf_create.py @@ -0,0 +1,71 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json, logging, os +from typing import Dict +from common.Constants import DEFAULT_CONTEXT_NAME +from common.proto.context_pb2 import ContextId, ServiceStatusEnum, ServiceTypeEnum +from common.tools.grpc.Tools import grpc_message_to_json_string +from common.tools.object_factory.Context import json_context_id +from context.client.ContextClient import ContextClient +from .Fixtures import context_client # pylint: disable=unused-import +from .Tools import do_rest_get_request, do_rest_post_request + + +LOGGER = logging.getLogger(__name__) +LOGGER.setLevel(logging.DEBUG) + +REQUEST_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'ietf-l3vpn-service.json') +ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) + + +# pylint: disable=redefined-outer-name, unused-argument +def test_service_ietf_creation( + context_client : ContextClient, +): + # Issue service creation request + with open(REQUEST_FILE, 'r', encoding='UTF-8') as f: + svc1_data = json.load(f) + URL = '/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services' + do_rest_post_request(URL, body=svc1_data, logger=LOGGER, expected_status_codes={201}) + vpn_id = svc1_data['ietf-l3vpn-svc:l3vpn-svc']['vpn-services']['vpn-service'][0]['vpn-id'] + + URL = '/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services/vpn-service={:s}/'.format(vpn_id) + service_data = do_rest_get_request(URL, logger=LOGGER, expected_status_codes={200}) + service_uuid = service_data['service-id'] + + # Verify service was created + response = context_client.GetContext(ADMIN_CONTEXT_ID) + assert len(response.service_ids) == 1 + assert len(response.slice_ids) == 0 + + # Check there is 1 service + response = context_client.ListServices(ADMIN_CONTEXT_ID) + LOGGER.warning('Services[{:d}] = {:s}'.format( + len(response.services), grpc_message_to_json_string(response) + )) + assert len(response.services) == 1 + + for service in response.services: + service_id = service.service_id + assert service_id.service_uuid.uuid == service_uuid + assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE + assert service.service_type == ServiceTypeEnum.SERVICETYPE_L3NM + + response = context_client.ListConnections(service_id) + LOGGER.warning(' ServiceId[{:s}] => Connections[{:d}] = {:s}'.format( + grpc_message_to_json_string(service_id), len(response.connections), + grpc_message_to_json_string(response) + )) + assert len(response.connections) == 1 diff --git a/src/tests/acl_end2end/tests/test_service_ietf_remove.py b/src/tests/acl_end2end/tests/test_service_ietf_remove.py new file mode 100644 index 000000000..2c3920824 --- /dev/null +++ b/src/tests/acl_end2end/tests/test_service_ietf_remove.py @@ -0,0 +1,77 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging, os +from typing import Dict, Set, Tuple +from common.Constants import DEFAULT_CONTEXT_NAME +from common.proto.context_pb2 import ContextId, ServiceStatusEnum, ServiceTypeEnum +from common.tools.grpc.Tools import grpc_message_to_json_string +from common.tools.object_factory.Context import json_context_id +from context.client.ContextClient import ContextClient +from .Fixtures import context_client # pylint: disable=unused-import +from .Tools import do_rest_delete_request + + +LOGGER = logging.getLogger(__name__) +LOGGER.setLevel(logging.DEBUG) + +REQUEST_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'ietf-l3vpn-service.json') +ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) + + +# pylint: disable=redefined-outer-name, unused-argument +def test_service_ietf_removal( + context_client : ContextClient, # pylint: disable=redefined-outer-name +): + # Verify the scenario has 1 service and 0 slices + response = context_client.GetContext(ADMIN_CONTEXT_ID) + assert len(response.service_ids) == 1 + assert len(response.slice_ids) == 0 + + # Check there are no slices + response = context_client.ListSlices(ADMIN_CONTEXT_ID) + LOGGER.warning('Slices[{:d}] = {:s}'.format(len(response.slices), grpc_message_to_json_string(response))) + assert len(response.slices) == 0 + + # Check there is 1 service + response = context_client.ListServices(ADMIN_CONTEXT_ID) + LOGGER.warning('Services[{:d}] = {:s}'.format(len(response.services), grpc_message_to_json_string(response))) + assert len(response.services) == 1 + + service_uuids : Set[str] = set() + for service in response.services: + service_id = service.service_id + assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE + assert service.service_type == ServiceTypeEnum.SERVICETYPE_L3NM + + response = context_client.ListConnections(service_id) + LOGGER.warning(' ServiceId[{:s}] => Connections[{:d}] = {:s}'.format( + grpc_message_to_json_string(service_id), len(response.connections), + grpc_message_to_json_string(response) + )) + assert len(response.connections) == 1 + + service_uuids.add(service_id.service_uuid.uuid) + + # Identify service to delete + assert len(service_uuids) == 1 + service_uuid = set(service_uuids).pop() + + URL = '/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services/vpn-service={:s}/'.format(service_uuid) + do_rest_delete_request(URL, logger=LOGGER, expected_status_codes={204}) + + # Verify the scenario has no services/slices + response = context_client.GetContext(ADMIN_CONTEXT_ID) + assert len(response.service_ids) == 0 + assert len(response.slice_ids) == 0 diff --git a/src/tests/acl_end2end/tests/test_service_tfs_create.py b/src/tests/acl_end2end/tests/test_service_tfs_create.py new file mode 100644 index 000000000..301602792 --- /dev/null +++ b/src/tests/acl_end2end/tests/test_service_tfs_create.py @@ -0,0 +1,76 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging, os +from common.Constants import DEFAULT_CONTEXT_NAME +from common.proto.context_pb2 import ContextId, ServiceStatusEnum, ServiceTypeEnum +from common.tools.descriptor.Loader import DescriptorLoader, check_descriptor_load_results +from common.tools.grpc.Tools import grpc_message_to_json_string +from common.tools.object_factory.Context import json_context_id +from context.client.ContextClient import ContextClient +from device.client.DeviceClient import DeviceClient +from service.client.ServiceClient import ServiceClient +from .Fixtures import context_client, device_client, service_client # pylint: disable=unused-import + + +LOGGER = logging.getLogger(__name__) +LOGGER.setLevel(logging.DEBUG) + +DESCRIPTOR_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'tfs-service.json') +ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) + + +def test_service_tfs_creation( + context_client : ContextClient, # pylint: disable=redefined-outer-name + device_client : DeviceClient, # pylint: disable=redefined-outer-name + service_client : ServiceClient, # pylint: disable=redefined-outer-name +): + # Load descriptors and validate the base scenario + descriptor_loader = DescriptorLoader( + descriptors_file=DESCRIPTOR_FILE, context_client=context_client, + device_client=device_client, service_client=service_client + ) + results = descriptor_loader.process() + check_descriptor_load_results(results, descriptor_loader) + + # Verify the scenario has 1 service and 0 slices + response = context_client.GetContext(ADMIN_CONTEXT_ID) + assert len(response.service_ids) == 1 + assert len(response.slice_ids) == 0 + + # Check there are no slices + response = context_client.ListSlices(ADMIN_CONTEXT_ID) + LOGGER.warning('Slices[{:d}] = {:s}'.format( + len(response.slices), grpc_message_to_json_string(response) + )) + assert len(response.slices) == 0 + + # Check there is 1 service + response = context_client.ListServices(ADMIN_CONTEXT_ID) + LOGGER.warning('Services[{:d}] = {:s}'.format( + len(response.services), grpc_message_to_json_string(response) + )) + assert len(response.services) == 1 + + for service in response.services: + service_id = service.service_id + assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE + assert service.service_type == ServiceTypeEnum.SERVICETYPE_L3NM + + response = context_client.ListConnections(service_id) + LOGGER.warning(' ServiceId[{:s}] => Connections[{:d}] = {:s}'.format( + grpc_message_to_json_string(service_id), len(response.connections), + grpc_message_to_json_string(response) + )) + assert len(response.connections) == 1 diff --git a/src/tests/acl_end2end/tests/test_service_tfs_remove.py b/src/tests/acl_end2end/tests/test_service_tfs_remove.py new file mode 100644 index 000000000..50d4acb7a --- /dev/null +++ b/src/tests/acl_end2end/tests/test_service_tfs_remove.py @@ -0,0 +1,80 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging, os +from typing import Set, Tuple +from common.Constants import DEFAULT_CONTEXT_NAME +from common.proto.context_pb2 import ContextId, ServiceId, ServiceStatusEnum, ServiceTypeEnum +from common.tools.grpc.Tools import grpc_message_to_json_string +from common.tools.object_factory.Context import json_context_id +from common.tools.object_factory.Service import json_service_id +from context.client.ContextClient import ContextClient +from service.client.ServiceClient import ServiceClient +from .Fixtures import context_client, service_client # pylint: disable=unused-import + + +LOGGER = logging.getLogger(__name__) +LOGGER.setLevel(logging.DEBUG) + +DESCRIPTOR_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'tfs-service.json') +ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) + + +def test_service_tfs_removal( + context_client : ContextClient, # pylint: disable=redefined-outer-name + service_client : ServiceClient, # pylint: disable=redefined-outer-name +): + # Verify the scenario has 1 service and 0 slices + response = context_client.GetContext(ADMIN_CONTEXT_ID) + assert len(response.service_ids) == 1 + assert len(response.slice_ids) == 0 + + # Check there are no slices + response = context_client.ListSlices(ADMIN_CONTEXT_ID) + LOGGER.warning('Slices[{:d}] = {:s}'.format(len(response.slices), grpc_message_to_json_string(response))) + assert len(response.slices) == 0 + + # Check there is 1 service + response = context_client.ListServices(ADMIN_CONTEXT_ID) + LOGGER.warning('Services[{:d}] = {:s}'.format(len(response.services), grpc_message_to_json_string(response))) + assert len(response.services) == 1 + + context_service_uuids : Set[Tuple[str, str]] = set() + for service in response.services: + service_id = service.service_id + assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE + assert service.service_type == ServiceTypeEnum.SERVICETYPE_L3NM + + response = context_client.ListConnections(service_id) + LOGGER.warning(' ServiceId[{:s}] => Connections[{:d}] = {:s}'.format( + grpc_message_to_json_string(service_id), len(response.connections), + grpc_message_to_json_string(response) + )) + assert len(response.connections) == 1 + + context_uuid = service_id.context_id.context_uuid.uuid + service_uuid = service_id.service_uuid.uuid + context_service_uuids.add((context_uuid, service_uuid)) + + # Identify service to delete + assert len(context_service_uuids) == 1 + context_uuid, service_uuid = set(context_service_uuids).pop() + + # Delete Service + service_client.DeleteService(ServiceId(**json_service_id(service_uuid, json_context_id(context_uuid)))) + + # Verify the scenario has no services/slices + response = context_client.GetContext(ADMIN_CONTEXT_ID) + assert len(response.service_ids) == 0 + assert len(response.slice_ids) == 0 -- GitLab From 1b2841ab0494b26ad3af5a54a148681c65b35f0c Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 10:32:19 +0000 Subject: [PATCH 02/20] Tests - ACL End-to-end integration test: - Updated README.md - Updated ContainerLab scenario - Updated TFS Topology descriptor - Updated CI/CD pipeline - Removed unneeded files --- src/tests/acl_end2end/.gitlab-ci.yml | 98 ++++--------------- src/tests/acl_end2end/README.md | 40 ++++---- .../acl_end2end/clab/acl_end2end.clab.yml | 24 ++--- .../{r1-startup.cfg => firewall-startup.cfg} | 8 +- src/tests/acl_end2end/clab/r2-startup.cfg | 48 --------- src/tests/acl_end2end/clab/r3-startup.cfg | 48 --------- .../acl_end2end/data/ietf-l3vpn-service.json | 54 +++++----- src/tests/acl_end2end/data/tfs-service.json | 26 ----- src/tests/acl_end2end/data/tfs-topology.json | 82 +++------------- .../{clab-cli-dc1.sh => clab-cli-client.sh} | 2 +- .../{clab-cli-r3.sh => clab-cli-dc.sh} | 2 +- .../{clab-cli-dc2.sh => clab-cli-firewall.sh} | 2 +- .../acl_end2end/deploy-scripts/clab-cli-r1.sh | 16 --- .../acl_end2end/deploy-scripts/clab-cli-r2.sh | 16 --- .../scripts/run-service-tfs-create.sh | 20 ---- .../scripts/run-service-tfs-remove.sh | 20 ---- .../tests/test_service_tfs_create.py | 76 -------------- .../tests/test_service_tfs_remove.py | 80 --------------- 18 files changed, 96 insertions(+), 566 deletions(-) rename src/tests/acl_end2end/clab/{r1-startup.cfg => firewall-startup.cfg} (82%) delete mode 100644 src/tests/acl_end2end/clab/r2-startup.cfg delete mode 100644 src/tests/acl_end2end/clab/r3-startup.cfg delete mode 100644 src/tests/acl_end2end/data/tfs-service.json rename src/tests/acl_end2end/deploy-scripts/{clab-cli-dc1.sh => clab-cli-client.sh} (93%) rename src/tests/acl_end2end/deploy-scripts/{clab-cli-r3.sh => clab-cli-dc.sh} (93%) rename src/tests/acl_end2end/deploy-scripts/{clab-cli-dc2.sh => clab-cli-firewall.sh} (93%) delete mode 100755 src/tests/acl_end2end/deploy-scripts/clab-cli-r1.sh delete mode 100755 src/tests/acl_end2end/deploy-scripts/clab-cli-r2.sh delete mode 100755 src/tests/acl_end2end/scripts/run-service-tfs-create.sh delete mode 100755 src/tests/acl_end2end/scripts/run-service-tfs-remove.sh delete mode 100644 src/tests/acl_end2end/tests/test_service_tfs_create.py delete mode 100644 src/tests/acl_end2end/tests/test_service_tfs_remove.py diff --git a/src/tests/acl_end2end/.gitlab-ci.yml b/src/tests/acl_end2end/.gitlab-ci.yml index 25dc770ba..08854a929 100644 --- a/src/tests/acl_end2end/.gitlab-ci.yml +++ b/src/tests/acl_end2end/.gitlab-ci.yml @@ -137,10 +137,8 @@ end2end_test acl_end2end: - sleep 3 - docker ps -a - # Dump configuration of the routers (before any configuration) - - containerlab exec --name acl_end2end --label clab-node-name=r1 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" - - containerlab exec --name acl_end2end --label clab-node-name=r2 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" - - containerlab exec --name acl_end2end --label clab-node-name=r3 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + # Dump configuration of the firewall (before any configuration) + - containerlab exec --name acl_end2end --label clab-node-name=firewall --cmd "Cli --command \"enable"$'\n'$"show running-config\"" # Configure TeraFlowSDN deployment # Uncomment if DEBUG log level is needed for the components @@ -190,50 +188,6 @@ end2end_test acl_end2end: --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-onboarding.sh - # Run end-to-end test: configure service TFS - - > - docker run -t --rm --name ${TEST_NAME} --network=host - --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh" - --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" - $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-service-tfs-create.sh - - # Dump configuration of the routers (after configure TFS service) - - containerlab exec --name acl_end2end --label clab-node-name=r1 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" - - containerlab exec --name acl_end2end --label clab-node-name=r2 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" - - containerlab exec --name acl_end2end --label clab-node-name=r3 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" - - # Run end-to-end test: test connectivity with ping - - export TEST1_10=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.1.10' --format json) - - echo $TEST1_10 - - echo $TEST1_10 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST1_1=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.1.1' --format json) - - echo $TEST1_1 - - echo $TEST1_1 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST2_1=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.2.1' --format json) - - echo $TEST2_1 - - echo $TEST2_1 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST2_10=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.2.10' --format json) - - echo $TEST2_10 - - echo $TEST2_10 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST3_1=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.3.1' --format json) - - echo $TEST3_1 - - echo $TEST3_1 | grep -E '3 packets transmitted, 0 received, 100\% packet loss' - - export TEST3_10=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.3.10' --format json) - - echo $TEST3_10 - - echo $TEST3_10 | grep -E '3 packets transmitted, 0 received, 100\% packet loss' - - # Run end-to-end test: deconfigure service TFS - - > - docker run -t --rm --name ${TEST_NAME} --network=host - --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh" - --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" - $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-service-tfs-remove.sh - - # Dump configuration of the routers (after deconfigure TFS service) - - containerlab exec --name acl_end2end --label clab-node-name=r1 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" - - containerlab exec --name acl_end2end --label clab-node-name=r2 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" - - containerlab exec --name acl_end2end --label clab-node-name=r3 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" - # Run end-to-end test: configure service IETF - > docker run -t --rm --name ${TEST_NAME} --network=host @@ -241,30 +195,22 @@ end2end_test acl_end2end: --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-service-ietf-create.sh - # Dump configuration of the routers (after configure IETF service) - - containerlab exec --name acl_end2end --label clab-node-name=r1 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" - - containerlab exec --name acl_end2end --label clab-node-name=r2 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" - - containerlab exec --name acl_end2end --label clab-node-name=r3 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + # Dump configuration of the firewall (after configure IETF service) + - containerlab exec --name acl_end2end --label clab-node-name=firewall --cmd "Cli --command \"enable"$'\n'$"show running-config\"" # Run end-to-end test: test connectivity with ping - - export TEST1_10=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.1.10' --format json) - - echo $TEST1_10 - - echo $TEST1_10 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST1_1=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.1.1' --format json) - - echo $TEST1_1 - - echo $TEST1_1 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST2_1=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.2.1' --format json) - - echo $TEST2_1 - - echo $TEST2_1 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST2_10=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.2.10' --format json) - - echo $TEST2_10 - - echo $TEST2_10 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST3_1=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.3.1' --format json) - - echo $TEST3_1 - - echo $TEST3_1 | grep -E '3 packets transmitted, 0 received, 100\% packet loss' - - export TEST3_10=$(containerlab exec --name acl_end2end --label clab-node-name=dc1 --cmd 'ping -n -c3 172.16.3.10' --format json) - - echo $TEST3_10 - - echo $TEST3_10 | grep -E '3 packets transmitted, 0 received, 100\% packet loss' + - export TEST_CLIENT_FIREWALL=$(containerlab exec --name acl_end2end --label clab-node-name=client --cmd 'ping -n -c3 172.16.1.1' --format json) + - echo $TEST_CLIENT_FIREWALL + - echo $TEST_CLIENT_FIREWALL | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST_CLIENT_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client --cmd 'ping -n -c3 172.16.2.10' --format json) + - echo $TEST_CLIENT_DC + - echo $TEST_CLIENT_DC | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST_DC_FIREWALL=$(containerlab exec --name acl_end2end --label clab-node-name=dc --cmd 'ping -n -c3 172.16.2.1' --format json) + - echo $TEST_DC_FIREWALL + - echo $TEST_DC_FIREWALL | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST_DC_CLIENT=$(containerlab exec --name acl_end2end --label clab-node-name=dc --cmd 'ping -n -c3 172.16.1.10' --format json) + - echo $TEST_DC_CLIENT + - echo $TEST_DC_CLIENT | grep -E '3 packets transmitted, 3 received, 0\% packet loss' # Run end-to-end test: deconfigure service IETF - > @@ -273,10 +219,8 @@ end2end_test acl_end2end: --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-service-ietf-remove.sh - # Dump configuration of the routers (after deconfigure IETF service) - - containerlab exec --name acl_end2end --label clab-node-name=r1 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" - - containerlab exec --name acl_end2end --label clab-node-name=r2 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" - - containerlab exec --name acl_end2end --label clab-node-name=r3 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + # Dump configuration of the firewall (after deconfigure IETF service) + - containerlab exec --name acl_end2end --label clab-node-name=firewall --cmd "Cli --command \"enable"$'\n'$"show running-config\"" # Run end-to-end test: cleanup scenario - > @@ -286,10 +230,8 @@ end2end_test acl_end2end: $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-cleanup.sh after_script: - # Dump configuration of the routers (on after_script) - - containerlab exec --name acl_end2end --label clab-node-name=r1 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" - - containerlab exec --name acl_end2end --label clab-node-name=r2 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" - - containerlab exec --name acl_end2end --label clab-node-name=r3 --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + # Dump configuration of the firewall (on after_script) + - containerlab exec --name acl_end2end --label clab-node-name=firewall --cmd "Cli --command \"enable"$'\n'$"show running-config\"" # Dump TeraFlowSDN component logs - source src/tests/${TEST_NAME}/deploy_specs.sh diff --git a/src/tests/acl_end2end/README.md b/src/tests/acl_end2end/README.md index 51bb9d3c6..195ea4d70 100644 --- a/src/tests/acl_end2end/README.md +++ b/src/tests/acl_end2end/README.md @@ -1,4 +1,4 @@ -# DataPlane-in-a-Box - Control an Emulated DataPlane through TeraFlowSDN +# Control an Arista Firewall through TeraFlowSDN ## Emulated DataPlane Deployment - ContainerLab @@ -46,22 +46,20 @@ sudo rm -rf clab-acl_end2end/ .acl_end2end.clab.yml.bak ## Access cEOS Bash/CLI ```bash -docker exec -it clab-acl_end2end-r1 bash -docker exec -it clab-acl_end2end-r2 bash -docker exec -it clab-acl_end2end-r3 bash -docker exec -it clab-acl_end2end-r1 Cli -docker exec -it clab-acl_end2end-r2 Cli -docker exec -it clab-acl_end2end-r3 Cli +docker exec -it clab-acl_end2end-firewall bash +docker exec -it clab-acl_end2end-client bash +docker exec -it clab-acl_end2end-dc bash +docker exec -it clab-acl_end2end-firewall Cli ``` ## Configure ContainerLab clients ```bash -docker exec -it clab-acl_end2end-dc1 bash +docker exec -it clab-acl_end2end-client bash ip address add 172.16.1.10/24 dev eth1 ip route add 172.16.2.0/24 via 172.16.1.1 ping 172.16.2.10 -docker exec -it clab-acl_end2end-dc2 bash +docker exec -it clab-acl_end2end-dc bash ip address add 172.16.2.10/24 dev eth1 ip route add 172.16.1.0/24 via 172.16.2.1 ping 172.16.1.10 @@ -74,38 +72,38 @@ sudo bash -c "$(curl -sL https://get-gnmic.kmrd.dev)" ## gNMI Capabilities request ```bash -gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure capabilities +gnmic --address clab-acl_end2end-firewall --port 6030 --username admin --password admin --insecure capabilities ``` ## gNMI Get request ```bash -gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path / > r1.json -gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path /interfaces/interface > r1-ifaces.json +gnmic --address clab-acl_end2end-firewall --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path / > firewall.json +gnmic --address clab-acl_end2end-firewall --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path /interfaces/interface > firewall-ifaces.json ``` ## gNMI Set request ```bash -gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf set --update-path /system/config/hostname --update-value srl11 -gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path /system/config/hostname +gnmic --address clab-acl_end2end-firewall --port 6030 --username admin --password admin --insecure --encoding json_ietf set --update-path /system/config/hostname --update-value srl11 +gnmic --address clab-acl_end2end-firewall --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path /system/config/hostname ``` ## Subscribe request ```bash -gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf subscribe --path /interfaces/interface[name=Management0]/state/ +gnmic --address clab-acl_end2end-firewall --port 6030 --username admin --password admin --insecure --encoding json_ietf subscribe --path /interfaces/interface[name=Management0]/state/ # In another terminal, you can generate traffic opening SSH connection -ssh admin@clab-acl_end2end-r1 +ssh admin@clab-acl_end2end-firewall ``` # Check configurations done: ```bash -gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path '/network-instances' > r1-nis.json -gnmic --address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path '/interfaces' > r1-ifs.json +gnmic --address clab-acl_end2end-firewall --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path '/network-instances' > firewall-nis.json +gnmic --address clab-acl_end2end-firewall --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path '/interfaces' > firewall-ifs.json ``` # Delete elements: ```bash ---address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf set --delete '/network-instances/network-instance[name=b19229e8]' ---address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf set --delete '/interfaces/interface[name=ethernet-1/1]/subinterfaces/subinterface[index=0]' ---address clab-acl_end2end-r1 --port 6030 --username admin --password admin --insecure --encoding json_ietf set --delete '/interfaces/interface[name=ethernet-1/2]/subinterfaces/subinterface[index=0]' +--address clab-acl_end2end-firewall --port 6030 --username admin --password admin --insecure --encoding json_ietf set --delete '/network-instances/network-instance[name=b19229e8]' +--address clab-acl_end2end-firewall --port 6030 --username admin --password admin --insecure --encoding json_ietf set --delete '/interfaces/interface[name=ethernet-1/1]/subinterfaces/subinterface[index=0]' +--address clab-acl_end2end-firewall --port 6030 --username admin --password admin --insecure --encoding json_ietf set --delete '/interfaces/interface[name=ethernet-1/2]/subinterfaces/subinterface[index=0]' ``` diff --git a/src/tests/acl_end2end/clab/acl_end2end.clab.yml b/src/tests/acl_end2end/clab/acl_end2end.clab.yml index 6a31872dc..8b7329847 100644 --- a/src/tests/acl_end2end/clab/acl_end2end.clab.yml +++ b/src/tests/acl_end2end/clab/acl_end2end.clab.yml @@ -36,22 +36,12 @@ topology: image: ghcr.io/hellt/network-multitool:latest nodes: - r1: + firewall: kind: arista_ceos mgmt-ipv4: 172.20.20.101 - startup-config: r1-startup.cfg + startup-config: firewall-startup.cfg - r2: - kind: arista_ceos - mgmt-ipv4: 172.20.20.102 - startup-config: r2-startup.cfg - - r3: - kind: arista_ceos - mgmt-ipv4: 172.20.20.103 - startup-config: r3-startup.cfg - - dc1: + client: kind: linux mgmt-ipv4: 172.20.20.201 exec: @@ -59,7 +49,7 @@ topology: - ip address add 172.16.1.10/24 dev eth1 - ip route add 172.16.2.0/24 via 172.16.1.1 - dc2: + dc: kind: linux mgmt-ipv4: 172.20.20.202 exec: @@ -68,7 +58,5 @@ topology: - ip route add 172.16.1.0/24 via 172.16.2.1 links: - - endpoints: ["r1:eth2", "r2:eth1"] - - endpoints: ["r2:eth3", "r3:eth2"] - - endpoints: ["r1:eth10", "dc1:eth1"] - - endpoints: ["r3:eth10", "dc2:eth1"] + - endpoints: ["firewall:eth10", "client:eth1"] + - endpoints: ["firewall:eth2", "dc:eth1"] diff --git a/src/tests/acl_end2end/clab/r1-startup.cfg b/src/tests/acl_end2end/clab/firewall-startup.cfg similarity index 82% rename from src/tests/acl_end2end/clab/r1-startup.cfg rename to src/tests/acl_end2end/clab/firewall-startup.cfg index b7feebe06..d3b91baed 100644 --- a/src/tests/acl_end2end/clab/r1-startup.cfg +++ b/src/tests/acl_end2end/clab/firewall-startup.cfg @@ -1,4 +1,4 @@ -! device: r1 (cEOSLab, EOS-4.32.2F-38195967.4322F (engineering build)) +! device: firewall (cEOSLab, EOS-4.32.2F-38195967.4322F (engineering build)) ! no aaa root ! @@ -13,7 +13,7 @@ transceiver qsfp default-mode 4x10G ! service routing protocols model multi-agent ! -hostname r1 +hostname firewall ! spanning-tree mode mstp ! @@ -28,8 +28,12 @@ management api netconf transport ssh default ! interface Ethernet2 + ip address 172.16.2.1/24 + no shutdown ! interface Ethernet10 + ip address 172.16.1.1/24 + no shutdown ! interface Management0 ip address 172.20.20.101/24 diff --git a/src/tests/acl_end2end/clab/r2-startup.cfg b/src/tests/acl_end2end/clab/r2-startup.cfg deleted file mode 100644 index e1ab661a0..000000000 --- a/src/tests/acl_end2end/clab/r2-startup.cfg +++ /dev/null @@ -1,48 +0,0 @@ -! device: r2 (cEOSLab, EOS-4.32.2F-38195967.4322F (engineering build)) -! -no aaa root -! -username admin privilege 15 role network-admin secret sha512 $6$OmfaAwJRg/r44r5U$9Fca1O1G6Bgsd4NKwSyvdRJcHHk71jHAR3apDWAgSTN/t/j1iroEhz5J36HjWjOF/jEVC/R8Wa60VmbX6.cr70 -! -management api http-commands - no shutdown -! -no service interface inactive port-id allocation disabled -! -transceiver qsfp default-mode 4x10G -! -service routing protocols model multi-agent -! -hostname r2 -! -spanning-tree mode mstp -! -system l1 - unsupported speed action error - unsupported error-correction action error -! -management api gnmi - transport grpc default -! -management api netconf - transport ssh default -! -interface Ethernet1 -! -interface Ethernet3 -! -interface Management0 - ip address 172.20.20.102/24 -! -ip routing -! -ip route 0.0.0.0/0 172.20.20.1 -! -router multicast - ipv4 - software-forwarding kernel - ! - ipv6 - software-forwarding kernel -! -end diff --git a/src/tests/acl_end2end/clab/r3-startup.cfg b/src/tests/acl_end2end/clab/r3-startup.cfg deleted file mode 100644 index 63c062593..000000000 --- a/src/tests/acl_end2end/clab/r3-startup.cfg +++ /dev/null @@ -1,48 +0,0 @@ -! device: r3 (cEOSLab, EOS-4.32.2F-38195967.4322F (engineering build)) -! -no aaa root -! -username admin privilege 15 role network-admin secret sha512 $6$OmfaAwJRg/r44r5U$9Fca1O1G6Bgsd4NKwSyvdRJcHHk71jHAR3apDWAgSTN/t/j1iroEhz5J36HjWjOF/jEVC/R8Wa60VmbX6.cr70 -! -management api http-commands - no shutdown -! -no service interface inactive port-id allocation disabled -! -transceiver qsfp default-mode 4x10G -! -service routing protocols model multi-agent -! -hostname r3 -! -spanning-tree mode mstp -! -system l1 - unsupported speed action error - unsupported error-correction action error -! -management api gnmi - transport grpc default -! -management api netconf - transport ssh default -! -interface Ethernet2 -! -interface Ethernet10 -! -interface Management0 - ip address 172.20.20.103/24 -! -ip routing -! -ip route 0.0.0.0/0 172.20.20.1 -! -router multicast - ipv4 - software-forwarding kernel - ! - ipv6 - software-forwarding kernel -! -end diff --git a/src/tests/acl_end2end/data/ietf-l3vpn-service.json b/src/tests/acl_end2end/data/ietf-l3vpn-service.json index a0f28ee06..0f471168c 100644 --- a/src/tests/acl_end2end/data/ietf-l3vpn-service.json +++ b/src/tests/acl_end2end/data/ietf-l3vpn-service.json @@ -3,22 +3,22 @@ "vpn-services": {"vpn-service": [{"vpn-id": "ietf-l3vpn-svc"}]}, "sites": { "site": [ - { - "site-id": "site_DC1", - "management": {"type": "ietf-l3vpn-svc:provider-managed"}, - "locations": {"location": [{"location-id": "DC1"}]}, - "devices": {"device": [{"device-id": "dc1", "location": "DC1"}]}, - "site-network-accesses": { - "site-network-access": [ - { - "site-network-access-id": "eth1", - "site-network-access-type": "ietf-l3vpn-svc:multipoint", - "device-reference": "dc1", - "vpn-attachment": {"vpn-id": "ietf-l3vpn-svc", "site-role": "ietf-l3vpn-svc:spoke-role"}, - "ip-connection": { - "ipv4": { - "address-allocation-type": "ietf-l3vpn-svc:static-address", - "addresses": { + { + "site-id": "site_client", + "management": {"type": "ietf-l3vpn-svc:provider-managed"}, + "locations": {"location": [{"location-id": "CLIENT"}]}, + "devices": {"device": [{"device-id": "client", "location": "CLIENT"}]}, + "site-network-accesses": { + "site-network-access": [ + { + "site-network-access-id": "eth1", + "site-network-access-type": "ietf-l3vpn-svc:multipoint", + "device-reference": "client", + "vpn-attachment": {"vpn-id": "ietf-l3vpn-svc", "site-role": "ietf-l3vpn-svc:spoke-role"}, + "ip-connection": { + "ipv4": { + "address-allocation-type": "ietf-l3vpn-svc:static-address", + "addresses": { "provider-address": "172.16.1.1", "customer-address": "172.16.1.10", "prefix-length": 24 @@ -40,17 +40,17 @@ ] } }, - { - "site-id": "site_DC2", - "management": {"type": "ietf-l3vpn-svc:provider-managed"}, - "locations": {"location": [{"location-id": "DC2"}]}, - "devices": {"device": [{"device-id": "dc2", "location": "DC2"}]}, - "site-network-accesses": { - "site-network-access": [ - { - "site-network-access-id": "eth1", - "site-network-access-type": "ietf-l3vpn-svc:multipoint", - "device-reference": "dc2", + { + "site-id": "site_dc", + "management": {"type": "ietf-l3vpn-svc:provider-managed"}, + "locations": {"location": [{"location-id": "DC"}]}, + "devices": {"device": [{"device-id": "dc", "location": "DC"}]}, + "site-network-accesses": { + "site-network-access": [ + { + "site-network-access-id": "eth1", + "site-network-access-type": "ietf-l3vpn-svc:multipoint", + "device-reference": "dc", "vpn-attachment": {"vpn-id": "ietf-l3vpn-svc", "site-role": "ietf-l3vpn-svc:hub-role"}, "ip-connection": { "ipv4": { diff --git a/src/tests/acl_end2end/data/tfs-service.json b/src/tests/acl_end2end/data/tfs-service.json deleted file mode 100644 index e4bb7c2d2..000000000 --- a/src/tests/acl_end2end/data/tfs-service.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "services": [ - { - "service_id": { - "context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "tfs-l3vpn-svc"} - }, - "service_type": "SERVICETYPE_L3NM", - "service_status": {"service_status": "SERVICESTATUS_PLANNED"}, - "service_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "dc1"}}, "endpoint_uuid": {"uuid": "int"}}, - {"device_id": {"device_uuid": {"uuid": "dc2"}}, "endpoint_uuid": {"uuid": "int"}} - ], - "service_constraints": [], - "service_config": {"config_rules": [ - {"action": "CONFIGACTION_SET", "custom": { - "resource_key": "/device[dc1]/endpoint[eth1]/settings", - "resource_value": {"address_ip": "172.16.1.10", "address_prefix": 24, "index": 0} - }}, - {"action": "CONFIGACTION_SET", "custom": { - "resource_key": "/device[dc2]/endpoint[eth1]/settings", - "resource_value": {"address_ip": "172.16.2.10", "address_prefix": 24, "index": 0} - }} - ]} - } - ] -} diff --git a/src/tests/acl_end2end/data/tfs-topology.json b/src/tests/acl_end2end/data/tfs-topology.json index ac87af62d..da142fddb 100644 --- a/src/tests/acl_end2end/data/tfs-topology.json +++ b/src/tests/acl_end2end/data/tfs-topology.json @@ -7,7 +7,7 @@ ], "devices": [ { - "device_id": {"device_uuid": {"uuid": "dc1"}}, "device_type": "emu-datacenter", + "device_id": {"device_uuid": {"uuid": "client"}}, "device_type": "emu-client", "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_config": {"config_rules": [ {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, @@ -18,7 +18,7 @@ ]} }, { - "device_id": {"device_uuid": {"uuid": "dc2"}}, "device_type": "emu-datacenter", + "device_id": {"device_uuid": {"uuid": "dc"}}, "device_type": "emu-datacenter", "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_config": {"config_rules": [ {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, @@ -29,7 +29,7 @@ ]} }, { - "device_id": {"device_uuid": {"uuid": "r1"}}, "device_type": "packet-router", + "device_id": {"device_uuid": {"uuid": "firewall"}}, "device_type": "packet-router", "device_drivers": ["DEVICEDRIVER_GNMI_OPENCONFIG"], "device_config": {"config_rules": [ {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "172.20.20.101"}}, @@ -38,88 +38,36 @@ "username": "admin", "password": "admin", "use_tls": false }}} ]} - }, - { - "device_id": {"device_uuid": {"uuid": "r2"}}, "device_type": "packet-router", - "device_drivers": ["DEVICEDRIVER_GNMI_OPENCONFIG"], - "device_config": {"config_rules": [ - {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "172.20.20.102"}}, - {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "6030"}}, - {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": { - "username": "admin", "password": "admin", "use_tls": false - }}} - ]} - }, - { - "device_id": {"device_uuid": {"uuid": "r3"}}, "device_type": "packet-router", - "device_drivers": ["DEVICEDRIVER_GNMI_OPENCONFIG"], - "device_config": {"config_rules": [ - {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "172.20.20.103"}}, - {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "6030"}}, - {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": { - "username": "admin", "password": "admin", "use_tls": false - }}} - ]} } ], "links": [ { - "link_id": {"link_uuid": {"uuid": "r1/Ethernet2==r2/Ethernet1"}}, - "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "r1"}}, "endpoint_uuid": {"uuid": "Ethernet2"}}, - {"device_id": {"device_uuid": {"uuid": "r2"}}, "endpoint_uuid": {"uuid": "Ethernet1"}} - ] - }, - { - "link_id": {"link_uuid": {"uuid": "r2/Ethernet1==r1/Ethernet2"}}, - "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "r2"}}, "endpoint_uuid": {"uuid": "Ethernet1"}}, - {"device_id": {"device_uuid": {"uuid": "r1"}}, "endpoint_uuid": {"uuid": "Ethernet2"}} - ] - }, - - { - "link_id": {"link_uuid": {"uuid": "r2/Ethernet3==r3/Ethernet2"}}, - "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "r2"}}, "endpoint_uuid": {"uuid": "Ethernet3"}}, - {"device_id": {"device_uuid": {"uuid": "r3"}}, "endpoint_uuid": {"uuid": "Ethernet2"}} - ] - }, - { - "link_id": {"link_uuid": {"uuid": "r3/Ethernet2==r2/Ethernet3"}}, - "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "r3"}}, "endpoint_uuid": {"uuid": "Ethernet2"}}, - {"device_id": {"device_uuid": {"uuid": "r2"}}, "endpoint_uuid": {"uuid": "Ethernet3"}} - ] - }, - - { - "link_id": {"link_uuid": {"uuid": "r1/Ethernet10==dc1/eth1"}}, + "link_id": {"link_uuid": {"uuid": "firewall/Ethernet10==client/eth1"}}, "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "r1"}}, "endpoint_uuid": {"uuid": "Ethernet10"}}, - {"device_id": {"device_uuid": {"uuid": "dc1"}}, "endpoint_uuid": {"uuid": "eth1"}} + {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet10"}}, + {"device_id": {"device_uuid": {"uuid": "client"}}, "endpoint_uuid": {"uuid": "eth1"}} ] }, { - "link_id": {"link_uuid": {"uuid": "dc1/eth1==r1/Ethernet10"}}, + "link_id": {"link_uuid": {"uuid": "client/eth1==firewall/Ethernet10"}}, "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "dc1"}}, "endpoint_uuid": {"uuid": "eth1"}}, - {"device_id": {"device_uuid": {"uuid": "r1"}}, "endpoint_uuid": {"uuid": "Ethernet10"}} + {"device_id": {"device_uuid": {"uuid": "client"}}, "endpoint_uuid": {"uuid": "eth1"}}, + {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet10"}} ] }, { - "link_id": {"link_uuid": {"uuid": "r3/Ethernet10==dc2/eth1"}}, + "link_id": {"link_uuid": {"uuid": "firewall/Ethernet2==dc/eth1"}}, "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "r3"}}, "endpoint_uuid": {"uuid": "Ethernet10"}}, - {"device_id": {"device_uuid": {"uuid": "dc2"}}, "endpoint_uuid": {"uuid": "eth1"}} + {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet2"}}, + {"device_id": {"device_uuid": {"uuid": "dc"}}, "endpoint_uuid": {"uuid": "eth1"}} ] }, { - "link_id": {"link_uuid": {"uuid": "dc2/eth1==r3/Ethernet10"}}, + "link_id": {"link_uuid": {"uuid": "dc/eth1==firewall/Ethernet2"}}, "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "dc2"}}, "endpoint_uuid": {"uuid": "eth1"}}, - {"device_id": {"device_uuid": {"uuid": "r3"}}, "endpoint_uuid": {"uuid": "Ethernet10"}} + {"device_id": {"device_uuid": {"uuid": "dc"}}, "endpoint_uuid": {"uuid": "eth1"}}, + {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet2"}} ] } ] diff --git a/src/tests/acl_end2end/deploy-scripts/clab-cli-dc1.sh b/src/tests/acl_end2end/deploy-scripts/clab-cli-client.sh similarity index 93% rename from src/tests/acl_end2end/deploy-scripts/clab-cli-dc1.sh rename to src/tests/acl_end2end/deploy-scripts/clab-cli-client.sh index 2da0f61cb..1e2890641 100755 --- a/src/tests/acl_end2end/deploy-scripts/clab-cli-dc1.sh +++ b/src/tests/acl_end2end/deploy-scripts/clab-cli-client.sh @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -docker exec -it clab-acl_end2end-dc1 bash +docker exec -it clab-acl_end2end-client bash diff --git a/src/tests/acl_end2end/deploy-scripts/clab-cli-r3.sh b/src/tests/acl_end2end/deploy-scripts/clab-cli-dc.sh similarity index 93% rename from src/tests/acl_end2end/deploy-scripts/clab-cli-r3.sh rename to src/tests/acl_end2end/deploy-scripts/clab-cli-dc.sh index 47b12cc90..bde012b37 100755 --- a/src/tests/acl_end2end/deploy-scripts/clab-cli-r3.sh +++ b/src/tests/acl_end2end/deploy-scripts/clab-cli-dc.sh @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -docker exec -it clab-acl_end2end-r3 Cli +docker exec -it clab-acl_end2end-dc bash diff --git a/src/tests/acl_end2end/deploy-scripts/clab-cli-dc2.sh b/src/tests/acl_end2end/deploy-scripts/clab-cli-firewall.sh similarity index 93% rename from src/tests/acl_end2end/deploy-scripts/clab-cli-dc2.sh rename to src/tests/acl_end2end/deploy-scripts/clab-cli-firewall.sh index 873c1cbc8..ad5ab0ce7 100755 --- a/src/tests/acl_end2end/deploy-scripts/clab-cli-dc2.sh +++ b/src/tests/acl_end2end/deploy-scripts/clab-cli-firewall.sh @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -docker exec -it clab-acl_end2end-dc2 bash +docker exec -it clab-acl_end2end-firewall Cli diff --git a/src/tests/acl_end2end/deploy-scripts/clab-cli-r1.sh b/src/tests/acl_end2end/deploy-scripts/clab-cli-r1.sh deleted file mode 100755 index bb68a32e1..000000000 --- a/src/tests/acl_end2end/deploy-scripts/clab-cli-r1.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -docker exec -it clab-acl_end2end-r1 Cli diff --git a/src/tests/acl_end2end/deploy-scripts/clab-cli-r2.sh b/src/tests/acl_end2end/deploy-scripts/clab-cli-r2.sh deleted file mode 100755 index 1aebae12d..000000000 --- a/src/tests/acl_end2end/deploy-scripts/clab-cli-r2.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -docker exec -it clab-acl_end2end-r2 Cli diff --git a/src/tests/acl_end2end/scripts/run-service-tfs-create.sh b/src/tests/acl_end2end/scripts/run-service-tfs-create.sh deleted file mode 100755 index 9a902e422..000000000 --- a/src/tests/acl_end2end/scripts/run-service-tfs-create.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -source /var/teraflow/tfs_runtime_env_vars.sh -export PYTHONPATH=/var/teraflow -pytest --verbose --log-level=INFO \ - --junitxml=/opt/results/report_service_tfs_create.xml \ - /var/teraflow/tests/acl_end2end/tests/test_service_tfs_create.py diff --git a/src/tests/acl_end2end/scripts/run-service-tfs-remove.sh b/src/tests/acl_end2end/scripts/run-service-tfs-remove.sh deleted file mode 100755 index d284097c7..000000000 --- a/src/tests/acl_end2end/scripts/run-service-tfs-remove.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -source /var/teraflow/tfs_runtime_env_vars.sh -export PYTHONPATH=/var/teraflow -pytest --verbose --log-level=INFO \ - --junitxml=/opt/results/report_service_tfs_remove.xml \ - /var/teraflow/tests/acl_end2end/tests/test_service_tfs_remove.py diff --git a/src/tests/acl_end2end/tests/test_service_tfs_create.py b/src/tests/acl_end2end/tests/test_service_tfs_create.py deleted file mode 100644 index 301602792..000000000 --- a/src/tests/acl_end2end/tests/test_service_tfs_create.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging, os -from common.Constants import DEFAULT_CONTEXT_NAME -from common.proto.context_pb2 import ContextId, ServiceStatusEnum, ServiceTypeEnum -from common.tools.descriptor.Loader import DescriptorLoader, check_descriptor_load_results -from common.tools.grpc.Tools import grpc_message_to_json_string -from common.tools.object_factory.Context import json_context_id -from context.client.ContextClient import ContextClient -from device.client.DeviceClient import DeviceClient -from service.client.ServiceClient import ServiceClient -from .Fixtures import context_client, device_client, service_client # pylint: disable=unused-import - - -LOGGER = logging.getLogger(__name__) -LOGGER.setLevel(logging.DEBUG) - -DESCRIPTOR_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'tfs-service.json') -ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) - - -def test_service_tfs_creation( - context_client : ContextClient, # pylint: disable=redefined-outer-name - device_client : DeviceClient, # pylint: disable=redefined-outer-name - service_client : ServiceClient, # pylint: disable=redefined-outer-name -): - # Load descriptors and validate the base scenario - descriptor_loader = DescriptorLoader( - descriptors_file=DESCRIPTOR_FILE, context_client=context_client, - device_client=device_client, service_client=service_client - ) - results = descriptor_loader.process() - check_descriptor_load_results(results, descriptor_loader) - - # Verify the scenario has 1 service and 0 slices - response = context_client.GetContext(ADMIN_CONTEXT_ID) - assert len(response.service_ids) == 1 - assert len(response.slice_ids) == 0 - - # Check there are no slices - response = context_client.ListSlices(ADMIN_CONTEXT_ID) - LOGGER.warning('Slices[{:d}] = {:s}'.format( - len(response.slices), grpc_message_to_json_string(response) - )) - assert len(response.slices) == 0 - - # Check there is 1 service - response = context_client.ListServices(ADMIN_CONTEXT_ID) - LOGGER.warning('Services[{:d}] = {:s}'.format( - len(response.services), grpc_message_to_json_string(response) - )) - assert len(response.services) == 1 - - for service in response.services: - service_id = service.service_id - assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE - assert service.service_type == ServiceTypeEnum.SERVICETYPE_L3NM - - response = context_client.ListConnections(service_id) - LOGGER.warning(' ServiceId[{:s}] => Connections[{:d}] = {:s}'.format( - grpc_message_to_json_string(service_id), len(response.connections), - grpc_message_to_json_string(response) - )) - assert len(response.connections) == 1 diff --git a/src/tests/acl_end2end/tests/test_service_tfs_remove.py b/src/tests/acl_end2end/tests/test_service_tfs_remove.py deleted file mode 100644 index 50d4acb7a..000000000 --- a/src/tests/acl_end2end/tests/test_service_tfs_remove.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging, os -from typing import Set, Tuple -from common.Constants import DEFAULT_CONTEXT_NAME -from common.proto.context_pb2 import ContextId, ServiceId, ServiceStatusEnum, ServiceTypeEnum -from common.tools.grpc.Tools import grpc_message_to_json_string -from common.tools.object_factory.Context import json_context_id -from common.tools.object_factory.Service import json_service_id -from context.client.ContextClient import ContextClient -from service.client.ServiceClient import ServiceClient -from .Fixtures import context_client, service_client # pylint: disable=unused-import - - -LOGGER = logging.getLogger(__name__) -LOGGER.setLevel(logging.DEBUG) - -DESCRIPTOR_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'tfs-service.json') -ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) - - -def test_service_tfs_removal( - context_client : ContextClient, # pylint: disable=redefined-outer-name - service_client : ServiceClient, # pylint: disable=redefined-outer-name -): - # Verify the scenario has 1 service and 0 slices - response = context_client.GetContext(ADMIN_CONTEXT_ID) - assert len(response.service_ids) == 1 - assert len(response.slice_ids) == 0 - - # Check there are no slices - response = context_client.ListSlices(ADMIN_CONTEXT_ID) - LOGGER.warning('Slices[{:d}] = {:s}'.format(len(response.slices), grpc_message_to_json_string(response))) - assert len(response.slices) == 0 - - # Check there is 1 service - response = context_client.ListServices(ADMIN_CONTEXT_ID) - LOGGER.warning('Services[{:d}] = {:s}'.format(len(response.services), grpc_message_to_json_string(response))) - assert len(response.services) == 1 - - context_service_uuids : Set[Tuple[str, str]] = set() - for service in response.services: - service_id = service.service_id - assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE - assert service.service_type == ServiceTypeEnum.SERVICETYPE_L3NM - - response = context_client.ListConnections(service_id) - LOGGER.warning(' ServiceId[{:s}] => Connections[{:d}] = {:s}'.format( - grpc_message_to_json_string(service_id), len(response.connections), - grpc_message_to_json_string(response) - )) - assert len(response.connections) == 1 - - context_uuid = service_id.context_id.context_uuid.uuid - service_uuid = service_id.service_uuid.uuid - context_service_uuids.add((context_uuid, service_uuid)) - - # Identify service to delete - assert len(context_service_uuids) == 1 - context_uuid, service_uuid = set(context_service_uuids).pop() - - # Delete Service - service_client.DeleteService(ServiceId(**json_service_id(service_uuid, json_context_id(context_uuid)))) - - # Verify the scenario has no services/slices - response = context_client.GetContext(ADMIN_CONTEXT_ID) - assert len(response.service_ids) == 0 - assert len(response.slice_ids) == 0 -- GitLab From d393cba5d93834e9161b5855a81704abe0b2457f Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 11:36:09 +0000 Subject: [PATCH 03/20] Tests - ACL End-to-end integration test: - Fixed name of clients in deploy scripts --- .../{clab-cli-client.sh => clab-cli-client1.sh} | 2 +- .../deploy-scripts/clab-cli-client2.sh | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) rename src/tests/acl_end2end/deploy-scripts/{clab-cli-client.sh => clab-cli-client1.sh} (93%) create mode 100644 src/tests/acl_end2end/deploy-scripts/clab-cli-client2.sh diff --git a/src/tests/acl_end2end/deploy-scripts/clab-cli-client.sh b/src/tests/acl_end2end/deploy-scripts/clab-cli-client1.sh similarity index 93% rename from src/tests/acl_end2end/deploy-scripts/clab-cli-client.sh rename to src/tests/acl_end2end/deploy-scripts/clab-cli-client1.sh index 1e2890641..4c0a5740d 100755 --- a/src/tests/acl_end2end/deploy-scripts/clab-cli-client.sh +++ b/src/tests/acl_end2end/deploy-scripts/clab-cli-client1.sh @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -docker exec -it clab-acl_end2end-client bash +docker exec -it clab-acl_end2end-client1 bash diff --git a/src/tests/acl_end2end/deploy-scripts/clab-cli-client2.sh b/src/tests/acl_end2end/deploy-scripts/clab-cli-client2.sh new file mode 100644 index 000000000..54ca743a4 --- /dev/null +++ b/src/tests/acl_end2end/deploy-scripts/clab-cli-client2.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +docker exec -it clab-acl_end2end-client2 bash -- GitLab From 8ab42c8eb51b3543c3251786919689a112164cc3 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 11:49:29 +0000 Subject: [PATCH 04/20] Tests - ACL End-to-end integration test: - Updated ContainerLab scenario - Removed unneeded IETF service files - Added IETF ACL data file - Updated topology file - Updated run ACL script - Updated CI/CD pipeline descriptor --- src/tests/acl_end2end/.gitlab-ci.yml | 33 +++----- src/tests/acl_end2end/README.md | 20 ++++- .../acl_end2end/clab/acl_end2end.clab.yml | 32 ++++--- .../acl_end2end/clab/firewall-startup.cfg | 12 ++- src/tests/acl_end2end/data/ietf-acl.json | 40 +++++++++ .../acl_end2end/data/ietf-l3vpn-service.json | 83 ------------------- src/tests/acl_end2end/data/tfs-topology.json | 36 ++++++-- ...ervice-ietf-create.sh => run-acl-tests.sh} | 4 +- .../scripts/run-service-ietf-remove.sh | 20 ----- src/tests/acl_end2end/tests/test_acl.py | 57 +++++++++++++ .../tests/test_service_ietf_create.py | 71 ---------------- .../tests/test_service_ietf_remove.py | 77 ----------------- 12 files changed, 189 insertions(+), 296 deletions(-) create mode 100644 src/tests/acl_end2end/data/ietf-acl.json delete mode 100644 src/tests/acl_end2end/data/ietf-l3vpn-service.json rename src/tests/acl_end2end/scripts/{run-service-ietf-create.sh => run-acl-tests.sh} (85%) mode change 100755 => 100644 delete mode 100755 src/tests/acl_end2end/scripts/run-service-ietf-remove.sh create mode 100644 src/tests/acl_end2end/tests/test_acl.py delete mode 100644 src/tests/acl_end2end/tests/test_service_ietf_create.py delete mode 100644 src/tests/acl_end2end/tests/test_service_ietf_remove.py diff --git a/src/tests/acl_end2end/.gitlab-ci.yml b/src/tests/acl_end2end/.gitlab-ci.yml index 08854a929..36da8fea0 100644 --- a/src/tests/acl_end2end/.gitlab-ci.yml +++ b/src/tests/acl_end2end/.gitlab-ci.yml @@ -188,39 +188,32 @@ end2end_test acl_end2end: --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-onboarding.sh - # Run end-to-end test: configure service IETF + # Run end-to-end test: configure ACLs - > docker run -t --rm --name ${TEST_NAME} --network=host --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh" --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" - $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-service-ietf-create.sh - - # Dump configuration of the firewall (after configure IETF service) - - containerlab exec --name acl_end2end --label clab-node-name=firewall --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-acl-tests.sh # Run end-to-end test: test connectivity with ping - - export TEST_CLIENT_FIREWALL=$(containerlab exec --name acl_end2end --label clab-node-name=client --cmd 'ping -n -c3 172.16.1.1' --format json) + - export TEST_CLIENT_FIREWALL=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.1.1' --format json) - echo $TEST_CLIENT_FIREWALL - echo $TEST_CLIENT_FIREWALL | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST_CLIENT_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client --cmd 'ping -n -c3 172.16.2.10' --format json) + - export TEST_CLIENT_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.0.10' --format json) - echo $TEST_CLIENT_DC - echo $TEST_CLIENT_DC | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST_DC_FIREWALL=$(containerlab exec --name acl_end2end --label clab-node-name=dc --cmd 'ping -n -c3 172.16.2.1' --format json) - - echo $TEST_DC_FIREWALL - - echo $TEST_DC_FIREWALL | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST_CLIENT2_FIREWALL=$(containerlab exec --name acl_end2end --label clab-node-name=client2 --cmd 'ping -n -c3 172.16.2.1' --format json) + - echo $TEST_CLIENT2_FIREWALL + - echo $TEST_CLIENT2_FIREWALL | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST_CLIENT2_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client2 --cmd 'ping -n -c3 172.16.0.10' --format json) + - echo $TEST_CLIENT2_DC + - echo $TEST_CLIENT2_DC | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - export TEST_DC_CLIENT=$(containerlab exec --name acl_end2end --label clab-node-name=dc --cmd 'ping -n -c3 172.16.1.10' --format json) - echo $TEST_DC_CLIENT - echo $TEST_DC_CLIENT | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - # Run end-to-end test: deconfigure service IETF - - > - docker run -t --rm --name ${TEST_NAME} --network=host - --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh" - --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" - $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-service-ietf-remove.sh - - # Dump configuration of the firewall (after deconfigure IETF service) - - containerlab exec --name acl_end2end --label clab-node-name=firewall --cmd "Cli --command \"enable"$'\n'$"show running-config\"" + - export TEST_DC_CLIENT2=$(containerlab exec --name acl_end2end --label clab-node-name=dc --cmd 'ping -n -c3 172.16.2.10' --format json) + - echo $TEST_DC_CLIENT2 + - echo $TEST_DC_CLIENT2 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' # Run end-to-end test: cleanup scenario - > diff --git a/src/tests/acl_end2end/README.md b/src/tests/acl_end2end/README.md index 195ea4d70..2df4fdacf 100644 --- a/src/tests/acl_end2end/README.md +++ b/src/tests/acl_end2end/README.md @@ -47,22 +47,31 @@ sudo rm -rf clab-acl_end2end/ .acl_end2end.clab.yml.bak ## Access cEOS Bash/CLI ```bash docker exec -it clab-acl_end2end-firewall bash -docker exec -it clab-acl_end2end-client bash +docker exec -it clab-acl_end2end-client1 bash docker exec -it clab-acl_end2end-dc bash +docker exec -it clab-acl_end2end-client2 bash docker exec -it clab-acl_end2end-firewall Cli ``` ## Configure ContainerLab clients ```bash -docker exec -it clab-acl_end2end-client bash +docker exec -it clab-acl_end2end-client1 bash ip address add 172.16.1.10/24 dev eth1 + ip route add 172.16.0.0/24 via 172.16.1.1 ip route add 172.16.2.0/24 via 172.16.1.1 - ping 172.16.2.10 + ping 172.16.0.10 docker exec -it clab-acl_end2end-dc bash + ip address add 172.16.0.10/24 dev eth1 + ip route add 172.16.1.0/24 via 172.16.0.1 + ip route add 172.16.2.0/24 via 172.16.0.1 + ping 172.16.1.10 + +docker exec -it clab-acl_end2end-client2 bash ip address add 172.16.2.10/24 dev eth1 + ip route add 172.16.0.0/24 via 172.16.2.1 ip route add 172.16.1.0/24 via 172.16.2.1 - ping 172.16.1.10 + ping 172.16.0.10 ``` ## Install gNMIc @@ -101,6 +110,9 @@ gnmic --address clab-acl_end2end-firewall --port 6030 --username admin --passwor gnmic --address clab-acl_end2end-firewall --port 6030 --username admin --password admin --insecure --encoding json_ietf get --path '/interfaces' > firewall-ifs.json ``` +# ACL payload +`data/ietf-acl.json` contains an example ACL that blocks ICMP from client1 (172.16.1.10) to the DC (172.16.0.10) on the firewall ingress interface Ethernet10 while permitting other traffic. Post it to `/restconf/data/device=firewall/ietf-access-control-list:acls`. + # Delete elements: ```bash --address clab-acl_end2end-firewall --port 6030 --username admin --password admin --insecure --encoding json_ietf set --delete '/network-instances/network-instance[name=b19229e8]' diff --git a/src/tests/acl_end2end/clab/acl_end2end.clab.yml b/src/tests/acl_end2end/clab/acl_end2end.clab.yml index 8b7329847..48bf2de44 100644 --- a/src/tests/acl_end2end/clab/acl_end2end.clab.yml +++ b/src/tests/acl_end2end/clab/acl_end2end.clab.yml @@ -41,22 +41,34 @@ topology: mgmt-ipv4: 172.20.20.101 startup-config: firewall-startup.cfg - client: + dc: kind: linux - mgmt-ipv4: 172.20.20.201 + mgmt-ipv4: 172.20.20.200 exec: - - ip link set address 00:c1:ab:00:01:01 dev eth1 + - ip link set address 00:c1:ab:00:01:0a dev eth1 - ip address add 172.16.1.10/24 dev eth1 - - ip route add 172.16.2.0/24 via 172.16.1.1 + - ip route add 172.16.11.0/24 via 172.16.1.1 + - ip route add 172.16.12.0/24 via 172.16.1.1 - dc: + client1: + kind: linux + mgmt-ipv4: 172.20.20.201 + exec: + - ip link set address 00:c1:ab:00:0b:0a dev eth1 + - ip address add 172.16.11.10/24 dev eth1 + - ip route add 172.16.1.0/24 via 172.16.11.1 + - ip route add 172.16.12.0/24 via 172.16.11.1 + + client2: kind: linux mgmt-ipv4: 172.20.20.202 exec: - - ip link set address 00:c1:ab:00:02:01 dev eth1 - - ip address add 172.16.2.10/24 dev eth1 - - ip route add 172.16.1.0/24 via 172.16.2.1 + - ip link set address 00:c1:ab:00:0c:0a dev eth1 + - ip address add 172.16.12.10/24 dev eth1 + - ip route add 172.16.1.0/24 via 172.16.12.1 + - ip route add 172.16.11.0/24 via 172.16.12.1 links: - - endpoints: ["firewall:eth10", "client:eth1"] - - endpoints: ["firewall:eth2", "dc:eth1"] + - endpoints: ["firewall:eth1", "dc:eth1" ] + - endpoints: ["firewall:eth11", "client1:eth1"] + - endpoints: ["firewall:eth12", "client2:eth1"] diff --git a/src/tests/acl_end2end/clab/firewall-startup.cfg b/src/tests/acl_end2end/clab/firewall-startup.cfg index d3b91baed..2213566fa 100644 --- a/src/tests/acl_end2end/clab/firewall-startup.cfg +++ b/src/tests/acl_end2end/clab/firewall-startup.cfg @@ -27,12 +27,16 @@ management api gnmi management api netconf transport ssh default ! -interface Ethernet2 - ip address 172.16.2.1/24 +interface Ethernet1 + ip address 172.16.1.1/24 no shutdown ! -interface Ethernet10 - ip address 172.16.1.1/24 +interface Ethernet11 + ip address 172.16.11.1/24 + no shutdown +! +interface Ethernet12 + ip address 172.16.12.1/24 no shutdown ! interface Management0 diff --git a/src/tests/acl_end2end/data/ietf-acl.json b/src/tests/acl_end2end/data/ietf-acl.json new file mode 100644 index 000000000..6c6f187b3 --- /dev/null +++ b/src/tests/acl_end2end/data/ietf-acl.json @@ -0,0 +1,40 @@ +{ + "ietf-access-control-list:acls": { + "acl": [{ + "name": "block-client1-ping-permit-other", + "type": "ipv4-acl-type", + "aces": { + "ace": [{ + "name": "block-client1-ping", + "matches": { + "ingress-interface": "Ethernet10", + "ipv4": { + "protocol": 1, + "source-ipv4-network": "172.16.1.10/32", + "destination-ipv4-network": "172.16.0.10/32" + }, + "icmp": {} + }, + "actions": {"forwarding": "reject"} + }, + { + "name": "permit-other", + "matches": { + "ingress-interface": "Ethernet10" + }, + "actions": {"forwarding": "accept"} + }] + } + }], + "attachment-points": { + "interface": [{ + "interface-id": "Ethernet10", + "ingress": { + "acl-sets": { + "acl-set": [{"name": "block-client1-ping-permit-other"}] + } + } + }] + } + } +} diff --git a/src/tests/acl_end2end/data/ietf-l3vpn-service.json b/src/tests/acl_end2end/data/ietf-l3vpn-service.json deleted file mode 100644 index 0f471168c..000000000 --- a/src/tests/acl_end2end/data/ietf-l3vpn-service.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "ietf-l3vpn-svc:l3vpn-svc": { - "vpn-services": {"vpn-service": [{"vpn-id": "ietf-l3vpn-svc"}]}, - "sites": { - "site": [ - { - "site-id": "site_client", - "management": {"type": "ietf-l3vpn-svc:provider-managed"}, - "locations": {"location": [{"location-id": "CLIENT"}]}, - "devices": {"device": [{"device-id": "client", "location": "CLIENT"}]}, - "site-network-accesses": { - "site-network-access": [ - { - "site-network-access-id": "eth1", - "site-network-access-type": "ietf-l3vpn-svc:multipoint", - "device-reference": "client", - "vpn-attachment": {"vpn-id": "ietf-l3vpn-svc", "site-role": "ietf-l3vpn-svc:spoke-role"}, - "ip-connection": { - "ipv4": { - "address-allocation-type": "ietf-l3vpn-svc:static-address", - "addresses": { - "provider-address": "172.16.1.1", - "customer-address": "172.16.1.10", - "prefix-length": 24 - } - } - }, - "service": { - "svc-mtu": 1500, - "svc-input-bandwidth": 1000000000, - "svc-output-bandwidth": 1000000000, - "qos": {"qos-profile": {"classes": {"class": [{ - "class-id": "qos-realtime", - "direction": "ietf-l3vpn-svc:both", - "latency": {"latency-boundary": 10}, - "bandwidth": {"guaranteed-bw-percent": 100} - }]}}} - } - } - ] - } - }, - { - "site-id": "site_dc", - "management": {"type": "ietf-l3vpn-svc:provider-managed"}, - "locations": {"location": [{"location-id": "DC"}]}, - "devices": {"device": [{"device-id": "dc", "location": "DC"}]}, - "site-network-accesses": { - "site-network-access": [ - { - "site-network-access-id": "eth1", - "site-network-access-type": "ietf-l3vpn-svc:multipoint", - "device-reference": "dc", - "vpn-attachment": {"vpn-id": "ietf-l3vpn-svc", "site-role": "ietf-l3vpn-svc:hub-role"}, - "ip-connection": { - "ipv4": { - "address-allocation-type": "ietf-l3vpn-svc:static-address", - "addresses": { - "provider-address": "172.16.2.1", - "customer-address": "172.16.2.10", - "prefix-length": 24 - } - } - }, - "service": { - "svc-mtu": 1500, - "svc-input-bandwidth": 1000000000, - "svc-output-bandwidth": 1000000000, - "qos": {"qos-profile": {"classes": {"class": [{ - "class-id": "qos-realtime", - "direction": "ietf-l3vpn-svc:both", - "latency": {"latency-boundary": 10}, - "bandwidth": {"guaranteed-bw-percent": 100} - }]}}} - } - } - ] - } - } - ] - } - } -} diff --git a/src/tests/acl_end2end/data/tfs-topology.json b/src/tests/acl_end2end/data/tfs-topology.json index da142fddb..96202672c 100644 --- a/src/tests/acl_end2end/data/tfs-topology.json +++ b/src/tests/acl_end2end/data/tfs-topology.json @@ -7,7 +7,18 @@ ], "devices": [ { - "device_id": {"device_uuid": {"uuid": "client"}}, "device_type": "emu-client", + "device_id": {"device_uuid": {"uuid": "client1"}}, "device_type": "emu-client", + "device_drivers": ["DEVICEDRIVER_UNDEFINED"], + "device_config": {"config_rules": [ + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"uuid": "eth1", "type": "copper"}, {"uuid": "int", "type": "copper"} + ]}}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "client2"}}, "device_type": "emu-client", "device_drivers": ["DEVICEDRIVER_UNDEFINED"], "device_config": {"config_rules": [ {"action": "CONFIGACTION_SET", "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, @@ -42,16 +53,16 @@ ], "links": [ { - "link_id": {"link_uuid": {"uuid": "firewall/Ethernet10==client/eth1"}}, + "link_id": {"link_uuid": {"uuid": "firewall/Ethernet10==client1/eth1"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet10"}}, - {"device_id": {"device_uuid": {"uuid": "client"}}, "endpoint_uuid": {"uuid": "eth1"}} + {"device_id": {"device_uuid": {"uuid": "client1"}}, "endpoint_uuid": {"uuid": "eth1"}} ] }, { - "link_id": {"link_uuid": {"uuid": "client/eth1==firewall/Ethernet10"}}, + "link_id": {"link_uuid": {"uuid": "client1/eth1==firewall/Ethernet10"}}, "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "client"}}, "endpoint_uuid": {"uuid": "eth1"}}, + {"device_id": {"device_uuid": {"uuid": "client1"}}, "endpoint_uuid": {"uuid": "eth1"}}, {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet10"}} ] }, @@ -69,6 +80,21 @@ {"device_id": {"device_uuid": {"uuid": "dc"}}, "endpoint_uuid": {"uuid": "eth1"}}, {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet2"}} ] + }, + + { + "link_id": {"link_uuid": {"uuid": "firewall/Ethernet3==client2/eth1"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet3"}}, + {"device_id": {"device_uuid": {"uuid": "client2"}}, "endpoint_uuid": {"uuid": "eth1"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "client2/eth1==firewall/Ethernet3"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "client2"}}, "endpoint_uuid": {"uuid": "eth1"}}, + {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet3"}} + ] } ] } diff --git a/src/tests/acl_end2end/scripts/run-service-ietf-create.sh b/src/tests/acl_end2end/scripts/run-acl-tests.sh old mode 100755 new mode 100644 similarity index 85% rename from src/tests/acl_end2end/scripts/run-service-ietf-create.sh rename to src/tests/acl_end2end/scripts/run-acl-tests.sh index bc592f32f..9cfd14b65 --- a/src/tests/acl_end2end/scripts/run-service-ietf-create.sh +++ b/src/tests/acl_end2end/scripts/run-acl-tests.sh @@ -16,5 +16,5 @@ source /var/teraflow/tfs_runtime_env_vars.sh export PYTHONPATH=/var/teraflow pytest --verbose --log-level=INFO \ - --junitxml=/opt/results/report_service_ietf_create.xml \ - /var/teraflow/tests/acl_end2end/tests/test_service_ietf_create.py + --junitxml=/opt/results/report_acl.xml \ + /var/teraflow/tests/acl_end2end/tests/test_acl.py diff --git a/src/tests/acl_end2end/scripts/run-service-ietf-remove.sh b/src/tests/acl_end2end/scripts/run-service-ietf-remove.sh deleted file mode 100755 index cd55fdaa1..000000000 --- a/src/tests/acl_end2end/scripts/run-service-ietf-remove.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -source /var/teraflow/tfs_runtime_env_vars.sh -export PYTHONPATH=/var/teraflow -pytest --verbose --log-level=INFO \ - --junitxml=/opt/results/report_service_ietf_remove.xml \ - /var/teraflow/tests/acl_end2end/tests/test_service_ietf_remove.py diff --git a/src/tests/acl_end2end/tests/test_acl.py b/src/tests/acl_end2end/tests/test_acl.py new file mode 100644 index 000000000..7cf4c7d64 --- /dev/null +++ b/src/tests/acl_end2end/tests/test_acl.py @@ -0,0 +1,57 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json, logging, os +from typing import Dict +from .Tools import do_rest_delete_request, do_rest_get_request, do_rest_post_request + + +LOGGER = logging.getLogger(__name__) +LOGGER.setLevel(logging.DEBUG) + +ACL_URL = '/restconf/data/device=firewall/ietf-access-control-list:acls' +ACL_GET_URL_TEMPLATE = '/restconf/data/device=firewall/ietf-access-control-list:acl={acl_name}' +ACL_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'ietf-acl.json') + + +def _load_acl_payload() -> Dict: + with open(ACL_FILE, 'r', encoding='UTF-8') as f: + return json.load(f) + + +def test_ietf_acl_create() -> None: + acl_payload = _load_acl_payload() + acl_name = acl_payload['ietf-access-control-list:acls']['acl'][0]['name'] + + do_rest_delete_request( + ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, expected_status_codes={200, 204, 404} + ) + do_rest_post_request(ACL_URL, body=acl_payload, logger=LOGGER, expected_status_codes={201, 204}) + response = do_rest_get_request( + ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, expected_status_codes={200} + ) + assert response is not None + + +def test_ietf_acl_delete() -> None: + acl_payload = _load_acl_payload() + acl_name = acl_payload['ietf-access-control-list:acls']['acl'][0]['name'] + + do_rest_post_request(ACL_URL, body=acl_payload, logger=LOGGER, expected_status_codes={201, 204}) + do_rest_delete_request( + ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, expected_status_codes={200, 204} + ) + do_rest_get_request( + ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, expected_status_codes={404} + ) diff --git a/src/tests/acl_end2end/tests/test_service_ietf_create.py b/src/tests/acl_end2end/tests/test_service_ietf_create.py deleted file mode 100644 index f3a68801d..000000000 --- a/src/tests/acl_end2end/tests/test_service_ietf_create.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import json, logging, os -from typing import Dict -from common.Constants import DEFAULT_CONTEXT_NAME -from common.proto.context_pb2 import ContextId, ServiceStatusEnum, ServiceTypeEnum -from common.tools.grpc.Tools import grpc_message_to_json_string -from common.tools.object_factory.Context import json_context_id -from context.client.ContextClient import ContextClient -from .Fixtures import context_client # pylint: disable=unused-import -from .Tools import do_rest_get_request, do_rest_post_request - - -LOGGER = logging.getLogger(__name__) -LOGGER.setLevel(logging.DEBUG) - -REQUEST_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'ietf-l3vpn-service.json') -ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) - - -# pylint: disable=redefined-outer-name, unused-argument -def test_service_ietf_creation( - context_client : ContextClient, -): - # Issue service creation request - with open(REQUEST_FILE, 'r', encoding='UTF-8') as f: - svc1_data = json.load(f) - URL = '/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services' - do_rest_post_request(URL, body=svc1_data, logger=LOGGER, expected_status_codes={201}) - vpn_id = svc1_data['ietf-l3vpn-svc:l3vpn-svc']['vpn-services']['vpn-service'][0]['vpn-id'] - - URL = '/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services/vpn-service={:s}/'.format(vpn_id) - service_data = do_rest_get_request(URL, logger=LOGGER, expected_status_codes={200}) - service_uuid = service_data['service-id'] - - # Verify service was created - response = context_client.GetContext(ADMIN_CONTEXT_ID) - assert len(response.service_ids) == 1 - assert len(response.slice_ids) == 0 - - # Check there is 1 service - response = context_client.ListServices(ADMIN_CONTEXT_ID) - LOGGER.warning('Services[{:d}] = {:s}'.format( - len(response.services), grpc_message_to_json_string(response) - )) - assert len(response.services) == 1 - - for service in response.services: - service_id = service.service_id - assert service_id.service_uuid.uuid == service_uuid - assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE - assert service.service_type == ServiceTypeEnum.SERVICETYPE_L3NM - - response = context_client.ListConnections(service_id) - LOGGER.warning(' ServiceId[{:s}] => Connections[{:d}] = {:s}'.format( - grpc_message_to_json_string(service_id), len(response.connections), - grpc_message_to_json_string(response) - )) - assert len(response.connections) == 1 diff --git a/src/tests/acl_end2end/tests/test_service_ietf_remove.py b/src/tests/acl_end2end/tests/test_service_ietf_remove.py deleted file mode 100644 index 2c3920824..000000000 --- a/src/tests/acl_end2end/tests/test_service_ietf_remove.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging, os -from typing import Dict, Set, Tuple -from common.Constants import DEFAULT_CONTEXT_NAME -from common.proto.context_pb2 import ContextId, ServiceStatusEnum, ServiceTypeEnum -from common.tools.grpc.Tools import grpc_message_to_json_string -from common.tools.object_factory.Context import json_context_id -from context.client.ContextClient import ContextClient -from .Fixtures import context_client # pylint: disable=unused-import -from .Tools import do_rest_delete_request - - -LOGGER = logging.getLogger(__name__) -LOGGER.setLevel(logging.DEBUG) - -REQUEST_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'ietf-l3vpn-service.json') -ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME)) - - -# pylint: disable=redefined-outer-name, unused-argument -def test_service_ietf_removal( - context_client : ContextClient, # pylint: disable=redefined-outer-name -): - # Verify the scenario has 1 service and 0 slices - response = context_client.GetContext(ADMIN_CONTEXT_ID) - assert len(response.service_ids) == 1 - assert len(response.slice_ids) == 0 - - # Check there are no slices - response = context_client.ListSlices(ADMIN_CONTEXT_ID) - LOGGER.warning('Slices[{:d}] = {:s}'.format(len(response.slices), grpc_message_to_json_string(response))) - assert len(response.slices) == 0 - - # Check there is 1 service - response = context_client.ListServices(ADMIN_CONTEXT_ID) - LOGGER.warning('Services[{:d}] = {:s}'.format(len(response.services), grpc_message_to_json_string(response))) - assert len(response.services) == 1 - - service_uuids : Set[str] = set() - for service in response.services: - service_id = service.service_id - assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE - assert service.service_type == ServiceTypeEnum.SERVICETYPE_L3NM - - response = context_client.ListConnections(service_id) - LOGGER.warning(' ServiceId[{:s}] => Connections[{:d}] = {:s}'.format( - grpc_message_to_json_string(service_id), len(response.connections), - grpc_message_to_json_string(response) - )) - assert len(response.connections) == 1 - - service_uuids.add(service_id.service_uuid.uuid) - - # Identify service to delete - assert len(service_uuids) == 1 - service_uuid = set(service_uuids).pop() - - URL = '/restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services/vpn-service={:s}/'.format(service_uuid) - do_rest_delete_request(URL, logger=LOGGER, expected_status_codes={204}) - - # Verify the scenario has no services/slices - response = context_client.GetContext(ADMIN_CONTEXT_ID) - assert len(response.service_ids) == 0 - assert len(response.slice_ids) == 0 -- GitLab From 3f0dce82bffc331cf637fea536e822bfbf53d166 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 12:03:42 +0000 Subject: [PATCH 05/20] Tests - ACL End-to-end integration test: - Updated ContainerLab scenario and config - Updated TFS descritpors - Updated IETF ACL data file --- .../acl_end2end/clab/acl_end2end.clab.yml | 14 +++---- .../acl_end2end/clab/firewall-startup.cfg | 4 +- src/tests/acl_end2end/data/ietf-acl.json | 39 ++++++++++++++----- src/tests/acl_end2end/data/tfs-topology.json | 28 ++++++------- 4 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/tests/acl_end2end/clab/acl_end2end.clab.yml b/src/tests/acl_end2end/clab/acl_end2end.clab.yml index 48bf2de44..737dd1f9d 100644 --- a/src/tests/acl_end2end/clab/acl_end2end.clab.yml +++ b/src/tests/acl_end2end/clab/acl_end2end.clab.yml @@ -45,10 +45,10 @@ topology: kind: linux mgmt-ipv4: 172.20.20.200 exec: - - ip link set address 00:c1:ab:00:01:0a dev eth1 - - ip address add 172.16.1.10/24 dev eth1 - - ip route add 172.16.11.0/24 via 172.16.1.1 - - ip route add 172.16.12.0/24 via 172.16.1.1 + - ip link set address 00:c1:ab:00:0a:0a dev eth1 + - ip address add 172.16.10.10/24 dev eth1 + - ip route add 172.16.11.0/24 via 172.16.10.1 + - ip route add 172.16.12.0/24 via 172.16.10.1 client1: kind: linux @@ -56,7 +56,7 @@ topology: exec: - ip link set address 00:c1:ab:00:0b:0a dev eth1 - ip address add 172.16.11.10/24 dev eth1 - - ip route add 172.16.1.0/24 via 172.16.11.1 + - ip route add 172.16.10.0/24 via 172.16.11.1 - ip route add 172.16.12.0/24 via 172.16.11.1 client2: @@ -65,10 +65,10 @@ topology: exec: - ip link set address 00:c1:ab:00:0c:0a dev eth1 - ip address add 172.16.12.10/24 dev eth1 - - ip route add 172.16.1.0/24 via 172.16.12.1 + - ip route add 172.16.10.0/24 via 172.16.12.1 - ip route add 172.16.11.0/24 via 172.16.12.1 links: - - endpoints: ["firewall:eth1", "dc:eth1" ] + - endpoints: ["firewall:eth10", "dc:eth1" ] - endpoints: ["firewall:eth11", "client1:eth1"] - endpoints: ["firewall:eth12", "client2:eth1"] diff --git a/src/tests/acl_end2end/clab/firewall-startup.cfg b/src/tests/acl_end2end/clab/firewall-startup.cfg index 2213566fa..50ce415c1 100644 --- a/src/tests/acl_end2end/clab/firewall-startup.cfg +++ b/src/tests/acl_end2end/clab/firewall-startup.cfg @@ -27,8 +27,8 @@ management api gnmi management api netconf transport ssh default ! -interface Ethernet1 - ip address 172.16.1.1/24 +interface Ethernet10 + ip address 172.16.10.1/24 no shutdown ! interface Ethernet11 diff --git a/src/tests/acl_end2end/data/ietf-acl.json b/src/tests/acl_end2end/data/ietf-acl.json index 6c6f187b3..a3a311950 100644 --- a/src/tests/acl_end2end/data/ietf-acl.json +++ b/src/tests/acl_end2end/data/ietf-acl.json @@ -1,26 +1,39 @@ { "ietf-access-control-list:acls": { "acl": [{ - "name": "block-client1-ping-permit-other", + "name": "eth11-block-ping-permit-other", "type": "ipv4-acl-type", "aces": { "ace": [{ - "name": "block-client1-ping", + "name": "eth11-block-ping", "matches": { - "ingress-interface": "Ethernet10", + "ingress-interface": "Ethernet11", "ipv4": { "protocol": 1, - "source-ipv4-network": "172.16.1.10/32", - "destination-ipv4-network": "172.16.0.10/32" + "source-ipv4-network": "172.16.11.10/32", + "destination-ipv4-network": "172.16.1.10/32" }, "icmp": {} }, "actions": {"forwarding": "reject"} }, { - "name": "permit-other", + "name": "eth11-permit-other", "matches": { - "ingress-interface": "Ethernet10" + "ingress-interface": "Ethernet11" + }, + "actions": {"forwarding": "accept"} + }] + } + }, + { + "name": "eth12-permit-other", + "type": "ipv4-acl-type", + "aces": { + "ace": [{ + "name": "eth12-permit-other", + "matches": { + "ingress-interface": "Ethernet12" }, "actions": {"forwarding": "accept"} }] @@ -28,10 +41,18 @@ }], "attachment-points": { "interface": [{ - "interface-id": "Ethernet10", + "interface-id": "Ethernet11", + "ingress": { + "acl-sets": { + "acl-set": [{"name": "eth11-block-ping-permit-other"}] + } + } + }, + { + "interface-id": "Ethernet12", "ingress": { "acl-sets": { - "acl-set": [{"name": "block-client1-ping-permit-other"}] + "acl-set": [{"name": "eth12-permit-other"}] } } }] diff --git a/src/tests/acl_end2end/data/tfs-topology.json b/src/tests/acl_end2end/data/tfs-topology.json index 96202672c..6875b5075 100644 --- a/src/tests/acl_end2end/data/tfs-topology.json +++ b/src/tests/acl_end2end/data/tfs-topology.json @@ -53,47 +53,47 @@ ], "links": [ { - "link_id": {"link_uuid": {"uuid": "firewall/Ethernet10==client1/eth1"}}, + "link_id": {"link_uuid": {"uuid": "firewall/Ethernet10==dc/eth1"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet10"}}, - {"device_id": {"device_uuid": {"uuid": "client1"}}, "endpoint_uuid": {"uuid": "eth1"}} + {"device_id": {"device_uuid": {"uuid": "dc"}}, "endpoint_uuid": {"uuid": "eth1"}} ] }, { - "link_id": {"link_uuid": {"uuid": "client1/eth1==firewall/Ethernet10"}}, + "link_id": {"link_uuid": {"uuid": "dc/eth1==firewall/Ethernet10"}}, "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "client1"}}, "endpoint_uuid": {"uuid": "eth1"}}, + {"device_id": {"device_uuid": {"uuid": "dc"}}, "endpoint_uuid": {"uuid": "eth1"}}, {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet10"}} ] }, { - "link_id": {"link_uuid": {"uuid": "firewall/Ethernet2==dc/eth1"}}, + "link_id": {"link_uuid": {"uuid": "firewall/Ethernet11==client1/eth1"}}, "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet2"}}, - {"device_id": {"device_uuid": {"uuid": "dc"}}, "endpoint_uuid": {"uuid": "eth1"}} + {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet11"}}, + {"device_id": {"device_uuid": {"uuid": "client1"}}, "endpoint_uuid": {"uuid": "eth1"}} ] }, { - "link_id": {"link_uuid": {"uuid": "dc/eth1==firewall/Ethernet2"}}, + "link_id": {"link_uuid": {"uuid": "client1/eth1==firewall/Ethernet11"}}, "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "dc"}}, "endpoint_uuid": {"uuid": "eth1"}}, - {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet2"}} + {"device_id": {"device_uuid": {"uuid": "client1"}}, "endpoint_uuid": {"uuid": "eth1"}}, + {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet11"}} ] }, { - "link_id": {"link_uuid": {"uuid": "firewall/Ethernet3==client2/eth1"}}, + "link_id": {"link_uuid": {"uuid": "firewall/Ethernet12==client2/eth1"}}, "link_endpoint_ids": [ - {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet3"}}, + {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet12"}}, {"device_id": {"device_uuid": {"uuid": "client2"}}, "endpoint_uuid": {"uuid": "eth1"}} ] }, { - "link_id": {"link_uuid": {"uuid": "client2/eth1==firewall/Ethernet3"}}, + "link_id": {"link_uuid": {"uuid": "client2/eth1==firewall/Ethernet12"}}, "link_endpoint_ids": [ {"device_id": {"device_uuid": {"uuid": "client2"}}, "endpoint_uuid": {"uuid": "eth1"}}, - {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet3"}} + {"device_id": {"device_uuid": {"uuid": "firewall"}}, "endpoint_uuid": {"uuid": "Ethernet12"}} ] } ] -- GitLab From b2ae6cf3d04854f5838bb4733016de4cacd7f9a4 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 13:24:13 +0000 Subject: [PATCH 06/20] Tests - ACL End-to-end integration test: - Updated README.md --- src/tests/acl_end2end/README.md | 34 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/tests/acl_end2end/README.md b/src/tests/acl_end2end/README.md index 2df4fdacf..fe3718bea 100644 --- a/src/tests/acl_end2end/README.md +++ b/src/tests/acl_end2end/README.md @@ -47,31 +47,33 @@ sudo rm -rf clab-acl_end2end/ .acl_end2end.clab.yml.bak ## Access cEOS Bash/CLI ```bash docker exec -it clab-acl_end2end-firewall bash +docker exec -it clab-acl_end2end-firewall Cli docker exec -it clab-acl_end2end-client1 bash -docker exec -it clab-acl_end2end-dc bash docker exec -it clab-acl_end2end-client2 bash -docker exec -it clab-acl_end2end-firewall Cli +docker exec -it clab-acl_end2end-dc bash ``` ## Configure ContainerLab clients ```bash +docker exec -it clab-acl_end2end-dc bash + ip address add 172.16.10.10/24 dev eth1 + ip route add 172.16.11.0/24 via 172.16.10.1 + ip route add 172.16.12.0/24 via 172.16.10.1 + ping 172.16.11.10 + ping 172.16.12.10 + docker exec -it clab-acl_end2end-client1 bash - ip address add 172.16.1.10/24 dev eth1 - ip route add 172.16.0.0/24 via 172.16.1.1 - ip route add 172.16.2.0/24 via 172.16.1.1 - ping 172.16.0.10 + ip address add 172.16.11.10/24 dev eth1 + ip route add 172.16.10.0/24 via 172.16.11.1 + ip route add 172.16.12.0/24 via 172.16.11.1 + ping 172.16.10.10 -docker exec -it clab-acl_end2end-dc bash - ip address add 172.16.0.10/24 dev eth1 - ip route add 172.16.1.0/24 via 172.16.0.1 - ip route add 172.16.2.0/24 via 172.16.0.1 - ping 172.16.1.10 docker exec -it clab-acl_end2end-client2 bash - ip address add 172.16.2.10/24 dev eth1 - ip route add 172.16.0.0/24 via 172.16.2.1 - ip route add 172.16.1.0/24 via 172.16.2.1 - ping 172.16.0.10 + ip address add 172.16.12.10/24 dev eth1 + ip route add 172.16.10.0/24 via 172.16.12.1 + ip route add 172.16.11.0/24 via 172.16.12.1 + ping 172.16.10.10 ``` ## Install gNMIc @@ -111,7 +113,7 @@ gnmic --address clab-acl_end2end-firewall --port 6030 --username admin --passwor ``` # ACL payload -`data/ietf-acl.json` contains an example ACL that blocks ICMP from client1 (172.16.1.10) to the DC (172.16.0.10) on the firewall ingress interface Ethernet10 while permitting other traffic. Post it to `/restconf/data/device=firewall/ietf-access-control-list:acls`. +`data/ietf-acl.json` contains an example ACL that blocks ICMP from client1 (172.16.11.10) to the DC (172.16.10.10) on the firewall ingress interface Ethernet11 while permitting other traffic. Post it to `/restconf/data/device=firewall/ietf-access-control-list:acls`. # Delete elements: ```bash -- GitLab From c3d8c70b77482af1a95f0339fdca9c49de2636a5 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 13:26:37 +0000 Subject: [PATCH 07/20] Tests - ACL End-to-end integration test: - Updated IETF ACL data file --- src/tests/acl_end2end/data/ietf-acl.json | 123 ++++++++++++++--------- 1 file changed, 74 insertions(+), 49 deletions(-) diff --git a/src/tests/acl_end2end/data/ietf-acl.json b/src/tests/acl_end2end/data/ietf-acl.json index a3a311950..39ea4ab85 100644 --- a/src/tests/acl_end2end/data/ietf-acl.json +++ b/src/tests/acl_end2end/data/ietf-acl.json @@ -1,61 +1,86 @@ { "ietf-access-control-list:acls": { - "acl": [{ - "name": "eth11-block-ping-permit-other", - "type": "ipv4-acl-type", - "aces": { - "ace": [{ - "name": "eth11-block-ping", - "matches": { - "ingress-interface": "Ethernet11", - "ipv4": { - "protocol": 1, - "source-ipv4-network": "172.16.11.10/32", - "destination-ipv4-network": "172.16.1.10/32" + "acl": [ + { + "name": "eth10-permit-other", + "type": "ipv4-acl-type", + "aces": { + "ace": [{ + "name": "eth10-permit-other", + "matches": { + "ingress-interface": "Ethernet10" }, - "icmp": {} - }, - "actions": {"forwarding": "reject"} - }, - { - "name": "eth11-permit-other", - "matches": { - "ingress-interface": "Ethernet11" - }, - "actions": {"forwarding": "accept"} - }] - } - }, - { - "name": "eth12-permit-other", - "type": "ipv4-acl-type", - "aces": { - "ace": [{ - "name": "eth12-permit-other", - "matches": { - "ingress-interface": "Ethernet12" + "actions": {"forwarding": "accept"} + }] + } + }, + { + "name": "eth11-block-ping-permit-other", + "type": "ipv4-acl-type", + "aces": { + "ace": [{ + "name": "eth11-block-ping", + "matches": { + "ingress-interface": "Ethernet11", + "ipv4": { + "protocol": 1, + "source-ipv4-network": "172.16.11.10/32", + "destination-ipv4-network": "172.16.10.10/32" + }, + "icmp": {} + }, + "actions": {"forwarding": "reject"} }, - "actions": {"forwarding": "accept"} - }] - } - }], - "attachment-points": { - "interface": [{ - "interface-id": "Ethernet11", - "ingress": { - "acl-sets": { - "acl-set": [{"name": "eth11-block-ping-permit-other"}] - } + { + "name": "eth11-permit-other", + "matches": { + "ingress-interface": "Ethernet11" + }, + "actions": {"forwarding": "accept"} + }] } }, { - "interface-id": "Ethernet12", - "ingress": { - "acl-sets": { - "acl-set": [{"name": "eth12-permit-other"}] + "name": "eth12-permit-other", + "type": "ipv4-acl-type", + "aces": { + "ace": [{ + "name": "eth12-permit-other", + "matches": { + "ingress-interface": "Ethernet12" + }, + "actions": {"forwarding": "accept"} + }] + } + } + ], + "attachment-points": { + "interface": [ + { + "interface-id": "Ethernet10", + "ingress": { + "acl-sets": { + "acl-set": [{"name": "eth10-permit-other"}] + } + } + }, + { + "interface-id": "Ethernet11", + "ingress": { + "acl-sets": { + "acl-set": [{"name": "eth11-block-ping-permit-other"}] + } + } + }, + { + "interface-id": "Ethernet12", + "ingress": { + "acl-sets": { + "acl-set": [{"name": "eth12-permit-other"}] + } } } - }] + ] } } } -- GitLab From e7c5c3158a85809ca8b37437fb2fbf19588ad311 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 13:53:46 +0000 Subject: [PATCH 08/20] Tests - ACL End-to-end integration test: - Updated test scripts and code - Updated CI/CD descriptor - Added CI/CD test to pipeline --- src/tests/.gitlab-ci.yml | 1 + src/tests/acl_end2end/.gitlab-ci.yml | 82 ++++++++++++++----- .../{run-acl-tests.sh => run-acl-create.sh} | 5 +- .../acl_end2end/scripts/run-acl-delete.sh | 19 +++++ .../acl_end2end/tests/test_acl_create.py | 49 +++++++++++ .../tests/{test_acl.py => test_acl_delete.py} | 34 +++----- 6 files changed, 146 insertions(+), 44 deletions(-) rename src/tests/acl_end2end/scripts/{run-acl-tests.sh => run-acl-create.sh} (86%) create mode 100644 src/tests/acl_end2end/scripts/run-acl-delete.sh create mode 100644 src/tests/acl_end2end/tests/test_acl_create.py rename src/tests/acl_end2end/tests/{test_acl.py => test_acl_delete.py} (53%) diff --git a/src/tests/.gitlab-ci.yml b/src/tests/.gitlab-ci.yml index 9b256f1ae..723c26d6f 100644 --- a/src/tests/.gitlab-ci.yml +++ b/src/tests/.gitlab-ci.yml @@ -26,6 +26,7 @@ include: #- local: '/src/tests/ofc25/.gitlab-ci.yml' #- local: '/src/tests/ryu-openflow/.gitlab-ci.yml' - local: '/src/tests/qkd_end2end/.gitlab-ci.yml' + - local: '/src/tests/acl_end2end/.gitlab-ci.yml' - local: '/src/tests/tools/mock_tfs_nbi_dependencies/.gitlab-ci.yml' - local: '/src/tests/tools/mock_qkd_node/.gitlab-ci.yml' diff --git a/src/tests/acl_end2end/.gitlab-ci.yml b/src/tests/acl_end2end/.gitlab-ci.yml index 36da8fea0..6962d9f4a 100644 --- a/src/tests/acl_end2end/.gitlab-ci.yml +++ b/src/tests/acl_end2end/.gitlab-ci.yml @@ -188,32 +188,74 @@ end2end_test acl_end2end: --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-onboarding.sh - # Run end-to-end test: configure ACLs + # Baseline connectivity: both clients can reach the DC + - | + export BASE_CLIENT1_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.1.10' --format json) + echo "${BASE_CLIENT1_DC}" + echo "${BASE_CLIENT1_DC}" | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - | + export BASE_CLIENT2_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client2 --cmd 'ping -n -c3 172.16.1.10' --format json) + echo "${BASE_CLIENT2_DC}" + echo "${BASE_CLIENT2_DC}" | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + + # Run end-to-end test: test connectivity with ping before creating ACL + - export TEST_CLIENT1_FW=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.11.1' --format json) + - echo $TEST_CLIENT1_FW + - echo $TEST_CLIENT1_FW | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST_CLIENT1_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.10.10' --format json) + - echo $TEST_CLIENT1_DC + - echo $TEST_CLIENT1_DC | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + + - export TEST_CLIENT2_FW=$(containerlab exec --name acl_end2end --label clab-node-name=client2 --cmd 'ping -n -c3 172.16.12.1' --format json) + - echo $TEST_CLIENT2_FW + - echo $TEST_CLIENT2_FW | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST_CLIENT2_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client2 --cmd 'ping -n -c3 172.16.10.10' --format json) + - echo $TEST_CLIENT2_DC + - echo $TEST_CLIENT2_DC | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + + # Run end-to-end test: create ACLs + - > + docker run -t --rm --name ${TEST_NAME} --network=host + --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh" + --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" + $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-acl-create-tests.sh + + # Run end-to-end test: test connectivity with ping after creating ACL + - export TEST_CLIENT1_FW=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.11.1' --format json) + - echo $TEST_CLIENT1_FW + - echo $TEST_CLIENT1_FW | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST_CLIENT1_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.10.10' --format json) + - echo $TEST_CLIENT1_DC + - echo $TEST_CLIENT1_DC | grep -E '3 packets transmitted, 0 received, 100\% packet loss' + + - export TEST_CLIENT2_FW=$(containerlab exec --name acl_end2end --label clab-node-name=client2 --cmd 'ping -n -c3 172.16.12.1' --format json) + - echo $TEST_CLIENT2_FW + - echo $TEST_CLIENT2_FW | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST_CLIENT2_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client2 --cmd 'ping -n -c3 172.16.10.10' --format json) + - echo $TEST_CLIENT2_DC + - echo $TEST_CLIENT2_DC | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + + # Run end-to-end test: delete ACLs - > docker run -t --rm --name ${TEST_NAME} --network=host --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh" --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" - $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-acl-tests.sh - - # Run end-to-end test: test connectivity with ping - - export TEST_CLIENT_FIREWALL=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.1.1' --format json) - - echo $TEST_CLIENT_FIREWALL - - echo $TEST_CLIENT_FIREWALL | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST_CLIENT_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.0.10' --format json) - - echo $TEST_CLIENT_DC - - echo $TEST_CLIENT_DC | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST_CLIENT2_FIREWALL=$(containerlab exec --name acl_end2end --label clab-node-name=client2 --cmd 'ping -n -c3 172.16.2.1' --format json) - - echo $TEST_CLIENT2_FIREWALL - - echo $TEST_CLIENT2_FIREWALL | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST_CLIENT2_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client2 --cmd 'ping -n -c3 172.16.0.10' --format json) + $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-acl-delete-tests.sh + + # Run end-to-end test: test connectivity with ping after deleting ACL + - export TEST_CLIENT1_FW=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.11.1' --format json) + - echo $TEST_CLIENT1_FW + - echo $TEST_CLIENT1_FW | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST_CLIENT1_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.10.10' --format json) + - echo $TEST_CLIENT1_DC + - echo $TEST_CLIENT1_DC | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + + - export TEST_CLIENT2_FW=$(containerlab exec --name acl_end2end --label clab-node-name=client2 --cmd 'ping -n -c3 172.16.12.1' --format json) + - echo $TEST_CLIENT2_FW + - echo $TEST_CLIENT2_FW | grep -E '3 packets transmitted, 3 received, 0\% packet loss' + - export TEST_CLIENT2_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client2 --cmd 'ping -n -c3 172.16.10.10' --format json) - echo $TEST_CLIENT2_DC - echo $TEST_CLIENT2_DC | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST_DC_CLIENT=$(containerlab exec --name acl_end2end --label clab-node-name=dc --cmd 'ping -n -c3 172.16.1.10' --format json) - - echo $TEST_DC_CLIENT - - echo $TEST_DC_CLIENT | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - export TEST_DC_CLIENT2=$(containerlab exec --name acl_end2end --label clab-node-name=dc --cmd 'ping -n -c3 172.16.2.10' --format json) - - echo $TEST_DC_CLIENT2 - - echo $TEST_DC_CLIENT2 | grep -E '3 packets transmitted, 3 received, 0\% packet loss' # Run end-to-end test: cleanup scenario - > diff --git a/src/tests/acl_end2end/scripts/run-acl-tests.sh b/src/tests/acl_end2end/scripts/run-acl-create.sh similarity index 86% rename from src/tests/acl_end2end/scripts/run-acl-tests.sh rename to src/tests/acl_end2end/scripts/run-acl-create.sh index 9cfd14b65..b2d9915d7 100644 --- a/src/tests/acl_end2end/scripts/run-acl-tests.sh +++ b/src/tests/acl_end2end/scripts/run-acl-create.sh @@ -1,4 +1,3 @@ -#!/bin/bash # Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,5 +15,5 @@ source /var/teraflow/tfs_runtime_env_vars.sh export PYTHONPATH=/var/teraflow pytest --verbose --log-level=INFO \ - --junitxml=/opt/results/report_acl.xml \ - /var/teraflow/tests/acl_end2end/tests/test_acl.py + --junitxml=/opt/results/report_acl_create.xml \ + /var/teraflow/tests/acl_end2end/tests/test_acl_create.py diff --git a/src/tests/acl_end2end/scripts/run-acl-delete.sh b/src/tests/acl_end2end/scripts/run-acl-delete.sh new file mode 100644 index 000000000..933063cf1 --- /dev/null +++ b/src/tests/acl_end2end/scripts/run-acl-delete.sh @@ -0,0 +1,19 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source /var/teraflow/tfs_runtime_env_vars.sh +export PYTHONPATH=/var/teraflow +pytest --verbose --log-level=INFO \ + --junitxml=/opt/results/report_acl_delete.xml \ + /var/teraflow/tests/acl_end2end/tests/test_acl_delete.py diff --git a/src/tests/acl_end2end/tests/test_acl_create.py b/src/tests/acl_end2end/tests/test_acl_create.py new file mode 100644 index 000000000..054472113 --- /dev/null +++ b/src/tests/acl_end2end/tests/test_acl_create.py @@ -0,0 +1,49 @@ +# Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json, logging, os +from typing import Dict +from .Tools import do_rest_get_request, do_rest_post_request + +LOGGER = logging.getLogger(__name__) +LOGGER.setLevel(logging.DEBUG) + +ACL_URL = '/restconf/data/device=firewall/ietf-access-control-list:acls' +ACL_GET_URL_TEMPLATE = '/restconf/data/device=firewall/ietf-access-control-list:acl={acl_name}' +ACL_FILE = os.path.join( + os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'ietf-acl.json' +) + + +def load_acl_payload() -> Dict: + with open(ACL_FILE, 'r', encoding='UTF-8') as f: + return json.load(f) + +def get_acl_name(payload: Dict) -> str: + return payload['ietf-access-control-list:acls']['acl'][0]['name'] + + +def test_ietf_acl_create() -> None: + acl_payload = load_acl_payload() + acl_name = get_acl_name(acl_payload) + + do_rest_post_request( + ACL_URL, body=acl_payload, logger=LOGGER, + expected_status_codes={201, 204} + ) + response = do_rest_get_request( + ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, + expected_status_codes={200} + ) + assert response is not None diff --git a/src/tests/acl_end2end/tests/test_acl.py b/src/tests/acl_end2end/tests/test_acl_delete.py similarity index 53% rename from src/tests/acl_end2end/tests/test_acl.py rename to src/tests/acl_end2end/tests/test_acl_delete.py index 7cf4c7d64..9507bc159 100644 --- a/src/tests/acl_end2end/tests/test_acl.py +++ b/src/tests/acl_end2end/tests/test_acl_delete.py @@ -14,44 +14,36 @@ import json, logging, os from typing import Dict -from .Tools import do_rest_delete_request, do_rest_get_request, do_rest_post_request +from .Tools import do_rest_delete_request, do_rest_get_request LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) ACL_URL = '/restconf/data/device=firewall/ietf-access-control-list:acls' ACL_GET_URL_TEMPLATE = '/restconf/data/device=firewall/ietf-access-control-list:acl={acl_name}' -ACL_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'ietf-acl.json') +ACL_FILE = os.path.join( + os.path.dirname(os.path.abspath(__file__)), '..', 'data', 'ietf-acl.json' +) -def _load_acl_payload() -> Dict: +def load_acl_payload() -> Dict: with open(ACL_FILE, 'r', encoding='UTF-8') as f: return json.load(f) - -def test_ietf_acl_create() -> None: - acl_payload = _load_acl_payload() - acl_name = acl_payload['ietf-access-control-list:acls']['acl'][0]['name'] - - do_rest_delete_request( - ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, expected_status_codes={200, 204, 404} - ) - do_rest_post_request(ACL_URL, body=acl_payload, logger=LOGGER, expected_status_codes={201, 204}) - response = do_rest_get_request( - ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, expected_status_codes={200} - ) - assert response is not None +def get_acl_name(payload: Dict) -> str: + return payload['ietf-access-control-list:acls']['acl'][0]['name'] def test_ietf_acl_delete() -> None: - acl_payload = _load_acl_payload() - acl_name = acl_payload['ietf-access-control-list:acls']['acl'][0]['name'] + acl_payload = load_acl_payload() + acl_name = get_acl_name(acl_payload) - do_rest_post_request(ACL_URL, body=acl_payload, logger=LOGGER, expected_status_codes={201, 204}) do_rest_delete_request( - ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, expected_status_codes={200, 204} + ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, + expected_status_codes={200, 204} ) do_rest_get_request( - ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, expected_status_codes={404} + ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, + expected_status_codes={404} ) -- GitLab From ed131e777d87b1b936ca7cfdbe694bc430e671db Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 14:02:00 +0000 Subject: [PATCH 09/20] Tests - ACL End-to-end integration test: - Code polishing - Added execute permissions to scripts --- src/tests/acl_end2end/scripts/run-acl-create.sh | 1 + src/tests/acl_end2end/scripts/run-acl-delete.sh | 1 + src/tests/acl_end2end/tests/test_acl_delete.py | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) mode change 100644 => 100755 src/tests/acl_end2end/scripts/run-acl-create.sh mode change 100644 => 100755 src/tests/acl_end2end/scripts/run-acl-delete.sh diff --git a/src/tests/acl_end2end/scripts/run-acl-create.sh b/src/tests/acl_end2end/scripts/run-acl-create.sh old mode 100644 new mode 100755 index b2d9915d7..97b8da8db --- a/src/tests/acl_end2end/scripts/run-acl-create.sh +++ b/src/tests/acl_end2end/scripts/run-acl-create.sh @@ -1,3 +1,4 @@ +#!/bin/bash # Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/tests/acl_end2end/scripts/run-acl-delete.sh b/src/tests/acl_end2end/scripts/run-acl-delete.sh old mode 100644 new mode 100755 index 933063cf1..c3450174a --- a/src/tests/acl_end2end/scripts/run-acl-delete.sh +++ b/src/tests/acl_end2end/scripts/run-acl-delete.sh @@ -1,3 +1,4 @@ +#!/bin/bash # Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/src/tests/acl_end2end/tests/test_acl_delete.py b/src/tests/acl_end2end/tests/test_acl_delete.py index 9507bc159..63d9e5a81 100644 --- a/src/tests/acl_end2end/tests/test_acl_delete.py +++ b/src/tests/acl_end2end/tests/test_acl_delete.py @@ -14,7 +14,6 @@ import json, logging, os from typing import Dict - from .Tools import do_rest_delete_request, do_rest_get_request LOGGER = logging.getLogger(__name__) -- GitLab From 131a662838e61fd3d66f9f8c6b4ff8ffa0c7264b Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 14:50:36 +0000 Subject: [PATCH 10/20] Tests - ACL End-to-end integration test: - Removed leftovers in CI/CD pipeline --- src/tests/acl_end2end/.gitlab-ci.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/tests/acl_end2end/.gitlab-ci.yml b/src/tests/acl_end2end/.gitlab-ci.yml index 6962d9f4a..f6301ade2 100644 --- a/src/tests/acl_end2end/.gitlab-ci.yml +++ b/src/tests/acl_end2end/.gitlab-ci.yml @@ -188,16 +188,6 @@ end2end_test acl_end2end: --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-onboarding.sh - # Baseline connectivity: both clients can reach the DC - - | - export BASE_CLIENT1_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.1.10' --format json) - echo "${BASE_CLIENT1_DC}" - echo "${BASE_CLIENT1_DC}" | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - - | - export BASE_CLIENT2_DC=$(containerlab exec --name acl_end2end --label clab-node-name=client2 --cmd 'ping -n -c3 172.16.1.10' --format json) - echo "${BASE_CLIENT2_DC}" - echo "${BASE_CLIENT2_DC}" | grep -E '3 packets transmitted, 3 received, 0\% packet loss' - # Run end-to-end test: test connectivity with ping before creating ACL - export TEST_CLIENT1_FW=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.11.1' --format json) - echo $TEST_CLIENT1_FW -- GitLab From 506a4f5ba7990ae8a134758054a001b5c2d2ae85 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 15:54:07 +0000 Subject: [PATCH 11/20] Tests - ACL End-to-end integration test: - Fixed paths in deploy/destroy scripts - Fixed firewall startup config --- src/tests/acl_end2end/clab/firewall-startup.cfg | 3 +++ src/tests/acl_end2end/deploy-scripts/clab-deploy.sh | 2 +- src/tests/acl_end2end/deploy-scripts/clab-destroy.sh | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tests/acl_end2end/clab/firewall-startup.cfg b/src/tests/acl_end2end/clab/firewall-startup.cfg index 50ce415c1..274ecc71e 100644 --- a/src/tests/acl_end2end/clab/firewall-startup.cfg +++ b/src/tests/acl_end2end/clab/firewall-startup.cfg @@ -28,14 +28,17 @@ management api netconf transport ssh default ! interface Ethernet10 + no switchport ip address 172.16.10.1/24 no shutdown ! interface Ethernet11 + no switchport ip address 172.16.11.1/24 no shutdown ! interface Ethernet12 + no switchport ip address 172.16.12.1/24 no shutdown ! diff --git a/src/tests/acl_end2end/deploy-scripts/clab-deploy.sh b/src/tests/acl_end2end/deploy-scripts/clab-deploy.sh index 5389305a4..7738f011d 100755 --- a/src/tests/acl_end2end/deploy-scripts/clab-deploy.sh +++ b/src/tests/acl_end2end/deploy-scripts/clab-deploy.sh @@ -14,4 +14,4 @@ # limitations under the License. cd ~/tfs-ctrl/src/tests/acl_end2end -sudo containerlab deploy --topo acl_end2end.clab.yml +sudo containerlab deploy --topo clab/acl_end2end.clab.yml diff --git a/src/tests/acl_end2end/deploy-scripts/clab-destroy.sh b/src/tests/acl_end2end/deploy-scripts/clab-destroy.sh index f9bcc9883..efcfcc09d 100755 --- a/src/tests/acl_end2end/deploy-scripts/clab-destroy.sh +++ b/src/tests/acl_end2end/deploy-scripts/clab-destroy.sh @@ -14,5 +14,5 @@ # limitations under the License. cd ~/tfs-ctrl/src/tests/acl_end2end -sudo containerlab destroy --topo acl_end2end.clab.yml -sudo rm -rf clab-acl_end2end/ .acl_end2end.clab.yml.bak +sudo containerlab destroy --topo clab/acl_end2end.clab.yml +sudo rm -rf clab/clab-acl_end2end/ clab/.acl_end2end.clab.yml.bak -- GitLab From d6e55aaa874ecf08bceb224fd1d4fd24a7900017 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 15:54:21 +0000 Subject: [PATCH 12/20] Tests - EUCNC24 End-to-end integration test: - Fixed paths in deploy/destroy scripts --- src/tests/eucnc24/deploy-scripts/clab-deploy.sh | 2 +- src/tests/eucnc24/deploy-scripts/clab-destroy.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/eucnc24/deploy-scripts/clab-deploy.sh b/src/tests/eucnc24/deploy-scripts/clab-deploy.sh index 5e79b0253..4ed529e48 100755 --- a/src/tests/eucnc24/deploy-scripts/clab-deploy.sh +++ b/src/tests/eucnc24/deploy-scripts/clab-deploy.sh @@ -14,4 +14,4 @@ # limitations under the License. cd ~/tfs-ctrl/src/tests/eucnc24 -sudo containerlab deploy --topo eucnc24.clab.yml +sudo containerlab deploy --topo clab/eucnc24.clab.yml diff --git a/src/tests/eucnc24/deploy-scripts/clab-destroy.sh b/src/tests/eucnc24/deploy-scripts/clab-destroy.sh index 55dcf96dc..464b82df6 100755 --- a/src/tests/eucnc24/deploy-scripts/clab-destroy.sh +++ b/src/tests/eucnc24/deploy-scripts/clab-destroy.sh @@ -14,5 +14,5 @@ # limitations under the License. cd ~/tfs-ctrl/src/tests/eucnc24 -sudo containerlab destroy --topo eucnc24.clab.yml -sudo rm -rf clab-eucnc24/ .eucnc24.clab.yml.bak +sudo containerlab destroy --topo clab/eucnc24.clab.yml +sudo rm -rf clab/clab-eucnc24/ clab/.eucnc24.clab.yml.bak -- GitLab From 02b6e5c8a64840cc8e91129abea2b01e7a8d7803 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 16:21:19 +0000 Subject: [PATCH 13/20] Tests - EUCNC24 End-to-end integration test: - Fixed CI/CD test commands - Deactivated other unneeded tests temporarily --- .gitlab-ci.yml | 76 ++++++++++++++-------------- src/tests/.gitlab-ci.yml | 32 ++++++------ src/tests/acl_end2end/.gitlab-ci.yml | 4 +- 3 files changed, 56 insertions(+), 56 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e11c8474a..e3286d05f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,44 +22,44 @@ stages: # include the individual .gitlab-ci.yml of each micro-service and tests include: - #- local: '/manifests/.gitlab-ci.yml' - - local: '/src/monitoring/.gitlab-ci.yml' - - local: '/src/nbi/.gitlab-ci.yml' - - local: '/src/context/.gitlab-ci.yml' - - local: '/src/device/.gitlab-ci.yml' - - local: '/src/service/.gitlab-ci.yml' - - local: '/src/qkd_app/.gitlab-ci.yml' - - local: '/src/dbscanserving/.gitlab-ci.yml' - - local: '/src/opticalattackmitigator/.gitlab-ci.yml' - - local: '/src/opticalattackdetector/.gitlab-ci.yml' - - local: '/src/opticalattackmanager/.gitlab-ci.yml' - - local: '/src/opticalcontroller/.gitlab-ci.yml' - - local: '/src/ztp/.gitlab-ci.yml' - - local: '/src/policy/.gitlab-ci.yml' - - local: '/src/automation/.gitlab-ci.yml' - - local: '/src/forecaster/.gitlab-ci.yml' - #- local: '/src/webui/.gitlab-ci.yml' - #- local: '/src/l3_distributedattackdetector/.gitlab-ci.yml' - #- local: '/src/l3_centralizedattackdetector/.gitlab-ci.yml' - #- local: '/src/l3_attackmitigator/.gitlab-ci.yml' - - local: '/src/slice/.gitlab-ci.yml' - #- local: '/src/interdomain/.gitlab-ci.yml' - - local: '/src/pathcomp/.gitlab-ci.yml' - #- local: '/src/dlt/.gitlab-ci.yml' - - local: '/src/load_generator/.gitlab-ci.yml' - - local: '/src/bgpls_speaker/.gitlab-ci.yml' - - local: '/src/kpi_manager/.gitlab-ci.yml' - - local: '/src/kpi_value_api/.gitlab-ci.yml' - #- local: '/src/kpi_value_writer/.gitlab-ci.yml' - #- local: '/src/telemetry/.gitlab-ci.yml' - - local: '/src/analytics/.gitlab-ci.yml' - - local: '/src/qos_profile/.gitlab-ci.yml' - - local: '/src/vnt_manager/.gitlab-ci.yml' - - local: '/src/e2e_orchestrator/.gitlab-ci.yml' - - local: '/src/ztp_server/.gitlab-ci.yml' - - local: '/src/osm_client/.gitlab-ci.yml' - - local: '/src/simap_connector/.gitlab-ci.yml' - - local: '/src/pluggables/.gitlab-ci.yml' +# #- local: '/manifests/.gitlab-ci.yml' +# - local: '/src/monitoring/.gitlab-ci.yml' +# - local: '/src/nbi/.gitlab-ci.yml' +# - local: '/src/context/.gitlab-ci.yml' +# - local: '/src/device/.gitlab-ci.yml' +# - local: '/src/service/.gitlab-ci.yml' +# - local: '/src/qkd_app/.gitlab-ci.yml' +# - local: '/src/dbscanserving/.gitlab-ci.yml' +# - local: '/src/opticalattackmitigator/.gitlab-ci.yml' +# - local: '/src/opticalattackdetector/.gitlab-ci.yml' +# - local: '/src/opticalattackmanager/.gitlab-ci.yml' +# - local: '/src/opticalcontroller/.gitlab-ci.yml' +# - local: '/src/ztp/.gitlab-ci.yml' +# - local: '/src/policy/.gitlab-ci.yml' +# - local: '/src/automation/.gitlab-ci.yml' +# - local: '/src/forecaster/.gitlab-ci.yml' +# #- local: '/src/webui/.gitlab-ci.yml' +# #- local: '/src/l3_distributedattackdetector/.gitlab-ci.yml' +# #- local: '/src/l3_centralizedattackdetector/.gitlab-ci.yml' +# #- local: '/src/l3_attackmitigator/.gitlab-ci.yml' +# - local: '/src/slice/.gitlab-ci.yml' +# #- local: '/src/interdomain/.gitlab-ci.yml' +# - local: '/src/pathcomp/.gitlab-ci.yml' +# #- local: '/src/dlt/.gitlab-ci.yml' +# - local: '/src/load_generator/.gitlab-ci.yml' +# - local: '/src/bgpls_speaker/.gitlab-ci.yml' +# - local: '/src/kpi_manager/.gitlab-ci.yml' +# - local: '/src/kpi_value_api/.gitlab-ci.yml' +# #- local: '/src/kpi_value_writer/.gitlab-ci.yml' +# #- local: '/src/telemetry/.gitlab-ci.yml' +# - local: '/src/analytics/.gitlab-ci.yml' +# - local: '/src/qos_profile/.gitlab-ci.yml' +# - local: '/src/vnt_manager/.gitlab-ci.yml' +# - local: '/src/e2e_orchestrator/.gitlab-ci.yml' +# - local: '/src/ztp_server/.gitlab-ci.yml' +# - local: '/src/osm_client/.gitlab-ci.yml' +# - local: '/src/simap_connector/.gitlab-ci.yml' +# - local: '/src/pluggables/.gitlab-ci.yml' # This should be last one: end-to-end integration tests - local: '/src/tests/.gitlab-ci.yml' diff --git a/src/tests/.gitlab-ci.yml b/src/tests/.gitlab-ci.yml index 723c26d6f..e373365f3 100644 --- a/src/tests/.gitlab-ci.yml +++ b/src/tests/.gitlab-ci.yml @@ -14,21 +14,21 @@ # include the individual .gitlab-ci.yml of each end-to-end integration test include: - - local: '/src/tests/ofc22/.gitlab-ci.yml' - #- local: '/src/tests/oeccpsc22/.gitlab-ci.yml' - - local: '/src/tests/ecoc22/.gitlab-ci.yml' - #- local: '/src/tests/nfvsdn22/.gitlab-ci.yml' - #- local: '/src/tests/ofc23/.gitlab-ci.yml' - - local: '/src/tests/ofc24/.gitlab-ci.yml' - - local: '/src/tests/eucnc24/.gitlab-ci.yml' - #- local: '/src/tests/ofc25-camara-agg-net-controller/.gitlab-ci.yml' - #- local: '/src/tests/ofc25-camara-e2e-controller/.gitlab-ci.yml' - #- local: '/src/tests/ofc25/.gitlab-ci.yml' - #- local: '/src/tests/ryu-openflow/.gitlab-ci.yml' - - local: '/src/tests/qkd_end2end/.gitlab-ci.yml' +# - local: '/src/tests/ofc22/.gitlab-ci.yml' +# #- local: '/src/tests/oeccpsc22/.gitlab-ci.yml' +# - local: '/src/tests/ecoc22/.gitlab-ci.yml' +# #- local: '/src/tests/nfvsdn22/.gitlab-ci.yml' +# #- local: '/src/tests/ofc23/.gitlab-ci.yml' +# - local: '/src/tests/ofc24/.gitlab-ci.yml' +# - local: '/src/tests/eucnc24/.gitlab-ci.yml' +# #- local: '/src/tests/ofc25-camara-agg-net-controller/.gitlab-ci.yml' +# #- local: '/src/tests/ofc25-camara-e2e-controller/.gitlab-ci.yml' +# #- local: '/src/tests/ofc25/.gitlab-ci.yml' +# #- local: '/src/tests/ryu-openflow/.gitlab-ci.yml' +# - local: '/src/tests/qkd_end2end/.gitlab-ci.yml' - local: '/src/tests/acl_end2end/.gitlab-ci.yml' - - local: '/src/tests/tools/mock_tfs_nbi_dependencies/.gitlab-ci.yml' - - local: '/src/tests/tools/mock_qkd_node/.gitlab-ci.yml' - - local: '/src/tests/tools/mock_osm_nbi/.gitlab-ci.yml' - - local: '/src/tests/tools/simap_server/.gitlab-ci.yml' +# - local: '/src/tests/tools/mock_tfs_nbi_dependencies/.gitlab-ci.yml' +# - local: '/src/tests/tools/mock_qkd_node/.gitlab-ci.yml' +# - local: '/src/tests/tools/mock_osm_nbi/.gitlab-ci.yml' +# - local: '/src/tests/tools/simap_server/.gitlab-ci.yml' diff --git a/src/tests/acl_end2end/.gitlab-ci.yml b/src/tests/acl_end2end/.gitlab-ci.yml index f6301ade2..675dc7068 100644 --- a/src/tests/acl_end2end/.gitlab-ci.yml +++ b/src/tests/acl_end2end/.gitlab-ci.yml @@ -208,7 +208,7 @@ end2end_test acl_end2end: docker run -t --rm --name ${TEST_NAME} --network=host --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh" --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" - $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-acl-create-tests.sh + $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-acl-create.sh # Run end-to-end test: test connectivity with ping after creating ACL - export TEST_CLIENT1_FW=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.11.1' --format json) @@ -230,7 +230,7 @@ end2end_test acl_end2end: docker run -t --rm --name ${TEST_NAME} --network=host --volume "$PWD/tfs_runtime_env_vars.sh:/var/teraflow/tfs_runtime_env_vars.sh" --volume "$PWD/src/tests/${TEST_NAME}:/opt/results" - $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-acl-delete-tests.sh + $CI_REGISTRY_IMAGE/${TEST_NAME}:latest /var/teraflow/run-acl-delete.sh # Run end-to-end test: test connectivity with ping after deleting ACL - export TEST_CLIENT1_FW=$(containerlab exec --name acl_end2end --label clab-node-name=client1 --cmd 'ping -n -c3 172.16.11.1' --format json) -- GitLab From c3279bc05203aebce7bb1b1ddd5c46616cb58650 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 16:45:09 +0000 Subject: [PATCH 14/20] Device component - gNMI/OpenConfig Driver: - Fixed composition and parsing of ACL rule matches --- .../drivers/gnmi_openconfig/handlers/Acl.py | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/Acl.py b/src/device/service/drivers/gnmi_openconfig/handlers/Acl.py index 06061a0b8..de1432ddb 100644 --- a/src/device/service/drivers/gnmi_openconfig/handlers/Acl.py +++ b/src/device/service/drivers/gnmi_openconfig/handlers/Acl.py @@ -89,7 +89,7 @@ class AclHandler(_Handler): y_entries = y_set.create_path('acl-entries') for entry in rs.get('entries', []): seq = int(entry['sequence_id']) - m_ = entry['match'] + m_ = entry.get('match', dict()) src_address = m_.get('src_address', '0.0.0.0/0') dst_address = m_.get('dst_address', '0.0.0.0/0') src_port = m_.get('src_port') @@ -110,10 +110,9 @@ class AclHandler(_Handler): if src_port or dst_port: y_trans = y_e.create_path('transport') if src_port: - y_trans.create_path("config/source-port", int(src_port)) + y_trans.create_path('config/source-port', int(src_port)) if dst_port: - y_trans.create_path("config/destination-port", int(dst_port)) - y_ipv4.create_path('config/protocol', int(proto)) + y_trans.create_path('config/destination-port', int(dst_port)) y_act = y_e.create_path('actions') y_act.create_path('config/forwarding-action', act) @@ -183,14 +182,24 @@ class AclHandler(_Handler): act = ace.get('actions', {}).get('config', {}).get('forwarding-action', 'DROP') fwd_tfs = _OC_TFS_FWD_ACTION[act] ipv4_cfg = ace.get('ipv4', {}).get('config', {}) + transport_cfg = ace.get('transport', {}).get('config', {}) + + match_conditions = dict() + if 'source-address' in ipv4_cfg: + match_conditions['src_address'] = ipv4_cfg['source-address'] + if 'destination-address' in ipv4_cfg: + match_conditions['dst_address'] = ipv4_cfg['destination-address'] + if 'protocol' in ipv4_cfg: + match_conditions['protocol'] = ipv4_cfg['protocol'] + if 'source-port' in transport_cfg: + match_conditions['src_port'] = transport_cfg['source-port'] + if 'destination-port' in transport_cfg: + match_conditions['dst_port'] = transport_cfg['destination-port'] rule_set['entries'].append( { 'sequence_id': seq, - 'match': { - 'src_address': ipv4_cfg.get('source-address', ''), - 'dst_address': ipv4_cfg.get('destination-address', ''), - }, + 'match': match_conditions, 'action': {'forward_action': fwd_tfs}, } ) -- GitLab From cca4ea780426898249f3d1847a6af1779b717462 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 17:00:50 +0000 Subject: [PATCH 15/20] Device component - gNMI/OpenConfig Driver: - Fixed ACL composition for Arista --- src/device/service/drivers/gnmi_openconfig/handlers/Acl.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/Acl.py b/src/device/service/drivers/gnmi_openconfig/handlers/Acl.py index de1432ddb..0e6f31ff7 100644 --- a/src/device/service/drivers/gnmi_openconfig/handlers/Acl.py +++ b/src/device/service/drivers/gnmi_openconfig/handlers/Acl.py @@ -30,7 +30,8 @@ _TFS_OC_RULE_TYPE = { _TFS_OC_FWD_ACTION = { 'ACLFORWARDINGACTION_DROP': 'DROP', 'ACLFORWARDINGACTION_ACCEPT': 'ACCEPT', - 'ACLFORWARDINGACTION_REJECT': 'REJECT', + #'ACLFORWARDINGACTION_REJECT': 'REJECT', # Correct according to OpenConfig. + 'ACLFORWARDINGACTION_REJECT': 'DROP', # - Arista EOS only supports ACCEPT/DROP } _OC_TFS_RULE_TYPE = {v: k for k, v in _TFS_OC_RULE_TYPE.items()} -- GitLab From 4e6aeab5727582928e9adf6cb6d56924470ced75 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 17:19:56 +0000 Subject: [PATCH 16/20] NBI component - IETF ACL connector: - Fixed returned status codes --- src/nbi/service/ietf_acl/Acl.py | 7 ++++++- src/nbi/service/ietf_acl/Acls.py | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/nbi/service/ietf_acl/Acl.py b/src/nbi/service/ietf_acl/Acl.py index c0635968b..d48b645de 100644 --- a/src/nbi/service/ietf_acl/Acl.py +++ b/src/nbi/service/ietf_acl/Acl.py @@ -13,6 +13,7 @@ # limitations under the License. import json, logging, re +from flask import jsonify from flask_restful import Resource from werkzeug.exceptions import NotFound from common.proto.context_pb2 import ConfigActionEnum, ConfigRule @@ -20,6 +21,7 @@ from common.tools.context_queries.Device import get_device from context.client.ContextClient import ContextClient from device.client.DeviceClient import DeviceClient from nbi.service._tools.Authentication import HTTP_AUTH +from nbi.service._tools.HttpStatusCodes import HTTP_NOCONTENT from .ietf_acl_parser import ietf_acl_from_config_rule_resource_value LOGGER = logging.getLogger(__name__) @@ -72,4 +74,7 @@ class Acl(Resource): del device.device_config.config_rules[:] device.device_config.config_rules.extend(delete_config_rules) device_client.ConfigureDevice(device) - return None + + response = jsonify({}) + response.status_code = HTTP_NOCONTENT + return response diff --git a/src/nbi/service/ietf_acl/Acls.py b/src/nbi/service/ietf_acl/Acls.py index e966f2c0c..e9268226b 100644 --- a/src/nbi/service/ietf_acl/Acls.py +++ b/src/nbi/service/ietf_acl/Acls.py @@ -23,6 +23,7 @@ from common.tools.grpc.Tools import grpc_message_to_json_string from context.client.ContextClient import ContextClient from device.client.DeviceClient import DeviceClient from nbi.service._tools.Authentication import HTTP_AUTH +from nbi.service._tools.HttpStatusCodes import HTTP_CREATED from .ietf_acl_parser import AclDirectionEnum, config_rule_from_ietf_acl from .YangValidator import YangValidator @@ -129,4 +130,7 @@ class Acls(Resource): device_client = DeviceClient() device_client.ConfigureDevice(device) - return jsonify({}) + + response = jsonify({}) + response.status_code = HTTP_CREATED + return response -- GitLab From 4e3bd3d1a0c387deb5f6d0f9911bc6f4bb528a0f Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 17:45:44 +0000 Subject: [PATCH 17/20] NBI component - IETF ACL connector: - Fixed composition of ACL rules in GET --- src/nbi/service/ietf_acl/ietf_acl_parser.py | 52 +++++++++++++++------ 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/nbi/service/ietf_acl/ietf_acl_parser.py b/src/nbi/service/ietf_acl/ietf_acl_parser.py index 7305775b8..0ed994a51 100644 --- a/src/nbi/service/ietf_acl/ietf_acl_parser.py +++ b/src/nbi/service/ietf_acl/ietf_acl_parser.py @@ -28,9 +28,12 @@ class AclDirectionEnum(Enum): class Ipv4(BaseModel): dscp: int = 0 - source_ipv4_network: str = Field(serialization_alias='source-ipv4-network', default='') + protocol: int = 0 + source_ipv4_network: str = Field( + serialization_alias='source-ipv4-network', default=None + ) destination_ipv4_network: str = Field( - serialization_alias='destination-ipv4-network', default='' + serialization_alias='destination-ipv4-network', default=None ) @@ -45,9 +48,15 @@ class Tcp(BaseModel): destination_port: Optional[Port] = Field(serialization_alias='destination-port', default=None) +class Udp(BaseModel): + source_port: Optional[Port] = Field(serialization_alias='source-port', default=None) + destination_port: Optional[Port] = Field(serialization_alias='destination-port', default=None) + + class Matches(BaseModel): ipv4: Ipv4 = Ipv4() tcp: Optional[Tcp] = None + udp: Optional[Udp] = None class Action(BaseModel): @@ -237,27 +246,42 @@ def config_rule_from_ietf_acl( def ietf_acl_from_config_rule_resource_value(config_rule_rv: Dict) -> Dict: - rule_set = config_rule_rv['rule_set'] + rule_set = config_rule_rv.get('rule_set', dict()) ace = [] - for acl_entry in rule_set['entries']: - match_ = acl_entry['match'] + for acl_entry in rule_set.get('entries', list()): + match_ = acl_entry.get('match', dict()) + protocol = match_.get('protocol', 0) ipv4 = Ipv4( - dscp=match_['dscp'], - source_ipv4_network=match_['src_address'], - destination_ipv4_network=match_['dst_address'], + dscp=match_.get('dscp', 0), + protocol=protocol, + source_ipv4_network=match_.get('src_address'), + destination_ipv4_network=match_.get('dst_address'), ) + + src_port = match_.get('src_port') + src_port = None if src_port is None else Port(port=src_port) + dst_port = match_.get('dst_port') + dst_port = None if dst_port is None else Port(port=dst_port) + tcp = None - if match_['tcp_flags']: + udp = None + if protocol == 6: tcp = Tcp( - flags=match_['tcp_flags'], - source_port=Port(port=match_['src_port']), - destination_port=Port(port=match_['dst_port']), + flags=match_.get('tcp_flags', 0), + source_port=src_port, + destination_port=dst_port, ) - matches = Matches(ipv4=ipv4, tcp=tcp) + elif protocol == 17: + udp = Udp( + source_port=src_port, + destination_port=dst_port, + ) + + matches = Matches(ipv4=ipv4, tcp=tcp, udp=udp) ace.append( Ace( - name=acl_entry['description'], + name=acl_entry.get('description', ''), matches=matches, actions=Action( forwarding=TFS_IETF_FORWARDING_ACTION_MAPPING[ -- GitLab From 7fcf60c042d3f4b53d38749f48e2cf7c6395fc6f Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 18:02:33 +0000 Subject: [PATCH 18/20] NBI component - IETF ACL connector: - Fixed composition of ACL rules in GET --- src/nbi/service/ietf_acl/ietf_acl_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nbi/service/ietf_acl/ietf_acl_parser.py b/src/nbi/service/ietf_acl/ietf_acl_parser.py index 0ed994a51..66c041f20 100644 --- a/src/nbi/service/ietf_acl/ietf_acl_parser.py +++ b/src/nbi/service/ietf_acl/ietf_acl_parser.py @@ -29,10 +29,10 @@ class AclDirectionEnum(Enum): class Ipv4(BaseModel): dscp: int = 0 protocol: int = 0 - source_ipv4_network: str = Field( + source_ipv4_network: Optional[str] = Field( serialization_alias='source-ipv4-network', default=None ) - destination_ipv4_network: str = Field( + destination_ipv4_network: Optional[str] = Field( serialization_alias='destination-ipv4-network', default=None ) -- GitLab From c1e05b547fcca61861ceeb4057ace6797e1a7751 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Wed, 17 Dec 2025 18:21:39 +0000 Subject: [PATCH 19/20] Tests - EUCNC24 End-to-end integration test: - Create and Delete ACLs to check all ACLs created --- .../acl_end2end/tests/test_acl_create.py | 23 ++++++++------ .../acl_end2end/tests/test_acl_delete.py | 30 +++++++++++-------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/tests/acl_end2end/tests/test_acl_create.py b/src/tests/acl_end2end/tests/test_acl_create.py index 054472113..ff38434c2 100644 --- a/src/tests/acl_end2end/tests/test_acl_create.py +++ b/src/tests/acl_end2end/tests/test_acl_create.py @@ -13,7 +13,7 @@ # limitations under the License. import json, logging, os -from typing import Dict +from typing import Dict, List from .Tools import do_rest_get_request, do_rest_post_request LOGGER = logging.getLogger(__name__) @@ -30,20 +30,25 @@ def load_acl_payload() -> Dict: with open(ACL_FILE, 'r', encoding='UTF-8') as f: return json.load(f) -def get_acl_name(payload: Dict) -> str: - return payload['ietf-access-control-list:acls']['acl'][0]['name'] +def get_acl_names(payload: Dict) -> List[str]: + return [ + acl['name'] + for acl in payload['ietf-access-control-list:acls']['acl'] + ] def test_ietf_acl_create() -> None: acl_payload = load_acl_payload() - acl_name = get_acl_name(acl_payload) + acl_names = get_acl_names(acl_payload) do_rest_post_request( ACL_URL, body=acl_payload, logger=LOGGER, expected_status_codes={201, 204} ) - response = do_rest_get_request( - ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, - expected_status_codes={200} - ) - assert response is not None + + for acl_name in acl_names: + response = do_rest_get_request( + ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, + expected_status_codes={200} + ) + assert response is not None diff --git a/src/tests/acl_end2end/tests/test_acl_delete.py b/src/tests/acl_end2end/tests/test_acl_delete.py index 63d9e5a81..c52079ec5 100644 --- a/src/tests/acl_end2end/tests/test_acl_delete.py +++ b/src/tests/acl_end2end/tests/test_acl_delete.py @@ -13,7 +13,7 @@ # limitations under the License. import json, logging, os -from typing import Dict +from typing import Dict, List from .Tools import do_rest_delete_request, do_rest_get_request LOGGER = logging.getLogger(__name__) @@ -30,19 +30,23 @@ def load_acl_payload() -> Dict: with open(ACL_FILE, 'r', encoding='UTF-8') as f: return json.load(f) -def get_acl_name(payload: Dict) -> str: - return payload['ietf-access-control-list:acls']['acl'][0]['name'] +def get_acl_names(payload: Dict) -> List[str]: + return [ + acl['name'] + for acl in payload['ietf-access-control-list:acls']['acl'] + ] def test_ietf_acl_delete() -> None: acl_payload = load_acl_payload() - acl_name = get_acl_name(acl_payload) - - do_rest_delete_request( - ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, - expected_status_codes={200, 204} - ) - do_rest_get_request( - ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, - expected_status_codes={404} - ) + acl_names = get_acl_names(acl_payload) + + for acl_name in acl_names: + do_rest_delete_request( + ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, + expected_status_codes={200, 204} + ) + do_rest_get_request( + ACL_GET_URL_TEMPLATE.format(acl_name=acl_name), logger=LOGGER, + expected_status_codes={404} + ) -- GitLab From 0a73a3b68eff476e9d18273aaf62cfce2cf1e388 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Thu, 18 Dec 2025 08:41:53 +0000 Subject: [PATCH 20/20] Tests - EUCNC24 End-to-end integration test: - Reactivated other CI/CD tests --- .gitlab-ci.yml | 76 ++++++++++++++++++++-------------------- src/tests/.gitlab-ci.yml | 32 ++++++++--------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e3286d05f..e11c8474a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,44 +22,44 @@ stages: # include the individual .gitlab-ci.yml of each micro-service and tests include: -# #- local: '/manifests/.gitlab-ci.yml' -# - local: '/src/monitoring/.gitlab-ci.yml' -# - local: '/src/nbi/.gitlab-ci.yml' -# - local: '/src/context/.gitlab-ci.yml' -# - local: '/src/device/.gitlab-ci.yml' -# - local: '/src/service/.gitlab-ci.yml' -# - local: '/src/qkd_app/.gitlab-ci.yml' -# - local: '/src/dbscanserving/.gitlab-ci.yml' -# - local: '/src/opticalattackmitigator/.gitlab-ci.yml' -# - local: '/src/opticalattackdetector/.gitlab-ci.yml' -# - local: '/src/opticalattackmanager/.gitlab-ci.yml' -# - local: '/src/opticalcontroller/.gitlab-ci.yml' -# - local: '/src/ztp/.gitlab-ci.yml' -# - local: '/src/policy/.gitlab-ci.yml' -# - local: '/src/automation/.gitlab-ci.yml' -# - local: '/src/forecaster/.gitlab-ci.yml' -# #- local: '/src/webui/.gitlab-ci.yml' -# #- local: '/src/l3_distributedattackdetector/.gitlab-ci.yml' -# #- local: '/src/l3_centralizedattackdetector/.gitlab-ci.yml' -# #- local: '/src/l3_attackmitigator/.gitlab-ci.yml' -# - local: '/src/slice/.gitlab-ci.yml' -# #- local: '/src/interdomain/.gitlab-ci.yml' -# - local: '/src/pathcomp/.gitlab-ci.yml' -# #- local: '/src/dlt/.gitlab-ci.yml' -# - local: '/src/load_generator/.gitlab-ci.yml' -# - local: '/src/bgpls_speaker/.gitlab-ci.yml' -# - local: '/src/kpi_manager/.gitlab-ci.yml' -# - local: '/src/kpi_value_api/.gitlab-ci.yml' -# #- local: '/src/kpi_value_writer/.gitlab-ci.yml' -# #- local: '/src/telemetry/.gitlab-ci.yml' -# - local: '/src/analytics/.gitlab-ci.yml' -# - local: '/src/qos_profile/.gitlab-ci.yml' -# - local: '/src/vnt_manager/.gitlab-ci.yml' -# - local: '/src/e2e_orchestrator/.gitlab-ci.yml' -# - local: '/src/ztp_server/.gitlab-ci.yml' -# - local: '/src/osm_client/.gitlab-ci.yml' -# - local: '/src/simap_connector/.gitlab-ci.yml' -# - local: '/src/pluggables/.gitlab-ci.yml' + #- local: '/manifests/.gitlab-ci.yml' + - local: '/src/monitoring/.gitlab-ci.yml' + - local: '/src/nbi/.gitlab-ci.yml' + - local: '/src/context/.gitlab-ci.yml' + - local: '/src/device/.gitlab-ci.yml' + - local: '/src/service/.gitlab-ci.yml' + - local: '/src/qkd_app/.gitlab-ci.yml' + - local: '/src/dbscanserving/.gitlab-ci.yml' + - local: '/src/opticalattackmitigator/.gitlab-ci.yml' + - local: '/src/opticalattackdetector/.gitlab-ci.yml' + - local: '/src/opticalattackmanager/.gitlab-ci.yml' + - local: '/src/opticalcontroller/.gitlab-ci.yml' + - local: '/src/ztp/.gitlab-ci.yml' + - local: '/src/policy/.gitlab-ci.yml' + - local: '/src/automation/.gitlab-ci.yml' + - local: '/src/forecaster/.gitlab-ci.yml' + #- local: '/src/webui/.gitlab-ci.yml' + #- local: '/src/l3_distributedattackdetector/.gitlab-ci.yml' + #- local: '/src/l3_centralizedattackdetector/.gitlab-ci.yml' + #- local: '/src/l3_attackmitigator/.gitlab-ci.yml' + - local: '/src/slice/.gitlab-ci.yml' + #- local: '/src/interdomain/.gitlab-ci.yml' + - local: '/src/pathcomp/.gitlab-ci.yml' + #- local: '/src/dlt/.gitlab-ci.yml' + - local: '/src/load_generator/.gitlab-ci.yml' + - local: '/src/bgpls_speaker/.gitlab-ci.yml' + - local: '/src/kpi_manager/.gitlab-ci.yml' + - local: '/src/kpi_value_api/.gitlab-ci.yml' + #- local: '/src/kpi_value_writer/.gitlab-ci.yml' + #- local: '/src/telemetry/.gitlab-ci.yml' + - local: '/src/analytics/.gitlab-ci.yml' + - local: '/src/qos_profile/.gitlab-ci.yml' + - local: '/src/vnt_manager/.gitlab-ci.yml' + - local: '/src/e2e_orchestrator/.gitlab-ci.yml' + - local: '/src/ztp_server/.gitlab-ci.yml' + - local: '/src/osm_client/.gitlab-ci.yml' + - local: '/src/simap_connector/.gitlab-ci.yml' + - local: '/src/pluggables/.gitlab-ci.yml' # This should be last one: end-to-end integration tests - local: '/src/tests/.gitlab-ci.yml' diff --git a/src/tests/.gitlab-ci.yml b/src/tests/.gitlab-ci.yml index e373365f3..723c26d6f 100644 --- a/src/tests/.gitlab-ci.yml +++ b/src/tests/.gitlab-ci.yml @@ -14,21 +14,21 @@ # include the individual .gitlab-ci.yml of each end-to-end integration test include: -# - local: '/src/tests/ofc22/.gitlab-ci.yml' -# #- local: '/src/tests/oeccpsc22/.gitlab-ci.yml' -# - local: '/src/tests/ecoc22/.gitlab-ci.yml' -# #- local: '/src/tests/nfvsdn22/.gitlab-ci.yml' -# #- local: '/src/tests/ofc23/.gitlab-ci.yml' -# - local: '/src/tests/ofc24/.gitlab-ci.yml' -# - local: '/src/tests/eucnc24/.gitlab-ci.yml' -# #- local: '/src/tests/ofc25-camara-agg-net-controller/.gitlab-ci.yml' -# #- local: '/src/tests/ofc25-camara-e2e-controller/.gitlab-ci.yml' -# #- local: '/src/tests/ofc25/.gitlab-ci.yml' -# #- local: '/src/tests/ryu-openflow/.gitlab-ci.yml' -# - local: '/src/tests/qkd_end2end/.gitlab-ci.yml' + - local: '/src/tests/ofc22/.gitlab-ci.yml' + #- local: '/src/tests/oeccpsc22/.gitlab-ci.yml' + - local: '/src/tests/ecoc22/.gitlab-ci.yml' + #- local: '/src/tests/nfvsdn22/.gitlab-ci.yml' + #- local: '/src/tests/ofc23/.gitlab-ci.yml' + - local: '/src/tests/ofc24/.gitlab-ci.yml' + - local: '/src/tests/eucnc24/.gitlab-ci.yml' + #- local: '/src/tests/ofc25-camara-agg-net-controller/.gitlab-ci.yml' + #- local: '/src/tests/ofc25-camara-e2e-controller/.gitlab-ci.yml' + #- local: '/src/tests/ofc25/.gitlab-ci.yml' + #- local: '/src/tests/ryu-openflow/.gitlab-ci.yml' + - local: '/src/tests/qkd_end2end/.gitlab-ci.yml' - local: '/src/tests/acl_end2end/.gitlab-ci.yml' -# - local: '/src/tests/tools/mock_tfs_nbi_dependencies/.gitlab-ci.yml' -# - local: '/src/tests/tools/mock_qkd_node/.gitlab-ci.yml' -# - local: '/src/tests/tools/mock_osm_nbi/.gitlab-ci.yml' -# - local: '/src/tests/tools/simap_server/.gitlab-ci.yml' + - local: '/src/tests/tools/mock_tfs_nbi_dependencies/.gitlab-ci.yml' + - local: '/src/tests/tools/mock_qkd_node/.gitlab-ci.yml' + - local: '/src/tests/tools/mock_osm_nbi/.gitlab-ci.yml' + - local: '/src/tests/tools/simap_server/.gitlab-ci.yml' -- GitLab